[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 /* These all have the same structure */
466 ASSERT(AceSource->Header.AceType == ACCESS_ALLOWED_ACE_TYPE ||
467 AceSource->Header.AceType == ACCESS_DENIED_ACE_TYPE ||
468 AceSource->Header.AceType == SYSTEM_AUDIT_ACE_TYPE);
469
470 ASSERT(AceSource->Header.AceSize % sizeof(ULONG) == 0);
471 ASSERT(AceSource->Header.AceSize >= sizeof(*AceSource));
472 if (!SepShouldPropagateAce(AceSource->Header.AceFlags,
473 &AceFlags,
474 IsInherited,
475 IsDirectoryObject))
476 {
477 CurrentSource += AceSource->Header.AceSize;
478 continue;
479 }
480
481 /* FIXME: filter out duplicate ACEs */
482 AceSize = AceSource->Header.AceSize;
483 Mask = AceSource->Mask;
484 Sid = (PSID)&AceSource->SidStart;
485 ASSERT(AceSize >= FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(Sid));
486
487 WriteTwoAces = FALSE;
488 /* Map effective ACE to specific rights */
489 if (!(AceFlags & INHERIT_ONLY_ACE))
490 {
491 RtlMapGenericMask(&Mask, GenericMapping);
492 Mask &= GenericMapping->GenericAll;
493
494 if (IsInherited)
495 {
496 if (RtlEqualSid(Sid, SeCreatorOwnerSid))
497 Sid = Owner;
498 else if (RtlEqualSid(Sid, SeCreatorGroupSid))
499 Sid = Group;
500 AceSize = FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + RtlLengthSid(Sid);
501
502 /*
503 * A generic container ACE becomes two ACEs:
504 * - a specific effective ACE with no inheritance flags
505 * - an inherit-only ACE that keeps the generic rights
506 */
507 if (IsDirectoryObject &&
508 (AceFlags & CONTAINER_INHERIT_ACE) &&
509 (Mask != AceSource->Mask || Sid != (PSID)&AceSource->SidStart))
510 {
511 WriteTwoAces = TRUE;
512 }
513 }
514 }
515
516 while (1)
517 {
518 if (*AclLength >= Written + AceSize)
519 {
520 AceDest->Header.AceType = AceSource->Header.AceType;
521 AceDest->Header.AceFlags = WriteTwoAces ? AceFlags & ~VALID_INHERIT_FLAGS
522 : AceFlags;
523 AceDest->Header.AceSize = AceSize;
524 AceDest->Mask = Mask;
525 RtlCopySid(AceSize - FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart),
526 (PSID)&AceDest->SidStart,
527 Sid);
528 }
529 Written += AceSize;
530
531 AceCount++;
532 CurrentDest += AceSize;
533
534 if (!WriteTwoAces)
535 break;
536
537 /* Second ACE keeps all the generics from the source ACE */
538 WriteTwoAces = FALSE;
539 AceDest = (PACCESS_ALLOWED_ACE)CurrentDest;
540 AceSize = AceSource->Header.AceSize;
541 Mask = AceSource->Mask;
542 Sid = (PSID)&AceSource->SidStart;
543 AceFlags |= INHERIT_ONLY_ACE;
544 }
545
546 CurrentSource += AceSource->Header.AceSize;
547 }
548
549 if (*AclLength >= sizeof(ACL))
550 {
551 AclDest->AceCount = AceCount;
552 AclDest->AclSize = Written;
553 }
554
555 if (Written > *AclLength)
556 {
557 *AclLength = Written;
558 return STATUS_BUFFER_TOO_SMALL;
559 }
560 *AclLength = Written;
561 return STATUS_SUCCESS;
562 }
563
564 PACL
565 SepSelectAcl(
566 _In_opt_ PACL ExplicitAcl,
567 _In_ BOOLEAN ExplicitPresent,
568 _In_ BOOLEAN ExplicitDefaulted,
569 _In_opt_ PACL ParentAcl,
570 _In_opt_ PACL DefaultAcl,
571 _Out_ PULONG AclLength,
572 _In_ PSID Owner,
573 _In_ PSID Group,
574 _Out_ PBOOLEAN AclPresent,
575 _Out_ PBOOLEAN IsInherited,
576 _In_ BOOLEAN IsDirectoryObject,
577 _In_ PGENERIC_MAPPING GenericMapping)
578 {
579 PACL Acl;
580 NTSTATUS Status;
581
582 *AclPresent = TRUE;
583 if (ExplicitPresent && !ExplicitDefaulted)
584 {
585 Acl = ExplicitAcl;
586 }
587 else
588 {
589 if (ParentAcl)
590 {
591 *IsInherited = TRUE;
592 *AclLength = 0;
593 Status = SepPropagateAcl(NULL,
594 AclLength,
595 ParentAcl,
596 Owner,
597 Group,
598 *IsInherited,
599 IsDirectoryObject,
600 GenericMapping);
601 ASSERT(Status == STATUS_BUFFER_TOO_SMALL);
602
603 /* Use the parent ACL only if it's not empty */
604 if (*AclLength != sizeof(ACL))
605 return ParentAcl;
606 }
607
608 if (ExplicitPresent)
609 {
610 Acl = ExplicitAcl;
611 }
612 else if (DefaultAcl)
613 {
614 Acl = DefaultAcl;
615 }
616 else
617 {
618 *AclPresent = FALSE;
619 Acl = NULL;
620 }
621 }
622
623 *IsInherited = FALSE;
624 *AclLength = 0;
625 if (Acl)
626 {
627 /* Get the length */
628 Status = SepPropagateAcl(NULL,
629 AclLength,
630 Acl,
631 Owner,
632 Group,
633 *IsInherited,
634 IsDirectoryObject,
635 GenericMapping);
636 ASSERT(Status == STATUS_BUFFER_TOO_SMALL);
637 }
638 return Acl;
639 }
640
641 /* EOF */