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