ReactOS  0.4.11-dev-721-g95bc44e
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 
29  Status = ZwOpenThreadToken(NtCurrentThread(), DesiredAccess,
30  TRUE, TokenHandle);
31  if (!NT_SUCCESS(Status))
32  {
33  Status = ZwOpenThreadToken(NtCurrentThread(), DesiredAccess,
34  FALSE, TokenHandle);
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 */
131  if (Flags & RTL_ACQUIRE_PRIVILEGE_PROCESS)
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  */
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 */
196  if (Flags & RTL_ACQUIRE_PRIVILEGE_PROCESS)
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  */
210  Status = ZwOpenProcessToken(NtCurrentProcess(), TOKEN_DUPLICATE, &ProcessToken);
211 
212  InitializeObjectAttributes(&ObjectAttributes,
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,
227  &ObjectAttributes,
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  */
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;
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 */
282  if (Status == STATUS_BUFFER_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 */
295  Status = STATUS_NO_MEMORY;
296  }
297  }
298 
299  /* If we failed to assign at least one privilege */
300  if (Status == STATUS_NOT_ALL_ASSIGNED)
301  {
302  /* If there was actually only one privilege to acquire, use more accurate status */
303  if (NumPriv == 1)
304  {
305  Status = STATUS_PRIVILEGE_NOT_HELD;
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  {
380  RtlRaiseStatus(Status);
381  }
382 
383  /* And close the token if needed */
384  if (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 
454  Status = ZwAdjustPrivilegesToken(TokenHandle,
455  FALSE,
456  &NewState,
457  sizeof(TOKEN_PRIVILEGES),
458  &OldState,
459  &ReturnLength);
460  ZwClose (TokenHandle);
461  if (Status == STATUS_NOT_ALL_ASSIGNED)
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  {
479  *Enabled = (OldState.Privileges[0].Attributes & SE_PRIVILEGE_ENABLED);
480  }
481 
482  DPRINT("RtlAdjustPrivilege() done\n");
483 
484  return STATUS_SUCCESS;
485 }
DWORD *typedef PVOID
Definition: winlogon.h:61
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
BOOLEAN Enable
Definition: acefiex.h:245
#define ANYSIZE_ARRAY
Definition: typedefs.h:45
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
NTSYSAPI NTSTATUS NTAPI ZwClose(_In_ HANDLE Handle)
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:603
#define NtCurrentThread()
UCHAR OldPrivBuffer[1024]
Definition: rtltypes.h:1404
$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:52
SECURITY_CONTEXT_TRACKING_MODE ContextTrackingMode
Definition: lsa.idl:66
PTOKEN_PRIVILEGES OldPrivileges
Definition: rtltypes.h:1401
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
#define SE_PRIVILEGE_ENABLED
Definition: setypes.h:63
GLenum GLclampf GLint i
Definition: glfuncs.h:14
#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
#define FALSE
Definition: types.h:117
struct _RTL_ACQUIRE_STATE * PRTL_ACQUIRE_STATE
enum _SECURITY_IMPERSONATION_LEVEL SECURITY_IMPERSONATION_LEVEL
PTOKEN_PRIVILEGES NewPrivileges
Definition: rtltypes.h:1402
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
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
#define TOKEN_QUERY
Definition: setypes.h:874
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:24
DWORD LowPart
_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)
_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:3393
#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
DWORD *typedef HANDLE
Definition: winlogon.h:61
HANDLE OldImpersonationToken
Definition: rtltypes.h:1400
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:2710
#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)