2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
5 * PURPOSE: Security related functions and Security Objects
6 * PROGRAMMER: Eric Kohl
7 * Pierre Schweitzer (pierre@reactos.org)
10 /* INCLUDES *****************************************************************/
17 /* FUNCTIONS ***************************************************************/
24 RtlpOpenThreadToken(IN ACCESS_MASK DesiredAccess
,
25 OUT PHANDLE TokenHandle
)
29 Status
= ZwOpenThreadToken(NtCurrentThread(), DesiredAccess
,
31 if (!NT_SUCCESS(Status
))
33 Status
= ZwOpenThreadToken(NtCurrentThread(), DesiredAccess
,
45 RtlImpersonateSelf(IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel
)
48 HANDLE ImpersonationToken
;
50 OBJECT_ATTRIBUTES ObjAttr
;
51 SECURITY_QUALITY_OF_SERVICE Sqos
;
55 Status
= ZwOpenProcessToken(NtCurrentProcess(),
58 if (!NT_SUCCESS(Status
))
60 DPRINT1("NtOpenProcessToken() failed (Status %lx)\n", Status
);
64 Sqos
.Length
= sizeof(SECURITY_QUALITY_OF_SERVICE
);
65 Sqos
.ImpersonationLevel
= ImpersonationLevel
;
66 Sqos
.ContextTrackingMode
= 0;
67 Sqos
.EffectiveOnly
= FALSE
;
69 InitializeObjectAttributes(&ObjAttr
,
75 ObjAttr
.SecurityQualityOfService
= &Sqos
;
77 Status
= ZwDuplicateToken(ProcessToken
,
80 Sqos
.EffectiveOnly
, /* why both here _and_ in Sqos? */
83 if (!NT_SUCCESS(Status
))
85 DPRINT1("NtDuplicateToken() failed (Status %lx)\n", Status
);
86 NtClose(ProcessToken
);
90 Status
= ZwSetInformationThread(NtCurrentThread(),
91 ThreadImpersonationToken
,
94 if (!NT_SUCCESS(Status
))
96 DPRINT1("NtSetInformationThread() failed (Status %lx)\n", Status
);
99 ZwClose(ImpersonationToken
);
100 ZwClose(ProcessToken
);
110 RtlAcquirePrivilege(IN PULONG Privilege
,
113 OUT PVOID
*ReturnedState
)
115 PRTL_ACQUIRE_STATE State
;
116 NTSTATUS Status
, IntStatus
;
117 ULONG ReturnLength
, i
, OldSize
;
118 SECURITY_QUALITY_OF_SERVICE Sqos
;
119 OBJECT_ATTRIBUTES ObjectAttributes
;
120 HANDLE ImpersonationToken
= 0, ProcessToken
;
122 DPRINT("RtlAcquirePrivilege(%p, %u, %u, %p)\n", Privilege
, NumPriv
, Flags
, ReturnedState
);
125 if (Flags
& ~(RTL_ACQUIRE_PRIVILEGE_PROCESS
| RTL_ACQUIRE_PRIVILEGE_IMPERSONATE
))
127 return STATUS_INVALID_PARAMETER
;
130 /* If user wants to acquire privileges for the process, we have to impersonate him */
131 if (Flags
& RTL_ACQUIRE_PRIVILEGE_PROCESS
)
133 Flags
|= RTL_ACQUIRE_PRIVILEGE_IMPERSONATE
;
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)
139 State
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(RTL_ACQUIRE_STATE
) + sizeof(TOKEN_PRIVILEGES
) +
140 (NumPriv
- ANYSIZE_ARRAY
) * sizeof(LUID_AND_ATTRIBUTES
));
143 return STATUS_NO_MEMORY
;
146 /* Only zero a bit of the memory (will be faster that way) */
148 State
->OldImpersonationToken
= 0;
150 State
->OldPrivileges
= NULL
;
152 /* Check whether we have already an active impersonation */
153 if (NtCurrentTeb()->IsImpersonating
)
155 /* Check whether we want to impersonate */
156 if (Flags
& RTL_ACQUIRE_PRIVILEGE_IMPERSONATE
)
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
162 Status
= RtlpOpenThreadToken(TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
, &State
->Token
);
163 if (!NT_SUCCESS(Status
))
165 RtlFreeHeap(RtlGetProcessHeap(), 0, State
);
171 /* Otherwise, we have to temporary disable active impersonation.
172 * Get previous impersonation token to save it
174 Status
= RtlpOpenThreadToken(TOKEN_IMPERSONATE
, &State
->OldImpersonationToken
);
175 if (!NT_SUCCESS(Status
))
177 RtlFreeHeap(RtlGetProcessHeap(), 0, State
);
181 /* Remember the fact we had an active impersonation */
182 State
->Flags
|= RTL_ACQUIRE_PRIVILEGE_IMPERSONATE
;
184 /* Revert impersonation (ie, give 0 as handle) */
185 Status
= ZwSetInformationThread(NtCurrentThread(),
186 ThreadImpersonationToken
,
192 /* If we have no token yet (which is likely) */
195 /* If we are asked to use process, then do */
196 if (Flags
& RTL_ACQUIRE_PRIVILEGE_PROCESS
)
198 Status
= ZwOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
,
200 if (!NT_SUCCESS(Status
))
207 /* Otherwise, we have to impersonate.
208 * Open token for duplication
210 Status
= ZwOpenProcessToken(NtCurrentProcess(), TOKEN_DUPLICATE
, &ProcessToken
);
212 InitializeObjectAttributes(&ObjectAttributes
,
218 ObjectAttributes
.SecurityQualityOfService
= &Sqos
;
219 Sqos
.Length
= sizeof(SECURITY_QUALITY_OF_SERVICE
);
220 Sqos
.ImpersonationLevel
= SecurityDelegation
;
221 Sqos
.ContextTrackingMode
= 1;
222 Sqos
.EffectiveOnly
= FALSE
;
225 Status
= ZwDuplicateToken(ProcessToken
,
226 TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
| TOKEN_IMPERSONATE
,
230 &ImpersonationToken
);
231 if (!NT_SUCCESS(Status
))
233 ZwClose(ProcessToken
);
237 /* Assign our duplicated token to current thread */
238 Status
= ZwSetInformationThread(NtCurrentThread(),
239 ThreadImpersonationToken
,
242 if (!NT_SUCCESS(Status
))
244 ZwClose(ImpersonationToken
);
245 ZwClose(ProcessToken
);
249 /* Save said token and the fact we have impersonated */
250 State
->Token
= ImpersonationToken
;
251 State
->Flags
|= RTL_ACQUIRE_PRIVILEGE_IMPERSONATE
;
253 ZwClose(ProcessToken
);
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)
262 State
->OldPrivileges
= (PTOKEN_PRIVILEGES
)State
->OldPrivBuffer
;
263 State
->NewPrivileges
= (PTOKEN_PRIVILEGES
)(State
->OldPrivBuffer
+ (sizeof(State
->OldPrivBuffer
) / sizeof(State
->OldPrivBuffer
[0])));
265 /* Assign all the privileges to be acquired */
266 State
->NewPrivileges
->PrivilegeCount
= NumPriv
;
267 for (i
= 0; i
< NumPriv
; ++i
)
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
;
274 /* Start privileges adjustements */
275 OldSize
= sizeof(State
->OldPrivBuffer
);
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
)
284 /* Try to allocate a new one, big enough to hold data */
285 State
->OldPrivileges
= RtlAllocateHeap(RtlGetProcessHeap(), 0, ReturnLength
);
286 if (State
->OldPrivileges
)
288 DPRINT("Allocated old privileges: %p\n", State
->OldPrivileges
);
289 OldSize
= ReturnLength
;
294 /* If we failed, properly set status: we failed because of the lack of memory */
295 Status
= STATUS_NO_MEMORY
;
299 /* If we failed to assign at least one privilege */
300 if (Status
== STATUS_NOT_ALL_ASSIGNED
)
302 /* If there was actually only one privilege to acquire, use more accurate status */
305 Status
= STATUS_PRIVILEGE_NOT_HELD
;
309 /* Fail if needed, otherwise return our state to caller */
310 if (!NT_SUCCESS(Status
))
316 *ReturnedState
= State
;
321 DPRINT("RtlAcquirePrivilege succeed!\n");
326 /* If we allocated our own buffer for old privileges, release it */
327 if (State
->OldPrivileges
&& (PVOID
)State
->OldPrivBuffer
!= (PVOID
)State
->OldPrivileges
)
329 RtlFreeHeap(RtlGetProcessHeap(), 0, State
->OldPrivileges
);
332 /* Do we have to restore previously active impersonation? */
333 if (State
->Flags
& RTL_ACQUIRE_PRIVILEGE_IMPERSONATE
)
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
))
340 RtlRaiseStatus(IntStatus
);
347 ZwClose(State
->Token
);
350 /* And free our state buffer */
351 RtlFreeHeap(RtlGetProcessHeap(), 0, State
);
353 DPRINT("RtlAcquirePrivilege() failed with status: %lx\n", Status
);
363 RtlReleasePrivilege(IN PVOID ReturnedState
)
366 PRTL_ACQUIRE_STATE State
= (PRTL_ACQUIRE_STATE
)ReturnedState
;
368 DPRINT("RtlReleasePrivilege(%p)\n", ReturnedState
);
370 /* If we had an active impersonation before we acquired privileges
371 * Or if we have impersonated, quit it
373 if (State
->Flags
& RTL_ACQUIRE_PRIVILEGE_IMPERSONATE
)
375 /* Restore it for the current thread */
376 Status
= ZwSetInformationThread(NtCurrentThread(), ThreadImpersonationToken
,
377 &State
->OldImpersonationToken
, sizeof(HANDLE
));
378 if (!NT_SUCCESS(Status
))
380 RtlRaiseStatus(Status
);
383 /* And close the token if needed */
384 if (State
->OldImpersonationToken
)
385 ZwClose(State
->OldImpersonationToken
);
389 /* Otherwise, restore old state */
390 ZwAdjustPrivilegesToken(State
->Token
, FALSE
,
391 State
->OldPrivileges
, 0, NULL
, NULL
);
395 /* If we used a different buffer for old privileges, just free it */
396 if ((PVOID
)State
->OldPrivBuffer
!= (PVOID
)State
->OldPrivileges
)
398 DPRINT("Releasing old privileges: %p\n", State
->OldPrivileges
);
399 RtlFreeHeap(RtlGetProcessHeap(), 0, State
->OldPrivileges
);
402 /* Release token and free state */
403 ZwClose(State
->Token
);
404 RtlFreeHeap(RtlGetProcessHeap(), 0, State
);
412 RtlAdjustPrivilege(IN ULONG Privilege
,
414 IN BOOLEAN CurrentThread
,
415 OUT PBOOLEAN Enabled
)
417 TOKEN_PRIVILEGES NewState
;
418 TOKEN_PRIVILEGES OldState
;
425 DPRINT("RtlAdjustPrivilege() called\n");
429 Status
= ZwOpenThreadToken(NtCurrentThread(),
430 TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
,
436 Status
= ZwOpenProcessToken(NtCurrentProcess(),
437 TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
,
441 if (!NT_SUCCESS (Status
))
443 DPRINT1("Retrieving token handle failed (Status %lx)\n", Status
);
447 OldState
.PrivilegeCount
= 1;
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;
454 Status
= ZwAdjustPrivilegesToken(TokenHandle
,
457 sizeof(TOKEN_PRIVILEGES
),
460 ZwClose (TokenHandle
);
461 if (Status
== STATUS_NOT_ALL_ASSIGNED
)
463 DPRINT1("Failed to assign all privileges\n");
464 return STATUS_PRIVILEGE_NOT_HELD
;
467 if (!NT_SUCCESS(Status
))
469 DPRINT1("NtAdjustPrivilegesToken() failed (Status %lx)\n", Status
);
473 if (OldState
.PrivilegeCount
== 0)
479 *Enabled
= (OldState
.Privileges
[0].Attributes
& SE_PRIVILEGE_ENABLED
);
482 DPRINT("RtlAdjustPrivilege() done\n");
484 return STATUS_SUCCESS
;