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
)
116 PRTL_ACQUIRE_STATE State
;
117 NTSTATUS Status
, IntStatus
;
118 ULONG ReturnLength
, i
, OldSize
;
119 SECURITY_QUALITY_OF_SERVICE Sqos
;
120 OBJECT_ATTRIBUTES ObjectAttributes
;
121 HANDLE ImpersonationToken
= 0, ProcessToken
;
123 DPRINT("RtlAcquirePrivilege(%p, %u, %u, %p)\n", Privilege
, NumPriv
, Flags
, ReturnedState
);
126 if (Flags
& ~(RTL_ACQUIRE_PRIVILEGE_PROCESS
| RTL_ACQUIRE_PRIVILEGE_IMPERSONATE
))
128 return STATUS_INVALID_PARAMETER
;
131 /* If user wants to acquire privileges for the process, we have to impersonate him */
132 if (Flags
& RTL_ACQUIRE_PRIVILEGE_PROCESS
)
134 Flags
|= RTL_ACQUIRE_PRIVILEGE_IMPERSONATE
;
137 /* Allocate enough memory to hold: old privileges (fixed buffer size, might not be enough)
138 * new privileges (big enough, after old privileges memory area)
140 State
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(RTL_ACQUIRE_STATE
) + sizeof(TOKEN_PRIVILEGES
) +
141 NumPriv
* sizeof(LUID_AND_ATTRIBUTES
));
144 return STATUS_NO_MEMORY
;
147 /* Only zero a bit of the memory (will be faster that way) */
149 State
->OldImpersonationToken
= 0;
151 State
->OldPrivileges
= NULL
;
153 /* Check whether we have already an active impersonation */
154 if (NtCurrentTeb()->IsImpersonating
)
156 /* Check whether we want to impersonate */
157 if (Flags
& RTL_ACQUIRE_PRIVILEGE_IMPERSONATE
)
159 /* That's all fine, just get the token.
160 * We need access for: adjust (obvious...) but also
161 * query, to be able to query old privileges
163 Status
= RtlpOpenThreadToken(TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
, &State
->Token
);
164 if (!NT_SUCCESS(Status
))
166 RtlFreeHeap(RtlGetProcessHeap(), 0, State
);
172 /* Otherwise, we have to temporary disable active impersonation.
173 * Get previous impersonation token to save it
175 Status
= RtlpOpenThreadToken(TOKEN_IMPERSONATE
, &State
->OldImpersonationToken
);
176 if (!NT_SUCCESS(Status
))
178 RtlFreeHeap(RtlGetProcessHeap(), 0, State
);
182 /* Remember the fact we had an active impersonation */
183 State
->Flags
|= RTL_ACQUIRE_PRIVILEGE_IMPERSONATE
;
185 /* Revert impersonation (ie, give 0 as handle) */
186 Status
= ZwSetInformationThread(NtCurrentThread(),
187 ThreadImpersonationToken
,
193 /* If we have no token yet (which is likely) */
196 /* If we are asked to use process, then do */
197 if (Flags
& RTL_ACQUIRE_PRIVILEGE_PROCESS
)
199 Status
= ZwOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
,
201 if (!NT_SUCCESS(Status
))
208 /* Otherwise, we have to impersonate.
209 * Open token for duplication
211 Status
= ZwOpenProcessToken(NtCurrentProcess(), TOKEN_DUPLICATE
, &ProcessToken
);
213 InitializeObjectAttributes(&ObjectAttributes
,
219 ObjectAttributes
.SecurityQualityOfService
= &Sqos
;
220 Sqos
.Length
= sizeof(SECURITY_QUALITY_OF_SERVICE
);
221 Sqos
.ImpersonationLevel
= SecurityDelegation
;
222 Sqos
.ContextTrackingMode
= 1;
223 Sqos
.EffectiveOnly
= FALSE
;
226 Status
= ZwDuplicateToken(ProcessToken
,
227 TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
| TOKEN_IMPERSONATE
,
231 &ImpersonationToken
);
232 if (!NT_SUCCESS(Status
))
234 ZwClose(ProcessToken
);
238 /* Assign our duplicated token to current thread */
239 Status
= ZwSetInformationThread(NtCurrentThread(),
240 ThreadImpersonationToken
,
243 if (!NT_SUCCESS(Status
))
245 ZwClose(ImpersonationToken
);
246 ZwClose(ProcessToken
);
250 /* Save said token */
251 State
->Token
= ImpersonationToken
;
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
+ 1024);
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
;
320 DPRINT("RtlAcquirePrivilege succeed!\n");
325 /* If we allocated our own buffer for old privileges, release it */
326 if (State
->OldPrivileges
&& (PVOID
)State
->OldPrivBuffer
!= (PVOID
)State
->OldPrivileges
)
328 RtlFreeHeap(RtlGetProcessHeap(), 0, State
->OldPrivileges
);
331 /* Do we have to restore previously active impersonation? */
332 if (State
->Flags
& RTL_ACQUIRE_PRIVILEGE_IMPERSONATE
)
334 IntStatus
= ZwSetInformationThread(NtCurrentThread(), ThreadImpersonationToken
,
335 &State
->OldImpersonationToken
, sizeof(HANDLE
));
336 /* If this ever happens, we're in a really bad situation... */
337 if (!NT_SUCCESS(IntStatus
))
339 RtlRaiseStatus(IntStatus
);
346 ZwClose(State
->Token
);
349 /* And free our state buffer */
350 RtlFreeHeap(RtlGetProcessHeap(), 0, State
);
352 DPRINT("RtlAcquirePrivilege() failed with status: %lx\n", Status
);
357 return STATUS_NOT_IMPLEMENTED
;
366 RtlReleasePrivilege(IN PVOID ReturnedState
)
370 PRTL_ACQUIRE_STATE State
= (PRTL_ACQUIRE_STATE
)ReturnedState
;
372 DPRINT("RtlReleasePrivilege(%p)\n", ReturnedState
);
374 /* If we had an active impersonation before we acquired privileges */
375 if (State
->Flags
& RTL_ACQUIRE_PRIVILEGE_IMPERSONATE
)
377 /* Restore it for the current thread */
378 Status
= ZwSetInformationThread(NtCurrentThread(), ThreadImpersonationToken
,
379 &State
->OldImpersonationToken
, sizeof(HANDLE
));
380 if (!NT_SUCCESS(Status
))
382 RtlRaiseStatus(Status
);
385 /* And close the token if needed */
386 if (State
->OldImpersonationToken
)
387 ZwClose(State
->OldImpersonationToken
);
391 /* Otherwise, restore old state */
392 ZwAdjustPrivilegesToken(State
->Token
, FALSE
,
393 State
->OldPrivileges
, 0, NULL
, NULL
);
397 /* If we used a different buffer for old privileges, just free it */
398 if ((PVOID
)State
->OldPrivBuffer
!= (PVOID
)State
->OldPrivileges
)
400 DPRINT("Releasing old privileges: %p\n", State
->OldPrivileges
);
401 RtlFreeHeap(RtlGetProcessHeap(), 0, State
->OldPrivileges
);
404 /* Release token and free state */
405 ZwClose(State
->Token
);
406 RtlFreeHeap(RtlGetProcessHeap(), 0, State
);
417 RtlAdjustPrivilege(IN ULONG Privilege
,
419 IN BOOLEAN CurrentThread
,
420 OUT PBOOLEAN Enabled
)
422 TOKEN_PRIVILEGES NewState
;
423 TOKEN_PRIVILEGES OldState
;
430 DPRINT("RtlAdjustPrivilege() called\n");
434 Status
= ZwOpenThreadToken(NtCurrentThread(),
435 TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
,
441 Status
= ZwOpenProcessToken(NtCurrentProcess(),
442 TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
,
446 if (!NT_SUCCESS (Status
))
448 DPRINT1("Retrieving token handle failed (Status %lx)\n", Status
);
452 OldState
.PrivilegeCount
= 1;
454 NewState
.PrivilegeCount
= 1;
455 NewState
.Privileges
[0].Luid
.LowPart
= Privilege
;
456 NewState
.Privileges
[0].Luid
.HighPart
= 0;
457 NewState
.Privileges
[0].Attributes
= (Enable
) ? SE_PRIVILEGE_ENABLED
: 0;
459 Status
= ZwAdjustPrivilegesToken(TokenHandle
,
462 sizeof(TOKEN_PRIVILEGES
),
465 ZwClose (TokenHandle
);
466 if (Status
== STATUS_NOT_ALL_ASSIGNED
)
468 DPRINT1("Failed to assign all privileges\n");
469 return STATUS_PRIVILEGE_NOT_HELD
;
472 if (!NT_SUCCESS(Status
))
474 DPRINT1("NtAdjustPrivilegesToken() failed (Status %lx)\n", Status
);
478 if (OldState
.PrivilegeCount
== 0)
484 *Enabled
= (OldState
.Privileges
[0].Attributes
& SE_PRIVILEGE_ENABLED
);
487 DPRINT("RtlAdjustPrivilege() done\n");
489 return STATUS_SUCCESS
;