d1b8731255255a0c0cb02422c7e8e619d33e998e
[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 PSECURITY_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
234 /* check if the Administrators are the owner and at least a not-NULL DACL
235 is present */
236 if (OwnerSid != NULL &&
237 RtlEqualSid(OwnerSid,
238 AdminSid) &&
239 DaclPresent && Dacl != NULL)
240 {
241 /* check the DACL for an Allowed ACE for the SYSTEM account */
242 AceIndex = 0;
243 do
244 {
245 Status = RtlGetAce(Dacl,
246 AceIndex++,
247 (PVOID*)&Ace);
248 if (!NT_SUCCESS(Status))
249 {
250 Ace = NULL;
251 }
252 else if (Ace != NULL && Ace->Header.AceType == ACCESS_ALLOWED_ACE_TYPE)
253 {
254 /* check if the the ACE is a set of allowed permissions for the
255 local SYSTEM account */
256 if (RtlEqualSid((PSID)(Ace + 1),
257 LocalSystemSid))
258 {
259 /* check if the ACE is inherited by noncontainer and
260 container objects, if not attempt to change that */
261 if (!(Ace->Header.AceFlags & OBJECT_INHERIT_ACE) ||
262 !(Ace->Header.AceFlags & CONTAINER_INHERIT_ACE))
263 {
264 Ace->Header.AceFlags |= OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE;
265 Status = ZwSetSecurityObject(DirectoryHandle,
266 DACL_SECURITY_INFORMATION,
267 RelSD);
268 }
269 else
270 {
271 /* all done, we have access */
272 Status = STATUS_SUCCESS;
273 }
274
275 goto Cleanup;
276 }
277 }
278 } while (Ace != NULL);
279 }
280
281 AbsSDSize = DescriptorSize;
282
283 /* because we need to change any existing data we need to convert it to
284 an absolute security descriptor first */
285 Status = RtlSelfRelativeToAbsoluteSD2(RelSD,
286 &AbsSDSize);
287 #ifdef _WIN64
288 if (Status == STATUS_BUFFER_TOO_SMALL)
289 {
290 /* this error code can only be returned on 64 bit builds because
291 the size of an absolute security descriptor is greater than the
292 size of a self-relative security descriptor */
293 ASSERT(AbsSDSize > DescriptorSize);
294
295 AbsSD = RtlpAllocateMemory(DescriptorSize,
296 TAG('S', 'e', 'S', 'd'));
297 if (AbsSD == NULL)
298 {
299 Status = STATUS_INSUFFICIENT_RESOURCES;
300 goto Cleanup;
301 }
302
303 AbsSDAllocated = TRUE;
304
305 /* make a raw copy of the self-relative descriptor */
306 RtlCopyMemory(AbsSD,
307 RelSD,
308 DescriptorSize);
309
310 /* finally convert it */
311 Status = RtlSelfRelativeToAbsoluteSD2(AbsSD,
312 &AbsSDSize);
313 }
314 else
315 #endif
316 {
317 AbsSD = RelSD;
318 }
319
320 if (!NT_SUCCESS(Status))
321 {
322 goto Cleanup;
323 }
324
325 /* set the owner SID */
326 Status = RtlSetOwnerSecurityDescriptor(AbsSD,
327 AdminSid,
328 FALSE);
329 if (!NT_SUCCESS(Status))
330 {
331 goto Cleanup;
332 }
333
334 /* set the DACL in the security descriptor */
335 Status = RtlSetDaclSecurityDescriptor(AbsSD,
336 TRUE,
337 SecurityDescriptor->Dacl,
338 FALSE);
339 if (!NT_SUCCESS(Status))
340 {
341 goto Cleanup;
342 }
343
344 /* convert it back to a self-relative descriptor, find out how much
345 memory we need */
346 Status = RtlAbsoluteToSelfRelativeSD(AbsSD,
347 NULL,
348 &RelSDSize);
349 if (Status != STATUS_BUFFER_TOO_SMALL)
350 {
351 goto Cleanup;
352 }
353
354 /* allocate enough memory for the new self-relative descriptor */
355 NewRelSD = RtlpAllocateMemory(RelSDSize,
356 TAG('S', 'e', 'S', 'd'));
357 if (NewRelSD == NULL)
358 {
359 goto Cleanup;
360 }
361
362 /* convert the security descriptor to self-relative format */
363 Status = RtlAbsoluteToSelfRelativeSD(AbsSD,
364 NewRelSD,
365 &RelSDSize);
366 if (Status != STATUS_BUFFER_TOO_SMALL)
367 {
368 goto Cleanup;
369 }
370
371 /* finally attempt to change the security information */
372 Status = ZwSetSecurityObject(DirectoryHandle,
373 OWNER_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION,
374 NewRelSD);
375
376 Cleanup:
377 if (AdminSid != NULL)
378 {
379 RtlFreeSid(AdminSid);
380 }
381
382 if (LocalSystemSid != NULL)
383 {
384 RtlFreeSid(LocalSystemSid);
385 }
386
387 if (RelSD != NULL)
388 {
389 RtlpFreeMemory(RelSD,
390 TAG('S', 'e', 'S', 'd'));
391 }
392
393 if (NewRelSD != NULL)
394 {
395 RtlpFreeMemory(NewRelSD,
396 TAG('S', 'e', 'S', 'd'));
397 }
398
399 #ifdef _WIN64
400 if (AbsSDAllocated)
401 {
402 RtlpFreeMemory(AbsSD,
403 TAG('S', 'e', 'S', 'd'));
404 }
405 #endif
406
407 return Status;
408 }
409
410 static NTSTATUS
411 RtlpSysVolTakeOwnership(IN PUNICODE_STRING DirectoryPath,
412 IN PSECURITY_DESCRIPTOR SecurityDescriptor)
413 {
414 TOKEN_PRIVILEGES TokenPrivileges;
415 OBJECT_ATTRIBUTES ObjectAttributes;
416 SECURITY_DESCRIPTOR AbsSD;
417 PSID AdminSid = NULL;
418 IO_STATUS_BLOCK IoStatusBlock;
419 BOOLEAN TokenEnabled = FALSE;
420 HANDLE hToken = NULL;
421 HANDLE hDirectory = NULL;
422 NTSTATUS Status;
423
424 Status = ZwOpenProcessToken(NtCurrentProcess(),
425 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
426 &hToken);
427 if (!NT_SUCCESS(Status))
428 {
429 goto Cleanup;
430 }
431
432 /* attempt to enable the SE_TAKE_OWNERSHIP_PRIVILEGE privilege */
433 TokenPrivileges.PrivilegeCount = 1;
434 TokenPrivileges.Privileges[0].Luid.LowPart = SE_TAKE_OWNERSHIP_PRIVILEGE;
435 TokenPrivileges.Privileges[0].Luid.HighPart = 0;
436 TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
437 Status = ZwAdjustPrivilegesToken(hToken,
438 FALSE,
439 &TokenPrivileges,
440 sizeof(TokenPrivileges),
441 &TokenPrivileges,
442 NULL);
443 if (!NT_SUCCESS(Status))
444 {
445 goto Cleanup;
446 }
447 TokenEnabled = (TokenPrivileges.PrivilegeCount != 0);
448
449 /* open the directory */
450 InitializeObjectAttributes(&ObjectAttributes,
451 DirectoryPath,
452 0,
453 NULL,
454 SecurityDescriptor);
455
456 Status = ZwOpenFile(&hDirectory,
457 SYNCHRONIZE | WRITE_OWNER,
458 &ObjectAttributes,
459 &IoStatusBlock,
460 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
461 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
462 if (!NT_SUCCESS(Status))
463 {
464 goto Cleanup;
465 }
466
467 /* create the Administrators SID */
468 Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
469 2,
470 SECURITY_BUILTIN_DOMAIN_RID,
471 DOMAIN_ALIAS_RID_ADMINS,
472 0,
473 0,
474 0,
475 0,
476 0,
477 0,
478 &AdminSid);
479 if (!NT_SUCCESS(Status))
480 {
481 goto Cleanup;
482 }
483
484 /* create the security descriptor */
485 Status = RtlCreateSecurityDescriptor(&AbsSD,
486 SECURITY_DESCRIPTOR_REVISION);
487 if (!NT_SUCCESS(Status))
488 {
489 goto Cleanup;
490 }
491
492 Status = RtlSetOwnerSecurityDescriptor(&AbsSD,
493 AdminSid,
494 FALSE);
495 if (!NT_SUCCESS(Status))
496 {
497 goto Cleanup;
498 }
499
500 /* attempt to take ownership */
501 Status = ZwSetSecurityObject(hDirectory,
502 OWNER_SECURITY_INFORMATION,
503 &AbsSD);
504
505 Cleanup:
506 if (TokenEnabled)
507 {
508 ZwAdjustPrivilegesToken(hToken,
509 FALSE,
510 &TokenPrivileges,
511 0,
512 NULL,
513 NULL);
514 }
515
516 if (AdminSid != NULL)
517 {
518 RtlFreeSid(AdminSid);
519 }
520
521 if (hDirectory != NULL)
522 {
523 ZwClose(hDirectory);
524 }
525
526 if (hToken != NULL)
527 {
528 ZwClose(hToken);
529 }
530
531 return Status;
532 }
533
534 /*
535 * @implemented
536 */
537 NTSTATUS
538 NTAPI
539 RtlCreateSystemVolumeInformationFolder(
540 IN PUNICODE_STRING VolumeRootPath
541 )
542 {
543 OBJECT_ATTRIBUTES ObjectAttributes;
544 IO_STATUS_BLOCK IoStatusBlock;
545 HANDLE hDirectory;
546 UNICODE_STRING DirectoryName, NewPath;
547 ULONG PathLen;
548 PSECURITY_DESCRIPTOR SecurityDescriptor = NULL;
549 PSID SystemSid = NULL;
550 BOOLEAN AddSep = FALSE;
551 NTSTATUS Status;
552
553 PAGED_CODE_RTL();
554
555 RtlInitUnicodeString(&DirectoryName,
556 L"System Volume Information");
557
558 PathLen = VolumeRootPath->Length + DirectoryName.Length;
559
560 /* make sure we don't overflow while appending the strings */
561 if (PathLen > 0xFFFC)
562 {
563 return STATUS_INVALID_PARAMETER;
564 }
565
566 if (VolumeRootPath->Buffer[(VolumeRootPath->Length / sizeof(WCHAR)) - 1] != L'\\')
567 {
568 AddSep = TRUE;
569 PathLen += sizeof(WCHAR);
570 }
571
572 /* allocate the new string */
573 NewPath.MaximumLength = (USHORT)PathLen + sizeof(WCHAR);
574 NewPath.Buffer = RtlpAllocateStringMemory(NewPath.MaximumLength,
575 TAG_USTR);
576 if (NewPath.Buffer == NULL)
577 {
578 return STATUS_INSUFFICIENT_RESOURCES;
579 }
580
581 /* create the new path string */
582 NewPath.Length = VolumeRootPath->Length;
583 RtlCopyMemory(NewPath.Buffer,
584 VolumeRootPath->Buffer,
585 NewPath.Length);
586 if (AddSep)
587 {
588 NewPath.Buffer[NewPath.Length / sizeof(WCHAR)] = L'\\';
589 NewPath.Length += sizeof(WCHAR);
590 }
591 RtlCopyMemory(NewPath.Buffer + (NewPath.Length / sizeof(WCHAR)),
592 DirectoryName.Buffer,
593 DirectoryName.Length);
594 NewPath.Length += DirectoryName.Length;
595 NewPath.Buffer[NewPath.Length / sizeof(WCHAR)] = L'\0';
596
597 ASSERT(NewPath.Length == PathLen);
598 ASSERT(NewPath.Length == NewPath.MaximumLength - sizeof(WCHAR));
599
600 /* create the security descriptor for the new directory */
601 Status = RtlpSysVolCreateSecurityDescriptor(&SecurityDescriptor,
602 &SystemSid);
603 if (NT_SUCCESS(Status))
604 {
605 /* create or open the directory */
606 InitializeObjectAttributes(&ObjectAttributes,
607 &NewPath,
608 0,
609 NULL,
610 SecurityDescriptor);
611
612 Status = ZwCreateFile(&hDirectory,
613 SYNCHRONIZE | WRITE_OWNER | WRITE_DAC | READ_CONTROL,
614 &ObjectAttributes,
615 &IoStatusBlock,
616 NULL,
617 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
618 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
619 FILE_OPEN_IF,
620 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
621 NULL,
622 0);
623 if (!NT_SUCCESS(Status))
624 {
625 Status = RtlpSysVolTakeOwnership(&NewPath,
626 SecurityDescriptor);
627
628 if (NT_SUCCESS(Status))
629 {
630 /* successfully took ownership, attempt to open it */
631 Status = ZwCreateFile(&hDirectory,
632 SYNCHRONIZE | WRITE_OWNER | WRITE_DAC | READ_CONTROL,
633 &ObjectAttributes,
634 &IoStatusBlock,
635 NULL,
636 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
637 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
638 FILE_OPEN_IF,
639 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT,
640 NULL,
641 0);
642 }
643 }
644
645 if (NT_SUCCESS(Status))
646 {
647 /* check security now and adjust it if neccessary */
648 Status = RtlpSysVolCheckOwnerAndSecurity(hDirectory,
649 SecurityDescriptor);
650 ZwClose(hDirectory);
651 }
652
653 /* free allocated memory */
654 ASSERT(SecurityDescriptor != NULL);
655 ASSERT(SecurityDescriptor->Dacl != NULL)
656
657 RtlpFreeMemory(SecurityDescriptor->Dacl,
658 TAG('S', 'e', 'A', 'c'));
659 RtlpFreeMemory(SecurityDescriptor,
660 TAG('S', 'e', 'S', 'd'));
661
662 RtlFreeSid(SystemSid);
663 }
664
665 RtlpFreeStringMemory(NewPath.Buffer,
666 TAG_USTR);
667 return Status;
668 }
669
670 /*
671 * @unimplemented
672 */
673 NTSTATUS
674 NTAPI
675 RtlGetSetBootStatusData(
676 HANDLE Filehandle,
677 BOOLEAN WriteMode,
678 DWORD DataClass,
679 PVOID Buffer,
680 ULONG BufferSize,
681 DWORD DataClass2
682 )
683 {
684 UNIMPLEMENTED;
685 return STATUS_NOT_IMPLEMENTED;
686 }
687
688 /*
689 * @unimplemented
690 */
691 NTSTATUS
692 NTAPI
693 RtlLockBootStatusData(
694 HANDLE Filehandle
695 )
696 {
697 UNIMPLEMENTED;
698 return STATUS_NOT_IMPLEMENTED;
699 }
700
701 /*
702 * @unimplemented
703 */
704 NTSTATUS
705 NTAPI
706 RtlUnlockBootStatusData(
707 HANDLE Filehandle
708 )
709 {
710 UNIMPLEMENTED;
711 return STATUS_NOT_IMPLEMENTED;
712 }
713
714 /* EOF */