336 lines
10 KiB
C
336 lines
10 KiB
C
|
#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;
|
||
|
}
|