xref: /reactos/sdk/lib/rtl/priv.c (revision 46394ab8)
1c2c66affSColin Finck /*
2c2c66affSColin Finck  * COPYRIGHT:         See COPYING in the top level directory
3c2c66affSColin Finck  * PROJECT:           ReactOS system libraries
4c2c66affSColin Finck  * FILE:              lib/rtl/priv.c
5c2c66affSColin Finck  * PURPOSE:           Security related functions and Security Objects
6c2c66affSColin Finck  * PROGRAMMER:        Eric Kohl
7c2c66affSColin Finck  *                    Pierre Schweitzer (pierre@reactos.org)
8c2c66affSColin Finck  */
9c2c66affSColin Finck 
10c2c66affSColin Finck /* INCLUDES *****************************************************************/
11c2c66affSColin Finck 
12c2c66affSColin Finck #include <rtl.h>
13c2c66affSColin Finck 
14c2c66affSColin Finck #define NDEBUG
15c2c66affSColin Finck #include <debug.h>
16c2c66affSColin Finck 
17c2c66affSColin Finck /* FUNCTIONS ***************************************************************/
18c2c66affSColin Finck 
19c2c66affSColin Finck /*
20c2c66affSColin Finck  * @implemented
21c2c66affSColin Finck  */
22c2c66affSColin Finck NTSTATUS
23c2c66affSColin Finck NTAPI
24c2c66affSColin Finck RtlpOpenThreadToken(IN ACCESS_MASK DesiredAccess,
25c2c66affSColin Finck                     OUT PHANDLE TokenHandle)
26c2c66affSColin Finck {
27c2c66affSColin Finck     NTSTATUS Status;
28c2c66affSColin Finck 
29c2c66affSColin Finck     Status = ZwOpenThreadToken(NtCurrentThread(), DesiredAccess,
30c2c66affSColin Finck                                TRUE, TokenHandle);
31c2c66affSColin Finck     if (!NT_SUCCESS(Status))
32c2c66affSColin Finck     {
33c2c66affSColin Finck         Status = ZwOpenThreadToken(NtCurrentThread(), DesiredAccess,
34c2c66affSColin Finck                                    FALSE, TokenHandle);
35c2c66affSColin Finck     }
36c2c66affSColin Finck 
37c2c66affSColin Finck     return Status;
38c2c66affSColin Finck }
39c2c66affSColin Finck 
40c2c66affSColin Finck /*
41c2c66affSColin Finck  * @implemented
42c2c66affSColin Finck  */
43c2c66affSColin Finck NTSTATUS
44c2c66affSColin Finck NTAPI
45c2c66affSColin Finck RtlImpersonateSelf(IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
46c2c66affSColin Finck {
47c2c66affSColin Finck     HANDLE ProcessToken;
48c2c66affSColin Finck     HANDLE ImpersonationToken;
49c2c66affSColin Finck     NTSTATUS Status;
50c2c66affSColin Finck     OBJECT_ATTRIBUTES ObjAttr;
51c2c66affSColin Finck     SECURITY_QUALITY_OF_SERVICE Sqos;
52c2c66affSColin Finck 
53c2c66affSColin Finck     PAGED_CODE_RTL();
54c2c66affSColin Finck 
55c2c66affSColin Finck     Status = ZwOpenProcessToken(NtCurrentProcess(),
56c2c66affSColin Finck                                 TOKEN_DUPLICATE,
57c2c66affSColin Finck                                 &ProcessToken);
58c2c66affSColin Finck     if (!NT_SUCCESS(Status))
59c2c66affSColin Finck     {
60c2c66affSColin Finck         DPRINT1("NtOpenProcessToken() failed (Status %lx)\n", Status);
61c2c66affSColin Finck         return Status;
62c2c66affSColin Finck     }
63c2c66affSColin Finck 
64c2c66affSColin Finck     Sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
65c2c66affSColin Finck     Sqos.ImpersonationLevel = ImpersonationLevel;
66c2c66affSColin Finck     Sqos.ContextTrackingMode = 0;
67c2c66affSColin Finck     Sqos.EffectiveOnly = FALSE;
68c2c66affSColin Finck 
69c2c66affSColin Finck     InitializeObjectAttributes(&ObjAttr,
70c2c66affSColin Finck                                NULL,
71c2c66affSColin Finck                                0,
72c2c66affSColin Finck                                NULL,
73c2c66affSColin Finck                                NULL);
74c2c66affSColin Finck 
75c2c66affSColin Finck     ObjAttr.SecurityQualityOfService = &Sqos;
76c2c66affSColin Finck 
77c2c66affSColin Finck     Status = ZwDuplicateToken(ProcessToken,
78c2c66affSColin Finck                               TOKEN_IMPERSONATE,
79c2c66affSColin Finck                               &ObjAttr,
80c2c66affSColin Finck                               Sqos.EffectiveOnly, /* why both here _and_ in Sqos? */
81c2c66affSColin Finck                               TokenImpersonation,
82c2c66affSColin Finck                               &ImpersonationToken);
83c2c66affSColin Finck     if (!NT_SUCCESS(Status))
84c2c66affSColin Finck     {
85c2c66affSColin Finck         DPRINT1("NtDuplicateToken() failed (Status %lx)\n", Status);
86c2c66affSColin Finck         NtClose(ProcessToken);
87c2c66affSColin Finck         return Status;
88c2c66affSColin Finck     }
89c2c66affSColin Finck 
90c2c66affSColin Finck     Status = ZwSetInformationThread(NtCurrentThread(),
91c2c66affSColin Finck                                     ThreadImpersonationToken,
92c2c66affSColin Finck                                     &ImpersonationToken,
93c2c66affSColin Finck                                     sizeof(HANDLE));
94c2c66affSColin Finck     if (!NT_SUCCESS(Status))
95c2c66affSColin Finck     {
96c2c66affSColin Finck         DPRINT1("NtSetInformationThread() failed (Status %lx)\n", Status);
97c2c66affSColin Finck     }
98c2c66affSColin Finck 
99c2c66affSColin Finck     ZwClose(ImpersonationToken);
100c2c66affSColin Finck     ZwClose(ProcessToken);
101c2c66affSColin Finck 
102c2c66affSColin Finck     return Status;
103c2c66affSColin Finck }
104c2c66affSColin Finck 
105c2c66affSColin Finck /*
106c2c66affSColin Finck  * @implemented
107c2c66affSColin Finck  */
108c2c66affSColin Finck NTSTATUS
109c2c66affSColin Finck NTAPI
110c2c66affSColin Finck RtlAcquirePrivilege(IN PULONG Privilege,
111c2c66affSColin Finck                     IN ULONG NumPriv,
112c2c66affSColin Finck                     IN ULONG Flags,
113c2c66affSColin Finck                     OUT PVOID *ReturnedState)
114c2c66affSColin Finck {
115c2c66affSColin Finck     PRTL_ACQUIRE_STATE State;
116c2c66affSColin Finck     NTSTATUS Status, IntStatus;
117c2c66affSColin Finck     ULONG ReturnLength, i, OldSize;
118c2c66affSColin Finck     SECURITY_QUALITY_OF_SERVICE Sqos;
119c2c66affSColin Finck     OBJECT_ATTRIBUTES ObjectAttributes;
120c2c66affSColin Finck     HANDLE ImpersonationToken = 0, ProcessToken;
121c2c66affSColin Finck 
122c2c66affSColin Finck     DPRINT("RtlAcquirePrivilege(%p, %u, %u, %p)\n", Privilege, NumPriv, Flags, ReturnedState);
123c2c66affSColin Finck 
124c2c66affSColin Finck     /* Validate flags */
125c2c66affSColin Finck     if (Flags & ~(RTL_ACQUIRE_PRIVILEGE_PROCESS | RTL_ACQUIRE_PRIVILEGE_IMPERSONATE))
126c2c66affSColin Finck     {
127c2c66affSColin Finck         return STATUS_INVALID_PARAMETER;
128c2c66affSColin Finck     }
129c2c66affSColin Finck 
130c2c66affSColin Finck     /* If user wants to acquire privileges for the process, we have to impersonate him */
131c2c66affSColin Finck     if (Flags & RTL_ACQUIRE_PRIVILEGE_PROCESS)
132c2c66affSColin Finck     {
133c2c66affSColin Finck         Flags |= RTL_ACQUIRE_PRIVILEGE_IMPERSONATE;
134c2c66affSColin Finck     }
135c2c66affSColin Finck 
136c2c66affSColin Finck     /* Allocate enough memory to hold: old privileges (fixed buffer size, might not be enough)
137c2c66affSColin Finck      *                                 new privileges (big enough, after old privileges memory area)
138c2c66affSColin Finck      */
139c2c66affSColin Finck     State = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(RTL_ACQUIRE_STATE) + sizeof(TOKEN_PRIVILEGES) +
140c2c66affSColin Finck                                                     (NumPriv - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES));
141c2c66affSColin Finck     if (!State)
142c2c66affSColin Finck     {
143c2c66affSColin Finck         return STATUS_NO_MEMORY;
144c2c66affSColin Finck     }
145c2c66affSColin Finck 
146c2c66affSColin Finck     /* Only zero a bit of the memory (will be faster that way) */
147c2c66affSColin Finck     State->Token = 0;
148c2c66affSColin Finck     State->OldImpersonationToken = 0;
149c2c66affSColin Finck     State->Flags = 0;
150c2c66affSColin Finck     State->OldPrivileges = NULL;
151c2c66affSColin Finck 
152c2c66affSColin Finck     /* Check whether we have already an active impersonation */
153c2c66affSColin Finck     if (NtCurrentTeb()->IsImpersonating)
154c2c66affSColin Finck     {
155c2c66affSColin Finck         /* Check whether we want to impersonate */
156c2c66affSColin Finck         if (Flags & RTL_ACQUIRE_PRIVILEGE_IMPERSONATE)
157c2c66affSColin Finck         {
158c2c66affSColin Finck             /* That's all fine, just get the token.
159c2c66affSColin Finck              * We need access for: adjust (obvious...) but also
160c2c66affSColin Finck              *                     query, to be able to query old privileges
161c2c66affSColin Finck              */
162c2c66affSColin Finck             Status = RtlpOpenThreadToken(TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &State->Token);
163c2c66affSColin Finck             if (!NT_SUCCESS(Status))
164c2c66affSColin Finck             {
165c2c66affSColin Finck                 RtlFreeHeap(RtlGetProcessHeap(), 0, State);
166c2c66affSColin Finck                 return Status;
167c2c66affSColin Finck             }
168c2c66affSColin Finck         }
169c2c66affSColin Finck         else
170c2c66affSColin Finck         {
171c2c66affSColin Finck             /* Otherwise, we have to temporary disable active impersonation.
172c2c66affSColin Finck              * Get previous impersonation token to save it
173c2c66affSColin Finck              */
174c2c66affSColin Finck             Status = RtlpOpenThreadToken(TOKEN_IMPERSONATE, &State->OldImpersonationToken);
175c2c66affSColin Finck             if (!NT_SUCCESS(Status))
176c2c66affSColin Finck             {
177c2c66affSColin Finck                 RtlFreeHeap(RtlGetProcessHeap(), 0, State);
178c2c66affSColin Finck                 return Status;
179c2c66affSColin Finck             }
180c2c66affSColin Finck 
181c2c66affSColin Finck             /* Remember the fact we had an active impersonation */
182c2c66affSColin Finck             State->Flags |= RTL_ACQUIRE_PRIVILEGE_IMPERSONATE;
183c2c66affSColin Finck 
184c2c66affSColin Finck             /* Revert impersonation (ie, give 0 as handle) */
185c2c66affSColin Finck             Status = ZwSetInformationThread(NtCurrentThread(),
186c2c66affSColin Finck                                             ThreadImpersonationToken,
187c2c66affSColin Finck                                             &ImpersonationToken,
188c2c66affSColin Finck                                             sizeof(HANDLE));
189c2c66affSColin Finck         }
190c2c66affSColin Finck     }
191c2c66affSColin Finck 
192c2c66affSColin Finck     /* If we have no token yet (which is likely) */
193c2c66affSColin Finck     if (!State->Token)
194c2c66affSColin Finck     {
195c2c66affSColin Finck         /* If we are asked to use process, then do */
196c2c66affSColin Finck         if (Flags & RTL_ACQUIRE_PRIVILEGE_PROCESS)
197c2c66affSColin Finck         {
198c2c66affSColin Finck             Status = ZwOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
199c2c66affSColin Finck                                         &State->Token);
200c2c66affSColin Finck             if (!NT_SUCCESS(Status))
201c2c66affSColin Finck             {
202c2c66affSColin Finck                 goto Cleanup;
203c2c66affSColin Finck             }
204c2c66affSColin Finck         }
205c2c66affSColin Finck         else
206c2c66affSColin Finck         {
207c2c66affSColin Finck             /* Otherwise, we have to impersonate.
208c2c66affSColin Finck              * Open token for duplication
209c2c66affSColin Finck              */
210c2c66affSColin Finck             Status = ZwOpenProcessToken(NtCurrentProcess(), TOKEN_DUPLICATE, &ProcessToken);
211c2c66affSColin Finck 
212c2c66affSColin Finck             InitializeObjectAttributes(&ObjectAttributes,
213c2c66affSColin Finck                                        NULL,
214c2c66affSColin Finck                                        0,
215c2c66affSColin Finck                                        NULL,
216c2c66affSColin Finck                                        NULL);
217c2c66affSColin Finck 
218c2c66affSColin Finck             ObjectAttributes.SecurityQualityOfService = &Sqos;
219c2c66affSColin Finck             Sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
220c2c66affSColin Finck             Sqos.ImpersonationLevel = SecurityDelegation;
221c2c66affSColin Finck             Sqos.ContextTrackingMode = 1;
222c2c66affSColin Finck             Sqos.EffectiveOnly = FALSE;
223c2c66affSColin Finck 
224c2c66affSColin Finck             /* Duplicate */
225c2c66affSColin Finck             Status = ZwDuplicateToken(ProcessToken,
226c2c66affSColin Finck                                       TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_IMPERSONATE,
227c2c66affSColin Finck                                       &ObjectAttributes,
228c2c66affSColin Finck                                       FALSE,
229c2c66affSColin Finck                                       TokenImpersonation,
230c2c66affSColin Finck                                       &ImpersonationToken);
231c2c66affSColin Finck             if (!NT_SUCCESS(Status))
232c2c66affSColin Finck             {
233c2c66affSColin Finck                 ZwClose(ProcessToken);
234c2c66affSColin Finck                 goto Cleanup;
235c2c66affSColin Finck             }
236c2c66affSColin Finck 
237c2c66affSColin Finck             /* Assign our duplicated token to current thread */
238c2c66affSColin Finck             Status = ZwSetInformationThread(NtCurrentThread(),
239c2c66affSColin Finck                                             ThreadImpersonationToken,
240c2c66affSColin Finck                                             &ImpersonationToken,
241c2c66affSColin Finck                                             sizeof(HANDLE));
242c2c66affSColin Finck             if (!NT_SUCCESS(Status))
243c2c66affSColin Finck             {
244c2c66affSColin Finck                 ZwClose(ImpersonationToken);
245c2c66affSColin Finck                 ZwClose(ProcessToken);
246c2c66affSColin Finck                 goto Cleanup;
247c2c66affSColin Finck             }
248c2c66affSColin Finck 
249c2c66affSColin Finck             /* Save said token and the fact we have impersonated */
250c2c66affSColin Finck             State->Token = ImpersonationToken;
251c2c66affSColin Finck             State->Flags |= RTL_ACQUIRE_PRIVILEGE_IMPERSONATE;
252c2c66affSColin Finck 
253c2c66affSColin Finck             ZwClose(ProcessToken);
254c2c66affSColin Finck         }
255c2c66affSColin Finck     }
256c2c66affSColin Finck 
257c2c66affSColin Finck     /* Properly set the privileges pointers:
258c2c66affSColin Finck      * OldPrivileges points to the static memory in struct (= OldPrivBuffer)
259c2c66affSColin Finck      * NewPrivileges points to the dynamic memory after OldPrivBuffer
260c2c66affSColin Finck      * There's NO overflow risks (OldPrivileges is always used with its size)
261c2c66affSColin Finck      */
262c2c66affSColin Finck     State->OldPrivileges = (PTOKEN_PRIVILEGES)State->OldPrivBuffer;
263c2c66affSColin Finck     State->NewPrivileges = (PTOKEN_PRIVILEGES)(State->OldPrivBuffer + (sizeof(State->OldPrivBuffer) / sizeof(State->OldPrivBuffer[0])));
264c2c66affSColin Finck 
265c2c66affSColin Finck     /* Assign all the privileges to be acquired */
266c2c66affSColin Finck     State->NewPrivileges->PrivilegeCount = NumPriv;
267c2c66affSColin Finck     for (i = 0; i < NumPriv; ++i)
268c2c66affSColin Finck     {
269c2c66affSColin Finck         State->NewPrivileges->Privileges[i].Luid.LowPart = Privilege[i];
270c2c66affSColin Finck         State->NewPrivileges->Privileges[i].Luid.HighPart = 0;
271c2c66affSColin Finck         State->NewPrivileges->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED;
272c2c66affSColin Finck     }
273c2c66affSColin Finck 
274c2c66affSColin Finck     /* Start privileges adjustements */
275c2c66affSColin Finck     OldSize = sizeof(State->OldPrivBuffer);
276c2c66affSColin Finck     do
277c2c66affSColin Finck     {
278c2c66affSColin Finck         ReturnLength = sizeof(State->OldPrivBuffer);
279c2c66affSColin Finck         Status = ZwAdjustPrivilegesToken(State->Token, FALSE, State->NewPrivileges,
280c2c66affSColin Finck                                          OldSize, State->OldPrivileges, &ReturnLength);
281c2c66affSColin Finck         /* This is returned when OldPrivileges buffer is too small */
282c2c66affSColin Finck         if (Status == STATUS_BUFFER_TOO_SMALL)
283c2c66affSColin Finck         {
284c2c66affSColin Finck             /* Try to allocate a new one, big enough to hold data */
285c2c66affSColin Finck             State->OldPrivileges = RtlAllocateHeap(RtlGetProcessHeap(), 0, ReturnLength);
286c2c66affSColin Finck             if (State->OldPrivileges)
287c2c66affSColin Finck             {
288c2c66affSColin Finck                 DPRINT("Allocated old privileges: %p\n", State->OldPrivileges);
289c2c66affSColin Finck                 OldSize = ReturnLength;
290c2c66affSColin Finck                 continue;
291c2c66affSColin Finck             }
292c2c66affSColin Finck             else
293c2c66affSColin Finck             {
294c2c66affSColin Finck                 /* If we failed, properly set status: we failed because of the lack of memory */
295c2c66affSColin Finck                 Status = STATUS_NO_MEMORY;
296c2c66affSColin Finck             }
297c2c66affSColin Finck         }
298c2c66affSColin Finck 
299c2c66affSColin Finck         /* If we failed to assign at least one privilege */
300c2c66affSColin Finck         if (Status == STATUS_NOT_ALL_ASSIGNED)
301c2c66affSColin Finck         {
302c2c66affSColin Finck             /* If there was actually only one privilege to acquire, use more accurate status */
303c2c66affSColin Finck             if (NumPriv == 1)
304c2c66affSColin Finck             {
305c2c66affSColin Finck                 Status = STATUS_PRIVILEGE_NOT_HELD;
306c2c66affSColin Finck             }
307c2c66affSColin Finck         }
308c2c66affSColin Finck 
309c2c66affSColin Finck         /* Fail if needed, otherwise return our state to caller */
310c2c66affSColin Finck         if (!NT_SUCCESS(Status))
311c2c66affSColin Finck         {
312c2c66affSColin Finck             goto Cleanup;
313c2c66affSColin Finck         }
314c2c66affSColin Finck         else
315c2c66affSColin Finck         {
316c2c66affSColin Finck             *ReturnedState = State;
317c2c66affSColin Finck             break;
318c2c66affSColin Finck         }
319c2c66affSColin Finck     } while (TRUE);
320c2c66affSColin Finck 
321c2c66affSColin Finck     DPRINT("RtlAcquirePrivilege succeed!\n");
322c2c66affSColin Finck 
323c2c66affSColin Finck     return Status;
324c2c66affSColin Finck 
325c2c66affSColin Finck Cleanup:
326c2c66affSColin Finck     /* If we allocated our own buffer for old privileges, release it */
327c2c66affSColin Finck     if (State->OldPrivileges && (PVOID)State->OldPrivBuffer != (PVOID)State->OldPrivileges)
328c2c66affSColin Finck     {
329c2c66affSColin Finck         RtlFreeHeap(RtlGetProcessHeap(), 0, State->OldPrivileges);
330c2c66affSColin Finck     }
331c2c66affSColin Finck 
332c2c66affSColin Finck     /* Do we have to restore previously active impersonation? */
333c2c66affSColin Finck     if (State->Flags & RTL_ACQUIRE_PRIVILEGE_IMPERSONATE)
334c2c66affSColin Finck     {
335c2c66affSColin Finck         IntStatus = ZwSetInformationThread(NtCurrentThread(), ThreadImpersonationToken,
336c2c66affSColin Finck                                            &State->OldImpersonationToken, sizeof(HANDLE));
337c2c66affSColin Finck         /* If this ever happens, we're in a really bad situation... */
338c2c66affSColin Finck         if (!NT_SUCCESS(IntStatus))
339c2c66affSColin Finck         {
340c2c66affSColin Finck             RtlRaiseStatus(IntStatus);
341c2c66affSColin Finck         }
342c2c66affSColin Finck     }
343c2c66affSColin Finck 
344c2c66affSColin Finck     /* Release token */
345c2c66affSColin Finck     if (State->Token)
346c2c66affSColin Finck     {
347c2c66affSColin Finck         ZwClose(State->Token);
348c2c66affSColin Finck     }
349c2c66affSColin Finck 
350c2c66affSColin Finck     /* And free our state buffer */
351c2c66affSColin Finck     RtlFreeHeap(RtlGetProcessHeap(), 0, State);
352c2c66affSColin Finck 
353c2c66affSColin Finck     DPRINT("RtlAcquirePrivilege() failed with status: %lx\n", Status);
354c2c66affSColin Finck 
355c2c66affSColin Finck     return Status;
356c2c66affSColin Finck }
357c2c66affSColin Finck 
358c2c66affSColin Finck /*
359c2c66affSColin Finck  * @implemented
360c2c66affSColin Finck  */
361c2c66affSColin Finck VOID
362c2c66affSColin Finck NTAPI
363c2c66affSColin Finck RtlReleasePrivilege(IN PVOID ReturnedState)
364c2c66affSColin Finck {
365c2c66affSColin Finck     NTSTATUS Status;
366c2c66affSColin Finck     PRTL_ACQUIRE_STATE State = (PRTL_ACQUIRE_STATE)ReturnedState;
367c2c66affSColin Finck 
368c2c66affSColin Finck     DPRINT("RtlReleasePrivilege(%p)\n", ReturnedState);
369c2c66affSColin Finck 
370c2c66affSColin Finck     /* If we had an active impersonation before we acquired privileges
371c2c66affSColin Finck      * Or if we have impersonated, quit it
372c2c66affSColin Finck      */
373c2c66affSColin Finck     if (State->Flags & RTL_ACQUIRE_PRIVILEGE_IMPERSONATE)
374c2c66affSColin Finck     {
375c2c66affSColin Finck         /* Restore it for the current thread */
376c2c66affSColin Finck         Status = ZwSetInformationThread(NtCurrentThread(), ThreadImpersonationToken,
377c2c66affSColin Finck                                         &State->OldImpersonationToken, sizeof(HANDLE));
378c2c66affSColin Finck         if (!NT_SUCCESS(Status))
379c2c66affSColin Finck         {
380c2c66affSColin Finck             RtlRaiseStatus(Status);
381c2c66affSColin Finck         }
382c2c66affSColin Finck 
383c2c66affSColin Finck         /* And close the token if needed */
384c2c66affSColin Finck         if (State->OldImpersonationToken)
385c2c66affSColin Finck             ZwClose(State->OldImpersonationToken);
386c2c66affSColin Finck     }
387c2c66affSColin Finck     else
388c2c66affSColin Finck     {
389c2c66affSColin Finck         /* Otherwise, restore old state */
390*46394ab8SJérôme Gardou         Status = ZwAdjustPrivilegesToken(State->Token, FALSE,
391c2c66affSColin Finck                                          State->OldPrivileges, 0, NULL, NULL);
392*46394ab8SJérôme Gardou         if (!NT_SUCCESS(Status))
393*46394ab8SJérôme Gardou         {
394*46394ab8SJérôme Gardou             RtlRaiseStatus(Status);
395*46394ab8SJérôme Gardou         }
396c2c66affSColin Finck     }
397c2c66affSColin Finck 
398c2c66affSColin Finck     /* If we used a different buffer for old privileges, just free it */
399c2c66affSColin Finck     if ((PVOID)State->OldPrivBuffer != (PVOID)State->OldPrivileges)
400c2c66affSColin Finck     {
401c2c66affSColin Finck         DPRINT("Releasing old privileges: %p\n", State->OldPrivileges);
402c2c66affSColin Finck         RtlFreeHeap(RtlGetProcessHeap(), 0, State->OldPrivileges);
403c2c66affSColin Finck     }
404c2c66affSColin Finck 
405c2c66affSColin Finck     /* Release token and free state */
406c2c66affSColin Finck     ZwClose(State->Token);
407c2c66affSColin Finck     RtlFreeHeap(RtlGetProcessHeap(), 0, State);
408c2c66affSColin Finck }
409c2c66affSColin Finck 
410c2c66affSColin Finck /*
411c2c66affSColin Finck  * @implemented
412c2c66affSColin Finck  */
413c2c66affSColin Finck NTSTATUS
414c2c66affSColin Finck NTAPI
415c2c66affSColin Finck RtlAdjustPrivilege(IN ULONG Privilege,
416c2c66affSColin Finck                    IN BOOLEAN Enable,
417c2c66affSColin Finck                    IN BOOLEAN CurrentThread,
418c2c66affSColin Finck                    OUT PBOOLEAN Enabled)
419c2c66affSColin Finck {
420c2c66affSColin Finck     TOKEN_PRIVILEGES NewState;
421c2c66affSColin Finck     TOKEN_PRIVILEGES OldState;
422c2c66affSColin Finck     ULONG ReturnLength;
423c2c66affSColin Finck     HANDLE TokenHandle;
424c2c66affSColin Finck     NTSTATUS Status;
425c2c66affSColin Finck 
426c2c66affSColin Finck     PAGED_CODE_RTL();
427c2c66affSColin Finck 
428c2c66affSColin Finck     DPRINT("RtlAdjustPrivilege() called\n");
429c2c66affSColin Finck 
430c2c66affSColin Finck     if (CurrentThread)
431c2c66affSColin Finck     {
432c2c66affSColin Finck         Status = ZwOpenThreadToken(NtCurrentThread(),
433c2c66affSColin Finck                                    TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
434c2c66affSColin Finck                                    FALSE,
435c2c66affSColin Finck                                    &TokenHandle);
436c2c66affSColin Finck     }
437c2c66affSColin Finck     else
438c2c66affSColin Finck     {
439c2c66affSColin Finck         Status = ZwOpenProcessToken(NtCurrentProcess(),
440c2c66affSColin Finck                                     TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
441c2c66affSColin Finck                                     &TokenHandle);
442c2c66affSColin Finck     }
443c2c66affSColin Finck 
444c2c66affSColin Finck     if (!NT_SUCCESS (Status))
445c2c66affSColin Finck     {
446c2c66affSColin Finck         DPRINT1("Retrieving token handle failed (Status %lx)\n", Status);
447c2c66affSColin Finck         return Status;
448c2c66affSColin Finck     }
449c2c66affSColin Finck 
450c2c66affSColin Finck     OldState.PrivilegeCount = 1;
451c2c66affSColin Finck 
452c2c66affSColin Finck     NewState.PrivilegeCount = 1;
453c2c66affSColin Finck     NewState.Privileges[0].Luid.LowPart = Privilege;
454c2c66affSColin Finck     NewState.Privileges[0].Luid.HighPart = 0;
455c2c66affSColin Finck     NewState.Privileges[0].Attributes = (Enable) ? SE_PRIVILEGE_ENABLED : 0;
456c2c66affSColin Finck 
457c2c66affSColin Finck     Status = ZwAdjustPrivilegesToken(TokenHandle,
458c2c66affSColin Finck                                      FALSE,
459c2c66affSColin Finck                                      &NewState,
460c2c66affSColin Finck                                      sizeof(TOKEN_PRIVILEGES),
461c2c66affSColin Finck                                      &OldState,
462c2c66affSColin Finck                                      &ReturnLength);
463c2c66affSColin Finck     ZwClose (TokenHandle);
464c2c66affSColin Finck     if (Status == STATUS_NOT_ALL_ASSIGNED)
465c2c66affSColin Finck     {
466c2c66affSColin Finck         DPRINT1("Failed to assign all privileges\n");
467c2c66affSColin Finck        return STATUS_PRIVILEGE_NOT_HELD;
468c2c66affSColin Finck     }
469c2c66affSColin Finck 
470c2c66affSColin Finck     if (!NT_SUCCESS(Status))
471c2c66affSColin Finck     {
472c2c66affSColin Finck         DPRINT1("NtAdjustPrivilegesToken() failed (Status %lx)\n", Status);
473c2c66affSColin Finck         return Status;
474c2c66affSColin Finck     }
475c2c66affSColin Finck 
476c2c66affSColin Finck     if (OldState.PrivilegeCount == 0)
477c2c66affSColin Finck     {
478c2c66affSColin Finck         *Enabled = Enable;
479c2c66affSColin Finck     }
480c2c66affSColin Finck     else
481c2c66affSColin Finck     {
482c2c66affSColin Finck         *Enabled = (OldState.Privileges[0].Attributes & SE_PRIVILEGE_ENABLED);
483c2c66affSColin Finck     }
484c2c66affSColin Finck 
485c2c66affSColin Finck     DPRINT("RtlAdjustPrivilege() done\n");
486c2c66affSColin Finck 
487c2c66affSColin Finck     return STATUS_SUCCESS;
488c2c66affSColin Finck }
489