SeCaptureSubjectContext() must not crash if no current thread exists.
[reactos.git] / reactos / ntoskrnl / se / semgr.c
1 /* $Id: semgr.c,v 1.35 2004/07/19 12:45:56 ekohl Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * PURPOSE: Security manager
6 * FILE: kernel/se/semgr.c
7 * PROGRAMER: ?
8 * REVISION HISTORY:
9 * 26/07/98: Added stubs for security functions
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ddk/ntddk.h>
15 #include <internal/ps.h>
16 #include <internal/se.h>
17
18 #define NDEBUG
19 #include <internal/debug.h>
20
21 #define TAG_SXPT TAG('S', 'X', 'P', 'T')
22
23
24 /* GLOBALS ******************************************************************/
25
26 PSE_EXPORTS EXPORTED SeExports = NULL;
27
28
29 /* PROTOTYPES ***************************************************************/
30
31 static BOOLEAN SepInitExports(VOID);
32
33 /* FUNCTIONS ****************************************************************/
34
35
36 BOOLEAN INIT_FUNCTION
37 SeInit1(VOID)
38 {
39 SepInitLuid();
40
41 if (!SepInitSecurityIDs())
42 return FALSE;
43
44 if (!SepInitDACLs())
45 return FALSE;
46
47 if (!SepInitSDs())
48 return FALSE;
49
50 SepInitPrivileges();
51
52 if (!SepInitExports())
53 return FALSE;
54
55 return TRUE;
56 }
57
58
59 BOOLEAN INIT_FUNCTION
60 SeInit2(VOID)
61 {
62 SepInitializeTokenImplementation();
63
64 return TRUE;
65 }
66
67
68 BOOLEAN
69 SeInitSRM(VOID)
70 {
71 OBJECT_ATTRIBUTES ObjectAttributes;
72 UNICODE_STRING Name;
73 HANDLE DirectoryHandle;
74 HANDLE EventHandle;
75 NTSTATUS Status;
76
77 /* Create '\Security' directory */
78 RtlInitUnicodeString(&Name,
79 L"\\Security");
80 InitializeObjectAttributes(&ObjectAttributes,
81 &Name,
82 OBJ_PERMANENT,
83 0,
84 NULL);
85 Status = NtCreateDirectoryObject(&DirectoryHandle,
86 DIRECTORY_ALL_ACCESS,
87 &ObjectAttributes);
88 if (!NT_SUCCESS(Status))
89 {
90 DPRINT1("Failed to create 'Security' directory!\n");
91 return FALSE;
92 }
93
94 /* Create 'LSA_AUTHENTICATION_INITALIZED' event */
95 RtlInitUnicodeString(&Name,
96 L"\\LSA_AUTHENTICATION_INITALIZED");
97 InitializeObjectAttributes(&ObjectAttributes,
98 &Name,
99 OBJ_PERMANENT,
100 DirectoryHandle,
101 SePublicDefaultSd);
102 Status = NtCreateEvent(&EventHandle,
103 EVENT_ALL_ACCESS,
104 &ObjectAttributes,
105 FALSE,
106 FALSE);
107 if (!NT_SUCCESS(Status))
108 {
109 DPRINT1("Failed to create 'LSA_AUTHENTICATION_INITALIZED' event!\n");
110 NtClose(DirectoryHandle);
111 return FALSE;
112 }
113
114 NtClose(EventHandle);
115 NtClose(DirectoryHandle);
116
117 /* FIXME: Create SRM port and listener thread */
118
119 return TRUE;
120 }
121
122
123 static BOOLEAN INIT_FUNCTION
124 SepInitExports(VOID)
125 {
126 SeExports = ExAllocatePoolWithTag(NonPagedPool,
127 sizeof(SE_EXPORTS),
128 TAG_SXPT);
129 if (SeExports == NULL)
130 return FALSE;
131
132 SeExports->SeCreateTokenPrivilege = SeCreateTokenPrivilege;
133 SeExports->SeAssignPrimaryTokenPrivilege = SeAssignPrimaryTokenPrivilege;
134 SeExports->SeLockMemoryPrivilege = SeLockMemoryPrivilege;
135 SeExports->SeIncreaseQuotaPrivilege = SeIncreaseQuotaPrivilege;
136 SeExports->SeUnsolicitedInputPrivilege = SeUnsolicitedInputPrivilege;
137 SeExports->SeTcbPrivilege = SeTcbPrivilege;
138 SeExports->SeSecurityPrivilege = SeSecurityPrivilege;
139 SeExports->SeTakeOwnershipPrivilege = SeTakeOwnershipPrivilege;
140 SeExports->SeLoadDriverPrivilege = SeLoadDriverPrivilege;
141 SeExports->SeCreatePagefilePrivilege = SeCreatePagefilePrivilege;
142 SeExports->SeIncreaseBasePriorityPrivilege = SeIncreaseBasePriorityPrivilege;
143 SeExports->SeSystemProfilePrivilege = SeSystemProfilePrivilege;
144 SeExports->SeSystemtimePrivilege = SeSystemtimePrivilege;
145 SeExports->SeProfileSingleProcessPrivilege = SeProfileSingleProcessPrivilege;
146 SeExports->SeCreatePermanentPrivilege = SeCreatePermanentPrivilege;
147 SeExports->SeBackupPrivilege = SeBackupPrivilege;
148 SeExports->SeRestorePrivilege = SeRestorePrivilege;
149 SeExports->SeShutdownPrivilege = SeShutdownPrivilege;
150 SeExports->SeDebugPrivilege = SeDebugPrivilege;
151 SeExports->SeAuditPrivilege = SeAuditPrivilege;
152 SeExports->SeSystemEnvironmentPrivilege = SeSystemEnvironmentPrivilege;
153 SeExports->SeChangeNotifyPrivilege = SeChangeNotifyPrivilege;
154 SeExports->SeRemoteShutdownPrivilege = SeRemoteShutdownPrivilege;
155
156 SeExports->SeNullSid = SeNullSid;
157 SeExports->SeWorldSid = SeWorldSid;
158 SeExports->SeLocalSid = SeLocalSid;
159 SeExports->SeCreatorOwnerSid = SeCreatorOwnerSid;
160 SeExports->SeCreatorGroupSid = SeCreatorGroupSid;
161 SeExports->SeNtAuthoritySid = SeNtAuthoritySid;
162 SeExports->SeDialupSid = SeDialupSid;
163 SeExports->SeNetworkSid = SeNetworkSid;
164 SeExports->SeBatchSid = SeBatchSid;
165 SeExports->SeInteractiveSid = SeInteractiveSid;
166 SeExports->SeLocalSystemSid = SeLocalSystemSid;
167 SeExports->SeAliasAdminsSid = SeAliasAdminsSid;
168 SeExports->SeAliasUsersSid = SeAliasUsersSid;
169 SeExports->SeAliasGuestsSid = SeAliasGuestsSid;
170 SeExports->SeAliasPowerUsersSid = SeAliasPowerUsersSid;
171 SeExports->SeAliasAccountOpsSid = SeAliasAccountOpsSid;
172 SeExports->SeAliasSystemOpsSid = SeAliasSystemOpsSid;
173 SeExports->SeAliasPrintOpsSid = SeAliasPrintOpsSid;
174 SeExports->SeAliasBackupOpsSid = SeAliasBackupOpsSid;
175
176 return TRUE;
177 }
178
179
180 VOID SepReferenceLogonSession(PLUID AuthenticationId)
181 {
182 UNIMPLEMENTED;
183 }
184
185 VOID SepDeReferenceLogonSession(PLUID AuthenticationId)
186 {
187 UNIMPLEMENTED;
188 }
189
190
191
192 /*
193 * @unimplemented
194 */
195 NTSTATUS STDCALL
196 NtAllocateUuids(PULARGE_INTEGER Time,
197 PULONG Range,
198 PULONG Sequence)
199 {
200 UNIMPLEMENTED;
201 return(STATUS_NOT_IMPLEMENTED);
202 }
203
204
205 /*
206 * @implemented
207 */
208 VOID STDCALL
209 SeCaptureSubjectContext(OUT PSECURITY_SUBJECT_CONTEXT SubjectContext)
210 {
211 PETHREAD Thread;
212 BOOLEAN CopyOnOpen;
213 BOOLEAN EffectiveOnly;
214
215 Thread = PsGetCurrentThread();
216 if (Thread == NULL)
217 {
218 SubjectContext->ProcessAuditId = 0;
219 SubjectContext->PrimaryToken = NULL;
220 SubjectContext->ClientToken = NULL;
221 SubjectContext->ImpersonationLevel = 0;
222 }
223 else
224 {
225 SubjectContext->ProcessAuditId = Thread->ThreadsProcess;
226 SubjectContext->ClientToken =
227 PsReferenceImpersonationToken(Thread,
228 &CopyOnOpen,
229 &EffectiveOnly,
230 &SubjectContext->ImpersonationLevel);
231 SubjectContext->PrimaryToken = PsReferencePrimaryToken(Thread->ThreadsProcess);
232 }
233 }
234
235
236 /*
237 * @unimplemented
238 */
239 VOID STDCALL
240 SeLockSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
241 {
242 UNIMPLEMENTED;
243 }
244
245
246 /*
247 * @implemented
248 */
249 VOID STDCALL
250 SeReleaseSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
251 {
252 if (SubjectContext->PrimaryToken != NULL)
253 {
254 ObDereferenceObject(SubjectContext->PrimaryToken);
255 }
256
257 if (SubjectContext->ClientToken != NULL)
258 {
259 ObDereferenceObject(SubjectContext->ClientToken);
260 }
261 }
262
263
264 /*
265 * @unimplemented
266 */
267 VOID STDCALL
268 SeUnlockSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
269 {
270 UNIMPLEMENTED;
271 }
272
273
274 /*
275 * @implemented
276 */
277 NTSTATUS STDCALL
278 SeDeassignSecurity(PSECURITY_DESCRIPTOR *SecurityDescriptor)
279 {
280 if (*SecurityDescriptor != NULL)
281 {
282 ExFreePool(*SecurityDescriptor);
283 *SecurityDescriptor = NULL;
284 }
285
286 return STATUS_SUCCESS;
287 }
288
289
290 #if 0
291 VOID
292 SepGetDefaultsSubjectContext(PSECURITY_SUBJECT_CONTEXT SubjectContext,
293 PSID* Owner,
294 PSID* PrimaryGroup,
295 PSID* ProcessOwner,
296 PSID* ProcessPrimaryGroup,
297 PACL* DefaultDacl)
298 {
299 PACCESS_TOKEN Token;
300
301 if (SubjectContext->ClientToken != NULL)
302 {
303 Token = SubjectContext->ClientToken;
304 }
305 else
306 {
307 Token = SubjectContext->PrimaryToken;
308 }
309 *Owner = Token->UserAndGroups[Token->DefaultOwnerIndex].Sid;
310 *PrimaryGroup = Token->PrimaryGroup;
311 *DefaultDacl = Token->DefaultDacl;
312 *ProcessOwner = SubjectContext->PrimaryToken->
313 UserAndGroups[Token->DefaultOwnerIndex].Sid;
314 *ProcessPrimaryGroup = SubjectContext->PrimaryToken->PrimaryGroup;
315 }
316
317
318 NTSTATUS
319 SepInheritAcl(PACL Acl,
320 BOOLEAN IsDirectoryObject,
321 PSID Owner,
322 PSID PrimaryGroup,
323 PACL DefaultAcl,
324 PSID ProcessOwner,
325 PSID ProcessGroup,
326 PGENERIC_MAPPING GenericMapping)
327 {
328 if (Acl == NULL)
329 {
330 return(STATUS_UNSUCCESSFUL);
331 }
332
333 if (Acl->AclRevision != 2 &&
334 Acl->AclRevision != 3 )
335 {
336 return(STATUS_UNSUCCESSFUL);
337 }
338
339 }
340 #endif
341
342
343 /*
344 * @unimplemented
345 */
346 NTSTATUS STDCALL
347 SeAssignSecurity(PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL,
348 PSECURITY_DESCRIPTOR ExplicitDescriptor OPTIONAL,
349 PSECURITY_DESCRIPTOR *NewDescriptor,
350 BOOLEAN IsDirectoryObject,
351 PSECURITY_SUBJECT_CONTEXT SubjectContext,
352 PGENERIC_MAPPING GenericMapping,
353 POOL_TYPE PoolType)
354 {
355 PSECURITY_DESCRIPTOR Descriptor;
356 ULONG Length;
357 NTSTATUS Status;
358
359 if (ExplicitDescriptor != NULL)
360 {
361 Length = RtlLengthSecurityDescriptor(ExplicitDescriptor);
362 }
363 else
364 {
365 DPRINT("No explicit security descriptor\n");
366 return STATUS_UNSUCCESSFUL;
367 }
368
369 Descriptor = ExAllocatePool(NonPagedPool,
370 Length);
371 if (Descriptor == NULL)
372 {
373 DPRINT1("ExAlloctePool() failed\n");
374 return STATUS_UNSUCCESSFUL;
375 }
376
377 Status = RtlMakeSelfRelativeSD(ExplicitDescriptor,
378 Descriptor,
379 &Length);
380 if (!NT_SUCCESS(Status))
381 {
382 DPRINT1("RtlMakeSelfRelativeSD() failed (Status %lx)\n", Status);
383 return Status;
384 }
385
386 *NewDescriptor = Descriptor;
387
388 return STATUS_SUCCESS;
389
390 #if 0
391 PSID Owner;
392 PSID PrimaryGroup;
393 PACL DefaultDacl;
394 PSID ProcessOwner;
395 PSID ProcessPrimaryGroup;
396 PACL Sacl;
397
398 if (ExplicitDescriptor == NULL)
399 {
400 RtlCreateSecurityDescriptor(&Descriptor, 1);
401 }
402 else
403 {
404 Descriptor = ExplicitDescriptor;
405 }
406
407 SeLockSubjectContext(SubjectContext);
408
409 SepGetDefaultsSubjectContext(SubjectContext,
410 &Owner,
411 &PrimaryGroup,
412 &DefaultDacl,
413 &ProcessOwner,
414 &ProcessPrimaryGroup);
415
416 if (Descriptor->Control & SE_SACL_PRESENT ||
417 Descriptor->Control & SE_SACL_DEFAULTED)
418 {
419 if (ParentDescriptor == NULL)
420 {
421 }
422
423 if (Descriptor->Control & SE_SACL_PRESENT ||
424 Descriptor->Sacl == NULL ||)
425 {
426 Sacl = NULL;
427 }
428 else
429 {
430 Sacl = Descriptor->Sacl;
431 if (Descriptor->Control & SE_SELF_RELATIVE)
432 {
433 Sacl = (PACL)(((ULONG_PTR)Sacl) + (ULONG_PTR)Descriptor);
434 }
435 }
436
437 SepInheritAcl(Sacl,
438 IsDirectoryObject,
439 Owner,
440 PrimaryGroup,
441 DefaultDacl,
442 ProcessOwner,
443 GenericMapping);
444 }
445 #endif
446 }
447
448
449 static BOOLEAN
450 SepSidInToken(PACCESS_TOKEN Token,
451 PSID Sid)
452 {
453 ULONG i;
454
455 if (Token->UserAndGroupCount == 0)
456 {
457 return FALSE;
458 }
459
460 for (i=0; i<Token->UserAndGroupCount; i++)
461 {
462 if (RtlEqualSid(Sid, Token->UserAndGroups[i].Sid))
463 {
464 if (Token->UserAndGroups[i].Attributes & SE_GROUP_ENABLED)
465 {
466 return TRUE;
467 }
468
469 return FALSE;
470 }
471 }
472
473 return FALSE;
474 }
475
476
477 /*
478 * FUNCTION: Determines whether the requested access rights can be granted
479 * to an object protected by a security descriptor and an object owner
480 * ARGUMENTS:
481 * SecurityDescriptor = Security descriptor protecting the object
482 * SubjectSecurityContext = Subject's captured security context
483 * SubjectContextLocked = Indicates the user's subject context is locked
484 * DesiredAccess = Access rights the caller is trying to acquire
485 * PreviouslyGrantedAccess = Specified the access rights already granted
486 * Privileges = ?
487 * GenericMapping = Generic mapping associated with the object
488 * AccessMode = Access mode used for the check
489 * GrantedAccess (OUT) = On return specifies the access granted
490 * AccessStatus (OUT) = Status indicating why access was denied
491 * RETURNS: If access was granted, returns TRUE
492 *
493 * @implemented
494 */
495 BOOLEAN STDCALL
496 SeAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
497 IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
498 IN BOOLEAN SubjectContextLocked,
499 IN ACCESS_MASK DesiredAccess,
500 IN ACCESS_MASK PreviouslyGrantedAccess,
501 OUT PPRIVILEGE_SET* Privileges,
502 IN PGENERIC_MAPPING GenericMapping,
503 IN KPROCESSOR_MODE AccessMode,
504 OUT PACCESS_MASK GrantedAccess,
505 OUT PNTSTATUS AccessStatus)
506 {
507 LUID_AND_ATTRIBUTES Privilege;
508 ACCESS_MASK CurrentAccess;
509 PACCESS_TOKEN Token;
510 ULONG i;
511 PACL Dacl;
512 BOOLEAN Present;
513 BOOLEAN Defaulted;
514 PACE CurrentAce;
515 PSID Sid;
516 NTSTATUS Status;
517
518 CurrentAccess = PreviouslyGrantedAccess;
519
520 Token = SubjectSecurityContext->ClientToken ?
521 SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken;
522
523 /* Get the DACL */
524 Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
525 &Present,
526 &Dacl,
527 &Defaulted);
528 if (!NT_SUCCESS(Status))
529 {
530 *AccessStatus = Status;
531 return FALSE;
532 }
533
534 /* RULE 1: Grant desired access if the object is unprotected */
535 if (Dacl == NULL)
536 {
537 *GrantedAccess = DesiredAccess;
538 *AccessStatus = STATUS_SUCCESS;
539 return TRUE;
540 }
541
542 CurrentAccess = PreviouslyGrantedAccess;
543
544 /* RULE 2: Check token for 'take ownership' privilege */
545 Privilege.Luid = SeTakeOwnershipPrivilege;
546 Privilege.Attributes = SE_PRIVILEGE_ENABLED;
547
548 if (SepPrivilegeCheck(Token,
549 &Privilege,
550 1,
551 PRIVILEGE_SET_ALL_NECESSARY,
552 AccessMode))
553 {
554 CurrentAccess |= WRITE_OWNER;
555 if (DesiredAccess == CurrentAccess)
556 {
557 *GrantedAccess = CurrentAccess;
558 *AccessStatus = STATUS_SUCCESS;
559 return TRUE;
560 }
561 }
562
563 /* RULE 3: Check whether the token is the owner */
564 Status = RtlGetOwnerSecurityDescriptor(SecurityDescriptor,
565 &Sid,
566 &Defaulted);
567 if (!NT_SUCCESS(Status))
568 {
569 DPRINT1("RtlGetOwnerSecurityDescriptor() failed (Status %lx)\n", Status);
570 *AccessStatus = Status;
571 return FALSE;
572 }
573
574 if (SepSidInToken(Token, Sid))
575 {
576 CurrentAccess |= (READ_CONTROL | WRITE_DAC);
577 if (DesiredAccess == CurrentAccess)
578 {
579 *GrantedAccess = CurrentAccess;
580 *AccessStatus = STATUS_SUCCESS;
581 return TRUE;
582 }
583 }
584
585 /* RULE 4: Grant rights according to the DACL */
586 CurrentAce = (PACE)(Dacl + 1);
587 for (i = 0; i < Dacl->AceCount; i++)
588 {
589 Sid = (PSID)(CurrentAce + 1);
590 if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE)
591 {
592 if (SepSidInToken(Token, Sid))
593 {
594 *GrantedAccess = 0;
595 *AccessStatus = STATUS_ACCESS_DENIED;
596 return TRUE;
597 }
598 }
599
600 if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
601 {
602 if (SepSidInToken(Token, Sid))
603 {
604 CurrentAccess |= CurrentAce->AccessMask;
605 }
606 }
607 }
608
609 DPRINT("CurrentAccess %08lx\n DesiredAccess %08lx\n",
610 CurrentAccess, DesiredAccess);
611
612 *GrantedAccess = CurrentAccess & DesiredAccess;
613
614 *AccessStatus =
615 (*GrantedAccess == DesiredAccess) ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
616
617 return TRUE;
618 }
619
620
621 NTSTATUS STDCALL
622 NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
623 IN HANDLE TokenHandle,
624 IN ACCESS_MASK DesiredAccess,
625 IN PGENERIC_MAPPING GenericMapping,
626 OUT PPRIVILEGE_SET PrivilegeSet,
627 OUT PULONG ReturnLength,
628 OUT PACCESS_MASK GrantedAccess,
629 OUT PNTSTATUS AccessStatus)
630 {
631 SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
632 KPROCESSOR_MODE PreviousMode;
633 PACCESS_TOKEN Token;
634 NTSTATUS Status;
635
636 DPRINT("NtAccessCheck() called\n");
637
638 PreviousMode = KeGetPreviousMode();
639 if (PreviousMode == KernelMode)
640 {
641 *GrantedAccess = DesiredAccess;
642 *AccessStatus = STATUS_SUCCESS;
643 return STATUS_SUCCESS;
644 }
645
646 Status = ObReferenceObjectByHandle(TokenHandle,
647 TOKEN_QUERY,
648 SepTokenObjectType,
649 PreviousMode,
650 (PVOID*)&Token,
651 NULL);
652 if (!NT_SUCCESS(Status))
653 {
654 DPRINT1("Failed to reference token (Status %lx)\n", Status);
655 return Status;
656 }
657
658 /* Check token type */
659 if (Token->TokenType != TokenImpersonation)
660 {
661 DPRINT1("No impersonation token\n");
662 ObDereferenceObject(Token);
663 return STATUS_ACCESS_VIOLATION;
664 }
665
666 /* Check impersonation level */
667 if (Token->ImpersonationLevel < SecurityAnonymous)
668 {
669 DPRINT1("Invalid impersonation level\n");
670 ObDereferenceObject(Token);
671 return STATUS_ACCESS_VIOLATION;
672 }
673
674 RtlZeroMemory(&SubjectSecurityContext,
675 sizeof(SECURITY_SUBJECT_CONTEXT));
676 SubjectSecurityContext.ClientToken = Token;
677 SubjectSecurityContext.ImpersonationLevel = Token->ImpersonationLevel;
678
679 /* FIXME: Lock subject context */
680
681 if (!SeAccessCheck(SecurityDescriptor,
682 &SubjectSecurityContext,
683 TRUE,
684 DesiredAccess,
685 0,
686 &PrivilegeSet,
687 GenericMapping,
688 PreviousMode,
689 GrantedAccess,
690 AccessStatus))
691 {
692 Status = *AccessStatus;
693 }
694 else
695 {
696 Status = STATUS_SUCCESS;
697 }
698
699 /* FIXME: Unlock subject context */
700
701 ObDereferenceObject(Token);
702
703 DPRINT("NtAccessCheck() done\n");
704
705 return Status;
706 }
707
708 /* EOF */