Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

689 lines
20 KiB

/*++ BUILD Version: 0001 // Increment this if a change has global effects
Copyright (c) 1992-1994 Microsoft Corporation
Module Name:
perfsec.c
Abstract:
This file implements the _access checking functions used by the
performance registry API's
Author:
Bob Watson (a-robw)
Revision History:
8-Mar-95 Created (and extracted from Perflib.c
--*/
#define UNICODE
//
// Include files
//
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include "ntconreg.h"
#include "perfsec.h"
#define INITIAL_SID_BUFFER_SIZE 4096
#define FREE_IF_ALLOC(x) if ((x) != NULL) {FREEMEM(RtlProcessHeap(), 0, x);}
static
BOOL
CheckKeyForAccess (
IN PSID psidAccess, // sid to check
IN ACCESS_MASK amAccess, // desired access
IN HKEY hKey // key to check
)
/*++
Routine Description:
checks the ACL attached to the hKey registry key for the desired
access granted to the user referenced by the SID
Arguments:
IN HKEY hKey
open handle of key to dump ACL from
ReturnValue:
WIN32 status of function
--*/
{
PACL pDacl;
PSECURITY_DESCRIPTOR psdKey;
LONG lStatus;
DWORD dwBuffSize;
PSID psidOwner;
BOOL bStatus;
BOOL bReturn;
BOOL bOwnerDefaulted;
BOOL bDaclDefaulted;
BOOL bDaclPresent;
ACCESS_ALLOWED_ACE *pAce;
ACCESS_MASK amUser;
ACCESS_MASK amWorld;
DWORD iAce;
LPSTR szKeyBuffer;
LPSTR szValueBuffer;
BOOL bWorldFound;
BOOL bUserFound;
BOOL bAccess = FALSE; // assume no access
PSID psidWorld = NULL;
SID_IDENTIFIER_AUTHORITY siaWorld = SECURITY_WORLD_SID_AUTHORITY;
// create the World SID
if (!AllocateAndInitializeSid(&siaWorld,
1,
SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0, &psidWorld)) {
// unable to create the "Everyone" sid
return bAccess;
}
dwBuffSize = INITIAL_SID_BUFFER_SIZE;
psdKey = (PSECURITY_DESCRIPTOR)ALLOCMEM(RtlProcessHeap(),
HEAP_ZERO_MEMORY, dwBuffSize);
szValueBuffer = (LPSTR)ALLOCMEM(RtlProcessHeap(),
HEAP_ZERO_MEMORY, MAX_PATH);
szKeyBuffer = (LPSTR)ALLOCMEM(RtlProcessHeap(),
HEAP_ZERO_MEMORY, MAX_PATH);
if ((BOOL)psdKey &&
(BOOL)szKeyBuffer &&
(BOOL)szValueBuffer) {
// try to get Key security descriptor, and expand buffer as
// required.
while ((lStatus = RegGetKeySecurity (
hKey,
DACL_SECURITY_INFORMATION,
psdKey,
&dwBuffSize)) == ERROR_INSUFFICIENT_BUFFER) {
psdKey = (PSECURITY_DESCRIPTOR)REALLOCMEM(
RtlProcessHeap(),
HEAP_ZERO_MEMORY,
psdKey,
dwBuffSize);
if (!(BOOL)psdKey) {
lStatus = ERROR_OUTOFMEMORY;
break;
}
}
// if security descriptor read OK, then check the ACL
if (lStatus == ERROR_SUCCESS) { // then continue to look at sec. info
bStatus = GetSecurityDescriptorDacl (
psdKey,
&bDaclPresent,
&pDacl,
&bDaclDefaulted);
if (bStatus) {
if (pDacl != NULL) {
// prepare to walk list of ACE's
bWorldFound = FALSE;
bUserFound = FALSE;
amUser = 0;
amWorld = 0;
for (iAce = 0; iAce < pDacl->AceCount; iAce++) {
bStatus = GetAce (
pDacl,
iAce,
&pAce);
if (bStatus) {
// got an ace so check it
if (EqualSid(psidWorld,
(PSID)(&(pAce->SidStart)))) {
// a match so see what access is allowed
if (pAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) {
// check access bits to see of the right ones are set
amWorld |= pAce->Mask;
bWorldFound = TRUE;
}
}
if (EqualSid(psidAccess,
(PSID)(&(pAce->SidStart)))) {
// a match so see what access is allowed
if (pAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE) {
// check access bits to see of the right ones are set
amUser |= pAce->Mask;
bUserFound = TRUE;
}
}
} // end if GetAce Ok
}// end for iAce loop
// user ACE found so see if this grants sufficient access
if (bUserFound) {
bAccess = AreAllAccessesGranted (
amUser, // access granted by key
amAccess);
}
if (!bAccess && bWorldFound) {
// the user doesn't have an EXPLICIT ACE granting
// access, so check to see if they can have it from
// Everyone's ACE
bAccess = AreAllAccessesGranted (
pAce->Mask, // access granted by key
amAccess);
}
} else {
// no DACL means Access is ALWAYS granted.
bAccess = TRUE;
}
} else {
// no DACL means Access is ALWAYS granted.
bAccess = TRUE;
}
} // end of if descriptor
} else {
// unable to allocate a buffer (or 2 or 3)
SetLastError(ERROR_OUTOFMEMORY);
}
FREE_IF_ALLOC(psdKey);
FREE_IF_ALLOC(szKeyBuffer);
FREE_IF_ALLOC(szValueBuffer);
FREE_IF_ALLOC(psidWorld);
// return access granted by ACL
return bAccess;
}
static
BOOL
TestTokenForAccess(
IN HANDLE hToken,
IN ACCESS_MASK amAccess
)
/***************************************************************************\
* TestTokenForAccess
*
* Returns TRUE if the token passed can access the perf data
*
* The token handle passed must have TOKEN_QUERY access.
*
* History:
* 05-06-92 Davidc Created
* 03-07-95 a-robw adapted to Win32 Calls
\***************************************************************************/
{
LONG lStatus;
BOOL bStatus;
DWORD dwBufferLength;
HKEY hKeyPerflib;
DWORD dwGroupSidIndex;
TOKEN_USER *ptuData;
TOKEN_GROUPS *ptgData;
PSECURITY_DESCRIPTOR pSid = NULL;
BOOL bAccessGranted = FALSE;
DWORD dwLastError = ERROR_SUCCESS;
lStatus = RegOpenKeyExW (
HKEY_LOCAL_MACHINE,
L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib",
0L,
KEY_READ,
&hKeyPerflib);
if (lStatus == ERROR_SUCCESS) {
// get SID to check
GetTokenInformation (
hToken,
TokenUser,
NULL,
0,
&dwBufferLength);
ptuData = (TOKEN_USER *)ALLOCMEM (RtlProcessHeap(),
HEAP_ZERO_MEMORY, dwBufferLength);
if (ptuData != NULL) {
if (GetTokenInformation (
hToken,
TokenUser,
ptuData,
dwBufferLength,
&dwBufferLength)) {
// token information found so check access
bAccessGranted = CheckKeyForAccess (
ptuData->User.Sid,
amAccess,
hKeyPerflib);
if (!bAccessGranted) {
// access is not granted to the specific user
// or the world, so see if there are any groups
// associated with this token and check them
GetTokenInformation (
hToken,
TokenGroups,
NULL,
0,
&dwBufferLength);
ptgData = (TOKEN_GROUPS *)ALLOCMEM (RtlProcessHeap(),
HEAP_ZERO_MEMORY, dwBufferLength);
if (ptuData != NULL) {
if (GetTokenInformation (
hToken,
TokenGroups,
ptgData,
dwBufferLength,
&dwBufferLength)) {
// token group information found so check access
// on each group SID returned
for (dwGroupSidIndex = 0;
dwGroupSidIndex < ptgData->GroupCount;
dwGroupSidIndex++) {
bAccessGranted = CheckKeyForAccess (
ptgData->Groups[dwGroupSidIndex].Sid,
amAccess,
hKeyPerflib);
// if one of the groups is granted access
// then that's good enough. so exit loop
if (bAccessGranted) break;
}
} else {
dwLastError = GetLastError();
}
FREEMEM (RtlProcessHeap(), 0, ptgData);
} else {
SetLastError (ERROR_OUTOFMEMORY);
}
} // end if not access granted
} else {
dwLastError = GetLastError();
}
FREEMEM (RtlProcessHeap(), 0, ptuData);
} else {
dwLastError = GetLastError();
}
RegCloseKey (hKeyPerflib);
}
return(bAccessGranted);
}
static
BOOL
TestTokenForPriv(
HANDLE hToken,
LPTSTR szPrivName
)
/***************************************************************************\
* TestTokenForPriv
*
* Returns TRUE if the token passed has the specified privilege
*
* The token handle passed must have TOKEN_QUERY access.
*
* History:
* 03-07-95 a-robw Created
\***************************************************************************/
{
BOOL bStatus;
LUID PrivLuid;
PRIVILEGE_SET PrivSet;
LUID_AND_ATTRIBUTES PrivLAndA[1];
BOOL bReturn = FALSE;
// get value of priv
bStatus = LookupPrivilegeValue (
NULL,
szPrivName,
&PrivLuid);
if (!bStatus) {
// unable to lookup privilege
goto Exit_Point;
}
// build Privilege Set for function call
PrivLAndA[0].Luid = PrivLuid;
PrivLAndA[0].Attributes = 0;
PrivSet.PrivilegeCount = 1;
PrivSet.Control = PRIVILEGE_SET_ALL_NECESSARY;
PrivSet.Privilege[0] = PrivLAndA[0];
// check for the specified priv in the token
bStatus = PrivilegeCheck (
hToken,
&PrivSet,
&bReturn);
if (bStatus) {
SetLastError (ERROR_SUCCESS);
}
//
// Tidy up
//
Exit_Point:
return(bReturn);
}
BOOL
TestClientForPriv (
BOOL *pbThread,
LPTSTR szPrivName
)
/***************************************************************************\
* TestClientForPriv
*
* Returns TRUE if our client has the specified privilege
* Otherwise, returns FALSE.
*
\***************************************************************************/
{
BOOL bResult;
BOOL bIgnore;
DWORD dwLastError;
BOOL bThreadFlag = FALSE; // assume data is from process or an error occurred
HANDLE hClient;
SetLastError (ERROR_SUCCESS);
bResult = OpenThreadToken(GetCurrentThread(), // This Thread
TOKEN_QUERY, //DesiredAccess
FALSE, // use context of calling thread
&hClient); //TokenHandle
if (!bResult) {
// unable to get a Thread Token, try a Process Token
bResult = OpenProcessToken(GetCurrentProcess(), // This Process
TOKEN_QUERY, //DesiredAccess
&hClient); //TokenHandle
} else {
// data is from current THREAD
bThreadFlag = TRUE;
}
if (bResult) {
try {
bResult = TestTokenForPriv( hClient, szPrivName );
} except (EXCEPTION_EXECUTE_HANDLER) {
bResult = FALSE;
}
bIgnore = CloseHandle( hClient );
ASSERT(bIgnore == TRUE);
} else {
dwLastError = GetLastError ();
}
// set thread flag if present
if (pbThread != NULL) {
try {
*pbThread = bThreadFlag;
} except (EXCEPTION_EXECUTE_HANDLER) {
SetLastError (ERROR_INVALID_PARAMETER);
}
}
return(bResult);
}
LONG
GetProcessNameColMeth (
VOID
)
{
NTSTATUS Status;
HANDLE hPerflibKey;
OBJECT_ATTRIBUTES oaPerflibKey;
ACCESS_MASK amPerflibKey;
UNICODE_STRING PerflibSubKeyString;
UNICODE_STRING NameInfoValueString;
LONG lReturn = PNCM_SYSTEM_INFO;
PKEY_VALUE_PARTIAL_INFORMATION pKeyInfo;
DWORD dwBufLen;
DWORD dwRetBufLen;
PDWORD pdwValue;
RtlInitUnicodeString (
&PerflibSubKeyString,
L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib");
InitializeObjectAttributes(
&oaPerflibKey,
&PerflibSubKeyString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtOpenKey(
&hPerflibKey,
MAXIMUM_ALLOWED,
&oaPerflibKey
);
if (NT_SUCCESS (Status)) {
// registry key opened, now read value.
// allocate enough room for the structure, - the last
// UCHAR in the struct, but + the data buffer (a dword)
dwBufLen = sizeof(KEY_VALUE_PARTIAL_INFORMATION) -
sizeof(UCHAR) + sizeof (DWORD);
pKeyInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ALLOCMEM (
RtlProcessHeap(),
HEAP_ZERO_MEMORY,
dwBufLen);
if (pKeyInfo != NULL) {
// initialize value name string
RtlInitUnicodeString (
&NameInfoValueString,
L"CollectUnicodeProcessNames");
dwRetBufLen = 0;
Status = NtQueryValueKey (
hPerflibKey,
&NameInfoValueString,
KeyValuePartialInformation,
(PVOID)pKeyInfo,
dwBufLen,
&dwRetBufLen);
if (NT_SUCCESS(Status)) {
// check value of return data buffer
pdwValue = (PDWORD)&pKeyInfo->Data[0];
if (*pdwValue == PNCM_MODULE_FILE) {
lReturn = PNCM_MODULE_FILE;
} else {
// all other values will cause this routine to return
// the default value of PNCM_SYSTEM_INFO;
}
}
FREEMEM (RtlProcessHeap(), 0, pKeyInfo);
}
// close handle
NtClose (hPerflibKey);
}
return lReturn;
}
LONG
GetPerfDataAccess (
VOID
)
{
NTSTATUS Status;
HANDLE hPerflibKey;
OBJECT_ATTRIBUTES oaPerflibKey;
ACCESS_MASK amPerflibKey;
UNICODE_STRING PerflibSubKeyString;
UNICODE_STRING NameInfoValueString;
LONG lReturn = CPSR_EVERYONE;
PKEY_VALUE_PARTIAL_INFORMATION pKeyInfo;
DWORD dwBufLen;
DWORD dwRetBufLen;
PDWORD pdwValue;
RtlInitUnicodeString (
&PerflibSubKeyString,
L"\\Registry\\Machine\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib");
InitializeObjectAttributes(
&oaPerflibKey,
&PerflibSubKeyString,
OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
Status = NtOpenKey(
&hPerflibKey,
MAXIMUM_ALLOWED,
&oaPerflibKey
);
if (NT_SUCCESS (Status)) {
// registry key opened, now read value.
// allocate enough room for the structure, - the last
// UCHAR in the struct, but + the data buffer (a dword)
dwBufLen = sizeof(KEY_VALUE_PARTIAL_INFORMATION) -
sizeof(UCHAR) + sizeof (DWORD);
pKeyInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ALLOCMEM (
RtlProcessHeap(),
HEAP_ZERO_MEMORY,
dwBufLen);
if (pKeyInfo != NULL) {
// see if the user right should be checked
// init value name string
RtlInitUnicodeString (
&NameInfoValueString,
L"CheckProfileSystemRight");
dwRetBufLen = 0;
Status = NtQueryValueKey (
hPerflibKey,
&NameInfoValueString,
KeyValuePartialInformation,
(PVOID)pKeyInfo,
dwBufLen,
&dwRetBufLen);
if (NT_SUCCESS(Status)) {
// check value of return data buffer
pdwValue = (PDWORD)&pKeyInfo->Data[0];
if (*pdwValue == CPSR_CHECK_ENABLED) {
lReturn = CPSR_CHECK_PRIVS;
} else {
// all other values will cause this routine to return
// the default value of CPSR_EVERYONE
}
}
FREEMEM (RtlProcessHeap(), 0, pKeyInfo);
}
// close handle
NtClose (hPerflibKey);
}
return lReturn;
}
BOOL
TestClientForAccess (
IN BOOL *pbThread,
IN ACCESS_MASK amAccess
)
/***************************************************************************\
* TestClientForAccess
*
* Returns TRUE if our client is allowed to read the perflib key.
* Otherwise, returns FALSE.
*
\***************************************************************************/
{
BOOL bResult;
BOOL bIgnore;
DWORD dwLastError;
BOOL bThreadFlag = FALSE; // assume data is from process or an error occurred
HANDLE hClient;
HANDLE hImpersonate;
SetLastError (ERROR_SUCCESS);
bResult = OpenThreadToken(GetCurrentThread(), // This Thread
TOKEN_QUERY | TOKEN_IMPERSONATE, //DesiredAccess
FALSE, // use context of calling thread
&hClient); //TokenHandle
if (!bResult) {
// unable to get a Thread Token, try a Process Token
bResult = OpenProcessToken(GetCurrentProcess(), // This Process
TOKEN_QUERY | TOKEN_IMPERSONATE, //DesiredAccess
&hClient); //TokenHandle
} else {
// data is from current THREAD
bThreadFlag = TRUE;
}
if (bResult) {
try {
bResult = TestTokenForAccess ( hClient, amAccess);
} except (EXCEPTION_EXECUTE_HANDLER) {
bResult = FALSE;
}
bIgnore = CloseHandle( hClient );
ASSERT(bIgnore == TRUE);
} else {
dwLastError = GetLastError ();
}
// set thread flag if present
if (pbThread != NULL) {
try {
*pbThread = bThreadFlag;
} except (EXCEPTION_EXECUTE_HANDLER) {
SetLastError (ERROR_INVALID_PARAMETER);
}
}
return(bResult);
}