1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * PURPOSE: Boot Data implementation
5 * FILE: lib/rtl/bootdata.c
6 * PROGRAMMERS:
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <rtl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* FUNCTIONS *****************************************************************/
16
17 static SID_IDENTIFIER_AUTHORITY LocalSystemAuthority = {SECURITY_NT_AUTHORITY};
18
19 static NTSTATUS
RtlpSysVolCreateSecurityDescriptor(OUT PISECURITY_DESCRIPTOR * SecurityDescriptor,OUT PSID * SystemSid)20 RtlpSysVolCreateSecurityDescriptor(OUT PISECURITY_DESCRIPTOR *SecurityDescriptor,
21 OUT PSID *SystemSid)
22 {
23 PSECURITY_DESCRIPTOR AbsSD = NULL;
24 PSID LocalSystemSid = NULL;
25 PACL Dacl = NULL;
26 ULONG DaclSize;
27 NTSTATUS Status;
28
29 /* create the local SYSTEM SID */
30 Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
31 1,
32 SECURITY_LOCAL_SYSTEM_RID,
33 0,
34 0,
35 0,
36 0,
37 0,
38 0,
39 0,
40 &LocalSystemSid);
41 if (!NT_SUCCESS(Status))
42 {
43 return Status;
44 }
45
46 /* allocate and initialize the security descriptor */
47 AbsSD = RtlpAllocateMemory(sizeof(SECURITY_DESCRIPTOR),
48 'dSeS');
49 if (AbsSD == NULL)
50 {
51 Status = STATUS_NO_MEMORY;
52 goto Cleanup;
53 }
54
55 Status = RtlCreateSecurityDescriptor(AbsSD,
56 SECURITY_DESCRIPTOR_REVISION);
57 if (!NT_SUCCESS(Status))
58 {
59 goto Cleanup;
60 }
61
62 /* allocate and create the DACL */
63 DaclSize = sizeof(ACL) + sizeof(ACE) +
64 RtlLengthSid(LocalSystemSid);
65 Dacl = RtlpAllocateMemory(DaclSize,
66 'cAeS');
67 if (Dacl == NULL)
68 {
69 Status = STATUS_NO_MEMORY;
70 goto Cleanup;
71 }
72
73 Status = RtlCreateAcl(Dacl,
74 DaclSize,
75 ACL_REVISION);
76 if (!NT_SUCCESS(Status))
77 {
78 goto Cleanup;
79 }
80
81 Status = RtlAddAccessAllowedAceEx(Dacl,
82 ACL_REVISION,
83 OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE,
84 STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
85 LocalSystemSid);
86 if (!NT_SUCCESS(Status))
87 {
88 goto Cleanup;
89 }
90
91 /* set the DACL in the security descriptor */
92 Status = RtlSetDaclSecurityDescriptor(AbsSD,
93 TRUE,
94 Dacl,
95 FALSE);
96
97 /* all done */
98 if (NT_SUCCESS(Status))
99 {
100 *SecurityDescriptor = AbsSD;
101 *SystemSid = LocalSystemSid;
102 }
103 else
104 {
105 Cleanup:
106 if (LocalSystemSid != NULL)
107 {
108 RtlFreeSid(LocalSystemSid);
109 }
110
111 if (Dacl != NULL)
112 {
113 RtlpFreeMemory(Dacl,
114 'cAeS');
115 }
116
117 if (AbsSD != NULL)
118 {
119 RtlpFreeMemory(AbsSD,
120 'dSeS');
121 }
122 }
123
124 return Status;
125 }
126
127 static NTSTATUS
RtlpSysVolCheckOwnerAndSecurity(IN HANDLE DirectoryHandle,IN PISECURITY_DESCRIPTOR SecurityDescriptor)128 RtlpSysVolCheckOwnerAndSecurity(IN HANDLE DirectoryHandle,
129 IN PISECURITY_DESCRIPTOR SecurityDescriptor)
130 {
131 PSECURITY_DESCRIPTOR RelSD = NULL;
132 PSECURITY_DESCRIPTOR NewRelSD = NULL;
133 PSECURITY_DESCRIPTOR AbsSD = NULL;
134 #ifdef _WIN64
135 BOOLEAN AbsSDAllocated = FALSE;
136 #endif
137 PSID AdminSid = NULL;
138 PSID LocalSystemSid = NULL;
139 ULONG DescriptorSize;
140 ULONG AbsSDSize, RelSDSize = 0;
141 PACL Dacl;
142 BOOLEAN DaclPresent, DaclDefaulted;
143 PSID OwnerSid;
144 BOOLEAN OwnerDefaulted;
145 ULONG AceIndex;
146 PACE Ace = NULL;
147 NTSTATUS Status;
148
149 /* find out how much memory we need to allocate for the self-relative
150 descriptor we're querying */
151 Status = ZwQuerySecurityObject(DirectoryHandle,
152 OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
153 NULL,
154 0,
155 &DescriptorSize);
156 if (Status != STATUS_BUFFER_TOO_SMALL)
157 {
158 /* looks like the FS doesn't support security... return success */
159 Status = STATUS_SUCCESS;
160 goto Cleanup;
161 }
162
163 /* allocate enough memory for the security descriptor */
164 RelSD = RtlpAllocateMemory(DescriptorSize,
165 'dSeS');
166 if (RelSD == NULL)
167 {
168 Status = STATUS_NO_MEMORY;
169 goto Cleanup;
170 }
171
172 /* query the self-relative security descriptor */
173 Status = ZwQuerySecurityObject(DirectoryHandle,
174 OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
175 RelSD,
176 DescriptorSize,
177 &DescriptorSize);
178 if (!NT_SUCCESS(Status))
179 {
180 /* FIXME - handle the case where someone else modified the owner and/or
181 DACL while we allocated memory. But that should be *very*
182 unlikely.... */
183 goto Cleanup;
184 }
185
186 /* query the owner and DACL from the descriptor */
187 Status = RtlGetOwnerSecurityDescriptor(RelSD,
188 &OwnerSid,
189 &OwnerDefaulted);
190 if (!NT_SUCCESS(Status))
191 {
192 goto Cleanup;
193 }
194
195 Status = RtlGetDaclSecurityDescriptor(RelSD,
196 &DaclPresent,
197 &Dacl,
198 &DaclDefaulted);
199 if (!NT_SUCCESS(Status))
200 {
201 goto Cleanup;
202 }
203
204 /* create the Administrators SID */
205 Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
206 2,
207 SECURITY_BUILTIN_DOMAIN_RID,
208 DOMAIN_ALIAS_RID_ADMINS,
209 0,
210 0,
211 0,
212 0,
213 0,
214 0,
215 &AdminSid);
216 if (!NT_SUCCESS(Status))
217 {
218 goto Cleanup;
219 }
220
221 /* create the local SYSTEM SID */
222 Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
223 1,
224 SECURITY_LOCAL_SYSTEM_RID,
225 0,
226 0,
227 0,
228 0,
229 0,
230 0,
231 0,
232 &LocalSystemSid);
233 if (!NT_SUCCESS(Status))
234 {
235 goto Cleanup;
236 }
237
238 /* check if the Administrators are the owner and at least a not-NULL DACL
239 is present */
240 if (OwnerSid != NULL &&
241 RtlEqualSid(OwnerSid,
242 AdminSid) &&
243 DaclPresent && Dacl != NULL)
244 {
245 /* check the DACL for an Allowed ACE for the SYSTEM account */
246 AceIndex = 0;
247 do
248 {
249 Status = RtlGetAce(Dacl,
250 AceIndex++,
251 (PVOID*)&Ace);
252 if (!NT_SUCCESS(Status))
253 {
254 Ace = NULL;
255 }
256 else if (Ace != NULL && Ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
257 {
258 /* check if the the ACE is a set of allowed permissions for the
259 local SYSTEM account */
260 if (RtlEqualSid((PSID)(Ace + 1),
261 LocalSystemSid))
262 {
263 /* check if the ACE is inherited by noncontainer and
264 container objects, if not attempt to change that */
265 if (!(Ace->Header.AceFlags & OBJECT_INHERIT_ACE) ||
266 !(Ace->Header.AceFlags & CONTAINER_INHERIT_ACE))
267 {
268 Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
269 Status = ZwSetSecurityObject(DirectoryHandle,
270 DACL_SECURITY_INFORMATION,
271 RelSD);
272 }
273 else
274 {
275 /* all done, we have access */
276 Status = STATUS_SUCCESS;
277 }
278
279 goto Cleanup;
280 }
281 }
282 } while (Ace != NULL);
283 }
284
285 AbsSDSize = DescriptorSize;
286
287 /* because we need to change any existing data we need to convert it to
288 an absolute security descriptor first */
289 Status = RtlSelfRelativeToAbsoluteSD2(RelSD,
290 &AbsSDSize);
291 #ifdef _WIN64
292 if (Status == STATUS_BUFFER_TOO_SMALL)
293 {
294 /* this error code can only be returned on 64 bit builds because
295 the size of an absolute security descriptor is greater than the
296 size of a self-relative security descriptor */
297 ASSERT(AbsSDSize > DescriptorSize);
298
299 AbsSD = RtlpAllocateMemory(DescriptorSize,
300 'dSeS');
301 if (AbsSD == NULL)
302 {
303 Status = STATUS_NO_MEMORY;
304 goto Cleanup;
305 }
306
307 AbsSDAllocated = TRUE;
308
309 /* make a raw copy of the self-relative descriptor */
310 RtlCopyMemory(AbsSD,
311 RelSD,
312 DescriptorSize);
313
314 /* finally convert it */
315 Status = RtlSelfRelativeToAbsoluteSD2(AbsSD,
316 &AbsSDSize);
317 }
318 else
319 #endif
320 {
321 AbsSD = RelSD;
322 }
323
324 if (!NT_SUCCESS(Status))
325 {
326 goto Cleanup;
327 }
328
329 /* set the owner SID */
330 Status = RtlSetOwnerSecurityDescriptor(AbsSD,
331 AdminSid,
332 FALSE);
333 if (!NT_SUCCESS(Status))
334 {
335 goto Cleanup;
336 }
337
338 /* set the DACL in the security descriptor */
339 Status = RtlSetDaclSecurityDescriptor(AbsSD,
340 TRUE,
341 SecurityDescriptor->Dacl,
342 FALSE);
343 if (!NT_SUCCESS(Status))
344 {
345 goto Cleanup;
346 }
347
348 /* convert it back to a self-relative descriptor, find out how much
349 memory we need */
350 Status = RtlAbsoluteToSelfRelativeSD(AbsSD,
351 NULL,
352 &RelSDSize);
353 if (Status != STATUS_BUFFER_TOO_SMALL)
354 {
355 goto Cleanup;
356 }
357
358 /* allocate enough memory for the new self-relative descriptor */
359 NewRelSD = RtlpAllocateMemory(RelSDSize,
360 'dSeS');
361 if (NewRelSD == NULL)
362 {
363 Status = STATUS_NO_MEMORY;
364 goto Cleanup;
365 }
366
367 /* convert the security descriptor to self-relative format */
368 Status = RtlAbsoluteToSelfRelativeSD(AbsSD,
369 NewRelSD,
370 &RelSDSize);
371 if (Status == STATUS_BUFFER_TOO_SMALL)
372 {
373 goto Cleanup;
374 }
375
376 /* finally attempt to change the security information */
377 Status = ZwSetSecurityObject(DirectoryHandle,
378 OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
379 NewRelSD);
380
381 Cleanup:
382 if (AdminSid != NULL)
383 {
384 RtlFreeSid(AdminSid);
385 }
386
387 if (LocalSystemSid != NULL)
388 {
389 RtlFreeSid(LocalSystemSid);
390 }
391
392 if (RelSD != NULL)
393 {
394 RtlpFreeMemory(RelSD,
395 'dSeS');
396 }
397
398 if (NewRelSD != NULL)
399 {
400 RtlpFreeMemory(NewRelSD,
401 'dSeS');
402 }
403
404 #ifdef _WIN64
405 if (AbsSDAllocated)
406 {
407 RtlpFreeMemory(AbsSD,
408 'dSeS');
409 }
410 #endif
411
412 return Status;
413 }
414
415 _Must_inspect_result_
416 static
417 NTSTATUS
RtlpSysVolTakeOwnership(IN PUNICODE_STRING DirectoryPath,IN PSECURITY_DESCRIPTOR SecurityDescriptor)418 RtlpSysVolTakeOwnership(IN PUNICODE_STRING DirectoryPath,
419 IN PSECURITY_DESCRIPTOR SecurityDescriptor)
420 {
421 TOKEN_PRIVILEGES TokenPrivileges;
422 OBJECT_ATTRIBUTES ObjectAttributes;
423 SECURITY_DESCRIPTOR AbsSD;
424 PSID AdminSid = NULL;
425 IO_STATUS_BLOCK IoStatusBlock;
426 BOOLEAN TokenEnabled = FALSE;
427 HANDLE hToken = NULL;
428 HANDLE hDirectory = NULL;
429 NTSTATUS Status;
430 ULONG ReturnLength;
431
432 Status = ZwOpenProcessToken(NtCurrentProcess(),
433 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
434 &hToken);
435 if (!NT_SUCCESS(Status))
436 {
437 goto Cleanup;
438 }
439
440 /* attempt to enable the SE_TAKE_OWNERSHIP_PRIVILEGE privilege */
441 TokenPrivileges.PrivilegeCount = 1;
442 TokenPrivileges.Privileges[0].Luid.LowPart = SE_TAKE_OWNERSHIP_PRIVILEGE;
443 TokenPrivileges.Privileges[0].Luid.HighPart = 0;
444 TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
445 Status = ZwAdjustPrivilegesToken(hToken,
446 FALSE,
447 &TokenPrivileges,
448 sizeof(TokenPrivileges),
449 &TokenPrivileges,
450 &ReturnLength);
451 if (!NT_SUCCESS(Status))
452 {
453 goto Cleanup;
454 }
455 TokenEnabled = (TokenPrivileges.PrivilegeCount != 0);
456
457 /* open the directory */
458 InitializeObjectAttributes(&ObjectAttributes,
459 DirectoryPath,
460 0,
461 NULL,
462 SecurityDescriptor);
463
464 Status = ZwOpenFile(&hDirectory,
465 SYNCHRONIZE | WRITE_OWNER,
466 &ObjectAttributes,
467 &IoStatusBlock,
468 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
469 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
470 if (!NT_SUCCESS(Status))
471 {
472 goto Cleanup;
473 }
474
475 /* create the Administrators SID */
476 Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
477 2,
478 SECURITY_BUILTIN_DOMAIN_RID,
479 DOMAIN_ALIAS_RID_ADMINS,
480 0,
481 0,
482 0,
483 0,
484 0,
485 0,
486 &AdminSid);
487 if (!NT_SUCCESS(Status))
488 {
489 goto Cleanup;
490 }
491
492 /* create the security descriptor */
493 Status = RtlCreateSecurityDescriptor(&AbsSD,
494 SECURITY_DESCRIPTOR_REVISION);
495 if (!NT_SUCCESS(Status))
496 {
497 goto Cleanup;
498 }
499
500 Status = RtlSetOwnerSecurityDescriptor(&AbsSD,
501 AdminSid,
502 FALSE);
503 if (!NT_SUCCESS(Status))
504 {
505 goto Cleanup;
506 }
507
508 /* attempt to take ownership */
509 Status = ZwSetSecurityObject(hDirectory,
510 OWNER_SECURITY_INFORMATION,
511 &AbsSD);
512
513 Cleanup:
514 if (TokenEnabled)
515 {
516 /* Disable privileges that we had to enable, whetever the result was. */
517 NTSTATUS Status2 = ZwAdjustPrivilegesToken(hToken,
518 FALSE,
519 &TokenPrivileges,
520 0,
521 NULL,
522 NULL);
523 /* This must succeed */
524 ASSERT(NT_SUCCESS(Status2));
525 (void)Status2;
526 }
527
528 if (AdminSid != NULL)
529 {
530 RtlFreeSid(AdminSid);
531 }
532
533 if (hDirectory != NULL)
534 {
535 ZwClose(hDirectory);
536 }
537
538 if (hToken != NULL)
539 {
540 ZwClose(hToken);
541 }
542
543 return Status;
544 }
545
546 /*
547 * @implemented
548 */
549 NTSTATUS
550 NTAPI
RtlCreateSystemVolumeInformationFolder(IN PUNICODE_STRING VolumeRootPath)551 RtlCreateSystemVolumeInformationFolder(IN PUNICODE_STRING VolumeRootPath)
552 {
553 OBJECT_ATTRIBUTES ObjectAttributes;
554 IO_STATUS_BLOCK IoStatusBlock;
555 HANDLE hDirectory;
556 UNICODE_STRING DirectoryName, NewPath;
557 ULONG PathLen;
558 PISECURITY_DESCRIPTOR SecurityDescriptor = NULL;
559 PSID SystemSid = NULL;
560 BOOLEAN AddSep = FALSE;
561 NTSTATUS Status;
562
563 PAGED_CODE_RTL();
564
565 RtlInitUnicodeString(&DirectoryName,
566 L"System Volume Information");
567
568 PathLen = VolumeRootPath->Length + DirectoryName.Length;
569
570 /* make sure we don't overflow while appending the strings */
571 if (PathLen > 0xFFFC)
572 {
573 return STATUS_INVALID_PARAMETER;
574 }
575
576 if (VolumeRootPath->Buffer[(VolumeRootPath->Length / sizeof(WCHAR)) - 1] != L'\\')
577 {
578 AddSep = TRUE;
579 PathLen += sizeof(WCHAR);
580 }
581
582 /* allocate the new string */
583 NewPath.MaximumLength = (USHORT)PathLen + sizeof(WCHAR);
584 NewPath.Buffer = RtlpAllocateStringMemory(NewPath.MaximumLength,
585 TAG_USTR);
586 if (NewPath.Buffer == NULL)
587 {
588 return STATUS_INSUFFICIENT_RESOURCES;
589 }
590
591 /* create the new path string */
592 NewPath.Length = VolumeRootPath->Length;
593 RtlCopyMemory(NewPath.Buffer,
594 VolumeRootPath->Buffer,
595 NewPath.Length);
596 if (AddSep)
597 {
598 NewPath.Buffer[NewPath.Length / sizeof(WCHAR)] = L'\\';
599 NewPath.Length += sizeof(WCHAR);
600 }
601 RtlCopyMemory(NewPath.Buffer + (NewPath.Length / sizeof(WCHAR)),
602 DirectoryName.Buffer,
603 DirectoryName.Length);
604 NewPath.Length += DirectoryName.Length;
605 NewPath.Buffer[NewPath.Length / sizeof(WCHAR)] = L'\0';
606
607 ASSERT(NewPath.Length == PathLen);
608 ASSERT(NewPath.Length == NewPath.MaximumLength - sizeof(WCHAR));
609
610 /* create the security descriptor for the new directory */
611 Status = RtlpSysVolCreateSecurityDescriptor(&SecurityDescriptor,
612 &SystemSid);
613 if (NT_SUCCESS(Status))
614 {
615 /* create or open the directory */
616 InitializeObjectAttributes(&ObjectAttributes,
617 &NewPath,
618 0,
619 NULL,
620 SecurityDescriptor);
621
622 Status = ZwCreateFile(&hDirectory,
623 SYNCHRONIZE | WRITE_OWNER | WRITE_DAC | READ_CONTROL,
624 &ObjectAttributes,
625 &IoStatusBlock,
626 NULL,
627 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
628 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
629 FILE_OPEN_IF,
630 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
631 NULL,
632 0);
633 if (!NT_SUCCESS(Status))
634 {
635 Status = RtlpSysVolTakeOwnership(&NewPath,
636 SecurityDescriptor);
637
638 if (NT_SUCCESS(Status))
639 {
640 /* successfully took ownership, attempt to open it */
641 Status = ZwCreateFile(&hDirectory,
642 SYNCHRONIZE | WRITE_OWNER | WRITE_DAC | READ_CONTROL,
643 &ObjectAttributes,
644 &IoStatusBlock,
645 NULL,
646 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
647 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
648 FILE_OPEN_IF,
649 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
650 NULL,
651 0);
652 }
653 }
654
655 if (NT_SUCCESS(Status))
656 {
657 /* check security now and adjust it if neccessary */
658 Status = RtlpSysVolCheckOwnerAndSecurity(hDirectory,
659 SecurityDescriptor);
660 ZwClose(hDirectory);
661 }
662
663 /* free allocated memory */
664 ASSERT(SecurityDescriptor != NULL);
665 ASSERT(SecurityDescriptor->Dacl != NULL);
666
667 RtlpFreeMemory(SecurityDescriptor->Dacl,
668 'cAeS');
669 RtlpFreeMemory(SecurityDescriptor,
670 'dSeS');
671
672 RtlFreeSid(SystemSid);
673 }
674
675 RtlpFreeStringMemory(NewPath.Buffer,
676 TAG_USTR);
677 return Status;
678 }
679
680 /* EOF */
681