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