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