You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
805 lines
16 KiB
805 lines
16 KiB
/*++
|
|
|
|
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
|
|
//
|