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 ULONG ReturnLength
, i
, OldSize
;
118 SECURITY_QUALITY_OF_SERVICE Sqos
;
119 OBJECT_ATTRIBUTES ObjectAttributes
;
120 HANDLE ImpersonationToken
= 0, ProcessToken
;
123 if (Flags
& ~(RTL_ACQUIRE_PRIVILEGE_PROCESS
| RTL_ACQUIRE_PRIVILEGE_IMPERSONATE
))
125 return STATUS_INVALID_PARAMETER
;
128 /* If user wants to acquire privileges for the process, we have to impersonate him */
129 if (Flags
& RTL_ACQUIRE_PRIVILEGE_PROCESS
)
131 Flags
|= RTL_ACQUIRE_PRIVILEGE_IMPERSONATE
;
134 /* Allocate enough memory to hold: old privileges (fixed buffer size, might not be enough)
135 * new privileges (big enough, after old privileges memory area)
137 State
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(RTL_ACQUIRE_STATE
) + sizeof(TOKEN_PRIVILEGES
) +
138 NumPriv
* sizeof(LUID_AND_ATTRIBUTES
));
141 return STATUS_NO_MEMORY
;
144 /* Only zero a bit of the memory (will be faster that way) */
146 State
->OldImpersonationToken
= 0;
148 State
->OldPrivileges
= NULL
;
150 /* Check whether we have already an active impersonation */
151 if (NtCurrentTeb()->IsImpersonating
)
153 /* Check whether we want to impersonate */
154 if (Flags
& RTL_ACQUIRE_PRIVILEGE_IMPERSONATE
)
156 /* That's all fine, just get the token.
157 * We need access for: adjust (obvious...) but also
158 * query, to be able to query old privileges
160 Status
= RtlpOpenThreadToken(TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
, &State
->Token
);
161 if (!NT_SUCCESS(Status
))
163 RtlFreeHeap(RtlGetProcessHeap(), 0, State
);
169 /* Otherwise, we have to temporary disable active impersonation.
170 * Get previous impersonation token to save it
172 Status
= RtlpOpenThreadToken(TOKEN_IMPERSONATE
, &State
->OldImpersonationToken
);
173 if (!NT_SUCCESS(Status
))
175 RtlFreeHeap(RtlGetProcessHeap(), 0, State
);
179 /* Remember the fact we had an active impersonation */
180 State
->Flags
|= RTL_ACQUIRE_PRIVILEGE_IMPERSONATE
;
182 /* Revert impersonation (ie, give 0 as handle) */
183 Status
= ZwSetInformationThread(NtCurrentThread(),
184 ThreadImpersonationToken
,
190 /* If we have no token yet (which is likely) */
193 /* If we are asked to use process, then do */
194 if (Flags
& RTL_ACQUIRE_PRIVILEGE_PROCESS
)
196 Status
= ZwOpenProcessToken(NtCurrentProcess(), TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
,
198 if (!NT_SUCCESS(Status
))
205 /* Otherwise, we have to impersonate.
206 * Open token for duplication
208 Status
= ZwOpenProcessToken(NtCurrentProcess(), TOKEN_DUPLICATE
, &ProcessToken
);
210 InitializeObjectAttributes(&ObjectAttributes
,
216 ObjectAttributes
.SecurityQualityOfService
= &Sqos
;
217 Sqos
.Length
= sizeof(SECURITY_QUALITY_OF_SERVICE
);
218 Sqos
.ImpersonationLevel
= SecurityDelegation
;
219 Sqos
.ContextTrackingMode
= 1;
220 Sqos
.EffectiveOnly
= FALSE
;
223 Status
= ZwDuplicateToken(ProcessToken
,
224 TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
| TOKEN_IMPERSONATE
,
228 &ImpersonationToken
);
229 if (!NT_SUCCESS(Status
))
231 ZwClose(ProcessToken
);
235 /* Assign our duplicated token to current thread */
236 Status
= ZwSetInformationThread(NtCurrentThread(),
237 ThreadImpersonationToken
,
240 if (!NT_SUCCESS(Status
))
242 ZwClose(ImpersonationToken
);
243 ZwClose(ProcessToken
);
247 /* Save said token */
248 State
->Token
= ImpersonationToken
;
250 ZwClose(ProcessToken
);
254 /* Properly set the privileges pointers:
255 * OldPrivileges points to the static memory in struct (= OldPrivBuffer)
256 * NewPrivileges points to the dynamic memory after OldPrivBuffer
257 * There's NO overflow risks (OldPrivileges is always used with its size)
259 State
->OldPrivileges
= (PTOKEN_PRIVILEGES
)State
->OldPrivBuffer
;
260 State
->NewPrivileges
= (PTOKEN_PRIVILEGES
)(State
->OldPrivBuffer
+ 1024);
262 /* Assign all the privileges to be acquired */
263 State
->NewPrivileges
->PrivilegeCount
= NumPriv
;
264 for (i
= 0; i
< NumPriv
; ++i
)
266 State
->NewPrivileges
->Privileges
[i
].Luid
.LowPart
= Privilege
[i
];
267 State
->NewPrivileges
->Privileges
[i
].Luid
.HighPart
= 0;
268 State
->NewPrivileges
->Privileges
[i
].Attributes
= SE_PRIVILEGE_ENABLED
;
271 /* Start privileges adjustements */
272 OldSize
= sizeof(State
->OldPrivBuffer
);
275 ReturnLength
= sizeof(State
->OldPrivBuffer
);
276 Status
= ZwAdjustPrivilegesToken(State
->Token
, FALSE
, State
->NewPrivileges
,
277 OldSize
, State
->OldPrivileges
, &ReturnLength
);
278 /* This is returned when OldPrivileges buffer is too small */
279 if (Status
== STATUS_BUFFER_TOO_SMALL
)
281 /* Try to allocate a new one, big enough to hold data */
282 State
->OldPrivileges
= RtlAllocateHeap(RtlGetProcessHeap(), 0, ReturnLength
);
283 if (State
->OldPrivileges
)
285 OldSize
= ReturnLength
;
290 /* If we failed, properly set status: we failed because of the lack of memory */
291 Status
= STATUS_NO_MEMORY
;
295 /* If we failed to assign at least one privilege */
296 if (Status
== STATUS_NOT_ALL_ASSIGNED
)
298 /* If there was actually only one privilege to acquire, use more accurate status */
301 Status
= STATUS_PRIVILEGE_NOT_HELD
;
305 /* Fail if needed, otherwise return our state to caller */
306 if (!NT_SUCCESS(Status
))
312 *ReturnedState
= State
;
319 /* If we allocated our own buffer for old privileges, release it */
320 if (State
->OldPrivileges
&& (PVOID
)State
->OldPrivBuffer
!= (PVOID
)State
->OldPrivileges
)
322 RtlFreeHeap(RtlGetProcessHeap(), 0, State
->OldPrivileges
);
325 /* Do we have to restore previously active impersonation? */
326 if (State
->Flags
& RTL_ACQUIRE_PRIVILEGE_IMPERSONATE
)
328 Status
= ZwSetInformationThread(NtCurrentThread(), ThreadImpersonationToken
,
329 &State
->OldImpersonationToken
, sizeof(HANDLE
));
330 /* If this ever happens, we're in a really bad situation... */
331 if (!NT_SUCCESS(Status
))
333 RtlRaiseStatus(Status
);
340 ZwClose(State
->Token
);
343 /* And free our state buffer */
344 RtlFreeHeap(RtlGetProcessHeap(), 0, State
);
354 RtlReleasePrivilege(IN PVOID ReturnedState
)
357 PRTL_ACQUIRE_STATE State
= (PRTL_ACQUIRE_STATE
)ReturnedState
;
359 /* If we had an active impersonation before we acquired privileges */
360 if (State
->Flags
& RTL_ACQUIRE_PRIVILEGE_IMPERSONATE
)
362 /* Restore it for the current thread */
363 Status
= ZwSetInformationThread(NtCurrentThread(), ThreadImpersonationToken
,
364 &State
->OldImpersonationToken
, sizeof(HANDLE
));
365 if (!NT_SUCCESS(Status
))
367 RtlRaiseStatus(Status
);
370 /* And close the token if needed */
371 if (State
->OldImpersonationToken
)
372 ZwClose(State
->OldImpersonationToken
);
376 /* Otherwise, restore old state */
377 ZwAdjustPrivilegesToken(State
->Token
, FALSE
,
378 State
->OldPrivileges
, 0, NULL
, NULL
);
382 /* If we used a different buffer for old privileges, just free it */
383 if ((PVOID
)State
->OldPrivBuffer
!= (PVOID
)State
->OldPrivileges
)
385 RtlFreeHeap(RtlGetProcessHeap(), 0, State
->OldPrivileges
);
388 /* Release token and free state */
389 ZwClose(State
->Token
);
390 RtlFreeHeap(RtlGetProcessHeap(), 0, State
);
398 RtlAdjustPrivilege(IN ULONG Privilege
,
400 IN BOOLEAN CurrentThread
,
401 OUT PBOOLEAN Enabled
)
403 TOKEN_PRIVILEGES NewState
;
404 TOKEN_PRIVILEGES OldState
;
411 DPRINT("RtlAdjustPrivilege() called\n");
415 Status
= ZwOpenThreadToken(NtCurrentThread(),
416 TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
,
422 Status
= ZwOpenProcessToken(NtCurrentProcess(),
423 TOKEN_ADJUST_PRIVILEGES
| TOKEN_QUERY
,
427 if (!NT_SUCCESS (Status
))
429 DPRINT1("Retrieving token handle failed (Status %lx)\n", Status
);
433 OldState
.PrivilegeCount
= 1;
435 NewState
.PrivilegeCount
= 1;
436 NewState
.Privileges
[0].Luid
.LowPart
= Privilege
;
437 NewState
.Privileges
[0].Luid
.HighPart
= 0;
438 NewState
.Privileges
[0].Attributes
= (Enable
) ? SE_PRIVILEGE_ENABLED
: 0;
440 Status
= ZwAdjustPrivilegesToken(TokenHandle
,
443 sizeof(TOKEN_PRIVILEGES
),
446 ZwClose (TokenHandle
);
447 if (Status
== STATUS_NOT_ALL_ASSIGNED
)
449 DPRINT1("Failed to assign all privileges\n");
450 return STATUS_PRIVILEGE_NOT_HELD
;
453 if (!NT_SUCCESS(Status
))
455 DPRINT1("NtAdjustPrivilegesToken() failed (Status %lx)\n", Status
);
459 if (OldState
.PrivilegeCount
== 0)
465 *Enabled
= (OldState
.Privileges
[0].Attributes
& SE_PRIVILEGE_ENABLED
);
468 DPRINT("RtlAdjustPrivilege() done\n");
470 return STATUS_SUCCESS
;