|
|
//Copyright (c) 1998 - 1999 Microsoft Corporation
/*************************************************************************
* * acl.c * * Generic routines to manage ACL's * * Author: John Richardson 04/25/97 * * *************************************************************************/
/*
* Includes */ #include "stdafx.h"
/*
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
*/
#include <windows.h>
#include <rpc.h>
#include <stdio.h>
#include <process.h>
#include <lmaccess.h>
#include <lmapibuf.h>
#include <lmerr.h>
#undef DBG
#define DBG 1
#define DBGTRACE 1
#define DbgPrint(x)
#if DBG
//ULONG
//DbgPrint(
// PCH Format,
// ...
// );
#define DBGPRINT(x) DbgPrint(x)
#if DBGTRACE
#define TRACE0(x) DbgPrint x
#define TRACE1(x) DbgPrint x
#else
#define TRACE0(x)
#define TRACE1(x)
#endif
#else
#define DBGPRINT(x)
#define TRACE0(x)
#define TRACE1(x)
#endif
/*
* Forward references */ BOOL xxxLookupAccountName( PWCHAR pSystemName, PWCHAR pAccountName, PSID *ppSid );
BOOL SelfRelativeToAbsoluteSD( PSECURITY_DESCRIPTOR SecurityDescriptorIn, PSECURITY_DESCRIPTOR *SecurityDescriptorOut, PULONG ReturnedLength );
/*****************************************************************************
* * AddTerminalServerUserToSD * * Add the given user for the given domain to the security descriptor. * The callers security descriptor may be re-allocated. * * ENTRY: * Param1 (input/output) * Comments * * EXIT: * STATUS_SUCCESS - no error * ****************************************************************************/ BOOL AddTerminalServerUserToSD( PSECURITY_DESCRIPTOR *ppSd, DWORD NewAccess, PACL *ppDacl ) { ULONG i; BOOL Result; BOOL DaclPresent; BOOL DaclDefaulted; DWORD Length; DWORD NewAclLength; PACE_HEADER OldAce; PACE_HEADER NewAce; ACL_SIZE_INFORMATION AclInfo; PSID pSid = NULL; PACL Dacl = NULL; PACL NewDacl = NULL; PACL NewAceDacl = NULL; PSECURITY_DESCRIPTOR NewSD = NULL; PSECURITY_DESCRIPTOR OldSD = NULL; SID_IDENTIFIER_AUTHORITY SepNtAuthority = SECURITY_NT_AUTHORITY;
OldSD = *ppSd;
pSid = LocalAlloc(LMEM_FIXED, 1024); if (!pSid || !InitializeSid(pSid, &SepNtAuthority, 1)) { return( FALSE ); };
*(GetSidSubAuthority(pSid, 0 )) = SECURITY_TERMINAL_SERVER_RID;
/*
* Convert SecurityDescriptor to absolute format. It generates * a new SecurityDescriptor for its output which we must free. */ Result = SelfRelativeToAbsoluteSD( OldSD, &NewSD, NULL ); if ( !Result ) { LOGMESSAGE1(_T("Could not convert to AbsoluteSD %d\n"),GetLastError()); LocalFree( pSid ); return( FALSE ); }
// Must get DACL pointer again from new (absolute) SD
Result = GetSecurityDescriptorDacl( NewSD, &DaclPresent, &Dacl, &DaclDefaulted ); if( !Result ) { LOGMESSAGE1(_T("Could not get Dacl %d\n"),GetLastError()); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); }
//
// If no DACL, no need to add the user since no DACL
// means all accesss
//
if( !DaclPresent ) { LOGMESSAGE2(_T("SD has no DACL, Present %d, Defaulted %d\n"),DaclPresent,DaclDefaulted); LocalFree( pSid ); LocalFree( NewSD ); return( TRUE ); }
//
// Code can return DaclPresent, but a NULL which means
// a NULL Dacl is present. This allows all access to the object.
//
if( Dacl == NULL ) { LOGMESSAGE2(_T("SD has NULL DACL, Present %d, Defaulted %d\n"),DaclPresent,DaclDefaulted); LocalFree( pSid ); LocalFree( NewSD ); return( TRUE ); }
// Get the current ACL's size
Result = GetAclInformation( Dacl, &AclInfo, sizeof(AclInfo), AclSizeInformation ); if( !Result ) { LOGMESSAGE1(_T("Error GetAclInformation %d\n"),GetLastError()); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); }
//
// Create a new ACL to put the new access allowed ACE on
// to get the right structures and sizes.
//
NewAclLength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG) + GetLengthSid( pSid );
NewAceDacl = (PACL) LocalAlloc( LMEM_FIXED, NewAclLength ); if ( NewAceDacl == NULL ) { LOGMESSAGE1(_T("Error LocalAlloc %d bytes\n"),NewAclLength); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); }
Result = InitializeAcl( NewAceDacl, NewAclLength, ACL_REVISION ); if( !Result ) { LOGMESSAGE1(_T("Error Initializing Acl %d\n"),GetLastError()); LocalFree( NewAceDacl ); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); }
Result = AddAccessAllowedAce( NewAceDacl, ACL_REVISION, NewAccess, pSid ); if( !Result ) { LOGMESSAGE1(_T("Error adding Ace %d\n"),GetLastError()); LocalFree( NewAceDacl ); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); }
LOGMESSAGE1(_T("Added 0x%x Access to ACL\n"),NewAccess);
Result = GetAce( NewAceDacl, 0, (void **)&NewAce ); if( !Result ) { LOGMESSAGE1(_T("Error getting Ace %d\n"),GetLastError()); LocalFree( NewAceDacl ); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); }
/* add CONTAINER_INHERIT_ACE TO AceFlags */ NewAce->AceFlags |= CONTAINER_INHERIT_ACE;
/*
* Allocate new DACL and copy existing ACE list */ Length = AclInfo.AclBytesInUse + NewAce->AceSize; NewDacl = (PACL) LocalAlloc( LMEM_FIXED, Length ); if( NewDacl == NULL ) { LOGMESSAGE1(_T("Error LocalAlloc %d bytes\n"),Length); LocalFree( NewAceDacl ); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); }
Result = InitializeAcl( NewDacl, Length, ACL_REVISION ); if( !Result ) { LOGMESSAGE1(_T("Error Initializing Acl %d\n"),GetLastError()); LocalFree( NewDacl ); LocalFree( NewAceDacl ); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); }
/*
* Insert new ACE at the front of the DACL */ Result = AddAce( NewDacl, ACL_REVISION, 0, NewAce, NewAce->AceSize ); if( !Result ) { LOGMESSAGE1(_T("Error Adding New Ace to Acl %d\n"),GetLastError()); LocalFree( NewDacl ); LocalFree( NewAceDacl ); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); }
/*
* Now put the ACE's on the old Dacl to the new Dacl */ for ( i = 0; i < AclInfo.AceCount; i++ ) {
Result = GetAce( Dacl, i, (void **) &OldAce ); if( !Result ) { LOGMESSAGE1(_T("Error getting old Ace from Acl %d\n"),GetLastError()); LocalFree( NewDacl ); LocalFree( NewAceDacl ); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); }
Result = AddAce( NewDacl, ACL_REVISION, i+1, OldAce, OldAce->AceSize ); if( !Result ) { LOGMESSAGE1(_T("Error setting old Ace to Acl %d\n"),GetLastError()); LocalFree( NewDacl ); LocalFree( NewAceDacl ); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); } }
/*
* Set new DACL for Security Descriptor */ Result = SetSecurityDescriptorDacl( NewSD, TRUE, NewDacl, FALSE ); if( !Result ) { LOGMESSAGE1(_T("Error setting New Dacl to SD %d\n"),GetLastError()); LocalFree( NewDacl ); LocalFree( NewAceDacl ); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); }
// the DACL must be passed back so that it can be saved to the registry using the new
// GetNamedSecurityInfo() func.
*ppDacl = Dacl = NewDacl;
// Release the callers old security descriptor
// LocalFree( OldSD );
// There was a bug in W2K such that keys created under our install hive had the
// incorrect DACL headers which caused the DACL to be basically open to all users
// for full control.
// The prolem was due to the wrong SD->Control flag which was NT4 style though ACLs
// were in NT5 style
SetSecurityDescriptorControl(NewSD, SE_DACL_AUTO_INHERIT_REQ|SE_DACL_AUTO_INHERITED, SE_DACL_AUTO_INHERIT_REQ|SE_DACL_AUTO_INHERITED);
*ppSd = NewSD;
// The new SD is in absolute format, so don't free the SID.
// LocalFree( pSid );
return( TRUE ); }
/*****************************************************************************
* * AddUserToSD * * Add the given user for the given domain to the security descriptor. * The callers security descriptor may be re-allocated. * * ENTRY: * Param1 (input/output) * Comments * * EXIT: * STATUS_SUCCESS - no error * ****************************************************************************/
BOOL AddUserToSD( PSECURITY_DESCRIPTOR *ppSd, PWCHAR pAccount, PWCHAR pDomain, DWORD NewAccess ) { ULONG i; BOOL Result; BOOL DaclPresent; BOOL DaclDefaulted; DWORD Length; // NET_API_STATUS Status;
DWORD /*NewAceLength,*/ NewAclLength; PACE_HEADER OldAce; PACE_HEADER NewAce; ACL_SIZE_INFORMATION AclInfo; PWCHAR pDC = NULL; PSID pSid = NULL; PACL Dacl = NULL; PACL NewDacl = NULL; PACL NewAceDacl = NULL; PSECURITY_DESCRIPTOR NewSD = NULL; PSECURITY_DESCRIPTOR OldSD = NULL;
OldSD = *ppSd; /*
// Get our domain controller
Status = NetGetAnyDCName( NULL, // Local computer
pDomain, (LPBYTE*)&pDC ); if( Status != NERR_Success ) { LOGMESSAGE2(_T("SUSERVER: Could not get domain controller %d for domain %ws\n"),Status,pDomain); return( FALSE ); } */ // Get Users SID
Result = xxxLookupAccountName( pDomain, pAccount, &pSid ); if( !Result ) { LOGMESSAGE2(_T("SUSERVER: Could not get users SID %d, %ws\n"),GetLastError(),pAccount); NetApiBufferFree( pDC ); return( FALSE ); }
NetApiBufferFree( pDC );
/*
* Convert SecurityDescriptor to absolute format. It generates * a new SecurityDescriptor for its output which we must free. */ Result = SelfRelativeToAbsoluteSD( OldSD, &NewSD, NULL ); if ( !Result ) { LOGMESSAGE1(_T("Could not convert to AbsoluteSD %d\n"),GetLastError()); LocalFree( pSid ); return( FALSE ); }
// Must get DACL pointer again from new (absolute) SD
Result = GetSecurityDescriptorDacl( NewSD, &DaclPresent, &Dacl, &DaclDefaulted ); if( !Result ) { LOGMESSAGE1(_T("Could not get Dacl %d\n"),GetLastError()); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); }
//
// If no DACL, no need to add the user since no DACL
// means all accesss
//
if( !DaclPresent ) { LOGMESSAGE2(_T("SD has no DACL, Present %d, Defaulted %d\n"),DaclPresent,DaclDefaulted); LocalFree( pSid ); LocalFree( NewSD ); return( TRUE ); }
//
// Code can return DaclPresent, but a NULL which means
// a NULL Dacl is present. This allows all access to the object.
//
if( Dacl == NULL ) { LOGMESSAGE2(_T("SD has NULL DACL, Present %d, Defaulted %d\n"),DaclPresent,DaclDefaulted); LocalFree( pSid ); LocalFree( NewSD ); return( TRUE ); }
// Get the current ACL's size
Result = GetAclInformation( Dacl, &AclInfo, sizeof(AclInfo), AclSizeInformation ); if( !Result ) { LOGMESSAGE1(_T("Error GetAclInformation %d\n"),GetLastError()); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); }
//
// Create a new ACL to put the new access allowed ACE on
// to get the right structures and sizes.
//
NewAclLength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG) + GetLengthSid( pSid );
NewAceDacl = (PACL) LocalAlloc( LMEM_FIXED, NewAclLength ); if ( NewAceDacl == NULL ) { LOGMESSAGE1(_T("Error LocalAlloc %d bytes\n"),NewAclLength); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); }
Result = InitializeAcl( NewAceDacl, NewAclLength, ACL_REVISION ); if( !Result ) { LOGMESSAGE1(_T("Error Initializing Acl %d\n"),GetLastError()); LocalFree( NewAceDacl ); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); }
Result = AddAccessAllowedAce( NewAceDacl, ACL_REVISION, NewAccess, pSid ); if( !Result ) { LOGMESSAGE1(_T("Error adding Ace %d\n"),GetLastError()); LocalFree( NewAceDacl ); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); }
LOGMESSAGE1(_T("Added 0x%x Access to ACL\n"),NewAccess);
Result = GetAce( NewAceDacl, 0, (void **)&NewAce ); if( !Result ) { LOGMESSAGE1(_T("Error getting Ace %d\n"),GetLastError()); LocalFree( NewAceDacl ); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); }
/* add CONTAINER_INHERIT_ACE TO AceFlags */ NewAce->AceFlags |= CONTAINER_INHERIT_ACE;
/*
* Allocate new DACL and copy existing ACE list */ Length = AclInfo.AclBytesInUse + NewAce->AceSize; NewDacl = (PACL) LocalAlloc( LMEM_FIXED, Length ); if( NewDacl == NULL ) { LOGMESSAGE1(_T("Error LocalAlloc %d bytes\n"),Length); LocalFree( NewAceDacl ); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); }
Result = InitializeAcl( NewDacl, Length, ACL_REVISION ); if( !Result ) { LOGMESSAGE1(_T("Error Initializing Acl %d\n"),GetLastError()); LocalFree( NewDacl ); LocalFree( NewAceDacl ); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); }
/*
* Insert new ACE at the front of the DACL */ Result = AddAce( NewDacl, ACL_REVISION, 0, NewAce, NewAce->AceSize ); if( !Result ) { LOGMESSAGE1(_T("Error Adding New Ace to Acl %d\n"),GetLastError()); LocalFree( NewDacl ); LocalFree( NewAceDacl ); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); }
/*
* Now put the ACE's on the old Dacl to the new Dacl */ for ( i = 0; i < AclInfo.AceCount; i++ ) {
Result = GetAce( Dacl, i, (void **) &OldAce ); if( !Result ) { LOGMESSAGE1(_T("Error getting old Ace from Acl %d\n"),GetLastError()); LocalFree( NewDacl ); LocalFree( NewAceDacl ); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); }
Result = AddAce( NewDacl, ACL_REVISION, i+1, OldAce, OldAce->AceSize ); if( !Result ) { LOGMESSAGE1(_T("Error setting old Ace to Acl %d\n"),GetLastError()); LocalFree( NewDacl ); LocalFree( NewAceDacl ); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); } }
/*
* Set new DACL for Security Descriptor */ Result = SetSecurityDescriptorDacl( NewSD, TRUE, NewDacl, FALSE ); if( !Result ) { LOGMESSAGE1(_T("Error setting New Dacl to SD %d\n"),GetLastError()); LocalFree( NewDacl ); LocalFree( NewAceDacl ); LocalFree( pSid ); LocalFree( NewSD ); return( FALSE ); }
Dacl = NewDacl;
// Release the callers old security descriptor
// LocalFree( OldSD );
*ppSd = NewSD;
// The new SD is in absolute format, so don't free the SID.
// LocalFree( pSid );
return( TRUE ); }
/*******************************************************************************
* * SelfRelativeToAbsoluteSD * * Convert a Security Descriptor from self-relative format to absolute. * * ENTRY: * SecurityDescriptorIn (input) * Pointer to self-relative SD to convert * SecurityDescriptorIn (output) * Pointer to location to return absolute SD * ReturnLength (output) * Pointer to location to return length of absolute SD * * EXIT: * ******************************************************************************/
BOOL SelfRelativeToAbsoluteSD( PSECURITY_DESCRIPTOR SecurityDescriptorIn, PSECURITY_DESCRIPTOR *SecurityDescriptorOut, PULONG ReturnedLength ) { BOOL Result; PACL pDacl, pSacl; PSID pOwner, pGroup; PSECURITY_DESCRIPTOR pSD; ULONG SdSize, DaclSize, SaclSize, OwnerSize, GroupSize;
/*
* Determine buffer size needed to convert self-relative SD to absolute. * We use try-except here since if the input security descriptor value * is sufficiently messed up, it is possible for this call to trap. */ SdSize = DaclSize = SaclSize = OwnerSize = GroupSize = 0;
__try { Result = MakeAbsoluteSD( SecurityDescriptorIn, NULL, &SdSize, NULL, &DaclSize, NULL, &SaclSize, NULL, &OwnerSize, NULL, &GroupSize );
} __except( EXCEPTION_EXECUTE_HANDLER ) { SetLastError( ERROR_INVALID_SECURITY_DESCR ); Result = FALSE; }
if ( Result || (GetLastError() != ERROR_INSUFFICIENT_BUFFER) ) { LOGMESSAGE1(_T("SUSERVER: SelfRelativeToAbsoluteSD, Error %d\n"),GetLastError()); return( FALSE ); }
/*
* Allocate memory for the absolute SD and setup various pointers */ pSD = LocalAlloc( LMEM_FIXED, SdSize + DaclSize + SaclSize + OwnerSize + GroupSize ); if ( pSD == NULL ) return( FALSE );
pDacl = (PACL)((PCHAR)pSD + SdSize); pSacl = (PACL)((PCHAR)pDacl + DaclSize); pOwner = (PSID)((PCHAR)pSacl + SaclSize); pGroup = (PSID)((PCHAR)pOwner + OwnerSize);
/*
* Now convert self-relative SD to absolute format. * We use try-except here since if the input security descriptor value * is sufficiently messed up, it is possible for this call to trap. */ __try { Result = MakeAbsoluteSD( SecurityDescriptorIn, pSD, &SdSize, pDacl, &DaclSize, pSacl, &SaclSize, pOwner, &OwnerSize, pGroup, &GroupSize );
} __except( EXCEPTION_EXECUTE_HANDLER ) { SetLastError( ERROR_INVALID_SECURITY_DESCR ); Result = FALSE; }
if ( !Result ) { LOGMESSAGE1(_T("SUSERVER: SelfRelativeToAbsoluteSD, Error %d\n"),GetLastError()); LocalFree( pSD ); return( FALSE ); }
*SecurityDescriptorOut = pSD;
if ( ReturnedLength ) *ReturnedLength = SdSize + DaclSize + SaclSize + OwnerSize + GroupSize;
return( TRUE ); }
/*****************************************************************************
* * xxxLookupAccountName * * Wrapper to lookup the SID for a given account name * * Returns a pointer to the SID in newly allocated memory * * ENTRY: * Param1 (input/output) * Comments * * EXIT: * STATUS_SUCCESS - no error * ****************************************************************************/
BOOL xxxLookupAccountName( PWCHAR pSystemName, PWCHAR pAccountName, PSID *ppSid ) { BOOL rc; DWORD Size, DomainSize, Error; SID_NAME_USE Type; PWCHAR pDomain = NULL; PSID pSid = NULL; WCHAR Buf;
Size = 0; DomainSize = 0;
rc = LookupAccountNameW( pSystemName, pAccountName, &Buf, // pSid
&Size, &Buf, // pDomain
&DomainSize, &Type );
if( rc ) { return( FALSE ); } else { Error = GetLastError(); if( Error != ERROR_INSUFFICIENT_BUFFER ) { return( FALSE ); }
pSid = LocalAlloc( LMEM_FIXED, Size ); if( pSid == NULL ) { return( FALSE ); }
pDomain = (WCHAR *)LocalAlloc( LMEM_FIXED, DomainSize*sizeof(WCHAR) ); if( pDomain == NULL ) { LocalFree( pSid ); return( FALSE ); }
rc = LookupAccountNameW( pSystemName, pAccountName, pSid, &Size, pDomain, &DomainSize, &Type );
if( !rc ) { LocalFree( pSid ); LocalFree( pDomain ); return( FALSE ); }
*ppSid = pSid;
LocalFree( pDomain ); return( TRUE ); } }
|