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