[SHELL32] SHChangeNotify: Use tree for CDirectoryList (#6784)
[reactos.git] / drivers / filesystems / udfs / secursup.cpp
1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3 // All rights reserved
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*************************************************************************
7 *
8 * File: SecurSup.cpp
9 *
10 * Module: UDF File System Driver (Kernel mode execution only)
11 *
12 * Description:
13 * Contains code to handle the "Get/Set Security" dispatch entry points.
14 *
15 *************************************************************************/
16
17 #include "udffs.h"
18
19 // define the file specific bug-check id
20 #define UDF_BUG_CHECK_ID UDF_FILE_SECURITY
21
22 #ifdef UDF_ENABLE_SECURITY
23
24 NTSTATUS UDFConvertToSelfRelative(
25 IN OUT PSECURITY_DESCRIPTOR* SecurityDesc);
26
27 /*UCHAR FullControlSD[] = {
28 0x01, 0x00, 0x04, 0x80, 0x4c, 0x00, 0x00, 0x00,
29 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
30 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x38, 0x00,
31 0x02, 0x00, 0x00, 0x00, 0x00, 0x09, 0x18, 0x00,
32 0x00, 0x00, 0x00, 0x10, 0x01, 0x01, 0x00, 0x00,
33 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
34 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x18, 0x00,
35 0xff, 0x01, 0x1f, 0x00, 0x01, 0x01, 0x00, 0x00,
36 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
37 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00,
38 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
39 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
40 0x00, 0x00, 0x00, 0x00
41 };*/
42
43 /*************************************************************************
44 *
45 * Function: UDFGetSecurity()
46 *
47 * Description:
48 *
49 * Expected Interrupt Level (for execution) :
50 *
51 * IRQL_PASSIVE_LEVEL
52 *
53 * Return Value: Irrelevant.
54 *
55 *************************************************************************/
56 NTSTATUS
57 UDFGetSecurity(
58 IN PDEVICE_OBJECT DeviceObject, // the logical volume device object
59 IN PIRP Irp) // I/O Request Packet
60 {
61 NTSTATUS RC = STATUS_SUCCESS;
62 PtrUDFIrpContext PtrIrpContext = NULL;
63 BOOLEAN AreWeTopLevel = FALSE;
64
65 UDFPrint(("UDFGetSecurity\n"));
66 // BrutePoint();
67
68 FsRtlEnterFileSystem();
69 ASSERT(DeviceObject);
70 ASSERT(Irp);
71
72 // set the top level context
73 AreWeTopLevel = UDFIsIrpTopLevel(Irp);
74 ASSERT(!UDFIsFSDevObj(DeviceObject));
75 // Call the common Lock Control routine, with blocking allowed if
76 // synchronous
77 _SEH2_TRY {
78
79 // get an IRP context structure and issue the request
80 PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
81 if(PtrIrpContext) {
82 RC = UDFCommonGetSecurity(PtrIrpContext, Irp);
83 } else {
84 RC = STATUS_INSUFFICIENT_RESOURCES;
85 Irp->IoStatus.Status = RC;
86 Irp->IoStatus.Information = 0;
87 // complete the IRP
88 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
89 }
90
91 } __except (UDFExceptionFilter(PtrIrpContext, GetExceptionInformation())) {
92
93 RC = UDFExceptionHandler(PtrIrpContext, Irp);
94
95 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
96 }
97
98 if (AreWeTopLevel) {
99 IoSetTopLevelIrp(NULL);
100 }
101
102 FsRtlExitFileSystem();
103
104 return(RC);
105 } // end UDFGetSecurity()
106
107
108 /*************************************************************************
109 *
110 * Function: UDFCommonGetSecurity()
111 *
112 * Description:
113 * This is the common routine for getting Security (ACL) called
114 * by both the fsd and fsp threads
115 *
116 * Expected Interrupt Level (for execution) :
117 *
118 * IRQL_PASSIVE_LEVEL
119 *
120 * Return Value: Irrelevant
121 *
122 *************************************************************************/
123 NTSTATUS
124 UDFCommonGetSecurity(
125 IN PtrUDFIrpContext PtrIrpContext,
126 IN PIRP Irp)
127 {
128 NTSTATUS RC = STATUS_SUCCESS;
129 PIO_STACK_LOCATION IrpSp = NULL;
130 BOOLEAN PostRequest = FALSE;
131 BOOLEAN CanWait = FALSE;
132 PtrUDFNTRequiredFCB NtReqFcb = NULL;
133 BOOLEAN AcquiredFCB = FALSE;
134 PFILE_OBJECT FileObject = NULL;
135 PtrUDFFCB Fcb = NULL;
136 PtrUDFCCB Ccb = NULL;
137 PVOID PtrSystemBuffer = NULL;
138 ULONG BufferLength = 0;
139
140 UDFPrint(("UDFCommonGetSecurity\n"));
141
142 _SEH2_TRY {
143
144 // First, get a pointer to the current I/O stack location.
145 IrpSp = IoGetCurrentIrpStackLocation(Irp);
146 ASSERT(IrpSp);
147
148 FileObject = IrpSp->FileObject;
149 ASSERT(FileObject);
150
151 // Get the FCB and CCB pointers.
152 Ccb = (PtrUDFCCB)(FileObject->FsContext2);
153 ASSERT(Ccb);
154 Fcb = Ccb->Fcb;
155 ASSERT(Fcb);
156
157 /* if(!Fcb->Vcb->ReadSecurity)
158 try_return(RC = STATUS_NOT_IMPLEMENTED);*/
159
160 NtReqFcb = Fcb->NTRequiredFCB;
161 CanWait = ((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
162
163 // Acquire the FCB resource shared
164 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
165 if (!UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), CanWait)) {
166 // if (!UDFAcquireResourceShared(&(NtReqFcb->MainResource), CanWait)) {
167 PostRequest = TRUE;
168 try_return(RC = STATUS_PENDING);
169 }
170 AcquiredFCB = TRUE;
171
172 PtrSystemBuffer = UDFGetCallersBuffer(PtrIrpContext, Irp);
173 if(!PtrSystemBuffer)
174 try_return(RC = STATUS_INVALID_USER_BUFFER);
175 BufferLength = IrpSp->Parameters.QuerySecurity.Length;
176
177 if(!NtReqFcb->SecurityDesc) {
178 RC = UDFAssignAcl(Fcb->Vcb, FileObject, Fcb, NtReqFcb);
179 if(!NT_SUCCESS(RC))
180 try_return(RC);
181 }
182
183 _SEH2_TRY {
184 RC = SeQuerySecurityDescriptorInfo(&(IrpSp->Parameters.QuerySecurity.SecurityInformation),
185 (PSECURITY_DESCRIPTOR)PtrSystemBuffer,
186 &BufferLength,
187 &(NtReqFcb->SecurityDesc) );
188 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
189 RC = STATUS_BUFFER_TOO_SMALL;
190 }
191
192 try_exit: NOTHING;
193
194 } _SEH2_FINALLY {
195
196 // Release the FCB resources if acquired.
197 if (AcquiredFCB) {
198 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
199 UDFReleaseResource(&(NtReqFcb->MainResource));
200 AcquiredFCB = FALSE;
201 }
202
203 if (PostRequest) {
204 // Perform appropriate post related processing here
205 RC = UDFPostRequest(PtrIrpContext, Irp);
206 } else
207 if(!AbnormalTermination()) {
208 Irp->IoStatus.Status = RC;
209 Irp->IoStatus.Information = BufferLength;
210 // Free up the Irp Context
211 UDFReleaseIrpContext(PtrIrpContext);
212 // complete the IRP
213 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
214 }
215
216 } // end of "__finally" processing
217
218 return(RC);
219 }
220
221 #ifndef UDF_READ_ONLY_BUILD
222 /*************************************************************************
223 *
224 * Function: UDFSetSecurity()
225 *
226 * Description:
227 *
228 * Expected Interrupt Level (for execution) :
229 *
230 * IRQL_PASSIVE_LEVEL
231 *
232 * Return Value: Irrelevant.
233 *
234 *************************************************************************/
235 NTSTATUS
236 UDFSetSecurity(
237 IN PDEVICE_OBJECT DeviceObject, // the logical volume device object
238 IN PIRP Irp) // I/O Request Packet
239 {
240 NTSTATUS RC = STATUS_SUCCESS;
241 PtrUDFIrpContext PtrIrpContext = NULL;
242 BOOLEAN AreWeTopLevel = FALSE;
243
244 UDFPrint(("UDFSetSecurity\n"));
245 // BrutePoint();
246
247 FsRtlEnterFileSystem();
248 ASSERT(DeviceObject);
249 ASSERT(Irp);
250
251 // set the top level context
252 AreWeTopLevel = UDFIsIrpTopLevel(Irp);
253 // Call the common Lock Control routine, with blocking allowed if
254 // synchronous
255 _SEH2_TRY {
256
257 // get an IRP context structure and issue the request
258 PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
259 if(PtrIrpContext) {
260 RC = UDFCommonSetSecurity(PtrIrpContext, Irp);
261 } else {
262 RC = STATUS_INSUFFICIENT_RESOURCES;
263 Irp->IoStatus.Status = RC;
264 Irp->IoStatus.Information = 0;
265 // complete the IRP
266 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
267 }
268
269 } __except (UDFExceptionFilter(PtrIrpContext, GetExceptionInformation())) {
270
271 RC = UDFExceptionHandler(PtrIrpContext, Irp);
272
273 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
274 }
275
276 if (AreWeTopLevel) {
277 IoSetTopLevelIrp(NULL);
278 }
279
280 FsRtlExitFileSystem();
281
282 return(RC);
283 } // end UDFSetSecurity()
284
285
286 /*************************************************************************
287 *
288 * Function: UDFCommonSetSecurity()
289 *
290 * Description:
291 * This is the common routine for getting Security (ACL) called
292 * by both the fsd and fsp threads
293 *
294 * Expected Interrupt Level (for execution) :
295 *
296 * IRQL_PASSIVE_LEVEL
297 *
298 * Return Value: Irrelevant
299 *
300 *************************************************************************/
301 NTSTATUS
302 UDFCommonSetSecurity(
303 IN PtrUDFIrpContext PtrIrpContext,
304 IN PIRP Irp)
305 {
306 NTSTATUS RC = STATUS_SUCCESS;
307 PIO_STACK_LOCATION IrpSp = NULL;
308 BOOLEAN PostRequest = FALSE;
309 BOOLEAN CanWait = FALSE;
310 PtrUDFNTRequiredFCB NtReqFcb = NULL;
311 BOOLEAN AcquiredFCB = FALSE;
312 PFILE_OBJECT FileObject = NULL;
313 PtrUDFFCB Fcb = NULL;
314 PtrUDFCCB Ccb = NULL;
315 ACCESS_MASK DesiredAccess = 0;
316
317 UDFPrint(("UDFCommonSetSecurity\n"));
318
319 _SEH2_TRY {
320
321 // First, get a pointer to the current I/O stack location.
322 IrpSp = IoGetCurrentIrpStackLocation(Irp);
323 ASSERT(IrpSp);
324
325 FileObject = IrpSp->FileObject;
326 ASSERT(FileObject);
327
328 // Get the FCB and CCB pointers.
329 Ccb = (PtrUDFCCB)(FileObject->FsContext2);
330 ASSERT(Ccb);
331 Fcb = Ccb->Fcb;
332 ASSERT(Fcb);
333
334 if(!Fcb->Vcb->WriteSecurity)
335 try_return(RC = STATUS_NOT_IMPLEMENTED);
336
337 NtReqFcb = Fcb->NTRequiredFCB;
338 CanWait = ((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
339
340 // Acquire the FCB resource exclusive
341 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
342 if (!UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), CanWait)) {
343 PostRequest = TRUE;
344 try_return(RC = STATUS_PENDING);
345 }
346 AcquiredFCB = TRUE;
347
348 //OWNER_SECURITY_INFORMATION
349 if(IrpSp->Parameters.SetSecurity.SecurityInformation & OWNER_SECURITY_INFORMATION)
350 DesiredAccess |= WRITE_OWNER;
351 //GROUP_SECURITY_INFORMATION
352 if(IrpSp->Parameters.SetSecurity.SecurityInformation & GROUP_SECURITY_INFORMATION)
353 DesiredAccess |= WRITE_OWNER;
354 //DACL_SECURITY_INFORMATION
355 if(IrpSp->Parameters.SetSecurity.SecurityInformation & DACL_SECURITY_INFORMATION)
356 DesiredAccess |= WRITE_DAC;
357 //SACL_SECURITY_INFORMATION
358 if(IrpSp->Parameters.SetSecurity.SecurityInformation & SACL_SECURITY_INFORMATION)
359 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
360
361 _SEH2_TRY {
362 UDFConvertToSelfRelative(&(NtReqFcb->SecurityDesc));
363
364 KdDump(NtReqFcb->SecurityDesc, RtlLengthSecurityDescriptor(NtReqFcb->SecurityDesc));
365 UDFPrint(("\n"));
366
367 RC = SeSetSecurityDescriptorInfo(/*FileObject*/ NULL,
368 &(IrpSp->Parameters.SetSecurity.SecurityInformation),
369 IrpSp->Parameters.SetSecurity.SecurityDescriptor,
370 &(NtReqFcb->SecurityDesc),
371 NonPagedPool,
372 IoGetFileObjectGenericMapping() );
373
374 KdDump(NtReqFcb->SecurityDesc, RtlLengthSecurityDescriptor(NtReqFcb->SecurityDesc));
375
376 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
377 RC = STATUS_INVALID_PARAMETER;
378 }
379 if(NT_SUCCESS(RC)) {
380 NtReqFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_SD_MODIFIED;
381
382 UDFNotifyFullReportChange( Fcb->Vcb, Fcb->FileInfo,
383 FILE_NOTIFY_CHANGE_SECURITY,
384 FILE_ACTION_MODIFIED);
385 }
386
387 try_exit: NOTHING;
388
389 } _SEH2_FINALLY {
390
391 // Release the FCB resources if acquired.
392 if (AcquiredFCB) {
393 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
394 UDFReleaseResource(&(NtReqFcb->MainResource));
395 AcquiredFCB = FALSE;
396 }
397
398 if (PostRequest) {
399 // Perform appropriate post related processing here
400 RC = UDFPostRequest(PtrIrpContext, Irp);
401 } else
402 if(!AbnormalTermination()) {
403 Irp->IoStatus.Status = RC;
404 Irp->IoStatus.Information = 0;
405 // Free up the Irp Context
406 UDFReleaseIrpContext(PtrIrpContext);
407 // complete the IRP
408 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
409 }
410
411 } // end of "__finally" processing
412
413 return(RC);
414 } // ens UDFCommonSetSecurity()
415
416 #endif //UDF_READ_ONLY_BUILD
417 #endif //UDF_ENABLE_SECURITY
418
419 NTSTATUS
420 UDFReadSecurity(
421 IN PVCB Vcb,
422 IN PtrUDFFCB Fcb,
423 IN PSECURITY_DESCRIPTOR* SecurityDesc
424 )
425 {
426 #ifdef UDF_ENABLE_SECURITY
427 PUDF_FILE_INFO FileInfo = NULL;
428 PUDF_FILE_INFO SDirInfo = NULL;
429 PUDF_FILE_INFO AclInfo = NULL;
430 NTSTATUS RC;
431 ULONG NumberBytesRead;
432 PERESOURCE Res1 = NULL;
433
434 UDFPrint(("UDFReadSecurity\n"));
435
436 _SEH2_TRY {
437
438 FileInfo = Fcb->FileInfo;
439 ASSERT(FileInfo);
440 if(!FileInfo) {
441 UDFPrint((" Volume Security\n"));
442 try_return(RC = STATUS_NO_SECURITY_ON_OBJECT);
443 }
444 if(Vcb->VCBFlags & UDF_VCB_FLAGS_RAW_DISK) {
445 UDFPrint((" No Security on blank volume\n"));
446 try_return(RC = STATUS_NO_SECURITY_ON_OBJECT);
447 }
448
449 // Open Stream Directory
450 RC = UDFOpenStreamDir__(Vcb, FileInfo, &SDirInfo);
451
452 if(RC == STATUS_NOT_FOUND)
453 try_return(RC = STATUS_NO_SECURITY_ON_OBJECT);
454 if(!NT_SUCCESS(RC)) {
455 if(UDFCleanUpFile__(Vcb, SDirInfo)) {
456 if(SDirInfo) MyFreePool__(SDirInfo);
457 }
458 SDirInfo = NULL;
459 try_return(RC);
460 }
461 // Acquire SDir exclusively if Fcb present
462 if(SDirInfo->Fcb) {
463 BrutePoint();
464 UDF_CHECK_PAGING_IO_RESOURCE(SDirInfo->Fcb->NTRequiredFCB);
465 UDFAcquireResourceExclusive(Res1 = &(SDirInfo->Fcb->NTRequiredFCB->MainResource),TRUE);
466 }
467
468 // Open Acl Stream
469 RC = UDFOpenFile__(Vcb,
470 FALSE,TRUE,&(UDFGlobalData.AclName),
471 SDirInfo,&AclInfo,NULL);
472 if(RC == STATUS_OBJECT_NAME_NOT_FOUND)
473 try_return(RC = STATUS_NO_SECURITY_ON_OBJECT);
474 if(!NT_SUCCESS(RC)) {
475 if(UDFCleanUpFile__(Vcb, AclInfo)) {
476 if(AclInfo) MyFreePool__(AclInfo);
477 }
478 AclInfo = NULL;
479 try_return(RC);
480 }
481
482 NumberBytesRead = (ULONG)UDFGetFileSize(AclInfo);
483 (*SecurityDesc) = DbgAllocatePool(NonPagedPool, NumberBytesRead);
484 if(!(*SecurityDesc))
485 try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
486 RC = UDFReadFile__(Vcb, AclInfo, 0, NumberBytesRead,
487 FALSE, (PCHAR)(*SecurityDesc), &NumberBytesRead);
488 if(!NT_SUCCESS(RC))
489 try_return(RC);
490
491 RC = RtlValidSecurityDescriptor(*SecurityDesc);
492
493 try_exit: NOTHING;
494
495 } _SEH2_FINALLY {
496
497 if(AclInfo) {
498 UDFCloseFile__(Vcb, AclInfo);
499 if(UDFCleanUpFile__(Vcb, AclInfo))
500 MyFreePool__(AclInfo);
501 }
502
503 if(SDirInfo) {
504 UDFCloseFile__(Vcb, SDirInfo);
505 if(UDFCleanUpFile__(Vcb, SDirInfo))
506 MyFreePool__(SDirInfo);
507 }
508
509 if(!NT_SUCCESS(RC) && (*SecurityDesc)) {
510 DbgFreePool(*SecurityDesc);
511 (*SecurityDesc) = NULL;
512 }
513 if(Res1)
514 UDFReleaseResource(Res1);
515 }
516
517 return RC;
518 #else
519 return STATUS_NO_SECURITY_ON_OBJECT;
520 #endif //UDF_ENABLE_SECURITY
521
522 } // end UDFReadSecurity()
523
524 #ifdef UDF_ENABLE_SECURITY
525 NTSTATUS
526 UDFConvertToSelfRelative(
527 IN OUT PSECURITY_DESCRIPTOR* SecurityDesc
528 )
529 {
530 NTSTATUS RC;
531 SECURITY_INFORMATION SecurityInformation;
532 PSECURITY_DESCRIPTOR NewSD;
533 ULONG Len;
534
535 UDFPrint((" UDFConvertToSelfRelative\n"));
536
537 if(!(*SecurityDesc))
538 return STATUS_NO_SECURITY_ON_OBJECT;
539
540 SecurityInformation = FULL_SECURITY_INFORMATION;
541 Len = RtlLengthSecurityDescriptor(*SecurityDesc);
542 ASSERT(Len <= 1024);
543 NewSD = (PSECURITY_DESCRIPTOR)DbgAllocatePool(NonPagedPool, Len);
544 if(!NewSD)
545 return STATUS_INSUFFICIENT_RESOURCES;
546 _SEH2_TRY {
547 RC = SeQuerySecurityDescriptorInfo(&SecurityInformation, NewSD, &Len, SecurityDesc);
548 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
549 RC = STATUS_INSUFFICIENT_RESOURCES;
550 }
551
552 if(NT_SUCCESS(RC)) {
553 DbgFreePool(*SecurityDesc);
554 *SecurityDesc = NewSD;
555 } else {
556 DbgFreePool(NewSD);
557 }
558 return RC;
559 } // end UDFConvertToSelfRelative()
560
561 NTSTATUS
562 UDFInheritAcl(
563 IN PVCB Vcb,
564 IN PSECURITY_DESCRIPTOR* ParentSecurityDesc,
565 IN OUT PSECURITY_DESCRIPTOR* SecurityDesc
566 )
567 {
568 NTSTATUS RC;
569 SECURITY_INFORMATION SecurityInformation;
570 ULONG Len;
571
572 UDFPrint((" UDFInheritAcl\n"));
573
574 if(!(*ParentSecurityDesc)) {
575 *SecurityDesc = NULL;
576 return STATUS_SUCCESS;
577 }
578
579 SecurityInformation = FULL_SECURITY_INFORMATION;
580 Len = RtlLengthSecurityDescriptor(*ParentSecurityDesc);
581 *SecurityDesc = (PSECURITY_DESCRIPTOR)DbgAllocatePool(NonPagedPool, Len);
582 if(!(*SecurityDesc))
583 return STATUS_INSUFFICIENT_RESOURCES;
584 _SEH2_TRY {
585 RC = SeQuerySecurityDescriptorInfo(&SecurityInformation, *SecurityDesc, &Len, ParentSecurityDesc);
586 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
587 RC = STATUS_INSUFFICIENT_RESOURCES;
588 }
589
590 if(!NT_SUCCESS(RC)) {
591 DbgFreePool(*SecurityDesc);
592 *SecurityDesc = NULL;
593 }
594 return RC;
595 } // end UDFInheritAcl()
596
597 NTSTATUS
598 UDFBuildEmptyAcl(
599 IN PVCB Vcb,
600 IN PSECURITY_DESCRIPTOR* SecurityDesc
601 )
602 {
603 NTSTATUS RC;
604 ULONG Len = 2 * (sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + sizeof(ULONG)*4 /*RtlLengthSid(SeExports->SeWorldSid)*/);
605
606 UDFPrint((" UDFBuildEmptyAcl\n"));
607 // Create Security Descriptor
608 (*SecurityDesc) = (PSECURITY_DESCRIPTOR)DbgAllocatePool(NonPagedPool,
609 sizeof(SECURITY_DESCRIPTOR) + Len);
610 if(!(*SecurityDesc))
611 return STATUS_INSUFFICIENT_RESOURCES;
612
613 RC = RtlCreateSecurityDescriptor(*SecurityDesc, SECURITY_DESCRIPTOR_REVISION);
614
615 if(!NT_SUCCESS(RC)) {
616 DbgFreePool(*SecurityDesc);
617 *((PULONG)SecurityDesc) = NULL;
618 }
619 return RC;
620 } // end UDFBuildEmptyAcl()
621
622 NTSTATUS
623 UDFBuildFullControlAcl(
624 IN PVCB Vcb,
625 IN PSECURITY_DESCRIPTOR* SecurityDesc
626 )
627 {
628 NTSTATUS RC;
629 PACL Acl;
630 ULONG Len = sizeof(ACL) + 2*(sizeof(ACCESS_ALLOWED_ACE) + sizeof(ULONG)*4 /*- sizeof(ULONG)*/ /*+ RtlLengthSid(SeExports->SeWorldSid)*/);
631
632 UDFPrint((" UDFBuildFullControlAcl\n"));
633 // Create Security Descriptor
634 RC = UDFBuildEmptyAcl(Vcb, SecurityDesc);
635 if(!NT_SUCCESS(RC))
636 return RC;
637
638 // Set Owner
639 RC = RtlSetOwnerSecurityDescriptor(*SecurityDesc, SeExports->SeWorldSid, FALSE);
640 if(!NT_SUCCESS(RC)) {
641 DbgFreePool(*SecurityDesc);
642 *((PULONG)SecurityDesc) = NULL;
643 return RC;
644 }
645
646 // Set Group
647 RC = RtlSetGroupSecurityDescriptor(*SecurityDesc, SeExports->SeWorldSid, FALSE);
648 if(!NT_SUCCESS(RC)) {
649 DbgFreePool(*SecurityDesc);
650 *((PULONG)SecurityDesc) = NULL;
651 return RC;
652 }
653
654 // Create empty Acl
655 Acl = (PACL)DbgAllocatePool(NonPagedPool, Len);
656 if(!Acl) {
657 DbgFreePool(*SecurityDesc);
658 *((PULONG)SecurityDesc) = NULL;
659 return RC;
660 }
661 RtlZeroMemory(Acl, Len);
662
663 RC = RtlCreateAcl(Acl, Len, ACL_REVISION);
664 if(!NT_SUCCESS(RC)) {
665 DbgFreePool(Acl);
666 DbgFreePool(*SecurityDesc);
667 *((PULONG)SecurityDesc) = NULL;
668 return RC;
669 }
670
671 // Add (All)(All) access for Everyone
672 /* RC = RtlAddAccessAllowedAce(Acl, ACL_REVISION,
673 GENERIC_ALL,
674 SeExports->SeWorldSid);*/
675
676 RC = RtlAddAccessAllowedAce(Acl, ACL_REVISION,
677 FILE_ALL_ACCESS,
678 SeExports->SeWorldSid);
679
680 if(!NT_SUCCESS(RC)) {
681 DbgFreePool(Acl);
682 DbgFreePool(*SecurityDesc);
683 *((PULONG)SecurityDesc) = NULL;
684 return RC;
685 }
686
687 // Add Acl to Security Descriptor
688 RC = RtlSetDaclSecurityDescriptor(*SecurityDesc, TRUE, Acl, FALSE);
689 if(!NT_SUCCESS(RC)) {
690 DbgFreePool(Acl);
691 DbgFreePool(*SecurityDesc);
692 *((PULONG)SecurityDesc) = NULL;
693 return RC;
694 }
695
696 RC = UDFConvertToSelfRelative(SecurityDesc);
697
698 DbgFreePool(Acl);
699
700 return RC;
701 } // end UDFBuildFullControlAcl()
702
703 #endif // UDF_ENABLE_SECURITY
704
705 NTSTATUS
706 UDFAssignAcl(
707 IN PVCB Vcb,
708 IN PFILE_OBJECT FileObject, // OPTIONAL
709 IN PtrUDFFCB Fcb,
710 IN PtrUDFNTRequiredFCB NtReqFcb
711 )
712 {
713 NTSTATUS RC = STATUS_SUCCESS;
714 #ifdef UDF_ENABLE_SECURITY
715 // SECURITY_INFORMATION SecurityInformation;
716
717 // UDFPrint((" UDFAssignAcl\n"));
718 if(!NtReqFcb->SecurityDesc) {
719
720 PSECURITY_DESCRIPTOR ExplicitSecurity = NULL;
721
722 if(UDFIsAStreamDir(Fcb->FileInfo) || UDFIsAStream(Fcb->FileInfo)) {
723 // Stream/SDir security
724 NtReqFcb->SecurityDesc = Fcb->FileInfo->ParentFile->Dloc->CommonFcb->SecurityDesc;
725 return STATUS_SUCCESS;
726 } else
727 if(!Fcb->FileInfo) {
728 // Volume security
729 if(Vcb->RootDirFCB &&
730 Vcb->RootDirFCB->FileInfo &&
731 Vcb->RootDirFCB->FileInfo->Dloc &&
732 Vcb->RootDirFCB->FileInfo->Dloc->CommonFcb) {
733 RC = UDFInheritAcl(Vcb, &(Vcb->RootDirFCB->FileInfo->Dloc->CommonFcb->SecurityDesc), &ExplicitSecurity);
734 } else {
735 NtReqFcb->SecurityDesc = NULL;
736 RC = STATUS_NO_SECURITY_ON_OBJECT;
737 }
738 return RC;
739 }
740
741 RC = UDFReadSecurity(Vcb, Fcb, &ExplicitSecurity);
742 if(RC == STATUS_NO_SECURITY_ON_OBJECT) {
743 if(!Fcb->FileInfo->ParentFile) {
744 RC = UDFBuildFullControlAcl(Vcb, &ExplicitSecurity);
745 } else {
746 RC = UDFInheritAcl(Vcb, &(Fcb->FileInfo->ParentFile->Dloc->CommonFcb->SecurityDesc), &ExplicitSecurity);
747 }
748 /* if(NT_SUCCESS(RC)) {
749 NtReqFcb->NtReqFCBFlags |= UDF_NTREQ_FCB_SD_MODIFIED;
750 }*/
751 }
752 if(NT_SUCCESS(RC)) {
753
754 // SecurityInformation = FULL_SECURITY_INFORMATION;
755 NtReqFcb->SecurityDesc = ExplicitSecurity;
756
757 /* RC = SeSetSecurityDescriptorInfo(FileObject,
758 &SecurityInformation,
759 ExplicitSecurity,
760 &(NtReqFcb->SecurityDesc),
761 NonPagedPool,
762 IoGetFileObjectGenericMapping() );*/
763
764 }
765 }
766 #endif //UDF_ENABLE_SECURITY
767 return RC;
768 } // end UDFAssignAcl()
769
770
771 VOID
772 UDFDeassignAcl(
773 IN PtrUDFNTRequiredFCB NtReqFcb,
774 IN BOOLEAN AutoInherited
775 )
776 {
777 #ifdef UDF_ENABLE_SECURITY
778 // NTSTATUS RC = STATUS_SUCCESS;
779
780 // UDFPrint((" UDFDeassignAcl\n"));
781 if(!NtReqFcb->SecurityDesc)
782 return;
783
784 if(AutoInherited) {
785 NtReqFcb->SecurityDesc = NULL;
786 return;
787 }
788
789 SeDeassignSecurity(&(NtReqFcb->SecurityDesc));
790 NtReqFcb->SecurityDesc = NULL; // HA BCRK CLU4
791 #endif //UDF_ENABLE_SECURITY
792 return;
793 } // end UDFDeassignAcl()
794
795 NTSTATUS
796 UDFWriteSecurity(
797 IN PVCB Vcb,
798 IN PtrUDFFCB Fcb,
799 IN PSECURITY_DESCRIPTOR* SecurityDesc
800 )
801 {
802 #ifdef UDF_ENABLE_SECURITY
803 PUDF_FILE_INFO FileInfo = NULL;
804 PUDF_FILE_INFO SDirInfo = NULL;
805 PUDF_FILE_INFO AclInfo = NULL;
806 PERESOURCE Res1 = NULL;
807 NTSTATUS RC;
808 ULONG NumberBytesRead;
809
810 // UDFPrint(("UDFWriteSecurity\n"));
811
812 #if !defined(UDF_READ_ONLY_BUILD)
813
814 if(!Vcb->WriteSecurity ||
815 (Vcb->VCBFlags & (UDF_VCB_FLAGS_VOLUME_READ_ONLY |
816 UDF_VCB_FLAGS_MEDIA_READ_ONLY)))
817
818 #endif //!defined(UDF_READ_ONLY_BUILD)
819
820 return STATUS_SUCCESS;
821
822 #if !defined(UDF_READ_ONLY_BUILD)
823
824 _SEH2_TRY {
825
826 FileInfo = Fcb->FileInfo;
827 ASSERT(FileInfo);
828 if(!FileInfo) {
829 UDFPrint((" Volume Security\n"));
830 try_return(RC = STATUS_SUCCESS);
831 }
832
833 if(!(Fcb->NTRequiredFCB->NtReqFCBFlags & UDF_NTREQ_FCB_SD_MODIFIED))
834 try_return(RC = STATUS_SUCCESS);
835
836 // Open Stream Directory
837 RC = UDFOpenStreamDir__(Vcb, FileInfo, &SDirInfo);
838
839 if(RC == STATUS_NOT_FOUND) {
840 RC = UDFCreateStreamDir__(Vcb, FileInfo, &SDirInfo);
841 }
842 if(!NT_SUCCESS(RC)) {
843 if(UDFCleanUpFile__(Vcb, SDirInfo)) {
844 if(SDirInfo) MyFreePool__(SDirInfo);
845 }
846 SDirInfo = NULL;
847 try_return(RC);
848 }
849 // Acquire SDir exclusively if Fcb present
850 if(SDirInfo->Fcb) {
851 BrutePoint();
852 UDF_CHECK_PAGING_IO_RESOURCE(SDirInfo->Fcb->NTRequiredFCB);
853 UDFAcquireResourceExclusive(Res1 = &(SDirInfo->Fcb->NTRequiredFCB->MainResource),TRUE);
854 }
855
856 // Open Acl Stream
857 RC = UDFOpenFile__(Vcb,
858 FALSE,TRUE,&(UDFGlobalData.AclName),
859 SDirInfo,&AclInfo,NULL);
860 if(RC == STATUS_OBJECT_NAME_NOT_FOUND) {
861 RC = UDFCreateFile__(Vcb, FALSE, &(UDFGlobalData.AclName),
862 0, 0, FALSE, FALSE, SDirInfo, &AclInfo);
863 }
864 if(!NT_SUCCESS(RC)) {
865 if(UDFCleanUpFile__(Vcb, AclInfo)) {
866 if(AclInfo) MyFreePool__(AclInfo);
867 }
868 AclInfo = NULL;
869 try_return(RC);
870 }
871
872 if(!(*SecurityDesc)) {
873 UDFFlushFile__(Vcb, AclInfo);
874 RC = UDFUnlinkFile__(Vcb, AclInfo, TRUE);
875 try_return(RC);
876 }
877 NumberBytesRead = RtlLengthSecurityDescriptor(*SecurityDesc);
878
879 RC = UDFWriteFile__(Vcb, AclInfo, 0, NumberBytesRead,
880 FALSE, (PCHAR)(*SecurityDesc), &NumberBytesRead);
881 if(!NT_SUCCESS(RC))
882 try_return(RC);
883
884 Fcb->NTRequiredFCB->NtReqFCBFlags &= ~UDF_NTREQ_FCB_SD_MODIFIED;
885
886 try_exit: NOTHING;
887
888 } _SEH2_FINALLY {
889
890 if(AclInfo) {
891 UDFCloseFile__(Vcb, AclInfo);
892 if(UDFCleanUpFile__(Vcb, AclInfo))
893 MyFreePool__(AclInfo);
894 }
895
896 if(SDirInfo) {
897 UDFCloseFile__(Vcb, SDirInfo);
898 if(UDFCleanUpFile__(Vcb, SDirInfo))
899 MyFreePool__(SDirInfo);
900 }
901 if(Res1)
902 UDFReleaseResource(Res1);
903 }
904
905 return RC;
906
907 #endif //!defined(UDF_READ_ONLY_BUILD)
908 #endif //UDF_ENABLE_SECURITY
909
910 return STATUS_SUCCESS;
911
912 } // end UDFWriteSecurity()
913
914 PSECURITY_DESCRIPTOR
915 UDFLookUpAcl(
916 IN PVCB Vcb,
917 PFILE_OBJECT FileObject, // OPTIONAL
918 IN PtrUDFFCB Fcb
919 )
920 {
921 UDFAssignAcl(Vcb, FileObject, Fcb, Fcb->NTRequiredFCB);
922 return (Fcb->NTRequiredFCB->SecurityDesc);
923 } // end UDFLookUpAcl()
924
925
926 NTSTATUS
927 UDFCheckAccessRights(
928 PFILE_OBJECT FileObject, // OPTIONAL
929 PACCESS_STATE AccessState,
930 PtrUDFFCB Fcb,
931 PtrUDFCCB Ccb, // OPTIONAL
932 ACCESS_MASK DesiredAccess,
933 USHORT ShareAccess
934 )
935 {
936 NTSTATUS RC;
937 BOOLEAN ROCheck = FALSE;
938 #ifdef UDF_ENABLE_SECURITY
939 BOOLEAN SecurityCheck;
940 PSECURITY_DESCRIPTOR SecDesc;
941 SECURITY_SUBJECT_CONTEXT SubjectContext;
942 ACCESS_MASK LocalAccessMask;
943 #endif //UDF_ENABLE_SECURITY
944
945 // Check attr compatibility
946 ASSERT(Fcb);
947 ASSERT(Fcb->Vcb);
948 #ifdef UDF_READ_ONLY_BUILD
949 goto treat_as_ro;
950 #endif //UDF_READ_ONLY_BUILD
951
952 if(Fcb->FCBFlags & UDF_FCB_READ_ONLY) {
953 ROCheck = TRUE;
954 } else
955 if((Fcb->Vcb->origIntegrityType == INTEGRITY_TYPE_OPEN) &&
956 Ccb && !(Ccb->CCBFlags & UDF_CCB_VOLUME_OPEN) &&
957 (Fcb->Vcb->CompatFlags & UDF_VCB_IC_DIRTY_RO)) {
958 AdPrint(("force R/O on dirty\n"));
959 ROCheck = TRUE;
960 }
961 if(ROCheck) {
962 #ifdef UDF_READ_ONLY_BUILD
963 treat_as_ro:
964 #endif //UDF_READ_ONLY_BUILD
965 ACCESS_MASK DesiredAccessMask = 0;
966
967 if(Fcb->Vcb->CompatFlags & UDF_VCB_IC_WRITE_IN_RO_DIR) {
968 if(Fcb->FCBFlags & UDF_FCB_DIRECTORY) {
969 DesiredAccessMask = (FILE_WRITE_EA |
970 DELETE);
971 } else {
972 DesiredAccessMask = (FILE_WRITE_DATA |
973 FILE_APPEND_DATA |
974 FILE_WRITE_EA |
975 DELETE);
976 }
977 } else {
978 DesiredAccessMask = (FILE_WRITE_DATA |
979 FILE_APPEND_DATA |
980 FILE_WRITE_EA |
981 FILE_DELETE_CHILD |
982 FILE_ADD_SUBDIRECTORY |
983 FILE_ADD_FILE |
984 DELETE);
985 }
986 if(DesiredAccess & DesiredAccessMask)
987 return STATUS_ACCESS_DENIED;
988 }
989 #ifdef UDF_ENABLE_SECURITY
990 // Check Security
991 // NOTE: we should not perform security check if an empty DesiredAccess
992 // was specified. AFAIU, SeAccessCheck() will return FALSE in this case.
993 SecDesc = UDFLookUpAcl(Fcb->Vcb, FileObject, Fcb);
994 if(SecDesc && DesiredAccess) {
995 SeCaptureSubjectContext(&SubjectContext);
996 SecurityCheck =
997 SeAccessCheck(SecDesc,
998 &SubjectContext,
999 FALSE,
1000 DesiredAccess,
1001 Ccb ? Ccb->PreviouslyGrantedAccess : 0,
1002 NULL,
1003 IoGetFileObjectGenericMapping(),
1004 UserMode,
1005 Ccb ? &(Ccb->PreviouslyGrantedAccess) : &LocalAccessMask,
1006 &RC);
1007 SeReleaseSubjectContext(&SubjectContext);
1008
1009 if(!SecurityCheck) {
1010 return RC;
1011 } else
1012 #endif //UDF_ENABLE_SECURITY
1013 if(DesiredAccess & ACCESS_SYSTEM_SECURITY) {
1014 if (!SeSinglePrivilegeCheck(SeExports->SeSecurityPrivilege, UserMode))
1015 return STATUS_ACCESS_DENIED;
1016 Ccb->PreviouslyGrantedAccess |= ACCESS_SYSTEM_SECURITY;
1017 }
1018 #ifdef UDF_ENABLE_SECURITY
1019 }
1020 #endif //UDF_ENABLE_SECURITY
1021 if(FileObject) {
1022 if (Fcb->OpenHandleCount) {
1023 // The FCB is currently in use by some thread.
1024 // We must check whether the requested access/share access
1025 // conflicts with the existing open operations.
1026 RC = IoCheckShareAccess(DesiredAccess, ShareAccess, FileObject,
1027 &(Fcb->NTRequiredFCB->FCBShareAccess), TRUE);
1028 #ifndef UDF_ENABLE_SECURITY
1029 if(Ccb)
1030 Ccb->PreviouslyGrantedAccess |= DesiredAccess;
1031 IoUpdateShareAccess(FileObject, &(Fcb->NTRequiredFCB->FCBShareAccess));
1032 #endif //UDF_ENABLE_SECURITY
1033 } else {
1034 IoSetShareAccess(DesiredAccess, ShareAccess, FileObject, &(Fcb->NTRequiredFCB->FCBShareAccess));
1035 #ifndef UDF_ENABLE_SECURITY
1036 if(Ccb)
1037 Ccb->PreviouslyGrantedAccess = DesiredAccess;
1038 #endif //UDF_ENABLE_SECURITY
1039 RC = STATUS_SUCCESS;
1040 }
1041 } else {
1042 // we get here if given file was opened for internal purposes
1043 RC = STATUS_SUCCESS;
1044 }
1045 return RC;
1046 } // end UDFCheckAccessRights()
1047
1048 NTSTATUS
1049 UDFSetAccessRights(
1050 PFILE_OBJECT FileObject,
1051 PACCESS_STATE AccessState,
1052 PtrUDFFCB Fcb,
1053 PtrUDFCCB Ccb,
1054 ACCESS_MASK DesiredAccess,
1055 USHORT ShareAccess
1056 )
1057 {
1058 #ifndef UDF_ENABLE_SECURITY
1059 ASSERT(Ccb);
1060 ASSERT(Fcb->FileInfo);
1061
1062 return UDFCheckAccessRights(FileObject, AccessState, Fcb, Ccb, DesiredAccess, ShareAccess);
1063
1064 #else //UDF_ENABLE_SECURITY
1065
1066 NTSTATUS RC;
1067 // Set Security on Object
1068 PSECURITY_DESCRIPTOR SecDesc;
1069 SECURITY_SUBJECT_CONTEXT SubjectContext;
1070 BOOLEAN AutoInherit;
1071
1072 ASSERT(Ccb);
1073 ASSERT(Fcb->FileInfo);
1074
1075 SecDesc = UDFLookUpAcl(Fcb->Vcb, FileObject, Fcb);
1076 AutoInherit = UDFIsAStreamDir(Fcb->FileInfo) || UDFIsAStream(Fcb->FileInfo);
1077
1078 if(SecDesc && !AutoInherit) {
1079 // Get caller's User/Primary Group info
1080 SeCaptureSubjectContext(&SubjectContext);
1081 RC = SeAssignSecurity(
1082 Fcb->FileInfo->ParentFile->Dloc->CommonFcb->SecurityDesc,
1083 // NULL,
1084 AccessState->SecurityDescriptor,
1085 &(Fcb->NTRequiredFCB->SecurityDesc),
1086 UDFIsADirectory(Fcb->FileInfo),
1087 &SubjectContext,
1088 IoGetFileObjectGenericMapping(),
1089 NonPagedPool);
1090 SeReleaseSubjectContext(&SubjectContext);
1091 UDFConvertToSelfRelative(&(Fcb->NTRequiredFCB->SecurityDesc));
1092
1093 if(!NT_SUCCESS(RC)) {
1094 Clean_Up_SD:
1095 UDFDeassignAcl(Fcb->NTRequiredFCB, AutoInherit);
1096 return RC;
1097 }
1098 }
1099
1100 RC = UDFCheckAccessRights(FileObject, AccessState, Fcb, Ccb, DesiredAccess, ShareAccess);
1101 if(!NT_SUCCESS(RC))
1102 goto Clean_Up_SD;
1103 return RC;
1104
1105 #endif //UDF_ENABLE_SECURITY
1106
1107 } // end UDFSetAccessRights()
1108