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
RtlpOpenThreadToken(IN ACCESS_MASK DesiredAccess,OUT PHANDLE TokenHandle)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
RtlImpersonateSelf(IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)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
RtlAcquirePrivilege(IN PULONG Privilege,IN ULONG NumPriv,IN ULONG Flags,OUT PVOID * ReturnedState)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
RtlReleasePrivilege(IN PVOID ReturnedState)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 */
39046394ab8SJérôme Gardou Status = ZwAdjustPrivilegesToken(State->Token, FALSE,
391c2c66affSColin Finck State->OldPrivileges, 0, NULL, NULL);
39246394ab8SJérôme Gardou if (!NT_SUCCESS(Status))
39346394ab8SJérôme Gardou {
39446394ab8SJérôme Gardou RtlRaiseStatus(Status);
39546394ab8SJé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
RtlAdjustPrivilege(IN ULONG Privilege,IN BOOLEAN Enable,IN BOOLEAN CurrentThread,OUT PBOOLEAN Enabled)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 }
489badd9704SRatin Gao
490*49da1cdbSTimo Kreuzer #if (NTDDI_VERSION >= NTDDI_VISTA) || (DLL_EXPORT_VERSION >= _WIN32_WINNT_VISTA)
491badd9704SRatin Gao
492badd9704SRatin Gao /**
493badd9704SRatin Gao * @brief
494badd9704SRatin Gao * Removes all privileges in the specified access token.
495badd9704SRatin Gao *
496badd9704SRatin Gao * @param[in] TokenHandle
497badd9704SRatin Gao * A handle to the access token that contains the privileges to be removed.
498badd9704SRatin Gao *
499badd9704SRatin Gao * @param[in] PrivilegesToKeep
500badd9704SRatin Gao * A pointer to an array of privilege values (defined as SE_XXX_PRIVILEGE) that specify
501badd9704SRatin Gao * the privileges to keep in the token.
502badd9704SRatin Gao *
503badd9704SRatin Gao * @param[in] PrivilegeCount
504badd9704SRatin Gao * Specifies the number of entries in the PrivilegesToKeep array.
505badd9704SRatin Gao *
506badd9704SRatin Gao * @return
507badd9704SRatin Gao * Returns STATUS_SUCCESS if privileges removed successfully.
508badd9704SRatin Gao * STATUS_INVALID_PARAMETER is returned if input privilege value greater than
509badd9704SRatin Gao * SE_MAX_WELL_KNOWN_PRIVILEGE. STATUS_NOT_ALL_ASSIGNED is returned if The token does
510badd9704SRatin Gao * not have one or more of the privileges specified in the PrivilegesToKeep parameter,
511badd9704SRatin Gao * and no privileges were removed. A failure NTSTATUS code is returned otherwise.
512badd9704SRatin Gao */
513badd9704SRatin Gao NTSTATUS
514badd9704SRatin Gao NTAPI
515badd9704SRatin Gao RtlRemovePrivileges(
516badd9704SRatin Gao _In_ HANDLE TokenHandle,
517badd9704SRatin Gao _In_reads_opt_(PrivilegeCount) _When_(PrivilegeCount != 0, _Notnull_)
518badd9704SRatin Gao PULONG PrivilegesToKeep,
519badd9704SRatin Gao _In_ ULONG PrivilegeCount)
520badd9704SRatin Gao {
521badd9704SRatin Gao NTSTATUS Status;
522badd9704SRatin Gao UINT64 PrivilegesToKeepBitmap;
523badd9704SRatin Gao ULONG i, ReturnLength;
524badd9704SRatin Gao UCHAR Buffer[sizeof(TOKEN_PRIVILEGES) +
525badd9704SRatin Gao sizeof(LUID_AND_ATTRIBUTES) * (SE_MAX_WELL_KNOWN_PRIVILEGE - SE_MIN_WELL_KNOWN_PRIVILEGE)];
526badd9704SRatin Gao PTOKEN_PRIVILEGES Privileges;
527badd9704SRatin Gao
528badd9704SRatin Gao C_ASSERT(SE_MAX_WELL_KNOWN_PRIVILEGE < 64);
529badd9704SRatin Gao
530badd9704SRatin Gao DPRINT("RtlRemovePrivileges(%p, %p, %u)\n", TokenHandle, PrivilegesToKeep, PrivilegeCount);
531badd9704SRatin Gao
532badd9704SRatin Gao /* Save privileges that should be keep */
533badd9704SRatin Gao PrivilegesToKeepBitmap = 0;
534badd9704SRatin Gao if (PrivilegeCount)
535badd9704SRatin Gao {
536badd9704SRatin Gao for (i = 0; i < PrivilegeCount; i++)
537badd9704SRatin Gao {
538badd9704SRatin Gao if (PrivilegesToKeep[i] > SE_MAX_WELL_KNOWN_PRIVILEGE)
539badd9704SRatin Gao {
540badd9704SRatin Gao return STATUS_INVALID_PARAMETER;
541badd9704SRatin Gao }
542badd9704SRatin Gao PrivilegesToKeepBitmap |= (1ULL << PrivilegesToKeep[i]);
543badd9704SRatin Gao }
544badd9704SRatin Gao }
545badd9704SRatin Gao
546badd9704SRatin Gao /* Get token privileges information */
547badd9704SRatin Gao Status = ZwQueryInformationToken(TokenHandle,
548badd9704SRatin Gao TokenPrivileges,
549badd9704SRatin Gao Buffer,
550badd9704SRatin Gao sizeof(Buffer),
551badd9704SRatin Gao &ReturnLength);
552badd9704SRatin Gao if (!NT_SUCCESS(Status))
553badd9704SRatin Gao {
554badd9704SRatin Gao return Status;
555badd9704SRatin Gao }
556badd9704SRatin Gao
557badd9704SRatin Gao /* Remove all privileges that we don't need to keep */
558badd9704SRatin Gao Privileges = (PTOKEN_PRIVILEGES)Buffer;
559badd9704SRatin Gao for (i = 0; i < Privileges->PrivilegeCount; i++)
560badd9704SRatin Gao {
561badd9704SRatin Gao LARGE_INTEGER Privilege = *(LARGE_INTEGER*)&Privileges->Privileges[i].Luid;
562badd9704SRatin Gao ASSERT(Privilege.QuadPart <= SE_MAX_WELL_KNOWN_PRIVILEGE);
563badd9704SRatin Gao if (PrivilegesToKeepBitmap & (1ULL << Privilege.QuadPart))
564badd9704SRatin Gao {
565badd9704SRatin Gao PrivilegesToKeepBitmap &= ~(1ULL << Privilege.QuadPart);
566badd9704SRatin Gao }
567badd9704SRatin Gao else
568badd9704SRatin Gao {
569badd9704SRatin Gao Privileges->Privileges[i].Attributes = SE_PRIVILEGE_REMOVED;
570badd9704SRatin Gao }
571badd9704SRatin Gao }
572badd9704SRatin Gao
573badd9704SRatin Gao if (PrivilegesToKeepBitmap)
574badd9704SRatin Gao {
575badd9704SRatin Gao Status = STATUS_NOT_ALL_ASSIGNED;
576badd9704SRatin Gao }
577badd9704SRatin Gao else
578badd9704SRatin Gao {
579badd9704SRatin Gao Status = ZwAdjustPrivilegesToken(TokenHandle,
580badd9704SRatin Gao FALSE,
581badd9704SRatin Gao (PTOKEN_PRIVILEGES)Buffer,
582badd9704SRatin Gao sizeof(Buffer),
583badd9704SRatin Gao NULL,
584badd9704SRatin Gao NULL);
585badd9704SRatin Gao }
586badd9704SRatin Gao
587badd9704SRatin Gao return Status;
588badd9704SRatin Gao }
589badd9704SRatin Gao
590badd9704SRatin Gao #endif /* (NTDDI_VERSION >= NTDDI_VISTA) */
591