- use inlined probing macros for basic types
[reactos.git] / reactos / ntoskrnl / ps / security.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ps/security.c
5 * PURPOSE: Process Manager Security (Tokens, Impersionation)
6 *
7 * PROGRAMMERS: David Welch (welch@cwcom.net)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <internal/debug.h>
15
16 /* INTERNAL ******************************************************************/
17
18 /* FIXME: Turn into Macro */
19 VOID
20 STDCALL
21 PspLockProcessSecurityShared(PEPROCESS Process)
22 {
23 /* Enter a Guarded Region */
24 KeEnterGuardedRegion();
25
26 /* Lock the Process */
27 //ExAcquirePushLockShared(&Process->ProcessLock);
28 }
29
30 /* FIXME: Turn into Macro */
31 VOID
32 STDCALL
33 PspUnlockProcessSecurityShared(PEPROCESS Process)
34 {
35 /* Unlock the Process */
36 //ExReleasePushLockShared(&Process->ProcessLock);
37
38 /* Leave Guarded Region */
39 KeLeaveGuardedRegion();
40 }
41
42 /* FUNCTIONS *****************************************************************/
43
44 /*
45 * @implemented
46 */
47 NTSTATUS
48 STDCALL
49 NtOpenProcessToken(IN HANDLE ProcessHandle,
50 IN ACCESS_MASK DesiredAccess,
51 OUT PHANDLE TokenHandle)
52 {
53 return NtOpenProcessTokenEx(ProcessHandle,
54 DesiredAccess,
55 0,
56 TokenHandle);
57 }
58
59 /*
60 * @implemented
61 */
62 NTSTATUS
63 STDCALL
64 NtOpenProcessTokenEx(IN HANDLE ProcessHandle,
65 IN ACCESS_MASK DesiredAccess,
66 IN ULONG HandleAttributes,
67 OUT PHANDLE TokenHandle)
68 {
69 PACCESS_TOKEN Token;
70 HANDLE hToken;
71 KPROCESSOR_MODE PreviousMode;
72 NTSTATUS Status = STATUS_SUCCESS;
73
74 PAGED_CODE();
75
76 PreviousMode = ExGetPreviousMode();
77
78 if(PreviousMode != KernelMode)
79 {
80 _SEH_TRY
81 {
82 ProbeForWriteHandle(TokenHandle);
83 }
84 _SEH_HANDLE
85 {
86 Status = _SEH_GetExceptionCode();
87 }
88 _SEH_END;
89
90 if(!NT_SUCCESS(Status))
91 {
92 return Status;
93 }
94 }
95
96 Status = PsOpenTokenOfProcess(ProcessHandle,
97 &Token);
98 if(NT_SUCCESS(Status))
99 {
100 Status = ObpCreateHandle(PsGetCurrentProcess(),
101 Token,
102 DesiredAccess,
103 FALSE,
104 &hToken);
105 ObDereferenceObject(Token);
106
107 if(NT_SUCCESS(Status))
108 {
109 _SEH_TRY
110 {
111 *TokenHandle = hToken;
112 }
113 _SEH_HANDLE
114 {
115 Status = _SEH_GetExceptionCode();
116 }
117 _SEH_END;
118 }
119 }
120
121 return Status;
122 }
123
124 /*
125 * @implemented
126 */
127 PACCESS_TOKEN
128 STDCALL
129 PsReferencePrimaryToken(PEPROCESS Process)
130 {
131 PACCESS_TOKEN Token;
132
133 /* Fast Reference the Token */
134 Token = ObFastReferenceObject(&Process->Token);
135
136 /* Check if we got the Token or if we got locked */
137 if (!Token)
138 {
139 /* Lock the Process */
140 PspLockProcessSecurityShared(Process);
141
142 /* Do a Locked Fast Reference */
143 //Token = ObFastReferenceObjectLocked(&Process->Token);
144
145 /* Unlock the Process */
146 PspUnlockProcessSecurityShared(Process);
147 }
148
149 /* Return the Token */
150 return Token;
151 }
152
153 /*
154 * @implemented
155 */
156 NTSTATUS
157 STDCALL
158 PsOpenTokenOfProcess(HANDLE ProcessHandle,
159 PACCESS_TOKEN* Token)
160 {
161 PEPROCESS Process;
162 NTSTATUS Status;
163
164 /* Get the Token */
165 Status = ObReferenceObjectByHandle(ProcessHandle,
166 PROCESS_QUERY_INFORMATION,
167 PsProcessType,
168 ExGetPreviousMode(),
169 (PVOID*)&Process,
170 NULL);
171
172 /* Reference it */
173 if(NT_SUCCESS(Status)) {
174
175 *Token = PsReferencePrimaryToken(Process);
176 ObDereferenceObject(Process);
177 }
178
179 /* Return */
180 return Status;
181 }
182
183 NTSTATUS
184 STDCALL
185 PspInitializeProcessSecurity(PEPROCESS Process,
186 PEPROCESS Parent OPTIONAL)
187 {
188 NTSTATUS Status = STATUS_SUCCESS;
189
190 /* If we have a parent, then duplicate the Token */
191 if (Parent) {
192
193 PTOKEN pNewToken;
194 PTOKEN pParentToken;
195 OBJECT_ATTRIBUTES ObjectAttributes;
196
197 /* Get the Parent Token */
198 pParentToken = PsReferencePrimaryToken(Parent);
199
200 /* Initialize the Object Attributes */
201 InitializeObjectAttributes(&ObjectAttributes,
202 NULL,
203 0,
204 NULL,
205 NULL);
206
207 /* Duplicate the Token */
208 Status = SepDuplicateToken(pParentToken,
209 &ObjectAttributes,
210 FALSE,
211 TokenPrimary,
212 pParentToken->ImpersonationLevel,
213 KernelMode,
214 &pNewToken);
215
216 if(!NT_SUCCESS(Status)) {
217
218 DPRINT1("Failed to Duplicate Token\n");
219 return Status;
220 }
221
222 /* Dereference the Token */
223 ObFastDereferenceObject(&Parent->Token, pParentToken);
224
225 /* Set the new Token */
226 ObInitializeFastReference(&Process->Token, pNewToken);
227
228 } else {
229
230 #ifdef SCHED_REWRITE
231 PTOKEN BootToken;
232
233 /* No parent, this is the Initial System Process. Assign Boot Token */
234 BootToken = SepCreateSystemProcessToken();
235 BootToken->TokenInUse = TRUE;
236 Process->Token = BootToken;
237 ObReferenceObject(BootToken);
238 #else
239 DPRINT1("PspInitializeProcessSecurity called with no parent.\n");
240 #endif
241 }
242
243 /* Return to caller */
244 return Status;
245 }
246
247
248 NTSTATUS
249 STDCALL
250 PspAssignPrimaryToken(PEPROCESS Process,
251 HANDLE TokenHandle)
252 {
253 PACCESS_TOKEN Token;
254 PACCESS_TOKEN OldToken;
255 NTSTATUS Status;
256
257 /* Reference the Token */
258 Status = ObReferenceObjectByHandle(TokenHandle,
259 0,
260 SepTokenObjectType,
261 KeGetPreviousMode(),
262 (PVOID*)&Token,
263 NULL);
264 if (!NT_SUCCESS(Status)) {
265
266 return(Status);
267 }
268
269 /* Exchange them */
270 Status = SeExchangePrimaryToken(Process, Token, &OldToken);
271
272 /* Derefernece Tokens and Return */
273 ObDereferenceObject(Token);
274 return(Status);
275 }
276
277 /*
278 * @implemented
279 */
280 NTSTATUS
281 STDCALL
282 PsAssignImpersonationToken(PETHREAD Thread,
283 HANDLE TokenHandle)
284 {
285 PACCESS_TOKEN Token;
286 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
287 NTSTATUS Status;
288
289 if (TokenHandle != NULL) {
290
291 Status = ObReferenceObjectByHandle(TokenHandle,
292 TOKEN_IMPERSONATE,
293 SepTokenObjectType,
294 KeGetPreviousMode(),
295 (PVOID*)&Token,
296 NULL);
297
298 if (!NT_SUCCESS(Status)) {
299
300 return(Status);
301 }
302
303 ImpersonationLevel = SeTokenImpersonationLevel(Token);
304
305 } else {
306
307 Token = NULL;
308 ImpersonationLevel = 0;
309 }
310
311 PsImpersonateClient(Thread,
312 Token,
313 FALSE,
314 FALSE,
315 ImpersonationLevel);
316
317 if (Token != NULL) ObDereferenceObject(Token);
318 return(STATUS_SUCCESS);
319 }
320
321 /*
322 * @implemented
323 */
324 VOID STDCALL
325 PsRevertToSelf (VOID)
326 {
327 PsRevertThreadToSelf(PsGetCurrentThread());
328 }
329
330 /*
331 * @implemented
332 */
333 VOID
334 STDCALL
335 PsRevertThreadToSelf(IN PETHREAD Thread)
336 {
337 if (Thread->ActiveImpersonationInfo == TRUE) {
338
339 ObDereferenceObject (Thread->ImpersonationInfo->Token);
340 Thread->ActiveImpersonationInfo = FALSE;
341 }
342 }
343
344 /*
345 * @implemented
346 */
347 NTSTATUS
348 STDCALL
349 PsImpersonateClient(IN PETHREAD Thread,
350 IN PACCESS_TOKEN Token,
351 IN BOOLEAN CopyOnOpen,
352 IN BOOLEAN EffectiveOnly,
353 IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
354 {
355
356 if (Token == NULL) {
357
358 if (Thread->ActiveImpersonationInfo == TRUE) {
359
360 Thread->ActiveImpersonationInfo = FALSE;
361
362 if (Thread->ImpersonationInfo->Token != NULL) {
363
364 ObDereferenceObject (Thread->ImpersonationInfo->Token);
365 }
366 }
367
368 return STATUS_UNSUCCESSFUL;
369 }
370
371 if (Thread->ImpersonationInfo == NULL) {
372
373 Thread->ImpersonationInfo = ExAllocatePool(NonPagedPool,
374 sizeof(PS_IMPERSONATION_INFORMATION));
375 }
376
377 Thread->ImpersonationInfo->ImpersonationLevel = ImpersonationLevel;
378 Thread->ImpersonationInfo->CopyOnOpen = CopyOnOpen;
379 Thread->ImpersonationInfo->EffectiveOnly = EffectiveOnly;
380 Thread->ImpersonationInfo->Token = Token;
381
382 ObReferenceObjectByPointer(Token,
383 0,
384 SepTokenObjectType,
385 KernelMode);
386
387 Thread->ActiveImpersonationInfo = TRUE;
388
389 return STATUS_SUCCESS;
390 }
391
392
393 PACCESS_TOKEN
394 STDCALL
395 PsReferenceEffectiveToken(PETHREAD Thread,
396 PTOKEN_TYPE TokenType,
397 PBOOLEAN EffectiveOnly,
398 PSECURITY_IMPERSONATION_LEVEL Level)
399 {
400 PEPROCESS Process;
401 PACCESS_TOKEN Token;
402
403 if (Thread->ActiveImpersonationInfo == FALSE)
404 {
405 Process = Thread->ThreadsProcess;
406 *TokenType = TokenPrimary;
407 *EffectiveOnly = FALSE;
408
409 /* Fast Reference the Token */
410 Token = ObFastReferenceObject(&Process->Token);
411
412 /* Check if we got the Token or if we got locked */
413 if (!Token)
414 {
415 /* Lock the Process */
416 PspLockProcessSecurityShared(Process);
417
418 /* Do a Locked Fast Reference */
419 //Token = ObFastReferenceObjectLocked(&Process->Token);
420
421 /* Unlock the Process */
422 PspUnlockProcessSecurityShared(Process);
423 }
424 }
425 else
426 {
427 Token = Thread->ImpersonationInfo->Token;
428 *TokenType = TokenImpersonation;
429 *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
430 *Level = Thread->ImpersonationInfo->ImpersonationLevel;
431 }
432
433 return Token;
434 }
435
436 NTSTATUS
437 STDCALL
438 NtImpersonateThread(IN HANDLE ThreadHandle,
439 IN HANDLE ThreadToImpersonateHandle,
440 IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService)
441 {
442 SECURITY_QUALITY_OF_SERVICE SafeServiceQoS;
443 SECURITY_CLIENT_CONTEXT ClientContext;
444 PETHREAD Thread;
445 PETHREAD ThreadToImpersonate;
446 KPROCESSOR_MODE PreviousMode;
447 NTSTATUS Status = STATUS_SUCCESS;
448
449 PAGED_CODE();
450
451 PreviousMode = ExGetPreviousMode();
452
453 if(PreviousMode != KernelMode)
454 {
455 _SEH_TRY
456 {
457 ProbeForRead(SecurityQualityOfService,
458 sizeof(SECURITY_QUALITY_OF_SERVICE),
459 sizeof(ULONG));
460 SafeServiceQoS = *SecurityQualityOfService;
461 SecurityQualityOfService = &SafeServiceQoS;
462 }
463 _SEH_HANDLE
464 {
465 Status = _SEH_GetExceptionCode();
466 }
467 _SEH_END;
468
469 if(!NT_SUCCESS(Status))
470 {
471 return Status;
472 }
473 }
474
475 Status = ObReferenceObjectByHandle(ThreadHandle,
476 THREAD_IMPERSONATE,
477 PsThreadType,
478 PreviousMode,
479 (PVOID*)&Thread,
480 NULL);
481 if(NT_SUCCESS(Status))
482 {
483 Status = ObReferenceObjectByHandle(ThreadToImpersonateHandle,
484 THREAD_DIRECT_IMPERSONATION,
485 PsThreadType,
486 PreviousMode,
487 (PVOID*)&ThreadToImpersonate,
488 NULL);
489 if(NT_SUCCESS(Status))
490 {
491 Status = SeCreateClientSecurity(ThreadToImpersonate,
492 SecurityQualityOfService,
493 0,
494 &ClientContext);
495 if(NT_SUCCESS(Status))
496 {
497 SeImpersonateClient(&ClientContext,
498 Thread);
499 if(ClientContext.ClientToken != NULL)
500 {
501 ObDereferenceObject (ClientContext.ClientToken);
502 }
503 }
504
505 ObDereferenceObject(ThreadToImpersonate);
506 }
507 ObDereferenceObject(Thread);
508 }
509
510 return Status;
511 }
512
513 /*
514 * @implemented
515 */
516 PACCESS_TOKEN
517 STDCALL
518 PsReferenceImpersonationToken(IN PETHREAD Thread,
519 OUT PBOOLEAN CopyOnOpen,
520 OUT PBOOLEAN EffectiveOnly,
521 OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
522 {
523
524 if (Thread->ActiveImpersonationInfo == FALSE) {
525
526 return NULL;
527 }
528
529 *ImpersonationLevel = Thread->ImpersonationInfo->ImpersonationLevel;
530 *CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen;
531 *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
532
533 ObReferenceObjectByPointer(Thread->ImpersonationInfo->Token,
534 TOKEN_ALL_ACCESS,
535 SepTokenObjectType,
536 KernelMode);
537
538 return Thread->ImpersonationInfo->Token;
539 }
540
541 #ifdef PsDereferencePrimaryToken
542 #undef PsDereferenceImpersonationToken
543 #endif
544 /*
545 * @implemented
546 */
547 VOID
548 STDCALL
549 PsDereferenceImpersonationToken(IN PACCESS_TOKEN ImpersonationToken)
550 {
551 if (ImpersonationToken) {
552
553 ObDereferenceObject(ImpersonationToken);
554 }
555 }
556
557 #ifdef PsDereferencePrimaryToken
558 #undef PsDereferencePrimaryToken
559 #endif
560 /*
561 * @implemented
562 */
563 VOID
564 STDCALL
565 PsDereferencePrimaryToken(IN PACCESS_TOKEN PrimaryToken)
566 {
567 ObDereferenceObject(PrimaryToken);
568 }
569
570 /*
571 * @implemented
572 */
573 BOOLEAN
574 STDCALL
575 PsDisableImpersonation(IN PETHREAD Thread,
576 IN PSE_IMPERSONATION_STATE ImpersonationState)
577 {
578 if (Thread->ActiveImpersonationInfo == FALSE) {
579 ImpersonationState->Token = NULL;
580 ImpersonationState->CopyOnOpen = FALSE;
581 ImpersonationState->EffectiveOnly = FALSE;
582 ImpersonationState->Level = 0;
583 return TRUE;
584 }
585
586 /* FIXME */
587 /* ExfAcquirePushLockExclusive(&Thread->ThreadLock); */
588
589 Thread->ActiveImpersonationInfo = FALSE;
590 ImpersonationState->Token = Thread->ImpersonationInfo->Token;
591 ImpersonationState->CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen;
592 ImpersonationState->EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
593 ImpersonationState->Level = Thread->ImpersonationInfo->ImpersonationLevel;
594
595 /* FIXME */
596 /* ExfReleasePushLock(&Thread->ThreadLock); */
597
598 return TRUE;
599 }
600
601 /*
602 * @implemented
603 */
604 VOID
605 STDCALL
606 PsRestoreImpersonation(IN PETHREAD Thread,
607 IN PSE_IMPERSONATION_STATE ImpersonationState)
608 {
609
610 PsImpersonateClient(Thread,
611 ImpersonationState->Token,
612 ImpersonationState->CopyOnOpen,
613 ImpersonationState->EffectiveOnly,
614 ImpersonationState->Level);
615
616 ObfDereferenceObject(ImpersonationState->Token);
617 }
618
619 /* EOF */