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

1354 lines
39 KiB
C

/*++
Copyright (c) 1997-2000 Microsoft Corporation
Module Name:
safepolr.c (SAFER Code Authorization Policy)
Abstract:
This module implements the WinSAFER APIs that query and set the
persisted and cached policy definitions.
Author:
Jeffrey Lawson (JLawson) - Apr 1999
Environment:
User mode only.
Exported Functions:
Revision History:
Created - Apr 1999
--*/
#include "pch.h"
#pragma hdrstop
#include <winsafer.h>
#include <winsaferp.h>
#include "saferp.h"
NTSTATUS NTAPI
CodeAuthzPol_GetInfoCached_LevelListRaw(
IN DWORD dwScopeId,
IN DWORD InfoBufferSize OPTIONAL,
OUT PVOID InfoBuffer OPTIONAL,
OUT PDWORD InfoBufferRetSize OPTIONAL
)
/*++
Routine Description:
Asks the system to query for the list of available
WinSafer Levels for the currently loaded policy scope.
Arguments:
dwScopeId - specifies the registry scope that will be examined.
If the currently cached scope included a registry handle
then AUTHZSCOPE_REGISTRY must be specified. Otherwise,
this must be SAFER_SCOPEID_MACHINE.
InfoBufferSize - optionally specifies the size of input buffer
supplied by the caller to receive the results. If this argument
is supplied, then InfoBuffer must also be supplied.
InfoBuffer - optionally specifies the input buffer that was
supplied by the caller to receive the results. If this argument
is supplied, then InfoBufferSize must also be supplied.
InfoBufferRetSize - optionally specifies a pointer that will receive
the size of the results actually written to the InfoBuffer.
Return Value:
Returns STATUS_SUCCESS on successful return. Otherwise a status
code such as STATUS_BUFFER_TOO_SMALL or STATUS_NOT_FOUND.
--*/
{
NTSTATUS Status;
PVOID RestartKey;
PAUTHZLEVELTABLERECORD authzobj;
DWORD dwSizeNeeded;
LPVOID lpNextPtr, lpEndBuffer;
//
// Load the list of all of the available objects.
//
if (!g_bInitializedFirstTime) {
Status = STATUS_UNSUCCESSFUL;
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;
}
}
if (g_bNeedCacheReload) {
Status = CodeAuthzpImmediateReloadCacheTables();
if (!NT_SUCCESS(Status)) {
goto ExitHandler2;
}
}
if (RtlIsGenericTableEmpty(&g_CodeLevelObjTable)) {
Status = STATUS_NOT_FOUND;
goto ExitHandler2;
}
//
// Determine the necessary size needed to store a DWORD array
// of all of the Levels that were found in this scope.
//
dwSizeNeeded = 0;
RestartKey = NULL;
for (authzobj = (PAUTHZLEVELTABLERECORD)
RtlEnumerateGenericTableWithoutSplaying(
&g_CodeLevelObjTable, &RestartKey);
authzobj != NULL;
authzobj = (PAUTHZLEVELTABLERECORD)
RtlEnumerateGenericTableWithoutSplaying(
&g_CodeLevelObjTable, &RestartKey))
{
if (authzobj->isEnumerable) { //only allow enumeration if the level is enumerable
dwSizeNeeded += sizeof(DWORD);
}
}
if (!ARGUMENT_PRESENT(InfoBuffer) ||
!InfoBufferSize ||
InfoBufferSize < dwSizeNeeded)
{
if (ARGUMENT_PRESENT(InfoBufferRetSize))
*InfoBufferRetSize = dwSizeNeeded;
Status = STATUS_BUFFER_TOO_SMALL;
goto ExitHandler2;
}
//
// Fill the buffer with the resulting data.
//
lpNextPtr = (LPVOID) InfoBuffer;
lpEndBuffer = (LPVOID) ( ((LPBYTE) InfoBuffer) + InfoBufferSize);
RestartKey = NULL;
for (authzobj = (PAUTHZLEVELTABLERECORD)
RtlEnumerateGenericTableWithoutSplaying(
&g_CodeLevelObjTable, &RestartKey);
authzobj != NULL;
authzobj = (PAUTHZLEVELTABLERECORD)
RtlEnumerateGenericTableWithoutSplaying(
&g_CodeLevelObjTable, &RestartKey))
{
if (authzobj->isEnumerable) { //only allow enumeration if the level is enumerable
*((PDWORD)lpNextPtr) = authzobj->dwLevelId;
lpNextPtr = (LPVOID) ( ((PBYTE) lpNextPtr) + sizeof(DWORD));
}
}
ASSERT(lpNextPtr <= lpEndBuffer);
//
// Return the final buffer size and result code.
//
if (ARGUMENT_PRESENT(InfoBufferRetSize))
*InfoBufferRetSize = (DWORD) ((PBYTE) lpNextPtr - (PBYTE) InfoBuffer);
Status = STATUS_SUCCESS;
ExitHandler2:
RtlLeaveCriticalSection(&g_TableCritSec);
ExitHandler:
return Status;
}
NTSTATUS NTAPI
SaferpPol_GetInfoCommon_DefaultLevel(
IN DWORD dwScopeId,
IN DWORD InfoBufferSize OPTIONAL,
OUT PVOID InfoBuffer OPTIONAL,
OUT PDWORD InfoBufferRetSize OPTIONAL,
IN BOOLEAN bUseCached
)
/*++
Routine Description:
Queries the current WinSafer Level that has been configured to be
the default policy level.
Note that this query always accepts a constant-sized buffer that
is only a single DWORD in length.
Although this API directly queries the registry scope indicated,
the pre-cached list of available Levels is used to validate the
specified Level.
Arguments:
dwScopeId - specifies the registry scope that will be examined.
If the currently cached scope included a registry handle
then AUTHZSCOPE_REGISTRY must be specified. Otherwise,
this can be SAFER_SCOPEID_MACHINE or SAFER_SCOPEID_USER.
InfoBufferSize - optionally specifies the size of input buffer
supplied by the caller to receive the results. If this argument
is supplied, then InfoBuffer must also be supplied.
InfoBuffer - optionally specifies the input buffer that was
supplied by the caller to receive the results. If this argument
is supplied, then InfoBufferSize must also be supplied.
InfoBufferRetSize - optionally specifies a pointer that will receive
the size of the results actually written to the InfoBuffer.
Return Value:
Returns STATUS_SUCCESS on a successful query result. InfoBuffer will
be filled with a single DWORD of the level that has been configured
to be the default level for this scope. InfoBufferRetSize will
contain the length of the result (a single DWORD).
Returns STATUS_NOT_FOUND if no default level has been configured
for the given scope (or the level defined does not exist).
Returns STATUS_BUFFER_TOO_SMALL if there was a defined default level
but a buffer was not supplied, or the buffer supplied was too
small to accomodate the results.
--*/
{
NTSTATUS Status;
DWORD dwNewLevelId = (DWORD) -1;
//
// Open up the regkey to the base of the policies.
//
if (!g_bInitializedFirstTime) {
Status = STATUS_UNSUCCESSFUL;
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;
}
}
if (g_bNeedCacheReload) {
Status = CodeAuthzpImmediateReloadCacheTables();
if (!NT_SUCCESS(Status)) {
goto ExitHandler2;
}
}
if (RtlIsGenericTableEmpty(&g_CodeLevelObjTable)) {
Status = STATUS_NOT_FOUND;
goto ExitHandler2;
}
//
// Query the current value setting.
//
if (!bUseCached)
{
HANDLE hKeyBase;
ULONG ActualSize;
UNICODE_STRING ValueName;
WCHAR KeyPathBuffer[ MAXIMUM_FILENAME_LENGTH+6 ];
PKEY_VALUE_FULL_INFORMATION ValueBuffer =
(PKEY_VALUE_FULL_INFORMATION) KeyPathBuffer;
Status = CodeAuthzpOpenPolicyRootKey(
dwScopeId,
g_hKeyCustomRoot,
L"\\" SAFER_CODEIDS_REGSUBKEY,
KEY_READ, FALSE, &hKeyBase);
if (NT_SUCCESS(Status))
{
RtlInitUnicodeString(&ValueName, SAFER_DEFAULTOBJ_REGVALUE);
Status = NtQueryValueKey(hKeyBase,
&ValueName,
KeyValueFullInformation,
ValueBuffer, // ptr to KeyPathBuffer
sizeof(KeyPathBuffer),
&ActualSize);
if (NT_SUCCESS(Status)) {
if (ValueBuffer->Type != REG_DWORD ||
ValueBuffer->DataLength != sizeof(DWORD)) {
Status = STATUS_NOT_FOUND;
} else {
dwNewLevelId = * (PDWORD) ((PBYTE) ValueBuffer +
ValueBuffer->DataOffset);
}
}
NtClose(hKeyBase);
}
if (!NT_SUCCESS(Status)) {
goto ExitHandler2;
}
}
else
{
if (dwScopeId == SAFER_SCOPEID_USER) {
if (!g_DefaultCodeLevelUser) {
dwNewLevelId = SAFER_LEVELID_FULLYTRUSTED;
} else {
dwNewLevelId = g_DefaultCodeLevelUser->dwLevelId;
}
} else {
if (!g_DefaultCodeLevelMachine) {
dwNewLevelId = SAFER_LEVELID_FULLYTRUSTED;
} else {
dwNewLevelId = g_DefaultCodeLevelMachine->dwLevelId;
}
}
}
//
// Make sure the level we found is actually
// valid (still in our level table).
//
if (!CodeAuthzLevelObjpLookupByLevelId(
&g_CodeLevelObjTable, dwNewLevelId)) {
Status = STATUS_NOT_FOUND;
goto ExitHandler2;
}
//
// Make sure the target buffer is large
// enough and copy the levelid into it.
//
if (!ARGUMENT_PRESENT(InfoBuffer) ||
InfoBufferSize < sizeof(DWORD)) {
Status = STATUS_BUFFER_TOO_SMALL;
} else {
RtlCopyMemory(InfoBuffer, &dwNewLevelId, sizeof(DWORD));
Status = STATUS_SUCCESS;
}
if (ARGUMENT_PRESENT(InfoBufferRetSize))
*InfoBufferRetSize = sizeof(DWORD);
ExitHandler2:
RtlLeaveCriticalSection(&g_TableCritSec);
ExitHandler:
return Status;
}
NTSTATUS NTAPI
CodeAuthzPol_GetInfoCached_DefaultLevel(
IN DWORD dwScopeId,
IN DWORD InfoBufferSize OPTIONAL,
OUT PVOID InfoBuffer OPTIONAL,
OUT PDWORD InfoBufferRetSize OPTIONAL
)
{
return SaferpPol_GetInfoCommon_DefaultLevel(
dwScopeId,
InfoBufferSize,
InfoBuffer,
InfoBufferRetSize,
TRUE);
}
NTSTATUS NTAPI
CodeAuthzPol_GetInfoRegistry_DefaultLevel(
IN DWORD dwScopeId,
IN DWORD InfoBufferSize OPTIONAL,
OUT PVOID InfoBuffer OPTIONAL,
OUT PDWORD InfoBufferRetSize OPTIONAL
)
{
return SaferpPol_GetInfoCommon_DefaultLevel(
dwScopeId,
InfoBufferSize,
InfoBuffer,
InfoBufferRetSize,
FALSE);
}
NTSTATUS NTAPI
CodeAuthzPol_SetInfoDual_DefaultLevel(
IN DWORD dwScopeId,
IN DWORD InfoBufferSize,
OUT PVOID InfoBuffer
)
/*++
Routine Description:
Modifies the current WinSafer Level that has been configured to be
the default policy level.
Note that this query always accepts a constant-sized buffer that
is only a single DWORD in length.
Arguments:
dwScopeId - specifies the registry scope that will be examined.
If the currently cached scope included a registry handle
then AUTHZSCOPE_REGISTRY must be specified. Otherwise,
this can be SAFER_SCOPEID_MACHINE or SAFER_SCOPEID_USER.
InfoBufferSize - specifies the size of input buffer
supplied by the caller to receive the results.
InfoBuffer - specifies the input buffer that was
supplied by the caller to receive the results.
Return Value:
Returns STATUS_SUCCESS on a successful query result. InfoBuffer will
be filled with a single DWORD of the level that has been configured
to be the default level for this scope. InfoBufferRetSize will
contain the length of the result (a single DWORD).
Returns STATUS_NOT_FOUND if no default level has been configured
for the given scope (or the level defined does not exist).
Returns STATUS_BUFFER_TOO_SMALL if there was a defined default level
but a buffer was not supplied, or the buffer supplied was too
small to accomodate the results.
--*/
{
NTSTATUS Status;
HANDLE hKeyBase;
DWORD dwNewLevelId;
UNICODE_STRING ValueName;
PAUTHZLEVELTABLERECORD pLevelRecord;
//
// Open up the regkey to the base of the policies.
//
if (!g_bInitializedFirstTime) {
Status = STATUS_UNSUCCESSFUL;
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;
}
}
if (g_bNeedCacheReload) {
Status = CodeAuthzpImmediateReloadCacheTables();
if (!NT_SUCCESS(Status)) {
goto ExitHandler2;
}
}
Status = CodeAuthzpOpenPolicyRootKey(
dwScopeId,
g_hKeyCustomRoot,
L"\\" SAFER_CODEIDS_REGSUBKEY,
KEY_READ | KEY_SET_VALUE,
TRUE, &hKeyBase);
if (!NT_SUCCESS(Status)) {
goto ExitHandler2;
}
//
// Load the list of all of the available objects.
//
if (RtlIsGenericTableEmpty(&g_CodeLevelObjTable)) {
Status = STATUS_NOT_FOUND;
goto ExitHandler3;
}
//
// If we are going to set a new default object,
// make sure it is a valid one.
//
if (InfoBufferSize < sizeof(DWORD) ||
!ARGUMENT_PRESENT(InfoBuffer))
{
// Caller wants to clear the default object.
InfoBuffer = NULL;
pLevelRecord = NULL;
}
else
{
dwNewLevelId = *(PDWORD) InfoBuffer;
pLevelRecord = CodeAuthzLevelObjpLookupByLevelId(
&g_CodeLevelObjTable, dwNewLevelId);
if (!pLevelRecord)
{
// Caller was trying to set the default to an
// authorization object that does not exist.
Status = STATUS_NOT_FOUND;
goto ExitHandler3;
}
}
//
// Write the name of the default object that is specified.
//
RtlInitUnicodeString(&ValueName, SAFER_DEFAULTOBJ_REGVALUE);
Status = NtSetValueKey(hKeyBase,
&ValueName,
0,
REG_DWORD,
&dwNewLevelId,
sizeof(DWORD));
if (NT_SUCCESS(Status)) {
if (dwScopeId == SAFER_SCOPEID_USER) {
g_DefaultCodeLevelUser = pLevelRecord;
} else {
g_DefaultCodeLevelMachine = pLevelRecord;
}
//
// Compute the effective Default Level (take the least privileged).
//
CodeAuthzpRecomputeEffectiveDefaultLevel();
}
ExitHandler3:
NtClose(hKeyBase);
ExitHandler2:
RtlLeaveCriticalSection(&g_TableCritSec);
ExitHandler:
return Status;
}
NTSTATUS NTAPI
SaferpPol_GetInfoCommon_HonorUserIdentities(
IN DWORD dwScopeId,
IN DWORD InfoBufferSize OPTIONAL,
OUT PVOID InfoBuffer OPTIONAL,
OUT PDWORD InfoBufferRetSize OPTIONAL,
IN BOOLEAN bUseCached
)
/*++
Routine Description:
Queries the current WinSafer policy to determine if Code Identities
defined within the User's registry scope should be considered.
Note that this query always accepts a constant-sized buffer that is
only a single DWORD in length.
Arguments:
dwScopeId - specifies the registry scope that will be examined.
If the currently cached scope included a registry handle
then AUTHZSCOPE_REGISTRY must be specified. Otherwise,
this must be SAFER_SCOPEID_MACHINE.
InfoBufferSize - optionally specifies the size of input buffer
supplied by the caller to receive the results. If this argument
is supplied, then InfoBuffer must also be supplied.
InfoBuffer - optionally specifies the input buffer that was
supplied by the caller to receive the results. If this argument
is supplied, then InfoBufferSize must also be supplied.
InfoBufferRetSize - optionally specifies a pointer that will receive
the size of the results actually written to the InfoBuffer.
Return Value:
Returns STATUS_SUCCESS on a successful query result.
InfoBuffer will be filled with a single DWORD containing
either a TRUE or FALSE value that indicates whether the option
is enabled. InfoBufferRetSize will contain the length of the
result (a single DWORD).
Returns STATUS_BUFFER_TOO_SMALL if the buffer was not supplied, or
the buffer supplied was too small to accomodate the result.
--*/
{
NTSTATUS Status;
DWORD dwValueState = (DWORD) -1;
//
// Open up the regkey to the base of the policies.
//
if (!g_bInitializedFirstTime) {
Status = STATUS_UNSUCCESSFUL;
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) {
Status = STATUS_INVALID_PARAMETER_MIX;
goto ExitHandler2;
}
}
if (g_bNeedCacheReload) {
Status = CodeAuthzpImmediateReloadCacheTables();
if (!NT_SUCCESS(Status)) {
goto ExitHandler2;
}
}
//
// Read or write the name of the policy value that is specified.
//
if (!bUseCached)
{
HANDLE hKeyBase;
ULONG ActualSize;
UNICODE_STRING ValueName;
WCHAR KeyPathBuffer[ MAXIMUM_FILENAME_LENGTH+6 ];
PKEY_VALUE_FULL_INFORMATION ValueBuffer =
(PKEY_VALUE_FULL_INFORMATION) KeyPathBuffer;
Status = CodeAuthzpOpenPolicyRootKey(
dwScopeId,
g_hKeyCustomRoot,
L"\\" SAFER_CODEIDS_REGSUBKEY,
KEY_READ, FALSE, &hKeyBase);
if (NT_SUCCESS(Status))
{
RtlInitUnicodeString(&ValueName,
SAFER_HONORUSER_REGVALUE);
Status = NtQueryValueKey(hKeyBase,
&ValueName,
KeyValueFullInformation,
ValueBuffer, // ptr to KeyPathBuffer
sizeof(KeyPathBuffer),
&ActualSize);
if (NT_SUCCESS(Status)) {
if (ValueBuffer->Type != REG_DWORD ||
ValueBuffer->DataLength != sizeof(DWORD)) {
Status = STATUS_NOT_FOUND;
} else {
dwValueState = * (PDWORD) ((PBYTE) ValueBuffer +
ValueBuffer->DataOffset);
}
}
NtClose(hKeyBase);
}
if (!NT_SUCCESS(Status)) {
goto ExitHandler2;
}
}
else
{
dwValueState = (g_bHonorScopeUser ? TRUE : FALSE);
}
//
// Make sure the target buffer is large
// enough and copy the object name into it.
//
if (!ARGUMENT_PRESENT(InfoBuffer) ||
InfoBufferSize < sizeof(DWORD)) {
Status = STATUS_BUFFER_TOO_SMALL;
} else {
RtlCopyMemory(InfoBuffer, &dwValueState, sizeof(DWORD));
Status = STATUS_SUCCESS;
}
if (ARGUMENT_PRESENT(InfoBufferRetSize))
*InfoBufferRetSize = sizeof(DWORD);
ExitHandler2:
RtlLeaveCriticalSection(&g_TableCritSec);
ExitHandler:
return Status;
}
NTSTATUS NTAPI
CodeAuthzPol_GetInfoCached_HonorUserIdentities(
IN DWORD dwScopeId,
IN DWORD InfoBufferSize OPTIONAL,
OUT PVOID InfoBuffer OPTIONAL,
OUT PDWORD InfoBufferRetSize OPTIONAL
)
{
return SaferpPol_GetInfoCommon_HonorUserIdentities(
dwScopeId, InfoBufferSize,
InfoBuffer, InfoBufferRetSize, TRUE);
}
NTSTATUS NTAPI
CodeAuthzPol_GetInfoRegistry_HonorUserIdentities(
IN DWORD dwScopeId,
IN DWORD InfoBufferSize OPTIONAL,
OUT PVOID InfoBuffer OPTIONAL,
OUT PDWORD InfoBufferRetSize OPTIONAL
)
{
return SaferpPol_GetInfoCommon_HonorUserIdentities(
dwScopeId, InfoBufferSize,
InfoBuffer, InfoBufferRetSize, FALSE);
}
NTSTATUS NTAPI
CodeAuthzPol_SetInfoDual_HonorUserIdentities(
IN DWORD dwScopeId,
IN DWORD InfoBufferSize,
IN PVOID InfoBuffer
)
/*++
Routine Description:
Queries the current WinSafer policy to determine if Code Identities
defined within the User's registry scope should be considered.
Note that this API always accepts a constant-sized buffer that is
only a single DWORD in length.
Arguments:
dwScopeId - specifies the registry scope that will be examined.
If the currently cached scope included a registry handle
then AUTHZSCOPE_REGISTRY must be specified. Otherwise,
this must be SAFER_SCOPEID_MACHINE.
InfoBufferSize - specifies the size of input buffer
supplied by the caller to receive the results. If this argument
is supplied, then InfoBuffer must also be supplied.
InfoBuffer - specifies the input buffer that was
supplied by the caller to receive the results. If this argument
is supplied, then InfoBufferSize must also be supplied.
Return Value:
Returns STATUS_SUCCESS on a successful query result. InfoBuffer will
be filled with a single DWORD of the level that has been configured
to be the default level for this scope. InfoBufferRetSize will
contain the length of the result (a single DWORD).
Returns STATUS_NOT_FOUND if no default level has been configured
for the given scope (or the level defined does not exist).
Returns STATUS_BUFFER_TOO_SMALL if there was a defined default level
but a buffer was not supplied, or the buffer supplied was too
small to accomodate the results.
--*/
{
HANDLE hKeyBase;
NTSTATUS Status;
UNICODE_STRING ValueName;
//
// Open up the regkey to the base of the policies.
//
if (!g_bInitializedFirstTime) {
Status = STATUS_UNSUCCESSFUL;
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) {
Status = STATUS_INVALID_PARAMETER_MIX;
goto ExitHandler2;
}
}
if (g_bNeedCacheReload) {
Status = CodeAuthzpImmediateReloadCacheTables();
if (!NT_SUCCESS(Status)) {
goto ExitHandler2;
}
}
Status = CodeAuthzpOpenPolicyRootKey(
dwScopeId,
g_hKeyCustomRoot,
L"\\" SAFER_CODEIDS_REGSUBKEY,
(KEY_READ | KEY_SET_VALUE),
TRUE, &hKeyBase);
if (!NT_SUCCESS(Status)) {
goto ExitHandler2;
}
//
// Make sure the input buffer is large enough.
//
if (InfoBufferSize < sizeof(DWORD) ||
!ARGUMENT_PRESENT(InfoBuffer)) {
Status = STATUS_BUFFER_TOO_SMALL;
goto ExitHandler3;
}
//
// Write the policy value that is specified.
//
RtlInitUnicodeString(&ValueName, SAFER_HONORUSER_REGVALUE);
Status = NtSetValueKey(hKeyBase,
&ValueName,
0,
REG_DWORD,
InfoBuffer,
sizeof(DWORD));
if (NT_SUCCESS(Status)) {
BOOLEAN bNewHonorScopeUser = (*((PDWORD)InfoBuffer) != 0 ? TRUE : FALSE);
if (g_bHonorScopeUser != bNewHonorScopeUser)
{
g_bHonorScopeUser = bNewHonorScopeUser;
//
// If the actual value is different from what we had then we
// need to purge the identities table and reload the only the
// parts that we should consider.
//
if (g_hKeyCustomRoot == NULL)
{
CodeAuthzGuidIdentsEntireTableFree(&g_CodeIdentitiesTable);
CodeAuthzGuidIdentsLoadTableAll(
&g_CodeLevelObjTable,
&g_CodeIdentitiesTable,
SAFER_SCOPEID_MACHINE,
NULL);
if (g_bHonorScopeUser) {
CodeAuthzGuidIdentsLoadTableAll(
&g_CodeLevelObjTable,
&g_CodeIdentitiesTable,
SAFER_SCOPEID_USER,
NULL);
}
}
}
}
ExitHandler3:
NtClose(hKeyBase);
ExitHandler2:
RtlLeaveCriticalSection(&g_TableCritSec);
ExitHandler:
return Status;
}
NTSTATUS NTAPI
CodeAuthzPol_GetInfoRegistry_TransparentEnabled(
IN DWORD dwScopeId,
IN DWORD InfoBufferSize OPTIONAL,
OUT PVOID InfoBuffer OPTIONAL,
OUT PDWORD InfoBufferRetSize OPTIONAL
)
/*++
Routine Description:
Queries the current "transparent enforcement" setting. This is a
global setting that can be used to enable or disable automatic
WinSafer token reductions.
Arguments:
dwScopeId - specifies the registry scope that will be examined.
If the currently cached scope included a registry handle
then AUTHZSCOPE_REGISTRY must be specified. Otherwise,
this must be SAFER_SCOPEID_MACHINE.
InfoBufferSize - optionally specifies the size of input buffer
supplied by the caller to receive the results. If this argument
is supplied, then InfoBuffer must also be supplied.
InfoBuffer - optionally specifies the input buffer that was
supplied by the caller to receive the results. If this argument
is supplied, then InfoBufferSize must also be supplied.
InfoBufferRetSize - optionally specifies a pointer that will receive
the size of the results actually written to the InfoBuffer.
Return Value:
Returns STATUS_SUCCESS on a successful query result. If the
operation is not successful, then the contents of 'pdwEnabled'
are left untouched.
--*/
{
NTSTATUS Status;
DWORD dwValueState = (DWORD) -1;
//
// Open up the regkey to the base of the policies.
//
if (!g_bInitializedFirstTime) {
Status = STATUS_UNSUCCESSFUL;
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) {
Status = STATUS_INVALID_PARAMETER_MIX;
goto ExitHandler2;
}
}
//
// Query the current value setting.
//
{
HANDLE hKeyBase;
DWORD ActualSize;
UNICODE_STRING ValueName;
WCHAR KeyPathBuffer[ MAXIMUM_FILENAME_LENGTH+6 ];
PKEY_VALUE_FULL_INFORMATION ValueBuffer =
(PKEY_VALUE_FULL_INFORMATION) KeyPathBuffer;
Status = CodeAuthzpOpenPolicyRootKey(
dwScopeId,
g_hKeyCustomRoot,
L"\\" SAFER_CODEIDS_REGSUBKEY,
KEY_READ, FALSE, &hKeyBase);
if (NT_SUCCESS(Status)) {
RtlInitUnicodeString(&ValueName,
SAFER_TRANSPARENTENABLED_REGVALUE);
Status = NtQueryValueKey(hKeyBase,
&ValueName,
KeyValueFullInformation,
ValueBuffer, // ptr to KeyPathBuffer
sizeof(KeyPathBuffer),
&ActualSize);
if (NT_SUCCESS(Status)) {
if (ValueBuffer->Type != REG_DWORD ||
ValueBuffer->DataLength != sizeof(DWORD)) {
Status = STATUS_NOT_FOUND;
} else {
dwValueState = * (PDWORD) ((PBYTE) ValueBuffer +
ValueBuffer->DataOffset);
}
}
NtClose(hKeyBase);
}
if (!NT_SUCCESS(Status)) {
// On failure, just ignore it and pretend it was FALSE.
dwValueState = FALSE;
}
}
//
// Make sure the target buffer is large
// enough and copy the object name into it.
//
if (!ARGUMENT_PRESENT(InfoBuffer) ||
InfoBufferSize < sizeof(DWORD)) {
Status = STATUS_BUFFER_TOO_SMALL;
} else {
RtlCopyMemory(InfoBuffer, &dwValueState, sizeof(DWORD));
Status = STATUS_SUCCESS;
}
if (ARGUMENT_PRESENT(InfoBufferRetSize))
*InfoBufferRetSize = sizeof(DWORD);
ExitHandler2:
RtlLeaveCriticalSection(&g_TableCritSec);
ExitHandler:
return Status;
}
NTSTATUS NTAPI
CodeAuthzPol_SetInfoRegistry_TransparentEnabled(
IN DWORD dwScopeId,
IN DWORD InfoBufferSize,
IN PVOID InfoBuffer
)
/*++
Routine Description:
Modifies the current "transparent enforcement" setting. This is a
global setting that can be used to enable or disable automatic
WinSafer token reductions.
Note that this API always accepts a constant-sized buffer that is
only a single DWORD in length.
Arguments:
dwScopeId - specifies the registry scope that will be examined.
If the currently cached scope included a registry handle
then AUTHZSCOPE_REGISTRY must be specified. Otherwise,
this must be SAFER_SCOPEID_MACHINE.
InfoBufferSize - specifies the size of input buffer
supplied by the caller to receive the results. If this argument
is supplied, then InfoBuffer must also be supplied.
InfoBuffer - specifies the input buffer that was
supplied by the caller to receive the results. If this argument
is supplied, then InfoBufferSize must also be supplied.
Return Value:
Returns STATUS_SUCCESS on a successful result.
--*/
{
HANDLE hKeyBase;
NTSTATUS Status;
UNICODE_STRING ValueName;
//
// Open up the regkey to the base of the policies.
//
if (!g_bInitializedFirstTime) {
Status = STATUS_UNSUCCESSFUL;
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) {
Status = STATUS_INVALID_PARAMETER_MIX;
goto ExitHandler2;
}
}
Status = CodeAuthzpOpenPolicyRootKey(
dwScopeId, g_hKeyCustomRoot,
L"\\" SAFER_CODEIDS_REGSUBKEY,
KEY_READ | KEY_SET_VALUE,
TRUE, &hKeyBase);
if (!NT_SUCCESS(Status)) {
goto ExitHandler2;
}
//
// Make sure the input buffer is large enough.
//
if (InfoBufferSize < sizeof(DWORD) ||
!ARGUMENT_PRESENT(InfoBuffer)) {
Status = STATUS_BUFFER_TOO_SMALL;
goto ExitHandler3;
}
//
// Write the policy value that is specified.
//
RtlInitUnicodeString(&ValueName,
SAFER_TRANSPARENTENABLED_REGVALUE);
Status = NtSetValueKey(hKeyBase,
&ValueName,
0,
REG_DWORD,
InfoBuffer,
sizeof(DWORD));
ExitHandler3:
NtClose(hKeyBase);
ExitHandler2:
RtlLeaveCriticalSection(&g_TableCritSec);
ExitHandler:
return Status;
}
NTSTATUS NTAPI
CodeAuthzPol_GetInfoRegistry_ScopeFlags(
IN DWORD dwScopeId,
IN DWORD InfoBufferSize OPTIONAL,
OUT PVOID InfoBuffer OPTIONAL,
OUT PDWORD InfoBufferRetSize OPTIONAL
)
/*++
Routine Description:
Queries the current "scope flags" setting.
Arguments:
dwScopeId - specifies the registry scope that will be examined.
If the currently cached scope included a registry handle
then AUTHZSCOPE_REGISTRY must be specified. Otherwise,
this must be SAFER_SCOPEID_MACHINE.
InfoBufferSize - optionally specifies the size of input buffer
supplied by the caller to receive the results. If this argument
is supplied, then InfoBuffer must also be supplied.
InfoBuffer - optionally specifies the input buffer that was
supplied by the caller to receive the results. If this argument
is supplied, then InfoBufferSize must also be supplied.
InfoBufferRetSize - optionally specifies a pointer that will receive
the size of the results actually written to the InfoBuffer.
Return Value:
Returns STATUS_SUCCESS on a successful query result. If the
operation is not successful, then the contents of 'pdwEnabled'
are left untouched.
--*/
{
NTSTATUS Status;
DWORD dwValueState = (DWORD) 0;
//
// Open up the regkey to the base of the policies.
//
if (!g_bInitializedFirstTime) {
Status = STATUS_UNSUCCESSFUL;
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) {
Status = STATUS_INVALID_PARAMETER_MIX;
goto ExitHandler2;
}
}
//
// Query the current value setting.
//
{
HANDLE hKeyBase;
DWORD ActualSize;
UNICODE_STRING ValueName;
WCHAR KeyPathBuffer[ MAXIMUM_FILENAME_LENGTH+6 ];
PKEY_VALUE_FULL_INFORMATION ValueBuffer =
(PKEY_VALUE_FULL_INFORMATION) KeyPathBuffer;
Status = CodeAuthzpOpenPolicyRootKey(
dwScopeId,
g_hKeyCustomRoot,
L"\\" SAFER_CODEIDS_REGSUBKEY,
KEY_READ, FALSE, &hKeyBase);
if (NT_SUCCESS(Status)) {
RtlInitUnicodeString(&ValueName,
SAFER_POLICY_SCOPE);
Status = NtQueryValueKey(hKeyBase,
&ValueName,
KeyValueFullInformation,
ValueBuffer, // ptr to KeyPathBuffer
sizeof(KeyPathBuffer),
&ActualSize);
if (NT_SUCCESS(Status)) {
if (ValueBuffer->Type != REG_DWORD ||
ValueBuffer->DataLength != sizeof(DWORD)) {
Status = STATUS_NOT_FOUND;
} else {
dwValueState = * (PDWORD) ((PBYTE) ValueBuffer +
ValueBuffer->DataOffset);
}
}
NtClose(hKeyBase);
}
if (!NT_SUCCESS(Status)) {
// On failure, just ignore it and pretend it was FALSE.
dwValueState = 0;
}
}
//
// Make sure the target buffer is large
// enough and copy the object name into it.
//
if (!ARGUMENT_PRESENT(InfoBuffer) ||
InfoBufferSize < sizeof(DWORD)) {
Status = STATUS_BUFFER_TOO_SMALL;
} else {
RtlCopyMemory(InfoBuffer, &dwValueState, sizeof(DWORD));
Status = STATUS_SUCCESS;
}
if (ARGUMENT_PRESENT(InfoBufferRetSize))
*InfoBufferRetSize = sizeof(DWORD);
ExitHandler2:
RtlLeaveCriticalSection(&g_TableCritSec);
ExitHandler:
return Status;
}
NTSTATUS NTAPI
CodeAuthzPol_SetInfoRegistry_ScopeFlags(
IN DWORD dwScopeId,
IN DWORD InfoBufferSize,
IN PVOID InfoBuffer
)
/*++
Routine Description:
Modifies the current "scope flags" setting.
Note that this API always accepts a constant-sized buffer that is
only a single DWORD in length.
Arguments:
dwScopeId - specifies the registry scope that will be examined.
If the currently cached scope included a registry handle
then AUTHZSCOPE_REGISTRY must be specified. Otherwise,
this must be SAFER_SCOPEID_MACHINE.
InfoBufferSize - specifies the size of input buffer
supplied by the caller to receive the results. If this argument
is supplied, then InfoBuffer must also be supplied.
InfoBuffer - specifies the input buffer that was
supplied by the caller to receive the results. If this argument
is supplied, then InfoBufferSize must also be supplied.
Return Value:
Returns STATUS_SUCCESS on a successful result.
--*/
{
HANDLE hKeyBase;
NTSTATUS Status;
UNICODE_STRING ValueName;
//
// Open up the regkey to the base of the policies.
//
if (!g_bInitializedFirstTime) {
Status = STATUS_UNSUCCESSFUL;
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) {
Status = STATUS_INVALID_PARAMETER_MIX;
goto ExitHandler2;
}
}
Status = CodeAuthzpOpenPolicyRootKey(
dwScopeId, g_hKeyCustomRoot,
L"\\" SAFER_CODEIDS_REGSUBKEY,
KEY_READ | KEY_SET_VALUE,
TRUE, &hKeyBase);
if (!NT_SUCCESS(Status)) {
goto ExitHandler2;
}
//
// Make sure the input buffer is large enough.
//
if (InfoBufferSize < sizeof(DWORD) ||
!ARGUMENT_PRESENT(InfoBuffer)) {
Status = STATUS_BUFFER_TOO_SMALL;
goto ExitHandler3;
}
//
// Write the policy value that is specified.
//
RtlInitUnicodeString(&ValueName,
SAFER_POLICY_SCOPE);
Status = NtSetValueKey(hKeyBase,
&ValueName,
0,
REG_DWORD,
InfoBuffer,
sizeof(DWORD));
ExitHandler3:
NtClose(hKeyBase);
ExitHandler2:
RtlLeaveCriticalSection(&g_TableCritSec);
ExitHandler:
return Status;
}