windows-nt/Source/XPSP1/NT/ds/security/winsafer/safehand.c
2020-09-26 16:20:57 +08:00

535 lines
14 KiB
C

/*++
Copyright (c) 1997-2000 Microsoft Corporation
Module Name:
SafeHand.c (WinSAFER Handle Operations)
Abstract:
This module implements the WinSAFER APIs to open and close handles
to SAFER Code Authorization Levels.
Author:
Jeffrey Lawson (JLawson) - Nov 1999
Environment:
User mode only.
Exported Functions:
CodeAuthzHandleToLevelStruct
CodeAuthzpOpenPolicyRootKey
CodeAuthzCreateLevelHandle
CodeAuthzCloseLevelHandle
SaferCreateLevel (public win32 api)
SaferCloseLevel (public win32 api)
Revision History:
Created - Nov 1999
--*/
#include "pch.h"
#pragma hdrstop
#include <winsafer.h>
#include <winsaferp.h>
#include "saferp.h"
//
// All handles have a bit pattern OR-ed onto them to serve both
// as a debugging aid in distinguishing obvious non-handles,
// and also to ensure that a zero handle is never given back.
//
#define LEVEL_HANDLE_BITS 0x74000000
#define LEVEL_HANDLE_MASK 0xFF000000
NTSTATUS NTAPI
CodeAuthzpCreateLevelHandleFromRecord(
IN PAUTHZLEVELTABLERECORD pLevelRecord,
IN DWORD dwScopeId,
IN DWORD dwSaferFlags OPTIONAL,
IN DWORD dwExtendedError,
IN SAFER_IDENTIFICATION_TYPES IdentificationType,
IN REFGUID refIdentGuid OPTIONAL,
OUT SAFER_LEVEL_HANDLE *pLevelHandle
)
/*++
Routine Description:
Converts a level record to an opaque SAFER_LEVEL_HANDLE handle.
Note that although this function assumes that the global
critical section has already been obtained by the caller.
Arguments:
pLevelRecord - specifies the level record for which the
request is being made. It is assumed that this record
is valid and exists within the g_CodeLevelObjTable.
dwScopeId - indicates the scope that will be stored within
the opened handle. This scope affects the behavior of
Get/SetInfoCodeAuthzLevel for code identifiers.
dwSaferFlags - indicates any optional Safer flags that were
derived from the matching code identifier. These bits
will be bitwise ORed in SaferComputeTokenFromLevel.
dwExtendedError - Error returned by WinVerifyTrust.
IdentificationType - Rule that identified this level.
refIdentGuid - indicates the Code Identifier record that was
used to match the given level. This may be NULL.
pLevelHandle - receives the resulting opaque Level handle.
Return Value:
Returns STATUS_SUCCESS on success.
--*/
{
NTSTATUS Status;
ULONG ulHandleIndex;
PAUTHZLEVELHANDLESTRUCT pLevelStruct;
ASSERT(ARGUMENT_PRESENT(pLevelRecord) &&
ARGUMENT_PRESENT(pLevelHandle));
//
// Validate the value passed within the dwScope argument.
//
if (g_hKeyCustomRoot != NULL) {
if (dwScopeId != SAFER_SCOPEID_REGISTRY) {
Status = STATUS_INVALID_PARAMETER_MIX;
goto ExitHandler;
}
} else {
if (dwScopeId != SAFER_SCOPEID_MACHINE &&
dwScopeId != SAFER_SCOPEID_USER) {
Status = STATUS_INVALID_PARAMETER_MIX;
goto ExitHandler;
}
}
//
// Allocate a handle to represent this level.
//
pLevelStruct = (PAUTHZLEVELHANDLESTRUCT) RtlAllocateHandle(
&g_LevelHandleTable,
&ulHandleIndex);
if (!pLevelStruct) {
Status = STATUS_INSUFFICIENT_RESOURCES;
goto ExitHandler;
}
ASSERT((ulHandleIndex & LEVEL_HANDLE_MASK) == 0);
*pLevelHandle = UlongToPtr(ulHandleIndex | LEVEL_HANDLE_BITS);
//
// Fill in the handle structure to represent this level.
//
RtlZeroMemory(pLevelStruct, sizeof(AUTHZLEVELHANDLESTRUCT));
pLevelStruct->HandleHeader.Flags = RTL_HANDLE_ALLOCATED;
pLevelStruct->dwLevelId = pLevelRecord->dwLevelId;
pLevelStruct->dwScopeId = dwScopeId;
pLevelStruct->dwSaferFlags = dwSaferFlags;
pLevelStruct->dwHandleSequence = g_dwLevelHandleSequence;
pLevelStruct->dwExtendedError = dwExtendedError;
pLevelStruct->IdentificationType = IdentificationType;
if (ARGUMENT_PRESENT(refIdentGuid)) {
RtlCopyMemory(&pLevelStruct->identGuid, refIdentGuid, sizeof(GUID));
} else {
ASSERT(IsZeroGUID(&pLevelStruct->identGuid));
}
Status = STATUS_SUCCESS;
ExitHandler:
return Status;
}
NTSTATUS NTAPI
CodeAuthzHandleToLevelStruct(
IN SAFER_LEVEL_HANDLE hLevelObject,
OUT PAUTHZLEVELHANDLESTRUCT *pLevelStruct)
/*++
Routine Description:
Converts an opaque SAFER_LEVEL_HANDLE handle into a pointer to the
internal handle structure.
Note that although this function gains and releases access to
the critical section during the API execution, the caller is
expected to have already entered the critical section and
maintain the critical section for the entire duration under
which the return pLevelStruct will be used. Otherwise, the
pLevelStruct can potentially become invalid if another thread
reloads the cache tables and invalidates all handles.
Arguments:
hLevelObject - specifies the handle to the AuthzObject for which the
request is being made.
lpLevelObjectStruct - receives a pointer to the internal handle
structure that represents the specified AuthzLevelObject.
Return Value:
Returns STATUS_SUCCESS on success.
--*/
{
NTSTATUS Status;
ULONG ulHandleIndex;
if (!g_bInitializedFirstTime) {
return STATUS_UNSUCCESSFUL;
}
if (!ARGUMENT_PRESENT(hLevelObject)) {
return STATUS_INVALID_HANDLE;
}
if (!ARGUMENT_PRESENT(pLevelStruct)) {
return STATUS_ACCESS_VIOLATION;
}
RtlEnterCriticalSection(&g_TableCritSec);
ASSERT(!g_bNeedCacheReload);
//
// Translate the handle index into a pointer to the handle structure.
//
ulHandleIndex = PtrToUlong(hLevelObject);
if ( (ulHandleIndex & LEVEL_HANDLE_MASK) != LEVEL_HANDLE_BITS) {
Status = STATUS_INVALID_HANDLE;
goto ExitHandler;
}
ulHandleIndex &= ~LEVEL_HANDLE_MASK;
if (!RtlIsValidIndexHandle(&g_LevelHandleTable, ulHandleIndex,
(PRTL_HANDLE_TABLE_ENTRY*) pLevelStruct)) {
Status = STATUS_INVALID_HANDLE;
goto ExitHandler;
}
//
// Verify some additional sanity checks on the handle structure
// that was mapped. Ensure that it was not a handle that was
// opened, but invalidated because CodeAuthzReloadCacheTables was
// called before closing then Level handle.
//
if (*pLevelStruct == NULL ||
(*pLevelStruct)->dwHandleSequence != g_dwLevelHandleSequence ||
!CodeAuthzLevelObjpLookupByLevelId(
&g_CodeLevelObjTable, (*pLevelStruct)->dwLevelId ) )
{
Status = STATUS_INVALID_HANDLE;
goto ExitHandler;
}
Status = STATUS_SUCCESS;
ExitHandler:
RtlLeaveCriticalSection(&g_TableCritSec);
return Status;
}
NTSTATUS NTAPI
CodeAuthzCreateLevelHandle(
IN DWORD dwLevelId,
IN DWORD OpenFlags,
IN DWORD dwScopeId,
IN DWORD dwSaferFlags OPTIONAL,
OUT SAFER_LEVEL_HANDLE *pLevelHandle)
/*++
Routine Description:
Internal function to open a handle to a WinSafer Level.
Arguments:
dwLevelId - input level of the WinSafer Level to open.
Note that the dwScopeId argument does not affect the scope
of the level that is opened itself.
OpenFlags - flags that affect how the object is opened.
dwScopeId - input scope identifier that is stored within the
resulting handle. This scope identifier is used to affect
the behavior of SaferGet/SetLevelInformation for code identifier.
dwSaferFlags - flags that are stored within the resulting handle.
These flags are usually derived from the code identifier
that matched, and will be used in the final call to
SaferComputeTokenFromLevel.
pLevelHandle - receives the new handle.
Return Value:
Returns STATUS_SUCCESS on success.
--*/
{
NTSTATUS Status;
PAUTHZLEVELTABLERECORD pLevelRecord;
//
// Verify our input arguments are okay.
//
if (!ARGUMENT_PRESENT(pLevelHandle)) {
Status = STATUS_ACCESS_VIOLATION;
goto ExitHandler;
}
if ((OpenFlags & SAFER_LEVEL_CREATE) != 0 ||
(OpenFlags & SAFER_LEVEL_DELETE) != 0) {
// BLACKCOMB TODO: need to support creation or deletion.
Status = STATUS_NOT_IMPLEMENTED;
goto ExitHandler;
}
if (!g_bInitializedFirstTime) {
Status = STATUS_UNSUCCESSFUL;
goto ExitHandler;
}
RtlEnterCriticalSection(&g_TableCritSec);
if (g_bNeedCacheReload) {
Status = CodeAuthzpImmediateReloadCacheTables();
if (!NT_SUCCESS(Status)) {
goto ExitHandler2;
}
}
//
// Find the cached record for the requested level.
//
pLevelRecord = CodeAuthzLevelObjpLookupByLevelId(
&g_CodeLevelObjTable,
dwLevelId);
if (!pLevelRecord) {
Status = STATUS_NOT_FOUND;
goto ExitHandler2;
}
ASSERT(pLevelRecord->dwLevelId == dwLevelId);
//
// Actually create a Level handle for this record.
//
Status = CodeAuthzpCreateLevelHandleFromRecord(
pLevelRecord, dwScopeId,
dwSaferFlags, ERROR_SUCCESS, SaferIdentityDefault, NULL, pLevelHandle);
//
// Handle cleanup and error handling.
//
ExitHandler2:
RtlLeaveCriticalSection(&g_TableCritSec);
ExitHandler:
return Status;
}
NTSTATUS NTAPI
CodeAuthzCloseLevelHandle(
IN SAFER_LEVEL_HANDLE hLevelObject)
/*++
Routine Description:
Internal function to close an AuthzObject handle.
Arguments:
hLevelObject - the AuthzObject handle to close.
Return Value:
Returns STATUS_SUCCESS on success.
--*/
{
NTSTATUS Status;
ULONG ulHandleIndex;
PAUTHZLEVELHANDLESTRUCT pLevelStruct;
if (!ARGUMENT_PRESENT(hLevelObject)) {
Status = STATUS_INVALID_HANDLE;
goto ExitHandler;
}
if (!g_bInitializedFirstTime) {
Status = STATUS_UNSUCCESSFUL;
goto ExitHandler;
}
RtlEnterCriticalSection(&g_TableCritSec);
ulHandleIndex = PtrToUlong(hLevelObject);
if ( (ulHandleIndex & LEVEL_HANDLE_MASK) != LEVEL_HANDLE_BITS) {
Status = STATUS_INVALID_HANDLE;
goto ExitHandler2;
}
ulHandleIndex &= ~LEVEL_HANDLE_MASK;
if (!RtlIsValidIndexHandle(&g_LevelHandleTable, ulHandleIndex,
(PRTL_HANDLE_TABLE_ENTRY *) &pLevelStruct)) {
Status = STATUS_INVALID_HANDLE;
goto ExitHandler2;
}
if (!RtlFreeHandle(&g_LevelHandleTable,
(PRTL_HANDLE_TABLE_ENTRY) pLevelStruct)) {
Status = STATUS_INVALID_HANDLE;
goto ExitHandler2;
}
Status = STATUS_SUCCESS;
ExitHandler2:
RtlLeaveCriticalSection(&g_TableCritSec);
ExitHandler:
return Status;
}
BOOL WINAPI
SaferCreateLevel(
IN DWORD dwScopeId,
IN DWORD dwLevelId,
IN DWORD OpenFlags,
OUT SAFER_LEVEL_HANDLE *pLevelObject,
IN LPVOID lpReserved)
/*++
Routine Description:
Public function implementing the Unicode version of this API,
allowing the user to create or open an Authorization Object
and receive a handle representing the object.
Arguments:
dwScopeId - not used (anymore), reserved for future use.
dwLevelId - input object level of the AuthzObject to create/open.
OpenFlags - flags to control opening, creation, or deletion.
lpReserved - not used, reserved for future use.
pLevelObject - receives the new handle.
Return Value:
Returns FALSE on error, TRUE on success. Sets GetLastError() on error.
--*/
{
NTSTATUS Status;
//
// Verify the arguments were all supplied.
//
UNREFERENCED_PARAMETER(lpReserved);
if (!g_bInitializedFirstTime) {
Status = STATUS_UNSUCCESSFUL;
goto ExitHandler;
}
if (!ARGUMENT_PRESENT(pLevelObject)) {
Status = STATUS_ACCESS_VIOLATION;
goto ExitHandler;
}
RtlEnterCriticalSection(&g_TableCritSec);
if (g_hKeyCustomRoot != NULL) {
if (dwScopeId != SAFER_SCOPEID_REGISTRY) {
Status = STATUS_INVALID_PARAMETER_MIX;
goto ExitHandler2;
}
} else {
if (dwScopeId != SAFER_SCOPEID_MACHINE &&
dwScopeId != SAFER_SCOPEID_USER) {
Status = STATUS_INVALID_PARAMETER_MIX;
goto ExitHandler2;
}
}
//
// Actually call the worker functions to get it done.
//
Status = CodeAuthzCreateLevelHandle(
dwLevelId,
OpenFlags,
dwScopeId,
0,
pLevelObject);
//
// Set the error result.
//
ExitHandler2:
RtlLeaveCriticalSection(&g_TableCritSec);
ExitHandler:
if ( NT_SUCCESS( Status ) ) {
return TRUE;
}
BaseSetLastNTError(Status);
return FALSE;
}
BOOL WINAPI
SaferCloseLevel(
IN SAFER_LEVEL_HANDLE hLevelObject)
/*++
Routine Description:
Public function to close a handle to an Authorization Level Object.
Arguments:
hLevelObject - the AuthzObject handle to close.
Return Value:
Returns FALSE on error, TRUE on success.
--*/
{
NTSTATUS Status;
Status = CodeAuthzCloseLevelHandle(hLevelObject);
if (! NT_SUCCESS(Status) ) {
BaseSetLastNTError(Status);
return FALSE;
}
return TRUE;
}