/*++ 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
//
#pragma warning(disable:4306)
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include "ntconreg.h"
#include "perflib.h"
#pragma warning(default:4306)

#define INITIAL_SID_BUFFER_SIZE     4096
#define FREE_IF_ALLOC(x)    if ((x) != NULL) {FREEMEM(x);}

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;
    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 (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 (pKeyInfo);
        }
        // close handle
        NtClose (hPerflibKey);
    }

    return lReturn;
}

LONG
GetPerfDataAccess (
    VOID
)
{
    NTSTATUS            Status;
    HANDLE              hPerflibKey;
    OBJECT_ATTRIBUTES   oaPerflibKey;
    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 (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 (pKeyInfo);
        }
        // close handle
        NtClose (hPerflibKey);
    }

    return lReturn;
}

BOOL
TestClientForAccess ( 
    VOID
)
/***************************************************************************\
* TestClientForAccess
*
* Returns TRUE if our client is allowed to read the perflib key.
* Otherwise, returns FALSE.
*
\***************************************************************************/
{
    HKEY hKeyPerflib;
    DWORD   dwStatus;
    BOOL bResult = FALSE;

    dwStatus = RegOpenKeyExW(
       HKEY_LOCAL_MACHINE,
       L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib",
       0L,
       KEY_READ,
       & hKeyPerflib);

    if (dwStatus == ERROR_SUCCESS) {
        RegCloseKey(hKeyPerflib);
        bResult = TRUE;
    }

    return (bResult);
}
