ReactOS 0.4.15-dev-6042-g2eb6700
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 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;
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
216 /* Query the user now as we have plenty of space to hold it */
217 Status = ZwQueryInformationToken(Token,
218 TokenUser,
219 UserToken,
221 &BufferLength);
222 if (!NT_SUCCESS(Status))
223 {
224 /* We failed, bail out */
225 ERR("IntQueryUserSecurityIdentification(): Failed to query token user (Status 0x%08lx)\n", Status);
226 IntFreeSecurityBuffer(UserToken);
227 ZwClose(Token);
228 return Status;
229 }
230
231 /* All good, give the buffer to the caller and close the captured token */
232 *User = UserToken;
233 ZwClose(Token);
234
235 return STATUS_SUCCESS;
236}
237
263NTAPI
268{
270 PSECURITY_DESCRIPTOR CapturedDescriptor;
272
273 /*
274 * Capture the security descriptor from
275 * the window station. The window station
276 * in question has a descriptor that is
277 * inheritable and contains desktop access
278 * rights as well.
279 */
281 &CapturedDescriptor,
283 if (!NT_SUCCESS(Status))
284 {
285 ERR("IntAssignDesktopSecurityOnParse(): Failed to capture the security descriptor from window station (Status 0x%08lx)\n", Status);
286 return Status;
287 }
288
289 /* Assign new security to the desktop */
291 CapturedDescriptor,
292 Desktop,
294 if (!NT_SUCCESS(Status))
295 {
296 ERR("IntAssignDesktopSecurityOnParse(): Failed to assign security information to the desktop object (Status 0x%08lx)\n", Status);
297 }
298
299 /* Release the descriptor that we have captured */
300 ObReleaseObjectSecurity(CapturedDescriptor, MemoryAllocated);
301 return Status;
302}
303
320NTAPI
322 _Out_ PSECURITY_DESCRIPTOR *ServiceSd)
323{
325 PACL ServiceDacl;
327 ULONG RelSDSize;
331
332 /* Initialize our local variables */
333 RelSDSize = 0;
334 TokenUser = NULL;
335 RelSD = NULL;
336 ServiceDacl = NULL;
337
338 /* Query the logged in user of the current security context (aka token) */
340 if (!TokenUser)
341 {
342 ERR("IntCreateServiceSecurity(): Failed to query the token user (Status 0x%08lx)\n", Status);
343 return Status;
344 }
345
346 /* Initialize the absolute security descriptor */
348 if (!NT_SUCCESS(Status))
349 {
350 ERR("IntCreateServiceSecurity(): Failed to initialize absolute SD (Status 0x%08lx)\n", Status);
351 goto Quit;
352 }
353
354 /*
355 * Build up the size of access control
356 * list (the DACL) necessary to initialize
357 * our ACL. The first two entry members
358 * of ACL field are the authenticated user
359 * that is associated with the security
360 * context of the token. Then here come
361 * the last two entries which are admins.
362 * Why the ACL contains two ACEs of the
363 * same SID is because of service access
364 * rights and ACE inheritance.
365 *
366 * A service is composed of a default
367 * desktop and window station upon
368 * booting the system. On Windows connection
369 * to such service is being made if no
370 * default window station and desktop handles
371 * were created before. The desktop and winsta
372 * objects grant access on a separate type basis.
373 * The user is granted full access to the window
374 * station first and then full access to the desktop.
375 * After that admins are granted specific rights
376 * separately, just like the user. Ultimately the
377 * ACEs that handle desktop rights management are
378 * inherited to the default desktop object so
379 * that there's no need to have a separate security
380 * descriptor for the desktop object alone.
381 */
382 DaclSize = sizeof(ACL) +
383 sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(TokenUser->User.Sid) +
384 sizeof(ACCESS_ALLOWED_ACE) + RtlLengthSid(TokenUser->User.Sid) +
387
388 /* Allocate memory for service DACL */
389 ServiceDacl = IntAllocateSecurityBuffer(DaclSize);
390 if (!ServiceDacl)
391 {
392 ERR("IntCreateServiceSecurity(): Failed to allocate memory for service DACL!\n");
394 goto Quit;
395 }
396
397 /* Now create the DACL */
398 Status = RtlCreateAcl(ServiceDacl,
399 DaclSize,
401 if (!NT_SUCCESS(Status))
402 {
403 ERR("IntCreateServiceSecurity(): Failed to create service DACL (Status 0x%08lx)\n", Status);
404 goto Quit;
405 }
406
407 /*
408 * The authenticated user is the ultimate and absolute
409 * king in charge of the created (or opened, whatever that is)
410 * window station object.
411 */
412 Status = RtlAddAccessAllowedAceEx(ServiceDacl,
414 0,
416 TokenUser->User.Sid);
417 if (!NT_SUCCESS(Status))
418 {
419 ERR("IntCreateServiceSecurity(): Failed to set up window station ACE for authenticated user (Status 0x%08lx)\n", Status);
420 goto Quit;
421 }
422
423 /*
424 * The authenticated user also has the ultimate power
425 * over the desktop object as well. This ACE cannot
426 * be propagated but inherited. See the comment
427 * above regarding ACL size for further explanation.
428 */
429 Status = RtlAddAccessAllowedAceEx(ServiceDacl,
433 TokenUser->User.Sid);
434 if (!NT_SUCCESS(Status))
435 {
436 ERR("IntCreateServiceSecurity(): Failed to set up desktop ACE for authenticated user (Status 0x%08lx)\n", Status);
437 goto Quit;
438 }
439
440 /*
441 * Administrators can only enumerate window
442 * stations within a desktop.
443 */
444 Status = RtlAddAccessAllowedAceEx(ServiceDacl,
446 0,
449 if (!NT_SUCCESS(Status))
450 {
451 ERR("IntCreateServiceSecurity(): Failed to set up window station ACE for admins (Status 0x%08lx)\n", Status);
452 goto Quit;
453 }
454
455 /*
456 * Administrators have some share of power over
457 * the desktop object. They can enumerate desktops,
458 * write and read upon the object itself.
459 */
460 Status = RtlAddAccessAllowedAceEx(ServiceDacl,
465 if (!NT_SUCCESS(Status))
466 {
467 ERR("IntCreateServiceSecurity(): Failed to set up desktop ACE for admins (Status 0x%08lx)\n", Status);
468 goto Quit;
469 }
470
471 /* Set the DACL to absolute SD */
473 TRUE,
474 ServiceDacl,
475 FALSE);
476 if (!NT_SUCCESS(Status))
477 {
478 ERR("IntCreateServiceSecurity(): Failed to set up service DACL to absolute SD (Status 0x%08lx)\n", Status);
479 goto Quit;
480 }
481
482 /* This descriptor is ownerless */
484 NULL,
485 FALSE);
486 if (!NT_SUCCESS(Status))
487 {
488 ERR("IntCreateServiceSecurity(): Failed to make the absolute SD as ownerless (Status 0x%08lx)\n", Status);
489 goto Quit;
490 }
491
492 /* This descriptor has no primary group */
494 NULL,
495 FALSE);
496 if (!NT_SUCCESS(Status))
497 {
498 ERR("IntCreateServiceSecurity(): Failed to make the absolute SD as having no primary group (Status 0x%08lx)\n", Status);
499 goto Quit;
500 }
501
502 /*
503 * Determine how much size is needed to allocate
504 * memory space for our relative security descriptor.
505 */
507 NULL,
508 &RelSDSize);
510 {
511 ERR("IntCreateServiceSecurity(): Unexpected status code, must be STATUS_BUFFER_TOO_SMALL (Status 0x%08lx)\n", Status);
512 goto Quit;
513 }
514
515 /* Allocate memory for this */
516 RelSD = IntAllocateSecurityBuffer(RelSDSize);
517 if (!RelSD)
518 {
519 ERR("IntCreateServiceSecurity(): Failed to allocate memory pool for relative SD!\n");
521 goto Quit;
522 }
523
524 /* Convert the absolute SD into a relative one now */
526 RelSD,
527 &RelSDSize);
528 if (!NT_SUCCESS(Status))
529 {
530 ERR("IntCreateServiceSecurity(): Failed to convert absolute SD to a relative one (Status 0x%08lx)\n", Status);
531 goto Quit;
532 }
533
534 /* All good, give the SD to the caller */
535 *ServiceSd = RelSD;
536
537Quit:
538 if (ServiceDacl)
539 {
540 IntFreeSecurityBuffer(ServiceDacl);
541 }
542
543 if (TokenUser)
544 {
546 }
547
548 if (!NT_SUCCESS(Status))
549 {
550 if (RelSD)
551 {
553 }
554 }
555
556 return Status;
557}
558
559/* EOF */
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
#define ERR(fmt,...)
Definition: debug.h:110
#define DBG_DEFAULT_CHANNEL(ch)
Definition: debug.h:103
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:32
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:20
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:718
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:1594
#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:1225
#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:264
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:321
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:924
#define OBJECT_INHERIT_ACE
Definition: setypes.h:746
@ TokenUser
Definition: setypes.h:962
#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()