- protect access to buffers in NtCreateThread and NtOpenThread
[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 Status = PsImpersonateClient(Thread,
312 Token,
313 FALSE,
314 FALSE,
315 ImpersonationLevel);
316
317 if (Token != NULL) ObDereferenceObject(Token);
318 return Status;
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 ObReferenceObject(Token);
383
384 Thread->ActiveImpersonationInfo = TRUE;
385
386 return STATUS_SUCCESS;
387 }
388
389
390 PACCESS_TOKEN
391 STDCALL
392 PsReferenceEffectiveToken(PETHREAD Thread,
393 PTOKEN_TYPE TokenType,
394 PBOOLEAN EffectiveOnly,
395 PSECURITY_IMPERSONATION_LEVEL Level)
396 {
397 PEPROCESS Process;
398 PACCESS_TOKEN Token;
399
400 if (Thread->ActiveImpersonationInfo == FALSE)
401 {
402 Process = Thread->ThreadsProcess;
403 *TokenType = TokenPrimary;
404 *EffectiveOnly = FALSE;
405
406 /* Fast Reference the Token */
407 Token = ObFastReferenceObject(&Process->Token);
408
409 /* Check if we got the Token or if we got locked */
410 if (!Token)
411 {
412 /* Lock the Process */
413 PspLockProcessSecurityShared(Process);
414
415 /* Do a Locked Fast Reference */
416 //Token = ObFastReferenceObjectLocked(&Process->Token);
417
418 /* Unlock the Process */
419 PspUnlockProcessSecurityShared(Process);
420 }
421 }
422 else
423 {
424 Token = Thread->ImpersonationInfo->Token;
425 *TokenType = TokenImpersonation;
426 *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
427 *Level = Thread->ImpersonationInfo->ImpersonationLevel;
428 }
429
430 return Token;
431 }
432
433 NTSTATUS
434 STDCALL
435 NtImpersonateThread(IN HANDLE ThreadHandle,
436 IN HANDLE ThreadToImpersonateHandle,
437 IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService)
438 {
439 SECURITY_QUALITY_OF_SERVICE SafeServiceQoS;
440 SECURITY_CLIENT_CONTEXT ClientContext;
441 PETHREAD Thread;
442 PETHREAD ThreadToImpersonate;
443 KPROCESSOR_MODE PreviousMode;
444 NTSTATUS Status = STATUS_SUCCESS;
445
446 PAGED_CODE();
447
448 PreviousMode = ExGetPreviousMode();
449
450 if(PreviousMode != KernelMode)
451 {
452 _SEH_TRY
453 {
454 ProbeForRead(SecurityQualityOfService,
455 sizeof(SECURITY_QUALITY_OF_SERVICE),
456 sizeof(ULONG));
457 SafeServiceQoS = *SecurityQualityOfService;
458 SecurityQualityOfService = &SafeServiceQoS;
459 }
460 _SEH_HANDLE
461 {
462 Status = _SEH_GetExceptionCode();
463 }
464 _SEH_END;
465
466 if(!NT_SUCCESS(Status))
467 {
468 return Status;
469 }
470 }
471
472 Status = ObReferenceObjectByHandle(ThreadHandle,
473 THREAD_IMPERSONATE,
474 PsThreadType,
475 PreviousMode,
476 (PVOID*)&Thread,
477 NULL);
478 if(NT_SUCCESS(Status))
479 {
480 Status = ObReferenceObjectByHandle(ThreadToImpersonateHandle,
481 THREAD_DIRECT_IMPERSONATION,
482 PsThreadType,
483 PreviousMode,
484 (PVOID*)&ThreadToImpersonate,
485 NULL);
486 if(NT_SUCCESS(Status))
487 {
488 Status = SeCreateClientSecurity(ThreadToImpersonate,
489 SecurityQualityOfService,
490 0,
491 &ClientContext);
492 if(NT_SUCCESS(Status))
493 {
494 SeImpersonateClient(&ClientContext,
495 Thread);
496 if(ClientContext.ClientToken != NULL)
497 {
498 ObDereferenceObject (ClientContext.ClientToken);
499 }
500 }
501
502 ObDereferenceObject(ThreadToImpersonate);
503 }
504 ObDereferenceObject(Thread);
505 }
506
507 return Status;
508 }
509
510 /*
511 * @implemented
512 */
513 PACCESS_TOKEN
514 STDCALL
515 PsReferenceImpersonationToken(IN PETHREAD Thread,
516 OUT PBOOLEAN CopyOnOpen,
517 OUT PBOOLEAN EffectiveOnly,
518 OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel)
519 {
520
521 if (Thread->ActiveImpersonationInfo == FALSE) {
522
523 return NULL;
524 }
525
526 *ImpersonationLevel = Thread->ImpersonationInfo->ImpersonationLevel;
527 *CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen;
528 *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
529
530 ObReferenceObjectByPointer(Thread->ImpersonationInfo->Token,
531 TOKEN_ALL_ACCESS,
532 SepTokenObjectType,
533 KernelMode);
534
535 return Thread->ImpersonationInfo->Token;
536 }
537
538 #ifdef PsDereferencePrimaryToken
539 #undef PsDereferenceImpersonationToken
540 #endif
541 /*
542 * @implemented
543 */
544 VOID
545 STDCALL
546 PsDereferenceImpersonationToken(IN PACCESS_TOKEN ImpersonationToken)
547 {
548 if (ImpersonationToken) {
549
550 ObDereferenceObject(ImpersonationToken);
551 }
552 }
553
554 #ifdef PsDereferencePrimaryToken
555 #undef PsDereferencePrimaryToken
556 #endif
557 /*
558 * @implemented
559 */
560 VOID
561 STDCALL
562 PsDereferencePrimaryToken(IN PACCESS_TOKEN PrimaryToken)
563 {
564 ObDereferenceObject(PrimaryToken);
565 }
566
567 /*
568 * @implemented
569 */
570 BOOLEAN
571 STDCALL
572 PsDisableImpersonation(IN PETHREAD Thread,
573 IN PSE_IMPERSONATION_STATE ImpersonationState)
574 {
575 if (Thread->ActiveImpersonationInfo == FALSE) {
576 ImpersonationState->Token = NULL;
577 ImpersonationState->CopyOnOpen = FALSE;
578 ImpersonationState->EffectiveOnly = FALSE;
579 ImpersonationState->Level = 0;
580 return TRUE;
581 }
582
583 /* FIXME */
584 /* ExfAcquirePushLockExclusive(&Thread->ThreadLock); */
585
586 Thread->ActiveImpersonationInfo = FALSE;
587 ImpersonationState->Token = Thread->ImpersonationInfo->Token;
588 ImpersonationState->CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen;
589 ImpersonationState->EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly;
590 ImpersonationState->Level = Thread->ImpersonationInfo->ImpersonationLevel;
591
592 /* FIXME */
593 /* ExfReleasePushLock(&Thread->ThreadLock); */
594
595 return TRUE;
596 }
597
598 /*
599 * @implemented
600 */
601 VOID
602 STDCALL
603 PsRestoreImpersonation(IN PETHREAD Thread,
604 IN PSE_IMPERSONATION_STATE ImpersonationState)
605 {
606
607 PsImpersonateClient(Thread,
608 ImpersonationState->Token,
609 ImpersonationState->CopyOnOpen,
610 ImpersonationState->EffectiveOnly,
611 ImpersonationState->Level);
612
613 ObfDereferenceObject(ImpersonationState->Token);
614 }
615
616 /* EOF */