|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1993 - 1995.
//
// File: aclutil.cxx
//
// Contents: utility function(s) for ACL api
//
// History: 8/94 davemont Created
//
//----------------------------------------------------------------------------
#include <aclpch.hxx>
#pragma hdrstop
extern "C" { #include <stdio.h>
#include <permit.h>
#include <dsgetdc.h>
#include <lmapibuf.h>
#include <wmistr.h>
#include <ntprov.hxx>
#include <strings.h>
}
DLLFuncsTable DLLFuncs;
typedef struct _NAME_RID_INFO {
PWSTR pwszName; ULONG Rid;
} NAME_RID_INFO, *PNAME_RID_INFO;
BOOL NameSidLookupInfoLoaded = FALSE; NAME_RID_INFO NameSidLookup[] = { { NULL, DOMAIN_ALIAS_RID_ACCOUNT_OPS }, { NULL, DOMAIN_ALIAS_RID_PRINT_OPS }, { NULL, DOMAIN_ALIAS_RID_SYSTEM_OPS }, { NULL, DOMAIN_ALIAS_RID_POWER_USERS } };
//
// Private functions
//
DWORD AccpLoadLocalizedNameTranslations() { DWORD dwErr = ERROR_SUCCESS; ULONG Value = 0,i; WCHAR wszStringBuffer[ 256];
RtlAcquireResourceExclusive(&gLocalSidCacheLock, TRUE);
if ( !NameSidLookupInfoLoaded ) {
for (i = 0; i < sizeof( NameSidLookup ) / sizeof( NAME_RID_INFO ); i++ ) {
switch ( NameSidLookup[ i ].Rid ) { case DOMAIN_ALIAS_RID_ACCOUNT_OPS: Value = ACCPROV_ACCOUNT_OPS; break;
case DOMAIN_ALIAS_RID_PRINT_OPS: Value = ACCPROV_PRINTER_OPS; break;
case DOMAIN_ALIAS_RID_SYSTEM_OPS: Value = ACCPROV_SYSTEM_OPS; break;
case DOMAIN_ALIAS_RID_POWER_USERS: Value = ACCPROV_POWER_USERS; break; }
if (LoadString(ghDll, Value, wszStringBuffer, sizeof( wszStringBuffer ) / sizeof( WCHAR )) != 0) {
ACC_ALLOC_AND_COPY_STRINGW(wszStringBuffer, NameSidLookup[ i ].pwszName, dwErr ); } else { dwErr = GetLastError(); }
if(dwErr != ERROR_SUCCESS) { break; } }
if(dwErr != ERROR_SUCCESS) { for(i = 0; i< sizeof( NameSidLookup ) / sizeof( NAME_RID_INFO ); i++ ) { LocalFree( NameSidLookup[ i ].pwszName ); NameSidLookup[ i ].pwszName = NULL; } } else { NameSidLookupInfoLoaded = TRUE; }
} RtlReleaseResource( &gLocalSidCacheLock );
return( dwErr ); }
DWORD AccpDoSidLookup(IN PWSTR pwszServer, IN PWSTR pwszName, OUT PSID *ppSid, OUT SID_NAME_USE *pSidType) { #define BASE_DOMAIN_NAME_SIZE 64
#define BASE_SID_SIZE 64
DWORD dwErr = ERROR_SUCCESS; DWORD cusid = BASE_SID_SIZE; DWORD crd = BASE_DOMAIN_NAME_SIZE; SID_NAME_USE esidtype = SidTypeUnknown; WCHAR domainbuf[BASE_DOMAIN_NAME_SIZE]; LPWSTR domain = (LPWSTR)domainbuf;
domainbuf[0] = L'\0'; if (LoadString(ghDll, ACCPROV_NTAUTHORITY, domainbuf, sizeof( domainbuf ) / sizeof( WCHAR )) != 0) {
if(_wcsicmp(pwszServer, domainbuf) == 0) {
pwszServer = NULL; } } else if(_wcsicmp(pwszServer, L"NT AUTHORITY") == 0) {
pwszServer = NULL; }
*ppSid = (PSID)AccAlloc(cusid);
if(*ppSid == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; } else { if(!LookupAccountName(pwszServer, pwszName, *ppSid, &cusid, domain, &crd, &esidtype)) { dwErr = GetLastError();
if(dwErr == ERROR_INSUFFICIENT_BUFFER) { dwErr = ERROR_SUCCESS;
//
// if the rooom for the sid was not big enough,
// grow it.
//
if(cusid > BASE_SID_SIZE) { AccFree(*ppSid); *ppSid = (PSID)AccAlloc(cusid); if (*ppSid == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; } }
if(dwErr == ERROR_SUCCESS) {
if(crd > BASE_DOMAIN_NAME_SIZE) { domain = (LPWSTR)AccAlloc(crd * sizeof(WCHAR)); if (NULL == domain) { AccFree(*ppSid); dwErr = ERROR_NOT_ENOUGH_MEMORY; } }
if(dwErr == ERROR_SUCCESS) { if(!LookupAccountName(pwszServer, pwszName, *ppSid, &cusid, domain, &crd, &esidtype)) { dwErr = GetLastError(); AccFree(*ppSid);
} if(domain != (LPWSTR)domainbuf) { AccFree(domain); } } } } else if(dwErr != ERROR_SUCCESS) { AccFree(*ppSid); *ppSid = NULL; } } else if(dwErr != ERROR_SUCCESS) { AccFree(*ppSid); *ppSid = NULL; } }
return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function : AccLookupAccountSid
//
// Synopsis : returns the SID for the specified trustee
//
// Arguments: [IN pwszServer] -- Name of the server to remote the
// call to
// [IN pName] -- the name to lookup the SID for
// [OUT ppwszName] -- Where the name is returned
// [OUT pSidType] -- Where the SID type is returned
//
// Returns: ERROR_SUCCESS -- Success
// ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed.
// ERROR_INVALID_PARAMETER -- The trustee form was bad
//
//----------------------------------------------------------------------------
DWORD AccLookupAccountSid(IN PWSTR pwszServer, IN PTRUSTEE pName, OUT PSID *ppsid, OUT SID_NAME_USE *pSidType) {
#define BASE_DOMAIN_NAME_SIZE 64
#define BASE_SID_SIZE 64
DWORD dwErr = ERROR_SUCCESS; DWORD cusid = BASE_SID_SIZE; DWORD crd = BASE_DOMAIN_NAME_SIZE; SID_NAME_USE esidtype = SidTypeUnknown; WCHAR domainbuf[BASE_DOMAIN_NAME_SIZE]; LPWSTR domain = (LPWSTR)domainbuf; PWSTR pwszSep; PWSTR pwszTempName;
if(pName->TrusteeForm == TRUSTEE_IS_SID) { //
// Trustee is of form TRUSTEE_IS_SID
//
*ppsid = (PSID) AccAlloc( GetLengthSid((PSID)pName->ptstrName) ); if (*ppsid != NULL) { if (!CopySid( GetLengthSid((PSID)pName->ptstrName), *ppsid, (PSID)pName->ptstrName)) { dwErr = GetLastError(); AccFree(*ppsid); *ppsid = NULL; } } else { dwErr = ERROR_NOT_ENOUGH_MEMORY; } } else if(pName->TrusteeForm == TRUSTEE_IS_NAME) { //
// Trustee is of form TRUSTEE_IS_NAME.
//
//
// Check for CURRENT_USER (in which case we get the name from
// the token)
//
if(_wcsicmp(pName->ptstrName, L"CURRENT_USER") == 0) {
HANDLE token_handle;
dwErr = GetCurrentToken( &token_handle );
//
// if we have a token, get the user SID from it
//
if(dwErr == ERROR_SUCCESS) { dwErr = AccGetSidFromToken(pwszServer, token_handle, TokenUser, ppsid); CloseHandle(token_handle); } } else { //
// if not current user, we have to do a name lookup
// first allocate a default sid (so the name lookup is not
// always performed twice.)
//
*ppsid = (PSID)AccAlloc(cusid);
if(*ppsid != NULL) { if(!LookupAccountName(pwszServer, pName->ptstrName, *ppsid, &cusid, domain, &crd, &esidtype)) { dwErr = GetLastError(); if(dwErr == ERROR_INSUFFICIENT_BUFFER) { dwErr = ERROR_SUCCESS;
//
// if the rooom for the sid was not big enough,
// grow it.
//
if(cusid > BASE_SID_SIZE) { AccFree(*ppsid); *ppsid = (PSID)AccAlloc(cusid); if (*ppsid == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; } }
if(dwErr == ERROR_SUCCESS) {
if(crd > BASE_DOMAIN_NAME_SIZE) { domain = (LPWSTR)AccAlloc(crd * sizeof(WCHAR)); if (NULL == domain) { AccFree(*ppsid); *ppsid = NULL; dwErr = ERROR_NOT_ENOUGH_MEMORY; } }
if(dwErr == ERROR_SUCCESS) { if(!LookupAccountName(pwszServer, pName->ptstrName, *ppsid, &cusid, domain, &crd, &esidtype)) { dwErr = GetLastError(); AccFree(*ppsid); *ppsid = NULL; }
if(crd > BASE_DOMAIN_NAME_SIZE) { AccFree(domain); } } } } else { //
// See if is a translation of a known name
//
dwErr = AccpLoadLocalizedNameTranslations();
*ppsid = NULL;
if(dwErr == ERROR_SUCCESS) {
//
// Check our well known sids
//
static SID_IDENTIFIER_AUTHORITY UaspBuiltinAuthority = SECURITY_NT_AUTHORITY; DWORD BuiltSid[sizeof(SID)/sizeof(DWORD) + 2 ]; PSID pSid = (PSID)BuiltSid; RtlInitializeSid( pSid, &UaspBuiltinAuthority, 1 );
*(RtlSubAuthoritySid(pSid, 0)) = SECURITY_BUILTIN_DOMAIN_RID;
for( ULONG i = 0; i < sizeof( NameSidLookup ) / sizeof( NAME_RID_INFO ); i++ ) { if ( _wcsicmp( pName->ptstrName, NameSidLookup[ i ].pwszName ) == 0) { *(RtlSubAuthoritySid(pSid, 1)) = NameSidLookup[ i ].Rid; break; } }
if ( i == sizeof( NameSidLookup ) / sizeof( NAME_RID_INFO ) ) {
pSid = NULL; } else { dwErr = ERROR_SUCCESS; ACC_ALLOC_AND_COPY_SID(pSid, *ppsid, dwErr); }
} //
// See if we have a server name specified in the user name
// when we didn't have one provided.
//
if(pwszServer == NULL) {
ACC_ALLOC_AND_COPY_STRINGW(pName->ptstrName, pwszTempName, dwErr );
if(dwErr == ERROR_SUCCESS) {
pwszSep = wcschr(pwszTempName, L'\\');
if(pwszSep != NULL) { *pwszSep = L'\0';
dwErr = AccpDoSidLookup(pwszTempName, pwszSep + 1, ppsid, pSidType);
if(dwErr != ERROR_SUCCESS) { //
// Ok, may that was a domain name instead of a
// server name
//
PDOMAIN_CONTROLLER_INFOW pDCI = NULL; dwErr = DsGetDcNameW(NULL, pwszTempName, NULL, NULL, 0, &pDCI); if(dwErr == ERROR_SUCCESS) { dwErr = AccpDoSidLookup( pDCI[0].DomainControllerAddress, pwszSep + 1, ppsid, pSidType );
NetApiBufferFree(pDCI); }
}
}
LocalFree(pwszTempName); } }
//
// If for any reason we haven't converted it, go ahead and
// dump it as a string.
//
if(*ppsid == NULL) { dwErr = ConvertStringToSid(pName->ptstrName, ppsid); } } } } else { dwErr = ERROR_NOT_ENOUGH_MEMORY; } } } else { //
// Trustee is not of known form
//
dwErr = ERROR_INVALID_PARAMETER; }
if(dwErr == ERROR_SUCCESS) { *pSidType = esidtype; }
return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function : AccGetSidFromToken
//
// Synopsis : Gets the SID from the given token handle
//
// Arguments: IN pwszServer -- Name of server to remote the
// call to
// IN [hToken] -- Token handle
// IN [TIC] -- Token information class
// OUT [ppSidFromToken]-- Where the SID is returned
//
// Returns: ERROR_SUCCESS -- Everything worked
// ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
//
//----------------------------------------------------------------------------
DWORD AccGetSidFromToken(IN PWSTR pwszServer, IN HANDLE hToken, IN TOKEN_INFORMATION_CLASS TIC, IN PSID *ppSidFromToken) { DWORD dwErr = ERROR_SUCCESS;
ULONG cSize; BYTE bBuf[64];
PTOKEN_USER pTknUsr = (TOKEN_USER *)bBuf;
if(GetTokenInformation(hToken, TIC, pTknUsr, sizeof(bBuf), &cSize) == FALSE) { dwErr = GetLastError();
if(dwErr == ERROR_INSUFFICIENT_BUFFER) { dwErr = ERROR_SUCCESS;
pTknUsr = (PTOKEN_USER)AccAlloc(cSize); if(pTknUsr == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; } else { //
// Now, call it again...
//
if(GetTokenInformation(hToken, TIC, pTknUsr, sizeof(bBuf), &cSize) == FALSE) { dwErr = GetLastError();
//
// deallocate our buffer here, since noone else
// will
//
AccFree(pTknUsr); } } } }
//
// One way or another, we got the token info, so we'll grab the
// sid
//
if(dwErr == ERROR_SUCCESS) { //
// allocate room for the returned sid
//
ULONG cSidSize = RtlLengthSid(pTknUsr->User.Sid); *ppSidFromToken = (PSID)AccAlloc(cSidSize); if(*ppSidFromToken == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; } else { //
// and copy the new sid
//
NTSTATUS Status = RtlCopySid(cSidSize, *ppSidFromToken, pTknUsr->User.Sid); if(!NT_SUCCESS(Status)) { dwErr = RtlNtStatusToDosError(Status); AccFree(*ppSidFromToken); *ppSidFromToken = NULL; } }
//
// See if we had to allocate
//
if(pTknUsr != (PTOKEN_USER)bBuf) { AccFree(pTknUsr); }
}
return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function : AccLookupAccountTrustee
//
// Synopsis : returns the TRUSTEE for the specified sid
//
// Arguments: [IN pwszServer] -- The server to remote the call to
// OUT [pTrustee] -- the returned trustee
// IN [pSid] -- the SID
//
// Returns: ERROR_SUCCESS -- Everything worked
// ERROR_NOT_ENOUGH_MEMORY A memory allocation failed
//
//----------------------------------------------------------------------------
DWORD AccLookupAccountTrustee(IN PWSTR pwszServer, IN PSID pSid, OUT PTRUSTEE *ppTrustee) { #define BASE_TRUSTEE_NAME_SIZE 256
acDebugOut((DEB_TRACE_ACC, "in AccLookupAccountTrustee \n"));
PWSTR pwszName; PWSTR pwszDomain; SID_NAME_USE SidType;
DWORD dwErr = AccLookupAccountName(pwszServer, pSid, &pwszName, &pwszDomain, &SidType); if(dwErr == ERROR_SUCCESS) { PTRUSTEE pTrustee; LPWSTR pName;
pTrustee = (PTRUSTEE) AccAlloc(sizeof(TRUSTEE) + SIZE_PWSTR(pwszName)); if(pTrustee != NULL) { pName = (LPWSTR) ((PBYTE)pTrustee + sizeof(TRUSTEE)); CopyMemory(pName, pwszName, SIZE_PWSTR(pwszName));
pTrustee->pMultipleTrustee = NULL; pTrustee->MultipleTrusteeOperation = NO_MULTIPLE_TRUSTEE; pTrustee->TrusteeForm = TRUSTEE_IS_NAME; pTrustee->TrusteeType = TRUSTEE_IS_UNKNOWN; pTrustee->ptstrName = pName; *ppTrustee = pTrustee;
if(SidType == SidTypeUnknown) { pTrustee->TrusteeType = TRUSTEE_IS_UNKNOWN; } else { pTrustee->TrusteeType = (TRUSTEE_TYPE)(SidType); } } else { dwErr = ERROR_NOT_ENOUGH_MEMORY; }
AccFree(pwszName); AccFree(pwszDomain); }
acDebugOut((DEB_TRACE_ACC, "out AccLookupAccountTrustee:%lu\n", dwErr));
return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function : AccLookupAccountName
//
// Synopsis : Returns the name for the given SID
//
// Arguments: [IN pwszServer] -- The name of the server to remote
// the call to.
// [IN pSid] -- the SID to lookup the name for
// [OUT ppwszName] -- Where the name is returned
// [OUT pSidType] -- Where the SID type is returned
//
// Returns: ERROR_SUCCESS -- Success
// ERROR_NOT_ENOUGH_MEMORY -- A memory allocation failed.
//
//----------------------------------------------------------------------------
DWORD AccLookupAccountName(IN PWSTR pwszServer, IN PSID pSid, OUT LPWSTR *ppwszName, OUT LPWSTR *ppwszDomain, OUT SID_NAME_USE *pSidType) { #define BASE_TRUSTEE_NAME_SIZE 256
acDebugOut((DEB_TRACE_ACC,"in AccLookupAccountName\n"));
DWORD dwErr = ERROR_SUCCESS; SID_NAME_USE esidtype = SidTypeUnknown; LPWSTR pwszDomain = NULL; LPWSTR pwszName = NULL; ULONG cName = 0; ULONG cDomain = 0;
DebugDumpSid("AccLookupAccountName", pSid);
if(LookupAccountSid(pwszServer, pSid, NULL, &cName, NULL, &cDomain, &esidtype) == FALSE) { pwszName = NULL; dwErr = GetLastError();
if(dwErr == ERROR_INSUFFICIENT_BUFFER) { dwErr = ERROR_SUCCESS;
//
// Allocate for the name and the domain
//
pwszName = (PWSTR)AccAlloc(cName * sizeof(WCHAR)); if(pwszName != NULL) { pwszDomain = (PWSTR)AccAlloc(cDomain * sizeof(WCHAR)); if(pwszDomain == NULL) { AccFree(pwszName); pwszName = NULL; } }
if(pwszName == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; }
if(dwErr == ERROR_SUCCESS) { if(LookupAccountSid(pwszServer, pSid, pwszName, &cName, pwszDomain, &cDomain, &esidtype) == FALSE) { dwErr = GetLastError(); AccFree(pwszName); pwszName = NULL; AccFree(pwszDomain); pwszDomain = NULL; } } } else // if(dwErr == ERROR_NONE_MAPPED)
{ dwErr = AccpLoadLocalizedNameTranslations();
if(dwErr == ERROR_SUCCESS) {
//
// Check our well known sids
//
static SID_IDENTIFIER_AUTHORITY UaspBuiltinAuthority = SECURITY_NT_AUTHORITY; DWORD BuiltSid[sizeof(SID)/sizeof(DWORD) + 2 ]; PSID pKnownSid = (PSID)BuiltSid; RtlInitializeSid( pKnownSid, &UaspBuiltinAuthority, 1 );
*(RtlSubAuthoritySid(pKnownSid, 0)) = SECURITY_BUILTIN_DOMAIN_RID;
for( ULONG i = 0;i < sizeof( NameSidLookup ) / sizeof( NAME_RID_INFO ); i++) { *(RtlSubAuthoritySid(pKnownSid, 1)) = NameSidLookup[ i ].Rid; if ( RtlEqualSid( pKnownSid, pSid ) == TRUE ) { ACC_ALLOC_AND_COPY_STRINGW(NameSidLookup[ i ].pwszName, pwszName, dwErr); break; } } }
//
// If it isn't someone we recognize, convert it to a string..
//
if(dwErr == ERROR_SUCCESS && pwszName == NULL) { //
// Ok, return the sid as a name
//
UCHAR String[256]; UNICODE_STRING SidStr; SidStr.Buffer = (PWSTR)String; SidStr.Length = SidStr.MaximumLength = 256;
NTSTATUS Status = RtlConvertSidToUnicodeString(&SidStr, pSid, FALSE); if(NT_SUCCESS(Status)) { ACC_ALLOC_AND_COPY_STRINGW(SidStr.Buffer, pwszName, dwErr); } else { dwErr = RtlNtStatusToDosError(Status); } } } }
if(dwErr == ERROR_SUCCESS) { #if 1
//
// Convert to RDN
//
*ppwszName = pwszName; *ppwszDomain = pwszDomain; *pSidType = esidtype;
ULONG cLen = wcslen(pwszName); if(pwszDomain != NULL && *pwszDomain != L'\0') { cLen += wcslen(pwszDomain) + 1; }
if(cLen != wcslen(pwszName)) { cLen++; PWSTR pwszFullName = (PWSTR)AccAlloc(cLen * sizeof(WCHAR)); if(pwszFullName == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; } else { swprintf(pwszFullName, L"%ws\\%ws", pwszDomain, pwszName); AccFree(pwszName); pwszName = NULL; *ppwszName = pwszFullName; } } AccFree(pwszDomain); pwszDomain = NULL; *ppwszDomain = NULL;
#else
dwErr = Nt4NameToNt5Name(pwszName, pwszDomain, ppwszName);
if(dwErr == ERROR_SUCCESS) { AccFree(pwszName); *ppwszDomain = pwszDomain; *pSidType = esidtype; } #endif
}
if(dwErr != ERROR_SUCCESS) { AccFree(pwszDomain); AccFree(pwszName); }
acDebugOut((DEB_TRACE_ACC,"Out AccLookupAccountName: %lu\n", dwErr));
return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function : GetDesiredAccess
//
// Synopsis : Gets the access required to open object to be able to set or
// get the specified security info.
//
// Arguments: IN [SecurityOpenType] - Flag indicating if the object is to be
// opened to read or write the DACL
//
//----------------------------------------------------------------------------
ACCESS_MASK GetDesiredAccess(IN SECURITY_OPEN_TYPE OpenType, IN SECURITY_INFORMATION SecurityInfo) { acDebugOut((DEB_TRACE_ACC, "in GetDesiredAccess \n"));
ACCESS_MASK DesiredAccess = 0;
if ( (SecurityInfo & OWNER_SECURITY_INFORMATION) || (SecurityInfo & GROUP_SECURITY_INFORMATION) ) { switch (OpenType) { case READ_ACCESS_RIGHTS: DesiredAccess |= READ_CONTROL; break; case WRITE_ACCESS_RIGHTS: DesiredAccess |= WRITE_OWNER; break; case MODIFY_ACCESS_RIGHTS: DesiredAccess |= READ_CONTROL | WRITE_OWNER; break; } }
if (SecurityInfo & DACL_SECURITY_INFORMATION) { switch (OpenType) { case READ_ACCESS_RIGHTS: DesiredAccess |= READ_CONTROL; break; case WRITE_ACCESS_RIGHTS: DesiredAccess |= WRITE_DAC; break; case MODIFY_ACCESS_RIGHTS: DesiredAccess |= READ_CONTROL | WRITE_DAC; break; } }
if (SecurityInfo & SACL_SECURITY_INFORMATION) { DesiredAccess |= ACCESS_SYSTEM_SECURITY; }
acDebugOut((DEB_TRACE_ACC, "out GetDesiredAccess: %lu\n", DesiredAccess));
return (DesiredAccess); }
//+---------------------------------------------------------------------------
//
// Function : GetSecurityDescriptorParts
//
// Synopsis : extracts the specified components of a security descriptor
// It is the responsibility of the invoker to free (using AccFree)
// any acquired security components.
//
// Arguments: IN [pSecurityDescriptor] - the input security descriptor
// IN [SecurityInfo] - flag indicating what security info to return
// OUT [psidOwner] - the (optional) returned owner sid
// OUT [psidGroup] - the (optional) returned group sid
// OUT [pDacl] - the (optional) returned DACL
// OUT [pSacl] - the (optional) returned SACL
//
// Returns:
//
//----------------------------------------------------------------------------
DWORD GetSecurityDescriptorParts( IN PISECURITY_DESCRIPTOR pSecurityDescriptor, IN SECURITY_INFORMATION SecurityInfo, OUT PSID *psidOwner, OUT PSID *psidGroup, OUT PACL *pDacl, OUT PACL *pSacl, OUT PSECURITY_DESCRIPTOR *pOutSecurityDescriptor) { acDebugOut((DEB_TRACE_ACC, "in GetSecurityDescriptorParts\n")); NTSTATUS Status; DWORD dwErr = ERROR_SUCCESS;
//
// if no security descriptor found, don't return one!
//
if(psidOwner) { *psidOwner = NULL; }
if(psidGroup) { *psidGroup = NULL; }
if(pDacl) { *pDacl = NULL; }
if(pSacl) { *pSacl = NULL; }
*pOutSecurityDescriptor = NULL;
if(pSecurityDescriptor) { PSID owner = NULL, group = NULL; PACL dacl = NULL, sacl = NULL; ULONG cSize = sizeof(SECURITY_DESCRIPTOR); BOOLEAN bDummy, bParmPresent = FALSE; PISECURITY_DESCRIPTOR pOutSD;
//
// if the security descriptor is self relative, get absolute
// pointers to the components
//
Status = RtlGetOwnerSecurityDescriptor(pSecurityDescriptor, &owner, &bDummy); if(NT_SUCCESS(Status)) { Status = RtlGetGroupSecurityDescriptor(pSecurityDescriptor, &group, &bDummy); }
if(NT_SUCCESS(Status)) { Status = RtlGetDaclSecurityDescriptor(pSecurityDescriptor, &bParmPresent, &dacl, &bDummy); if(NT_SUCCESS(Status) && !bParmPresent) { dacl = NULL; } }
if(NT_SUCCESS(Status)) { Status = RtlGetSaclSecurityDescriptor(pSecurityDescriptor, &bParmPresent, &sacl, &bDummy); if(NT_SUCCESS(Status) && !bParmPresent) { sacl = NULL; } }
if(NT_SUCCESS(Status)) { //
// Build the new security descriptor
//
cSize = RtlLengthSecurityDescriptor( pSecurityDescriptor ) + sizeof(SECURITY_DESCRIPTOR) - sizeof(SECURITY_DESCRIPTOR_RELATIVE);
pOutSD = (PISECURITY_DESCRIPTOR)AccAlloc(cSize); if(pOutSD == NULL) { return(ERROR_NOT_ENOUGH_MEMORY); }
RtlCreateSecurityDescriptor(pOutSD, SECURITY_DESCRIPTOR_REVISION);
void *bufptr = Add2Ptr(pOutSD, sizeof(SECURITY_DESCRIPTOR));
if(SecurityInfo & OWNER_SECURITY_INFORMATION) { if(NULL != owner) { //
// no error checking as these should not fail!!
//
RtlCopySid(RtlLengthSid(owner), (PSID)bufptr, owner); RtlSetOwnerSecurityDescriptor(pOutSD, (PSID)bufptr, FALSE); bufptr = Add2Ptr(bufptr,RtlLengthSid(owner)); if(psidOwner) { *psidOwner = pOutSD->Owner; } } else { AccFree(pOutSD); return(ERROR_NO_SECURITY_ON_OBJECT); } }
if(SecurityInfo & GROUP_SECURITY_INFORMATION) { if(NULL != group) { //
// no error checking as these should not fail!!
//
RtlCopySid(RtlLengthSid(group), (PSID)bufptr, group); RtlSetGroupSecurityDescriptor(pOutSD, (PSID)bufptr, FALSE); bufptr = Add2Ptr(bufptr,RtlLengthSid(group)); if(psidGroup) { *psidGroup = pOutSD->Group; } } else { AccFree(pOutSD); return(ERROR_NO_SECURITY_ON_OBJECT); } }
//
// The DACL and SACL may or may not be on the object.
//
if(SecurityInfo & DACL_SECURITY_INFORMATION) { if(NULL != dacl) { RtlCopyMemory(bufptr, dacl, dacl->AclSize); RtlSetDaclSecurityDescriptor(pOutSD, TRUE, (ACL *)bufptr, FALSE); if(pDacl) { *pDacl = pOutSD->Dacl; } } }
if(SecurityInfo & SACL_SECURITY_INFORMATION) { if(NULL != sacl) { RtlCopyMemory(bufptr, sacl, sacl->AclSize); RtlSetSaclSecurityDescriptor(pOutSD, TRUE, (PACL)bufptr, FALSE); if(pSacl) { *pSacl = pOutSD->Sacl; } } }
*pOutSecurityDescriptor = pOutSD; }
if(!NT_SUCCESS(Status)) { dwErr = RtlNtStatusToDosError(Status); } } acDebugOut((DEB_TRACE_ACC, "Out GetSecurityDescriptorParts(%d)\n", dwErr)); return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function : ParseName
//
// Synopsis : parses a UNC name for the machine name
//
// Arguments: [IN OUT pObjectName] -- the name of the object
// [OUT pMachineName] -- the machine the object is on
// [OUT pRemainingName] -- the remaining name after the
// machine name
//
// Returns: ERROR_SUCCESS -- The call succeeded
//
//----------------------------------------------------------------------------
DWORD ParseName(IN OUT LPWSTR pObjectName, OUT LPWSTR *pMachineName, OUT LPWSTR *pRemainingName) { acDebugOut((DEB_TRACE_ACC, "in/out ParseName \n"));
if(pObjectName == wcsstr(pObjectName, L"\\\\")) { *pMachineName = pObjectName + 2; *pRemainingName = wcschr(*pMachineName, L'\\'); if (*pRemainingName != NULL) { **pRemainingName = L'\0'; *pRemainingName += 1; } } else { *pMachineName = NULL; *pRemainingName = pObjectName; }
return(ERROR_SUCCESS); }
//+---------------------------------------------------------------------------
//
// Function: DoTrusteesMatch
//
// Synopsis: Determines if 2 trustess reference the same thing (ie:
// (are they equal)
//
// Arguments: [IN pwszServer] -- Server to lookup information on
// [IN pTrustee1] -- First trustee
// [IN pTrustee2] -- Second trustee
// [OUT pfMatch] -- Where the match results are
// returned.
//
// Returns: ERROR_SUCCESS -- The operation succeeded
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD DoTrusteesMatch(IN PWSTR pwszServer, IN PTRUSTEE pTrustee1, IN PTRUSTEE pTrustee2, IN PBOOL pfMatch) { DWORD dwErr = ERROR_SUCCESS;
//
// Assume failure...
//
*pfMatch = FALSE;
//
// Make sure they are the same type...
//
if(pTrustee1->MultipleTrusteeOperation == pTrustee2->MultipleTrusteeOperation) { //
// Ok, first compare the base trustee information...
//
if(pTrustee1->TrusteeForm == pTrustee2->TrusteeForm) { //
// Now, the trustee form... If they match, it's easy... Otherwise,
// we'll have to do some lookups...
//
if(pTrustee1->TrusteeForm == pTrustee2->TrusteeForm) { if(pTrustee1->TrusteeForm == TRUSTEE_IS_NAME) { if(_wcsicmp(pTrustee1->ptstrName, pTrustee2->ptstrName) == 0) { *pfMatch = TRUE; } } else { *pfMatch = RtlEqualSid((PSID)(pTrustee1->ptstrName), (PSID)(pTrustee2->ptstrName)); } } } else { //
// We'll look it up...
//
PSID pKnownSid; PTRUSTEE pLookupTrustee; if(pTrustee1->TrusteeForm == TRUSTEE_IS_NAME) { pLookupTrustee = pTrustee1; pKnownSid = (PSID)pTrustee2->ptstrName; } else { pLookupTrustee = pTrustee2; pKnownSid = (PSID)pTrustee1->ptstrName; }
PSID pNewSid; SID_NAME_USE SidType; dwErr = AccctrlLookupSid(pwszServer, pLookupTrustee->ptstrName, TRUE, &pNewSid, &SidType); if(dwErr == ERROR_SUCCESS) { *pfMatch = RtlEqualSid(pKnownSid, pNewSid); AccFree(pNewSid); } }
//
// Now, if that worked, look for the multiple trustee case
//
if(dwErr == ERROR_SUCCESS && *pfMatch == TRUE && pTrustee1->MultipleTrusteeOperation == TRUSTEE_IS_IMPERSONATE) { dwErr = DoTrusteesMatch(pwszServer, pTrustee1->pMultipleTrustee, pTrustee2->pMultipleTrustee, pfMatch); } } return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function: AccessMaskForAccessEntry
//
// Synopsis: Converts a Provider Independent access entry to an NT
// access mask format.
//
// Arguments: [IN pAE] -- The access entry that gets
// converted
//
// Returns: Converted acess mask
//
// Notes:
//
//----------------------------------------------------------------------------
ACCESS_MASK AccessMaskForAccessEntry(IN PACTRL_ACCESS_ENTRY pAE, IN SE_OBJECT_TYPE ObjType) { ACCESS_MASK RetMask = 0;
//
// We have some standard rights, so we'll add those in
//
if((pAE->Access & (ACTRL_STD_RIGHTS_ALL)) != 0) { RetMask = (pAE->Access & ACTRL_STD_RIGHTS_ALL) >> 11; }
if((pAE->Access & (ACTRL_SYSTEM_ACCESS)) != 0) { RetMask |= ACCESS_SYSTEM_SECURITY; }
//
// Then, we or in the rest of the access bits, plus the provider specific
// bits.
//
RetMask |= (pAE->Access & ~(ACTRL_STD_RIGHTS_ALL | ACTRL_SYSTEM_ACCESS)); RetMask |= pAE->ProvSpecificAccess;
//
// Handle any special case stuff here
//
switch (ObjType) { case SE_FILE_OBJECT: case SE_SERVICE: case SE_PRINTER: case SE_REGISTRY_KEY: case SE_LMSHARE: case SE_KERNEL_OBJECT: case SE_WINDOW_OBJECT: case SE_DS_OBJECT: case SE_DS_OBJECT_ALL: default: break; }
return(RetMask); }
//+---------------------------------------------------------------------------
//
// Function: AccConvertAccessMaskToActrlAccess
//
// Synopsis: Converts an NT access mask to the appropriate Provider
// Independent format.
//
// Arguments: [IN Access] -- Access mask to convert
// [IN ObjType] -- Type of the object
// [IN KernelObjectType] If this is a kernel object, the type of the
// object
// [IN pAE] -- The access entry that gets
// modified
//
// Returns: VOID
//
// Notes:
//
//----------------------------------------------------------------------------
VOID AccConvertAccessMaskToActrlAccess(IN ACCESS_MASK Access, IN SE_OBJECT_TYPE ObjType, IN MARTA_KERNEL_TYPE KernelObjectType, IN PACTRL_ACCESS_ENTRY pAE) {
//
// Ok, first thing we'll have to do is look for and remove any generic
// rights.
//
GENERIC_MAPPING GenMap = {0, 0, 0, 0}; switch(ObjType) { case SE_FILE_OBJECT: case SE_LMSHARE: GenMap.GenericRead = FILE_GENERIC_READ; GenMap.GenericWrite = FILE_GENERIC_WRITE; GenMap.GenericExecute = FILE_GENERIC_EXECUTE; GenMap.GenericAll = FILE_ALL_ACCESS; break;
case SE_SERVICE: GenMap.GenericRead = STANDARD_RIGHTS_READ | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_INTERROGATE;
GenMap.GenericWrite = STANDARD_RIGHTS_WRITE | SERVICE_CHANGE_CONFIG;
GenMap.GenericExecute = STANDARD_RIGHTS_EXECUTE | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_USER_DEFINED_CONTROL;
GenMap.GenericAll = SERVICE_ALL_ACCESS; break;
case SE_PRINTER: GenMap.GenericRead = PRINTER_READ; GenMap.GenericWrite = PRINTER_WRITE; GenMap.GenericExecute = PRINTER_EXECUTE; GenMap.GenericAll = PRINTER_ALL_ACCESS; break;
case SE_REGISTRY_KEY: GenMap.GenericRead = KEY_READ; GenMap.GenericWrite = KEY_WRITE; GenMap.GenericExecute = KEY_EXECUTE; GenMap.GenericAll = KEY_ALL_ACCESS; break;
case SE_KERNEL_OBJECT: switch ( KernelObjectType ) { // case MARTA_WMI_GUID:
// GenMap.GenericRead = WMIGUID_QUERY;
// GenMap.GenericWrite = WMIGUID_SET;
// GenMap.GenericExecute = WMIGUID_EXECUTE;
// GenMap.GenericAll = WMIGUID_QUERY | WMIGUID_SET | WMIGUID_EXECUTE;
// break;
case MARTA_EVENT: case MARTA_EVENT_PAIR: case MARTA_MUTANT: case MARTA_PROCESS: case MARTA_SECTION: case MARTA_SEMAPHORE: case MARTA_SYMBOLIC_LINK: case MARTA_THREAD: case MARTA_TIMER: case MARTA_JOB: default: GenMap.GenericRead = STANDARD_RIGHTS_READ | 0x1; GenMap.GenericWrite = STANDARD_RIGHTS_WRITE | 0x2; GenMap.GenericExecute = STANDARD_RIGHTS_EXECUTE | 0x4; GenMap.GenericAll = STANDARD_RIGHTS_REQUIRED | 0xFFFF; break;
} break;
case SE_WINDOW_OBJECT: GenMap.GenericRead = STANDARD_RIGHTS_READ | 0x1; GenMap.GenericWrite = STANDARD_RIGHTS_WRITE | 0x2; GenMap.GenericExecute = STANDARD_RIGHTS_EXECUTE | 0x4; GenMap.GenericAll = STANDARD_RIGHTS_REQUIRED | 0x1FF; break;
case SE_DS_OBJECT: case SE_DS_OBJECT_ALL: GenMap.GenericRead = GENERIC_READ_MAPPING; GenMap.GenericWrite = GENERIC_WRITE_MAPPING; GenMap.GenericExecute = GENERIC_EXECUTE_MAPPING; GenMap.GenericAll = GENERIC_ALL_MAPPING; break; }
MapGenericMask(&Access, &GenMap);
//
// Look for the known entries first
//
if((Access & STANDARD_RIGHTS_ALL) != 0) { pAE->Access = (Access & STANDARD_RIGHTS_ALL) << 11; }
if((Access & ACCESS_SYSTEM_SECURITY) != 0) { pAE->Access |= ACTRL_SYSTEM_ACCESS; }
//
// Add in the remaining rights
//
pAE->Access |= (Access & ~(STANDARD_RIGHTS_ALL | ACCESS_SYSTEM_SECURITY ));
}
//+---------------------------------------------------------------------------
//
// Function: LoadDLLFuncTable
//
// Synopsis:
//
// Arguments:
//+---------------------------------------------------------------------------
DWORD LoadDLLFuncTable() { DWORD dwErr;
if( !(DLLFuncs.dwFlags & LOADED_ALL_FUNCS)) { HINSTANCE NetApiHandle = NULL; HINSTANCE SamLibHandle = NULL; HINSTANCE WinspoolHandle = NULL;
//
// Load the functions needed from netapi32.dll
//
NetApiHandle = LoadLibraryA( "NetApi32" ); if(NetApiHandle == NULL) { dwErr = GetLastError(); return (dwErr); }
DLLFuncs.PNetApiBufferFree = (PNET_API_BUFFER_FREE) GetProcAddress( NetApiHandle, "NetApiBufferFree"); if(DLLFuncs.PNetApiBufferFree == NULL) { dwErr = GetLastError(); return (dwErr); }
DLLFuncs.PNetShareGetInfo = (PNET_SHARE_GET_INFO) GetProcAddress( NetApiHandle, "NetShareGetInfo"); if(DLLFuncs.PNetShareGetInfo == NULL) { dwErr = GetLastError(); return (dwErr); }
DLLFuncs.PNetShareSetInfo = (PNET_SHARE_SET_INFO) GetProcAddress( NetApiHandle, "NetShareSetInfo"); if(DLLFuncs.PNetShareSetInfo == NULL) { dwErr = GetLastError(); return (dwErr); }
DLLFuncs.PNetDfsGetInfo = (PNET_DFS_GET_INFO) GetProcAddress( NetApiHandle, "NetDfsGetInfo"); if(DLLFuncs.PNetDfsGetInfo == NULL) { dwErr = GetLastError(); return (dwErr); }
DLLFuncs.PI_NetGetDCList = (PINET_GET_DC_LIST) GetProcAddress( NetApiHandle, "I_NetGetDCList"); if(DLLFuncs.PI_NetGetDCList == NULL) { dwErr = GetLastError(); return (dwErr); }
//
// Load the functions needed from samlib.dll
//
SamLibHandle = LoadLibraryA( "Samlib" ); if(SamLibHandle == NULL) { dwErr = GetLastError(); return (dwErr); }
DLLFuncs.PSamCloseHandle = (PSAM_CLOSE_HANDLE) GetProcAddress( SamLibHandle, "SamCloseHandle"); if(DLLFuncs.PSamCloseHandle == NULL) { dwErr = GetLastError(); return (dwErr); }
DLLFuncs.PSamOpenDomain = (PSAM_OPEN_DOMAIN) GetProcAddress( SamLibHandle, "SamOpenDomain"); if(DLLFuncs.PSamOpenDomain == NULL) { dwErr = GetLastError(); return (dwErr); }
DLLFuncs.PSamConnect = (PSAM_CONNECT) GetProcAddress( SamLibHandle, "SamConnect"); if(DLLFuncs.PSamConnect == NULL) { dwErr = GetLastError(); return (dwErr); }
DLLFuncs.PSamGetMembersInGroup = (PSAM_GET_MEMBERS_IN_GROUP) GetProcAddress( SamLibHandle, "SamGetMembersInGroup"); if(DLLFuncs.PSamGetMembersInGroup == NULL) { dwErr = GetLastError(); return (dwErr); }
DLLFuncs.PSamOpenGroup = (PSAM_OPEN_GROUP) GetProcAddress( SamLibHandle, "SamOpenGroup"); if(DLLFuncs.PSamOpenGroup == NULL) { dwErr = GetLastError(); return (dwErr); }
DLLFuncs.PSamGetMembersInAlias = (PSAM_GET_MEMBERS_IN_ALIAS) GetProcAddress( SamLibHandle, "SamGetMembersInAlias"); if(DLLFuncs.PSamGetMembersInAlias == NULL) { dwErr = GetLastError(); return (dwErr); }
DLLFuncs.PSamOpenAlias = (PSAM_OPEN_ALIAS) GetProcAddress( SamLibHandle, "SamOpenAlias"); if(DLLFuncs.PSamOpenAlias == NULL) { dwErr = GetLastError(); return (dwErr); }
//
// Load functions from winspool.drv
//
WinspoolHandle = LoadLibraryA( "winspool.drv" ); if(WinspoolHandle == NULL) { dwErr = GetLastError(); return (dwErr); }
DLLFuncs.POpenPrinter = (POPEN_PRINTER) GetProcAddress( WinspoolHandle, "OpenPrinterW"); if(DLLFuncs.POpenPrinter == NULL) { dwErr = GetLastError(); return (dwErr); }
DLLFuncs.PClosePrinter = (PCLOSE_PRINTER) GetProcAddress( WinspoolHandle, "ClosePrinter"); if(DLLFuncs.PClosePrinter == NULL) { dwErr = GetLastError(); return (dwErr); }
DLLFuncs.PSetPrinter = (PSET_PRINTER) GetProcAddress( WinspoolHandle, "SetPrinterW"); if(DLLFuncs.PSetPrinter == NULL) { dwErr = GetLastError(); return (dwErr); }
DLLFuncs.PGetPrinter = (PGET_PRINTER) GetProcAddress( WinspoolHandle, "GetPrinterW"); if(DLLFuncs.PGetPrinter == NULL) { dwErr = GetLastError(); return (dwErr); }
DLLFuncs.dwFlags |= LOADED_ALL_FUNCS; }
return (NO_ERROR); }
//+---------------------------------------------------------------------------
//
// Function: AccSetEntriesInAList
//
// Synopsis: Helper function. Adds the given access entries to an optional
// existing list, and returns the resultant list
//
// Arguments: [IN cEntries] -- Number of items to add
// [IN pAccessEntryList] List to add
// [IN AccessMode] -- How to do the add (MERGE or SET)
// [IN lpProperty] -- Property to do the add for
// [IN fDoOldStyleMerge] If TRUE, does an NT4 ACLAPI style
// merge (Existing explicit entries are
// removed). Otherwise, and new style
// merge is done.
// [IN pOldList] -- Optional. If present, the new items
// are merged with this list [assuming a
// merge operation].
// [OUT ppNewList] -- Where the new list is returned.
//
// Returns: ERROR_SUCCESS -- Success
// ERROR_INVALID_PARAMETER A bad parameter was given
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD AccSetEntriesInAList(IN ULONG cEntries, IN PACTRL_ACCESS_ENTRYW pAccessEntryList, IN ACCESS_MODE AccessMode, IN SECURITY_INFORMATION SeInfo, IN LPCWSTR lpProperty, IN BOOL fDoOldStyleMerge, IN PACTRL_AUDITW pOldList, OUT PACTRL_AUDITW *ppNewList) { DWORD dwErr = ERROR_SUCCESS;
//
// First, a little parameter validation...
//
if(pAccessEntryList == NULL || ppNewList == NULL || (SeInfo != SACL_SECURITY_INFORMATION && SeInfo != DACL_SECURITY_INFORMATION)) { dwErr = ERROR_INVALID_PARAMETER; } else { CAccessList AccList; dwErr = AccList.SetObjectType(SE_UNKNOWN_OBJECT_TYPE);
if(dwErr == ERROR_SUCCESS) { if(pOldList != NULL && AccessMode != SET_ACCESS) { dwErr = AccList.AddAccessLists(SeInfo, pOldList, FALSE); } }
if(dwErr == ERROR_SUCCESS) { //
// We need to build a ACTRL_ALIST
//
ACTRL_ACCESSW AList; ACTRL_PROPERTY_ENTRY APE; ACTRL_ACCESS_ENTRY_LIST AAEL;
AAEL.cEntries = cEntries; AAEL.pAccessList = pAccessEntryList;
APE.lpProperty = (PWSTR)lpProperty; APE.pAccessEntryList = &(AAEL); APE.fListFlags = 0;
AList.cEntries = 1; AList.pPropertyAccessList = &APE;
//
// Now, we'll just do another add...
//
if(AccessMode == REVOKE_ACCESS) { dwErr = AccList.RevokeTrusteeAccess(SeInfo, &AList, (PWSTR)lpProperty); } else { dwErr = AccList.AddAccessLists(SeInfo, &AList, AccessMode == GRANT_ACCESS ? TRUE : FALSE, fDoOldStyleMerge);
} }
//
// If all of that worked, we'll simply marshal it up, and return it
//
if(dwErr == ERROR_SUCCESS) { dwErr = AccList.MarshalAccessLists( SeInfo, FLAG_ON(SeInfo, DACL_SECURITY_INFORMATION) ? ppNewList : NULL, FLAG_ON(SeInfo, SACL_SECURITY_INFORMATION) ? ppNewList : NULL); } }
return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function: AccConvertAccessToSecurityDescriptor
//
// Synopsis: Helper function. Converts a set of access lists and owner/
// group into a security descriptor. Only items that are present
// are added.
//
// Arguments: [IN pAccessList] -- OPTIONAL. Access list to convert
// [IN pAuditList] -- OPTIONAL. Audit list to add
// [IN lpOwner] -- OPTIONAL. Owner to add
// [IN lpGroup] -- OPTIONAL. Group to add
// [OUT ppSecDescriptor] Where the created security descriptor
// is returned.
//
// Returns: ERROR_SUCCESS -- Success
// ERROR_INVALID_PARAMETER A bad parameter was given
//
// Notes: The returned security descriptor must be freed via LocalFree
//
//----------------------------------------------------------------------------
DWORD AccConvertAccessToSecurityDescriptor(IN PACTRL_ACCESSW pAccessList, IN PACTRL_AUDITW pAuditList, IN LPCWSTR lpOwner, IN LPCWSTR lpGroup, OUT PSECURITY_DESCRIPTOR *ppSecDescriptor) { DWORD dwErr = ERROR_SUCCESS;
//
// First, verify the parameters. At least one has to be present
//
if(pAccessList == NULL && pAuditList == NULL && lpOwner == NULL && lpGroup == NULL) { dwErr = ERROR_INVALID_PARAMETER; } else { //
// Initialize our access lists
//
CAccessList AccList;
TRUSTEE_W Group; TRUSTEE_W Owner;
dwErr = AccList.SetObjectType(SE_UNKNOWN_OBJECT_TYPE);
if(dwErr == ERROR_SUCCESS && lpGroup != NULL) { memset(&Group, 0, sizeof(TRUSTEE_W)); Group.TrusteeForm = TRUSTEE_IS_NAME; Group.ptstrName = (PWSTR)lpGroup; dwErr = AccList.AddOwnerGroup(GROUP_SECURITY_INFORMATION, NULL, &Group);
}
if(dwErr == ERROR_SUCCESS && lpOwner) { memset(&Owner, 0, sizeof(TRUSTEE_W)); Owner.TrusteeForm = TRUSTEE_IS_NAME; Owner.ptstrName = (PWSTR)lpOwner; dwErr = AccList.AddOwnerGroup(OWNER_SECURITY_INFORMATION, &Owner, NULL); }
if(dwErr == ERROR_SUCCESS && pAccessList != NULL) { dwErr = AccList.AddAccessLists(DACL_SECURITY_INFORMATION, pAccessList, FALSE); }
if(dwErr == ERROR_SUCCESS && pAuditList != NULL) { dwErr = AccList.AddAccessLists(SACL_SECURITY_INFORMATION, pAuditList, FALSE); }
//
// Now, build the Security Descriptor
//
if(dwErr == ERROR_SUCCESS) { SECURITY_INFORMATION SeInfo; dwErr = AccList.BuildSDForAccessList(ppSecDescriptor, &SeInfo, ACCLIST_SD_ABSOK | ACCLIST_SD_NOFREE); } }
return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function: AccConvertSDToAccess
//
// Synopsis: Helper function. "Cracks" a security descriptor into the
// associated access lists and owner/group. Only the OUT
// parameters that are supplied will be cracked
//
// Arguments: [IN ObjectType] -- What type of object the security
// descriptor came from
// [IN pSecDescriptor]-- Security descriptor to crack
// [OUT ppAccessList] -- OPTIONAL. Where the access list is
// returned.
// [OUT ppAuditList] -- OPTIONAL. Where the audit list is
// returned
// [OUT lppOwner] -- OPTIONAL. Where the owner is returned
// [OUT lppGroup] -- OPTIONAL. Where the group is returned
//
// Returns: ERROR_SUCCESS -- Success
// ERROR_INVALID_PARAMETER A bad parameter was given
//
// Notes: The returned items must be freed via LocalFree
//
//----------------------------------------------------------------------------
DWORD AccConvertSDToAccess(IN SE_OBJECT_TYPE ObjectType, IN PSECURITY_DESCRIPTOR pSecDescriptor, OUT PACTRL_ACCESSW *ppAccessList, OUT PACTRL_AUDITW *ppAuditList, OUT LPWSTR *lppOwner, OUT LPWSTR *lppGroup) { DWORD dwErr = ERROR_SUCCESS;
//
// Make sure we have valid parameters
//
if(pSecDescriptor == NULL || ObjectType == SE_UNKNOWN_OBJECT_TYPE) { dwErr = ERROR_INVALID_PARAMETER; } else { //
// Make sure we have something to do
//
SECURITY_INFORMATION SeInfo = 0;
if(ppAccessList != NULL) { SeInfo |= DACL_SECURITY_INFORMATION; }
if(ppAuditList != NULL) { SeInfo |= SACL_SECURITY_INFORMATION; }
if(lppOwner != NULL) { SeInfo |= OWNER_SECURITY_INFORMATION; }
if(lppGroup != NULL) { SeInfo |= GROUP_SECURITY_INFORMATION; }
if(SeInfo != 0) { CAccessList AccList;
dwErr = AccList.SetObjectType(ObjectType);
if(dwErr == ERROR_SUCCESS) { dwErr = AccList.AddSD(pSecDescriptor, SeInfo, NULL);
//
// Now, build our individual lists from it...
//
if(dwErr == ERROR_SUCCESS) { dwErr = AccList.MarshalAccessLists(SeInfo, ppAccessList, ppAuditList);
if(dwErr == ERROR_SUCCESS) { //
// Save off the strings
//
if(FLAG_ON(SeInfo, OWNER_SECURITY_INFORMATION)) { PTRUSTEE_W pOwner;
dwErr = AccList.GetSDSidAsTrustee( OWNER_SECURITY_INFORMATION, &pOwner); if(dwErr == ERROR_SUCCESS) { ACC_ALLOC_AND_COPY_STRINGW( pOwner->ptstrName, *lppOwner, dwErr); AccFree(pOwner); } }
if(FLAG_ON(SeInfo, GROUP_SECURITY_INFORMATION)) { PTRUSTEE_W pGroup;
dwErr = AccList.GetSDSidAsTrustee( GROUP_SECURITY_INFORMATION, &pGroup); if(dwErr == ERROR_SUCCESS) { ACC_ALLOC_AND_COPY_STRINGW( pGroup->ptstrName, *lppGroup, dwErr); AccFree(pGroup); }
if(dwErr != ERROR_SUCCESS && FLAG_ON(SeInfo, OWNER_SECURITY_INFORMATION)) { AccFree(*lppOwner); } }
if(dwErr != ERROR_SUCCESS) { if(FLAG_ON(SeInfo, DACL_SECURITY_INFORMATION)) { AccFree(ppAccessList); }
if(FLAG_ON(SeInfo, SACL_SECURITY_INFORMATION)) { AccFree(ppAuditList); } } } } } } }
return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function: AccGetAccessForTrustee
//
// Synopsis: Helper function. Determines the access/audits for the
// given trustee
//
// Arguments: [IN pTrustee] -- Trustee to check access for
// [IN pAcl] -- Acl to get information from
// [IN SeInfo] -- Whether to handle this as an access or
// audit list
// [IN pwszProperty] -- Property on the acl to use
// [OUT pAllowed] -- Where the allowed/success mask is
// returned
// [OUT pDenied] -- Where the denied/failure mask is
// returned
//
// Returns: ERROR_SUCCESS -- Success
// ERROR_INVALID_PARAMETER A bad parameter was given
//
// Notes: The returned items must be freed via LocalFree
//
//----------------------------------------------------------------------------
DWORD AccGetAccessForTrustee(IN PTRUSTEE pTrustee, IN PACL pAcl, IN SECURITY_INFORMATION SeInfo, IN PWSTR pwszProperty, IN PACCESS_RIGHTS pAllowed, IN PACCESS_RIGHTS pDenied) { DWORD dwErr = ERROR_SUCCESS;
//
// Ok, first, initialize our access list
//
CAccessList AccList;
PACL pDAcl = NULL, pSAcl = NULL;
if(FLAG_ON(SeInfo, DACL_SECURITY_INFORMATION)) { pDAcl = pAcl; } else { pSAcl = pAcl; }
if(dwErr == ERROR_SUCCESS) { dwErr = AccList.AddAcl(pDAcl, pSAcl, NULL, NULL, SeInfo, NULL, TRUE); }
if(dwErr == ERROR_SUCCESS) { //
// Now, get the rights..
//
if(FLAG_ON(SeInfo, DACL_SECURITY_INFORMATION)) { dwErr = AccList.GetExplicitAccess(pTrustee, pwszProperty, pDenied, pAllowed); } else { dwErr = AccList.GetExplicitAudits(pTrustee, pwszProperty, pDenied, pAllowed); } }
return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function: AccConvertAclToAccess
//
// Synopsis: Helper function. Converts an ACL into access lists
//
// Arguments: [IN ObjectType] -- Type of object the acl came from
// [IN pAcl] -- Acl to convert
// [OUT ppAccessList] -- Where to return the access list
//
// Returns: ERROR_SUCCESS -- Success
// ERROR_INVALID_PARAMETER A bad parameter was given
//
// Notes: The returned items must be freed via LocalFree
//
//----------------------------------------------------------------------------
DWORD AccConvertAclToAccess(IN SE_OBJECT_TYPE ObjectType, IN PACL pAcl, OUT PACTRL_ACCESSW *ppAccessList) { DWORD dwErr = ERROR_SUCCESS;
//
// Make sure we have valid parameters
//
if(pAcl == NULL) { dwErr = ERROR_INVALID_PARAMETER; } else { CAccessList AccList;
dwErr = AccList.SetObjectType(ObjectType);
if(dwErr == ERROR_SUCCESS) { dwErr = AccList.AddAcl(pAcl, NULL, NULL, NULL, DACL_SECURITY_INFORMATION, NULL, TRUE);
//
// Now, build our individual lists from it...
//
if(dwErr == ERROR_SUCCESS) { dwErr = AccList.MarshalAccessLists(DACL_SECURITY_INFORMATION, ppAccessList, NULL); } } }
return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function: AccConvertAccessToSD
//
// Synopsis: Helper function. Converts a set of access lists and owner/
// group into a security descriptor.
//
// Arguments: [IN ObjectType] -- Type of object to add
// [IN SeInfo] -- Items being set in the SD
// [IN pAccessList] -- OPTIONAL. Access list to convert
// [IN pAuditList] -- OPTIONAL. Audit list to add
// [IN lpOwner] -- OPTIONAL. Owner to add
// [IN lpGroup] -- OPTIONAL. Group to add
// [IN fOpts] -- Options to use when building the SD
// [OUT ppSecDescriptor] Where the created security descriptor
// is returned.
// [OUT pcSDSize] -- Where the size of the security descriptor
// is returned
//
// Returns: ERROR_SUCCESS -- Success
// ERROR_INVALID_PARAMETER A bad parameter was given
//
// Notes: The returned security descriptor must be freed via LocalFree
//
//----------------------------------------------------------------------------
DWORD AccConvertAccessToSD(IN SE_OBJECT_TYPE ObjectType, IN SECURITY_INFORMATION SeInfo, IN PACTRL_ACCESSW pAccessList, IN PACTRL_AUDITW pAuditList, IN LPWSTR lpOwner, IN LPWSTR lpGroup, IN ULONG fOpts, OUT PSECURITY_DESCRIPTOR *ppSD, OUT PULONG pcSDSize) { DWORD dwErr = ERROR_SUCCESS;
//
// First, verify the parameters.
//
if(ObjectType > SE_PROVIDER_DEFINED_OBJECT || ppSD == NULL || pcSDSize == NULL) { dwErr = ERROR_INVALID_PARAMETER; } else { //
// Verify that we have the proper parameters for our SecurityInfo
//
if(FLAG_ON(SeInfo, DACL_SECURITY_INFORMATION) && pAccessList == NULL) { dwErr = ERROR_INVALID_PARAMETER; }
if(FLAG_ON(SeInfo, SACL_SECURITY_INFORMATION) && pAuditList == NULL) { dwErr = ERROR_INVALID_PARAMETER; }
if(FLAG_ON(SeInfo, GROUP_SECURITY_INFORMATION) && lpGroup == NULL) { dwErr = ERROR_INVALID_PARAMETER; }
if(FLAG_ON(SeInfo, OWNER_SECURITY_INFORMATION) && lpOwner == NULL) { dwErr = ERROR_INVALID_PARAMETER; } }
//
// If we have valid parameters, go do it...
//
if(dwErr == ERROR_SUCCESS) { //
// Initialize our access lists
//
CAccessList AccList;
TRUSTEE_W Group; TRUSTEE_W Owner;
dwErr = AccList.SetObjectType(ObjectType);
if(dwErr == ERROR_SUCCESS && lpGroup != NULL) { memset(&Group, 0, sizeof(TRUSTEE_W)); Group.TrusteeForm = TRUSTEE_IS_NAME; Group.ptstrName = (PWSTR)lpGroup; dwErr = AccList.AddOwnerGroup(GROUP_SECURITY_INFORMATION, NULL, &Group);
}
if(dwErr == ERROR_SUCCESS && lpOwner) { memset(&Owner, 0, sizeof(TRUSTEE_W)); Owner.TrusteeForm = TRUSTEE_IS_NAME; Owner.ptstrName = (PWSTR)lpOwner; dwErr = AccList.AddOwnerGroup(OWNER_SECURITY_INFORMATION, &Owner, NULL); }
if(dwErr == ERROR_SUCCESS && pAccessList != NULL) { dwErr = AccList.AddAccessLists(DACL_SECURITY_INFORMATION, pAccessList, FALSE); }
if(dwErr == ERROR_SUCCESS && pAuditList != NULL) { dwErr = AccList.AddAccessLists(SACL_SECURITY_INFORMATION, pAuditList, FALSE); }
//
// Now, build the Security Descriptor
//
if(dwErr == ERROR_SUCCESS) { SECURITY_INFORMATION LocalSeInfo; dwErr = AccList.BuildSDForAccessList(ppSD, &LocalSeInfo, ACCLIST_SD_NOFREE | FLAG_ON(fOpts, ACCCONVERT_SELF_RELATIVE) ? 0 : ACCLIST_SD_ABSOK );
if(dwErr == ERROR_SUCCESS) { *pcSDSize = AccList.QuerySDSize(); } } }
return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function: AccGetExplicitEntries
//
// Synopsis: Helper function. Gets the list of explicit entries for
// the given trustee from the acl.
//
// Arguments: [IN pTrustee] -- Trustee to get the list for
// [IN ObjectType] -- Type of object the acl came from
// [IN pAcl] -- Acl to examine
// [IN pwszProperty] -- Which acl property to examine
// [OUT pcEntries] -- Where the count of entries is returned
// [OUT ppAEList] -- Where the list of explicit entries
// is returned.
//
// Returns: ERROR_SUCCESS -- Success
// ERROR_INVALID_PARAMETER A bad parameter was given
//
// Notes: The returned list must be freed via LocalFree
//
//----------------------------------------------------------------------------
DWORD AccGetExplicitEntries(IN PTRUSTEE pTrustee, IN SE_OBJECT_TYPE ObjectType, IN PACL pAcl, IN PWSTR pwszProperty, OUT PULONG pcEntries, OUT PACTRL_ACCESS_ENTRYW *ppAEList) { DWORD dwErr = ERROR_SUCCESS;
//
// Make sure we have valid parameters
//
if(pAcl == NULL) { dwErr = ERROR_INVALID_PARAMETER; } else { CAccessList AccList;
dwErr = AccList.SetObjectType(ObjectType);
if(dwErr == ERROR_SUCCESS) { dwErr = AccList.AddAcl(pAcl, NULL, NULL, NULL, DACL_SECURITY_INFORMATION, NULL, TRUE);
//
// Now, build our individual lists from it...
//
if(dwErr == ERROR_SUCCESS) { dwErr = AccList.GetExplicitEntries(pTrustee, pwszProperty, DACL_SECURITY_INFORMATION, pcEntries, ppAEList); } } }
return(dwErr); return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function: ConvertStringToSid
//
// Synopsis: Converts a string representation of a SID back into a SID.
// This is the converse of RtlConvertSidToUnicode. If a non-
// SID string is given, an error is returned.
//
// Arguments: [IN pwszString] -- String to convert
// [OUT ppSid] -- Where the convertd sid is returned
//
// Returns: ERROR_SUCCESS -- Success
// ERROR_INVALID_PARAMETER A bad parameter was given
// ERROR_NONE_MAPPED -- The given string does not represent
// a SID
//
// Notes: The returned sid must be freed via LocalFree
//
//----------------------------------------------------------------------------
DWORD ConvertStringToSid(IN PWSTR pwszString, OUT PSID *ppSid) { DWORD dwErr = ERROR_SUCCESS;
if(wcslen(pwszString) < 2 || (*pwszString != L'S' && *(pwszString + 1) != L'-')) { return(ERROR_NONE_MAPPED); }
acDebugOut((DEB_TRACE_SID, "Converting %ws to sid\n", pwszString));
UCHAR Revision; UCHAR cSubs; SID_IDENTIFIER_AUTHORITY IDAuth; PULONG pSubAuth = NULL; PWSTR pwszEnd;
PWSTR pwszCurr = pwszString + 2;
Revision = (UCHAR)wcstol(pwszCurr, &pwszEnd, 10);
pwszCurr = pwszEnd + 1;
//
// Count the number of characters in the indentifer authority...
//
PWSTR pwszNext = wcschr(pwszCurr, L'-');
if(pwszNext - pwszCurr == 6) { for(ULONG iIndex = 0; iIndex < 6; iIndex++) { IDAuth.Value[iIndex] = (UCHAR)pwszNext[iIndex]; }
pwszCurr +=6; } else { IDAuth.Value[0] = IDAuth.Value[1] = 0; ULONG Auto = wcstoul(pwszCurr, &pwszEnd, 10); IDAuth.Value[5] = (UCHAR)Auto & 0xF; IDAuth.Value[4] = (UCHAR)((Auto >> 8) & 0xFF); IDAuth.Value[3] = (UCHAR)((Auto >> 16) & 0xFF); IDAuth.Value[2] = (UCHAR)((Auto >> 24) & 0xFF); pwszCurr = pwszEnd; }
pwszCurr++;
//
// Now, count the number of sub auths
//
cSubs = 0; pwszNext = pwszCurr;
if(pwszCurr != NULL) { cSubs++; }
while(TRUE) { pwszNext = wcschr(pwszNext,'-'); if(pwszNext == NULL || *(pwszNext + 1) == L'\0') { break; } pwszNext++; cSubs++; }
if(cSubs != 0) { pSubAuth = (PULONG)AccAlloc(cSubs * sizeof(ULONG)); if(pSubAuth == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; } else { for(ULONG iIndex = 0; iIndex < cSubs; iIndex++) { pSubAuth[iIndex] = wcstoul(pwszCurr, &pwszEnd, 10); pwszCurr = pwszEnd + 1; } } } else { dwErr = ERROR_NONE_MAPPED; }
//
// Now, create the SID
//
if(dwErr == ERROR_SUCCESS) { *ppSid = (PSID)AccAlloc(sizeof(SID) + cSubs * sizeof(ULONG)); if(*ppSid == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; } else { PISID pSid = (PISID)*ppSid; pSid->Revision = Revision; pSid->SubAuthorityCount = cSubs; memcpy(&(pSid->IdentifierAuthority), &IDAuth, sizeof(SID_IDENTIFIER_AUTHORITY)); memcpy(pSid->SubAuthority, pSubAuth, cSubs * sizeof(ULONG));
#if DBG
UNICODE_STRING SidString; NTSTATUS Status = RtlConvertSidToUnicodeString(&SidString, pSid, TRUE); if(!NT_SUCCESS(Status)) { acDebugOut((DEB_TRACE_SID, "Can't convert sid to string: 0x%lx\n", Status)); } else { acDebugOut((DEB_TRACE_SID, "Converted sid: %wZ\n", &SidString)); RtlFreeUnicodeString(&SidString); }
if(FLAG_ON(acInfoLevel, DEB_TRACE_SID)) { DebugBreak(); } #endif
} }
AccFree(pSubAuth);
return(dwErr); }
//+---------------------------------------------------------------------------
//
// Function: GetCurrentToken
//
// Synopsis: Gets the token from the current thread, if possible, or the
// process.
//
// Arguments: [IN pHandle] -- Where the token is returned
//
// Returns: ERROR_SUCCESS -- Success
//
// Notes:
//
//----------------------------------------------------------------------------
DWORD GetCurrentToken( OUT HANDLE *pHandle ) { DWORD dwErr = ERROR_SUCCESS;
//
// see if a thread token exists
//
if(!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, TRUE, pHandle)) { dwErr = GetLastError();
//
// if not, use the process token
//
if(dwErr == ERROR_NO_TOKEN) { dwErr = ERROR_SUCCESS; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, pHandle)) { dwErr = GetLastError(); } } }
return( dwErr ); }
|