|
|
#include "priv.h"
#pragma hdrstop
//---------------------------------------------------------------------------
// GetUserToken - Gets the current process's user token and returns
// it. It can later be free'd with LocalFree.
//
// REARCHITECT (reinerf) - stolen from shell32\securent.c, we should consolidate
// the code somewhere and export it
//---------------------------------------------------------------------------
PTOKEN_USER GetUserToken(HANDLE hUser) { PTOKEN_USER pUser; DWORD dwSize = 64; HANDLE hToClose = NULL;
if (hUser == NULL) { OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hUser); hToClose = hUser; }
pUser = (PTOKEN_USER)LocalAlloc(LPTR, dwSize); if (pUser) { DWORD dwNewSize; BOOL fOk = GetTokenInformation(hUser, TokenUser, pUser, dwSize, &dwNewSize); if (!fOk && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) { LocalFree((HLOCAL)pUser);
pUser = (PTOKEN_USER)LocalAlloc(LPTR, dwNewSize); if (pUser) { fOk = GetTokenInformation(hUser, TokenUser, pUser, dwNewSize, &dwNewSize); } } if (!fOk) { LocalFree((HLOCAL)pUser); pUser = NULL; } }
if (hToClose) { CloseHandle(hToClose); }
return pUser; }
//
// checks to see if the SHELL_USER_SID is all zeros (flag which means we should really use the users current sid)
//
__inline BOOL IsCurrentUserShellSID(PSHELL_USER_SID psusID) { SID_IDENTIFIER_AUTHORITY sidNULL = {0};
if ((psusID->dwUserGroupID == 0) && (psusID->dwUserID == 0) && memcmp(&psusID->sidAuthority, &sidNULL, sizeof(SID_IDENTIFIER_AUTHORITY)) == 0) { return TRUE; }
return FALSE; }
//
// Sets the specified ACE in the ACL to have dwAccessMask permissions.
//
__inline BOOL MakeACEInheritable(PACL pAcl, int iIndex, DWORD dwAccessMask) { ACE_HEADER* pAceHeader;
if (GetAce(pAcl, iIndex, (LPVOID*)&pAceHeader)) { pAceHeader->AceFlags |= dwAccessMask; return TRUE; }
return FALSE; }
//
// Helper function to generate a SECURITY_DESCRIPTOR with the specified rights
//
// OUT: psd - A pointer to a uninitialized SECURITY_DESCRIPTOR struct to be inited and filled in
// in by this function
//
// IN: PSHELL_USER_PERMISSION - An array of PSHELL_USER_PERMISSION pointers that specify what access to grant
// cUserPerm - The count of PSHELL_USER_PERMISSION pointers in the array above
//
//
STDAPI_(SECURITY_DESCRIPTOR*) GetShellSecurityDescriptor(PSHELL_USER_PERMISSION* apUserPerm, int cUserPerm) { BOOL fSuccess = TRUE; // assume success
SECURITY_DESCRIPTOR* pSD = NULL; PSID* apSids = NULL; int cAces = cUserPerm; // one ACE for each entry to start with
int iAceIndex = 0; // helps us keep count of how many ACE's we have added (count as we go)
PTOKEN_USER pUserToken = NULL; DWORD cbSidLength = 0; DWORD cbAcl; PACL pAcl; int i;
ASSERT(!IsBadReadPtr(apUserPerm, sizeof(PSHELL_USER_PERMISSION) * cUserPerm));
// healthy parameter checking
if (!apUserPerm || cUserPerm <= 0) { return NULL; }
// first find out how many additional ACE's we are going to need
// because of inheritance
for (i = 0; i < cUserPerm; i++) { if (apUserPerm[i]->fInherit) { cAces++; }
// also check to see if any of these are using susCurrentUser, in which case
// we want to get the users token now so we have it already
if ((pUserToken == NULL) && IsCurrentUserShellSID(&apUserPerm[i]->susID)) { pUserToken = GetUserToken(NULL); if (!pUserToken) { DWORD dwLastError = GetLastError(); TraceMsg(TF_WARNING, "Failed to get the users token. Error = %d", dwLastError); fSuccess = FALSE; goto cleanup; } } }
// alloc the array to hold all the SID's
apSids = (PSID*)LocalAlloc(LPTR, cUserPerm * sizeof(PSID)); if (!apSids) { DWORD dwLastError = GetLastError(); TraceMsg(TF_WARNING, "Failed allocate memory for %i SID's. Error = %d", cUserPerm, dwLastError); fSuccess = FALSE; goto cleanup; }
// initialize the SID's
for (i = 0; i < cUserPerm; i++) { DWORD cbSid;
// check for the special case of susCurrentUser
if (IsCurrentUserShellSID(&apUserPerm[i]->susID)) { ASSERT(pUserToken); apSids[i] = pUserToken->User.Sid; } else { SID_IDENTIFIER_AUTHORITY sidAuthority = apUserPerm[i]->susID.sidAuthority;
if (!AllocateAndInitializeSid(&sidAuthority, (BYTE)(apUserPerm[i]->susID.dwUserID ? 2 : 1), // if dwUserID is nonzero, then there are two SubAuthorities
apUserPerm[i]->susID.dwUserGroupID, apUserPerm[i]->susID.dwUserID, 0, 0, 0, 0, 0, 0, &apSids[i])) { DWORD dwLastError = GetLastError(); TraceMsg(TF_WARNING, "AllocateAndInitializeSid: Failed to initialze SID. Error = %d", cUserPerm, dwLastError); fSuccess = FALSE; goto cleanup; } }
// add up all the SID lengths for an easy ACL size computation later...
cbSid = GetLengthSid(apSids[i]);
cbSidLength += cbSid; if (apUserPerm[i]->fInherit) { // if we have an inherit ACE as well, we need to add in the size of the SID again
cbSidLength += cbSid; }
}
// calculate the size of the ACL we will be building (note: used sizeof(ACCESS_ALLOWED_ACE) b/c all ACE's are the same
// size (excepting wacko object ACE's which we dont deal with).
//
// this makes the size computation easy, since the size of the ACL will be the size of all the ACE's + the size of the SID's.
cbAcl = SIZEOF(ACL) + (cAces * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD))) + cbSidLength;
// HACKHACK (reinerf)
//
// we allocate enough space for the SECURITY_DESCRIPTOR and the ACL together and pass them both back to the
// caller to free. we need to to this since the SECURITY_DESCRIPTOR contains a pointer to the ACL
pSD = (SECURITY_DESCRIPTOR*)LocalAlloc(LPTR, SIZEOF(SECURITY_DESCRIPTOR) + cbAcl);
if (!pSD) { DWORD dwLastError = GetLastError(); TraceMsg(TF_WARNING, "Failed to allocate space for the SECURITY_DESCRIPTOR and the ACL. Error = %d", dwLastError); fSuccess = FALSE; goto cleanup; }
// set the address of the ACL to right after the SECURITY_DESCRIPTOR in the
// block of memory we just allocated
pAcl = (PACL)(pSD + 1); if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION)) { DWORD dwLastError = GetLastError(); TraceMsg(TF_WARNING, "InitializeAcl: Failed to init the ACL. Error = %d", dwLastError); fSuccess = FALSE; goto cleanup; }
for (i = 0; i < cUserPerm; i++) { BOOL bRet;
// add the ACE's to the ACL
if (apUserPerm[i]->dwAccessType == ACCESS_ALLOWED_ACE_TYPE) { bRet = AddAccessAllowedAce(pAcl, ACL_REVISION, apUserPerm[i]->dwAccessMask, apSids[i]); } else { bRet = AddAccessDeniedAce(pAcl, ACL_REVISION, apUserPerm[i]->dwAccessMask, apSids[i]); }
if (!bRet) { DWORD dwLastError = GetLastError(); TraceMsg(TF_WARNING, "AddAccessAllowed/DeniedAce: Failed to add SID. Error = %d", dwLastError); fSuccess = FALSE; goto cleanup; }
// sucessfully added an ace
iAceIndex++;
ASSERT(iAceIndex <= cAces);
// if its an inherit ACL, also add another ACE for the inheritance part
if (apUserPerm[i]->fInherit) { // add the ACE's to the ACL
if (apUserPerm[i]->dwAccessType == ACCESS_ALLOWED_ACE_TYPE) { bRet = AddAccessAllowedAce(pAcl, ACL_REVISION, apUserPerm[i]->dwInheritAccessMask, apSids[i]); } else { bRet = AddAccessDeniedAce(pAcl, ACL_REVISION, apUserPerm[i]->dwInheritAccessMask, apSids[i]); }
if (!bRet) { DWORD dwLastError = GetLastError(); TraceMsg(TF_WARNING, "AddAccessAllowed/DeniedAce: Failed to add SID. Error = %d", dwLastError); fSuccess = FALSE; goto cleanup; }
if (!MakeACEInheritable(pAcl, iAceIndex, apUserPerm[i]->dwInheritMask)) { DWORD dwLastError = GetLastError(); TraceMsg(TF_WARNING, "MakeACEInheritable: Failed to add SID. Error = %d", dwLastError); fSuccess = FALSE; goto cleanup; }
// sucessfully added another ace
iAceIndex++; ASSERT(iAceIndex <= cAces); } }
if (!InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION)) { DWORD dwLastError = GetLastError(); TraceMsg(TF_WARNING, "InitializeSecurityDescriptor: Failed to init the descriptor. Error = %d", dwLastError); fSuccess = FALSE; goto cleanup; }
if (!SetSecurityDescriptorDacl(pSD, TRUE, pAcl, FALSE)) { DWORD dwLastError = GetLastError(); TraceMsg(TF_WARNING, "SetSecurityDescriptorDacl: Failed to set the DACL. Error = %d", dwLastError); fSuccess = FALSE; goto cleanup; }
cleanup: if (apSids) { for (i = 0; i < cUserPerm; i++) { if (apSids[i]) { // if this is one of the ones we allocated (eg not the users sid), free it
if (!pUserToken || (apSids[i] != pUserToken->User.Sid)) { FreeSid(apSids[i]); } } }
LocalFree(apSids); }
if (pUserToken) LocalFree(pUserToken);
if (!fSuccess && pSD) { LocalFree(pSD); pSD = NULL; }
return pSD; }
|