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

1690 lines
58 KiB
C

/*++
Copyright (c) 1999-2000 Microsoft Corporation
Module Name:
SafeLevp.c (WinSAFER Level table privates)
Abstract:
This module implements the WinSAFER APIs that loads the names (and
high-level information) of all Authorization Levels defined within
a given registry context. The list of available levels is loaded
into a Rtl Generic Table that can be enumerated and accessed using
conventional Rtl Generic Table techniques.
Author:
Jeffrey Lawson (JLawson) - Nov 1999
Environment:
User mode only.
Exported Functions:
CodeAuthzLevelObjpInitializeTable
CodeAuthzLevelObjpLoadTable
CodeAuthzLevelObjpEntireTableFree
Revision History:
Created - Nov 1999
--*/
#include "pch.h"
#pragma hdrstop
#include <sddl.h>
#include <winsafer.h>
#include <winsaferp.h>
#include <winsafer.rh>
#include "saferp.h"
//
// Private enumerators used as the EntryContext parameter in our
// callback function CodeAuthzpBuildRestrictedToken during the
// call to RtlQueryRegistryValues.
//
#define AUTHZREGQUERY_IGNORE (0)
#define AUTHZREGQUERY_DISALLOWEXECUTION (1)
#define AUTHZREGQUERY_PTR_DISABLEMAX (2)
#define AUTHZREGQUERY_PTR_COUNT (3)
#define AUTHZREGQUERY_PTR_PRIVS (4)
#define AUTHZREGQUERY_PTR_INVERT (5)
#define AUTHZREGQUERY_RSADD_COUNT (6)
#define AUTHZREGQUERY_RSADD_SIDS (7)
#define AUTHZREGQUERY_RSINV_COUNT (8)
#define AUTHZREGQUERY_RSINV_SIDS (9)
#define AUTHZREGQUERY_STD_COUNT (10)
#define AUTHZREGQUERY_STD_SIDS (11)
#define AUTHZREGQUERY_STD_INVERT (12)
#define AUTHZREGQUERY_DEFAULTOWNER (13)
#define AUTHZREGQUERY_SAFERFLAGS (14)
#define AUTHZREGQUERY_DESCRIPTION (15)
#define AUTHZREGQUERY_FRIENDLYNAME (16)
//
// Prototype for the callback function used within the following table.
//
NTSTATUS NTAPI
SaferpBuildRestrictedToken(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext
);
PVOID NTAPI
SaferpGenericTableAllocate (
IN PRTL_GENERIC_TABLE Table,
IN CLONG ByteSize
);
VOID NTAPI
SaferpGenericTableFree (
IN PRTL_GENERIC_TABLE Table,
IN PVOID Buffer
);
//
// Internal structure used as an argument to RtlQueryRegistryValues
// during the loading/parsing of an Authorization Object's restrictions.
//
RTL_QUERY_REGISTRY_TABLE CodeAuthzpBuildRestrictedTokenTable[] =
{
// ----------- Object level flags ------------
{(PRTL_QUERY_REGISTRY_ROUTINE)SaferpBuildRestrictedToken,
0,
SAFER_OBJDISALLOW_REGVALUE,
(PVOID) AUTHZREGQUERY_DISALLOWEXECUTION,
REG_NONE, NULL, 0},
{(PRTL_QUERY_REGISTRY_ROUTINE)SaferpBuildRestrictedToken,
0,
SAFER_OBJDESCRIPTION_REGVALUEW,
(PVOID) AUTHZREGQUERY_DESCRIPTION,
REG_NONE, NULL, 0},
{(PRTL_QUERY_REGISTRY_ROUTINE)SaferpBuildRestrictedToken,
0,
SAFER_OBJFRIENDLYNAME_REGVALUEW,
(PVOID) AUTHZREGQUERY_FRIENDLYNAME,
REG_NONE, NULL, 0},
// ----------- Restriction level flags -----------
{(PRTL_QUERY_REGISTRY_ROUTINE)SaferpBuildRestrictedToken,
RTL_QUERY_REGISTRY_SUBKEY,
L"Restrictions", (PVOID) AUTHZREGQUERY_IGNORE,
REG_NONE, NULL, 0},
{(PRTL_QUERY_REGISTRY_ROUTINE)SaferpBuildRestrictedToken,
0,
L"DefaultOwner", (PVOID) AUTHZREGQUERY_DEFAULTOWNER,
REG_NONE, NULL, 0},
{(PRTL_QUERY_REGISTRY_ROUTINE)SaferpBuildRestrictedToken,
0,
L"SaferFlags", (PVOID) AUTHZREGQUERY_SAFERFLAGS,
REG_NONE, NULL, 0},
// ----------- Privileges To Remove ------------
{(PRTL_QUERY_REGISTRY_ROUTINE)SaferpBuildRestrictedToken,
RTL_QUERY_REGISTRY_SUBKEY,
L"Restrictions\\PrivsToRemove", (PVOID) AUTHZREGQUERY_IGNORE,
REG_NONE, NULL, 0},
{(PRTL_QUERY_REGISTRY_ROUTINE)SaferpBuildRestrictedToken,
0,
L"DisableMaxPrivilege", (PVOID) AUTHZREGQUERY_PTR_DISABLEMAX,
REG_NONE, NULL, 0},
{(PRTL_QUERY_REGISTRY_ROUTINE)SaferpBuildRestrictedToken,
0,
L"Count", (PVOID) AUTHZREGQUERY_PTR_COUNT,
REG_NONE, NULL, 0},
{(PRTL_QUERY_REGISTRY_ROUTINE)SaferpBuildRestrictedToken,
0,
NULL, (PVOID) AUTHZREGQUERY_PTR_PRIVS,
REG_NONE, NULL, 0},
{(PRTL_QUERY_REGISTRY_ROUTINE)SaferpBuildRestrictedToken,
0,
L"InvertPrivs", (PVOID) AUTHZREGQUERY_PTR_INVERT,
REG_NONE, NULL, 0},
// ----------- Sids To Disable ------------
{(PRTL_QUERY_REGISTRY_ROUTINE)SaferpBuildRestrictedToken,
RTL_QUERY_REGISTRY_SUBKEY,
L"Restrictions\\SidsToDisable", (PVOID) AUTHZREGQUERY_IGNORE,
REG_NONE, NULL, 0},
{(PRTL_QUERY_REGISTRY_ROUTINE)SaferpBuildRestrictedToken,
0,
L"Count", (PVOID) AUTHZREGQUERY_STD_COUNT,
REG_NONE, NULL, 0},
{(PRTL_QUERY_REGISTRY_ROUTINE)SaferpBuildRestrictedToken,
0,
NULL, (PVOID) AUTHZREGQUERY_STD_SIDS,
REG_NONE, NULL, 0},
{(PRTL_QUERY_REGISTRY_ROUTINE)SaferpBuildRestrictedToken,
0,
L"InvertGroups", (PVOID) AUTHZREGQUERY_STD_INVERT,
REG_NONE, NULL, 0},
// ----------- Restricting Sids Added ------------
{(PRTL_QUERY_REGISTRY_ROUTINE)SaferpBuildRestrictedToken,
RTL_QUERY_REGISTRY_SUBKEY,
L"Restrictions\\RestrictingSidsAdded", (PVOID) AUTHZREGQUERY_IGNORE,
REG_NONE, NULL, 0},
{(PRTL_QUERY_REGISTRY_ROUTINE)SaferpBuildRestrictedToken,
0,
L"Count", (PVOID) AUTHZREGQUERY_RSADD_COUNT,
REG_NONE, NULL, 0},
{(PRTL_QUERY_REGISTRY_ROUTINE)SaferpBuildRestrictedToken,
0,
NULL, (PVOID) AUTHZREGQUERY_RSADD_SIDS,
REG_NONE, NULL, 0},
// ----------- Restricting Sids Inverted ------------
{(PRTL_QUERY_REGISTRY_ROUTINE)SaferpBuildRestrictedToken,
RTL_QUERY_REGISTRY_SUBKEY,
L"Restrictions\\RestrictingSidsInverted", (PVOID) AUTHZREGQUERY_IGNORE,
REG_NONE, NULL, 0},
{(PRTL_QUERY_REGISTRY_ROUTINE)SaferpBuildRestrictedToken,
0,
L"Count", (PVOID) AUTHZREGQUERY_RSINV_COUNT,
REG_NONE, NULL, 0},
{(PRTL_QUERY_REGISTRY_ROUTINE)SaferpBuildRestrictedToken,
0,
NULL, (PVOID) AUTHZREGQUERY_RSINV_SIDS,
REG_NONE, NULL, 0},
// ----------- Terminating Entry ------------
{NULL, 0, NULL, NULL, REG_NONE, NULL, 0}
};
RTL_GENERIC_COMPARE_RESULTS NTAPI
SaferpLevelObjpTableCompare (
IN PRTL_GENERIC_TABLE Table,
IN PVOID FirstStruct,
IN PVOID SecondStruct
)
/*++
Routine Description:
Internal callback for the generic table implementation.
Comparison callback function used to sort or search entries in the
level table. Sorts the object records by the order in which they
should be evaluated to find the first matching rule for a given
piece of code.
Arguments:
Table - pointer to the generic table.
FirstStruct - first element to compare.
SecondStruct - second element to compare.
Return Value:
Returns GenericEqual, GenericLessThan, or GenericGreaterThan.
--*/
{
PAUTHZLEVELTABLERECORD FirstObj = (PAUTHZLEVELTABLERECORD) FirstStruct;
PAUTHZLEVELTABLERECORD SecondObj = (PAUTHZLEVELTABLERECORD) SecondStruct;
UNREFERENCED_PARAMETER(Table);
// Explicitly handle null parameters as wildcards, allowing them
// to match anything. We use this for quick deletion of the table.
if (FirstStruct == NULL || SecondStruct == NULL)
return GenericEqual;
// Compare ascending by dwLevelId.
if ( FirstObj->dwLevelId < SecondObj->dwLevelId )
return GenericLessThan;
else if ( FirstObj->dwLevelId > SecondObj->dwLevelId )
return GenericGreaterThan;
// otherwise they are equal.
return GenericEqual;
}
NTSTATUS NTAPI
SaferpBuildRestrictedToken(
IN PWSTR ValueName,
IN ULONG ValueType,
IN PVOID ValueData,
IN ULONG ValueLength,
IN PVOID Context,
IN PVOID EntryContext
)
/*++
Routine Description:
This is a callback function used during the reading and parsing
of the registry values associated with the restricted token
that will be built.
Arguments:
ValueName -
ValueType -
ValueData -
ValueLength -
Context - parameter from original RtlQueryRegistryValues function call.
EntryContext - parameter from structure entry.
Return Value:
Returns STATUS_SUCCESS if enumeration should continue.
--*/
{
PAUTHZLEVELTABLERECORD RegQuery = (PAUTHZLEVELTABLERECORD) Context;
switch ((ULONG_PTR) EntryContext)
{
case AUTHZREGQUERY_DISALLOWEXECUTION:
if (!RegQuery->Builtin) {
RegQuery->DisallowExecution =
((ValueType == REG_DWORD) &&
(ValueLength == sizeof(DWORD)) &&
(*(PDWORD) ValueData) != 0);
}
break;
case AUTHZREGQUERY_DESCRIPTION:
if (ValueType == REG_SZ &&
RegQuery->UnicodeDescription.Buffer == NULL)
{
RtlCreateUnicodeString(
&RegQuery->UnicodeDescription,
(LPCWSTR) ValueData);
}
break;
case AUTHZREGQUERY_FRIENDLYNAME:
if (ValueType == REG_SZ &&
RegQuery->UnicodeFriendlyName.Buffer == NULL)
{
RtlCreateUnicodeString(
&RegQuery->UnicodeFriendlyName,
(LPCWSTR) ValueData);
}
break;
//---------
case AUTHZREGQUERY_DEFAULTOWNER:
if (!RegQuery->Builtin && ValueType == REG_SZ &&
RegQuery->DefaultOwner == NULL)
{
if (!ConvertStringSidToSidW(
(LPCWSTR) ValueData,
&RegQuery->DefaultOwner))
{
RegQuery->DefaultOwner = NULL;
}
}
break;
case AUTHZREGQUERY_SAFERFLAGS:
if (!RegQuery->Builtin && ValueType == REG_DWORD &&
ValueLength == sizeof(DWORD))
{
RegQuery->SaferFlags = *(LPDWORD) ValueData;
}
break;
//---------
case AUTHZREGQUERY_PTR_DISABLEMAX:
if (!RegQuery->Builtin && ValueType == REG_DWORD &&
ValueLength == sizeof(DWORD) &&
(*(PDWORD) ValueData) != 0)
RegQuery->DisableMaxPrivileges = TRUE;
break;
case AUTHZREGQUERY_PTR_COUNT:
if (!RegQuery->Builtin && ValueType == REG_DWORD &&
ValueLength == sizeof(DWORD))
{
ASSERT(RegQuery->PrivilegesToDelete == NULL);
RegQuery->DeletePrivilegeCount = (*(PDWORD) ValueData);
RegQuery->DeletePrivilegeUsedCount = 0;
if (RegQuery->DeletePrivilegeCount > 0) {
RegQuery->PrivilegesToDelete =
(PLUID_AND_ATTRIBUTES) RtlAllocateHeap(
RtlProcessHeap(),
0,
sizeof(LUID_AND_ATTRIBUTES) *
RegQuery->DeletePrivilegeCount);
if (RegQuery->PrivilegesToDelete == NULL)
return STATUS_NO_MEMORY;
}
}
break;
case AUTHZREGQUERY_PTR_PRIVS:
if (!RegQuery->Builtin && ValueType == REG_SZ &&
_wcsnicmp(ValueName, L"Priv", 4) == 0 &&
RegQuery->PrivilegesToDelete != NULL &&
RegQuery->DeletePrivilegeUsedCount < RegQuery->DeletePrivilegeCount)
{
if (LookupPrivilegeValueW(NULL,
(LPCWSTR) ValueData,
&RegQuery->PrivilegesToDelete[
RegQuery->DeletePrivilegeUsedCount].Luid) != 0)
{
RegQuery->PrivilegesToDelete[
RegQuery->DeletePrivilegeUsedCount].Attributes = 0;
(RegQuery->DeletePrivilegeUsedCount)++;
}
}
break;
case AUTHZREGQUERY_PTR_INVERT:
if (!RegQuery->Builtin && ValueType == REG_DWORD &&
ValueLength == sizeof(DWORD))
{
RegQuery->InvertDeletePrivs =
( (*(PDWORD) ValueData) != 0 ? TRUE : FALSE);
}
break;
//---------
case AUTHZREGQUERY_STD_COUNT:
if (!RegQuery->Builtin && ValueType == REG_DWORD &&
ValueLength == sizeof(DWORD))
{
ASSERT(RegQuery->SidsToDisable == NULL);
RegQuery->DisableSidCount = (*(PDWORD) ValueData);
RegQuery->DisableSidUsedCount = 0;
if (RegQuery->DisableSidCount > 0) {
RegQuery->SidsToDisable =
(PAUTHZ_WILDCARDSID) RtlAllocateHeap(
RtlProcessHeap(),
0,
sizeof(AUTHZ_WILDCARDSID) *
RegQuery->DisableSidCount);
if (RegQuery->SidsToDisable == NULL)
return STATUS_NO_MEMORY;
}
}
break;
case AUTHZREGQUERY_STD_SIDS:
if (!RegQuery->Builtin && ValueType == REG_SZ &&
_wcsnicmp(ValueName, L"Group", 5) == 0 &&
RegQuery->SidsToDisable != NULL &&
RegQuery->DisableSidUsedCount < RegQuery->DisableSidCount)
{
NTSTATUS Status;
Status = CodeAuthzpConvertWildcardStringSidToSidW(
(LPCWSTR) ValueData,
&RegQuery->SidsToDisable[
RegQuery->DisableSidUsedCount]);
if (NT_SUCCESS(Status)) {
(RegQuery->DisableSidUsedCount)++;
}
}
break;
case AUTHZREGQUERY_STD_INVERT:
if (!RegQuery->Builtin && ValueType == REG_DWORD &&
ValueLength == sizeof(DWORD))
{
RegQuery->InvertDisableSids =
( (*(PDWORD) ValueData) != 0 ? TRUE : FALSE);
}
break;
//---------
case AUTHZREGQUERY_RSADD_COUNT:
if (!RegQuery->Builtin && ValueType == REG_DWORD &&
ValueLength == sizeof(DWORD))
{
ASSERT(RegQuery->RestrictedSidsAdded == NULL);
RegQuery->RestrictedSidsAddedCount = (*(PDWORD) ValueData);
RegQuery->RestrictedSidsAddedUsedCount = 0;
if (RegQuery->RestrictedSidsAddedCount > 0) {
RegQuery->RestrictedSidsAdded =
(PSID_AND_ATTRIBUTES) RtlAllocateHeap(
RtlProcessHeap(),
0,
sizeof(SID_AND_ATTRIBUTES) *
RegQuery->RestrictedSidsAddedCount);
if (RegQuery->RestrictedSidsAdded == NULL)
return STATUS_NO_MEMORY;
}
}
break;
case AUTHZREGQUERY_RSADD_SIDS:
if (!RegQuery->Builtin && ValueType == REG_SZ &&
_wcsnicmp(ValueName, L"Group", 5) == 0 &&
RegQuery->RestrictedSidsAdded != NULL &&
RegQuery->RestrictedSidsAddedUsedCount <
RegQuery->RestrictedSidsAddedCount)
{
if (ConvertStringSidToSidW(
(LPCWSTR) ValueData,
&RegQuery->RestrictedSidsAdded[
RegQuery->RestrictedSidsAddedUsedCount].Sid) != 0)
{
RegQuery->RestrictedSidsAdded[
RegQuery->RestrictedSidsAddedUsedCount].Attributes = 0;
(RegQuery->RestrictedSidsAddedUsedCount)++;
}
}
break;
//---------
case AUTHZREGQUERY_RSINV_COUNT:
if (!RegQuery->Builtin && ValueType == REG_DWORD &&
ValueLength == sizeof(DWORD))
{
ASSERT(RegQuery->RestrictedSidsInv == NULL);
RegQuery->RestrictedSidsInvCount = (*(PDWORD) ValueData);
RegQuery->RestrictedSidsInvUsedCount = 0;
if (RegQuery->RestrictedSidsInvCount > 0) {
RegQuery->RestrictedSidsInv =
(PAUTHZ_WILDCARDSID) RtlAllocateHeap(
RtlProcessHeap(),
0,
sizeof(AUTHZ_WILDCARDSID) *
RegQuery->RestrictedSidsInvCount);
if (RegQuery->RestrictedSidsInv == NULL)
return STATUS_NO_MEMORY;
}
}
break;
case AUTHZREGQUERY_RSINV_SIDS:
if (!RegQuery->Builtin && ValueType == REG_SZ &&
_wcsnicmp(ValueName, L"Group", 5) == 0 &&
RegQuery->RestrictedSidsInv != NULL &&
RegQuery->RestrictedSidsInvUsedCount <
RegQuery->RestrictedSidsInvCount)
{
NTSTATUS Status;
Status = CodeAuthzpConvertWildcardStringSidToSidW(
(LPCWSTR) ValueData,
&RegQuery->RestrictedSidsInv[
RegQuery->RestrictedSidsInvUsedCount]);
if (NT_SUCCESS(Status)) {
(RegQuery->RestrictedSidsInvUsedCount)++;
}
}
break;
//---------
default:
case AUTHZREGQUERY_IGNORE:
// ignore anything else.
break;
}
return STATUS_SUCCESS;
}
VOID NTAPI
CodeAuthzLevelObjpInitializeTable(
IN PRTL_GENERIC_TABLE AuthzObjTable
)
/*++
Routine Description:
Initializes a generic table structure to prepare it for use.
This function must be called before CodeAuthzObjpLoadTable
is used to load data into it.
Arguments:
AuthzObjTable = pointer to the level table being updated.
Return Value:
Does not return a value.
--*/
{
RtlInitializeGenericTable(
AuthzObjTable,
(PRTL_GENERIC_COMPARE_ROUTINE) SaferpLevelObjpTableCompare,
(PRTL_GENERIC_ALLOCATE_ROUTINE) SaferpGenericTableAllocate,
(PRTL_GENERIC_FREE_ROUTINE) SaferpGenericTableFree,
NULL);
}
VOID NTAPI
SaferpLevelObjpCleanupEntry(
IN OUT PAUTHZLEVELTABLERECORD pAuthzObjRecord
)
/*++
Routine Description:
Releases allocated memory represented within a level record.
Does not free the record itself or remove it from the
generic table that it belongs to.
Arguments:
pAuthzObjRecord = pointer to the level table record itself.
Return Value:
Does not return a value.
--*/
{
PVOID processheap = RtlProcessHeap();
ASSERT(pAuthzObjRecord != NULL);
if (pAuthzObjRecord->UnicodeDescription.Buffer != NULL) {
RtlFreeUnicodeString(&pAuthzObjRecord->UnicodeDescription);
}
if (pAuthzObjRecord->UnicodeFriendlyName.Buffer != NULL) {
RtlFreeUnicodeString(&pAuthzObjRecord->UnicodeFriendlyName);
}
if (pAuthzObjRecord->DefaultOwner != NULL) {
LocalFree((HLOCAL) pAuthzObjRecord->DefaultOwner);
}
if (pAuthzObjRecord->SidsToDisable != NULL) {
DWORD Index;
for (Index = 0; Index < pAuthzObjRecord->DisableSidUsedCount; Index++) {
LocalFree((HLOCAL) pAuthzObjRecord->SidsToDisable[Index].Sid);
}
RtlFreeHeap(processheap, 0, (LPVOID) pAuthzObjRecord->SidsToDisable);
}
if (pAuthzObjRecord->PrivilegesToDelete != NULL) {
RtlFreeHeap(processheap, 0, (LPVOID) pAuthzObjRecord->PrivilegesToDelete);
}
if (pAuthzObjRecord->RestrictedSidsAdded != NULL) {
DWORD Index;
for (Index = 0; Index < pAuthzObjRecord->RestrictedSidsAddedUsedCount; Index++) {
LocalFree((HLOCAL) pAuthzObjRecord->RestrictedSidsAdded[Index].Sid);
}
RtlFreeHeap(processheap, 0, (LPVOID) pAuthzObjRecord->RestrictedSidsAdded);
}
if (pAuthzObjRecord->RestrictedSidsInv != NULL) {
DWORD Index;
for (Index = 0; Index < pAuthzObjRecord->RestrictedSidsInvUsedCount; Index++) {
LocalFree((HLOCAL) pAuthzObjRecord->RestrictedSidsInv[Index].Sid);
}
RtlFreeHeap(processheap, 0, (LPVOID) pAuthzObjRecord->RestrictedSidsInv);
}
RtlZeroMemory(pAuthzObjRecord, sizeof(AUTHZLEVELTABLERECORD));
}
BOOL NTAPI
SaferpLoadUnicodeResourceString(
IN HANDLE hModule,
IN UINT wID,
OUT PUNICODE_STRING pUnicodeString,
IN WORD wLangId
)
/*++
Routine Description:
We roll our own instead of using LoadStringW() directly, because it
depends on user32.dll and would introduce a new dll dependency,
whereas this implementation only requires kernel32.dll imports.
Arguments:
hModule - handle the module to load the resource from.
wID - Resource ID to load.
pUnicodeString - output buffer to receive the loaded string. This
string must be freed with RtlFreeUnicodeString().
wLangId - language identifier to load. To simply use the current
thread locale, you may specify the value:
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL)
Return Value:
Returns FALSE on error, otherwise success.
--*/
{
NTSTATUS Status;
UNICODE_STRING UnicodeOrig;
HANDLE hResInfo;
HANDLE hStringSeg;
LPWSTR lpsz;
int cch;
hResInfo = FindResourceExW(
hModule,
MAKEINTRESOURCEW(6), /* RT_STRING */
(LPWSTR)((LONG_PTR)(((USHORT)wID >> 4) + 1)),
wLangId );
if (hResInfo) {
/*
* Load that segment.
*/
hStringSeg = LoadResource(hModule, hResInfo);
if (hStringSeg == NULL) {
return 0;
}
lpsz = (LPWSTR) (hStringSeg);
/*
* Move past the other strings in this segment.
* (16 strings in a segment -> & 0x0F)
*/
wID &= 0x0F;
for (;;) {
cch = *((WCHAR *)lpsz++); // PASCAL like string count
// first UTCHAR is count if TCHARs
if (wID-- == 0) break;
lpsz += cch; // Step to start if next string
}
/*
* Create the UNICODE_STRING version of the string based
* off of the pointer to the read-only resource buffer.
*/
UnicodeOrig.Buffer = (WCHAR *)lpsz;
UnicodeOrig.Length = UnicodeOrig.MaximumLength =
(USHORT) (cch * sizeof(WCHAR));
/*
* Allocate memory for the new copy, and pass that back.
*/
Status = RtlDuplicateUnicodeString(
RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
&UnicodeOrig, pUnicodeString);
if (NT_SUCCESS(Status)) {
return 1;
}
}
return 0;
}
NTSTATUS NTAPI
SaferpEnforceDefaultLevelDefinitions(
IN OUT PAUTHZLEVELTABLERECORD pAuthzObjTableRec
)
/*++
Routine Description:
Fills a level record structure with the built-in definitions of
the 5 WinSafer level definitions.
Arguments:
pAuthzObjTableRec - pointer to the level record to initialize.
The dwLevelId member of the record must be initialized. The
rest of the structure is expected to be NULL.
Return Value:
Returns STATUS_SUCCESS on success, otherwise error.
--*/
{
NTSTATUS Status;
const static SID_IDENTIFIER_AUTHORITY SIDAuth = SECURITY_NT_AUTHORITY;
const static SID_IDENTIFIER_AUTHORITY WorldAuth = SECURITY_WORLD_SID_AUTHORITY;
UINT uResourceID;
HANDLE hAdvApiInst;
if (!ARGUMENT_PRESENT(pAuthzObjTableRec)) {
Status = STATUS_INVALID_PARAMETER;
goto ExitHandler;
}
if (pAuthzObjTableRec->dwLevelId != SAFER_LEVELID_FULLYTRUSTED &&
pAuthzObjTableRec->dwLevelId != SAFER_LEVELID_NORMALUSER &&
pAuthzObjTableRec->dwLevelId != SAFER_LEVELID_CONSTRAINED &&
pAuthzObjTableRec->dwLevelId != SAFER_LEVELID_UNTRUSTED &&
pAuthzObjTableRec->dwLevelId != SAFER_LEVELID_DISALLOWED) {
Status = STATUS_NOT_IMPLEMENTED;
goto ExitHandler;
}
switch (pAuthzObjTableRec->dwLevelId)
{
case SAFER_LEVELID_DISALLOWED:
uResourceID = CODEAUTHZ_RC_LEVELNAME_DISALLOWED;
pAuthzObjTableRec->DisallowExecution = TRUE;
break;
// -----------------------
case SAFER_LEVELID_UNTRUSTED:
uResourceID = CODEAUTHZ_RC_LEVELNAME_UNTRUSTED;
pAuthzObjTableRec->DisallowExecution = FALSE;
ASSERT(pAuthzObjTableRec->DefaultOwner == NULL);
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 1,
SECURITY_PRINCIPAL_SELF_RID,
0, 0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->DefaultOwner);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->SaferFlags = SAFER_POLICY_JOBID_UNTRUSTED;
// Privileges.
pAuthzObjTableRec->DisableMaxPrivileges = TRUE;
pAuthzObjTableRec->DeletePrivilegeUsedCount = 0;
pAuthzObjTableRec->InvertDeletePrivs = FALSE;
// Sids to restrict.
ASSERT(pAuthzObjTableRec->RestrictedSidsAdded == NULL);
pAuthzObjTableRec->RestrictedSidsAddedCount =
pAuthzObjTableRec->RestrictedSidsAddedUsedCount = 5;
pAuthzObjTableRec->RestrictedSidsAdded =
(PSID_AND_ATTRIBUTES) RtlAllocateHeap(
RtlProcessHeap(), 0, 5 * sizeof(SID_AND_ATTRIBUTES));
if (!pAuthzObjTableRec->RestrictedSidsAdded) {
Status = STATUS_NO_MEMORY;
goto ExitHandler;
}
RtlZeroMemory(pAuthzObjTableRec->RestrictedSidsAdded,
5 * sizeof(SID_AND_ATTRIBUTES));
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 1,
SECURITY_RESTRICTED_CODE_RID,
0, 0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->RestrictedSidsAdded[0].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &WorldAuth, 1,
SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->RestrictedSidsAdded[1].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 1,
SECURITY_INTERACTIVE_RID,
0, 0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->RestrictedSidsAdded[2].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 1,
SECURITY_AUTHENTICATED_USER_RID,
0, 0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->RestrictedSidsAdded[3].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->RestrictedSidsAdded[4].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->RestrictedSidsInvUsedCount = 0;
// Sids to disable.
pAuthzObjTableRec->DisableSidCount =
pAuthzObjTableRec->DisableSidUsedCount = 5;
ASSERT(pAuthzObjTableRec->SidsToDisable == NULL);
pAuthzObjTableRec->SidsToDisable =
(PAUTHZ_WILDCARDSID) RtlAllocateHeap(
RtlProcessHeap(), 0, 5 * sizeof(AUTHZ_WILDCARDSID));
if (!pAuthzObjTableRec->SidsToDisable) {
Status = STATUS_NO_MEMORY;
goto ExitHandler;
}
RtlZeroMemory(pAuthzObjTableRec->SidsToDisable,
5 * sizeof(AUTHZ_WILDCARDSID));
pAuthzObjTableRec->SidsToDisable[0].WildcardPos = -1;
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &WorldAuth, 1,
SECURITY_WORLD_RID,
0, 0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->SidsToDisable[0].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->SidsToDisable[1].WildcardPos = -1;
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 1,
SECURITY_INTERACTIVE_RID,
0, 0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->SidsToDisable[1].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->SidsToDisable[2].WildcardPos = -1;
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 1,
SECURITY_PRINCIPAL_SELF_RID,
0, 0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->SidsToDisable[2].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->SidsToDisable[3].WildcardPos = -1;
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 1,
SECURITY_AUTHENTICATED_USER_RID,
0, 0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->SidsToDisable[3].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->SidsToDisable[4].WildcardPos = -1;
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_USERS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->SidsToDisable[4].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->InvertDisableSids = TRUE;
break;
// -----------------------
case SAFER_LEVELID_CONSTRAINED:
uResourceID = CODEAUTHZ_RC_LEVELNAME_CONSTRAINED;
pAuthzObjTableRec->DisallowExecution = FALSE;
ASSERT(pAuthzObjTableRec->DefaultOwner == NULL);
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 1,
SECURITY_PRINCIPAL_SELF_RID,
0, 0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->DefaultOwner);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->SaferFlags = SAFER_POLICY_JOBID_CONSTRAINED;
// Privileges.
pAuthzObjTableRec->DisableMaxPrivileges = TRUE;
pAuthzObjTableRec->DeletePrivilegeUsedCount = 0;
pAuthzObjTableRec->InvertDeletePrivs = FALSE;
// Sids to restrict (added).
ASSERT(pAuthzObjTableRec->RestrictedSidsAdded == NULL);
pAuthzObjTableRec->RestrictedSidsAddedCount =
pAuthzObjTableRec->RestrictedSidsAddedUsedCount = 1;
pAuthzObjTableRec->RestrictedSidsAdded =
(PSID_AND_ATTRIBUTES) RtlAllocateHeap(
RtlProcessHeap(), 0, 1 * sizeof(SID_AND_ATTRIBUTES));
if (!pAuthzObjTableRec->RestrictedSidsAdded) {
Status = STATUS_NO_MEMORY;
goto ExitHandler;
}
RtlZeroMemory(pAuthzObjTableRec->RestrictedSidsAdded,
1 * sizeof(SID_AND_ATTRIBUTES));
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 1,
SECURITY_RESTRICTED_CODE_RID,
0, 0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->RestrictedSidsAdded[0].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
// Sids to restrict (inverted).
ASSERT(pAuthzObjTableRec->RestrictedSidsInv == NULL);
pAuthzObjTableRec->RestrictedSidsInvCount =
pAuthzObjTableRec->RestrictedSidsInvUsedCount = 8;
pAuthzObjTableRec->RestrictedSidsInv =
(PAUTHZ_WILDCARDSID) RtlAllocateHeap(
RtlProcessHeap(), 0, 8 * sizeof(AUTHZ_WILDCARDSID));
if (!pAuthzObjTableRec->RestrictedSidsInv) {
Status = STATUS_NO_MEMORY;
goto ExitHandler;
}
RtlZeroMemory(pAuthzObjTableRec->RestrictedSidsInv,
8 * sizeof(AUTHZ_WILDCARDSID));
pAuthzObjTableRec->RestrictedSidsInv[0].WildcardPos = -1; // exact!
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 1,
SECURITY_PRINCIPAL_SELF_RID,
0, 0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->RestrictedSidsInv[0].Sid);
pAuthzObjTableRec->RestrictedSidsInv[1].WildcardPos = -1; // exact!
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->RestrictedSidsInv[1].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->RestrictedSidsInv[2].WildcardPos = -1; // exact!
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->RestrictedSidsInv[2].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->RestrictedSidsInv[3].WildcardPos = 1; // wildcard!
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_NT_NON_UNIQUE, DOMAIN_GROUP_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->RestrictedSidsInv[3].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->RestrictedSidsInv[4].WildcardPos = 1; // wildcard!
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_NT_NON_UNIQUE, DOMAIN_GROUP_RID_CERT_ADMINS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->RestrictedSidsInv[4].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->RestrictedSidsInv[5].WildcardPos = 1; // wildcard!
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_NT_NON_UNIQUE, DOMAIN_GROUP_RID_SCHEMA_ADMINS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->RestrictedSidsInv[5].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->RestrictedSidsInv[6].WildcardPos = 1; // wildcard!
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_NT_NON_UNIQUE, DOMAIN_GROUP_RID_ENTERPRISE_ADMINS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->RestrictedSidsInv[6].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->RestrictedSidsInv[7].WildcardPos = 1; // wildcard!
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_NT_NON_UNIQUE, DOMAIN_GROUP_RID_POLICY_ADMINS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->RestrictedSidsInv[7].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
// Sids to disable.
pAuthzObjTableRec->DisableSidCount =
pAuthzObjTableRec->DisableSidUsedCount = 7;
ASSERT(pAuthzObjTableRec->SidsToDisable == NULL);
pAuthzObjTableRec->SidsToDisable =
(PAUTHZ_WILDCARDSID) RtlAllocateHeap(
RtlProcessHeap(), 0, 7 * sizeof(AUTHZ_WILDCARDSID));
if (!pAuthzObjTableRec->SidsToDisable) {
Status = STATUS_NO_MEMORY;
goto ExitHandler;
}
RtlZeroMemory(pAuthzObjTableRec->SidsToDisable,
7 * sizeof(AUTHZ_WILDCARDSID));
pAuthzObjTableRec->SidsToDisable[0].WildcardPos = -1; // exact!
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->SidsToDisable[0].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->SidsToDisable[1].WildcardPos = -1; // exact!
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->SidsToDisable[1].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->SidsToDisable[2].WildcardPos = 1; // wildcard!
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_NT_NON_UNIQUE, DOMAIN_GROUP_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->SidsToDisable[2].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->SidsToDisable[3].WildcardPos = 1; // wildcard!
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_NT_NON_UNIQUE, DOMAIN_GROUP_RID_CERT_ADMINS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->SidsToDisable[3].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->SidsToDisable[4].WildcardPos = 1; // wildcard!
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_NT_NON_UNIQUE, DOMAIN_GROUP_RID_SCHEMA_ADMINS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->SidsToDisable[4].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->SidsToDisable[5].WildcardPos = 1; // wildcard!
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_NT_NON_UNIQUE, DOMAIN_GROUP_RID_ENTERPRISE_ADMINS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->SidsToDisable[5].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->SidsToDisable[6].WildcardPos = 1; // wildcard!
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_NT_NON_UNIQUE, DOMAIN_GROUP_RID_POLICY_ADMINS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->SidsToDisable[6].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->InvertDisableSids = FALSE;
break;
// -----------------------
case SAFER_LEVELID_NORMALUSER:
uResourceID = CODEAUTHZ_RC_LEVELNAME_NORMALUSER;
pAuthzObjTableRec->DisallowExecution = FALSE;
ASSERT(pAuthzObjTableRec->DefaultOwner == NULL);
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 1,
SECURITY_PRINCIPAL_SELF_RID,
0, 0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->DefaultOwner);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->SaferFlags = 0;
// Privileges
pAuthzObjTableRec->DisableMaxPrivileges = TRUE;
pAuthzObjTableRec->DeletePrivilegeUsedCount = 0;
pAuthzObjTableRec->InvertDeletePrivs = FALSE;
// Sids to restrict.
pAuthzObjTableRec->RestrictedSidsAddedUsedCount =
pAuthzObjTableRec->RestrictedSidsInvUsedCount = 0;
// Sids to disable.
pAuthzObjTableRec->DisableSidCount =
pAuthzObjTableRec->DisableSidUsedCount = 7;
ASSERT(pAuthzObjTableRec->SidsToDisable == NULL);
pAuthzObjTableRec->SidsToDisable =
(PAUTHZ_WILDCARDSID) RtlAllocateHeap(
RtlProcessHeap(), 0, 7 * sizeof(AUTHZ_WILDCARDSID));
if (!pAuthzObjTableRec->SidsToDisable) {
Status = STATUS_NO_MEMORY;
goto ExitHandler;
}
RtlZeroMemory(pAuthzObjTableRec->SidsToDisable,
7 * sizeof(AUTHZ_WILDCARDSID));
pAuthzObjTableRec->SidsToDisable[0].WildcardPos = -1; // exact!
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->SidsToDisable[0].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->SidsToDisable[1].WildcardPos = -1; // exact!
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_POWER_USERS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->SidsToDisable[1].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->SidsToDisable[2].WildcardPos = 1; // wildcard!
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_NT_NON_UNIQUE, DOMAIN_GROUP_RID_ADMINS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->SidsToDisable[2].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->SidsToDisable[3].WildcardPos = 1; // wildcard!
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_NT_NON_UNIQUE, DOMAIN_GROUP_RID_CERT_ADMINS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->SidsToDisable[3].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->SidsToDisable[4].WildcardPos = 1; // wildcard!
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_NT_NON_UNIQUE, DOMAIN_GROUP_RID_SCHEMA_ADMINS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->SidsToDisable[4].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->SidsToDisable[5].WildcardPos = 1; // wildcard!
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_NT_NON_UNIQUE, DOMAIN_GROUP_RID_ENTERPRISE_ADMINS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->SidsToDisable[5].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->SidsToDisable[6].WildcardPos = 1; // wildcard!
Status = RtlAllocateAndInitializeSid(
(PSID_IDENTIFIER_AUTHORITY) &SIDAuth, 2,
SECURITY_NT_NON_UNIQUE, DOMAIN_GROUP_RID_POLICY_ADMINS,
0, 0, 0, 0, 0, 0,
&pAuthzObjTableRec->SidsToDisable[6].Sid);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
pAuthzObjTableRec->InvertDisableSids = FALSE;
break;
// -----------------------
case SAFER_LEVELID_FULLYTRUSTED:
uResourceID = CODEAUTHZ_RC_LEVELNAME_FULLYTRUSTED;
pAuthzObjTableRec->DisallowExecution = FALSE;
ASSERT(pAuthzObjTableRec->DefaultOwner == NULL);
pAuthzObjTableRec->DisableMaxPrivileges = FALSE;
pAuthzObjTableRec->SaferFlags = 0;
pAuthzObjTableRec->DeletePrivilegeUsedCount =
pAuthzObjTableRec->DisableSidUsedCount =
pAuthzObjTableRec->RestrictedSidsAddedUsedCount =
pAuthzObjTableRec->RestrictedSidsInvUsedCount = 0;
pAuthzObjTableRec->InvertDeletePrivs =
pAuthzObjTableRec->InvertDisableSids = FALSE;
break;
// -----------------------
default:
// should not happen.
Status = STATUS_UNSUCCESSFUL;
goto ExitHandler;
}
//
// Load the resource descriptions and friendly names.
//
hAdvApiInst = (HANDLE) GetModuleHandleW(L"advapi32");
if (hAdvApiInst != NULL)
{
// load the friendly name.
SaferpLoadUnicodeResourceString(
hAdvApiInst,
(UINT) (uResourceID + 0),
&pAuthzObjTableRec->UnicodeFriendlyName,
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
// load the description.
SaferpLoadUnicodeResourceString(
hAdvApiInst,
(UINT) (uResourceID + 1),
&pAuthzObjTableRec->UnicodeDescription,
MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL));
}
Status = STATUS_SUCCESS;
ExitHandler:
return Status;
}
DWORD
SaferpEnumerateHiddenLevels(VOID)
/*++
Routine Description:
Reads which hidden levels should be enumerated.
Arguments:
Return Value:
Returns DWORD.
--*/
{
NTSTATUS Status;
UCHAR QueryBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + MAX_PATH * sizeof(WCHAR)];
PKEY_VALUE_PARTIAL_INFORMATION pKeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION) QueryBuffer;
DWORD dwActualSize = 0;
HKEY hKey = NULL;
const static UNICODE_STRING SaferUnicodeKeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Policies\\Microsoft\\Windows\\Safer\\CodeIdentifiers");
const static OBJECT_ATTRIBUTES SaferObjectAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&SaferUnicodeKeyName, OBJ_CASE_INSENSITIVE);
const static UNICODE_STRING SaferHiddenLevels = RTL_CONSTANT_STRING(SAFER_HIDDEN_LEVELS);
// Open the CodeIdentifiers key.
Status = NtOpenKey(
&hKey,
KEY_QUERY_VALUE,
(POBJECT_ATTRIBUTES) &SaferObjectAttributes
);
if (!NT_SUCCESS(Status)) {
return 0;
}
Status = NtQueryValueKey(
hKey,
(PUNICODE_STRING) &SaferHiddenLevels,
KeyValuePartialInformation,
pKeyValueInfo,
sizeof(QueryBuffer),
&dwActualSize
);
NtClose(hKey);
if (!NT_SUCCESS(Status)) {
return 0;
}
if (pKeyValueInfo->Type == REG_DWORD &&
pKeyValueInfo->DataLength == sizeof(DWORD)) {
return *((PDWORD) pKeyValueInfo->Data);
}
return 0;
}
NTSTATUS NTAPI
CodeAuthzLevelObjpLoadTable (
IN OUT PRTL_GENERIC_TABLE pAuthzObjTable,
IN DWORD dwScopeId,
IN HANDLE hKeyCustomRoot
)
/*++
Routine Description:
Pre-loads our table with a record for each Authorization Level
encountered in the registry. Each record in the table contains
the LevelId, registry handle, and all restricted token attributes
that will be needed to later compute the restricted token.
Arguments:
AuthzObjTable = pointer to the level table being updated. Must have
already been initialized with CodeAuthzLevelObjpInitializeTable.
Return Value:
Returns FALSE on error, otherwise success.
--*/
{
DWORD dwIndex;
NTSTATUS Status = STATUS_SUCCESS;
HANDLE hKeyLevelObjects;
DWORD LocalValue = 0;
OBJECT_ATTRIBUTES ObjectAttributes;
//
// Open a handle to the appropriate section of the registry where
// the Level definitions are stored. Generally they will come only
// from the AUTHZSCOPEID_MACHINE scope, but we allow it to be
// specified as an argument for the group policy editing case.
//
Status = CodeAuthzpOpenPolicyRootKey(
dwScopeId,
hKeyCustomRoot,
SAFER_OBJECTS_REGSUBKEY,
KEY_READ,
FALSE,
&hKeyLevelObjects);
if (!NT_SUCCESS(Status)) {
goto ExitHandler;
}
//
// Iterate through all subkeys under this branch.
//
for (dwIndex = 0; ; dwIndex++)
{
DWORD dwLength, dwLevelId;
HANDLE hKeyThisLevelObject;
AUTHZLEVELTABLERECORD AuthzObjTableRec;
UNICODE_STRING UnicodeKeyname;
BYTE RawQueryBuffer[sizeof(KEY_BASIC_INFORMATION) + 256];
PKEY_BASIC_INFORMATION pBasicInformation =
(PKEY_BASIC_INFORMATION) &RawQueryBuffer[0];
//
// Find the next Level that we will check.
//
Status = NtEnumerateKey(hKeyLevelObjects,
dwIndex,
KeyBasicInformation,
pBasicInformation,
sizeof(RawQueryBuffer),
&dwLength);
if (!NT_SUCCESS(Status)) {
break;
}
UnicodeKeyname.Buffer = pBasicInformation->Name;
UnicodeKeyname.MaximumLength = UnicodeKeyname.Length =
(USHORT) pBasicInformation->NameLength;
// Note that UnicodeKeyname.Buffer is not necessarily null terminated.
ASSERT(UnicodeKeyname.Length <= wcslen(UnicodeKeyname.Buffer) * sizeof(WCHAR));
//
// Translate the keyname (which we expect to be
// purely numeric) into the integer LevelId value.
//
Status = RtlUnicodeStringToInteger(
&UnicodeKeyname, 10, &dwLevelId);
if (!NT_SUCCESS(Status)) {
// the keyname was apparently not numeric.
continue;
}
//
// Try to open a handle to that Level for read-only access.
//
InitializeObjectAttributes(&ObjectAttributes,
&UnicodeKeyname,
OBJ_CASE_INSENSITIVE,
hKeyLevelObjects,
NULL
);
Status = NtOpenKey(&hKeyThisLevelObject,
KEY_READ,
&ObjectAttributes);
if (!NT_SUCCESS(Status)) {
// If we failed to open it, skip to the next one.
continue;
}
//
// Fill in the well-known portions of the record structure.
//
RtlZeroMemory(&AuthzObjTableRec, sizeof(AuthzObjTableRec));
AuthzObjTableRec.dwLevelId = dwLevelId;
AuthzObjTableRec.Builtin =
(dwLevelId == SAFER_LEVELID_FULLYTRUSTED ||
dwLevelId == SAFER_LEVELID_NORMALUSER ||
dwLevelId == SAFER_LEVELID_CONSTRAINED ||
dwLevelId == SAFER_LEVELID_UNTRUSTED ||
dwLevelId == SAFER_LEVELID_DISALLOWED) ? TRUE : FALSE;
AuthzObjTableRec.isEnumerable = TRUE; //always allow enumeration of entries defined in the registry.
//
// Read all of the restricted token attributes from the registry.
// Note that for Builtin Levels, we use a different query table
// that only attempts to read a reduced set of attributes from
// the registry, since we'd ignore most of them anyways.
//
if (!AuthzObjTableRec.Builtin) {
Status = RtlQueryRegistryValues(
RTL_REGISTRY_HANDLE,
(PCWSTR) hKeyThisLevelObject,
CodeAuthzpBuildRestrictedTokenTable,
&AuthzObjTableRec,
NULL
);
// (We don't actually look at the Status code, since it
// is acceptable for some values or subkeys to have not
// been specified.)
}
//
// If this is a built-in Level, then enforce the other expected attributes.
//
if (AuthzObjTableRec.Builtin) {
Status = SaferpEnforceDefaultLevelDefinitions(
&AuthzObjTableRec);
if (!NT_SUCCESS(Status)) {
SaferpLevelObjpCleanupEntry(&AuthzObjTableRec);
NtClose(hKeyThisLevelObject);
continue;
}
}
//
// Add the new record into our table.
//
if (RtlLookupElementGenericTable(pAuthzObjTable,
(PVOID) &AuthzObjTableRec) == NULL)
{
// Only insert the record if we don't have any other
// entries with this same LevelId combination.
RtlInsertElementGenericTable(
pAuthzObjTable,
(PVOID) &AuthzObjTableRec,
sizeof(AUTHZLEVELTABLERECORD),
NULL);
} else {
// Otherwise something with this same LevelId already existed.
// (like level names "01" and "1" being numerically the same).
SaferpLevelObjpCleanupEntry(&AuthzObjTableRec);
}
NtClose(hKeyThisLevelObject);
}
NtClose(hKeyLevelObjects);
//
// Look through and verify that all of the default Levels were
// actually loaded. If they were not, then try to add them.
//
ExitHandler:
LocalValue = SaferpEnumerateHiddenLevels();
for (dwIndex = 0; dwIndex < 5; dwIndex++)
{
const DWORD dwBuiltinLevels[5][2] = {
{SAFER_LEVELID_DISALLOWED, TRUE}, // true = always create
{SAFER_LEVELID_UNTRUSTED, FALSE},
{SAFER_LEVELID_CONSTRAINED, FALSE},
{SAFER_LEVELID_NORMALUSER, FALSE},
{SAFER_LEVELID_FULLYTRUSTED, TRUE} // true = always create
};
DWORD dwLevelId = dwBuiltinLevels[dwIndex][0];
if ( !CodeAuthzLevelObjpLookupByLevelId (
pAuthzObjTable, dwLevelId))
{
AUTHZLEVELTABLERECORD AuthzObjTableRec;
RtlZeroMemory(&AuthzObjTableRec, sizeof(AuthzObjTableRec));
AuthzObjTableRec.dwLevelId = dwLevelId;
AuthzObjTableRec.Builtin = TRUE;
AuthzObjTableRec.isEnumerable =(BOOLEAN)(dwBuiltinLevels[dwIndex][1]) ; //conditionally show this level
// If the registry key specifies that the level should be shown
// mark it as enumerable.
if ((LocalValue & dwLevelId) == dwLevelId) {
AuthzObjTableRec.isEnumerable = TRUE;
}
if (NT_SUCCESS(
SaferpEnforceDefaultLevelDefinitions(
&AuthzObjTableRec)))
{
RtlInsertElementGenericTable(
pAuthzObjTable,
(PVOID) &AuthzObjTableRec,
sizeof(AUTHZLEVELTABLERECORD),
NULL);
} else {
SaferpLevelObjpCleanupEntry(&AuthzObjTableRec);
}
}
}
return Status;
}
VOID NTAPI
CodeAuthzLevelObjpEntireTableFree (
IN PRTL_GENERIC_TABLE pAuthzObjTable
)
/*++
Routine Description:
This function frees all entries contained within a GENERIC_TABLE.
Arguments:
AuthzObjTable - pointer to the Generic Table structure
Return Value:
None.
--*/
{
ULONG NumElements;
PVOID RestartKey;
PAUTHZLEVELTABLERECORD pAuthzObjRecord;
//
// Enumerate through all records and close the registry handles.
//
RestartKey = NULL;
for (pAuthzObjRecord = (PAUTHZLEVELTABLERECORD)
RtlEnumerateGenericTableWithoutSplaying(
pAuthzObjTable, &RestartKey);
pAuthzObjRecord != NULL;
pAuthzObjRecord = (PAUTHZLEVELTABLERECORD)
RtlEnumerateGenericTableWithoutSplaying(
pAuthzObjTable, &RestartKey)
)
{
SaferpLevelObjpCleanupEntry(pAuthzObjRecord);
}
//
// Now iterate through the table again and free all of the
// elements themselves.
//
NumElements = RtlNumberGenericTableElements(pAuthzObjTable);
while ( NumElements-- > 0 ) {
// Delete all elements. Note that we pass NULL as the element
// to delete because our compare function is smart enough to
// allow treatment of NULL as a wildcard element.
BOOL retval = RtlDeleteElementGenericTable( pAuthzObjTable, NULL);
ASSERT(retval == TRUE);
}
}
PAUTHZLEVELTABLERECORD NTAPI
CodeAuthzLevelObjpLookupByLevelId (
IN PRTL_GENERIC_TABLE AuthzObjTable,
IN DWORD dwLevelId
)
/*++
Routine Description:
This function searches for a given Level within a GENERIC_TABLE.
Arguments:
AuthzObjTable - pointer to the Generic Table structure
dwLevelId - the DWORD Level identifier to search for.
Return Value:
On success, returns a pointer to the matching level record
if it was found within the table, otherwise returns NULL.
--*/
{
AUTHZLEVELTABLERECORD AuthzObjTableRec;
RtlZeroMemory(&AuthzObjTableRec, sizeof(AUTHZLEVELTABLERECORD));
AuthzObjTableRec.dwLevelId = dwLevelId;
return (PAUTHZLEVELTABLERECORD)
RtlLookupElementGenericTable(AuthzObjTable,
(PVOID) &AuthzObjTableRec);
}