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