806 lines
15 KiB
C
806 lines
15 KiB
C
/*++
|
||
|
||
Copyright (c) 1998-2001 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
secutil.c
|
||
|
||
Abstract:
|
||
|
||
Domain Name System (DNS) Library
|
||
|
||
DNS secure update API.
|
||
|
||
Author:
|
||
|
||
Jim Gilroy (jamesg) January, 1998
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "local.h"
|
||
|
||
// security headers
|
||
|
||
//#define SECURITY_WIN32
|
||
//#include "sspi.h"
|
||
//#include "issperr.h"
|
||
//#include "rpc.h"
|
||
//#include "rpcndr.h"
|
||
//#include "ntdsapi.h"
|
||
|
||
|
||
|
||
//
|
||
// Security utilities
|
||
//
|
||
|
||
DNS_STATUS
|
||
Dns_CreateSecurityDescriptor(
|
||
OUT PSECURITY_DESCRIPTOR * ppSD,
|
||
IN DWORD AclCount,
|
||
IN PSID * SidPtrArray,
|
||
IN DWORD * AccessMaskArray
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Build security descriptor.
|
||
|
||
Arguments:
|
||
|
||
ppSD -- addr to receive SD created
|
||
|
||
AclCount -- number of ACLs to add
|
||
|
||
SidPtrArray -- array of SIDs to create ACLs for
|
||
|
||
AccessMaskArray -- array of access masks corresponding to SIDs
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful
|
||
Error code on failure.
|
||
|
||
--*/
|
||
{
|
||
DNS_STATUS status;
|
||
DWORD i;
|
||
DWORD lengthAcl;
|
||
PSECURITY_DESCRIPTOR psd = NULL;
|
||
PACL pacl;
|
||
|
||
//
|
||
// calculate space for SD
|
||
//
|
||
|
||
lengthAcl = sizeof(ACL);
|
||
|
||
for ( i=0; i<AclCount; i++ )
|
||
{
|
||
if ( SidPtrArray[i] && AccessMaskArray[i] )
|
||
{
|
||
lengthAcl += GetLengthSid( SidPtrArray[i] ) + sizeof(ACCESS_ALLOWED_ACE);
|
||
}
|
||
ELSE
|
||
{
|
||
DNS_PRINT((
|
||
"ERROR: SD building with SID (%p) and mask (%p)\n",
|
||
SidPtrArray[i],
|
||
AccessMaskArray[i] ));
|
||
}
|
||
}
|
||
|
||
//
|
||
// allocate SD
|
||
//
|
||
|
||
psd = (PSECURITY_DESCRIPTOR) ALLOCATE_HEAP(
|
||
SECURITY_DESCRIPTOR_MIN_LENGTH + lengthAcl );
|
||
if ( !psd )
|
||
{
|
||
status = DNS_ERROR_NO_MEMORY;
|
||
goto Failed;
|
||
}
|
||
|
||
DNSDBG( INIT, (
|
||
"Allocated SecurityDesc at %p of length %d\n",
|
||
psd,
|
||
SECURITY_DESCRIPTOR_MIN_LENGTH + lengthAcl ));
|
||
|
||
//
|
||
// build ACL, adding ACE with desired access for each SID
|
||
//
|
||
|
||
pacl = (PACL) ((PBYTE)psd + SECURITY_DESCRIPTOR_MIN_LENGTH);
|
||
|
||
if ( !InitializeAcl(
|
||
pacl,
|
||
lengthAcl,
|
||
ACL_REVISION ) )
|
||
{
|
||
status = GetLastError();
|
||
goto Failed;
|
||
}
|
||
|
||
for ( i=0; i<AclCount; i++ )
|
||
{
|
||
if ( SidPtrArray[i] && AccessMaskArray[i] )
|
||
{
|
||
if ( !AddAccessAllowedAce(
|
||
pacl,
|
||
ACL_REVISION,
|
||
AccessMaskArray[i],
|
||
SidPtrArray[i] ) )
|
||
{
|
||
status = GetLastError();
|
||
DNSDBG( ANY, (
|
||
"ERROR: failed adding ACE for SID %p, mask %p\n",
|
||
SidPtrArray[i],
|
||
AccessMaskArray[i] ));
|
||
goto Failed;
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// setup SD with ACL
|
||
//
|
||
|
||
if ( !InitializeSecurityDescriptor(
|
||
psd,
|
||
SECURITY_DESCRIPTOR_REVISION ))
|
||
{
|
||
status = GetLastError();
|
||
goto Failed;
|
||
}
|
||
|
||
if ( !SetSecurityDescriptorDacl(
|
||
psd,
|
||
TRUE, // ACL present
|
||
pacl,
|
||
FALSE // explicit ACL, not defaulted
|
||
))
|
||
{
|
||
status = GetLastError();
|
||
goto Failed;
|
||
}
|
||
|
||
*ppSD = psd;
|
||
|
||
return( ERROR_SUCCESS );
|
||
|
||
|
||
Failed:
|
||
|
||
ASSERT( status != ERROR_SUCCESS );
|
||
*ppSD = NULL;
|
||
FREE_HEAP( psd );
|
||
|
||
return( status );
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// Credential utilities
|
||
//
|
||
|
||
PSEC_WINNT_AUTH_IDENTITY_W
|
||
Dns_AllocateAndInitializeCredentialsW(
|
||
IN PSEC_WINNT_AUTH_IDENTITY_W pAuthIn
|
||
)
|
||
/*++
|
||
|
||
Description:
|
||
|
||
Allocates auth identity info and initializes pAuthIn info
|
||
|
||
Parameters:
|
||
|
||
pAuthIn -- auth identity info
|
||
|
||
Return:
|
||
|
||
Ptr to newly create credentials.
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PSEC_WINNT_AUTH_IDENTITY_W pauthCopy = NULL;
|
||
|
||
DNSDBG( SECURITY, (
|
||
"Call Dns_AllocateAndInitializeCredentialsW\n" ));
|
||
|
||
if ( !pAuthIn )
|
||
{
|
||
return NULL;
|
||
}
|
||
ASSERT( pAuthIn->Flags == SEC_WINNT_AUTH_IDENTITY_UNICODE );
|
||
|
||
//
|
||
// allocate credentials struct
|
||
// - zero for simple cleanup on subfield alloc failures
|
||
//
|
||
|
||
pauthCopy = ALLOCATE_HEAP_ZERO( sizeof(SEC_WINNT_AUTH_IDENTITY_W) );
|
||
if ( !pauthCopy )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// copy subfields
|
||
//
|
||
|
||
// user
|
||
|
||
pauthCopy->UserLength = pAuthIn->UserLength;
|
||
if ( pAuthIn->UserLength )
|
||
{
|
||
ASSERT( pAuthIn->UserLength == wcslen(pAuthIn->User) );
|
||
|
||
pauthCopy->User = ALLOCATE_HEAP( (pAuthIn->UserLength + 1) * sizeof(WCHAR) );
|
||
if ( ! pauthCopy->User )
|
||
{
|
||
goto Failed;
|
||
}
|
||
wcscpy( pauthCopy->User, pAuthIn->User );
|
||
}
|
||
|
||
// password
|
||
// - must allow zero length password
|
||
|
||
pauthCopy->PasswordLength = pAuthIn->PasswordLength;
|
||
|
||
if ( pAuthIn->PasswordLength || pAuthIn->Password )
|
||
{
|
||
ASSERT( pAuthIn->PasswordLength == wcslen(pAuthIn->Password) );
|
||
|
||
pauthCopy->Password = ALLOCATE_HEAP( (pAuthIn->PasswordLength + 1) * sizeof(WCHAR) );
|
||
if ( ! pauthCopy->Password )
|
||
{
|
||
goto Failed;
|
||
}
|
||
wcscpy( pauthCopy->Password, pAuthIn->Password );
|
||
}
|
||
|
||
// domain
|
||
|
||
pauthCopy->DomainLength = pAuthIn->DomainLength;
|
||
if ( pAuthIn->DomainLength )
|
||
{
|
||
ASSERT( pAuthIn->DomainLength == wcslen(pAuthIn->Domain) );
|
||
|
||
pauthCopy->Domain = ALLOCATE_HEAP( (pAuthIn->DomainLength + 1) * sizeof(WCHAR) );
|
||
if ( ! pauthCopy->Domain )
|
||
{
|
||
goto Failed;
|
||
}
|
||
wcscpy( pauthCopy->Domain, pAuthIn->Domain );
|
||
}
|
||
|
||
pauthCopy->Flags = pAuthIn->Flags;
|
||
|
||
DNSDBG( SECURITY, (
|
||
"Exit Dns_AllocateAndInitializeCredentialsW()\n" ));
|
||
|
||
return pauthCopy;
|
||
|
||
|
||
Failed:
|
||
|
||
// allocation failure
|
||
// - cleanup what was allocated and get out
|
||
|
||
Dns_FreeAuthIdentityCredentials( pauthCopy );
|
||
return( NULL );
|
||
}
|
||
|
||
|
||
|
||
PSEC_WINNT_AUTH_IDENTITY_A
|
||
Dns_AllocateAndInitializeCredentialsA(
|
||
IN PSEC_WINNT_AUTH_IDENTITY_A pAuthIn
|
||
)
|
||
/*++
|
||
|
||
Description:
|
||
|
||
Allocates auth identity info and initializes pAuthIn info
|
||
|
||
Note: it is more work to convert to unicode and call previous
|
||
function than to call this one
|
||
|
||
Parameters:
|
||
|
||
pAuthIn -- auth identity info
|
||
|
||
Return:
|
||
|
||
Ptr to newly create credentials.
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PSEC_WINNT_AUTH_IDENTITY_A pauthCopy = NULL;
|
||
|
||
DNSDBG( SECURITY, (
|
||
"Call Dns_AllocateAndInitializeCredentialsA\n" ));
|
||
|
||
//
|
||
// allocate credentials struct
|
||
// - zero for simple cleanup on subfield alloc failures
|
||
//
|
||
|
||
if ( !pAuthIn )
|
||
{
|
||
return NULL;
|
||
}
|
||
ASSERT( pAuthIn->Flags == SEC_WINNT_AUTH_IDENTITY_ANSI );
|
||
|
||
//
|
||
// allocate credentials struct
|
||
// - zero for simple cleanup on subfield alloc failures
|
||
//
|
||
|
||
pauthCopy = ALLOCATE_HEAP_ZERO( sizeof(SEC_WINNT_AUTH_IDENTITY_A) );
|
||
if ( !pauthCopy )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// copy subfields
|
||
//
|
||
|
||
// user
|
||
|
||
pauthCopy->UserLength = pAuthIn->UserLength;
|
||
if ( pAuthIn->UserLength )
|
||
{
|
||
ASSERT( pAuthIn->UserLength == strlen(pAuthIn->User) );
|
||
|
||
pauthCopy->User = ALLOCATE_HEAP( (pAuthIn->UserLength + 1) * sizeof(CHAR) );
|
||
if ( ! pauthCopy->User )
|
||
{
|
||
goto Failed;
|
||
}
|
||
strcpy( pauthCopy->User, pAuthIn->User );
|
||
}
|
||
|
||
// password
|
||
// - must allow zero length password
|
||
|
||
pauthCopy->PasswordLength = pAuthIn->PasswordLength;
|
||
|
||
if ( pAuthIn->PasswordLength || pAuthIn->Password )
|
||
{
|
||
ASSERT( pAuthIn->PasswordLength == strlen(pAuthIn->Password) );
|
||
|
||
pauthCopy->Password = ALLOCATE_HEAP( (pAuthIn->PasswordLength + 1) * sizeof(CHAR) );
|
||
if ( ! pauthCopy->Password )
|
||
{
|
||
goto Failed;
|
||
}
|
||
strcpy( pauthCopy->Password, pAuthIn->Password );
|
||
}
|
||
|
||
// domain
|
||
|
||
pauthCopy->DomainLength = pAuthIn->DomainLength;
|
||
if ( pAuthIn->DomainLength )
|
||
{
|
||
ASSERT( pAuthIn->DomainLength == strlen(pAuthIn->Domain) );
|
||
|
||
pauthCopy->Domain = ALLOCATE_HEAP( (pAuthIn->DomainLength + 1) * sizeof(CHAR) );
|
||
if ( ! pauthCopy->Domain )
|
||
{
|
||
goto Failed;
|
||
}
|
||
strcpy( pauthCopy->Domain, pAuthIn->Domain );
|
||
}
|
||
|
||
pauthCopy->Flags = pAuthIn->Flags;
|
||
|
||
DNSDBG( SECURITY, (
|
||
"Exit Dns_AllocateAndInitializeCredentialsA()\n" ));
|
||
|
||
return pauthCopy;
|
||
|
||
|
||
Failed:
|
||
|
||
// allocation failure
|
||
// - cleanup what was allocated and get out
|
||
|
||
Dns_FreeAuthIdentityCredentials( pauthCopy );
|
||
return( NULL );
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
Dns_FreeAuthIdentityCredentials(
|
||
IN OUT PVOID pAuthIn
|
||
)
|
||
/*++
|
||
|
||
Routine Description (Dns_FreeAuthIdentityCredentials):
|
||
|
||
Free's structure given
|
||
|
||
Arguments:
|
||
|
||
pAuthIn -- in param to free
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
register PSEC_WINNT_AUTH_IDENTITY_W pauthId;
|
||
|
||
pauthId = (PSEC_WINNT_AUTH_IDENTITY_W) pAuthIn;
|
||
if ( !pauthId )
|
||
{
|
||
return;
|
||
}
|
||
|
||
//
|
||
// assuming _W and _A structs are equivalent except
|
||
// for string types
|
||
//
|
||
|
||
ASSERT( sizeof( SEC_WINNT_AUTH_IDENTITY_W ) ==
|
||
sizeof( SEC_WINNT_AUTH_IDENTITY_A ) );
|
||
|
||
if ( pauthId->User )
|
||
{
|
||
FREE_HEAP ( pauthId->User );
|
||
}
|
||
if ( pauthId->Password )
|
||
{
|
||
FREE_HEAP ( pauthId->Password );
|
||
}
|
||
if ( pauthId->Domain )
|
||
{
|
||
FREE_HEAP ( pauthId->Domain );
|
||
}
|
||
|
||
FREE_HEAP ( pauthId );
|
||
}
|
||
|
||
|
||
|
||
PSEC_WINNT_AUTH_IDENTITY_W
|
||
Dns_AllocateCredentials(
|
||
IN PWSTR pwsUserName,
|
||
IN PWSTR pwsDomain,
|
||
IN PWSTR pwsPassword
|
||
)
|
||
/*++
|
||
|
||
Description:
|
||
|
||
Allocates auth identity info and initializes pAuthIn info
|
||
|
||
Parameters:
|
||
|
||
pwsUserName -- user name
|
||
|
||
pwsDomain -- domain name
|
||
|
||
pwsPassword -- password
|
||
|
||
Return:
|
||
|
||
Ptr to newly create credentials.
|
||
NULL on failure.
|
||
|
||
--*/
|
||
{
|
||
PSEC_WINNT_AUTH_IDENTITY_W pauth = NULL;
|
||
DWORD length;
|
||
PWSTR pstr;
|
||
|
||
|
||
DNSDBG( SECURITY, (
|
||
"Enter Dns_AllocateCredentials()\n"
|
||
"\tuser = %S\n"
|
||
"\tdomain = %S\n"
|
||
"\tpassword = %S\n",
|
||
pwsUserName,
|
||
pwsDomain,
|
||
pwsPassword ));
|
||
|
||
//
|
||
// allocate credentials struct
|
||
// - zero for simple cleanup on subfield alloc failures
|
||
//
|
||
|
||
pauth = ALLOCATE_HEAP_ZERO( sizeof(SEC_WINNT_AUTH_IDENTITY_W) );
|
||
if ( !pauth )
|
||
{
|
||
return NULL;
|
||
}
|
||
|
||
// copy user
|
||
|
||
length = wcslen( pwsUserName );
|
||
|
||
pstr = ALLOCATE_HEAP( (length + 1) * sizeof(WCHAR) );
|
||
if ( ! pstr )
|
||
{
|
||
goto Failed;
|
||
}
|
||
wcscpy( pstr, pwsUserName );
|
||
|
||
pauth->User = pstr;
|
||
pauth->UserLength = length;
|
||
|
||
// copy domain
|
||
|
||
length = wcslen( pwsDomain );
|
||
|
||
pstr = ALLOCATE_HEAP( (length + 1) * sizeof(WCHAR) );
|
||
if ( ! pstr )
|
||
{
|
||
goto Failed;
|
||
}
|
||
wcscpy( pstr, pwsDomain );
|
||
|
||
pauth->Domain = pstr;
|
||
pauth->DomainLength = length;
|
||
|
||
// copy password
|
||
|
||
length = wcslen( pwsPassword );
|
||
|
||
pstr = ALLOCATE_HEAP( (length + 1) * sizeof(WCHAR) );
|
||
if ( ! pstr )
|
||
{
|
||
goto Failed;
|
||
}
|
||
wcscpy( pstr, pwsPassword );
|
||
|
||
pauth->Password = pstr;
|
||
pauth->PasswordLength = length;
|
||
|
||
// set to unicode
|
||
|
||
pauth->Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
|
||
|
||
DNSDBG( SECURITY, (
|
||
"Exit Dns_AllocateCredentialsW( %p )\n",
|
||
pauth ));
|
||
|
||
return pauth;
|
||
|
||
|
||
Failed:
|
||
|
||
// allocation failure
|
||
// - cleanup what was allocated and get out
|
||
|
||
Dns_FreeAuthIdentityCredentials( pauth );
|
||
return( NULL );
|
||
}
|
||
|
||
|
||
|
||
//
|
||
// DNS Credential utilities (unused)
|
||
//
|
||
|
||
DNS_STATUS
|
||
Dns_ImpersonateUser(
|
||
IN PDNS_CREDENTIALS pCreds
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Impersonate a user.
|
||
|
||
Arguments:
|
||
|
||
pCreds -- credentials of user to impersonate
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful
|
||
Error code on failure.
|
||
|
||
--*/
|
||
{
|
||
DNS_STATUS status = NO_ERROR;
|
||
HANDLE htoken;
|
||
|
||
//
|
||
// attempt logon
|
||
//
|
||
|
||
if ( ! LogonUserW(
|
||
pCreds->pUserName,
|
||
pCreds->pDomain,
|
||
pCreds->pPassword,
|
||
LOGON32_LOGON_SERVICE,
|
||
LOGON32_PROVIDER_WINNT50,
|
||
&htoken ) )
|
||
{
|
||
status = GetLastError();
|
||
if ( status == NO_ERROR )
|
||
{
|
||
status = ERROR_CANNOT_IMPERSONATE;
|
||
DNS_ASSERT( FALSE );
|
||
}
|
||
|
||
DNSDBG( SECURITY, (
|
||
"LogonUser() failed => %d\n"
|
||
"\tuser = %S\n"
|
||
"\tdomain = %S\n"
|
||
"\tpassword = %S\n",
|
||
status,
|
||
pCreds->pUserName,
|
||
pCreds->pDomain,
|
||
pCreds->pPassword
|
||
));
|
||
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// impersonate
|
||
//
|
||
|
||
if ( !ImpersonateLoggedOnUser( htoken ) )
|
||
{
|
||
status = GetLastError();
|
||
if ( status == NO_ERROR )
|
||
{
|
||
status = ERROR_CANNOT_IMPERSONATE;
|
||
DNS_ASSERT( FALSE );
|
||
}
|
||
|
||
DNSDBG( SECURITY, (
|
||
"ImpersonateLoggedOnUser() failed = %d\n",
|
||
status ));
|
||
}
|
||
|
||
CloseHandle( htoken );
|
||
|
||
DNSDBG( SECURITY, (
|
||
"%s\n"
|
||
"\tuser = %S\n"
|
||
"\tdomain = %S\n"
|
||
"\tpassword = %S\n",
|
||
(status == NO_ERROR)
|
||
? "Successfully IMPERSONATING!"
|
||
: "Failed IMPERSONATION!",
|
||
pCreds->pUserName,
|
||
pCreds->pDomain,
|
||
pCreds->pPassword ));
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
Dns_FreeCredentials(
|
||
IN PDNS_CREDENTIALS pCreds
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Free DNS credentials.
|
||
|
||
Arguments:
|
||
|
||
pCreds -- credentials to free
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// free subfields, then credentials
|
||
//
|
||
|
||
if ( !pCreds )
|
||
{
|
||
return;
|
||
}
|
||
|
||
if ( pCreds->pUserName )
|
||
{
|
||
FREE_HEAP( pCreds->pUserName );
|
||
}
|
||
if ( pCreds->pDomain )
|
||
{
|
||
FREE_HEAP( pCreds->pDomain );
|
||
}
|
||
if ( pCreds->pPassword )
|
||
{
|
||
FREE_HEAP( pCreds->pPassword );
|
||
}
|
||
FREE_HEAP( pCreds );
|
||
}
|
||
|
||
|
||
|
||
PDNS_CREDENTIALS
|
||
Dns_CopyCredentials(
|
||
IN PDNS_CREDENTIALS pCreds
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Create copy of DNS credentials.
|
||
|
||
Arguments:
|
||
|
||
pCreds -- credentials of user to copy
|
||
|
||
Return Value:
|
||
|
||
Ptr to allocated copy of credentials.
|
||
|
||
--*/
|
||
{
|
||
PDNS_CREDENTIALS pnewCreds = NULL;
|
||
PWSTR pfield;
|
||
|
||
//
|
||
// allocate credentials
|
||
// - copy of subfields
|
||
//
|
||
|
||
pnewCreds = (PDNS_CREDENTIALS) ALLOCATE_HEAP_ZERO( sizeof(*pnewCreds) );
|
||
if ( !pnewCreds )
|
||
{
|
||
return( NULL );
|
||
}
|
||
|
||
pfield = (PWSTR) Dns_CreateStringCopy_W( pCreds->pUserName );
|
||
if ( !pfield )
|
||
{
|
||
goto Failed;
|
||
}
|
||
pnewCreds->pUserName = pfield;
|
||
|
||
pfield = (PWSTR) Dns_CreateStringCopy_W( pCreds->pDomain );
|
||
if ( !pfield )
|
||
{
|
||
goto Failed;
|
||
}
|
||
pnewCreds->pDomain = pfield;
|
||
|
||
pfield = (PWSTR) Dns_CreateStringCopy_W( pCreds->pPassword );
|
||
if ( !pfield )
|
||
{
|
||
goto Failed;
|
||
}
|
||
pnewCreds->pPassword = pfield;
|
||
|
||
return( pnewCreds );
|
||
|
||
Failed:
|
||
|
||
Dns_FreeCredentials( pnewCreds );
|
||
return( NULL );
|
||
}
|
||
|
||
//
|
||
// End secutil.c
|
||
//
|