You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2561 lines
67 KiB
2561 lines
67 KiB
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
wdmsectest.c
|
|
|
|
Abstract:
|
|
|
|
Test program for IoCreateDeviceSecure
|
|
|
|
Environment:
|
|
|
|
Usre mode
|
|
|
|
Revision History:
|
|
|
|
|
|
5-Jun-1997 : Bogdan Andreiu (bogdana) created
|
|
|
|
25-April-2002 : Bogdan Andreiu (bogdana) re-used a nth time...
|
|
|
|
--*/
|
|
|
|
|
|
#include "instdev.h"
|
|
#include "sddl.h"
|
|
|
|
|
|
|
|
#define DUMMY_DEVICE_NAME TEXT("ROOT\\WDMSECTEST\\0000")
|
|
|
|
#define DEBUG
|
|
|
|
|
|
|
|
|
|
//
|
|
// The 3 class GUIDs
|
|
//
|
|
|
|
DEFINE_GUID (GUID_PERSISTENT_CLASS, 0x6e987e64, 0x3ab7, 0x4cd3, 0x8e, 0xf6, 0xe1, \
|
|
0xbb, 0xae, 0x2e, 0xc8, 0xd7);
|
|
// 6e987e64-3ab7-4cd3-8ef6-e1bbae2ec8d7
|
|
|
|
DEFINE_GUID (GUID_TEMP_CLASS, 0xa2a21bd2, 0x5333, 0x4711, 0x9f, 0x61, 0x58, \
|
|
0x52, 0x0e, 0x33, 0xb0, 0x27);
|
|
// a2a21bd2-5333-4711-9f61-58520e33b027
|
|
|
|
DEFINE_GUID (GUID_TEST_ACL_CLASS, 0xd0670a99, 0x53dd, 0x45c3, 0x8d, 0xe6, 0x3d, \
|
|
0xe5, 0x81, 0xb4, 0x13, 0x49);
|
|
// d0670a99-53dd-45c3-8de6-3de581b41349
|
|
|
|
//
|
|
// Global SDDL strings...
|
|
//
|
|
const struct {
|
|
PWSTR SDDLString;
|
|
BOOLEAN Succeed;
|
|
} g_SDDL[] = {
|
|
//
|
|
// Almost all the default strings
|
|
// (we do not use kernel-only because I don't know
|
|
// if I can open it...)
|
|
//
|
|
{L"D:P(A;;GA;;;SY)", TRUE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GRGX;;;BA)", TRUE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;GRGW;;;WD)(A;;GR;;;RC)", TRUE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GA;;;BA)", TRUE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;GR;;;WD)", TRUE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;GR;;;WD)(A;;GR;;;RC)", TRUE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;GRGWGX;;;WD)(A;;GRGWGX;;;RC)", TRUE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GRGWGX;;;BA)(A;;0x0004;;;WD)", TRUE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;WD)(A;;GA;;;RC)", TRUE},
|
|
//
|
|
// Various groups
|
|
//
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;AO)", FALSE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;AU)", TRUE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;BA)", TRUE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;BG)", TRUE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;BO)", FALSE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;BU)", TRUE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;CA)", FALSE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;DA)", FALSE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;DG)", FALSE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;DU)", FALSE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;IU)", TRUE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;LA)", FALSE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;LG)", FALSE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;NU)", TRUE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;PO)", FALSE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;PU)", FALSE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;RC)", TRUE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;SO)", FALSE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;SU)", FALSE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;WD)", TRUE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;NS)", TRUE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;LS)", TRUE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;AN)", TRUE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;RN)", FALSE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;RD)", FALSE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GR;;;NO)", FALSE},
|
|
//
|
|
// Weird, but valid
|
|
//
|
|
{L"D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;BA)(A;;GA;;;BA)(A;;GA;;;BA)", TRUE},
|
|
//
|
|
// Some bad strings - deny access
|
|
//
|
|
{L"D:P(A;;GA;;;SY)(D;;GW;;;IU)", FALSE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;BA)(A;;GA;;;BA)(D;;GW;;;IU)", FALSE},
|
|
{L"D:P(A;;GA;;;SY)(A;;GA;;;BA)(D;;GX;;;SU)", FALSE},
|
|
//
|
|
// SACL
|
|
//
|
|
{L"S:P(A;;GA;;;SY)", FALSE},
|
|
//
|
|
// Object and container inheritance
|
|
//
|
|
{L"D:P(A;OICI;GA;;;SY)", FALSE},
|
|
//
|
|
// Weird
|
|
//
|
|
{L"D:WEIRD", FALSE},
|
|
{L"D:P(A;;GA;;XX)", FALSE},
|
|
{L"D:P(A;;QA;;BA)", FALSE}
|
|
//
|
|
// BUGBUG - I need to thing of more cases...
|
|
//
|
|
|
|
};
|
|
|
|
|
|
#define DEFAULT_SDDL L"D:P(A;;GA;;;SY)(A;;GA;;;BA)"
|
|
#define MORE_RESTRICTIVE_SDDL L"D:P(A;;GA;;;SY)"
|
|
#define LESS_RESTRICTIVE_SDDL L"D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GRGW;;;WD)"
|
|
#define DENY_SDDL L"D:P(A;;GA;;;SY)(D;;GW;;;IU)"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
// Declare data used in GUID->string conversion (from ole32\common\ccompapi.cxx).
|
|
//
|
|
static const BYTE GuidMap[] = { 3, 2, 1, 0, '-', 5, 4, '-', 7, 6, '-',
|
|
8, 9, '-', 10, 11, 12, 13, 14, 15};
|
|
|
|
static const TCHAR szDigits[] = TEXT("0123456789ABCDEF");
|
|
|
|
#define GUID_STRING_LEN 39 // size in chars, including terminating NULL
|
|
|
|
|
|
|
|
|
|
//
|
|
// Other globals
|
|
//
|
|
HANDLE g_hLog;
|
|
PTSTR g_szFileLogName = TEXT("WdmSecTest.log");
|
|
BOOLEAN g_IsWin2K = FALSE;
|
|
|
|
//
|
|
// Useful functions
|
|
//
|
|
BOOLEAN
|
|
CompareSecurity (
|
|
IN HANDLE hDevice,
|
|
IN PWSTR SDDLString,
|
|
IN PSECURITY_DESCRIPTOR SecDesc,
|
|
IN ULONG Length
|
|
);
|
|
|
|
BOOLEAN
|
|
TestCreateDevice (
|
|
IN HANDLE hDevice,
|
|
IN LPCGUID Guid,
|
|
IN PWSTR InSDDL,
|
|
IN PWSTR OutSDDL
|
|
);
|
|
|
|
|
|
BOOLEAN
|
|
CheckClassExists (
|
|
IN LPCGUID Guid
|
|
);
|
|
|
|
BOOLEAN
|
|
TakeClassKeyOwnership (
|
|
IN LPCGUID Guid
|
|
);
|
|
|
|
BOOLEAN
|
|
DeleteClassKey (
|
|
IN LPCGUID Guid
|
|
);
|
|
|
|
BOOLEAN
|
|
SetClassSecurity (
|
|
IN LPCGUID Guid,
|
|
IN PWSTR SDDLString
|
|
);
|
|
|
|
VOID
|
|
GetClassOverrides (
|
|
IN LPCGUID Guid,
|
|
OUT PWST_CREATE_WITH_GUID Create
|
|
);
|
|
|
|
|
|
DWORD
|
|
StringFromGuid(
|
|
IN CONST GUID *Guid,
|
|
OUT PTSTR GuidString,
|
|
IN DWORD GuidStringSize
|
|
) ;
|
|
|
|
BOOLEAN
|
|
SDDLUnsupportedOnWin2K (
|
|
IN PWSTR SDDL
|
|
);
|
|
|
|
|
|
|
|
void
|
|
_cdecl main(int argc, char *argv[])
|
|
{
|
|
|
|
CONFIGRET configret;
|
|
DEVNODE dnRoot;
|
|
DEVNODE dnDevNode;
|
|
HANDLE hDevice = INVALID_HANDLE_VALUE;
|
|
TCHAR NewDeviceName[MAX_PATH];
|
|
TCHAR szInfName[MAX_PATH];
|
|
|
|
TCHAR szHardwareId[] = TEXT("*PNP2002\0");
|
|
OSVERSIONINFOEX osVerInfo;
|
|
|
|
//
|
|
// Initialize log file
|
|
//
|
|
g_hLog = tlCreateLog(g_szFileLogName, LOG_OPTIONS);
|
|
if (g_hLog) {
|
|
tlAddParticipant(g_hLog, 0, 0);
|
|
tlStartVariation(g_hLog);
|
|
} else {
|
|
MessageBox(NULL, TEXT("WdmSecTest is unable to create the log file"), TEXT("Warning!"),
|
|
MB_ICONEXCLAMATION | MB_OK);
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// See on what OS we're running
|
|
//
|
|
osVerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
|
|
GetVersionEx ((LPOSVERSIONINFO)&osVerInfo);
|
|
if (osVerInfo.dwMajorVersion != 5) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("This app runs only on Windows 2000, Windows XP or later"));
|
|
goto Clean0;
|
|
}
|
|
if (osVerInfo.dwMinorVersion == 1) {
|
|
tlLog(g_hLog,
|
|
INFO_VARIATION,
|
|
TEXT("Will run test on Windows XP or .NET Server"));
|
|
|
|
} else {
|
|
|
|
g_IsWin2K = TRUE;
|
|
tlLog(g_hLog,
|
|
INFO_VARIATION,
|
|
TEXT("Will run test on Windows 2000"));
|
|
|
|
}
|
|
|
|
|
|
|
|
hDevice = OpenDriver();
|
|
|
|
if (INVALID_HANDLE_VALUE == hDevice) {
|
|
|
|
if (!InstallDevice(NULL, szHardwareId, NewDeviceName)) {
|
|
|
|
tlLog(g_hLog, tlEndVariation(g_hLog) | FAIL_VARIATION,
|
|
TEXT("Install Device failed"));
|
|
goto Clean0;
|
|
} else {
|
|
_tprintf(TEXT("Install Device succeded (1)\n"));
|
|
//
|
|
// Wait a bit, the attempt to open the device
|
|
//
|
|
_tprintf(TEXT("Will sleep 5 seconds before retrying to open device\n"));
|
|
Sleep(5000);
|
|
hDevice = OpenDriver();
|
|
if (INVALID_HANDLE_VALUE == hDevice) {
|
|
tlLog(g_hLog, tlEndVariation(g_hLog) | FAIL_VARIATION,
|
|
TEXT("Cannot open handle to test driver"));
|
|
goto Clean0;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// 1. Check that no name will trigger a failure
|
|
//
|
|
TestDeviceName(hDevice);
|
|
//
|
|
// 2. Test that we can create device with a NULL DeviceClassGuid
|
|
//
|
|
TestNullDeviceClassGuid(hDevice);
|
|
//
|
|
// 3. Test that we can use a persistent DeviceClassGuid
|
|
//
|
|
TestPersistentClassGuid(hDevice);
|
|
//
|
|
// 4. Test that we can use a temporary DeviceClassGuid
|
|
//
|
|
TestTemporaryClassGuid(hDevice);
|
|
//
|
|
// 5. Test that if we do not override the class
|
|
// settings the ACLs placed on them are consistent
|
|
// with what the user-mode SetupDi APIs would do
|
|
//
|
|
TestAclsSetOnClassKey(hDevice);
|
|
//
|
|
// 6. Test various SDDL strings
|
|
//
|
|
TestSDDLStrings(hDevice);
|
|
//
|
|
// 7. Use security group's sddls.txt file and see what happens
|
|
//
|
|
TestSDDLsFromFile(hDevice);
|
|
|
|
Clean0:
|
|
|
|
if (hDevice != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(hDevice);
|
|
}
|
|
|
|
if (g_hLog) {
|
|
tlReportStats(g_hLog);
|
|
tlRemoveParticipant(g_hLog);
|
|
tlDestroyLog(g_hLog);
|
|
|
|
}
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
TestDeviceName(
|
|
HANDLE hDevice
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cheks some simple things about device names
|
|
(IoCreateDeviceSecure with no device name will fail).
|
|
|
|
Arguments:
|
|
|
|
hDevice - handle to our test driver
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG ulSize = 0;
|
|
TCHAR szMsg[MAX_PATH];
|
|
|
|
tlStartVariation(g_hLog);
|
|
|
|
//
|
|
// Issue and IOCTL and see what happens
|
|
//
|
|
if (!DeviceIoControl(hDevice,
|
|
IOCTL_TEST_NAME,
|
|
NULL, ulSize,
|
|
NULL, ulSize,
|
|
&ulSize, NULL)) {
|
|
_stprintf(szMsg, TEXT("Error %d after TestDeviceName\n"), GetLastError());
|
|
OutputDebugString(szMsg);
|
|
tlLog(g_hLog, FAIL_VARIATION, TEXT("Cannot issue DeviceIoControl(TEST_NAME) to device"));
|
|
|
|
|
|
|
|
}
|
|
tlLog(g_hLog,tlEndVariation(g_hLog)|LOG_VARIATION,
|
|
TEXT("Test Device Name"));
|
|
|
|
|
|
return;
|
|
|
|
} // TestDeviceName
|
|
|
|
VOID
|
|
TestNullDeviceClassGuid(
|
|
HANDLE hDevice
|
|
)
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cheks that security descriptors can be set and there is no override
|
|
at the class level.
|
|
Arguments:
|
|
|
|
hDevice - handle to our test driver
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG ulSize = 0;
|
|
TCHAR szMsg[MAX_PATH];
|
|
|
|
tlStartVariation(g_hLog);
|
|
//
|
|
// 3 settings can be set independently
|
|
//
|
|
if (FALSE == TestCreateDevice(hDevice,
|
|
NULL,
|
|
DEFAULT_SDDL,
|
|
DEFAULT_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("Error creating object with NULL Guid and SDDL %ws"),
|
|
DEFAULT_SDDL);
|
|
}
|
|
|
|
if (FALSE == TestCreateDevice(hDevice,
|
|
NULL,
|
|
MORE_RESTRICTIVE_SDDL,
|
|
MORE_RESTRICTIVE_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("Error creating object with NULL Guid and SDDL %ws"),
|
|
MORE_RESTRICTIVE_SDDL);
|
|
}
|
|
|
|
if (FALSE == TestCreateDevice(hDevice,
|
|
NULL,
|
|
LESS_RESTRICTIVE_SDDL,
|
|
LESS_RESTRICTIVE_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("Error creating object with NULL Guid and SDDL %ws"),
|
|
LESS_RESTRICTIVE_SDDL);
|
|
}
|
|
|
|
|
|
tlLog(g_hLog,tlEndVariation(g_hLog)|LOG_VARIATION,
|
|
TEXT("Test NULL DeviceClassGuid"));
|
|
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
TestPersistentClassGuid(
|
|
HANDLE hDevice
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cheks that security descriptors can be set and there is override
|
|
at the class level if a Class GUID is specified. Also, this is
|
|
the way to check that class settings are persisted.
|
|
|
|
Arguments:
|
|
|
|
hDevice - handle to our test driver
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
tlStartVariation(g_hLog);
|
|
//
|
|
// If the class does not exist, create it and warn the user
|
|
//
|
|
if (FALSE == CheckClassExists(&GUID_PERSISTENT_CLASS)) {
|
|
//
|
|
// Create it
|
|
//
|
|
if (FALSE == TestCreateDevice(hDevice,
|
|
&GUID_PERSISTENT_CLASS,
|
|
DEFAULT_SDDL,
|
|
DEFAULT_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("Error creating object with NULL Guid and SDDL %ws"),
|
|
DEFAULT_SDDL);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Now touch it so the override sticks.
|
|
//
|
|
|
|
if (FALSE == SetClassSecurity(&GUID_PERSISTENT_CLASS,
|
|
DEFAULT_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("Error creating object with Persistent Guid and SDDL %ws"),
|
|
DEFAULT_SDDL);
|
|
} else {
|
|
tlLog(g_hLog,
|
|
WARN_VARIATION,
|
|
TEXT("Please re-run this test after rebooting the machine to check if class settings are persistent"));
|
|
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
} else {
|
|
//
|
|
// Just make sure we're using the defaults by setting the class
|
|
// security
|
|
//
|
|
if (FALSE == SetClassSecurity(&GUID_PERSISTENT_CLASS,
|
|
DEFAULT_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("Error creating object with Persistent Guid and SDDL %ws"),
|
|
DEFAULT_SDDL);
|
|
}
|
|
}
|
|
//
|
|
// 2 settings as above. We expect the security sectting to
|
|
// be DEFAULT_SDDL
|
|
//
|
|
if (FALSE == TestCreateDevice(hDevice,
|
|
&GUID_PERSISTENT_CLASS,
|
|
MORE_RESTRICTIVE_SDDL,
|
|
DEFAULT_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("1: Error creating object with Persistent Guid and SDDL %ws"),
|
|
MORE_RESTRICTIVE_SDDL);
|
|
}
|
|
|
|
if (FALSE == TestCreateDevice(hDevice,
|
|
&GUID_PERSISTENT_CLASS,
|
|
LESS_RESTRICTIVE_SDDL,
|
|
DEFAULT_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("1: Error creating object with Persistent Guid and SDDL %ws"),
|
|
LESS_RESTRICTIVE_SDDL);
|
|
}
|
|
|
|
|
|
tlLog(g_hLog,tlEndVariation(g_hLog)|LOG_VARIATION,
|
|
TEXT("Test Persistent DeviceClassGuid"));
|
|
|
|
|
|
tlStartVariation(g_hLog);
|
|
|
|
//
|
|
// Now change settings and see how are the things...
|
|
//
|
|
if (FALSE == SetClassSecurity(&GUID_PERSISTENT_CLASS,
|
|
LESS_RESTRICTIVE_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("1: Cannot change persistent class security"));
|
|
goto Clean0;
|
|
}
|
|
|
|
if (FALSE == TestCreateDevice(hDevice,
|
|
&GUID_PERSISTENT_CLASS,
|
|
MORE_RESTRICTIVE_SDDL,
|
|
LESS_RESTRICTIVE_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("2: Error creating object with Persistent Guid and SDDL %ws"),
|
|
MORE_RESTRICTIVE_SDDL);
|
|
}
|
|
|
|
if (FALSE == TestCreateDevice(hDevice,
|
|
&GUID_PERSISTENT_CLASS,
|
|
DEFAULT_SDDL,
|
|
LESS_RESTRICTIVE_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("2: Error creating object with Persistent Guid and SDDL %ws"),
|
|
LESS_RESTRICTIVE_SDDL);
|
|
}
|
|
tlLog(g_hLog,tlEndVariation(g_hLog)|LOG_VARIATION,
|
|
TEXT("Change persistent class settings"));
|
|
|
|
tlStartVariation(g_hLog);
|
|
|
|
//
|
|
// Check that using a deny ACL is allowed if it read
|
|
// from the registry
|
|
//
|
|
|
|
if (FALSE == SetClassSecurity(&GUID_PERSISTENT_CLASS,
|
|
DENY_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("2: Cannot change persistent class security to Deny ACL"));
|
|
goto Clean0;
|
|
}
|
|
|
|
if (FALSE == TestCreateDevice(hDevice,
|
|
&GUID_PERSISTENT_CLASS,
|
|
MORE_RESTRICTIVE_SDDL,
|
|
DENY_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("3: Error creating object with Persistent Guid and SDDL %ws (Deny)"),
|
|
DENY_SDDL);
|
|
}
|
|
|
|
|
|
//
|
|
// Make sure we leave things as they were...
|
|
//
|
|
if (FALSE == SetClassSecurity(&GUID_PERSISTENT_CLASS,
|
|
DEFAULT_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("2: Cannot change persistent class security"));
|
|
}
|
|
|
|
Clean0:
|
|
|
|
tlLog(g_hLog,tlEndVariation(g_hLog)|LOG_VARIATION,
|
|
TEXT("Apply Deny ACL"));
|
|
|
|
|
|
|
|
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
TestTemporaryClassGuid(
|
|
HANDLE hDevice
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Cheks that security descriptors can be overriden at the class
|
|
level.
|
|
|
|
Arguments:
|
|
|
|
hDevice - handle to our test driver
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DEVICE_TYPE deviceType;
|
|
ULONG characteristics;
|
|
DWORD exclusivity;
|
|
|
|
//
|
|
// Make sure we delete the class settings
|
|
//
|
|
tlStartVariation(g_hLog);
|
|
DeleteClassKey(&GUID_TEMP_CLASS);
|
|
|
|
|
|
//
|
|
// 3 settings here. We expect the security sectting to
|
|
// be what we set (
|
|
//
|
|
|
|
|
|
if (FALSE == TestCreateDevice(hDevice,
|
|
&GUID_TEMP_CLASS,
|
|
DEFAULT_SDDL,
|
|
DEFAULT_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("1: Error creating object with Temporary Guid and SDDL %ws"),
|
|
DEFAULT_SDDL);
|
|
}
|
|
|
|
if (FALSE == TestCreateDevice(hDevice,
|
|
&GUID_TEMP_CLASS,
|
|
MORE_RESTRICTIVE_SDDL,
|
|
MORE_RESTRICTIVE_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("1: Error creating object with Temporary Guid and SDDL %ws"),
|
|
MORE_RESTRICTIVE_SDDL);
|
|
}
|
|
|
|
|
|
if (FALSE == TestCreateDevice(hDevice,
|
|
&GUID_TEMP_CLASS,
|
|
LESS_RESTRICTIVE_SDDL,
|
|
LESS_RESTRICTIVE_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("1: Error creating object with Temporary Guid and SDDL %ws"),
|
|
LESS_RESTRICTIVE_SDDL);
|
|
}
|
|
|
|
|
|
tlLog(g_hLog,tlEndVariation(g_hLog)|LOG_VARIATION,
|
|
TEXT("Test Temporary DeviceClassGuid"));
|
|
|
|
|
|
tlStartVariation(g_hLog);
|
|
|
|
//
|
|
// Now change settings and see how are the things...
|
|
//
|
|
if (FALSE == SetClassSecurity(&GUID_TEMP_CLASS,
|
|
LESS_RESTRICTIVE_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("1: Cannot change temporary class security"));
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// Try to different settings and check that they are overriden
|
|
// by the class settings
|
|
//
|
|
if (FALSE == TestCreateDevice(hDevice,
|
|
&GUID_TEMP_CLASS,
|
|
MORE_RESTRICTIVE_SDDL,
|
|
LESS_RESTRICTIVE_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("2: Error creating object with Temporary Guid and SDDL %ws"),
|
|
MORE_RESTRICTIVE_SDDL);
|
|
}
|
|
|
|
if (FALSE == TestCreateDevice(hDevice,
|
|
&GUID_TEMP_CLASS,
|
|
DEFAULT_SDDL,
|
|
LESS_RESTRICTIVE_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("2: Error creating object with Temporary Guid and SDDL %ws"),
|
|
LESS_RESTRICTIVE_SDDL);
|
|
}
|
|
|
|
tlLog(g_hLog,tlEndVariation(g_hLog)|LOG_VARIATION,
|
|
TEXT("Test Temporary DeviceClassGuid with overriding security settings"));
|
|
|
|
|
|
tlStartVariation(g_hLog);
|
|
|
|
//
|
|
// This would test elements
|
|
// other than security (DeviceType,
|
|
// Device Characteristics and Exclusivity)
|
|
//
|
|
// We will set each one of the remaining 3, then
|
|
// we will set all 4 (inclusing Security and see what happens)
|
|
//
|
|
|
|
//
|
|
// Start by deleteing the class Key
|
|
//
|
|
if (FALSE == DeleteClassKey(&GUID_TEMP_CLASS)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("Cannot delete temporary class"));
|
|
goto Clean0;
|
|
|
|
}
|
|
//
|
|
// Initialize our values. Try something other than
|
|
// what kernel-mode sets
|
|
//
|
|
deviceType = FILE_DEVICE_NULL;
|
|
characteristics = FILE_REMOTE_DEVICE;
|
|
exclusivity = 1; // TRUE
|
|
|
|
|
|
//
|
|
// Again, we need to do something about Win2K here
|
|
//
|
|
#if 0
|
|
if (FALSE == SetupDiSetClassRegistryProperty(&GUID_TEMP_CLASS,
|
|
SPCRP_DEVTYPE,
|
|
(PBYTE)&deviceType,
|
|
sizeof(deviceType),
|
|
NULL,
|
|
NULL
|
|
)) {
|
|
tlLog(g_hLog, FAIL_VARIATION,
|
|
TEXT("Cannot set DeviceType"));
|
|
}
|
|
#else
|
|
if (CR_SUCCESS != CM_Set_Class_Registry_Property((LPGUID)&GUID_TEMP_CLASS,
|
|
CM_CRP_DEVTYPE,
|
|
(PBYTE)&deviceType,
|
|
sizeof(deviceType),
|
|
0,
|
|
NULL
|
|
)) {
|
|
tlLog(g_hLog, FAIL_VARIATION,
|
|
TEXT("Cannot set DeviceType"));
|
|
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Try to create a device. We should get back what we set, since
|
|
// we deleted the key, right ?
|
|
//
|
|
if (FALSE == TestCreateDevice(hDevice,
|
|
&GUID_TEMP_CLASS,
|
|
DEFAULT_SDDL,
|
|
DEFAULT_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("3: Error creating object with Temporary Guid and SDDL %ws"),
|
|
DEFAULT_SDDL);
|
|
}
|
|
//
|
|
// Characteristics
|
|
//
|
|
#if 0
|
|
if (FALSE == SetupDiSetClassRegistryProperty(&GUID_TEMP_CLASS,
|
|
SPCRP_CHARACTERISTICS,
|
|
(PBYTE)&characteristics,
|
|
sizeof(characteristics),
|
|
NULL,
|
|
NULL
|
|
)) {
|
|
tlLog(g_hLog, FAIL_VARIATION,
|
|
TEXT("Cannot set Characteristics"));
|
|
}
|
|
#else
|
|
if (CR_SUCCESS != CM_Set_Class_Registry_Property((LPGUID)&GUID_TEMP_CLASS,
|
|
CM_CRP_CHARACTERISTICS,
|
|
(PBYTE)&characteristics,
|
|
sizeof(characteristics),
|
|
0,
|
|
NULL
|
|
)) {
|
|
tlLog(g_hLog, FAIL_VARIATION,
|
|
TEXT("Cannot set Characteristics"));
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
//
|
|
// Try to create a device. We should get back what we set, since
|
|
// we deleted the key, right ?
|
|
//
|
|
if (FALSE == TestCreateDevice(hDevice,
|
|
&GUID_TEMP_CLASS,
|
|
DEFAULT_SDDL,
|
|
DEFAULT_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("4: Error creating object with Temporary Guid and SDDL %ws"),
|
|
DEFAULT_SDDL);
|
|
}
|
|
|
|
|
|
#if 0
|
|
if (FALSE == SetupDiSetClassRegistryProperty(&GUID_TEMP_CLASS,
|
|
SPCRP_EXCLUSIVE,
|
|
(PBYTE)&exclusivity,
|
|
sizeof(exclusivity),
|
|
NULL,
|
|
NULL
|
|
)) {
|
|
tlLog(g_hLog, FAIL_VARIATION,
|
|
TEXT("Cannot set Exclusivity"));
|
|
}
|
|
#else
|
|
if (CR_SUCCESS != CM_Set_Class_Registry_Property((LPGUID)&GUID_TEMP_CLASS,
|
|
CM_CRP_EXCLUSIVE,
|
|
(PBYTE)&exclusivity,
|
|
sizeof(exclusivity),
|
|
0,
|
|
NULL
|
|
)) {
|
|
tlLog(g_hLog, FAIL_VARIATION,
|
|
TEXT("Cannot set Exclusivity"));
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
//
|
|
// Try to create a device. We should get back what we set, since
|
|
// we deleted the key, right ?
|
|
//
|
|
if (FALSE == TestCreateDevice(hDevice,
|
|
&GUID_TEMP_CLASS,
|
|
DEFAULT_SDDL,
|
|
DEFAULT_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("5: Error creating object with Temporary Guid and SDDL %ws"),
|
|
DEFAULT_SDDL);
|
|
}
|
|
|
|
|
|
|
|
//
|
|
// All together now. Make sure to use the Deny ACL and check that it works
|
|
// (it is set through teh registry so it should work, right ?)
|
|
//
|
|
|
|
if (FALSE == SetClassSecurity(&GUID_TEMP_CLASS,
|
|
DENY_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("3: Cannot change temporary class security with Deny ACL"));
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// Try to different settings and check that they are overriden
|
|
// by the class settings
|
|
//
|
|
if (FALSE == TestCreateDevice(hDevice,
|
|
&GUID_TEMP_CLASS,
|
|
LESS_RESTRICTIVE_SDDL,
|
|
DENY_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("6: Error creating object with Temporary Guid and SDDL %ws (Deny ACL)"),
|
|
DENY_SDDL);
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
// Make sure we leave things as they were...
|
|
//
|
|
Clean0:
|
|
|
|
if (FALSE == DeleteClassKey(&GUID_TEMP_CLASS)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("Cannot delete temporary class key. Why ?"));
|
|
}
|
|
|
|
tlLog(g_hLog,tlEndVariation(g_hLog)|LOG_VARIATION,
|
|
TEXT("Test Temporary DeviceClassGuid with overriding non-security settings"));
|
|
|
|
|
|
|
|
return;
|
|
} // TestTemporaryClassGuid
|
|
|
|
|
|
VOID
|
|
TestAclsSetOnClassKey (
|
|
HANDLE hDevice
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Uses a GUID to create a device object, but does not use
|
|
any override on the class, so we can actually check
|
|
the ACLs set by the wdmsec library on the class key itself
|
|
and check if they are OK.
|
|
|
|
Arguments:
|
|
|
|
hDevice - handle to our test driver
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
|
|
{
|
|
|
|
tlStartVariation(g_hLog);
|
|
//
|
|
// There should be no override, so this should work
|
|
//
|
|
if (FALSE == TestCreateDevice(hDevice,
|
|
&GUID_TEST_ACL_CLASS,
|
|
LESS_RESTRICTIVE_SDDL,
|
|
LESS_RESTRICTIVE_SDDL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("Error creating object with Test ACL Guid and SDDL %ws"),
|
|
LESS_RESTRICTIVE_SDDL);
|
|
}
|
|
tlLog(g_hLog,tlEndVariation(g_hLog)|LOG_VARIATION,
|
|
TEXT("Test ACL set on Class Key by the WdmSec library"));
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
|
} // TestAclsSetOnClassKey
|
|
|
|
|
|
|
|
VOID
|
|
TestSDDLStrings(
|
|
HANDLE hDevice
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Iterates through a list of SDDL strings, creates objects
|
|
with the appropriate security and checks if the security descriptor
|
|
we get back makes sense
|
|
|
|
Arguments:
|
|
|
|
hDevice - handle to our test driver
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
WST_CREATE_NO_GUID create;
|
|
ULONG ulSize;
|
|
TCHAR szMsg[MAX_PATH];
|
|
int i;
|
|
LPTSTR tsd;
|
|
|
|
tlStartVariation(g_hLog);
|
|
|
|
for (i = 0 ; i < sizeof(g_SDDL) / sizeof(g_SDDL[0]); i++) {
|
|
|
|
|
|
//
|
|
// Fill in the data
|
|
//
|
|
ZeroMemory(&create, sizeof(WST_CREATE_NO_GUID));
|
|
wcsncpy(create.InSDDL, g_SDDL[i].SDDLString, sizeof(create.InSDDL)/sizeof(create.InSDDL[0]) - 1);
|
|
ulSize = sizeof(WST_CREATE_NO_GUID);
|
|
|
|
if (!DeviceIoControl(hDevice,
|
|
IOCTL_TEST_NO_GUID,
|
|
&create, ulSize,
|
|
&create, ulSize,
|
|
&ulSize, NULL)) {
|
|
_stprintf(szMsg, TEXT("Error %d after DeviceIoControl(%d) in TestSDDLStrings)\n"),
|
|
GetLastError(), i);
|
|
OutputDebugString(szMsg);
|
|
tlLog(g_hLog, FAIL_VARIATION,
|
|
TEXT("Error %x after DeviceIoControl(%ws)"),
|
|
GetLastError(), create.InSDDL);
|
|
continue;
|
|
}
|
|
|
|
|
|
if (!NT_SUCCESS(create.Status)) {
|
|
if (g_SDDL[i].Succeed) {
|
|
//
|
|
// Oops, we're should have succeeded
|
|
//
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("Status %x after creating device object with SDDL %ws"),
|
|
create.Status, create.InSDDL);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
tlLog(g_hLog,
|
|
PASS_VARIATION,
|
|
TEXT("Status %x (as expected) after creating devobj with SDDL %ws"),
|
|
create.Status, create.InSDDL);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Some strings will not work on Win2K, just skip them
|
|
//
|
|
if (g_IsWin2K &&
|
|
(TRUE == SDDLUnsupportedOnWin2K(g_SDDL[i].SDDLString))) {
|
|
//
|
|
// Get a SDDL from the SD and see what we got back
|
|
//
|
|
LPTSTR lpStringSD = NULL;
|
|
|
|
|
|
//
|
|
// Try to get a SDDL string for the second descriptor
|
|
//
|
|
if (!ConvertSecurityDescriptorToStringSecurityDescriptor(
|
|
(PSECURITY_DESCRIPTOR) create.SecurityDescriptor,
|
|
SDDL_REVISION_1,
|
|
DACL_SECURITY_INFORMATION,
|
|
&lpStringSD,
|
|
NULL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("Cannot convert SD to SDDL"));
|
|
|
|
|
|
|
|
} else {
|
|
tlLog(g_hLog,
|
|
INFO_VARIATION,
|
|
TEXT("On Win2K unsupported SDDL %ws was applied as %s"),
|
|
g_SDDL[i].SDDLString,
|
|
lpStringSD);
|
|
|
|
}
|
|
|
|
if (lpStringSD) {
|
|
LocalFree(lpStringSD);
|
|
lpStringSD = NULL;
|
|
}
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
//
|
|
// We were succesfull, let's try and see if the security descriptor looks fine
|
|
//
|
|
|
|
if (FALSE == CompareSecurity(hDevice,
|
|
create.InSDDL,
|
|
(PSECURITY_DESCRIPTOR)&create.SecurityDescriptor,
|
|
create.SecDescLength)) {
|
|
tlLog(g_hLog, FAIL_VARIATION,
|
|
TEXT("Applied SDDL %ws but got back a wrong security descriptor"),
|
|
create.InSDDL);
|
|
} else {
|
|
tlLog(g_hLog, PASS_VARIATION,
|
|
TEXT("Applied SDDL %ws and got back a consistent security descriptor"),
|
|
create.InSDDL);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} // for all strings
|
|
tlLog(g_hLog,tlEndVariation(g_hLog)|LOG_VARIATION,
|
|
TEXT("Various SDDL strings"));
|
|
|
|
|
|
|
|
return;
|
|
} // TestSDDLStrings
|
|
|
|
VOID
|
|
TestSDDLsFromFile (
|
|
HANDLE hDevice
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Iterates through a list of SDDL strings in a file
|
|
which we got from the security team. The idea is that
|
|
I cannot determine if the strings should work (like the
|
|
strings in TestSDDLStrings) so I'll just try them and see
|
|
what happens.
|
|
|
|
|
|
Arguments:
|
|
|
|
hDevice - handle to our test driver
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
FILE *fp = NULL;
|
|
WCHAR line[512];
|
|
PWSTR aux;
|
|
|
|
tlStartVariation(g_hLog);
|
|
|
|
fp = _wfopen(L"sddls.txt", L"rt");
|
|
|
|
if (NULL == fp) {
|
|
tlLog(g_hLog,
|
|
WARN_VARIATION,
|
|
TEXT("Cannot open sddls.txt (error %x)"),
|
|
GetLastError());
|
|
tlLog(g_hLog,
|
|
WARN_VARIATION,
|
|
TEXT("Make sure sddls.txt is in the current directory."));
|
|
goto Clean0;
|
|
|
|
}
|
|
|
|
while (!feof(fp)) {
|
|
if ( fgetws( line, sizeof(line)/sizeof(line[0]) - 1, fp ) == NULL) {
|
|
//
|
|
// What can we do ? Maybe see if it's EOF ?
|
|
//
|
|
if (!feof(fp)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("fgets encountered an error (%x) in file sddls.txt"),
|
|
GetLastError());
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
//
|
|
// Replace '\r' and '\n'
|
|
//
|
|
aux = wcschr(line, L'\r');
|
|
if (aux) {
|
|
*aux = L'\0';
|
|
}
|
|
|
|
aux = wcschr(line, L'\n');
|
|
if (aux) {
|
|
*aux = L'\0';
|
|
}
|
|
|
|
//
|
|
// Don't care about empty lines
|
|
//
|
|
if (line[0] == L'\0') {
|
|
continue;
|
|
}
|
|
//
|
|
// Check if it works
|
|
//
|
|
if (FALSE == TestCreateDevice(hDevice,
|
|
NULL,
|
|
line,
|
|
NULL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("1: Error creating object with SDDL %ws (from file)"),
|
|
line);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} // while reading file
|
|
|
|
Clean0:
|
|
tlLog(g_hLog,tlEndVariation(g_hLog)|LOG_VARIATION,
|
|
TEXT("Various SDDL strings from a file"));
|
|
|
|
|
|
|
|
if (fp) {
|
|
fclose(fp);
|
|
}
|
|
|
|
return;
|
|
} // TestSDDLsFromFile
|
|
|
|
BOOLEAN
|
|
CompareSecurity (
|
|
IN HANDLE hDevice,
|
|
IN PWSTR SDDLString,
|
|
IN PSECURITY_DESCRIPTOR SecDesc,
|
|
IN ULONG Length
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Converts a SDDL string to a security descriptor and
|
|
then compares with a binary self-referencing one and
|
|
decides if they are the same.
|
|
|
|
Arguments:
|
|
|
|
hDevice - handle to our device (we need to call it to
|
|
do the dirty things for us)
|
|
|
|
SDDLString - a SDDL string
|
|
|
|
SecDesc - a binary security descriptor
|
|
|
|
Length - the length of the security decsriptor
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE is the SDDL string and the security descriptor describe the same thing,
|
|
FALSE if not
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PSECURITY_DESCRIPTOR psd = NULL;
|
|
BOOLEAN bRet = FALSE;
|
|
ULONG ulSize = 0;
|
|
ULONG ulSecDescSize = 0;
|
|
WST_CREATE_OBJECT create;
|
|
WST_DESTROY_OBJECT destroy;
|
|
WST_GET_SECURITY getSec;
|
|
TCHAR szMsg[MAX_PATH];
|
|
NTSTATUS status;
|
|
HANDLE handle = 0;
|
|
OBJECT_ATTRIBUTES objAttr;
|
|
IO_STATUS_BLOCK iosb;
|
|
UNICODE_STRING unicodeString;
|
|
SECURITY_INFORMATION securityInformation;
|
|
|
|
|
|
//
|
|
// Change the f... security information since we're interested in
|
|
// DACL only.
|
|
|
|
//
|
|
// What if we have more than DACLs in the SDDL string ? Who cares ?
|
|
// S... happens.
|
|
//
|
|
securityInformation = DACL_SECURITY_INFORMATION;
|
|
|
|
|
|
|
|
if (FALSE == ConvertStringSecurityDescriptorToSecurityDescriptorW(
|
|
SDDLString,
|
|
SDDL_REVISION_1,
|
|
&psd,
|
|
&ulSecDescSize)) {
|
|
|
|
tlLog(g_hLog, FAIL_VARIATION, TEXT("Cannot convert security descriptor %ws"),
|
|
SDDLString);
|
|
return FALSE;
|
|
}
|
|
//
|
|
// Do the full thingy (call into kernel-mode to get handle
|
|
// and stuff...)
|
|
//
|
|
|
|
ZeroMemory(&create, sizeof(create));
|
|
ZeroMemory(&destroy, sizeof(destroy));
|
|
ZeroMemory(&getSec, sizeof(getSec));
|
|
|
|
//
|
|
// Create a device object
|
|
//
|
|
|
|
ulSize = sizeof(create);
|
|
if (!DeviceIoControl(hDevice,
|
|
IOCTL_TEST_CREATE_OBJECT,
|
|
&create,
|
|
ulSize,
|
|
&create,
|
|
ulSize,
|
|
&ulSize,
|
|
NULL)) {
|
|
_stprintf(szMsg, TEXT("Error %d after CreateDevice in CompareSecurity\n"),
|
|
GetLastError());
|
|
OutputDebugString(szMsg);
|
|
tlLog(g_hLog, FAIL_VARIATION,
|
|
TEXT("Error %x after DeviceIoControl(CreateDevice, %ws)"),
|
|
GetLastError(), SDDLString);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Attempt to open the device and set its security descriptor
|
|
//
|
|
|
|
|
|
RtlInitUnicodeString(&unicodeString, create.Name);
|
|
InitializeObjectAttributes(&objAttr,
|
|
&unicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
ZeroMemory(&iosb, sizeof(iosb));
|
|
|
|
status = NtOpenFile(&handle,
|
|
(WRITE_DAC | GENERIC_READ),
|
|
&objAttr,
|
|
&iosb,
|
|
FILE_SHARE_READ,
|
|
0);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
tlLog(g_hLog, FAIL_VARIATION,
|
|
TEXT("Cannot open device %ws in CompareSecurity, status %x"),
|
|
create.Name, status);
|
|
|
|
goto Clean0;
|
|
}
|
|
|
|
status = NtSetSecurityObject(handle,
|
|
securityInformation,
|
|
psd);
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
|
|
tlLog(g_hLog, FAIL_VARIATION,
|
|
TEXT("NtSetSecurityObject failed with status %x\n"),
|
|
status);
|
|
goto Clean0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
//
|
|
// Get the security descriptor back
|
|
//
|
|
getSec.DevObj = create.DevObj;
|
|
getSec.SecurityInformation = securityInformation;
|
|
|
|
ulSize = sizeof(getSec);
|
|
if (!DeviceIoControl(hDevice,
|
|
IOCTL_TEST_GET_SECURITY,
|
|
&getSec,
|
|
ulSize,
|
|
&getSec,
|
|
ulSize,
|
|
&ulSize,
|
|
NULL)) {
|
|
_stprintf(szMsg, TEXT("Error %d after GetSecurity in CompareSecurity\n"),
|
|
GetLastError());
|
|
OutputDebugString(szMsg);
|
|
tlLog(g_hLog, FAIL_VARIATION,
|
|
TEXT("Error %x after DeviceIoControl(GetSecurity, %ws)"),
|
|
GetLastError(), SDDLString);
|
|
goto Clean0;
|
|
}
|
|
|
|
|
|
|
|
if ((getSec.Length != Length) ||
|
|
(0 != memcmp(getSec.SecurityDescriptor, SecDesc, Length))) {
|
|
|
|
LPTSTR lpStringSD = NULL;
|
|
|
|
|
|
//
|
|
// Try to get a SDDL string for the second descriptor
|
|
//
|
|
if (!ConvertSecurityDescriptorToStringSecurityDescriptor(
|
|
(PSECURITY_DESCRIPTOR) SecDesc,
|
|
SDDL_REVISION_1,
|
|
securityInformation,
|
|
&lpStringSD,
|
|
NULL)) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("Cannot convert SD to SDDL"));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
szMsg[MAX_PATH - 1] = 0;
|
|
tlLog(g_hLog, FAIL_VARIATION,
|
|
TEXT("Security descriptor with SDDL %ws and expected SDDL string %ws are different (address %p and %p for %x and %x bytes)"),
|
|
lpStringSD,
|
|
SDDLString,
|
|
&getSec.SecurityDescriptor,
|
|
SecDesc,
|
|
getSec.Length, Length);
|
|
|
|
_sntprintf(szMsg,
|
|
MAX_PATH - 1,
|
|
TEXT("Will break to examine why sec descs @ %p and %p (lengths %x and %x) are different (SDDL %ws)"),
|
|
&getSec.SecurityDescriptor,
|
|
SecDesc,
|
|
getSec.Length,
|
|
Length,
|
|
SDDLString);
|
|
OutputDebugString(szMsg);
|
|
DebugBreak();
|
|
|
|
if (lpStringSD) {
|
|
LocalFree(lpStringSD);
|
|
}
|
|
bRet = FALSE;
|
|
} else {
|
|
bRet = TRUE;
|
|
}
|
|
|
|
Clean0:
|
|
//
|
|
// A lot of cleanup to do here...
|
|
//
|
|
if (handle) {
|
|
NtClose(handle);
|
|
}
|
|
//
|
|
// Also destroy the device object
|
|
//
|
|
if (create.DevObj) {
|
|
destroy.DevObj = create.DevObj;
|
|
ulSize = sizeof(destroy);
|
|
if (!DeviceIoControl(hDevice,
|
|
IOCTL_TEST_DESTROY_OBJECT,
|
|
&destroy,
|
|
ulSize,
|
|
&destroy,
|
|
ulSize,
|
|
&ulSize,
|
|
NULL)) {
|
|
_stprintf(szMsg, TEXT("Error %d after DestroyDevice in CompareSecurity\n"),
|
|
GetLastError());
|
|
OutputDebugString(szMsg);
|
|
tlLog(g_hLog, FAIL_VARIATION,
|
|
TEXT("Error %x after DeviceIoControl(destroyDevice, %ws)"),
|
|
GetLastError(), SDDLString);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
if (psd) {
|
|
LocalFree(psd);
|
|
}
|
|
|
|
return bRet;
|
|
} // CompareSecurity
|
|
|
|
|
|
BOOLEAN
|
|
TestCreateDevice (
|
|
IN HANDLE hDevice,
|
|
IN LPCGUID Guid,
|
|
IN PWSTR InSDDL,
|
|
IN PWSTR OutSDDL
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a device object using IoCreateDeviceObjectSecure and
|
|
InSDDL and Guid as inputs. Finally checks that the security
|
|
descriptor retrieved matches OutSDDL
|
|
|
|
|
|
Arguments:
|
|
|
|
hDevice - handle to our device (we need to call it to
|
|
do the dirty things for us)
|
|
|
|
Guid - if present, it is supplied to kernel-mode
|
|
|
|
InSDDL - the SDDL string we pass to the driver
|
|
|
|
OutSDDL - the SDDL string we expect to match (may be
|
|
different than InSDDL since we may have a class
|
|
override)
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE is everything is fine, FALSE if not
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
WST_CREATE_WITH_GUID createWithGuid;
|
|
WST_CREATE_NO_GUID createNoGuid;
|
|
ULONG ulSize;
|
|
TCHAR szMsg[MAX_PATH];
|
|
PSECURITY_DESCRIPTOR secDesc;
|
|
ULONG length;
|
|
NTSTATUS status;
|
|
DEVICE_TYPE deviceType;
|
|
ULONG characteristics;
|
|
BOOLEAN exclusivity;
|
|
|
|
if (Guid) {
|
|
ZeroMemory(&createWithGuid, sizeof(WST_CREATE_WITH_GUID));
|
|
wcsncpy(createWithGuid.InSDDL,
|
|
InSDDL,
|
|
sizeof(createWithGuid.InSDDL)/sizeof(createWithGuid.InSDDL[0]) - 1);
|
|
|
|
CopyMemory(&createWithGuid.DeviceClassGuid,
|
|
Guid,
|
|
sizeof(GUID));
|
|
|
|
ulSize = sizeof(WST_CREATE_WITH_GUID);
|
|
|
|
if (!DeviceIoControl(hDevice,
|
|
IOCTL_TEST_GUID,
|
|
&createWithGuid,
|
|
ulSize,
|
|
&createWithGuid,
|
|
ulSize,
|
|
&ulSize,
|
|
NULL)) {
|
|
_stprintf(szMsg, TEXT("Error %d after DeviceIoControl(%ws) in TestCreateDevice with GUID\n"),
|
|
GetLastError(), createWithGuid.InSDDL);
|
|
OutputDebugString(szMsg);
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else {
|
|
//
|
|
// Save the elements we're interested in
|
|
//
|
|
status = createWithGuid.Status;
|
|
length = createWithGuid.SecDescLength;
|
|
secDesc = (PSECURITY_DESCRIPTOR)&createWithGuid.SecurityDescriptor;
|
|
}
|
|
|
|
//
|
|
// Also, if we have class overrides, pass them to the
|
|
// driver to check if they override them
|
|
//
|
|
GetClassOverrides(Guid, &createWithGuid);
|
|
//
|
|
// Save away the values so we can compare them later
|
|
//
|
|
deviceType = createWithGuid.DeviceType;
|
|
characteristics = createWithGuid.Characteristics;
|
|
exclusivity = createWithGuid.Exclusivity;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else {
|
|
ZeroMemory(&createNoGuid, sizeof(WST_CREATE_NO_GUID));
|
|
wcsncpy(createNoGuid.InSDDL,
|
|
InSDDL,
|
|
sizeof(createNoGuid.InSDDL)/sizeof(createNoGuid.InSDDL[0]) - 1);
|
|
|
|
ulSize = sizeof(WST_CREATE_NO_GUID);
|
|
|
|
if (!DeviceIoControl(hDevice,
|
|
IOCTL_TEST_NO_GUID,
|
|
&createNoGuid,
|
|
ulSize,
|
|
&createNoGuid,
|
|
ulSize,
|
|
&ulSize,
|
|
NULL)) {
|
|
_stprintf(szMsg, TEXT("Error %d after DeviceIoControl(%ws) in TestClassGuid without GUID\n"),
|
|
GetLastError(), createNoGuid.InSDDL);
|
|
OutputDebugString(szMsg);
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else {
|
|
//
|
|
// Save the elements we're interested in
|
|
//
|
|
status = createNoGuid.Status;
|
|
length = createNoGuid.SecDescLength;
|
|
secDesc = (PSECURITY_DESCRIPTOR)&createNoGuid.SecurityDescriptor;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
if (!NT_SUCCESS(status)) {
|
|
//
|
|
// This may be OK if the out SDDL is NULL, which means it is expected
|
|
//
|
|
if (NULL == OutSDDL) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// If we have non-security overrides, we need to check
|
|
// that they were applied
|
|
//
|
|
if (Guid) {
|
|
|
|
if ((createWithGuid.SettingsMask & SET_DEVICE_TYPE) &&
|
|
(createWithGuid.DeviceType != deviceType)) {
|
|
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("DeviceType was not overidden. Class had %x, after creation we got %x"),
|
|
deviceType, createWithGuid.DeviceType);
|
|
}
|
|
|
|
if ((createWithGuid.SettingsMask & SET_DEVICE_CHARACTERISTICS) &&
|
|
(createWithGuid.Characteristics != characteristics)) {
|
|
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("Characterisrics was not overidden. Class had %x, after creation we got %x"),
|
|
characteristics, createWithGuid.Characteristics);
|
|
}
|
|
if ((createWithGuid.SettingsMask & SET_EXCLUSIVITY) &&
|
|
(createWithGuid.Exclusivity != exclusivity)) {
|
|
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("Exclusivity was not overidden. Class had %x, after creation we got %x"),
|
|
exclusivity, createWithGuid.Exclusivity);
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
if (NULL == OutSDDL) {
|
|
//
|
|
// We were expecting a failure or didn't know
|
|
// what to expect. But if it succeeded, we need to
|
|
// check the security settings using the initial
|
|
// string as the expected one.
|
|
|
|
//
|
|
// Also print something so the user knows that they had a string that worked
|
|
//
|
|
tlLog(g_hLog,
|
|
PASS_VARIATION,
|
|
TEXT("IoCreateDeviceSecure returned success for SDDL %ws"),
|
|
InSDDL);
|
|
return CompareSecurity(hDevice, InSDDL, secDesc, length);
|
|
}
|
|
|
|
return CompareSecurity(hDevice, OutSDDL, secDesc, length);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} // TestCreateDevice
|
|
|
|
|
|
BOOLEAN
|
|
CheckClassExists (
|
|
IN LPCGUID Guid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks if a class exists
|
|
|
|
Arguments:
|
|
|
|
Guid - the class whose existence is to be checked
|
|
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
HKEY hKey;
|
|
BOOLEAN bRet = FALSE;
|
|
BYTE data[256];
|
|
ULONG size = sizeof(data);
|
|
|
|
hKey = SetupDiOpenClassRegKeyEx(Guid,
|
|
KEY_READ,
|
|
DIOCR_INSTALLER,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (INVALID_HANDLE_VALUE == hKey) {
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Check if we can get the class security.
|
|
// We need to use CM APIs because SetupDi ones
|
|
// do not work on Win2K
|
|
//
|
|
#if 0
|
|
if (FALSE == SetupDiGetClassRegistryProperty(Guid,
|
|
SPCRP_SECURITY,
|
|
NULL,
|
|
data,
|
|
sizeof(data),
|
|
NULL,
|
|
NULL,
|
|
NULL)) {
|
|
//
|
|
// We cannot get security for this guy. That means that
|
|
// the key does not exist.
|
|
//
|
|
bRet = FALSE;
|
|
|
|
|
|
} else {
|
|
bRet = TRUE;
|
|
}
|
|
#else
|
|
|
|
if (CR_SUCCESS != CM_Get_Class_Registry_Property((LPGUID)Guid,
|
|
CM_CRP_SECURITY,
|
|
NULL,
|
|
data,
|
|
&size,
|
|
0,
|
|
NULL
|
|
)) {
|
|
//
|
|
// We cannot get security for this guy. That means that
|
|
// the key does not exist.
|
|
//
|
|
bRet = FALSE;
|
|
|
|
|
|
} else {
|
|
bRet = TRUE;
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
RegCloseKey(hKey);
|
|
return bRet;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} //CheckClassExists
|
|
|
|
BOOLEAN
|
|
DeleteClassKey (
|
|
IN LPCGUID Guid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deletes a class key (used by the temporary class test).
|
|
We thought that we can just delete the key, but it is messy
|
|
(the Properties subkey is owned by system, etc.). So by deleting
|
|
I mean setting a NULL value for a security descriptor. This seems
|
|
to work, even though it may not be the best idea... It is for testing
|
|
purposes only... If someone shows some code that does this better,
|
|
I;d be happy to borrow it.
|
|
|
|
|
|
|
|
Arguments:
|
|
|
|
Guid - the class to be deleted
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE is succesfull, FALSE if not.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
#if 0
|
|
TCHAR szSubKey[128];
|
|
TCHAR szGuid[GUID_STRING_LEN];
|
|
LONG lResult;
|
|
|
|
|
|
|
|
if (NO_ERROR != StringFromGuid(Guid, szGuid, sizeof(szGuid)/sizeof(szGuid[0]))) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("Cannot convert a GUID to a string. Why ?"));
|
|
return FALSE;
|
|
}
|
|
szSubKey[sizeof(szSubKey) / sizeof(szSubKey[0]) - 1] = 0;
|
|
_sntprintf(szSubKey,
|
|
sizeof(szSubKey)/sizeof(szSubKey[0]) - 1,
|
|
TEXT("SYSTEM\\CurrentControlSet\\Control\\Class\\%s\\Properties"),
|
|
szGuid);
|
|
|
|
//
|
|
// If we fail, we'll try it anyway, this is why I won't
|
|
// check the return value
|
|
//
|
|
if (FALSE == TakeClassKeyOwnership(Guid)) {
|
|
tlLog(g_hLog, FAIL_VARIATION,
|
|
TEXT("Failed to take class ownership, error %x"),
|
|
GetLastError());
|
|
} else {
|
|
tlLog(g_hLog,
|
|
PASS_VARIATION,
|
|
TEXT("TakeClassOwnership succeeded"));
|
|
}
|
|
|
|
lResult = RegDeleteKey(HKEY_LOCAL_MACHINE, szSubKey);
|
|
|
|
if ((ERROR_SUCCESS != lResult) && (ERROR_FILE_NOT_FOUND != lResult)) {
|
|
tlLog(g_hLog, INFO_VARIATION,
|
|
TEXT("Could not delete key %s, error %x"),
|
|
szSubKey, lResult);
|
|
return FALSE;
|
|
}
|
|
|
|
#endif
|
|
|
|
//
|
|
// Check to see if setting a NULL security value will work
|
|
//
|
|
#if 0
|
|
if (FALSE == SetupDiSetClassRegistryProperty(Guid,
|
|
SPCRP_SECURITY,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL)) {
|
|
//
|
|
// The class may not exist, so it is OK to get an error
|
|
// here
|
|
//
|
|
tlLog(g_hLog, INFO_VARIATION,
|
|
TEXT("Error 0x%x after SetClassRegistryProperty(NULL Security)"),
|
|
GetLastError());
|
|
tlLog(g_hLog, INFO_VARIATION,
|
|
TEXT("This may be OK if the class does not exist"));
|
|
}
|
|
#else
|
|
|
|
if (CR_SUCCESS != CM_Set_Class_Registry_Property((LPGUID)Guid,
|
|
CM_CRP_SECURITY,
|
|
NULL,
|
|
0,
|
|
0,
|
|
NULL
|
|
)) {
|
|
//
|
|
// The class may not exist, so it is OK to get an error
|
|
// here
|
|
//
|
|
tlLog(g_hLog, INFO_VARIATION,
|
|
TEXT("Error 0x%x after SetClassRegistryProperty(NULL Security)"),
|
|
GetLastError());
|
|
tlLog(g_hLog, INFO_VARIATION,
|
|
TEXT("This may be OK if the class does not exist"));
|
|
|
|
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
//
|
|
// Delete the other fields as well. We are not going to
|
|
// check the return value, the reason is explained in
|
|
// the comment above.
|
|
//
|
|
#if 0
|
|
SetupDiSetClassRegistryProperty(Guid, SPCRP_DEVTYPE,
|
|
NULL, 0, NULL, NULL);
|
|
SetupDiSetClassRegistryProperty(Guid, SPCRP_CHARACTERISTICS,
|
|
NULL, 0, NULL, NULL);
|
|
SetupDiSetClassRegistryProperty(Guid, SPCRP_EXCLUSIVE,
|
|
NULL, 0, NULL, NULL);
|
|
#else
|
|
CM_Set_Class_Registry_Property((LPGUID)Guid, CM_CRP_DEVTYPE,
|
|
NULL, 0, 0, NULL);
|
|
CM_Set_Class_Registry_Property((LPGUID)Guid, CM_CRP_CHARACTERISTICS,
|
|
NULL, 0, 0, NULL);
|
|
CM_Set_Class_Registry_Property((LPGUID)Guid, CM_CRP_EXCLUSIVE,
|
|
NULL, 0, 0, NULL);
|
|
|
|
#endif
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} // DeleteClass
|
|
|
|
|
|
DWORD
|
|
StringFromGuid(
|
|
IN CONST GUID *Guid,
|
|
OUT PTSTR GuidString,
|
|
IN DWORD GuidStringSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine converts a GUID into a null-terminated string which represents
|
|
it. This string is of the form:
|
|
|
|
{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}
|
|
|
|
where x represents a hexadecimal digit.
|
|
|
|
This routine comes from ole32\common\ccompapi.cxx. It is included here to avoid linking
|
|
to ole32.dll. (The RPC version allocates memory, so it was avoided as well.)
|
|
|
|
Arguments:
|
|
|
|
Guid - Supplies a pointer to the GUID whose string representation is
|
|
to be retrieved.
|
|
|
|
GuidString - Supplies a pointer to character buffer that receives the
|
|
string. This buffer must be _at least_ 39 (GUID_STRING_LEN) characters
|
|
long.
|
|
|
|
Return Value:
|
|
|
|
If success, the return value is NO_ERROR.
|
|
if failure, the return value is
|
|
|
|
--*/{
|
|
CONST BYTE *GuidBytes;
|
|
INT i;
|
|
|
|
if (GuidStringSize < GUID_STRING_LEN) {
|
|
return ERROR_INSUFFICIENT_BUFFER;
|
|
}
|
|
|
|
GuidBytes = (CONST BYTE *)Guid;
|
|
|
|
*GuidString++ = TEXT('{');
|
|
|
|
for (i = 0; i < sizeof(GuidMap); i++) {
|
|
|
|
if (GuidMap[i] == '-') {
|
|
*GuidString++ = TEXT('-');
|
|
} else {
|
|
*GuidString++ = szDigits[ (GuidBytes[GuidMap[i]] & 0xF0) >> 4 ];
|
|
*GuidString++ = szDigits[ (GuidBytes[GuidMap[i]] & 0x0F) ];
|
|
}
|
|
}
|
|
|
|
*GuidString++ = TEXT('}');
|
|
*GuidString = TEXT('\0');
|
|
|
|
return NO_ERROR;
|
|
} // StringFromGuid
|
|
|
|
BOOLEAN
|
|
SetClassSecurity (
|
|
IN LPCGUID Guid,
|
|
IN PWSTR SDDLString
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Changes the security setting of a class.
|
|
Note:
|
|
|
|
We use CM instead of SetupDi APIs because only the former
|
|
are exposed on Win2K...
|
|
|
|
Arguments:
|
|
|
|
Guid - the class whose security is to be checked
|
|
|
|
SDDLString - the SDDL string describing the new security setting
|
|
|
|
|
|
|
|
Return Value:
|
|
|
|
TRUE if we were succesfull, FALSE if not.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG ulSecDescSize;
|
|
PSECURITY_DESCRIPTOR psd = NULL;
|
|
BOOLEAN bRet = FALSE;
|
|
|
|
if (FALSE == ConvertStringSecurityDescriptorToSecurityDescriptorW(
|
|
SDDLString,
|
|
SDDL_REVISION_1,
|
|
&psd,
|
|
&ulSecDescSize)) {
|
|
|
|
tlLog(g_hLog, FAIL_VARIATION, TEXT("Cannot convert security descriptor %ws"),
|
|
SDDLString);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Try to set it (we need to use CM_Set_Class_Registry_Property on Win2k)
|
|
//
|
|
#if 0
|
|
if (FALSE == SetupDiSetClassRegistryProperty(Guid,
|
|
SPCRP_SECURITY,
|
|
psd,
|
|
ulSecDescSize,
|
|
NULL,
|
|
NULL)) {
|
|
tlLog(g_hLog, FAIL_VARIATION,
|
|
TEXT("Failed to set security for SDDL %ws, error %x"),
|
|
SDDLString, GetLastError());
|
|
|
|
|
|
|
|
|
|
} else {
|
|
bRet = TRUE;
|
|
}
|
|
#else
|
|
if (CR_SUCCESS != CM_Set_Class_Registry_Property((LPGUID)Guid,
|
|
CM_CRP_SECURITY,
|
|
psd,
|
|
ulSecDescSize,
|
|
0,
|
|
NULL)) {
|
|
tlLog(g_hLog, FAIL_VARIATION,
|
|
TEXT("Failed to set security for SDDL %ws, error %x"),
|
|
SDDLString, GetLastError());
|
|
|
|
|
|
|
|
|
|
} else {
|
|
bRet = TRUE;
|
|
}
|
|
#endif
|
|
|
|
if (psd) {
|
|
LocalFree(psd);
|
|
}
|
|
|
|
return bRet;
|
|
} // SetClassSecurity
|
|
|
|
|
|
|
|
BOOLEAN
|
|
TakeClassKeyOwnership (
|
|
IN LPCGUID Guid
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
By deafult, class keys are accessible by SYSTEM
|
|
only. In order to manipulate the various values
|
|
(Security, DeviceType, etc.) we need to take ownership
|
|
of the key. This routine assumes the user runs as an administrator
|
|
(it will grant rights to admins).
|
|
|
|
Arguments:
|
|
|
|
Guid - the class whose ownership we want to
|
|
change
|
|
|
|
Return Value:
|
|
|
|
TRUE if we were succesfull, FALSE if not.
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
HKEY hKey = 0, hSubKey = 0;
|
|
PSECURITY_DESCRIPTOR psd = NULL;
|
|
BOOLEAN bRet = TRUE;
|
|
LONG lResult;
|
|
//
|
|
// This assumes I have to right to change the access rights
|
|
// As mentioned before, that means we are admins.
|
|
//
|
|
PTSTR sddlString = TEXT("D:P(A;OICI;GA;;;SY)(A;OICI;GA;;;BA)");
|
|
|
|
//
|
|
// Open the class key
|
|
//
|
|
hKey = SetupDiOpenClassRegKeyEx(Guid,
|
|
(KEY_READ| WRITE_DAC),
|
|
DIOCR_INSTALLER,
|
|
NULL,
|
|
NULL);
|
|
|
|
if (INVALID_HANDLE_VALUE == hKey) {
|
|
tlLog(g_hLog, PASS_VARIATION,
|
|
TEXT("SetupDiOpenClassRegKey failed with error %x in TakeOwnership"),
|
|
GetLastError());
|
|
//
|
|
// Return TRUE (we haven't found the class,
|
|
// so there is nothing to take ownership of)
|
|
//
|
|
bRet = TRUE;
|
|
goto Clean0;
|
|
}
|
|
|
|
|
|
lResult = RegOpenKeyEx(hKey,
|
|
TEXT("Properties"), // subkey name
|
|
0,
|
|
KEY_READ, // security access mask
|
|
&hSubKey);
|
|
|
|
if (ERROR_SUCCESS != lResult) {
|
|
tlLog(g_hLog,
|
|
FAIL_VARIATION,
|
|
TEXT("Cannot open Properties subkey in TakeOwnership, error %x"),
|
|
lResult);
|
|
bRet = FALSE;
|
|
goto Clean0;
|
|
}
|
|
|
|
|
|
//
|
|
// Let's try to apply a security descriptor that will allow us to delete this key
|
|
// This is because by default only SYSTEM has access to this key
|
|
// We'd like to change this if possible
|
|
//
|
|
if (FALSE == ConvertStringSecurityDescriptorToSecurityDescriptor(sddlString,
|
|
SDDL_REVISION_1,
|
|
&psd,
|
|
NULL)) {
|
|
|
|
tlLog(g_hLog, FAIL_VARIATION, TEXT("Cannot convert security descriptor %ws in TakeOwnership"),
|
|
sddlString);
|
|
bRet = FALSE;
|
|
goto Clean0;
|
|
}
|
|
|
|
//
|
|
// Let's apply the SD and see what happens
|
|
//
|
|
|
|
if (ERROR_SUCCESS != RegSetKeySecurity(hSubKey,
|
|
DACL_SECURITY_INFORMATION,
|
|
psd)) {
|
|
tlLog(g_hLog, WARN_VARIATION,
|
|
TEXT("Cannot change security for the Properties key. May not be admin ?"));
|
|
bRet = FALSE;
|
|
goto Clean0;
|
|
}
|
|
|
|
|
|
Clean0:
|
|
|
|
if (hKey) {
|
|
RegCloseKey(hKey);
|
|
}
|
|
if (hSubKey) {
|
|
RegCloseKey(hSubKey);
|
|
}
|
|
|
|
if (psd) {
|
|
LocalFree(psd);
|
|
}
|
|
|
|
|
|
return bRet;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} // TakeClassKeyOwnership
|
|
|
|
|
|
VOID
|
|
GetClassOverrides (
|
|
IN LPCGUID Guid,
|
|
OUT PWST_CREATE_WITH_GUID Create
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Fills in DeviceType, Characteristics and Exclusivity from the class key.
|
|
We use this to check that there is a class override mechanism for
|
|
IoCreateDeviceSecure.
|
|
|
|
|
|
Arguments:
|
|
|
|
Guid - the class we're interested in
|
|
|
|
Create - the structure we're going to fill with our defaults
|
|
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
DWORD dwExclusivity;
|
|
ULONG size;
|
|
//
|
|
// Make sure we initialize the mask to 0
|
|
//
|
|
Create->SettingsMask = 0;
|
|
|
|
#if 0
|
|
if (TRUE == SetupDiGetClassRegistryProperty(Guid,
|
|
SPCRP_DEVTYPE,
|
|
NULL,
|
|
(PBYTE)&Create->DeviceType,
|
|
sizeof(Create->DeviceType),
|
|
NULL,
|
|
NULL,
|
|
NULL)) {
|
|
Create->SettingsMask |= SET_DEVICE_TYPE;
|
|
}
|
|
if (TRUE == SetupDiGetClassRegistryProperty(Guid,
|
|
SPCRP_CHARACTERISTICS,
|
|
NULL,
|
|
(PBYTE)&Create->Characteristics,
|
|
sizeof(Create->Characteristics),
|
|
NULL,
|
|
NULL,
|
|
NULL)) {
|
|
Create->SettingsMask |= SET_DEVICE_TYPE;
|
|
}
|
|
|
|
if (TRUE == SetupDiGetClassRegistryProperty(Guid,
|
|
SPCRP_EXCLUSIVE,
|
|
NULL,
|
|
(PBYTE)&dwExclusivity,
|
|
sizeof(DWORD),
|
|
NULL,
|
|
NULL,
|
|
NULL)) {
|
|
Create->SettingsMask |= SET_DEVICE_TYPE;
|
|
if (dwExclusivity) {
|
|
Create->Exclusivity = TRUE;
|
|
} else {
|
|
Create->Exclusivity = FALSE;
|
|
}
|
|
|
|
|
|
}
|
|
#else
|
|
|
|
size = sizeof(Create->DeviceType);
|
|
if (CR_SUCCESS == CM_Get_Class_Registry_Property((LPGUID)Guid,
|
|
CM_CRP_DEVTYPE,
|
|
NULL,
|
|
(PBYTE)&Create->DeviceType,
|
|
&size,
|
|
0,
|
|
NULL)) {
|
|
Create->SettingsMask |= SET_DEVICE_TYPE;
|
|
}
|
|
size = sizeof(Create->Characteristics);
|
|
if (CR_SUCCESS == CM_Get_Class_Registry_Property((LPGUID)Guid,
|
|
CM_CRP_CHARACTERISTICS,
|
|
NULL,
|
|
(PBYTE)&Create->Characteristics,
|
|
&size,
|
|
0,
|
|
NULL)) {
|
|
Create->SettingsMask |= SET_DEVICE_TYPE;
|
|
}
|
|
|
|
size = sizeof(DWORD);
|
|
if (TRUE == CM_Get_Class_Registry_Property((LPGUID)Guid,
|
|
CM_CRP_EXCLUSIVE,
|
|
NULL,
|
|
(PBYTE)&dwExclusivity,
|
|
&size,
|
|
0,
|
|
NULL)) {
|
|
Create->SettingsMask |= SET_DEVICE_TYPE;
|
|
if (dwExclusivity) {
|
|
Create->Exclusivity = TRUE;
|
|
} else {
|
|
Create->Exclusivity = FALSE;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
|
|
} // GetClassOverrides
|
|
|
|
|
|
BOOLEAN
|
|
SDDLUnsupportedOnWin2K (
|
|
IN PWSTR SDDL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Checks whether or not an SDDL string is supported on
|
|
Windows 2000. Currently, this means looking
|
|
for the NS, LS and AN groups
|
|
|
|
|
|
Arguments:
|
|
|
|
SDDL - the string to check for support on Win2K
|
|
|
|
Return Value:
|
|
|
|
TRUE if the SDDL string is unsupported, FALSE if it
|
|
is supported
|
|
|
|
|
|
--*/
|
|
|
|
{
|
|
PWSTR unsupportedGroups[] = {L"NS", L"LS", L"AN"};
|
|
int i;
|
|
WCHAR string[MAX_PATH];
|
|
|
|
for (i = 0; i < sizeof(unsupportedGroups)/sizeof(unsupportedGroups[0]); i++) {
|
|
swprintf(string, L";;;%ws)", unsupportedGroups[i]);
|
|
if (wcsstr(SDDL, string)) {
|
|
return TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
return FALSE;
|
|
|
|
} // SDDLUnsupportedOnWin2K
|
|
|
|
|
|
|