390 lines
8.1 KiB
C++
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
|