windows-nt/Source/XPSP1/NT/windows/appcompat/shims/lib/secutils.cpp
2020-09-26 16:20:57 +08:00

390 lines
8.1 KiB
C++

/*++
Copyright (c) 2001 Microsoft Corporation
Module Name:
secutils.cpp
Abstract:
The utility functions for the shims.
History:
02/09/2001 maonis Created
08/14/2001 robkenny Moved code inside the ShimLib namespace.
--*/
#include "secutils.h"
namespace ShimLib
{
/*++
Function Description:
Determine if the log on user is a member of the group.
Arguments:
IN dwGroup - specify the alias of the group.
OUT pfIsMember - TRUE if it's a member, FALSE if not.
Return Value:
TRUE - we successfully determined if it's a member.
FALSE otherwise.
DevNote:
We are assuming the calling thread is not impersonating.
History:
02/12/2001 maonis Created
--*/
BOOL
SearchGroupForSID(
DWORD dwGroup,
BOOL* pfIsMember
)
{
PSID pSID = NULL;
SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
BOOL fRes = TRUE;
if (!AllocateAndInitializeSid(
&SIDAuth,
2,
SECURITY_BUILTIN_DOMAIN_RID,
dwGroup,
0,
0,
0,
0,
0,
0,
&pSID))
{
DPF("SecurityUtils", eDbgLevelError, "[SearchGroupForSID] AllocateAndInitializeSid failed %d", GetLastError());
return FALSE;
}
if (!CheckTokenMembership(NULL, pSID, pfIsMember))
{
DPF("SecurityUtils", eDbgLevelError, "[SearchGroupForSID] CheckTokenMembership failed: %d", GetLastError());
fRes = FALSE;
}
FreeSid(pSID);
return fRes;
}
/*++
Function Description:
Determine if we should shim this app or not.
If the user is
1) a member of the Users and
2) not a member of the Administrators group and
3) not a member of the Power Users group and
3) not a member of the Guest group
we'll apply the shim.
Arguments:
None.
Return Value:
TRUE - we should apply the shim.
FALSE otherwise.
History:
02/12/2001 maonis Created
--*/
BOOL
ShouldApplyShim()
{
BOOL fIsUser, fIsAdmin, fIsPowerUser, fIsGuest;
if (!SearchGroupForSID(DOMAIN_ALIAS_RID_USERS, &fIsUser) ||
!SearchGroupForSID(DOMAIN_ALIAS_RID_ADMINS, &fIsAdmin) ||
!SearchGroupForSID(DOMAIN_ALIAS_RID_POWER_USERS, &fIsPowerUser) ||
!SearchGroupForSID(DOMAIN_ALIAS_RID_GUESTS, &fIsGuest))
{
//
// Don't do anything if we are not sure.
//
return FALSE;
}
return (fIsUser && !fIsPowerUser && !fIsAdmin && !fIsGuest);
}
/*++
Function Description:
Get the current thread on user's SID. If the thread is not
impersonating we get the current process SID instead.
Arguments:
OUT ppThreadSid - points to the current thread's SID.
Return Value:
TRUE - successfully got the SID, the caller is responsible for
freeing it with free().
FALSE otherwise.
History:
02/12/2001 maonis Created
--*/
BOOL
GetCurrentThreadSid(
OUT PSID* ppThreadSid
)
{
HANDLE hToken;
DWORD dwLastErr;
DWORD cbBuffer, cbRequired;
PTOKEN_USER pUserInfo;
BOOL fRes = FALSE;
// Get the thread token.
if (!OpenThreadToken(
GetCurrentThread(),
TOKEN_QUERY,
FALSE,
&hToken))
{
if ((dwLastErr = GetLastError()) == ERROR_NO_TOKEN)
{
// The thread isn't impersonating so we get the process token instead.
if (!OpenProcessToken(
GetCurrentProcess(),
TOKEN_QUERY,
&hToken))
{
DPF("SecurityUtils", eDbgLevelError, "[GetThreadSid] OpenProcessToken failed: %d", GetLastError());
return FALSE;
}
}
else
{
DPF("SecurityUtils", eDbgLevelError,
"[GetThreadSid] OpenThreadToken failed (and not with no token): %d",
dwLastErr);
return FALSE;
}
}
// Call GetTokenInformation with 0 buffer length to get the
// required buffer size for the token info.
cbBuffer = 0;
if (!GetTokenInformation(
hToken,
TokenUser,
NULL,
cbBuffer,
&cbRequired) &&
(dwLastErr = GetLastError()) != ERROR_INSUFFICIENT_BUFFER)
{
DPF("SecurityUtils", eDbgLevelError,
"[GetThreadSid] 1st time calling GetTokenInformation "
"didn't failed with ERROR_INSUFFICIENT_BUFFER: %d",
dwLastErr);
return FALSE;
}
cbBuffer = cbRequired;
pUserInfo = (PTOKEN_USER)malloc(cbBuffer);
if (!pUserInfo)
{
DPF("SecurityUtils", eDbgLevelError, "[GetThreadSid] HeapAlloc for user data failed");
return FALSE;
}
// Make the "real" call.
if (!GetTokenInformation(
hToken,
TokenUser,
pUserInfo,
cbBuffer,
&cbRequired))
{
DPF("SecurityUtils", eDbgLevelError,
"[GetThreadSid] 2nd time calling GetTokenInformation failed: %d",
GetLastError());
goto EXIT;
}
cbBuffer = GetLengthSid(pUserInfo->User.Sid);
*ppThreadSid = (PSID)malloc(cbBuffer);
if (!(*ppThreadSid))
{
DPF("SecurityUtils", eDbgLevelError, "[GetThreadSid] HeapAlloc for SID failed");
goto EXIT;
}
if (!CopySid(cbBuffer, *ppThreadSid, pUserInfo->User.Sid))
{
DPF("SecurityUtils", eDbgLevelError, "[GetThreadSid] CopySid failed: %d", GetLastError());
goto EXIT;
}
fRes = TRUE;
EXIT:
free(pUserInfo);
return fRes;
}
// The GENERIC_MAPPING from generic file access rights to specific and standard
// access types.
static GENERIC_MAPPING s_gmFile =
{
FILE_GENERIC_READ,
FILE_GENERIC_WRITE,
FILE_GENERIC_EXECUTE,
FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE
};
/*++
Function Description:
Given the creation dispositon and the desired access when calling
CreateFile, we determine if the caller is requesting write access.
This is specific for files.
Arguments:
IN pszObject - name of the file or directory.
OUT pam - points to the access mask of the user to this object.
Return Value:
TRUE - successfully got the access mask.
FALSE otherwise.
DevNote:
UNDONE - This might not be a complete list...can add as we debug more apps.
History:
02/12/2001 maonis Created
--*/
BOOL
RequestWriteAccess(
IN DWORD dwCreationDisposition,
IN DWORD dwDesiredAccess
)
{
MapGenericMask(&dwDesiredAccess, &s_gmFile);
if ((dwCreationDisposition != OPEN_EXISTING) ||
(dwDesiredAccess & DELETE) ||
// Generally, app would not specify FILE_WRITE_DATA directly, and if
// it specifies GENERIC_WRITE, it will get mapped to FILE_WRITE_DATA
// OR other things so checking FILE_WRITE_DATA is sufficient.
(dwDesiredAccess & FILE_WRITE_DATA))
{
return TRUE;
}
return FALSE;
}
/*++
Function Description:
Given the name of a directory, determine if the user can create
new files in this directory.
Arguments:
IN pszDir - name of the directory.
IN pUserSid - the user that's requesting to create files.
OUT pfCanCreate.
Return Value:
TRUE - successfully enabled or disabled the privilege.
FALSE - otherwise.
History:
04/03/2001 maonis Created
--*/
BOOL
AdjustPrivilege(
LPCWSTR pwszPrivilege,
BOOL fEnable
)
{
HANDLE hToken;
TOKEN_PRIVILEGES tp;
BOOL fRes = FALSE;
// Obtain the process token.
if (OpenProcessToken(
GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
&hToken))
{
// Get the LUID.
if (LookupPrivilegeValueW(NULL, pwszPrivilege, &tp.Privileges[0].Luid))
{
tp.PrivilegeCount = 1;
tp.Privileges[0].Attributes = (fEnable ? SE_PRIVILEGE_ENABLED : 0);
// Enable or disable the privilege.
if (AdjustTokenPrivileges(
hToken,
FALSE,
&tp,
0,
(PTOKEN_PRIVILEGES)NULL,
0))
{
fRes = TRUE;
}
}
CloseHandle(hToken);
}
return fRes;
}
}; // end of namespace ShimLib