windows-nt/Source/XPSP1/NT/ds/dns/dnslib/secutil.c

806 lines
15 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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
//