/* * AclNt.c * * Author: BreenH * * Acl utilities in the NT flavor. */ /* * Includes */ #include "precomp.h" #include "tsutilnt.h" /* * Function Implementations */ NTSTATUS NTAPI NtConvertAbsoluteToSelfRelative( PSECURITY_DESCRIPTOR *ppSelfRelativeSd, PSECURITY_DESCRIPTOR pAbsoluteSd, PULONG pcbSelfRelativeSd ) { #if DBG BOOLEAN fAbsoluteSd; #endif NTSTATUS Status; PSECURITY_DESCRIPTOR pSd; ULONG cbSd; ASSERT(ppSelfRelativeSd != NULL); ASSERT(pAbsoluteSd != NULL); ASSERT(NT_SUCCESS(NtIsSecurityDescriptorAbsolute(pAbsoluteSd, &fAbsoluteSd))); ASSERT(fAbsoluteSd); // // Determine the buffer size needed to convert the security descriptor. // Catch any exceptions due to an invalid descriptor. // cbSd = 0; __try { Status = RtlAbsoluteToSelfRelativeSD( pAbsoluteSd, NULL, &cbSd ); } __except(EXCEPTION_EXECUTE_HANDLER) { return(STATUS_INVALID_SECURITY_DESCR); } // // Allocate memory for the self-relative security descriptor. // pSd = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, cbSd); if (pSd != NULL) { // // Now convert the security descriptor using the allocated buffer. // Catch any exceptions due to an invalid descriptor. // __try { Status = RtlAbsoluteToSelfRelativeSD( pAbsoluteSd, pSd, &cbSd ); } __except(EXCEPTION_EXECUTE_HANDLER) { Status = STATUS_INVALID_SECURITY_DESCR; } } else { return(STATUS_NO_MEMORY); } if (NT_SUCCESS(Status)) { // // If the conversion succeeded, save the pointer to the security // descriptor and return the size. // *ppSelfRelativeSd = pSd; if (pcbSelfRelativeSd != NULL) { *pcbSelfRelativeSd = cbSd; } } else { // // If the conversion failed, free the memory and leave the input // parameters alone. // LocalFree(pSd); } return(Status); } NTSTATUS NTAPI NtConvertSelfRelativeToAbsolute( PSECURITY_DESCRIPTOR *ppAbsoluteSd, PSECURITY_DESCRIPTOR pSelfRelativeSd ) { #if DBG BOOLEAN fAbsoluteSd; #endif NTSTATUS Status; PACL pDacl; PACL pSacl; PSID pGroup; PSID pOwner; PSECURITY_DESCRIPTOR pSd; ULONG cbDacl; ULONG cbGroup; ULONG cbOwner; ULONG cbSacl; ULONG cbSd; ASSERT(ppAbsoluteSd != NULL); ASSERT(pSelfRelativeSd != NULL); ASSERT(NT_SUCCESS(NtIsSecurityDescriptorAbsolute(pSelfRelativeSd, &fAbsoluteSd))); ASSERT(!fAbsoluteSd); // // Determine the size of each buffer needed to convert the security // descriptor. Catch any exceptions due to an invalid descriptor. // cbDacl = 0; cbGroup = 0; cbOwner = 0; cbSacl = 0; cbSd = 0; __try { Status = RtlSelfRelativeToAbsoluteSD( pSelfRelativeSd, NULL, &cbSd, NULL, &cbDacl, NULL, &cbSacl, NULL, &cbOwner, NULL, &cbGroup ); } __except(EXCEPTION_EXECUTE_HANDLER) { return(STATUS_INVALID_SECURITY_DESCR); } // // Allocate memory for the security descriptor and its components. // pDacl = NULL; pGroup = NULL; pOwner = NULL; pSacl = NULL; if (cbDacl > 0) { pDacl = (PACL)LocalAlloc(LMEM_FIXED, cbDacl); if (pDacl == NULL) { Status = STATUS_NO_MEMORY; goto allocerror; } } if (cbGroup > 0) { pGroup = (PSID)LocalAlloc(LMEM_FIXED, cbGroup); if (pGroup == NULL) { Status = STATUS_NO_MEMORY; goto allocerror; } } if (cbOwner > 0) { pOwner = (PSID)LocalAlloc(LMEM_FIXED, cbOwner); if (pOwner == NULL) { Status = STATUS_NO_MEMORY; goto allocerror; } } if (cbSacl > 0) { pSacl = (PACL)LocalAlloc(LMEM_FIXED, cbSacl); if (pSacl == NULL) { Status = STATUS_NO_MEMORY; goto allocerror; } } ASSERT(cbSd > 0); pSd = (PSECURITY_DESCRIPTOR)LocalAlloc(LMEM_FIXED, cbSd); if (pSd == NULL) { Status = STATUS_NO_MEMORY; goto allocerror; } // // Now convert the security descriptor using the allocated buffer. // Catch any exceptions due to an invalid descriptor. // __try { Status = RtlSelfRelativeToAbsoluteSD( pSelfRelativeSd, pSd, &cbSd, pDacl, &cbDacl, pSacl, &cbSacl, pOwner, &cbOwner, pGroup, &cbGroup ); } __except(EXCEPTION_EXECUTE_HANDLER) { Status = STATUS_INVALID_SECURITY_DESCR; } if (NT_SUCCESS(Status)) { *ppAbsoluteSd = pSd; return(Status); } LocalFree(pSd); allocerror: if (pSacl != NULL) { LocalFree(pSacl); } if (pOwner != NULL) { LocalFree(pOwner); } if (pGroup != NULL) { LocalFree(pGroup); } if (pDacl != NULL) { LocalFree(pDacl); } return(Status); } NTSTATUS NTAPI NtDestroySecurityDescriptor( PSECURITY_DESCRIPTOR *ppSd ) { BOOLEAN fAbsolute; NTSTATUS Status; ASSERT(ppSd != NULL); ASSERT(*ppSd != NULL); Status = NtIsSecurityDescriptorAbsolute(*ppSd, &fAbsolute); if (NT_SUCCESS(Status)) { if (fAbsolute) { PISECURITY_DESCRIPTOR pSd; PULONG_PTR pBeginning; PULONG_PTR pDacl; PULONG_PTR pEnd; PULONG_PTR pGroup; PULONG_PTR pOwner; PULONG_PTR pSacl; // // An absolute security descriptor is much more complicated. The // descriptor contains pointers to the other items (instead of // offsets). This does not mean, however, that it is made up of // more than one allocation. In fact, almost all absolute // descriptors from the NT RTL are made of one allocation, with // the internal pointers set to areas of memory inside the one // allocation. This makes completely freeing a security // descriptor a heinous effort. (As an aside, whats the point of // creating an absolute security descriptor out of one chunk of // memory? Just make it relative!) // // Each component of the security descriptor may be NULL. For the // Dacl and the Sacl, the f[D,S]aclPresent variable may be TRUE // with a NULL [D,S]acl. Therefore, compare all pointers to NULL // and against the security descriptor allocation before freeing. // // The check to NtIsSecurityDescriptorAbsolute verifies that this // is a valid security descriptor. Therefore it is safe to type // cast here instead of making several RtlGetXSecurityDescriptor // calls. // pSd = (PISECURITY_DESCRIPTOR)(*ppSd); pBeginning = (PULONG_PTR)(pSd); pEnd = (PULONG_PTR)((PBYTE)pBeginning + LocalSize(pSd)); pDacl = (PULONG_PTR)(pSd->Dacl); pGroup = (PULONG_PTR)(pSd->Group); pOwner = (PULONG_PTR)(pSd->Owner); pSacl = (PULONG_PTR)(pSd->Sacl); // // Handle the Dacl. // if (pDacl != NULL) { if ((pDacl > pEnd) || (pDacl < pBeginning)) { LocalFree(pDacl); } } // // Handle the Group. // if (pGroup != NULL) { if ((pGroup > pEnd) || (pGroup < pBeginning)) { LocalFree(pGroup); } } // // Handle the Owner. // if (pOwner != NULL) { if ((pOwner > pEnd) || (pOwner < pBeginning)) { LocalFree(pOwner); } } // // Handle the Sacl. // if (pSacl != NULL) { if ((pSacl > pEnd) || (pSacl < pBeginning)) { LocalFree(pSacl); } } } } else { return(Status); } // // If the security descriptor was absolute, the individual components // have been freed, and now the security descriptor itself can be freed. // If the security descriptor was self-relative, all the components are // stored in the same block of memory, so free it all at once. // LocalFree(*ppSd); *ppSd = NULL; return(STATUS_SUCCESS); } NTSTATUS NTAPI NtIsSecurityDescriptorAbsolute( PSECURITY_DESCRIPTOR pSd, PBOOLEAN pfAbsolute ) { NTSTATUS Status; ULONG ulRevision; SECURITY_DESCRIPTOR_CONTROL wSdControl; ASSERT(pSd != NULL); ASSERT(pfAbsolute != NULL); Status = RtlGetControlSecurityDescriptor(pSd, &wSdControl, &ulRevision); if (NT_SUCCESS(Status)) { // // Don't cast away the TRUE into a FALSE when dropping from a DWORD // to a UCHAR. // *pfAbsolute = (BOOLEAN)((wSdControl & SE_SELF_RELATIVE) ? TRUE : FALSE); } return(Status); }