[NTDLL]
[reactos.git] / reactos / lib / rtl / bootdata.c
1 /* COPYRIGHT: See COPYING in the top level directory
2 * PROJECT: ReactOS system libraries
3 * PURPOSE: Boot Data implementation
4 * FILE: lib/rtl/bootdata.c
5 * PROGRAMMERS:
6 */
7
8 /* INCLUDES *****************************************************************/
9
10 #include <rtl.h>
11
12 #define NDEBUG
13 #include <debug.h>
14
15 /* FUNCTIONS *****************************************************************/
16
17 static SID_IDENTIFIER_AUTHORITY LocalSystemAuthority = {SECURITY_NT_AUTHORITY};
18
19 static NTSTATUS
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
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 static NTSTATUS
416 RtlpSysVolTakeOwnership(IN PUNICODE_STRING DirectoryPath,
417 IN PSECURITY_DESCRIPTOR SecurityDescriptor)
418 {
419 TOKEN_PRIVILEGES TokenPrivileges;
420 OBJECT_ATTRIBUTES ObjectAttributes;
421 SECURITY_DESCRIPTOR AbsSD;
422 PSID AdminSid = NULL;
423 IO_STATUS_BLOCK IoStatusBlock;
424 BOOLEAN TokenEnabled = FALSE;
425 HANDLE hToken = NULL;
426 HANDLE hDirectory = NULL;
427 NTSTATUS Status;
428
429 Status = ZwOpenProcessToken(NtCurrentProcess(),
430 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
431 &hToken);
432 if (!NT_SUCCESS(Status))
433 {
434 goto Cleanup;
435 }
436
437 /* attempt to enable the SE_TAKE_OWNERSHIP_PRIVILEGE privilege */
438 TokenPrivileges.PrivilegeCount = 1;
439 TokenPrivileges.Privileges[0].Luid.LowPart = SE_TAKE_OWNERSHIP_PRIVILEGE;
440 TokenPrivileges.Privileges[0].Luid.HighPart = 0;
441 TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
442 Status = ZwAdjustPrivilegesToken(hToken,
443 FALSE,
444 &TokenPrivileges,
445 sizeof(TokenPrivileges),
446 &TokenPrivileges,
447 NULL);
448 if (!NT_SUCCESS(Status))
449 {
450 goto Cleanup;
451 }
452 TokenEnabled = (TokenPrivileges.PrivilegeCount != 0);
453
454 /* open the directory */
455 InitializeObjectAttributes(&ObjectAttributes,
456 DirectoryPath,
457 0,
458 NULL,
459 SecurityDescriptor);
460
461 Status = ZwOpenFile(&hDirectory,
462 SYNCHRONIZE | WRITE_OWNER,
463 &ObjectAttributes,
464 &IoStatusBlock,
465 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
466 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
467 if (!NT_SUCCESS(Status))
468 {
469 goto Cleanup;
470 }
471
472 /* create the Administrators SID */
473 Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
474 2,
475 SECURITY_BUILTIN_DOMAIN_RID,
476 DOMAIN_ALIAS_RID_ADMINS,
477 0,
478 0,
479 0,
480 0,
481 0,
482 0,
483 &AdminSid);
484 if (!NT_SUCCESS(Status))
485 {
486 goto Cleanup;
487 }
488
489 /* create the security descriptor */
490 Status = RtlCreateSecurityDescriptor(&AbsSD,
491 SECURITY_DESCRIPTOR_REVISION);
492 if (!NT_SUCCESS(Status))
493 {
494 goto Cleanup;
495 }
496
497 Status = RtlSetOwnerSecurityDescriptor(&AbsSD,
498 AdminSid,
499 FALSE);
500 if (!NT_SUCCESS(Status))
501 {
502 goto Cleanup;
503 }
504
505 /* attempt to take ownership */
506 Status = ZwSetSecurityObject(hDirectory,
507 OWNER_SECURITY_INFORMATION,
508 &AbsSD);
509
510 Cleanup:
511 if (TokenEnabled)
512 {
513 ZwAdjustPrivilegesToken(hToken,
514 FALSE,
515 &TokenPrivileges,
516 0,
517 NULL,
518 NULL);
519 }
520
521 if (AdminSid != NULL)
522 {
523 RtlFreeSid(AdminSid);
524 }
525
526 if (hDirectory != NULL)
527 {
528 ZwClose(hDirectory);
529 }
530
531 if (hToken != NULL)
532 {
533 ZwClose(hToken);
534 }
535
536 return Status;
537 }
538
539 /*
540 * @implemented
541 */
542 NTSTATUS
543 NTAPI
544 RtlCreateSystemVolumeInformationFolder(
545 IN PUNICODE_STRING VolumeRootPath
546 )
547 {
548 OBJECT_ATTRIBUTES ObjectAttributes;
549 IO_STATUS_BLOCK IoStatusBlock;
550 HANDLE hDirectory;
551 UNICODE_STRING DirectoryName, NewPath;
552 ULONG PathLen;
553 PISECURITY_DESCRIPTOR SecurityDescriptor = NULL;
554 PSID SystemSid = NULL;
555 BOOLEAN AddSep = FALSE;
556 NTSTATUS Status;
557
558 PAGED_CODE_RTL();
559
560 RtlInitUnicodeString(&DirectoryName,
561 L"System Volume Information");
562
563 PathLen = VolumeRootPath->Length + DirectoryName.Length;
564
565 /* make sure we don't overflow while appending the strings */
566 if (PathLen > 0xFFFC)
567 {
568 return STATUS_INVALID_PARAMETER;
569 }
570
571 if (VolumeRootPath->Buffer[(VolumeRootPath->Length / sizeof(WCHAR)) - 1] != L'\\')
572 {
573 AddSep = TRUE;
574 PathLen += sizeof(WCHAR);
575 }
576
577 /* allocate the new string */
578 NewPath.MaximumLength = (USHORT)PathLen + sizeof(WCHAR);
579 NewPath.Buffer = RtlpAllocateStringMemory(NewPath.MaximumLength,
580 TAG_USTR);
581 if (NewPath.Buffer == NULL)
582 {
583 return STATUS_INSUFFICIENT_RESOURCES;
584 }
585
586 /* create the new path string */
587 NewPath.Length = VolumeRootPath->Length;
588 RtlCopyMemory(NewPath.Buffer,
589 VolumeRootPath->Buffer,
590 NewPath.Length);
591 if (AddSep)
592 {
593 NewPath.Buffer[NewPath.Length / sizeof(WCHAR)] = L'\\';
594 NewPath.Length += sizeof(WCHAR);
595 }
596 RtlCopyMemory(NewPath.Buffer + (NewPath.Length / sizeof(WCHAR)),
597 DirectoryName.Buffer,
598 DirectoryName.Length);
599 NewPath.Length += DirectoryName.Length;
600 NewPath.Buffer[NewPath.Length / sizeof(WCHAR)] = L'\0';
601
602 ASSERT(NewPath.Length == PathLen);
603 ASSERT(NewPath.Length == NewPath.MaximumLength - sizeof(WCHAR));
604
605 /* create the security descriptor for the new directory */
606 Status = RtlpSysVolCreateSecurityDescriptor(&SecurityDescriptor,
607 &SystemSid);
608 if (NT_SUCCESS(Status))
609 {
610 /* create or open the directory */
611 InitializeObjectAttributes(&ObjectAttributes,
612 &NewPath,
613 0,
614 NULL,
615 SecurityDescriptor);
616
617 Status = ZwCreateFile(&hDirectory,
618 SYNCHRONIZE | WRITE_OWNER | WRITE_DAC | READ_CONTROL,
619 &ObjectAttributes,
620 &IoStatusBlock,
621 NULL,
622 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
623 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
624 FILE_OPEN_IF,
625 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
626 NULL,
627 0);
628 if (!NT_SUCCESS(Status))
629 {
630 Status = RtlpSysVolTakeOwnership(&NewPath,
631 SecurityDescriptor);
632
633 if (NT_SUCCESS(Status))
634 {
635 /* successfully took ownership, attempt to open it */
636 Status = ZwCreateFile(&hDirectory,
637 SYNCHRONIZE | WRITE_OWNER | WRITE_DAC | READ_CONTROL,
638 &ObjectAttributes,
639 &IoStatusBlock,
640 NULL,
641 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
642 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
643 FILE_OPEN_IF,
644 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
645 NULL,
646 0);
647 }
648 }
649
650 if (NT_SUCCESS(Status))
651 {
652 /* check security now and adjust it if neccessary */
653 Status = RtlpSysVolCheckOwnerAndSecurity(hDirectory,
654 SecurityDescriptor);
655 ZwClose(hDirectory);
656 }
657
658 /* free allocated memory */
659 ASSERT(SecurityDescriptor != NULL);
660 ASSERT(SecurityDescriptor->Dacl != NULL);
661
662 RtlpFreeMemory(SecurityDescriptor->Dacl,
663 'cAeS');
664 RtlpFreeMemory(SecurityDescriptor,
665 'dSeS');
666
667 RtlFreeSid(SystemSid);
668 }
669
670 RtlpFreeStringMemory(NewPath.Buffer,
671 TAG_USTR);
672 return Status;
673 }
674
675 /*
676 * @unimplemented
677 */
678 NTSTATUS
679 NTAPI
680 RtlCreateBootStatusDataFile(VOID)
681 {
682 UNIMPLEMENTED;
683 return STATUS_NOT_IMPLEMENTED;
684 }
685
686 /*
687 * @unimplemented
688 */
689 NTSTATUS
690 NTAPI
691 RtlGetSetBootStatusData(
692 HANDLE Filehandle,
693 BOOLEAN WriteMode,
694 DWORD DataClass,
695 PVOID Buffer,
696 ULONG BufferSize,
697 DWORD DataClass2
698 )
699 {
700 UNIMPLEMENTED;
701 return STATUS_NOT_IMPLEMENTED;
702 }
703
704 /*
705 * @unimplemented
706 */
707 NTSTATUS
708 NTAPI
709 RtlLockBootStatusData(
710 HANDLE Filehandle
711 )
712 {
713 UNIMPLEMENTED;
714 return STATUS_NOT_IMPLEMENTED;
715 }
716
717 /*
718 * @unimplemented
719 */
720 NTSTATUS
721 NTAPI
722 RtlUnlockBootStatusData(
723 HANDLE Filehandle
724 )
725 {
726 UNIMPLEMENTED;
727 return STATUS_NOT_IMPLEMENTED;
728 }
729
730 /* EOF */