ReactOS  0.4.15-dev-5496-g599ba9c
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>
11 DBG_DEFAULT_CHANNEL(UserSecurity);
12 
13 /* FUNCTIONS *****************************************************************/
14 
26 HANDLE
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,
43  &TokenHandle);
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  */
53  if (Status == STATUS_NO_TOKEN)
54  {
55  TRACE("IntGetCurrentAccessToken(): The thread doesn't have a token, trying to open the process one...\n");
58  &TokenHandle);
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 
96 PVOID
99 {
101  PVOID Buffer = NULL;
102 
103  /* Allocate the buffer in UM memory space */
104  Status = ZwAllocateVirtualMemory(ZwCurrentProcess(),
105  &Buffer,
106  0,
107  &Length,
108  MEM_COMMIT,
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 
132 VOID
134  _In_ PVOID Buffer)
135 {
136  SIZE_T Size = 0;
137 
138  ZwFreeVirtualMemory(ZwCurrentProcess(),
139  &Buffer,
140  &Size,
141  MEM_RELEASE);
142 }
143 
168 NTSTATUS
170  _Out_ PTOKEN_USER *User)
171 {
173  PTOKEN_USER UserToken;
174  HANDLE Token;
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,
220  BufferLength,
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 
262 NTSTATUS
263 NTAPI
265  _In_ PWINSTATION_OBJECT WinSta,
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  */
280  Status = ObGetObjectSecurity(WinSta,
281  &CapturedDescriptor,
282  &MemoryAllocated);
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 
319 NTSTATUS
320 NTAPI
322  _Out_ PSECURITY_DESCRIPTOR *ServiceSd)
323 {
325  PACL ServiceDacl;
326  ULONG DaclSize;
327  ULONG RelSDSize;
328  SECURITY_DESCRIPTOR AbsSD;
329  PSECURITY_DESCRIPTOR RelSD;
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,
400  ACL_REVISION);
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,
413  ACL_REVISION,
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,
430  ACL_REVISION,
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,
445  ACL_REVISION,
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,
461  ACL_REVISION,
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 
537 Quit:
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  {
552  IntFreeSecurityBuffer(RelSD);
553  }
554  }
555 
556  return Status;
557 }
558 
559 /* EOF */
PSID SeAliasAdminsSid
Definition: setypes.h:1225
NTSTATUS NTAPI ObAssignSecurity(IN PACCESS_STATE AccessState, IN PSECURITY_DESCRIPTOR SecurityDescriptor, IN PVOID Object, IN POBJECT_TYPE Type)
Definition: obsecure.c:550
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG BufferLength
Definition: wdfdevice.h:3767
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
NTSYSAPI NTSTATUS NTAPI RtlSetGroupSecurityDescriptor(IN OUT PSECURITY_DESCRIPTOR SecurityDescriptor, IN PSID Group, IN BOOLEAN GroupDefaulted)
Definition: sd.c:410
#define _Out_
Definition: ms_sal.h:345
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
#define TRUE
Definition: types.h:120
#define ZwCurrentProcess()
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
_Out_ PSECURITY_DESCRIPTOR _Out_ PBOOLEAN MemoryAllocated
Definition: obfuncs.h:23
LONG NTSTATUS
Definition: precomp.h:26
_IRQL_requires_same_ _In_ PLSA_STRING _In_ SECURITY_LOGON_TYPE _In_ ULONG _In_ ULONG _In_opt_ PTOKEN_GROUPS _In_ PTOKEN_SOURCE _Out_ PVOID _Out_ PULONG _Inout_ PLUID _Out_ PHANDLE Token
#define DESKTOP_ENUMERATE
Definition: winuser.h:218
NTSTATUS IntQueryUserSecurityIdentification(_Out_ PTOKEN_USER *User)
Queries the authenticated user security identifier (SID) that is associated with the security context...
Definition: security.c:169
IN PVOID IN PVOID IN USHORT IN USHORT Size
Definition: pci.h:361
struct _ACCESS_ALLOWED_ACE ACCESS_ALLOWED_ACE
POBJECT_TYPE ExDesktopObjectType
Definition: win32k.c:22
NTSYSAPI NTSTATUS WINAPI RtlSetOwnerSecurityDescriptor(PSECURITY_DESCRIPTOR, PSID, BOOLEAN)
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
NTSYSAPI NTSTATUS NTAPI RtlCreateSecurityDescriptor(_Out_ PSECURITY_DESCRIPTOR SecurityDescriptor, _In_ ULONG Revision)
#define WINSTA_ENUMERATE
Definition: winuser.h:412
#define NO_PROPAGATE_INHERIT_ACE
Definition: setypes.h:748
DBG_DEFAULT_CHANNEL(UserSecurity)
NTSYSAPI NTSTATUS WINAPI RtlSetDaclSecurityDescriptor(PSECURITY_DESCRIPTOR, BOOLEAN, PACL, BOOLEAN)
#define MEM_COMMIT
Definition: nt_native.h:1313
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
NTSYSAPI NTSTATUS NTAPI RtlCreateAcl(PACL Acl, ULONG AclSize, ULONG AclRevision)
#define SECURITY_DESCRIPTOR_REVISION
Definition: setypes.h:58
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
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 FALSE
Definition: types.h:117
PSE_EXPORTS SeExports
Definition: semgr.c:21
NTSYSAPI NTSTATUS NTAPI RtlAbsoluteToSelfRelativeSD(IN PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor, IN OUT PSECURITY_DESCRIPTOR SelfRelativeSecurityDescriptor, IN PULONG BufferLength)
Definition: sd.c:626
#define DESKTOP_READOBJECTS
Definition: winuser.h:222
VOID NTAPI ObReleaseObjectSecurity(IN PSECURITY_DESCRIPTOR SecurityDescriptor, IN BOOLEAN MemoryAllocated)
Definition: obsecure.c:709
unsigned char BOOLEAN
struct _ACL ACL
#define _In_
Definition: ms_sal.h:308
_In_ ACCESS_MASK _In_ ULONG _Out_ PHANDLE TokenHandle
Definition: psfuncs.h:715
Definition: bufpool.h:45
NTSYSAPI ULONG NTAPI RtlLengthSid(IN PSID Sid)
Definition: sid.c:150
NTSTATUS NTAPI ObGetObjectSecurity(IN PVOID Object, OUT PSECURITY_DESCRIPTOR *SecurityDescriptor, OUT PBOOLEAN MemoryAllocated)
Definition: obsecure.c:611
#define ZwCurrentThread()
Status
Definition: gdiplustypes.h:24
#define TRACE(s)
Definition: solgame.cpp:4
#define TOKEN_QUERY
Definition: setypes.h:924
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define STATUS_NO_TOKEN
Definition: ntstatus.h:360
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
_In_opt_ PVOID _In_opt_ PUNICODE_STRING _In_ PSECURITY_DESCRIPTOR _In_ PACCESS_STATE AccessState
Definition: sefuncs.h:414
NTSYSAPI NTSTATUS WINAPI RtlAddAccessAllowedAceEx(PACL, DWORD, DWORD, DWORD, PSID)
#define DESKTOP_ALL_ACCESS
Definition: precomp.h:20
NTSTATUS NTAPI IntCreateServiceSecurity(_Out_ PSECURITY_DESCRIPTOR *ServiceSd)
Creates a security descriptor for the service.
Definition: security.c:321
#define ERR(fmt,...)
Definition: debug.h:110
ULONG_PTR SIZE_T
Definition: typedefs.h:80
#define WINSTA_ACCESS_ALL
Definition: security.h:57
NTSYSAPI NTSTATUS NTAPI ZwOpenProcessToken(_In_ HANDLE ProcessHandle, _In_ ACCESS_MASK DesiredAccess, _Out_ PHANDLE TokenHandle)
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
#define STATUS_NO_MEMORY
Definition: ntstatus.h:260
#define NULL
Definition: types.h:112
_Out_writes_bytes_to_opt_ AbsoluteSecurityDescriptorSize PSECURITY_DESCRIPTOR _Inout_ PULONG _Out_writes_bytes_to_opt_ DaclSize PACL _Inout_ PULONG DaclSize
Definition: rtlfuncs.h:1593
#define ACL_REVISION
Definition: setypes.h:39
#define MEM_RELEASE
Definition: nt_native.h:1316
HANDLE IntGetCurrentAccessToken(VOID)
Opens an access token that represents the effective security context of the caller....
Definition: security.c:27
unsigned int ULONG
Definition: retypes.h:1
#define INHERIT_ONLY_ACE
Definition: setypes.h:749
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DESKTOP_WRITEOBJECTS
Definition: winuser.h:224
#define OBJECT_INHERIT_ACE
Definition: setypes.h:746
NTSYSAPI NTSTATUS NTAPI ZwOpenThreadToken(_In_ HANDLE ThreadHandle, _In_ ACCESS_MASK DesiredAccess, _In_ BOOLEAN OpenAsSelf, _Out_ PHANDLE TokenHandle)
#define PAGE_READWRITE
Definition: nt_native.h:1304