38296847940b119866e8ac3890ee4a8ae7b41d1b
[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
228 NTAPI
229 SepCreateImpersonationTokenDacl(
230 _In_ PTOKEN Token,
231 _In_ PTOKEN PrimaryToken,
232 _Out_ PACL* Dacl)
233 {
234 ULONG AclLength;
235 PACL TokenDacl;
236
237 PAGED_CODE();
238
239 *Dacl = NULL;
240
241 AclLength = sizeof(ACL) +
242 (sizeof(ACE) + RtlLengthSid(SeAliasAdminsSid)) +
243 (sizeof(ACE) + RtlLengthSid(SeLocalSystemSid)) +
244 (sizeof(ACE) + RtlLengthSid(SeRestrictedCodeSid)) +
245 (sizeof(ACE) + RtlLengthSid(Token->UserAndGroups->Sid)) +
246 (sizeof(ACE) + RtlLengthSid(PrimaryToken->UserAndGroups->Sid));
247
248 TokenDacl = ExAllocatePoolWithTag(PagedPool, AclLength, TAG_ACL);
249 if (TokenDacl == NULL)
250 {
251 return STATUS_INSUFFICIENT_RESOURCES;
252 }
253
254 RtlCreateAcl(TokenDacl, AclLength, ACL_REVISION);
255 RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL,
256 Token->UserAndGroups->Sid);
257 RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL,
258 PrimaryToken->UserAndGroups->Sid);
259 RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL,
260 SeAliasAdminsSid);
261 RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL,
262 SeLocalSystemSid);
263
264 if (Token->RestrictedSids != NULL || PrimaryToken->RestrictedSids != NULL)
265 {
266 RtlAddAccessAllowedAce(TokenDacl, ACL_REVISION, GENERIC_ALL,
267 SeRestrictedCodeSid);
268 }
269
270 *Dacl = TokenDacl;
271
272 return STATUS_SUCCESS;
273 }
274
275 NTSTATUS
276 NTAPI
277 SepCaptureAcl(IN PACL InputAcl,
278 IN KPROCESSOR_MODE AccessMode,
279 IN POOL_TYPE PoolType,
280 IN BOOLEAN CaptureIfKernel,
281 OUT PACL *CapturedAcl)
282 {
283 PACL NewAcl;
284 ULONG AclSize = 0;
285 NTSTATUS Status = STATUS_SUCCESS;
286
287 PAGED_CODE();
288
289 if (AccessMode != KernelMode)
290 {
291 _SEH2_TRY
292 {
293 ProbeForRead(InputAcl,
294 sizeof(ACL),
295 sizeof(ULONG));
296 AclSize = InputAcl->AclSize;
297 ProbeForRead(InputAcl,
298 AclSize,
299 sizeof(ULONG));
300 }
301 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
302 {
303 /* Return the exception code */
304 _SEH2_YIELD(return _SEH2_GetExceptionCode());
305 }
306 _SEH2_END;
307
308 NewAcl = ExAllocatePoolWithTag(PoolType,
309 AclSize,
310 TAG_ACL);
311 if (NewAcl != NULL)
312 {
313 _SEH2_TRY
314 {
315 RtlCopyMemory(NewAcl,
316 InputAcl,
317 AclSize);
318
319 *CapturedAcl = NewAcl;
320 }
321 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
322 {
323 /* Free the ACL and return the exception code */
324 ExFreePoolWithTag(NewAcl, TAG_ACL);
325 _SEH2_YIELD(return _SEH2_GetExceptionCode());
326 }
327 _SEH2_END;
328 }
329 else
330 {
331 Status = STATUS_INSUFFICIENT_RESOURCES;
332 }
333 }
334 else if (!CaptureIfKernel)
335 {
336 *CapturedAcl = InputAcl;
337 }
338 else
339 {
340 AclSize = InputAcl->AclSize;
341
342 NewAcl = ExAllocatePoolWithTag(PoolType,
343 AclSize,
344 TAG_ACL);
345
346 if (NewAcl != NULL)
347 {
348 RtlCopyMemory(NewAcl,
349 InputAcl,
350 AclSize);
351
352 *CapturedAcl = NewAcl;
353 }
354 else
355 {
356 Status = STATUS_INSUFFICIENT_RESOURCES;
357 }
358 }
359
360 return Status;
361 }
362
363 VOID
364 NTAPI
365 SepReleaseAcl(IN PACL CapturedAcl,
366 IN KPROCESSOR_MODE AccessMode,
367 IN BOOLEAN CaptureIfKernel)
368 {
369 PAGED_CODE();
370
371 if (CapturedAcl != NULL &&
372 (AccessMode != KernelMode ||
373 (AccessMode == KernelMode && CaptureIfKernel)))
374 {
375 ExFreePoolWithTag(CapturedAcl, TAG_ACL);
376 }
377 }
378
379 BOOLEAN
380 SepShouldPropagateAce(
381 _In_ UCHAR AceFlags,
382 _Out_ PUCHAR NewAceFlags,
383 _In_ BOOLEAN IsInherited,
384 _In_ BOOLEAN IsDirectoryObject)
385 {
386 if (!IsInherited)
387 {
388 *NewAceFlags = AceFlags;
389 return TRUE;
390 }
391
392 if (!IsDirectoryObject)
393 {
394 if (AceFlags & OBJECT_INHERIT_ACE)
395 {
396 *NewAceFlags = AceFlags & ~VALID_INHERIT_FLAGS;
397 return TRUE;
398 }
399 return FALSE;
400 }
401
402 if (AceFlags & NO_PROPAGATE_INHERIT_ACE)
403 {
404 if (AceFlags & CONTAINER_INHERIT_ACE)
405 {
406 *NewAceFlags = AceFlags & ~VALID_INHERIT_FLAGS;
407 return TRUE;
408 }
409 return FALSE;
410 }
411
412 if (AceFlags & CONTAINER_INHERIT_ACE)
413 {
414 *NewAceFlags = CONTAINER_INHERIT_ACE | (AceFlags & OBJECT_INHERIT_ACE) | (AceFlags & ~VALID_INHERIT_FLAGS);
415 return TRUE;
416 }
417
418 if (AceFlags & OBJECT_INHERIT_ACE)
419 {
420 *NewAceFlags = INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE | (AceFlags & ~VALID_INHERIT_FLAGS);
421 return TRUE;
422 }
423
424 return FALSE;
425 }
426
427 NTSTATUS
428 SepPropagateAcl(
429 _Out_writes_bytes_opt_(AclLength) PACL AclDest,
430 _Inout_ PULONG AclLength,
431 _In_reads_bytes_(AclSource->AclSize) PACL AclSource,
432 _In_ PSID Owner,
433 _In_ PSID Group,
434 _In_ BOOLEAN IsInherited,
435 _In_ BOOLEAN IsDirectoryObject,
436 _In_ PGENERIC_MAPPING GenericMapping)
437 {
438 ACCESS_MASK Mask;
439 PACCESS_ALLOWED_ACE AceSource;
440 PACCESS_ALLOWED_ACE AceDest;
441 PUCHAR CurrentDest;
442 PUCHAR CurrentSource;
443 ULONG i;
444 ULONG Written;
445 UCHAR AceFlags;
446 USHORT AceSize;
447 USHORT AceCount = 0;
448 PSID Sid;
449 BOOLEAN WriteTwoAces;
450
451 ASSERT(RtlValidAcl(AclSource));
452 ASSERT(AclSource->AclSize % sizeof(ULONG) == 0);
453 ASSERT(AclSource->Sbz1 == 0);
454 ASSERT(AclSource->Sbz2 == 0);
455
456 Written = 0;
457 if (*AclLength >= Written + sizeof(ACL))
458 {
459 RtlCopyMemory(AclDest,
460 AclSource,
461 sizeof(ACL));
462 }
463 Written += sizeof(ACL);
464
465 CurrentDest = (PUCHAR)(AclDest + 1);
466 CurrentSource = (PUCHAR)(AclSource + 1);
467 for (i = 0; i < AclSource->AceCount; i++)
468 {
469 ASSERT((ULONG_PTR)CurrentDest % sizeof(ULONG) == 0);
470 ASSERT((ULONG_PTR)CurrentSource % sizeof(ULONG) == 0);
471 AceDest = (PACCESS_ALLOWED_ACE)CurrentDest;
472 AceSource = (PACCESS_ALLOWED_ACE)CurrentSource;
473
474 if (AceSource->Header.AceType > ACCESS_MAX_MS_V2_ACE_TYPE)
475 {
476 /* FIXME: handle object & compound ACEs */
477 AceSize = AceSource->Header.AceSize;
478
479 if (*AclLength >= Written + AceSize)
480 {
481 RtlCopyMemory(AceDest, AceSource, AceSize);
482 }
483 CurrentDest += AceSize;
484 CurrentSource += AceSize;
485 Written += AceSize;
486 AceCount++;
487 continue;
488 }
489
490 /* These all have the same structure */
491 ASSERT(AceSource->Header.AceType == ACCESS_ALLOWED_ACE_TYPE ||
492 AceSource->Header.AceType == ACCESS_DENIED_ACE_TYPE ||
493 AceSource->Header.AceType == SYSTEM_AUDIT_ACE_TYPE ||
494 AceSource->Header.AceType == SYSTEM_ALARM_ACE_TYPE);
495
496 ASSERT(AceSource->Header.AceSize % sizeof(ULONG) == 0);
497 ASSERT(AceSource->Header.AceSize >= sizeof(*AceSource));
498 if (!SepShouldPropagateAce(AceSource->Header.AceFlags,
499 &AceFlags,
500 IsInherited,
501 IsDirectoryObject))
502 {
503 CurrentSource += AceSource->Header.AceSize;
504 continue;
505 }
506
507 /* FIXME: filter out duplicate ACEs */
508 AceSize = AceSource->Header.AceSize;
509 Mask = AceSource->Mask;
510 Sid = (PSID)&AceSource->SidStart;
511 ASSERT(AceSize >= FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(Sid));
512
513 WriteTwoAces = FALSE;
514 /* Map effective ACE to specific rights */
515 if (!(AceFlags & INHERIT_ONLY_ACE))
516 {
517 RtlMapGenericMask(&Mask, GenericMapping);
518 Mask &= GenericMapping->GenericAll;
519
520 if (IsInherited)
521 {
522 if (RtlEqualSid(Sid, SeCreatorOwnerSid))
523 Sid = Owner;
524 else if (RtlEqualSid(Sid, SeCreatorGroupSid))
525 Sid = Group;
526 AceSize = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(Sid);
527
528 /*
529 * A generic container ACE becomes two ACEs:
530 * - a specific effective ACE with no inheritance flags
531 * - an inherit-only ACE that keeps the generic rights
532 */
533 if (IsDirectoryObject &&
534 (AceFlags & CONTAINER_INHERIT_ACE) &&
535 (Mask != AceSource->Mask || Sid != (PSID)&AceSource->SidStart))
536 {
537 WriteTwoAces = TRUE;
538 }
539 }
540 }
541
542 while (1)
543 {
544 if (*AclLength >= Written + AceSize)
545 {
546 AceDest->Header.AceType = AceSource->Header.AceType;
547 AceDest->Header.AceFlags = WriteTwoAces ? AceFlags & ~VALID_INHERIT_FLAGS
548 : AceFlags;
549 AceDest->Header.AceSize = AceSize;
550 AceDest->Mask = Mask;
551 RtlCopySid(AceSize - FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart),
552 (PSID)&AceDest->SidStart,
553 Sid);
554 }
555 Written += AceSize;
556
557 AceCount++;
558 CurrentDest += AceSize;
559
560 if (!WriteTwoAces)
561 break;
562
563 /* Second ACE keeps all the generics from the source ACE */
564 WriteTwoAces = FALSE;
565 AceDest = (PACCESS_ALLOWED_ACE)CurrentDest;
566 AceSize = AceSource->Header.AceSize;
567 Mask = AceSource->Mask;
568 Sid = (PSID)&AceSource->SidStart;
569 AceFlags |= INHERIT_ONLY_ACE;
570 }
571
572 CurrentSource += AceSource->Header.AceSize;
573 }
574
575 if (*AclLength >= sizeof(ACL))
576 {
577 AclDest->AceCount = AceCount;
578 AclDest->AclSize = Written;
579 }
580
581 if (Written > *AclLength)
582 {
583 *AclLength = Written;
584 return STATUS_BUFFER_TOO_SMALL;
585 }
586 *AclLength = Written;
587 return STATUS_SUCCESS;
588 }
589
590 PACL
591 SepSelectAcl(
592 _In_opt_ PACL ExplicitAcl,
593 _In_ BOOLEAN ExplicitPresent,
594 _In_ BOOLEAN ExplicitDefaulted,
595 _In_opt_ PACL ParentAcl,
596 _In_opt_ PACL DefaultAcl,
597 _Out_ PULONG AclLength,
598 _In_ PSID Owner,
599 _In_ PSID Group,
600 _Out_ PBOOLEAN AclPresent,
601 _Out_ PBOOLEAN IsInherited,
602 _In_ BOOLEAN IsDirectoryObject,
603 _In_ PGENERIC_MAPPING GenericMapping)
604 {
605 PACL Acl;
606 NTSTATUS Status;
607
608 *AclPresent = TRUE;
609 if (ExplicitPresent && !ExplicitDefaulted)
610 {
611 Acl = ExplicitAcl;
612 }
613 else
614 {
615 if (ParentAcl)
616 {
617 *IsInherited = TRUE;
618 *AclLength = 0;
619 Status = SepPropagateAcl(NULL,
620 AclLength,
621 ParentAcl,
622 Owner,
623 Group,
624 *IsInherited,
625 IsDirectoryObject,
626 GenericMapping);
627 ASSERT(Status == STATUS_BUFFER_TOO_SMALL);
628
629 /* Use the parent ACL only if it's not empty */
630 if (*AclLength != sizeof(ACL))
631 return ParentAcl;
632 }
633
634 if (ExplicitPresent)
635 {
636 Acl = ExplicitAcl;
637 }
638 else if (DefaultAcl)
639 {
640 Acl = DefaultAcl;
641 }
642 else
643 {
644 *AclPresent = FALSE;
645 Acl = NULL;
646 }
647 }
648
649 *IsInherited = FALSE;
650 *AclLength = 0;
651 if (Acl)
652 {
653 /* Get the length */
654 Status = SepPropagateAcl(NULL,
655 AclLength,
656 Acl,
657 Owner,
658 Group,
659 *IsInherited,
660 IsDirectoryObject,
661 GenericMapping);
662 ASSERT(Status == STATUS_BUFFER_TOO_SMALL);
663 }
664 return Acl;
665 }
666
667 /* EOF */