- NDK 0.98, now with versionned headers. Too many changes to list, see the TinyKRNL...
[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(Token,
101 DesiredAccess,
102 HandleAttributes,
103 &hToken);
104 ObDereferenceObject(Token);
105
106 if(NT_SUCCESS(Status))
107 {
108 _SEH_TRY
109 {
110 *TokenHandle = hToken;
111 }
112 _SEH_HANDLE
113 {
114 Status = _SEH_GetExceptionCode();
115 }
116 _SEH_END;
117 }
118 }
119
120 return Status;
121 }
122
123 /*
124 * @implemented
125 */
126 PACCESS_TOKEN
127 STDCALL
128 PsReferencePrimaryToken(PEPROCESS Process)
129 {
130 PACCESS_TOKEN Token;
131
132 /* Fast Reference the Token */
133 Token = ObFastReferenceObject(&Process->Token);
134
135 /* Check if we got the Token or if we got locked */
136 if (!Token)
137 {
138 /* Lock the Process */
139 PspLockProcessSecurityShared(Process);
140
141 /* Do a Locked Fast Reference */
142 //Token = ObFastReferenceObjectLocked(&Process->Token);
143
144 /* Unlock the Process */
145 PspUnlockProcessSecurityShared(Process);
146 }
147
148 /* Return the Token */
149 return Token;
150 }
151
152 /*
153 * @implemented
154 */
155 NTSTATUS
156 STDCALL
157 PsOpenTokenOfProcess(HANDLE ProcessHandle,
158 PACCESS_TOKEN* Token)
159 {
160 PEPROCESS Process;
161 NTSTATUS Status;
162
163 /* Get the Token */
164 Status = ObReferenceObjectByHandle(ProcessHandle,
165 PROCESS_QUERY_INFORMATION,
166 PsProcessType,
167 ExGetPreviousMode(),
168 (PVOID*)&Process,
169 NULL);
170
171 /* Reference it */
172 if(NT_SUCCESS(Status)) {
173
174 *Token = PsReferencePrimaryToken(Process);
175 ObDereferenceObject(Process);
176 }
177
178 /* Return */
179 return Status;
180 }
181
182 NTSTATUS
183 STDCALL
184 PspInitializeProcessSecurity(PEPROCESS Process,
185 PEPROCESS Parent OPTIONAL)
186 {
187 NTSTATUS Status = STATUS_SUCCESS;
188
189 /* If we have a parent, then duplicate the Token */
190 if (Parent) {
191
192 PTOKEN pNewToken;
193 PTOKEN pParentToken;
194 OBJECT_ATTRIBUTES ObjectAttributes;
195
196 /* Get the Parent Token */
197 pParentToken = PsReferencePrimaryToken(Parent);
198
199 /* Initialize the Object Attributes */
200 InitializeObjectAttributes(&ObjectAttributes,
201 NULL,
202 0,
203 NULL,
204 NULL);
205
206 /* Duplicate the Token */
207 Status = SepDuplicateToken(pParentToken,
208 &ObjectAttributes,
209 FALSE,
210 TokenPrimary,
211 pParentToken->ImpersonationLevel,
212 KernelMode,
213 &pNewToken);
214
215 if(!NT_SUCCESS(Status)) {
216
217 DPRINT1("Failed to Duplicate Token\n");
218 return Status;
219 }
220
221 /* Dereference the Token */
222 ObFastDereferenceObject(&Parent->Token, pParentToken);
223
224 /* Set the new Token */
225 ObInitializeFastReference(&Process->Token, pNewToken);
226
227 } else {
228
229 #ifdef SCHED_REWRITE
230 PTOKEN BootToken;
231
232 /* No parent, this is the Initial System Process. Assign Boot Token */
233 BootToken = SepCreateSystemProcessToken();
234 BootToken->TokenInUse = TRUE;
235 Process->Token = BootToken;
236 ObReferenceObject(BootToken);
237 #else
238 DPRINT1("PspInitializeProcessSecurity called with no parent.\n");
239 #endif
240 }
241
242 /* Return to caller */
243 return Status;
244 }
245
246
247 NTSTATUS
248 STDCALL
249 PspAssignPrimaryToken(PEPROCESS Process,
250 HANDLE TokenHandle)
251 {
252 PACCESS_TOKEN Token;
253 PACCESS_TOKEN OldToken;
254 NTSTATUS Status;
255
256 /* Reference the Token */
257 Status = ObReferenceObjectByHandle(TokenHandle,
258 0,
259 SepTokenObjectType,
260 KeGetPreviousMode(),
261 (PVOID*)&Token,
262 NULL);
263 if (!NT_SUCCESS(Status)) {
264
265 return(Status);
266 }
267
268 /* Exchange them */
269 Status = SeExchangePrimaryToken(Process, Token, &OldToken);
270
271 /* Derefernece Tokens and Return */
272 ObDereferenceObject(Token);
273 return(Status);
274 }
275
276 /*
277 * @implemented
278 */
279 NTSTATUS
280 STDCALL
281 PsAssignImpersonationToken(PETHREAD Thread,
282 HANDLE TokenHandle)
283 {
284 PACCESS_TOKEN Token;
285 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
286 NTSTATUS Status;
287
288 if (TokenHandle != NULL) {
289
290 Status = ObReferenceObjectByHandle(TokenHandle,
291 TOKEN_IMPERSONATE,
292 SepTokenObjectType,
293 KeGetPreviousMode(),
294 (PVOID*)&Token,
295 NULL);
296
297 if (!NT_SUCCESS(Status)) {
298
299 return(Status);
300 }
301
302 ImpersonationLevel = SeTokenImpersonationLevel(Token);
303
304 } else {
305
306 Token = NULL;
307 ImpersonationLevel = 0;
308 }
309
310 Status = PsImpersonateClient(Thread,
311 Token,
312 FALSE,
313 FALSE,
314 ImpersonationLevel);
315
316 if (Token != NULL) ObDereferenceObject(Token);
317 return Status;
318 }
319
320 /*
321 * @implemented
322 */
323 VOID STDCALL
324 PsRevertToSelf (VOID)
325 {
326 PsRevertThreadToSelf(PsGetCurrentThread());
327 }
328
329 /*
330 * @implemented
331 */
332 VOID
333 STDCALL
334 PsRevertThreadToSelf(IN PETHREAD Thread)
335 {
336 if (Thread->ActiveImpersonationInfo == TRUE) {
337
338 ObDereferenceObject (Thread->ImpersonationInfo->Token);
339 Thread->ActiveImpersonationInfo = FALSE;
340 }
341 }
342
343 /*
344 * @implemented
345 */
346 NTSTATUS
347 STDCALL
348 PsImpersonateClient(IN PETHREAD Thread,
349 IN PACCESS_TOKEN Token,
350 IN BOOLEAN CopyOnOpen,
351 IN BOOLEAN EffectiveOnly,
352 IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
353 {
354
355 if (Token == NULL) {
356
357 if (Thread->ActiveImpersonationInfo == TRUE) {
358
359 Thread->ActiveImpersonationInfo = FALSE;
360
361 if (Thread->ImpersonationInfo->Token != NULL) {
362
363 ObDereferenceObject (Thread->ImpersonationInfo->Token);
364 }
365 }
366
367 return STATUS_UNSUCCESSFUL;
368 }
369
370 if (Thread->ImpersonationInfo == NULL) {
371
372 Thread->ImpersonationInfo = ExAllocatePool(NonPagedPool,
373 sizeof(PS_IMPERSONATION_INFORMATION));
374 }
375
376 Thread->ImpersonationInfo->ImpersonationLevel = ImpersonationLevel;
377 Thread->ImpersonationInfo->CopyOnOpen = CopyOnOpen;
378 Thread->ImpersonationInfo->EffectiveOnly = EffectiveOnly;
379 Thread->ImpersonationInfo->Token = Token;
380
381 ObReferenceObject(Token);
382
383 Thread->ActiveImpersonationInfo = TRUE;
384
385 return STATUS_SUCCESS;
386 }
387
388
389 PACCESS_TOKEN
390 STDCALL
391 PsReferenceEffectiveToken(PETHREAD Thread,
392 PTOKEN_TYPE TokenType,
393 PBOOLEAN EffectiveOnly,
394 PSECURITY_IMPERSONATION_LEVEL Level)
395 {
396 PEPROCESS Process;
397 PACCESS_TOKEN Token;
398
399 if (Thread->ActiveImpersonationInfo == FALSE)
400 {
401 Process = Thread->ThreadsProcess;
402 *TokenType = TokenPrimary;
403 *EffectiveOnly = FALSE;
404
405 /* Fast Reference the Token */
406 Token = ObFastReferenceObject(&Process->Token);
407
408 /* Check if we got the Token or if we got locked */
409 if (!Token)
410 {
411 /* Lock the Process */
412 PspLockProcessSecurityShared(Process);
413
414 /* Do a Locked Fast Reference */
415 //Token = ObFastReferenceObjectLocked(&Process->Token);
416
417 /* Unlock the Process */
418 PspUnlockProcessSecurityShared(Process);
419 }
420 }
421 else
422 {
423 Token = Thread->ImpersonationInfo->Token;
424 *TokenType = TokenImpersonation;
425 *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
426 *Level = Thread->ImpersonationInfo->ImpersonationLevel;
427 }
428
429 return Token;
430 }
431
432 NTSTATUS
433 STDCALL
434 NtImpersonateThread(IN HANDLE ThreadHandle,
435 IN HANDLE ThreadToImpersonateHandle,
436 IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService)
437 {
438 SECURITY_QUALITY_OF_SERVICE SafeServiceQoS;
439 SECURITY_CLIENT_CONTEXT ClientContext;
440 PETHREAD Thread;
441 PETHREAD ThreadToImpersonate;
442 KPROCESSOR_MODE PreviousMode;
443 NTSTATUS Status = STATUS_SUCCESS;
444
445 PAGED_CODE();
446
447 PreviousMode = ExGetPreviousMode();
448
449 if(PreviousMode != KernelMode)
450 {
451 _SEH_TRY
452 {
453 ProbeForRead(SecurityQualityOfService,
454 sizeof(SECURITY_QUALITY_OF_SERVICE),
455 sizeof(ULONG));
456 SafeServiceQoS = *SecurityQualityOfService;
457 SecurityQualityOfService = &SafeServiceQoS;
458 }
459 _SEH_HANDLE
460 {
461 Status = _SEH_GetExceptionCode();
462 }
463 _SEH_END;
464
465 if(!NT_SUCCESS(Status))
466 {
467 return Status;
468 }
469 }
470
471 Status = ObReferenceObjectByHandle(ThreadHandle,
472 THREAD_IMPERSONATE,
473 PsThreadType,
474 PreviousMode,
475 (PVOID*)&Thread,
476 NULL);
477 if(NT_SUCCESS(Status))
478 {
479 Status = ObReferenceObjectByHandle(ThreadToImpersonateHandle,
480 THREAD_DIRECT_IMPERSONATION,
481 PsThreadType,
482 PreviousMode,
483 (PVOID*)&ThreadToImpersonate,
484 NULL);
485 if(NT_SUCCESS(Status))
486 {
487 Status = SeCreateClientSecurity(ThreadToImpersonate,
488 SecurityQualityOfService,
489 0,
490 &ClientContext);
491 if(NT_SUCCESS(Status))
492 {
493 SeImpersonateClient(&ClientContext,
494 Thread);
495 if(ClientContext.ClientToken != NULL)
496 {
497 ObDereferenceObject (ClientContext.ClientToken);
498 }
499 }
500
501 ObDereferenceObject(ThreadToImpersonate);
502 }
503 ObDereferenceObject(Thread);
504 }
505
506 return Status;
507 }
508
509 /*
510 * @implemented
511 */
512 PACCESS_TOKEN
513 STDCALL
514 PsReferenceImpersonationToken(IN PETHREAD Thread,
515 OUT PBOOLEAN CopyOnOpen,
516 OUT PBOOLEAN EffectiveOnly,
517 OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
518 {
519
520 if (Thread->ActiveImpersonationInfo == FALSE) {
521
522 return NULL;
523 }
524
525 *ImpersonationLevel = Thread->ImpersonationInfo->ImpersonationLevel;
526 *CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen;
527 *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
528
529 ObReferenceObjectByPointer(Thread->ImpersonationInfo->Token,
530 TOKEN_ALL_ACCESS,
531 SepTokenObjectType,
532 KernelMode);
533
534 return Thread->ImpersonationInfo->Token;
535 }
536
537 #ifdef PsDereferencePrimaryToken
538 #undef PsDereferenceImpersonationToken
539 #endif
540 /*
541 * @implemented
542 */
543 VOID
544 STDCALL
545 PsDereferenceImpersonationToken(IN PACCESS_TOKEN ImpersonationToken)
546 {
547 if (ImpersonationToken) {
548
549 ObDereferenceObject(ImpersonationToken);
550 }
551 }
552
553 #ifdef PsDereferencePrimaryToken
554 #undef PsDereferencePrimaryToken
555 #endif
556 /*
557 * @implemented
558 */
559 VOID
560 STDCALL
561 PsDereferencePrimaryToken(IN PACCESS_TOKEN PrimaryToken)
562 {
563 ObDereferenceObject(PrimaryToken);
564 }
565
566 /*
567 * @implemented
568 */
569 BOOLEAN
570 STDCALL
571 PsDisableImpersonation(IN PETHREAD Thread,
572 IN PSE_IMPERSONATION_STATE ImpersonationState)
573 {
574 if (Thread->ActiveImpersonationInfo == FALSE) {
575 ImpersonationState->Token = NULL;
576 ImpersonationState->CopyOnOpen = FALSE;
577 ImpersonationState->EffectiveOnly = FALSE;
578 ImpersonationState->Level = 0;
579 return TRUE;
580 }
581
582 /* FIXME */
583 /* ExfAcquirePushLockExclusive(&Thread->ThreadLock); */
584
585 Thread->ActiveImpersonationInfo = FALSE;
586 ImpersonationState->Token = Thread->ImpersonationInfo->Token;
587 ImpersonationState->CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen;
588 ImpersonationState->EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
589 ImpersonationState->Level = Thread->ImpersonationInfo->ImpersonationLevel;
590
591 /* FIXME */
592 /* ExfReleasePushLock(&Thread->ThreadLock); */
593
594 return TRUE;
595 }
596
597 /*
598 * @implemented
599 */
600 VOID
601 STDCALL
602 PsRestoreImpersonation(IN PETHREAD Thread,
603 IN PSE_IMPERSONATION_STATE ImpersonationState)
604 {
605
606 PsImpersonateClient(Thread,
607 ImpersonationState->Token,
608 ImpersonationState->CopyOnOpen,
609 ImpersonationState->EffectiveOnly,
610 ImpersonationState->Level);
611
612 ObfDereferenceObject(ImpersonationState->Token);
613 }
614
615 /* EOF */