ReactOS  0.4.13-dev-249-gcba1a2f
priv.c
Go to the documentation of this file.
1 /*
2  * COPYRIGHT: See COPYING in the top level directory
3  * PROJECT: ReactOS system libraries
4  * FILE: lib/rtl/priv.c
5  * PURPOSE: Security related functions and Security Objects
6  * PROGRAMMER: Eric Kohl
7  * Pierre Schweitzer (pierre@reactos.org)
8  */
9 
10 /* INCLUDES *****************************************************************/
11 
12 #include <rtl.h>
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 /* FUNCTIONS ***************************************************************/
18 
19 /*
20  * @implemented
21  */
23 NTAPI
26 {
28 
30  TRUE, TokenHandle);
31  if (!NT_SUCCESS(Status))
32  {
35  }
36 
37  return Status;
38 }
39 
40 /*
41  * @implemented
42  */
44 NTAPI
46 {
47  HANDLE ProcessToken;
48  HANDLE ImpersonationToken;
50  OBJECT_ATTRIBUTES ObjAttr;
52 
54 
57  &ProcessToken);
58  if (!NT_SUCCESS(Status))
59  {
60  DPRINT1("NtOpenProcessToken() failed (Status %lx)\n", Status);
61  return Status;
62  }
63 
64  Sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
66  Sqos.ContextTrackingMode = 0;
67  Sqos.EffectiveOnly = FALSE;
68 
70  NULL,
71  0,
72  NULL,
73  NULL);
74 
75  ObjAttr.SecurityQualityOfService = &Sqos;
76 
77  Status = ZwDuplicateToken(ProcessToken,
79  &ObjAttr,
80  Sqos.EffectiveOnly, /* why both here _and_ in Sqos? */
82  &ImpersonationToken);
83  if (!NT_SUCCESS(Status))
84  {
85  DPRINT1("NtDuplicateToken() failed (Status %lx)\n", Status);
86  NtClose(ProcessToken);
87  return Status;
88  }
89 
90  Status = ZwSetInformationThread(NtCurrentThread(),
92  &ImpersonationToken,
93  sizeof(HANDLE));
94  if (!NT_SUCCESS(Status))
95  {
96  DPRINT1("NtSetInformationThread() failed (Status %lx)\n", Status);
97  }
98 
99  ZwClose(ImpersonationToken);
100  ZwClose(ProcessToken);
101 
102  return Status;
103 }
104 
105 /*
106  * @implemented
107  */
108 NTSTATUS
109 NTAPI
111  IN ULONG NumPriv,
112  IN ULONG Flags,
113  OUT PVOID *ReturnedState)
114 {
116  NTSTATUS Status, IntStatus;
117  ULONG ReturnLength, i, OldSize;
120  HANDLE ImpersonationToken = 0, ProcessToken;
121 
122  DPRINT("RtlAcquirePrivilege(%p, %u, %u, %p)\n", Privilege, NumPriv, Flags, ReturnedState);
123 
124  /* Validate flags */
126  {
128  }
129 
130  /* If user wants to acquire privileges for the process, we have to impersonate him */
132  {
134  }
135 
136  /* Allocate enough memory to hold: old privileges (fixed buffer size, might not be enough)
137  * new privileges (big enough, after old privileges memory area)
138  */
139  State = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(RTL_ACQUIRE_STATE) + sizeof(TOKEN_PRIVILEGES) +
140  (NumPriv - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES));
141  if (!State)
142  {
143  return STATUS_NO_MEMORY;
144  }
145 
146  /* Only zero a bit of the memory (will be faster that way) */
147  State->Token = 0;
148  State->OldImpersonationToken = 0;
149  State->Flags = 0;
150  State->OldPrivileges = NULL;
151 
152  /* Check whether we have already an active impersonation */
153  if (NtCurrentTeb()->IsImpersonating)
154  {
155  /* Check whether we want to impersonate */
157  {
158  /* That's all fine, just get the token.
159  * We need access for: adjust (obvious...) but also
160  * query, to be able to query old privileges
161  */
163  if (!NT_SUCCESS(Status))
164  {
165  RtlFreeHeap(RtlGetProcessHeap(), 0, State);
166  return Status;
167  }
168  }
169  else
170  {
171  /* Otherwise, we have to temporary disable active impersonation.
172  * Get previous impersonation token to save it
173  */
174  Status = RtlpOpenThreadToken(TOKEN_IMPERSONATE, &State->OldImpersonationToken);
175  if (!NT_SUCCESS(Status))
176  {
177  RtlFreeHeap(RtlGetProcessHeap(), 0, State);
178  return Status;
179  }
180 
181  /* Remember the fact we had an active impersonation */
183 
184  /* Revert impersonation (ie, give 0 as handle) */
185  Status = ZwSetInformationThread(NtCurrentThread(),
187  &ImpersonationToken,
188  sizeof(HANDLE));
189  }
190  }
191 
192  /* If we have no token yet (which is likely) */
193  if (!State->Token)
194  {
195  /* If we are asked to use process, then do */
197  {
199  &State->Token);
200  if (!NT_SUCCESS(Status))
201  {
202  goto Cleanup;
203  }
204  }
205  else
206  {
207  /* Otherwise, we have to impersonate.
208  * Open token for duplication
209  */
211 
213  NULL,
214  0,
215  NULL,
216  NULL);
217 
218  ObjectAttributes.SecurityQualityOfService = &Sqos;
219  Sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
221  Sqos.ContextTrackingMode = 1;
222  Sqos.EffectiveOnly = FALSE;
223 
224  /* Duplicate */
225  Status = ZwDuplicateToken(ProcessToken,
228  FALSE,
230  &ImpersonationToken);
231  if (!NT_SUCCESS(Status))
232  {
233  ZwClose(ProcessToken);
234  goto Cleanup;
235  }
236 
237  /* Assign our duplicated token to current thread */
238  Status = ZwSetInformationThread(NtCurrentThread(),
240  &ImpersonationToken,
241  sizeof(HANDLE));
242  if (!NT_SUCCESS(Status))
243  {
244  ZwClose(ImpersonationToken);
245  ZwClose(ProcessToken);
246  goto Cleanup;
247  }
248 
249  /* Save said token and the fact we have impersonated */
250  State->Token = ImpersonationToken;
252 
253  ZwClose(ProcessToken);
254  }
255  }
256 
257  /* Properly set the privileges pointers:
258  * OldPrivileges points to the static memory in struct (= OldPrivBuffer)
259  * NewPrivileges points to the dynamic memory after OldPrivBuffer
260  * There's NO overflow risks (OldPrivileges is always used with its size)
261  */
262  State->OldPrivileges = (PTOKEN_PRIVILEGES)State->OldPrivBuffer;
263  State->NewPrivileges = (PTOKEN_PRIVILEGES)(State->OldPrivBuffer + (sizeof(State->OldPrivBuffer) / sizeof(State->OldPrivBuffer[0])));
264 
265  /* Assign all the privileges to be acquired */
266  State->NewPrivileges->PrivilegeCount = NumPriv;
267  for (i = 0; i < NumPriv; ++i)
268  {
269  State->NewPrivileges->Privileges[i].Luid.LowPart = Privilege[i];
270  State->NewPrivileges->Privileges[i].Luid.HighPart = 0;
271  State->NewPrivileges->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED;
272  }
273 
274  /* Start privileges adjustements */
275  OldSize = sizeof(State->OldPrivBuffer);
276  do
277  {
278  ReturnLength = sizeof(State->OldPrivBuffer);
279  Status = ZwAdjustPrivilegesToken(State->Token, FALSE, State->NewPrivileges,
280  OldSize, State->OldPrivileges, &ReturnLength);
281  /* This is returned when OldPrivileges buffer is too small */
283  {
284  /* Try to allocate a new one, big enough to hold data */
285  State->OldPrivileges = RtlAllocateHeap(RtlGetProcessHeap(), 0, ReturnLength);
286  if (State->OldPrivileges)
287  {
288  DPRINT("Allocated old privileges: %p\n", State->OldPrivileges);
289  OldSize = ReturnLength;
290  continue;
291  }
292  else
293  {
294  /* If we failed, properly set status: we failed because of the lack of memory */
296  }
297  }
298 
299  /* If we failed to assign at least one privilege */
301  {
302  /* If there was actually only one privilege to acquire, use more accurate status */
303  if (NumPriv == 1)
304  {
306  }
307  }
308 
309  /* Fail if needed, otherwise return our state to caller */
310  if (!NT_SUCCESS(Status))
311  {
312  goto Cleanup;
313  }
314  else
315  {
316  *ReturnedState = State;
317  break;
318  }
319  } while (TRUE);
320 
321  DPRINT("RtlAcquirePrivilege succeed!\n");
322 
323  return Status;
324 
325 Cleanup:
326  /* If we allocated our own buffer for old privileges, release it */
327  if (State->OldPrivileges && (PVOID)State->OldPrivBuffer != (PVOID)State->OldPrivileges)
328  {
329  RtlFreeHeap(RtlGetProcessHeap(), 0, State->OldPrivileges);
330  }
331 
332  /* Do we have to restore previously active impersonation? */
334  {
335  IntStatus = ZwSetInformationThread(NtCurrentThread(), ThreadImpersonationToken,
336  &State->OldImpersonationToken, sizeof(HANDLE));
337  /* If this ever happens, we're in a really bad situation... */
338  if (!NT_SUCCESS(IntStatus))
339  {
340  RtlRaiseStatus(IntStatus);
341  }
342  }
343 
344  /* Release token */
345  if (State->Token)
346  {
347  ZwClose(State->Token);
348  }
349 
350  /* And free our state buffer */
351  RtlFreeHeap(RtlGetProcessHeap(), 0, State);
352 
353  DPRINT("RtlAcquirePrivilege() failed with status: %lx\n", Status);
354 
355  return Status;
356 }
357 
358 /*
359  * @implemented
360  */
361 VOID
362 NTAPI
364 {
367 
368  DPRINT("RtlReleasePrivilege(%p)\n", ReturnedState);
369 
370  /* If we had an active impersonation before we acquired privileges
371  * Or if we have impersonated, quit it
372  */
374  {
375  /* Restore it for the current thread */
376  Status = ZwSetInformationThread(NtCurrentThread(), ThreadImpersonationToken,
377  &State->OldImpersonationToken, sizeof(HANDLE));
378  if (!NT_SUCCESS(Status))
379  {
381  }
382 
383  /* And close the token if needed */
384  if (State->OldImpersonationToken)
385  ZwClose(State->OldImpersonationToken);
386  }
387  else
388  {
389  /* Otherwise, restore old state */
391  State->OldPrivileges, 0, NULL, NULL);
392 
393  }
394 
395  /* If we used a different buffer for old privileges, just free it */
396  if ((PVOID)State->OldPrivBuffer != (PVOID)State->OldPrivileges)
397  {
398  DPRINT("Releasing old privileges: %p\n", State->OldPrivileges);
399  RtlFreeHeap(RtlGetProcessHeap(), 0, State->OldPrivileges);
400  }
401 
402  /* Release token and free state */
403  ZwClose(State->Token);
404  RtlFreeHeap(RtlGetProcessHeap(), 0, State);
405 }
406 
407 /*
408  * @implemented
409  */
410 NTSTATUS
411 NTAPI
413  IN BOOLEAN Enable,
414  IN BOOLEAN CurrentThread,
416 {
417  TOKEN_PRIVILEGES NewState;
418  TOKEN_PRIVILEGES OldState;
422 
423  PAGED_CODE_RTL();
424 
425  DPRINT("RtlAdjustPrivilege() called\n");
426 
427  if (CurrentThread)
428  {
431  FALSE,
432  &TokenHandle);
433  }
434  else
435  {
438  &TokenHandle);
439  }
440 
441  if (!NT_SUCCESS (Status))
442  {
443  DPRINT1("Retrieving token handle failed (Status %lx)\n", Status);
444  return Status;
445  }
446 
447  OldState.PrivilegeCount = 1;
448 
449  NewState.PrivilegeCount = 1;
450  NewState.Privileges[0].Luid.LowPart = Privilege;
451  NewState.Privileges[0].Luid.HighPart = 0;
452  NewState.Privileges[0].Attributes = (Enable) ? SE_PRIVILEGE_ENABLED : 0;
453 
455  FALSE,
456  &NewState,
457  sizeof(TOKEN_PRIVILEGES),
458  &OldState,
459  &ReturnLength);
462  {
463  DPRINT1("Failed to assign all privileges\n");
465  }
466 
467  if (!NT_SUCCESS(Status))
468  {
469  DPRINT1("NtAdjustPrivilegesToken() failed (Status %lx)\n", Status);
470  return Status;
471  }
472 
473  if (OldState.PrivilegeCount == 0)
474  {
475  *Enabled = Enable;
476  }
477  else
478  {
480  }
481 
482  DPRINT("RtlAdjustPrivilege() done\n");
483 
484  return STATUS_SUCCESS;
485 }
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
IN CINT OUT PVOID IN ULONG OUT PULONG ReturnLength
Definition: dumpinfo.c:39
#define STATUS_NOT_ALL_ASSIGNED
Definition: ntstatus.h:85
#define IN
Definition: typedefs.h:38
DECLSPEC_NORETURN NTSYSAPI VOID NTAPI RtlRaiseStatus(_In_ NTSTATUS Status)
#define RTL_ACQUIRE_PRIVILEGE_PROCESS
Definition: rtltypes.h:269
#define STATUS_PRIVILEGE_NOT_HELD
Definition: DriverTester.h:9
#define TRUE
Definition: types.h:120
#define ANYSIZE_ARRAY
Definition: typedefs.h:45
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
LONG NTSTATUS
Definition: precomp.h:26
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:603
_In_ ULONGLONG _In_ ULONGLONG _In_ BOOLEAN Enable
Definition: ntddpcm.h:140
#define NtCurrentThread()
$ULONG PrivilegeCount
Definition: setypes.h:969
#define TOKEN_IMPERSONATE
Definition: setypes.h:873
#define PAGED_CODE_RTL()
Definition: rtlp.h:16
NTSTATUS NTAPI RtlAdjustPrivilege(IN ULONG Privilege, IN BOOLEAN Enable, IN BOOLEAN CurrentThread, OUT PBOOLEAN Enabled)
Definition: priv.c:412
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:64
SECURITY_CONTEXT_TRACKING_MODE ContextTrackingMode
Definition: lsa.idl:66
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
#define SE_PRIVILEGE_ENABLED
Definition: setypes.h:63
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define RTL_ACQUIRE_PRIVILEGE_IMPERSONATE
Definition: rtltypes.h:268
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
_Must_inspect_result_ NTSYSAPI NTSTATUS NTAPI ZwAdjustPrivilegesToken(_In_ HANDLE TokenHandle, _In_ BOOLEAN DisableAllPrivileges, _In_opt_ PTOKEN_PRIVILEGES NewState, _In_ ULONG BufferLength, _Out_writes_bytes_to_opt_(BufferLength, *ReturnLength) PTOKEN_PRIVILEGES PreviousState, _When_(PreviousState !=NULL, _Out_) PULONG ReturnLength)
struct _RTL_ACQUIRE_STATE * PRTL_ACQUIRE_STATE
enum _SECURITY_IMPERSONATION_LEVEL SECURITY_IMPERSONATION_LEVEL
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
void DPRINT(...)
Definition: polytest.cpp:61
_In_ ACCESS_MASK _In_ ULONG _Out_ PHANDLE TokenHandle
Definition: psfuncs.h:715
NTSTATUS NTAPI RtlAcquirePrivilege(IN PULONG Privilege, IN ULONG NumPriv, IN ULONG Flags, OUT PVOID *ReturnedState)
Definition: priv.c:110
#define NtCurrentProcess()
Definition: nt_native.h:1657
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:585
#define TOKEN_QUERY
Definition: setypes.h:874
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
DWORD LowPart
_Out_ PBOOLEAN _Out_ PBOOLEAN _Out_ PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel
Definition: psfuncs.h:154
BOOL Privilege(LPTSTR pszPrivilege, BOOL bEnable)
Definition: user_lib.cpp:531
VOID NTAPI RtlReleasePrivilege(IN PVOID ReturnedState)
Definition: priv.c:363
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3399
#define TOKEN_DUPLICATE
Definition: setypes.h:872
char * PBOOLEAN
Definition: retypes.h:11
struct _TOKEN_PRIVILEGES * PTOKEN_PRIVILEGES
LONG HighPart
PVOID *typedef PHANDLE
Definition: ntsecpkg.h:414
NTSTATUS NTAPI RtlImpersonateSelf(IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
Definition: priv.c:45
static const WCHAR Cleanup[]
Definition: register.c:80
Status
Definition: gdiplustypes.h:24
enum State_ State
Definition: pofuncs.h:54
FORCEINLINE struct _TEB * NtCurrentTeb(VOID)
Definition: psfuncs.h:420
NTSYSAPI NTSTATUS NTAPI ZwOpenProcessToken(_In_ HANDLE ProcessHandle, _In_ ACCESS_MASK DesiredAccess, _Out_ PHANDLE TokenHandle)
_In_ PIO_STACK_LOCATION _Inout_ PFILE_OBJECT _Inout_ PVCB _Outptr_result_maybenull_ PDCB _In_ PDCB _In_ PDIRENT _In_ ULONG _In_ ULONG _In_ PUNICODE_STRING _In_ PACCESS_MASK DesiredAccess
Definition: create.c:4157
#define STATUS_NO_MEMORY
Definition: ntstatus.h:246
struct _SECURITY_QUALITY_OF_SERVICE SECURITY_QUALITY_OF_SERVICE
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
Definition: lsa.idl:65
unsigned int * PULONG
Definition: retypes.h:1
LUID_AND_ATTRIBUTES Privileges[ANYSIZE_ARRAY]
Definition: setypes.h:970
#define DPRINT1
Definition: precomp.h:8
NTSTATUS NTAPI RtlpOpenThreadToken(IN ACCESS_MASK DesiredAccess, OUT PHANDLE TokenHandle)
Definition: priv.c:24
PVOID SecurityQualityOfService
Definition: umtypes.h:188
#define OUT
Definition: typedefs.h:39
unsigned int ULONG
Definition: retypes.h:1
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
return STATUS_SUCCESS
Definition: btrfs.c:2745
#define TOKEN_ADJUST_PRIVILEGES
Definition: setypes.h:876
ULONG ACCESS_MASK
Definition: nt_native.h:40
NTSYSAPI NTSTATUS NTAPI ZwOpenThreadToken(_In_ HANDLE ThreadHandle, _In_ ACCESS_MASK DesiredAccess, _In_ BOOLEAN OpenAsSelf, _Out_ PHANDLE TokenHandle)