6040d32c66b9f2f708652cd0470fabd3371e71e5
[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 PSECURITY_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 TAG('S', 'e', 'S', 'd'));
49 if (AbsSD == NULL)
50 {
51 Status = STATUS_INSUFFICIENT_RESOURCES;
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 TAG('S', 'e', 'A', 'c'));
67 if (Dacl == NULL)
68 {
69 Status = STATUS_INSUFFICIENT_RESOURCES;
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 TAG('S', 'e', 'A', 'c'));
115 }
116
117 if (AbsSD != NULL)
118 {
119 RtlpFreeMemory(AbsSD,
120 TAG('S', 'e', 'S', 'd'));
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 TAG('S', 'e', 'S', 'd'));
166 if (RelSD == NULL)
167 {
168 Status = STATUS_INSUFFICIENT_RESOURCES;
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 TAG('S', 'e', 'S', 'd'));
301 if (AbsSD == NULL)
302 {
303 Status = STATUS_INSUFFICIENT_RESOURCES;
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 TAG('S', 'e', 'S', 'd'));
361 if (NewRelSD == NULL)
362 {
363 goto Cleanup;
364 }
365
366 /* convert the security descriptor to self-relative format */
367 Status = RtlAbsoluteToSelfRelativeSD(AbsSD,
368 NewRelSD,
369 &RelSDSize);
370 if (Status == STATUS_BUFFER_TOO_SMALL)
371 {
372 goto Cleanup;
373 }
374
375 /* finally attempt to change the security information */
376 Status = ZwSetSecurityObject(DirectoryHandle,
377 OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
378 NewRelSD);
379
380 Cleanup:
381 if (AdminSid != NULL)
382 {
383 RtlFreeSid(AdminSid);
384 }
385
386 if (LocalSystemSid != NULL)
387 {
388 RtlFreeSid(LocalSystemSid);
389 }
390
391 if (RelSD != NULL)
392 {
393 RtlpFreeMemory(RelSD,
394 TAG('S', 'e', 'S', 'd'));
395 }
396
397 if (NewRelSD != NULL)
398 {
399 RtlpFreeMemory(NewRelSD,
400 TAG('S', 'e', 'S', 'd'));
401 }
402
403 #ifdef _WIN64
404 if (AbsSDAllocated)
405 {
406 RtlpFreeMemory(AbsSD,
407 TAG('S', 'e', 'S', 'd'));
408 }
409 #endif
410
411 return Status;
412 }
413
414 static NTSTATUS
415 RtlpSysVolTakeOwnership(IN PUNICODE_STRING DirectoryPath,
416 IN PSECURITY_DESCRIPTOR SecurityDescriptor)
417 {
418 TOKEN_PRIVILEGES TokenPrivileges;
419 OBJECT_ATTRIBUTES ObjectAttributes;
420 SECURITY_DESCRIPTOR AbsSD;
421 PSID AdminSid = NULL;
422 IO_STATUS_BLOCK IoStatusBlock;
423 BOOLEAN TokenEnabled = FALSE;
424 HANDLE hToken = NULL;
425 HANDLE hDirectory = NULL;
426 NTSTATUS Status;
427
428 Status = ZwOpenProcessToken(NtCurrentProcess(),
429 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
430 &hToken);
431 if (!NT_SUCCESS(Status))
432 {
433 goto Cleanup;
434 }
435
436 /* attempt to enable the SE_TAKE_OWNERSHIP_PRIVILEGE privilege */
437 TokenPrivileges.PrivilegeCount = 1;
438 TokenPrivileges.Privileges[0].Luid.LowPart = SE_TAKE_OWNERSHIP_PRIVILEGE;
439 TokenPrivileges.Privileges[0].Luid.HighPart = 0;
440 TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
441 Status = ZwAdjustPrivilegesToken(hToken,
442 FALSE,
443 &TokenPrivileges,
444 sizeof(TokenPrivileges),
445 &TokenPrivileges,
446 NULL);
447 if (!NT_SUCCESS(Status))
448 {
449 goto Cleanup;
450 }
451 TokenEnabled = (TokenPrivileges.PrivilegeCount != 0);
452
453 /* open the directory */
454 InitializeObjectAttributes(&ObjectAttributes,
455 DirectoryPath,
456 0,
457 NULL,
458 SecurityDescriptor);
459
460 Status = ZwOpenFile(&hDirectory,
461 SYNCHRONIZE | WRITE_OWNER,
462 &ObjectAttributes,
463 &IoStatusBlock,
464 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
465 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
466 if (!NT_SUCCESS(Status))
467 {
468 goto Cleanup;
469 }
470
471 /* create the Administrators SID */
472 Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
473 2,
474 SECURITY_BUILTIN_DOMAIN_RID,
475 DOMAIN_ALIAS_RID_ADMINS,
476 0,
477 0,
478 0,
479 0,
480 0,
481 0,
482 &AdminSid);
483 if (!NT_SUCCESS(Status))
484 {
485 goto Cleanup;
486 }
487
488 /* create the security descriptor */
489 Status = RtlCreateSecurityDescriptor(&AbsSD,
490 SECURITY_DESCRIPTOR_REVISION);
491 if (!NT_SUCCESS(Status))
492 {
493 goto Cleanup;
494 }
495
496 Status = RtlSetOwnerSecurityDescriptor(&AbsSD,
497 AdminSid,
498 FALSE);
499 if (!NT_SUCCESS(Status))
500 {
501 goto Cleanup;
502 }
503
504 /* attempt to take ownership */
505 Status = ZwSetSecurityObject(hDirectory,
506 OWNER_SECURITY_INFORMATION,
507 &AbsSD);
508
509 Cleanup:
510 if (TokenEnabled)
511 {
512 ZwAdjustPrivilegesToken(hToken,
513 FALSE,
514 &TokenPrivileges,
515 0,
516 NULL,
517 NULL);
518 }
519
520 if (AdminSid != NULL)
521 {
522 RtlFreeSid(AdminSid);
523 }
524
525 if (hDirectory != NULL)
526 {
527 ZwClose(hDirectory);
528 }
529
530 if (hToken != NULL)
531 {
532 ZwClose(hToken);
533 }
534
535 return Status;
536 }
537
538 /*
539 * @implemented
540 */
541 NTSTATUS
542 NTAPI
543 RtlCreateSystemVolumeInformationFolder(
544 IN PUNICODE_STRING VolumeRootPath
545 )
546 {
547 OBJECT_ATTRIBUTES ObjectAttributes;
548 IO_STATUS_BLOCK IoStatusBlock;
549 HANDLE hDirectory;
550 UNICODE_STRING DirectoryName, NewPath;
551 ULONG PathLen;
552 PISECURITY_DESCRIPTOR SecurityDescriptor = NULL;
553 PSID SystemSid = NULL;
554 BOOLEAN AddSep = FALSE;
555 NTSTATUS Status;
556
557 PAGED_CODE_RTL();
558
559 RtlInitUnicodeString(&DirectoryName,
560 L"System Volume Information");
561
562 PathLen = VolumeRootPath->Length + DirectoryName.Length;
563
564 /* make sure we don't overflow while appending the strings */
565 if (PathLen > 0xFFFC)
566 {
567 return STATUS_INVALID_PARAMETER;
568 }
569
570 if (VolumeRootPath->Buffer[(VolumeRootPath->Length / sizeof(WCHAR)) - 1] != L'\\')
571 {
572 AddSep = TRUE;
573 PathLen += sizeof(WCHAR);
574 }
575
576 /* allocate the new string */
577 NewPath.MaximumLength = (USHORT)PathLen + sizeof(WCHAR);
578 NewPath.Buffer = RtlpAllocateStringMemory(NewPath.MaximumLength,
579 TAG_USTR);
580 if (NewPath.Buffer == NULL)
581 {
582 return STATUS_INSUFFICIENT_RESOURCES;
583 }
584
585 /* create the new path string */
586 NewPath.Length = VolumeRootPath->Length;
587 RtlCopyMemory(NewPath.Buffer,
588 VolumeRootPath->Buffer,
589 NewPath.Length);
590 if (AddSep)
591 {
592 NewPath.Buffer[NewPath.Length / sizeof(WCHAR)] = L'\\';
593 NewPath.Length += sizeof(WCHAR);
594 }
595 RtlCopyMemory(NewPath.Buffer + (NewPath.Length / sizeof(WCHAR)),
596 DirectoryName.Buffer,
597 DirectoryName.Length);
598 NewPath.Length += DirectoryName.Length;
599 NewPath.Buffer[NewPath.Length / sizeof(WCHAR)] = L'\0';
600
601 ASSERT(NewPath.Length == PathLen);
602 ASSERT(NewPath.Length == NewPath.MaximumLength - sizeof(WCHAR));
603
604 /* create the security descriptor for the new directory */
605 Status = RtlpSysVolCreateSecurityDescriptor(&SecurityDescriptor,
606 &SystemSid);
607 if (NT_SUCCESS(Status))
608 {
609 /* create or open the directory */
610 InitializeObjectAttributes(&ObjectAttributes,
611 &NewPath,
612 0,
613 NULL,
614 SecurityDescriptor);
615
616 Status = ZwCreateFile(&hDirectory,
617 SYNCHRONIZE | WRITE_OWNER | WRITE_DAC | READ_CONTROL,
618 &ObjectAttributes,
619 &IoStatusBlock,
620 NULL,
621 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
622 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
623 FILE_OPEN_IF,
624 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
625 NULL,
626 0);
627 if (!NT_SUCCESS(Status))
628 {
629 Status = RtlpSysVolTakeOwnership(&NewPath,
630 SecurityDescriptor);
631
632 if (NT_SUCCESS(Status))
633 {
634 /* successfully took ownership, attempt to open it */
635 Status = ZwCreateFile(&hDirectory,
636 SYNCHRONIZE | WRITE_OWNER | WRITE_DAC | READ_CONTROL,
637 &ObjectAttributes,
638 &IoStatusBlock,
639 NULL,
640 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
641 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
642 FILE_OPEN_IF,
643 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
644 NULL,
645 0);
646 }
647 }
648
649 if (NT_SUCCESS(Status))
650 {
651 /* check security now and adjust it if neccessary */
652 Status = RtlpSysVolCheckOwnerAndSecurity(hDirectory,
653 SecurityDescriptor);
654 ZwClose(hDirectory);
655 }
656
657 /* free allocated memory */
658 ASSERT(SecurityDescriptor != NULL);
659 ASSERT(SecurityDescriptor->Dacl != NULL)
660
661 RtlpFreeMemory(SecurityDescriptor->Dacl,
662 TAG('S', 'e', 'A', 'c'));
663 RtlpFreeMemory(SecurityDescriptor,
664 TAG('S', 'e', 'S', 'd'));
665
666 RtlFreeSid(SystemSid);
667 }
668
669 RtlpFreeStringMemory(NewPath.Buffer,
670 TAG_USTR);
671 return Status;
672 }
673
674 /*
675 * @unimplemented
676 */
677 NTSTATUS
678 NTAPI
679 RtlGetSetBootStatusData(
680 HANDLE Filehandle,
681 BOOLEAN WriteMode,
682 DWORD DataClass,
683 PVOID Buffer,
684 ULONG BufferSize,
685 DWORD DataClass2
686 )
687 {
688 UNIMPLEMENTED;
689 return STATUS_NOT_IMPLEMENTED;
690 }
691
692 /*
693 * @unimplemented
694 */
695 NTSTATUS
696 NTAPI
697 RtlLockBootStatusData(
698 HANDLE Filehandle
699 )
700 {
701 UNIMPLEMENTED;
702 return STATUS_NOT_IMPLEMENTED;
703 }
704
705 /*
706 * @unimplemented
707 */
708 NTSTATUS
709 NTAPI
710 RtlUnlockBootStatusData(
711 HANDLE Filehandle
712 )
713 {
714 UNIMPLEMENTED;
715 return STATUS_NOT_IMPLEMENTED;
716 }
717
718 /* EOF */