[NTOS:INBV] Implement rotation bar for boot screen
[reactos.git] / ntoskrnl / se / acl.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/se/acl.c
5 * PURPOSE: Security manager
6 *
7 * PROGRAMMERS: David Welch <welch@cwcom.net>
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 #if defined (ALLOC_PRAGMA)
17 #pragma alloc_text(INIT, SepInitDACLs)
18 #endif
19
20 /* GLOBALS ********************************************************************/
21
22 PACL SePublicDefaultDacl = NULL;
23 PACL SeSystemDefaultDacl = NULL;
24 PACL SePublicDefaultUnrestrictedDacl = NULL;
25 PACL SePublicOpenDacl = NULL;
26 PACL SePublicOpenUnrestrictedDacl = NULL;
27 PACL SeUnrestrictedDacl = NULL;
28
29 /* FUNCTIONS ******************************************************************/
30
31 BOOLEAN
32 INIT_FUNCTION
33 NTAPI
34 SepInitDACLs(VOID)
35 {
36 ULONG AclLength;
37
38 /* create PublicDefaultDacl */
39 AclLength = sizeof(ACL) +
40 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) +
41 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
42 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid));
43
44 SePublicDefaultDacl = ExAllocatePoolWithTag(PagedPool,
45 AclLength,
46 TAG_ACL);
47 if (SePublicDefaultDacl == NULL)
48 return FALSE;
49
50 RtlCreateAcl(SePublicDefaultDacl,
51 AclLength,
52 ACL_REVISION);
53
54 RtlAddAccessAllowedAce(SePublicDefaultDacl,
55 ACL_REVISION,
56 GENERIC_EXECUTE,
57 SeWorldSid);
58
59 RtlAddAccessAllowedAce(SePublicDefaultDacl,
60 ACL_REVISION,
61 GENERIC_ALL,
62 SeLocalSystemSid);
63
64 RtlAddAccessAllowedAce(SePublicDefaultDacl,
65 ACL_REVISION,
66 GENERIC_ALL,
67 SeAliasAdminsSid);
68
69 /* create PublicDefaultUnrestrictedDacl */
70 AclLength = sizeof(ACL) +
71 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) +
72 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
73 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)) +
74 (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid));
75
76 SePublicDefaultUnrestrictedDacl = ExAllocatePoolWithTag(PagedPool,
77 AclLength,
78 TAG_ACL);
79 if (SePublicDefaultUnrestrictedDacl == NULL)
80 return FALSE;
81
82 RtlCreateAcl(SePublicDefaultUnrestrictedDacl,
83 AclLength,
84 ACL_REVISION);
85
86 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl,
87 ACL_REVISION,
88 GENERIC_EXECUTE,
89 SeWorldSid);
90
91 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl,
92 ACL_REVISION,
93 GENERIC_ALL,
94 SeLocalSystemSid);
95
96 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl,
97 ACL_REVISION,
98 GENERIC_ALL,
99 SeAliasAdminsSid);
100
101 RtlAddAccessAllowedAce(SePublicDefaultUnrestrictedDacl,
102 ACL_REVISION,
103 GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL,
104 SeRestrictedCodeSid);
105
106 /* create PublicOpenDacl */
107 AclLength = sizeof(ACL) +
108 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) +
109 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
110 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid));
111
112 SePublicOpenDacl = ExAllocatePoolWithTag(PagedPool,
113 AclLength,
114 TAG_ACL);
115 if (SePublicOpenDacl == NULL)
116 return FALSE;
117
118 RtlCreateAcl(SePublicOpenDacl,
119 AclLength,
120 ACL_REVISION);
121
122 RtlAddAccessAllowedAce(SePublicOpenDacl,
123 ACL_REVISION,
124 GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE,
125 SeWorldSid);
126
127 RtlAddAccessAllowedAce(SePublicOpenDacl,
128 ACL_REVISION,
129 GENERIC_ALL,
130 SeLocalSystemSid);
131
132 RtlAddAccessAllowedAce(SePublicOpenDacl,
133 ACL_REVISION,
134 GENERIC_ALL,
135 SeAliasAdminsSid);
136
137 /* create PublicOpenUnrestrictedDacl */
138 AclLength = sizeof(ACL) +
139 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) +
140 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
141 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)) +
142 (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid));
143
144 SePublicOpenUnrestrictedDacl = ExAllocatePoolWithTag(PagedPool,
145 AclLength,
146 TAG_ACL);
147 if (SePublicOpenUnrestrictedDacl == NULL)
148 return FALSE;
149
150 RtlCreateAcl(SePublicOpenUnrestrictedDacl,
151 AclLength,
152 ACL_REVISION);
153
154 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl,
155 ACL_REVISION,
156 GENERIC_ALL,
157 SeWorldSid);
158
159 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl,
160 ACL_REVISION,
161 GENERIC_ALL,
162 SeLocalSystemSid);
163
164 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl,
165 ACL_REVISION,
166 GENERIC_ALL,
167 SeAliasAdminsSid);
168
169 RtlAddAccessAllowedAce(SePublicOpenUnrestrictedDacl,
170 ACL_REVISION,
171 GENERIC_READ | GENERIC_EXECUTE,
172 SeRestrictedCodeSid);
173
174 /* create SystemDefaultDacl */
175 AclLength = sizeof(ACL) +
176 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
177 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid));
178
179 SeSystemDefaultDacl = ExAllocatePoolWithTag(PagedPool,
180 AclLength,
181 TAG_ACL);
182 if (SeSystemDefaultDacl == NULL)
183 return FALSE;
184
185 RtlCreateAcl(SeSystemDefaultDacl,
186 AclLength,
187 ACL_REVISION);
188
189 RtlAddAccessAllowedAce(SeSystemDefaultDacl,
190 ACL_REVISION,
191 GENERIC_ALL,
192 SeLocalSystemSid);
193
194 RtlAddAccessAllowedAce(SeSystemDefaultDacl,
195 ACL_REVISION,
196 GENERIC_READ | GENERIC_EXECUTE | READ_CONTROL,
197 SeAliasAdminsSid);
198
199 /* create UnrestrictedDacl */
200 AclLength = sizeof(ACL) +
201 (sizeof(ACE) + RtlLengthSid(SeWorldSid)) +
202 (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid));
203
204 SeUnrestrictedDacl = ExAllocatePoolWithTag(PagedPool,
205 AclLength,
206 TAG_ACL);
207 if (SeUnrestrictedDacl == NULL)
208 return FALSE;
209
210 RtlCreateAcl(SeUnrestrictedDacl,
211 AclLength,
212 ACL_REVISION);
213
214 RtlAddAccessAllowedAce(SeUnrestrictedDacl,
215 ACL_REVISION,
216 GENERIC_ALL,
217 SeWorldSid);
218
219 RtlAddAccessAllowedAce(SeUnrestrictedDacl,
220 ACL_REVISION,
221 GENERIC_READ | GENERIC_EXECUTE,
222 SeRestrictedCodeSid);
223
224 return TRUE;
225 }
226
227 NTSTATUS NTAPI
228 SepCreateImpersonationTokenDacl(PTOKEN Token,
229 PTOKEN PrimaryToken,
230 PACL *Dacl)
231 {
232 ULONG AclLength;
233 PVOID TokenDacl;
234
235 PAGED_CODE();
236
237 AclLength = sizeof(ACL) +
238 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)) +
239 (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid)) +
240 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
241 (sizeof(ACE) + RtlLengthSid(Token->UserAndGroups->Sid)) +
242 (sizeof(ACE) + RtlLengthSid(PrimaryToken->UserAndGroups->Sid));
243
244 TokenDacl = ExAllocatePoolWithTag(PagedPool, AclLength, TAG_ACL);
245 if (TokenDacl == NULL)
246 {
247 return STATUS_INSUFFICIENT_RESOURCES;
248 }
249
250 RtlCreateAcl(TokenDacl, AclLength, ACL_REVISION);
251 RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL,
252 Token->UserAndGroups->Sid);
253 RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL,
254 PrimaryToken->UserAndGroups->Sid);
255 RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL,
256 SeAliasAdminsSid);
257 RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL,
258 SeLocalSystemSid);
259
260 /* FIXME */
261 #if 0
262 if (Token->RestrictedSids != NULL || PrimaryToken->RestrictedSids != NULL)
263 {
264 RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL,
265 SeRestrictedCodeSid);
266 }
267 #endif
268
269 return STATUS_SUCCESS;
270 }
271
272 NTSTATUS
273 NTAPI
274 SepCaptureAcl(IN PACL InputAcl,
275 IN KPROCESSOR_MODE AccessMode,
276 IN POOL_TYPE PoolType,
277 IN BOOLEAN CaptureIfKernel,
278 OUT PACL *CapturedAcl)
279 {
280 PACL NewAcl;
281 ULONG AclSize = 0;
282 NTSTATUS Status = STATUS_SUCCESS;
283
284 PAGED_CODE();
285
286 if (AccessMode != KernelMode)
287 {
288 _SEH2_TRY
289 {
290 ProbeForRead(InputAcl,
291 sizeof(ACL),
292 sizeof(ULONG));
293 AclSize = InputAcl->AclSize;
294 ProbeForRead(InputAcl,
295 AclSize,
296 sizeof(ULONG));
297 }
298 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
299 {
300 /* Return the exception code */
301 _SEH2_YIELD(return _SEH2_GetExceptionCode());
302 }
303 _SEH2_END;
304
305 NewAcl = ExAllocatePoolWithTag(PoolType,
306 AclSize,
307 TAG_ACL);
308 if (NewAcl != NULL)
309 {
310 _SEH2_TRY
311 {
312 RtlCopyMemory(NewAcl,
313 InputAcl,
314 AclSize);
315
316 *CapturedAcl = NewAcl;
317 }
318 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
319 {
320 /* Free the ACL and return the exception code */
321 ExFreePoolWithTag(NewAcl, TAG_ACL);
322 _SEH2_YIELD(return _SEH2_GetExceptionCode());
323 }
324 _SEH2_END;
325 }
326 else
327 {
328 Status = STATUS_INSUFFICIENT_RESOURCES;
329 }
330 }
331 else if (!CaptureIfKernel)
332 {
333 *CapturedAcl = InputAcl;
334 }
335 else
336 {
337 AclSize = InputAcl->AclSize;
338
339 NewAcl = ExAllocatePoolWithTag(PoolType,
340 AclSize,
341 TAG_ACL);
342
343 if (NewAcl != NULL)
344 {
345 RtlCopyMemory(NewAcl,
346 InputAcl,
347 AclSize);
348
349 *CapturedAcl = NewAcl;
350 }
351 else
352 {
353 Status = STATUS_INSUFFICIENT_RESOURCES;
354 }
355 }
356
357 return Status;
358 }
359
360 VOID
361 NTAPI
362 SepReleaseAcl(IN PACL CapturedAcl,
363 IN KPROCESSOR_MODE AccessMode,
364 IN BOOLEAN CaptureIfKernel)
365 {
366 PAGED_CODE();
367
368 if (CapturedAcl != NULL &&
369 (AccessMode != KernelMode ||
370 (AccessMode == KernelMode && CaptureIfKernel)))
371 {
372 ExFreePoolWithTag(CapturedAcl, TAG_ACL);
373 }
374 }
375
376 BOOLEAN
377 SepShouldPropagateAce(
378 _In_ UCHAR AceFlags,
379 _Out_ PUCHAR NewAceFlags,
380 _In_ BOOLEAN IsInherited,
381 _In_ BOOLEAN IsDirectoryObject)
382 {
383 if (!IsInherited)
384 {
385 *NewAceFlags = AceFlags;
386 return TRUE;
387 }
388
389 if (!IsDirectoryObject)
390 {
391 if (AceFlags & OBJECT_INHERIT_ACE)
392 {
393 *NewAceFlags = AceFlags & ~VALID_INHERIT_FLAGS;
394 return TRUE;
395 }
396 return FALSE;
397 }
398
399 if (AceFlags & NO_PROPAGATE_INHERIT_ACE)
400 {
401 if (AceFlags & CONTAINER_INHERIT_ACE)
402 {
403 *NewAceFlags = AceFlags & ~VALID_INHERIT_FLAGS;
404 return TRUE;
405 }
406 return FALSE;
407 }
408
409 if (AceFlags & CONTAINER_INHERIT_ACE)
410 {
411 *NewAceFlags = CONTAINER_INHERIT_ACE | (AceFlags & OBJECT_INHERIT_ACE) | (AceFlags & ~VALID_INHERIT_FLAGS);
412 return TRUE;
413 }
414
415 if (AceFlags & OBJECT_INHERIT_ACE)
416 {
417 *NewAceFlags = INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | (AceFlags & ~VALID_INHERIT_FLAGS);
418 return TRUE;
419 }
420
421 return FALSE;
422 }
423
424 NTSTATUS
425 SepPropagateAcl(
426 _Out_writes_bytes_opt_(AclLength) PACL AclDest,
427 _Inout_ PULONG AclLength,
428 _In_reads_bytes_(AclSource->AclSize) PACL AclSource,
429 _In_ PSID Owner,
430 _In_ PSID Group,
431 _In_ BOOLEAN IsInherited,
432 _In_ BOOLEAN IsDirectoryObject,
433 _In_ PGENERIC_MAPPING GenericMapping)
434 {
435 ACCESS_MASK Mask;
436 PACCESS_ALLOWED_ACE AceSource;
437 PACCESS_ALLOWED_ACE AceDest;
438 PUCHAR CurrentDest;
439 PUCHAR CurrentSource;
440 ULONG i;
441 ULONG Written;
442 UCHAR AceFlags;
443 USHORT AceSize;
444 USHORT AceCount = 0;
445 PSID Sid;
446 BOOLEAN WriteTwoAces;
447
448 ASSERT(RtlValidAcl(AclSource));
449 ASSERT(AclSource->AclSize % sizeof(ULONG) == 0);
450 ASSERT(AclSource->Sbz1 == 0);
451 ASSERT(AclSource->Sbz2 == 0);
452
453 Written = 0;
454 if (*AclLength >= Written + sizeof(ACL))
455 {
456 RtlCopyMemory(AclDest,
457 AclSource,
458 sizeof(ACL));
459 }
460 Written += sizeof(ACL);
461
462 CurrentDest = (PUCHAR)(AclDest + 1);
463 CurrentSource = (PUCHAR)(AclSource + 1);
464 for (i = 0; i < AclSource->AceCount; i++)
465 {
466 ASSERT((ULONG_PTR)CurrentDest % sizeof(ULONG) == 0);
467 ASSERT((ULONG_PTR)CurrentSource % sizeof(ULONG) == 0);
468 AceDest = (PACCESS_ALLOWED_ACE)CurrentDest;
469 AceSource = (PACCESS_ALLOWED_ACE)CurrentSource;
470
471 if (AceSource->Header.AceType > ACCESS_MAX_MS_V2_ACE_TYPE)
472 {
473 /* FIXME: handle object & compound ACEs */
474 AceSize = AceSource->Header.AceSize;
475
476 if (*AclLength >= Written + AceSize)
477 {
478 RtlCopyMemory(AceDest, AceSource, AceSize);
479 }
480 CurrentDest += AceSize;
481 CurrentSource += AceSize;
482 Written += AceSize;
483 AceCount++;
484 continue;
485 }
486
487 /* These all have the same structure */
488 ASSERT(AceSource->Header.AceType == ACCESS_ALLOWED_ACE_TYPE ||
489 AceSource->Header.AceType == ACCESS_DENIED_ACE_TYPE ||
490 AceSource->Header.AceType == SYSTEM_AUDIT_ACE_TYPE ||
491 AceSource->Header.AceType == SYSTEM_ALARM_ACE_TYPE);
492
493 ASSERT(AceSource->Header.AceSize % sizeof(ULONG) == 0);
494 ASSERT(AceSource->Header.AceSize >= sizeof(*AceSource));
495 if (!SepShouldPropagateAce(AceSource->Header.AceFlags,
496 &AceFlags,
497 IsInherited,
498 IsDirectoryObject))
499 {
500 CurrentSource += AceSource->Header.AceSize;
501 continue;
502 }
503
504 /* FIXME: filter out duplicate ACEs */
505 AceSize = AceSource->Header.AceSize;
506 Mask = AceSource->Mask;
507 Sid = (PSID)&AceSource->SidStart;
508 ASSERT(AceSize >= FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(Sid));
509
510 WriteTwoAces = FALSE;
511 /* Map effective ACE to specific rights */
512 if (!(AceFlags & INHERIT_ONLY_ACE))
513 {
514 RtlMapGenericMask(&Mask, GenericMapping);
515 Mask &= GenericMapping->GenericAll;
516
517 if (IsInherited)
518 {
519 if (RtlEqualSid(Sid, SeCreatorOwnerSid))
520 Sid = Owner;
521 else if (RtlEqualSid(Sid, SeCreatorGroupSid))
522 Sid = Group;
523 AceSize = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(Sid);
524
525 /*
526 * A generic container ACE becomes two ACEs:
527 * - a specific effective ACE with no inheritance flags
528 * - an inherit-only ACE that keeps the generic rights
529 */
530 if (IsDirectoryObject &&
531 (AceFlags & CONTAINER_INHERIT_ACE) &&
532 (Mask != AceSource->Mask || Sid != (PSID)&AceSource->SidStart))
533 {
534 WriteTwoAces = TRUE;
535 }
536 }
537 }
538
539 while (1)
540 {
541 if (*AclLength >= Written + AceSize)
542 {
543 AceDest->Header.AceType = AceSource->Header.AceType;
544 AceDest->Header.AceFlags = WriteTwoAces ? AceFlags & ~VALID_INHERIT_FLAGS
545 : AceFlags;
546 AceDest->Header.AceSize = AceSize;
547 AceDest->Mask = Mask;
548 RtlCopySid(AceSize - FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart),
549 (PSID)&AceDest->SidStart,
550 Sid);
551 }
552 Written += AceSize;
553
554 AceCount++;
555 CurrentDest += AceSize;
556
557 if (!WriteTwoAces)
558 break;
559
560 /* Second ACE keeps all the generics from the source ACE */
561 WriteTwoAces = FALSE;
562 AceDest = (PACCESS_ALLOWED_ACE)CurrentDest;
563 AceSize = AceSource->Header.AceSize;
564 Mask = AceSource->Mask;
565 Sid = (PSID)&AceSource->SidStart;
566 AceFlags |= INHERIT_ONLY_ACE;
567 }
568
569 CurrentSource += AceSource->Header.AceSize;
570 }
571
572 if (*AclLength >= sizeof(ACL))
573 {
574 AclDest->AceCount = AceCount;
575 AclDest->AclSize = Written;
576 }
577
578 if (Written > *AclLength)
579 {
580 *AclLength = Written;
581 return STATUS_BUFFER_TOO_SMALL;
582 }
583 *AclLength = Written;
584 return STATUS_SUCCESS;
585 }
586
587 PACL
588 SepSelectAcl(
589 _In_opt_ PACL ExplicitAcl,
590 _In_ BOOLEAN ExplicitPresent,
591 _In_ BOOLEAN ExplicitDefaulted,
592 _In_opt_ PACL ParentAcl,
593 _In_opt_ PACL DefaultAcl,
594 _Out_ PULONG AclLength,
595 _In_ PSID Owner,
596 _In_ PSID Group,
597 _Out_ PBOOLEAN AclPresent,
598 _Out_ PBOOLEAN IsInherited,
599 _In_ BOOLEAN IsDirectoryObject,
600 _In_ PGENERIC_MAPPING GenericMapping)
601 {
602 PACL Acl;
603 NTSTATUS Status;
604
605 *AclPresent = TRUE;
606 if (ExplicitPresent && !ExplicitDefaulted)
607 {
608 Acl = ExplicitAcl;
609 }
610 else
611 {
612 if (ParentAcl)
613 {
614 *IsInherited = TRUE;
615 *AclLength = 0;
616 Status = SepPropagateAcl(NULL,
617 AclLength,
618 ParentAcl,
619 Owner,
620 Group,
621 *IsInherited,
622 IsDirectoryObject,
623 GenericMapping);
624 ASSERT(Status == STATUS_BUFFER_TOO_SMALL);
625
626 /* Use the parent ACL only if it's not empty */
627 if (*AclLength != sizeof(ACL))
628 return ParentAcl;
629 }
630
631 if (ExplicitPresent)
632 {
633 Acl = ExplicitAcl;
634 }
635 else if (DefaultAcl)
636 {
637 Acl = DefaultAcl;
638 }
639 else
640 {
641 *AclPresent = FALSE;
642 Acl = NULL;
643 }
644 }
645
646 *IsInherited = FALSE;
647 *AclLength = 0;
648 if (Acl)
649 {
650 /* Get the length */
651 Status = SepPropagateAcl(NULL,
652 AclLength,
653 Acl,
654 Owner,
655 Group,
656 *IsInherited,
657 IsDirectoryObject,
658 GenericMapping);
659 ASSERT(Status == STATUS_BUFFER_TOO_SMALL);
660 }
661 return Acl;
662 }
663
664 /* EOF */