ReactOS 0.4.16-dev-106-g10b08aa
security.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Win32k subsystem
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: Security infrastructure of NTUSER component of Win32k
5 * COPYRIGHT: Copyright 2022-2023 George Bișoc <george.bisoc@reactos.org>
6 */
7
8/* INCLUDES ******************************************************************/
9
10#include <win32k.h>
11DBG_DEFAULT_CHANNEL(UserSecurity);
12
13/* FUNCTIONS *****************************************************************/
14
28{
31
32 /*
33 * Try acquiring the security context by opening
34 * the current thread (or so called impersonation)
35 * token. Such token represents the effective caller.
36 * Otherwise if the current thread does not have a
37 * token (hence no impersonation occurs) then open
38 * the token of main calling process instead.
39 */
42 FALSE,
44 if (!NT_SUCCESS(Status))
45 {
46 /*
47 * We might likely fail to open the thread
48 * token if the process isn't impersonating
49 * a client. In scenarios where the server
50 * isn't impersonating, open the main process
51 * token.
52 */
54 {
55 TRACE("IntGetCurrentAccessToken(): The thread doesn't have a token, trying to open the process one...\n");
59 if (!NT_SUCCESS(Status))
60 {
61 /* We failed opening process token as well, bail out... */
62 ERR("IntGetCurrentAccessToken(): Failed to capture security context, couldn't open the process token (Status 0x%08lx)\n", Status);
63 return NULL;
64 }
65
66 /* Return the opened token handle */
67 return TokenHandle;
68 }
69
70 /* There's a thread token but we couldn't open it so bail out */
71 ERR("IntGetCurrentAccessToken(): Failed to capture security context, couldn't open the thread token (Status 0x%08lx)\n", Status);
72 return NULL;
73 }
74
75 /* Return the opened token handle */
76 return TokenHandle;
77}
78
99{
101 PVOID Buffer = NULL;
102
103 /* Allocate the buffer in UM memory space */
104 Status = ZwAllocateVirtualMemory(ZwCurrentProcess(),
105 &Buffer,
106 0,
107 &Length,
110 if (!NT_SUCCESS(Status))
111 {
112 ERR("IntAllocateSecurityBuffer(): Failed to allocate the buffer (Status 0x%08lx)\n", Status);
113 return NULL;
114 }
115
116 return Buffer;
117}
118
132VOID
135{
136 SIZE_T Size = 0;
137
138 ZwFreeVirtualMemory(ZwCurrentProcess(),
139 &Buffer,
140 &Size,
142}
143
170 _Out_ PTOKEN_USER *User)
171{
173 PTOKEN_USER UserToken = NULL;
176
177 /* Initialize the parameter */
178 *User = NULL;
179
180 /* Open the current token of the caller */
182 if (!Token)
183 {
184 ERR("IntQueryUserSecurityIdentification(): Couldn't capture the token!\n");
185 return STATUS_UNSUCCESSFUL;
186 }
187
188 /*
189 * Since we do not know what the length
190 * of the buffer size should be exactly to
191 * hold the user data, let the function
192 * tell us the size.
193 */
194 Status = ZwQueryInformationToken(Token,
195 TokenUser,
196 NULL,
197 0,
198 &BufferLength);
200 {
201 /*
202 * Allocate some memory for the buffer
203 * based on the size that the function
204 * gave us.
205 */
207 if (!UserToken)
208 {
209 /* Bail out if we failed */
210 ERR("IntQueryUserSecurityIdentification(): Couldn't allocate memory for the token user!\n");
211 ZwClose(Token);
212 return STATUS_NO_MEMORY;
213 }
214 }
215 else if (!NT_SUCCESS(Status))
216 {
217 ERR("IntQueryUserSecurityIdentification(): Failed to query the necessary length for the buffer (Status 0x%08lx)!\n", Status);
218 ZwClose(Token);
219 return Status;
220 }
221
222 /* Query the user now as we have plenty of space to hold it */
223 Status = ZwQueryInformationToken(Token,
224 TokenUser,
225 UserToken,
227 &BufferLength);
228 if (!NT_SUCCESS(Status))
229 {
230 /* We failed, bail out */
231 ERR("IntQueryUserSecurityIdentification(): Failed to query token user (Status 0x%08lx)\n", Status);
232 IntFreeSecurityBuffer(UserToken);
233 ZwClose(Token);
234 return Status;
235 }
236
237 /* All good, give the buffer to the caller and close the captured token */
238 *User = UserToken;
239 ZwClose(Token);
240
241 return STATUS_SUCCESS;
242}
243
269NTAPI
274{
276 PSECURITY_DESCRIPTOR CapturedDescriptor;
278
279 /*
280 * Capture the security descriptor from
281 * the window station. The window station
282 * in question has a descriptor that is
283 * inheritable and contains desktop access
284 * rights as well.
285 */
287 &CapturedDescriptor,
289 if (!NT_SUCCESS(Status))
290 {
291 ERR("IntAssignDesktopSecurityOnParse(): Failed to capture the security descriptor from window station (Status 0x%08lx)\n", Status);
292 return Status;
293 }
294
295 /* Assign new security to the desktop */
297 CapturedDescriptor,
298 Desktop,
300 if (!NT_SUCCESS(Status))
301 {
302 ERR("IntAssignDesktopSecurityOnParse(): Failed to assign security information to the desktop object (Status 0x%08lx)\n", Status);
303 }
304
305 /* Release the descriptor that we have captured */
306 ObReleaseObjectSecurity(CapturedDescriptor, MemoryAllocated);
307 return Status;
308}
309
326NTAPI
328 _Out_ PSECURITY_DESCRIPTOR *ServiceSd)
329{
331 PACL ServiceDacl;
333 ULONG RelSDSize;
337
338 /* Initialize our local variables */
339 RelSDSize = 0;
340 TokenUser = NULL;
341 RelSD = NULL;
342 ServiceDacl = NULL;
343
344 /* Query the logged in user of the current security context (aka token) */
346 if (!TokenUser)
347 {
348 ERR("IntCreateServiceSecurity(): Failed to query the token user (Status 0x%08lx)\n", Status);
349 return Status;
350 }
351
352 /* Initialize the absolute security descriptor */
354 if (!NT_SUCCESS(Status))
355 {
356 ERR("IntCreateServiceSecurity(): Failed to initialize absolute SD (Status 0x%08lx)\n", Status);
357 goto Quit;
358 }
359
360 /*
361 * Build up the size of access control
362 * list (the DACL) necessary to initialize
363 * our ACL. The first two entry members
364 * of ACL field are the authenticated user
365 * that is associated with the security
366 * context of the token. Then here come
367 * the last two entries which are admins.
368 * Why the ACL contains two ACEs of the
369 * same SID is because of service access
370 * rights and ACE inheritance.
371 *
372 * A service is composed of a default
373 * desktop and window station upon
374 * booting the system. On Windows connection
375 * to such service is being made if no
376 * default window station and desktop handles
377 * were created before. The desktop and winsta
378 * objects grant access on a separate type basis.
379 * The user is granted full access to the window
380 * station first and then full access to the desktop.
381 * After that admins are granted specific rights
382 * separately, just like the user. Ultimately the
383 * ACEs that handle desktop rights management are
384 * inherited to the default desktop object so
385 * that there's no need to have a separate security
386 * descriptor for the desktop object alone.
387 */
388 DaclSize = sizeof(ACL) +
389 sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(TokenUser->User.Sid) +
390 sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(TokenUser->User.Sid) +
393
394 /* Allocate memory for service DACL */
395 ServiceDacl = IntAllocateSecurityBuffer(DaclSize);
396 if (!ServiceDacl)
397 {
398 ERR("IntCreateServiceSecurity(): Failed to allocate memory for service DACL!\n");
400 goto Quit;
401 }
402
403 /* Now create the DACL */
404 Status = RtlCreateAcl(ServiceDacl,
405 DaclSize,
407 if (!NT_SUCCESS(Status))
408 {
409 ERR("IntCreateServiceSecurity(): Failed to create service DACL (Status 0x%08lx)\n", Status);
410 goto Quit;
411 }
412
413 /*
414 * The authenticated user is the ultimate and absolute
415 * king in charge of the created (or opened, whatever that is)
416 * window station object.
417 */
418 Status = RtlAddAccessAllowedAceEx(ServiceDacl,
420 0,
422 TokenUser->User.Sid);
423 if (!NT_SUCCESS(Status))
424 {
425 ERR("IntCreateServiceSecurity(): Failed to set up window station ACE for authenticated user (Status 0x%08lx)\n", Status);
426 goto Quit;
427 }
428
429 /*
430 * The authenticated user also has the ultimate power
431 * over the desktop object as well. This ACE cannot
432 * be propagated but inherited. See the comment
433 * above regarding ACL size for further explanation.
434 */
435 Status = RtlAddAccessAllowedAceEx(ServiceDacl,
439 TokenUser->User.Sid);
440 if (!NT_SUCCESS(Status))
441 {
442 ERR("IntCreateServiceSecurity(): Failed to set up desktop ACE for authenticated user (Status 0x%08lx)\n", Status);
443 goto Quit;
444 }
445
446 /*
447 * Administrators can only enumerate window
448 * stations within a desktop.
449 */
450 Status = RtlAddAccessAllowedAceEx(ServiceDacl,
452 0,
455 if (!NT_SUCCESS(Status))
456 {
457 ERR("IntCreateServiceSecurity(): Failed to set up window station ACE for admins (Status 0x%08lx)\n", Status);
458 goto Quit;
459 }
460
461 /*
462 * Administrators have some share of power over
463 * the desktop object. They can enumerate desktops,
464 * write and read upon the object itself.
465 */
466 Status = RtlAddAccessAllowedAceEx(ServiceDacl,
471 if (!NT_SUCCESS(Status))
472 {
473 ERR("IntCreateServiceSecurity(): Failed to set up desktop ACE for admins (Status 0x%08lx)\n", Status);
474 goto Quit;
475 }
476
477 /* Set the DACL to absolute SD */
479 TRUE,
480 ServiceDacl,
481 FALSE);
482 if (!NT_SUCCESS(Status))
483 {
484 ERR("IntCreateServiceSecurity(): Failed to set up service DACL to absolute SD (Status 0x%08lx)\n", Status);
485 goto Quit;
486 }
487
488 /* This descriptor is ownerless */
490 NULL,
491 FALSE);
492 if (!NT_SUCCESS(Status))
493 {
494 ERR("IntCreateServiceSecurity(): Failed to make the absolute SD as ownerless (Status 0x%08lx)\n", Status);
495 goto Quit;
496 }
497
498 /* This descriptor has no primary group */
500 NULL,
501 FALSE);
502 if (!NT_SUCCESS(Status))
503 {
504 ERR("IntCreateServiceSecurity(): Failed to make the absolute SD as having no primary group (Status 0x%08lx)\n", Status);
505 goto Quit;
506 }
507
508 /*
509 * Determine how much size is needed to allocate
510 * memory space for our relative security descriptor.
511 */
513 NULL,
514 &RelSDSize);
516 {
517 ERR("IntCreateServiceSecurity(): Unexpected status code, must be STATUS_BUFFER_TOO_SMALL (Status 0x%08lx)\n", Status);
518 goto Quit;
519 }
520
521 /* Allocate memory for this */
522 RelSD = IntAllocateSecurityBuffer(RelSDSize);
523 if (!RelSD)
524 {
525 ERR("IntCreateServiceSecurity(): Failed to allocate memory pool for relative SD!\n");
527 goto Quit;
528 }
529
530 /* Convert the absolute SD into a relative one now */
532 RelSD,
533 &RelSDSize);
534 if (!NT_SUCCESS(Status))
535 {
536 ERR("IntCreateServiceSecurity(): Failed to convert absolute SD to a relative one (Status 0x%08lx)\n", Status);
537 goto Quit;
538 }
539
540 /* All good, give the SD to the caller */
541 *ServiceSd = RelSD;
542
543Quit:
544 if (ServiceDacl)
545 {
546 IntFreeSecurityBuffer(ServiceDacl);
547 }
548
549 if (TokenUser)
550 {
552 }
553
554 if (!NT_SUCCESS(Status))
555 {
556 if (RelSD)
557 {
559 }
560 }
561
562 return Status;
563}
564
565/* EOF */
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
#define ERR(fmt,...)
Definition: precomp.h:57
#define DBG_DEFAULT_CHANNEL(ch)
Definition: debug.h:106
Definition: bufpool.h:45
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
Status
Definition: gdiplustypes.h:25
NTSYSAPI NTSTATUS WINAPI RtlAddAccessAllowedAceEx(PACL, DWORD, DWORD, DWORD, PSID)
NTSYSAPI NTSTATUS WINAPI RtlSetOwnerSecurityDescriptor(PSECURITY_DESCRIPTOR, PSID, BOOLEAN)
NTSYSAPI NTSTATUS WINAPI RtlSetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR, BOOLEAN, PACL, BOOLEAN)
#define DESKTOP_ALL_ACCESS
Definition: precomp.h:22
struct _ACL ACL
struct _ACCESS_ALLOWED_ACE ACCESS_ALLOWED_ACE
#define _Out_
Definition: ms_sal.h:345
#define _In_
Definition: ms_sal.h:308
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
_In_ ACCESS_MASK _In_ ULONG _Out_ PHANDLE TokenHandle
Definition: psfuncs.h:726
NTSYSAPI NTSTATUS NTAPI ZwOpenThreadToken(_In_ HANDLE ThreadHandle, _In_ ACCESS_MASK DesiredAccess, _In_ BOOLEAN OpenAsSelf, _Out_ PHANDLE TokenHandle)
NTSYSAPI NTSTATUS NTAPI RtlCreateAcl(PACL Acl, ULONG AclSize, ULONG AclRevision)
NTSYSAPI ULONG NTAPI RtlLengthSid(IN PSID Sid)
Definition: sid.c:150
NTSYSAPI NTSTATUS NTAPI RtlCreateSecurityDescriptor(_Out_ PSECURITY_DESCRIPTOR SecurityDescriptor, _In_ ULONG Revision)
_Out_writes_bytes_to_opt_ AbsoluteSecurityDescriptorSize PSECURITY_DESCRIPTOR _Inout_ PULONG _Out_writes_bytes_to_opt_ DaclSize PACL _Inout_ PULONG DaclSize
Definition: rtlfuncs.h:1606
#define PAGE_READWRITE
Definition: nt_native.h:1304
#define MEM_RELEASE
Definition: nt_native.h:1316
#define MEM_COMMIT
Definition: nt_native.h:1313
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
NTSYSAPI NTSTATUS NTAPI RtlSetGroupSecurityDescriptor(IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor, IN PSID Group, IN BOOLEAN GroupDefaulted)
Definition: sd.c:410
NTSYSAPI NTSTATUS NTAPI RtlAbsoluteToSelfRelativeSD(IN PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor, IN OUT PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor, IN PULONG BufferLength)
Definition: sd.c:626
#define STATUS_NO_TOKEN
Definition: ntstatus.h:360
#define STATUS_NO_MEMORY
Definition: ntstatus.h:260
NTSTATUS NTAPI ObGetObjectSecurity(IN PVOID Object, OUT PSECURITY_DESCRIPTOR *SecurityDescriptor, OUT PBOOLEAN MemoryAllocated)
Definition: obsecure.c:611
VOID NTAPI ObReleaseObjectSecurity(IN PSECURITY_DESCRIPTOR SecurityDescriptor, IN BOOLEAN MemoryAllocated)
Definition: obsecure.c:709
NTSTATUS NTAPI ObAssignSecurity(IN PACCESS_STATE AccessState, IN PSECURITY_DESCRIPTOR SecurityDescriptor, IN PVOID Object, IN POBJECT_TYPE Type)
Definition: obsecure.c:550
PSE_EXPORTS SeExports
Definition: semgr.c:21
#define STATUS_SUCCESS
Definition: shellext.h:65
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
#define TRACE(s)
Definition: solgame.cpp:4
PSID SeAliasAdminsSid
Definition: setypes.h:1229
#define NTAPI
Definition: typedefs.h:36
ULONG_PTR SIZE_T
Definition: typedefs.h:80
uint32_t ULONG
Definition: typedefs.h:59
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4533
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG BufferLength
Definition: wdfdevice.h:3771
POBJECT_TYPE ExDesktopObjectType
Definition: win32k.c:22
HANDLE IntGetCurrentAccessToken(VOID)
Opens an access token that represents the effective security context of the caller....
Definition: security.c:27
NTSTATUS NTAPI IntAssignDesktopSecurityOnParse(_In_ PWINSTATION_OBJECT WinSta, _In_ PDESKTOP Desktop, _In_ PACCESS_STATE AccessState)
Assigns a security descriptor to the desktop object during a desktop object parse procedure.
Definition: security.c:270
NTSTATUS IntQueryUserSecurityIdentification(_Out_ PTOKEN_USER *User)
Queries the authenticated user security identifier (SID) that is associated with the security context...
Definition: security.c:169
PVOID IntAllocateSecurityBuffer(_In_ SIZE_T Length)
Allocates a buffer within UM (user mode) address space area. Such buffer is reserved for security pur...
Definition: security.c:97
NTSTATUS NTAPI IntCreateServiceSecurity(_Out_ PSECURITY_DESCRIPTOR *ServiceSd)
Creates a security descriptor for the service.
Definition: security.c:327
VOID IntFreeSecurityBuffer(_In_ PVOID Buffer)
Frees an allocated security buffer from UM memory that is been previously allocated by IntAllocateSec...
Definition: security.c:133
#define WINSTA_ACCESS_ALL
Definition: security.h:57
#define DESKTOP_ENUMERATE
Definition: winuser.h:218
#define DESKTOP_WRITEOBJECTS
Definition: winuser.h:224
#define WINSTA_ENUMERATE
Definition: winuser.h:412
#define DESKTOP_READOBJECTS
Definition: winuser.h:222
_Out_ PSECURITY_DESCRIPTOR _Out_ PBOOLEAN MemoryAllocated
Definition: obfuncs.h:24
_In_opt_ PVOID _In_opt_ PUNICODE_STRING _In_ PSECURITY_DESCRIPTOR _In_ PACCESS_STATE AccessState
Definition: sefuncs.h:417
#define INHERIT_ONLY_ACE
Definition: setypes.h:749
#define TOKEN_QUERY
Definition: setypes.h:928
#define OBJECT_INHERIT_ACE
Definition: setypes.h:746
@ TokenUser
Definition: setypes.h:966
#define NO_PROPAGATE_INHERIT_ACE
Definition: setypes.h:748
#define SECURITY_DESCRIPTOR_REVISION
Definition: setypes.h:58
#define ACL_REVISION
Definition: setypes.h:39
#define ZwCurrentThread()
NTSYSAPI NTSTATUS NTAPI ZwOpenProcessToken(_In_ HANDLE ProcessHandle, _In_ ACCESS_MASK DesiredAccess, _Out_ PHANDLE TokenHandle)
#define ZwCurrentProcess()