CEF sometimes uses that during sandbox initialization.
-- v2: kernelbase/tests: Add test for DeriveCapabilitySidsFromName(). kernelbase: Implement DeriveCapabilitySidsFromName(). ntdll: Implement RtlDeriveCapabilitySidsFromName(). ntdll/tests: Add tests for RtlDeriveCapabilitySidsFromName(). ntdll: Add stub for RtlDeriveCapabilitySidsFromName().
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/ntdll.spec | 1 + dlls/ntdll/sec.c | 10 ++++++++++ include/winternl.h | 1 + 3 files changed, 12 insertions(+)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index c0d4c5eede7..784e37d45e2 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -629,6 +629,7 @@ @ stdcall RtlDeleteTimerQueueEx(ptr ptr) @ stdcall RtlDeregisterWait(ptr) @ stdcall RtlDeregisterWaitEx(ptr ptr) +@ stdcall RtlDeriveCapabilitySidsFromName(ptr ptr ptr) @ stdcall RtlDestroyAtomTable(ptr) @ stdcall RtlDestroyEnvironment(ptr) @ stdcall RtlDestroyHandleTable(ptr) diff --git a/dlls/ntdll/sec.c b/dlls/ntdll/sec.c index 2c09e31ac1a..e847d05955c 100644 --- a/dlls/ntdll/sec.c +++ b/dlls/ntdll/sec.c @@ -1866,3 +1866,13 @@ NTSTATUS WINAPI RtlDefaultNpAcl(PACL *pAcl) *pAcl = NULL; return STATUS_SUCCESS; } + +/****************************************************************************** + * RtlDeriveCapabilitySidsFromName (NTDLL.@) + */ +NTSTATUS WINAPI RtlDeriveCapabilitySidsFromName( UNICODE_STRING *cap_name, PSID cap_group_sid, PSID cap_sid ) +{ + FIXME( "cap_name %s, cap_group_sid %p, cap_sid %p.\n", debugstr_us(cap_name), cap_group_sid, cap_sid ); + + return STATUS_NOT_SUPPORTED; +} diff --git a/include/winternl.h b/include/winternl.h index 72c0933353f..4be1b8054f0 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -4845,6 +4845,7 @@ NTSYSAPI NTSTATUS WINAPI RtlDeleteTimerQueueEx(HANDLE, HANDLE); NTSYSAPI PRTL_USER_PROCESS_PARAMETERS WINAPI RtlDeNormalizeProcessParams(RTL_USER_PROCESS_PARAMETERS*); NTSYSAPI NTSTATUS WINAPI RtlDeregisterWait(HANDLE); NTSYSAPI NTSTATUS WINAPI RtlDeregisterWaitEx(HANDLE,HANDLE); +NTSYSAPI NTSTATUS WINAPI RtlDeriveCapabilitySidsFromName(UNICODE_STRING *cap_name, PSID cap_group_sid, PSID cap_sid); NTSYSAPI NTSTATUS WINAPI RtlDestroyAtomTable(RTL_ATOM_TABLE); NTSYSAPI NTSTATUS WINAPI RtlDestroyEnvironment(PWSTR); NTSYSAPI NTSTATUS WINAPI RtlDestroyHandleTable(RTL_HANDLE_TABLE *);
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/tests/rtl.c | 66 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+)
diff --git a/dlls/ntdll/tests/rtl.c b/dlls/ntdll/tests/rtl.c index ac53c8dcdcc..65c1eeab4b5 100644 --- a/dlls/ntdll/tests/rtl.c +++ b/dlls/ntdll/tests/rtl.c @@ -127,6 +127,7 @@ static VOID (WINAPI *pRtlGetDeviceFamilyInfoEnum)(ULONGLONG *,DWORD *,DWORD static void (WINAPI *pRtlRbInsertNodeEx)(RTL_RB_TREE *, RTL_BALANCED_NODE *, BOOLEAN, RTL_BALANCED_NODE *); static void (WINAPI *pRtlRbRemoveNode)(RTL_RB_TREE *, RTL_BALANCED_NODE *); static DWORD (WINAPI *pRtlConvertDeviceFamilyInfoToString)(DWORD *, DWORD *, WCHAR *, WCHAR *); +static NTSTATUS (WINAPI *pRtlDeriveCapabilitySidsFromName)(UNICODE_STRING *, PSID, PSID); static NTSTATUS (WINAPI *pRtlInitializeNtUserPfn)( const UINT64 *client_procsA, ULONG procsA_size, const UINT64 *client_procsW, ULONG procsW_size, const void *client_workers, ULONG workers_size ); @@ -193,6 +194,7 @@ static void InitFunctionPtrs(void) pLdrEnumerateLoadedModules = (void *)GetProcAddress(hntdll, "LdrEnumerateLoadedModules"); pLdrRegisterDllNotification = (void *)GetProcAddress(hntdll, "LdrRegisterDllNotification"); pLdrUnregisterDllNotification = (void *)GetProcAddress(hntdll, "LdrUnregisterDllNotification"); + pRtlDeriveCapabilitySidsFromName = (void *)GetProcAddress(hntdll, "RtlDeriveCapabilitySidsFromName"); pRtlGetDeviceFamilyInfoEnum = (void *)GetProcAddress(hntdll, "RtlGetDeviceFamilyInfoEnum"); pRtlRbInsertNodeEx = (void *)GetProcAddress(hntdll, "RtlRbInsertNodeEx"); pRtlRbRemoveNode = (void *)GetProcAddress(hntdll, "RtlRbRemoveNode"); @@ -5386,6 +5388,69 @@ static void test_RtlGetElementGenericTable(void) } }
+static void test_RtlDeriveCapabilitySidsFromName(void) +{ + static const SID_IDENTIFIER_AUTHORITY app_authority = { SECURITY_APP_PACKAGE_AUTHORITY }; + static SID_IDENTIFIER_AUTHORITY nt_authority = { SECURITY_NT_AUTHORITY }; + struct + { + const WCHAR *name; + DWORD hash[8]; + } + tests[] = + { + { NULL, { 0x42c4b0e3, 0x141cfc98, 0xc8f4fb9a, 0x24b96f99, 0xe441ae27, 0x4c939b64, 0x1b9995a4, 0x55b85278, }}, + { L"__AB", { 0xddd798eb, 0x367bd9d0, 0x1c9e610a, 0x0c43dc7e, 0xe91d8625, 0x395e7cf8, 0xe6e7c3d2, 0x2661e620 }}, + { L"__ab", { 0xddd798eb, 0x367bd9d0, 0x1c9e610a, 0x0c43dc7e, 0xe91d8625, 0x395e7cf8, 0xe6e7c3d2, 0x2661e620 }}, + { L"0123456789012345678901234567890123456789", + { 0x3c45e3e6, 0xa598e751, 0x2eb11e4c, 0x04e073fd, 0xb7c331a3, 0x07b1214d, 0xd8dee260, 0xa0966ecf }}, + }; + UNICODE_STRING cap_name; + SID *group_sid, *sid; + unsigned int i, size; + NTSTATUS status; + + if (!pRtlDeriveCapabilitySidsFromName) + { + win_skip( "RtlDeriveCapabilitySidsFromName is not available.\n" ); + return; + } + + size = RtlLengthRequiredSid( 10 ); + sid = malloc( size ); + group_sid = malloc( size ); + + for (i = 0; i < ARRAY_SIZE(tests); ++i) + { + winetest_push_context( "%s", debugstr_w(tests[i].name) ); + memset( sid, 0, size ); + memset( group_sid, 0, size ); + RtlInitUnicodeString( &cap_name, tests[i].name ); + todo_wine + { + status = pRtlDeriveCapabilitySidsFromName( &cap_name, group_sid, sid ); + ok( !status, "got %#lx.\n", status ); + + ok( sid->Revision == SID_REVISION, "got %u.\n", sid->Revision ); + ok( !memcmp( &sid->IdentifierAuthority, &app_authority, sizeof(app_authority) ), "mismatch.\n" ); + ok( sid->SubAuthorityCount == 10, "got %u.\n", sid->SubAuthorityCount ); + ok ( sid->SubAuthority[0] == SECURITY_BATCH_RID, "got %lu.\n", sid->SubAuthority[0] ); + ok ( sid->SubAuthority[1] == SECURITY_CAPABILITY_APP_RID, "got %lu.\n", sid->SubAuthority[1] ); + ok( !memcmp( sid->SubAuthority + 2, tests[i].hash, sizeof(tests[i].hash) ), "mismatch.\n" ); + + ok( group_sid->Revision == SID_REVISION, "got %u.\n", group_sid->Revision ); + ok( !memcmp( &group_sid->IdentifierAuthority, &nt_authority, sizeof(nt_authority) ), "mismatch.\n" ); + ok( group_sid->SubAuthorityCount == 9, "got %u.\n", group_sid->SubAuthorityCount ); + ok ( group_sid->SubAuthority[0] == SECURITY_BUILTIN_DOMAIN_RID, "got %lu.\n", group_sid->SubAuthority[0] ); + ok( !memcmp( group_sid->SubAuthority + 1, tests[i].hash, sizeof(tests[i].hash) ), "mismatch.\n" ); + } + winetest_pop_context(); + } + + free( sid ); + free( group_sid ); +} + START_TEST(rtl) { InitFunctionPtrs(); @@ -5454,4 +5519,5 @@ START_TEST(rtl) test_RtlEnumerateGenericTableWithoutSplaying(); test_RtlEnumerateGenericTable(); test_RtlGetElementGenericTable(); + test_RtlDeriveCapabilitySidsFromName(); }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/ntdll/sec.c | 36 ++++++++++++++++++++++++++++++++++-- dlls/ntdll/tests/rtl.c | 3 --- 2 files changed, 34 insertions(+), 5 deletions(-)
diff --git a/dlls/ntdll/sec.c b/dlls/ntdll/sec.c index e847d05955c..c1b5664cee2 100644 --- a/dlls/ntdll/sec.c +++ b/dlls/ntdll/sec.c @@ -29,7 +29,10 @@ #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" +#include "winbase.h" +#include "tomcrypt.h" #include "ntdll_misc.h" +#include "ddk/ntddk.h" #include "wine/exception.h" #include "wine/debug.h"
@@ -1872,7 +1875,36 @@ NTSTATUS WINAPI RtlDefaultNpAcl(PACL *pAcl) */ NTSTATUS WINAPI RtlDeriveCapabilitySidsFromName( UNICODE_STRING *cap_name, PSID cap_group_sid, PSID cap_sid ) { - FIXME( "cap_name %s, cap_group_sid %p, cap_sid %p.\n", debugstr_us(cap_name), cap_group_sid, cap_sid ); + static const SID_IDENTIFIER_AUTHORITY app_authority = { SECURITY_APP_PACKAGE_AUTHORITY }; + static const SID_IDENTIFIER_AUTHORITY nt_authority = { SECURITY_NT_AUTHORITY }; + UNICODE_STRING cap_upcase; + hash_state hash_ctx; + NTSTATUS status; + ULONG hash[8]; + SID *sid; + + TRACE( "cap_name %s, cap_group_sid %p, cap_sid %p.\n", debugstr_us(cap_name), cap_group_sid, cap_sid ); + + if ((status = RtlUpcaseUnicodeString( &cap_upcase, cap_name, TRUE ))) return status; + sha256_init( &hash_ctx ); + sha256_process( &hash_ctx, (UCHAR *)cap_upcase.Buffer, cap_upcase.Length ); + sha256_done( &hash_ctx, (UCHAR *)hash ); + RtlFreeUnicodeString( &cap_upcase ); + + sid = cap_sid; + sid->Revision = SID_REVISION; + sid->IdentifierAuthority = app_authority; + sid->SubAuthorityCount = 2 + ARRAY_SIZE(hash); + sid->SubAuthority[0] = SECURITY_BATCH_RID; + sid->SubAuthority[1] = SECURITY_CAPABILITY_APP_RID; + memcpy( sid->SubAuthority + 2, hash, sizeof(hash) ); + + sid = cap_group_sid; + sid->Revision = SID_REVISION; + sid->IdentifierAuthority = nt_authority; + sid->SubAuthorityCount = 1 + ARRAY_SIZE(hash); + sid->SubAuthority[0] = SECURITY_BUILTIN_DOMAIN_RID; + memcpy( sid->SubAuthority + 1, hash, sizeof(hash) );
- return STATUS_NOT_SUPPORTED; + return STATUS_SUCCESS; } diff --git a/dlls/ntdll/tests/rtl.c b/dlls/ntdll/tests/rtl.c index 65c1eeab4b5..e3f3efa5bfc 100644 --- a/dlls/ntdll/tests/rtl.c +++ b/dlls/ntdll/tests/rtl.c @@ -5426,8 +5426,6 @@ static void test_RtlDeriveCapabilitySidsFromName(void) memset( sid, 0, size ); memset( group_sid, 0, size ); RtlInitUnicodeString( &cap_name, tests[i].name ); - todo_wine - { status = pRtlDeriveCapabilitySidsFromName( &cap_name, group_sid, sid ); ok( !status, "got %#lx.\n", status );
@@ -5443,7 +5441,6 @@ static void test_RtlDeriveCapabilitySidsFromName(void) ok( group_sid->SubAuthorityCount == 9, "got %u.\n", group_sid->SubAuthorityCount ); ok ( group_sid->SubAuthority[0] == SECURITY_BUILTIN_DOMAIN_RID, "got %lu.\n", group_sid->SubAuthority[0] ); ok( !memcmp( group_sid->SubAuthority + 1, tests[i].hash, sizeof(tests[i].hash) ), "mismatch.\n" ); - } winetest_pop_context(); }
From: Paul Gofman pgofman@codeweavers.com
--- dlls/kernelbase/kernelbase.spec | 1 + dlls/kernelbase/security.c | 46 +++++++++++++++++++++++++++++++++ include/winbase.h | 1 + 3 files changed, 48 insertions(+)
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index f0a041d1de6..f522ebb3c27 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -243,6 +243,7 @@ @ stdcall CtrlRoutine(ptr) # @ stub CveEventWrite @ stdcall DeactivateActCtx(long long) +@ stdcall DeriveCapabilitySidsFromName(ptr ptr ptr ptr ptr) @ stdcall DebugActiveProcess(long) @ stdcall DebugActiveProcessStop(long) @ stdcall DebugBreak() diff --git a/dlls/kernelbase/security.c b/dlls/kernelbase/security.c index fd0eb4e561d..84cd6555075 100644 --- a/dlls/kernelbase/security.c +++ b/dlls/kernelbase/security.c @@ -1516,3 +1516,49 @@ BOOL WINAPI SetCachedSigningLevel( PHANDLE source, ULONG count, ULONG flags, HAN FIXME( "%p %lu %lu %p - stub\n", source, count, flags, file ); return TRUE; } + +/****************************************************************************** + * DeriveCapabilitySidsFromName (kernelbase.@) + */ +BOOL WINAPI DeriveCapabilitySidsFromName( const WCHAR *cap_name, PSID **cap_group_sids, DWORD *cap_group_sid_count, + PSID **cap_sids, DWORD *cap_sid_count ) +{ + NTSTATUS status = STATUS_NO_MEMORY; + UNICODE_STRING name_us; + DWORD size; + + TRACE( "cap_name %s, cap_group_sids %p, cap_group_sid_count %p, cap_sids %p, cap_sid_count %p.\n", + debugstr_w(cap_name), cap_group_sids, cap_group_sid_count, cap_sids, cap_sid_count ); + + *cap_group_sid_count = 1; + *cap_sid_count = 1; + *cap_group_sids = NULL; + *cap_sids = NULL; + + if (!(*cap_group_sids = RtlAllocateHeap( GetProcessHeap(), 0, *cap_group_sid_count * sizeof(**cap_group_sids) ))) + goto done; + if (!(*cap_sids = RtlAllocateHeap( GetProcessHeap(), 0, *cap_sid_count * sizeof(**cap_sids) ))) + goto done; + + /* There is no obvious way to query returned subauthority count for RtlDeriveCapabilitySidsFromName, + * so let's reserve a bit more. */ + size = RtlLengthRequiredSid( 16 ); + if (!(**cap_group_sids = RtlAllocateHeap( GetProcessHeap(), 0, size ))) goto done; + if (!(**cap_sids = RtlAllocateHeap( GetProcessHeap(), 0, size ))) goto done; + RtlInitUnicodeString( &name_us, cap_name ); + status = RtlDeriveCapabilitySidsFromName( &name_us, **cap_group_sids, **cap_sids ); + +done: + if (!status) return TRUE; + if (*cap_group_sids) + { + RtlFreeHeap( GetProcessHeap(), 0, **cap_group_sids ); + RtlFreeHeap( GetProcessHeap(), 0, *cap_group_sids ); + } + if (*cap_sids) + { + RtlFreeHeap( GetProcessHeap(), 0, **cap_sids ); + RtlFreeHeap( GetProcessHeap(), 0, *cap_sids ); + } + return set_ntstatus( status ); +} diff --git a/include/winbase.h b/include/winbase.h index 0d04fa09af0..40d973dd546 100644 --- a/include/winbase.h +++ b/include/winbase.h @@ -2024,6 +2024,7 @@ WINBASEAPI BOOL WINAPI DeleteVolumeMountPointW(LPCWSTR); #define DeleteVolumeMountPoint WINELIB_NAME_AW(DeleteVolumeMountPoint) WINBASEAPI BOOL WINAPI DequeueUmsCompletionListItems(void *, DWORD, PUMS_CONTEXT *); WINADVAPI BOOL WINAPI DeregisterEventSource(HANDLE); +WINADVAPI BOOL WINAPI DeriveCapabilitySidsFromName(const WCHAR *, PSID **, DWORD *, PSID **, DWORD *); WINADVAPI BOOL WINAPI DestroyPrivateObjectSecurity(PSECURITY_DESCRIPTOR*); WINBASEAPI BOOL WINAPI DeviceIoControl(HANDLE,DWORD,LPVOID,DWORD,LPVOID,DWORD,LPDWORD,LPOVERLAPPED); WINBASEAPI BOOL WINAPI DisableThreadLibraryCalls(HMODULE);
From: Paul Gofman pgofman@codeweavers.com
--- dlls/kernelbase/tests/Makefile.in | 1 + dlls/kernelbase/tests/security.c | 99 +++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 dlls/kernelbase/tests/security.c
diff --git a/dlls/kernelbase/tests/Makefile.in b/dlls/kernelbase/tests/Makefile.in index 16d3afe0dc8..5362d96cea1 100644 --- a/dlls/kernelbase/tests/Makefile.in +++ b/dlls/kernelbase/tests/Makefile.in @@ -6,4 +6,5 @@ SOURCES = \ path.c \ process.c \ rsrc.rc \ + security.c \ sync.c diff --git a/dlls/kernelbase/tests/security.c b/dlls/kernelbase/tests/security.c new file mode 100644 index 00000000000..e5f1ab93b01 --- /dev/null +++ b/dlls/kernelbase/tests/security.c @@ -0,0 +1,99 @@ +/* + * Copyright (C) 2023 Paul Gofman for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include <stdarg.h> +#include <stdlib.h> + +#include <ntstatus.h> +#define WIN32_NO_STATUS +#include <windef.h> +#include <winbase.h> +#include <winerror.h> +#include <winternl.h> + +#include "wine/test.h" + +static BOOL (WINAPI *pDeriveCapabilitySidsFromName)(const WCHAR *, PSID **, DWORD *, PSID **, DWORD *); + +static NTSTATUS (WINAPI *pRtlDeriveCapabilitySidsFromName)(UNICODE_STRING *, PSID, PSID); + +static void test_DeriveCapabilitySidsFromName(void) +{ + BYTE auth_count_sid, auth_count_group_sid; + PSID *check_group_sid, *check_sid; + DWORD sid_count, group_sid_count; + PSID *group_sids, *sids; + UNICODE_STRING name_us; + NTSTATUS status; + DWORD size; + BOOL bret; + + if (!pDeriveCapabilitySidsFromName) + { + win_skip ("DeriveCapabilitySidsFromName is not available.\n"); + return; + } + + if (0) + { + /* Crashes on Windows. */ + pDeriveCapabilitySidsFromName(L"test", NULL, &group_sid_count, NULL, &sid_count); + } + + sid_count = group_sid_count = 0xdeadbeef; + SetLastError(0xdeadbeef); + bret = pDeriveCapabilitySidsFromName(L"test", &group_sids, &group_sid_count, &sids, &sid_count); + ok(bret && GetLastError() == 0xdeadbeef, "got bret %d, err %lu.\n", bret, GetLastError()); + ok(group_sid_count == 1, "got %lu.\n", group_sid_count); + ok(sid_count == 1, "got %lu.\n", sid_count); + + auth_count_sid = *RtlSubAuthorityCountSid(sids[0]); + auth_count_group_sid = *RtlSubAuthorityCountSid(group_sids[0]); + + size = RtlLengthRequiredSid(auth_count_sid); + check_sid = malloc( size ); + size = RtlLengthRequiredSid(auth_count_group_sid); + check_group_sid = malloc( size ); + + RtlInitUnicodeString(&name_us, L"test"); + status = pRtlDeriveCapabilitySidsFromName(&name_us, check_group_sid, check_sid); + ok(!status, "failed, status %#lx.\n", status); + ok(!memcmp(sids[0], check_sid, RtlLengthRequiredSid(auth_count_sid)), "mismatch.\n"); + ok(!memcmp(group_sids[0], check_group_sid, RtlLengthRequiredSid(auth_count_group_sid)), "mismatch.\n"); + + free(check_sid); + free(check_group_sid); + + LocalFree(group_sids[0]); + LocalFree(group_sids); + LocalFree(sids[0]); + LocalFree(sids); +} + +START_TEST(security) +{ + HMODULE hmod; + + hmod = LoadLibraryA("kernelbase.dll"); + pDeriveCapabilitySidsFromName = (void *)GetProcAddress(hmod, "DeriveCapabilitySidsFromName"); + + hmod = LoadLibraryA("ntdll.dll"); + pRtlDeriveCapabilitySidsFromName = (void *)GetProcAddress(hmod, "RtlDeriveCapabilitySidsFromName"); + + test_DeriveCapabilitySidsFromName(); +}