Implement most simple code path of SeAssignSecurity().
[reactos.git] / reactos / ntoskrnl / se / semgr.c
1 /* $Id: semgr.c,v 1.34 2004/07/18 13:02:28 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 PEPROCESS Process;
212 BOOLEAN CopyOnOpen;
213 BOOLEAN EffectiveOnly;
214
215 Process = PsGetCurrentThread ()->ThreadsProcess;
216
217 SubjectContext->ProcessAuditId = Process;
218 SubjectContext->ClientToken =
219 PsReferenceImpersonationToken (PsGetCurrentThread(),
220 &CopyOnOpen,
221 &EffectiveOnly,
222 &SubjectContext->ImpersonationLevel);
223 SubjectContext->PrimaryToken = PsReferencePrimaryToken (Process);
224 }
225
226
227 /*
228 * @unimplemented
229 */
230 VOID STDCALL
231 SeLockSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
232 {
233 UNIMPLEMENTED;
234 }
235
236
237 /*
238 * @implemented
239 */
240 VOID STDCALL
241 SeReleaseSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
242 {
243 ObDereferenceObject (SubjectContext->PrimaryToken);
244 if (SubjectContext->ClientToken != NULL)
245 {
246 ObDereferenceObject (SubjectContext->ClientToken);
247 }
248 }
249
250
251 /*
252 * @unimplemented
253 */
254 VOID STDCALL
255 SeUnlockSubjectContext(IN PSECURITY_SUBJECT_CONTEXT SubjectContext)
256 {
257 UNIMPLEMENTED;
258 }
259
260
261 /*
262 * @implemented
263 */
264 NTSTATUS STDCALL
265 SeDeassignSecurity(PSECURITY_DESCRIPTOR* SecurityDescriptor)
266 {
267 if ((*SecurityDescriptor) != NULL)
268 {
269 ExFreePool(*SecurityDescriptor);
270 (*SecurityDescriptor) = NULL;
271 }
272 return(STATUS_SUCCESS);
273 }
274
275
276 #if 0
277 VOID
278 SepGetDefaultsSubjectContext(PSECURITY_SUBJECT_CONTEXT SubjectContext,
279 PSID* Owner,
280 PSID* PrimaryGroup,
281 PSID* ProcessOwner,
282 PSID* ProcessPrimaryGroup,
283 PACL* DefaultDacl)
284 {
285 PACCESS_TOKEN Token;
286
287 if (SubjectContext->ClientToken != NULL)
288 {
289 Token = SubjectContext->ClientToken;
290 }
291 else
292 {
293 Token = SubjectContext->PrimaryToken;
294 }
295 *Owner = Token->UserAndGroups[Token->DefaultOwnerIndex].Sid;
296 *PrimaryGroup = Token->PrimaryGroup;
297 *DefaultDacl = Token->DefaultDacl;
298 *ProcessOwner = SubjectContext->PrimaryToken->
299 UserAndGroups[Token->DefaultOwnerIndex].Sid;
300 *ProcessPrimaryGroup = SubjectContext->PrimaryToken->PrimaryGroup;
301 }
302
303
304 NTSTATUS
305 SepInheritAcl(PACL Acl,
306 BOOLEAN IsDirectoryObject,
307 PSID Owner,
308 PSID PrimaryGroup,
309 PACL DefaultAcl,
310 PSID ProcessOwner,
311 PSID ProcessGroup,
312 PGENERIC_MAPPING GenericMapping)
313 {
314 if (Acl == NULL)
315 {
316 return(STATUS_UNSUCCESSFUL);
317 }
318
319 if (Acl->AclRevision != 2 &&
320 Acl->AclRevision != 3 )
321 {
322 return(STATUS_UNSUCCESSFUL);
323 }
324
325 }
326 #endif
327
328
329 /*
330 * @unimplemented
331 */
332 NTSTATUS STDCALL
333 SeAssignSecurity(PSECURITY_DESCRIPTOR ParentDescriptor OPTIONAL,
334 PSECURITY_DESCRIPTOR ExplicitDescriptor OPTIONAL,
335 PSECURITY_DESCRIPTOR *NewDescriptor,
336 BOOLEAN IsDirectoryObject,
337 PSECURITY_SUBJECT_CONTEXT SubjectContext,
338 PGENERIC_MAPPING GenericMapping,
339 POOL_TYPE PoolType)
340 {
341 PSECURITY_DESCRIPTOR Descriptor;
342 ULONG Length;
343 NTSTATUS Status;
344
345 if (ExplicitDescriptor != NULL)
346 {
347 Length = RtlLengthSecurityDescriptor(ExplicitDescriptor);
348 }
349 else
350 {
351 DPRINT("No explicit security descriptor\n");
352 return STATUS_UNSUCCESSFUL;
353 }
354
355 Descriptor = ExAllocatePool(NonPagedPool,
356 Length);
357 if (Descriptor == NULL)
358 {
359 DPRINT1("ExAlloctePool() failed\n");
360 return STATUS_UNSUCCESSFUL;
361 }
362
363 Status = RtlMakeSelfRelativeSD(ExplicitDescriptor,
364 Descriptor,
365 &Length);
366 if (!NT_SUCCESS(Status))
367 {
368 DPRINT1("RtlMakeSelfRelativeSD() failed (Status %lx)\n", Status);
369 return Status;
370 }
371
372 *NewDescriptor = Descriptor;
373
374 return STATUS_SUCCESS;
375
376 #if 0
377 PSID Owner;
378 PSID PrimaryGroup;
379 PACL DefaultDacl;
380 PSID ProcessOwner;
381 PSID ProcessPrimaryGroup;
382 PACL Sacl;
383
384 if (ExplicitDescriptor == NULL)
385 {
386 RtlCreateSecurityDescriptor(&Descriptor, 1);
387 }
388 else
389 {
390 Descriptor = ExplicitDescriptor;
391 }
392
393 SeLockSubjectContext(SubjectContext);
394
395 SepGetDefaultsSubjectContext(SubjectContext,
396 &Owner,
397 &PrimaryGroup,
398 &DefaultDacl,
399 &ProcessOwner,
400 &ProcessPrimaryGroup);
401
402 if (Descriptor->Control & SE_SACL_PRESENT ||
403 Descriptor->Control & SE_SACL_DEFAULTED)
404 {
405 if (ParentDescriptor == NULL)
406 {
407 }
408
409 if (Descriptor->Control & SE_SACL_PRESENT ||
410 Descriptor->Sacl == NULL ||)
411 {
412 Sacl = NULL;
413 }
414 else
415 {
416 Sacl = Descriptor->Sacl;
417 if (Descriptor->Control & SE_SELF_RELATIVE)
418 {
419 Sacl = (PACL)(((ULONG_PTR)Sacl) + (ULONG_PTR)Descriptor);
420 }
421 }
422
423 SepInheritAcl(Sacl,
424 IsDirectoryObject,
425 Owner,
426 PrimaryGroup,
427 DefaultDacl,
428 ProcessOwner,
429 GenericMapping);
430 }
431 #endif
432 }
433
434
435 static BOOLEAN
436 SepSidInToken(PACCESS_TOKEN Token,
437 PSID Sid)
438 {
439 ULONG i;
440
441 if (Token->UserAndGroupCount == 0)
442 {
443 return FALSE;
444 }
445
446 for (i=0; i<Token->UserAndGroupCount; i++)
447 {
448 if (RtlEqualSid(Sid, Token->UserAndGroups[i].Sid))
449 {
450 if (Token->UserAndGroups[i].Attributes & SE_GROUP_ENABLED)
451 {
452 return TRUE;
453 }
454
455 return FALSE;
456 }
457 }
458
459 return FALSE;
460 }
461
462
463 /*
464 * FUNCTION: Determines whether the requested access rights can be granted
465 * to an object protected by a security descriptor and an object owner
466 * ARGUMENTS:
467 * SecurityDescriptor = Security descriptor protecting the object
468 * SubjectSecurityContext = Subject's captured security context
469 * SubjectContextLocked = Indicates the user's subject context is locked
470 * DesiredAccess = Access rights the caller is trying to acquire
471 * PreviouslyGrantedAccess = Specified the access rights already granted
472 * Privileges = ?
473 * GenericMapping = Generic mapping associated with the object
474 * AccessMode = Access mode used for the check
475 * GrantedAccess (OUT) = On return specifies the access granted
476 * AccessStatus (OUT) = Status indicating why access was denied
477 * RETURNS: If access was granted, returns TRUE
478 *
479 * @implemented
480 */
481 BOOLEAN STDCALL
482 SeAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
483 IN PSECURITY_SUBJECT_CONTEXT SubjectSecurityContext,
484 IN BOOLEAN SubjectContextLocked,
485 IN ACCESS_MASK DesiredAccess,
486 IN ACCESS_MASK PreviouslyGrantedAccess,
487 OUT PPRIVILEGE_SET* Privileges,
488 IN PGENERIC_MAPPING GenericMapping,
489 IN KPROCESSOR_MODE AccessMode,
490 OUT PACCESS_MASK GrantedAccess,
491 OUT PNTSTATUS AccessStatus)
492 {
493 LUID_AND_ATTRIBUTES Privilege;
494 ACCESS_MASK CurrentAccess;
495 PACCESS_TOKEN Token;
496 ULONG i;
497 PACL Dacl;
498 BOOLEAN Present;
499 BOOLEAN Defaulted;
500 PACE CurrentAce;
501 PSID Sid;
502 NTSTATUS Status;
503
504 CurrentAccess = PreviouslyGrantedAccess;
505
506 Token = SubjectSecurityContext->ClientToken ?
507 SubjectSecurityContext->ClientToken : SubjectSecurityContext->PrimaryToken;
508
509 /* Get the DACL */
510 Status = RtlGetDaclSecurityDescriptor(SecurityDescriptor,
511 &Present,
512 &Dacl,
513 &Defaulted);
514 if (!NT_SUCCESS(Status))
515 {
516 *AccessStatus = Status;
517 return FALSE;
518 }
519
520 /* RULE 1: Grant desired access if the object is unprotected */
521 if (Dacl == NULL)
522 {
523 *GrantedAccess = DesiredAccess;
524 *AccessStatus = STATUS_SUCCESS;
525 return TRUE;
526 }
527
528 CurrentAccess = PreviouslyGrantedAccess;
529
530 /* RULE 2: Check token for 'take ownership' privilege */
531 Privilege.Luid = SeTakeOwnershipPrivilege;
532 Privilege.Attributes = SE_PRIVILEGE_ENABLED;
533
534 if (SepPrivilegeCheck(Token,
535 &Privilege,
536 1,
537 PRIVILEGE_SET_ALL_NECESSARY,
538 AccessMode))
539 {
540 CurrentAccess |= WRITE_OWNER;
541 if (DesiredAccess == CurrentAccess)
542 {
543 *GrantedAccess = CurrentAccess;
544 *AccessStatus = STATUS_SUCCESS;
545 return TRUE;
546 }
547 }
548
549 /* RULE 3: Check whether the token is the owner */
550 Status = RtlGetOwnerSecurityDescriptor(SecurityDescriptor,
551 &Sid,
552 &Defaulted);
553 if (!NT_SUCCESS(Status))
554 {
555 DPRINT1("RtlGetOwnerSecurityDescriptor() failed (Status %lx)\n", Status);
556 *AccessStatus = Status;
557 return FALSE;
558 }
559
560 if (SepSidInToken(Token, Sid))
561 {
562 CurrentAccess |= (READ_CONTROL | WRITE_DAC);
563 if (DesiredAccess == CurrentAccess)
564 {
565 *GrantedAccess = CurrentAccess;
566 *AccessStatus = STATUS_SUCCESS;
567 return TRUE;
568 }
569 }
570
571 /* RULE 4: Grant rights according to the DACL */
572 CurrentAce = (PACE)(Dacl + 1);
573 for (i = 0; i < Dacl->AceCount; i++)
574 {
575 Sid = (PSID)(CurrentAce + 1);
576 if (CurrentAce->Header.AceType == ACCESS_DENIED_ACE_TYPE)
577 {
578 if (SepSidInToken(Token, Sid))
579 {
580 *GrantedAccess = 0;
581 *AccessStatus = STATUS_ACCESS_DENIED;
582 return TRUE;
583 }
584 }
585
586 if (CurrentAce->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
587 {
588 if (SepSidInToken(Token, Sid))
589 {
590 CurrentAccess |= CurrentAce->AccessMask;
591 }
592 }
593 }
594
595 DPRINT("CurrentAccess %08lx\n DesiredAccess %08lx\n",
596 CurrentAccess, DesiredAccess);
597
598 *GrantedAccess = CurrentAccess & DesiredAccess;
599
600 *AccessStatus =
601 (*GrantedAccess == DesiredAccess) ? STATUS_SUCCESS : STATUS_ACCESS_DENIED;
602
603 return TRUE;
604 }
605
606
607 NTSTATUS STDCALL
608 NtAccessCheck(IN PSECURITY_DESCRIPTOR SecurityDescriptor,
609 IN HANDLE TokenHandle,
610 IN ACCESS_MASK DesiredAccess,
611 IN PGENERIC_MAPPING GenericMapping,
612 OUT PPRIVILEGE_SET PrivilegeSet,
613 OUT PULONG ReturnLength,
614 OUT PACCESS_MASK GrantedAccess,
615 OUT PNTSTATUS AccessStatus)
616 {
617 SECURITY_SUBJECT_CONTEXT SubjectSecurityContext;
618 KPROCESSOR_MODE PreviousMode;
619 PACCESS_TOKEN Token;
620 NTSTATUS Status;
621
622 DPRINT("NtAccessCheck() called\n");
623
624 PreviousMode = KeGetPreviousMode();
625 if (PreviousMode == KernelMode)
626 {
627 *GrantedAccess = DesiredAccess;
628 *AccessStatus = STATUS_SUCCESS;
629 return STATUS_SUCCESS;
630 }
631
632 Status = ObReferenceObjectByHandle(TokenHandle,
633 TOKEN_QUERY,
634 SepTokenObjectType,
635 PreviousMode,
636 (PVOID*)&Token,
637 NULL);
638 if (!NT_SUCCESS(Status))
639 {
640 DPRINT1("Failed to reference token (Status %lx)\n", Status);
641 return Status;
642 }
643
644 /* Check token type */
645 if (Token->TokenType != TokenImpersonation)
646 {
647 DPRINT1("No impersonation token\n");
648 ObDereferenceObject(Token);
649 return STATUS_ACCESS_VIOLATION;
650 }
651
652 /* Check impersonation level */
653 if (Token->ImpersonationLevel < SecurityAnonymous)
654 {
655 DPRINT1("Invalid impersonation level\n");
656 ObDereferenceObject(Token);
657 return STATUS_ACCESS_VIOLATION;
658 }
659
660 RtlZeroMemory(&SubjectSecurityContext,
661 sizeof(SECURITY_SUBJECT_CONTEXT));
662 SubjectSecurityContext.ClientToken = Token;
663 SubjectSecurityContext.ImpersonationLevel = Token->ImpersonationLevel;
664
665 /* FIXME: Lock subject context */
666
667 if (!SeAccessCheck(SecurityDescriptor,
668 &SubjectSecurityContext,
669 TRUE,
670 DesiredAccess,
671 0,
672 &PrivilegeSet,
673 GenericMapping,
674 PreviousMode,
675 GrantedAccess,
676 AccessStatus))
677 {
678 Status = *AccessStatus;
679 }
680 else
681 {
682 Status = STATUS_SUCCESS;
683 }
684
685 /* FIXME: Unlock subject context */
686
687 ObDereferenceObject(Token);
688
689 DPRINT("NtAccessCheck() done\n");
690
691 return Status;
692 }
693
694 /* EOF */