[CRT] spawn: define a unicode environment when needed
[reactos.git] / sdk / lib / rtl / sysvol.c
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
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 ULONG ReturnLength;
429
430 Status = ZwOpenProcessToken(NtCurrentProcess(),
431 TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
432 &hToken);
433 if (!NT_SUCCESS(Status))
434 {
435 goto Cleanup;
436 }
437
438 /* attempt to enable the SE_TAKE_OWNERSHIP_PRIVILEGE privilege */
439 TokenPrivileges.PrivilegeCount = 1;
440 TokenPrivileges.Privileges[0].Luid.LowPart = SE_TAKE_OWNERSHIP_PRIVILEGE;
441 TokenPrivileges.Privileges[0].Luid.HighPart = 0;
442 TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
443 Status = ZwAdjustPrivilegesToken(hToken,
444 FALSE,
445 &TokenPrivileges,
446 sizeof(TokenPrivileges),
447 &TokenPrivileges,
448 &ReturnLength);
449 if (!NT_SUCCESS(Status))
450 {
451 goto Cleanup;
452 }
453 TokenEnabled = (TokenPrivileges.PrivilegeCount != 0);
454
455 /* open the directory */
456 InitializeObjectAttributes(&ObjectAttributes,
457 DirectoryPath,
458 0,
459 NULL,
460 SecurityDescriptor);
461
462 Status = ZwOpenFile(&hDirectory,
463 SYNCHRONIZE | WRITE_OWNER,
464 &ObjectAttributes,
465 &IoStatusBlock,
466 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
467 FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT);
468 if (!NT_SUCCESS(Status))
469 {
470 goto Cleanup;
471 }
472
473 /* create the Administrators SID */
474 Status = RtlAllocateAndInitializeSid(&LocalSystemAuthority,
475 2,
476 SECURITY_BUILTIN_DOMAIN_RID,
477 DOMAIN_ALIAS_RID_ADMINS,
478 0,
479 0,
480 0,
481 0,
482 0,
483 0,
484 &AdminSid);
485 if (!NT_SUCCESS(Status))
486 {
487 goto Cleanup;
488 }
489
490 /* create the security descriptor */
491 Status = RtlCreateSecurityDescriptor(&AbsSD,
492 SECURITY_DESCRIPTOR_REVISION);
493 if (!NT_SUCCESS(Status))
494 {
495 goto Cleanup;
496 }
497
498 Status = RtlSetOwnerSecurityDescriptor(&AbsSD,
499 AdminSid,
500 FALSE);
501 if (!NT_SUCCESS(Status))
502 {
503 goto Cleanup;
504 }
505
506 /* attempt to take ownership */
507 Status = ZwSetSecurityObject(hDirectory,
508 OWNER_SECURITY_INFORMATION,
509 &AbsSD);
510
511 Cleanup:
512 if (TokenEnabled)
513 {
514 ZwAdjustPrivilegesToken(hToken,
515 FALSE,
516 &TokenPrivileges,
517 0,
518 NULL,
519 NULL);
520 }
521
522 if (AdminSid != NULL)
523 {
524 RtlFreeSid(AdminSid);
525 }
526
527 if (hDirectory != NULL)
528 {
529 ZwClose(hDirectory);
530 }
531
532 if (hToken != NULL)
533 {
534 ZwClose(hToken);
535 }
536
537 return Status;
538 }
539
540 /*
541 * @implemented
542 */
543 NTSTATUS
544 NTAPI
545 RtlCreateSystemVolumeInformationFolder(IN PUNICODE_STRING VolumeRootPath)
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 'cAeS');
663 RtlpFreeMemory(SecurityDescriptor,
664 'dSeS');
665
666 RtlFreeSid(SystemSid);
667 }
668
669 RtlpFreeStringMemory(NewPath.Buffer,
670 TAG_USTR);
671 return Status;
672 }
673
674 /* EOF */