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 
1109