408 lines
11 KiB
C++
408 lines
11 KiB
C++
#include "shellprv.h"
|
|
#include "TokenUtil.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
// Gets the current process's user token and returns
|
|
// it. It can later be free'd with LocalFree.
|
|
//
|
|
// NOTE: This code is duped in shlwapi\shellacl.c. If you change it, modify
|
|
// it there as well.
|
|
|
|
STDAPI_(PTOKEN_USER) GetUserToken(HANDLE hUser)
|
|
{
|
|
DWORD dwSize = 64;
|
|
HANDLE hToClose = NULL;
|
|
|
|
if (hUser == NULL)
|
|
{
|
|
OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hUser);
|
|
hToClose = hUser;
|
|
}
|
|
|
|
PTOKEN_USER 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;
|
|
}
|
|
|
|
// Returns a localalloc'd string containing the text version of the current user's SID.
|
|
|
|
STDAPI_(LPTSTR) GetUserSid(HANDLE hToken)
|
|
{
|
|
LPTSTR pString = NULL;
|
|
PTOKEN_USER pUser = GetUserToken(hToken);
|
|
if (pUser)
|
|
{
|
|
UNICODE_STRING UnicodeString;
|
|
if (STATUS_SUCCESS == RtlConvertSidToUnicodeString(&UnicodeString, pUser->User.Sid, TRUE))
|
|
{
|
|
UINT nChars = (UnicodeString.Length / 2) + 1;
|
|
pString = (LPTSTR)LocalAlloc(LPTR, nChars * sizeof(TCHAR));
|
|
if (pString)
|
|
{
|
|
SHUnicodeToTChar(UnicodeString.Buffer, pString, nChars);
|
|
}
|
|
RtlFreeUnicodeString(&UnicodeString);
|
|
}
|
|
LocalFree((HLOCAL)pUser);
|
|
}
|
|
return pString;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
sets the security attributes for a given privilege.
|
|
|
|
Arguments:
|
|
|
|
PrivilegeName - Name of the privilege we are manipulating.
|
|
|
|
NewPrivilegeAttribute - The new attribute value to use.
|
|
|
|
OldPrivilegeAttribute - Pointer to receive the old privilege value. OPTIONAL
|
|
|
|
Return value:
|
|
|
|
NO_ERROR or WIN32 error.
|
|
|
|
--*/
|
|
|
|
DWORD SetPrivilegeAttribute(LPCTSTR PrivilegeName, DWORD NewPrivilegeAttribute, DWORD *OldPrivilegeAttribute)
|
|
{
|
|
LUID PrivilegeValue;
|
|
TOKEN_PRIVILEGES TokenPrivileges, OldTokenPrivileges;
|
|
DWORD ReturnLength;
|
|
HANDLE TokenHandle;
|
|
|
|
//
|
|
// First, find out the LUID Value of the privilege
|
|
//
|
|
|
|
if (!LookupPrivilegeValue(NULL, PrivilegeName, &PrivilegeValue))
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
//
|
|
// Get the token handle
|
|
//
|
|
if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &TokenHandle))
|
|
{
|
|
return GetLastError();
|
|
}
|
|
|
|
//
|
|
// Set up the privilege set we will need
|
|
//
|
|
|
|
TokenPrivileges.PrivilegeCount = 1;
|
|
TokenPrivileges.Privileges[0].Luid = PrivilegeValue;
|
|
TokenPrivileges.Privileges[0].Attributes = NewPrivilegeAttribute;
|
|
|
|
ReturnLength = sizeof( TOKEN_PRIVILEGES );
|
|
if (!AdjustTokenPrivileges (
|
|
TokenHandle,
|
|
FALSE,
|
|
&TokenPrivileges,
|
|
sizeof( TOKEN_PRIVILEGES ),
|
|
&OldTokenPrivileges,
|
|
&ReturnLength
|
|
))
|
|
{
|
|
CloseHandle(TokenHandle);
|
|
return GetLastError();
|
|
}
|
|
else
|
|
{
|
|
if (OldPrivilegeAttribute != NULL)
|
|
{
|
|
*OldPrivilegeAttribute = OldTokenPrivileges.Privileges[0].Attributes;
|
|
}
|
|
CloseHandle(TokenHandle);
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Purpose: Determines if the user is a member of the administrators group.
|
|
//
|
|
// Parameters: void
|
|
//
|
|
// Return: TRUE if user is a admin
|
|
// FALSE if not
|
|
// Comments:
|
|
//
|
|
// History: Date Author Comment
|
|
// 4/12/95 ericflo Created
|
|
// 11/4/99 jeffreys Use CheckTokenMembership
|
|
//
|
|
|
|
STDAPI_(BOOL) IsUserAnAdmin()
|
|
{
|
|
return SHTestTokenMembership(NULL, DOMAIN_ALIAS_RID_ADMINS);
|
|
}
|
|
|
|
// is user a guest but not a full user?
|
|
STDAPI_(BOOL) IsUserAGuest()
|
|
{
|
|
return SHTestTokenMembership(NULL, DOMAIN_ALIAS_RID_GUESTS);
|
|
}
|
|
|
|
STDAPI_(BOOL) GetUserProfileKey(HANDLE hToken, HKEY *phkey)
|
|
{
|
|
LPTSTR pUserSid = GetUserSid(hToken);
|
|
if (pUserSid)
|
|
{
|
|
LONG err = RegOpenKeyEx(HKEY_USERS, pUserSid, 0, KEY_READ | KEY_WRITE, phkey);
|
|
if (err == ERROR_ACCESS_DENIED)
|
|
err = RegOpenKeyEx(HKEY_USERS, pUserSid, 0, KEY_READ, phkey);
|
|
|
|
LocalFree(pUserSid);
|
|
return err == ERROR_SUCCESS;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Arguments: phToken = Handle to token.
|
|
//
|
|
// Returns: BOOL
|
|
//
|
|
// Purpose: Opens the thread token. If no thread impersonation token is
|
|
// present open the process token.
|
|
//
|
|
// History: 2000-02-28 vtan created
|
|
|
|
|
|
STDAPI_(BOOL) SHOpenEffectiveToken(HANDLE *phToken)
|
|
{
|
|
return OpenEffectiveToken(TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, phToken);
|
|
}
|
|
|
|
//
|
|
// Arguments: hToken = Handle to token (may be NULL).
|
|
// pszPrivilegeName = Name of privilege to check for.
|
|
//
|
|
// Returns: BOOL
|
|
//
|
|
// Purpose: Uses the given token or if no token is specified the effective
|
|
// token and looks through the list of privileges contained in
|
|
// token for a match against the given privilege being checked.
|
|
//
|
|
// History: 2000-02-28 vtan created
|
|
|
|
|
|
STDAPI_(BOOL) SHTestTokenPrivilege(HANDLE hToken, LPCTSTR pszPrivilegeName)
|
|
{
|
|
// Validate privilege name.
|
|
|
|
if (pszPrivilegeName == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL fResult = FALSE;
|
|
HANDLE hTokenToFree = NULL;
|
|
if (hToken == NULL)
|
|
{
|
|
if (SHOpenEffectiveToken(&hTokenToFree) != FALSE)
|
|
{
|
|
hToken = hTokenToFree;
|
|
}
|
|
}
|
|
if (hToken != NULL)
|
|
{
|
|
LUID luidPrivilege;
|
|
|
|
if (LookupPrivilegeValue(NULL, pszPrivilegeName, &luidPrivilege) != FALSE)
|
|
{
|
|
DWORD dwTokenPrivilegesSize = 0;
|
|
GetTokenInformation(hToken, TokenPrivileges, NULL, 0, &dwTokenPrivilegesSize);
|
|
TOKEN_PRIVILEGES *pTokenPrivileges = static_cast<TOKEN_PRIVILEGES*>(LocalAlloc(LMEM_FIXED, dwTokenPrivilegesSize));
|
|
if (pTokenPrivileges != NULL)
|
|
{
|
|
DWORD dwReturnLength;
|
|
|
|
if (GetTokenInformation(hToken, TokenPrivileges, pTokenPrivileges, dwTokenPrivilegesSize, &dwReturnLength) != FALSE)
|
|
{
|
|
DWORD dwIndex;
|
|
|
|
for (dwIndex = 0; !fResult && (dwIndex < pTokenPrivileges->PrivilegeCount); ++dwIndex)
|
|
{
|
|
fResult = (RtlEqualLuid(&luidPrivilege, &pTokenPrivileges->Privileges[dwIndex].Luid));
|
|
}
|
|
}
|
|
(HLOCAL)LocalFree(pTokenPrivileges);
|
|
}
|
|
}
|
|
}
|
|
if (hTokenToFree != NULL)
|
|
{
|
|
TBOOL(CloseHandle(hTokenToFree));
|
|
}
|
|
return fResult;
|
|
}
|
|
|
|
//
|
|
// Arguments: hToken = Handle to token (may be NULL).
|
|
// ulRID = RID of local group to test membership of.
|
|
//
|
|
// Returns: BOOL
|
|
//
|
|
// Purpose: Uses advapi32!CheckTokenMembership to test whether the given
|
|
// token is a member of the local group with the specified RID.
|
|
// This function wraps CheckTokenMember and only checks local
|
|
// groups.
|
|
//
|
|
// History: 2000-03-22 vtan created
|
|
|
|
|
|
STDAPI_(BOOL) SHTestTokenMembership(HANDLE hToken, ULONG ulRID)
|
|
{
|
|
static SID_IDENTIFIER_AUTHORITY sSystemSidAuthority = SECURITY_NT_AUTHORITY;
|
|
|
|
PSID pSIDLocalGroup;
|
|
BOOL fResult = FALSE;
|
|
if (AllocateAndInitializeSid(&sSystemSidAuthority,
|
|
2,
|
|
SECURITY_BUILTIN_DOMAIN_RID,
|
|
ulRID,
|
|
0, 0, 0, 0, 0, 0,
|
|
&pSIDLocalGroup) != FALSE)
|
|
{
|
|
if (CheckTokenMembership(hToken, pSIDLocalGroup, &fResult) == FALSE)
|
|
{
|
|
TraceMsg(TF_WARNING, "shell32: SHTestTokenMembership call to advapi32!CheckTokenMembership failed with error %d", GetLastError());
|
|
fResult = FALSE;
|
|
}
|
|
FreeSid(pSIDLocalGroup);
|
|
}
|
|
return fResult;
|
|
}
|
|
|
|
//
|
|
// Arguments: pszPrivilegeName = Name of privilege to be enabled.
|
|
// pfnPrivilegedFunction = Pointer to function to invoke.
|
|
// pv = Caller supplied data.
|
|
//
|
|
// Returns: HRESULT
|
|
//
|
|
// Purpose: Enables the given privilege in the current thread's
|
|
// impersonation or primary process' token, invokes the given
|
|
// function pointer with the caller supplied data and then
|
|
// restores the privilege back to its previous state.
|
|
//
|
|
// History: 2000-03-13 vtan created
|
|
|
|
|
|
STDAPI SHInvokePrivilegedFunction(LPCTSTR pszPrivilegeName, PFNPRIVILEGEDFUNCTION pfnPrivilegedFunction, void *pv)
|
|
{
|
|
if ((pszPrivilegeName == NULL) || (pfnPrivilegedFunction == NULL))
|
|
{
|
|
return E_INVALIDARG;
|
|
}
|
|
|
|
CPrivilegeEnable privilege(pszPrivilegeName);
|
|
|
|
return pfnPrivilegedFunction(pv);
|
|
}
|
|
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: DWORD
|
|
//
|
|
// Purpose: Returns the ID of the active console session.
|
|
//
|
|
// History: 2000-03-13 vtan created
|
|
|
|
|
|
STDAPI_(DWORD) SHGetActiveConsoleSessionId (void)
|
|
|
|
{
|
|
return static_cast<DWORD>(USER_SHARED_DATA->ActiveConsoleId);
|
|
}
|
|
|
|
//
|
|
// Arguments: hToken = Handle to the user token.
|
|
//
|
|
// Returns: DWORD
|
|
//
|
|
// Purpose: Returns the session ID associated with the given token. If no
|
|
// token is specified the effective token is used. This will
|
|
// allow a service to call this function when impersonating a
|
|
// client.
|
|
//
|
|
// The token must have TOKEN_QUERY access.
|
|
//
|
|
// History: 2000-03-13 vtan created
|
|
|
|
|
|
STDAPI_(DWORD) SHGetUserSessionId(HANDLE hToken)
|
|
{
|
|
ULONG ulUserSessionID = 0; // default to session 0
|
|
HANDLE hTokenToFree = NULL;
|
|
if (hToken == NULL)
|
|
{
|
|
TBOOL(SHOpenEffectiveToken(&hTokenToFree));
|
|
hToken = hTokenToFree;
|
|
}
|
|
if (hToken != NULL)
|
|
{
|
|
DWORD dwReturnLength;
|
|
TBOOL(GetTokenInformation(hToken,
|
|
TokenSessionId,
|
|
&ulUserSessionID,
|
|
sizeof(ulUserSessionID),
|
|
&dwReturnLength));
|
|
}
|
|
if (hTokenToFree != NULL)
|
|
{
|
|
TBOOL(CloseHandle(hTokenToFree));
|
|
}
|
|
return ulUserSessionID;
|
|
}
|
|
|
|
|
|
//
|
|
// Arguments: <none>
|
|
//
|
|
// Returns: BOOL
|
|
//
|
|
// Purpose: Returns whether the current process is the console session.
|
|
//
|
|
// History: 2000-03-27 vtan created
|
|
|
|
|
|
STDAPI_(BOOL) SHIsCurrentProcessConsoleSession(void)
|
|
|
|
{
|
|
return USER_SHARED_DATA->ActiveConsoleId == NtCurrentPeb()->SessionId;
|
|
}
|