dokany icon indicating copy to clipboard operation
dokany copied to clipboard

How to disable virtual disk renaming?

Open stroev-ao opened this issue 1 year ago • 23 comments

This does not interfere with the operation of the disk, but from a logical point of view, this should not be possible, since the disk name in my case is set remotely.

stroev-ao avatar Sep 01 '23 14:09 stroev-ao

I haven't tried but I am pretty sure this is due to the default sddl (you can find the value in sys/dokan.h) allowing this. You can set your custom value and deny the rename at mount time with the dokan option field VolumeSecurityDescriptor

Liryna avatar Sep 04 '23 15:09 Liryna

I use the InitializeSecurityDescriptor and SetSecurityDescriptorDacl methods from advapi32.dll, get the SECURITY_DESCRIPTOR structure, convert its IntPtr to a byte array and set it to the VolumeSecurityDescriptor field. After that I get an exception when calling DokanBuilder.Build. Am I doing it right? image image image

stroev-ao avatar Sep 05 '23 13:09 stroev-ao

Sorry I haven't tried it myself from C# but there is indeed a Marshall allocation issue here

Liryna avatar Sep 05 '23 14:09 Liryna

Can you create an c++ example please?

stroev-ao avatar Sep 05 '23 14:09 stroev-ao

I use the InitializeSecurityDescriptor and SetSecurityDescriptorDacl methods from advapi32.dll, get the SECURITY_DESCRIPTOR structure, convert its IntPtr to a byte array and set it to the VolumeSecurityDescriptor field. After that I get an exception when calling DokanBuilder.Build. Am I doing it right?

I would strongly suggest that you use .NET model objects for this as far as possible.

        var sec = new FileSecurity();

        sec.AddAccessRule( ... );

        var bytes = sec.GetSecurityDescriptorBinaryForm();

        options.VolumeSecurityDescriptor = bytes;
        options.VolumeSecurityDescriptorLength = bytes.Length;

There could of course still be things that you need to call through P/Invoke depending on what you want to do. But in my experience, that is almost never needed.

Does this help in your case?

LTRData avatar Sep 05 '23 19:09 LTRData

Thanks for the advice @LTRData! I tried to do it in .NET model objects but got the same exception. I also tried not setting a value in the VolumeSecurityDescriptorLength field - doesn't matter. image

stroev-ao avatar Sep 06 '23 03:09 stroev-ao

Could you share some details about the exception you get? What type of exception and if there are any more details in it.

LTRData avatar Sep 06 '23 12:09 LTRData

Sure. Exception type is System.ArgumentException. Message: Type could not be marshaled because the length of an embedded array instance does not match the declared length in the layout. Stack trace: at System.StubHelpers.MngdFixedArrayMarshaler.ConvertSpaceToNative(IntPtr pMarshalState, Object& pManagedHome, IntPtr pNativeHome) --- End of stack trace from previous location --- at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at Interop.Ole32.CoTaskMemFree(IntPtr ptr) at System.Runtime.InteropServices.Marshal.StructureToPtr(Object structure, IntPtr ptr, Boolean fDeleteOld) at System.Runtime.InteropServices.Marshal.StructureToPtr[T](T structure, IntPtr ptr, Boolean fDeleteOld) at DokanNet.NativeStructWrapper`1..ctor(T obj) at DokanNet.NativeStructWrapper.Wrap[T](T obj) at DokanNet.DokanInstance..ctor(ILogger logger, DOKAN_OPTIONS options, IDokanOperations operations) at DokanNet.DokanInstanceBuilder.Build(IDokanOperations operations) at MyClass (where DokanBuilder.Build is called).

What other information might help?

stroev-ao avatar Sep 06 '23 12:09 stroev-ao

Ah okay I understand. I missed that part. You need to resize the array: Array.Resize(ref bytes, 16384);

LTRData avatar Sep 06 '23 12:09 LTRData

Ah okay I understand. I missed that part. You need to resize the array: Array.Resize(ref bytes, 16384);

Okay, one more exception. Type: DokanException. Message: Can't install the Dokan driver. Stack trace: at DokanNet.DokanInstance..ctor(ILogger logger, DOKAN_OPTIONS options, IDokanOperations operations) at DokanNet.DokanInstanceBuilder.Build(IDokanOperations operations) at MyClass (where DokanBuilder.Build is called).

Am I doing it right? image

stroev-ao avatar Sep 06 '23 12:09 stroev-ao

Have you installed the Dokan setup package? Did you get any errors when you did that? What does the command sc query dokan2 at command line say?

LTRData avatar Sep 06 '23 13:09 LTRData

Have you installed the Dokan setup package? Did you get any errors when you did that? What does the command sc query dokan2 at command line say?

Yes, the Dokan package installed without errors. image The command sc query dokan2 result: image

stroev-ao avatar Sep 06 '23 13:09 stroev-ao

Strange. Could it be some kind of version mismatch between the native dokan2.dll that gets loaded into your process and Dokan2 driver? I am unsure in this case. It looks like it should have worked.

LTRData avatar Sep 06 '23 13:09 LTRData

Strange. Could it be some kind of version mismatch between the native dokan2.dll that gets loaded into your process and Dokan2 driver? I am unsure in this case. It looks like it should have worked.

You were right. The Dokan Library version was 2.0.6.1, the Dokan version from Nuget in my project is 2.0.5.1. I uninstalled Dokan Library 2.0.6.1 then installed Dokan Library 2.0.5.1, but the problem is still there.

stroev-ao avatar Sep 07 '23 02:09 stroev-ao

If other C# sample work, it means your install is correct but the provided VolumeSecurity are incorrect and failed the mount.

Liryna avatar Sep 07 '23 02:09 Liryna

Strange. Could it be some kind of version mismatch between the native dokan2.dll that gets loaded into your process and Dokan2 driver? I am unsure in this case. It looks like it should have worked.

You were right. The Dokan Library version was 2.0.6.1, the Dokan version from Nuget in my project is 2.0.5.1. I uninstalled Dokan Library 2.0.6.1 then installed Dokan Library 2.0.5.1, but the problem is still there.

I see now that this problem happens with that security descriptor if added to the native memfs C sample as well.

    PSECURITY_DESCRIPTOR sec_desc;
    ULONG sec_desc_length;
    BOOL rc = ConvertStringSecurityDescriptorToSecurityDescriptor(L"D:(D;;SD;;;WD)", SDDL_REVISION_1, &sec_desc, &sec_desc_length);
    memcpy(dokan_options.VolumeSecurityDescriptor, sec_desc, sec_desc_length);
    dokan_options.VolumeSecurityDescriptorLength = sec_desc_length;
    LocalFree(sec_desc);

I'll try to figure out what is going on here.

(Also, please do not post screenshots as pictures here, copy and paste your code instead so that it is easier for others to try out the same thing without the need to type your code manually and risk mistakes. Thank you!)

LTRData avatar Sep 07 '23 10:09 LTRData

Okay, so the problem here is that the security descriptor does not allow anything which means that everything is disallowed, which causes dokan2.dll not to be able to open the volume using CreateFile. The security descriptor needs to allow something:

            var sec = new FileSecurity();
            sec.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.ReadAndExecute, AccessControlType.Allow));
            sec.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.Delete, AccessControlType.Deny));
            var bytes = sec.GetSecurityDescriptorBinaryForm();

But actually, you could skip denying delete actions because anything that is not explicitly allowed in this security descriptor will be denied automatically:

            var sec = new FileSecurity();
            sec.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.ReadAndExecute, AccessControlType.Allow));
            var bytes = sec.GetSecurityDescriptorBinaryForm();

LTRData avatar Sep 07 '23 11:09 LTRData

Okay, so the problem here is that the security descriptor does not allow anything which means that everything is disallowed, which causes dokan2.dll not to be able to open the volume using CreateFile. The security descriptor needs to allow something:

            var sec = new FileSecurity();
            sec.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.ReadAndExecute, AccessControlType.Allow));
            sec.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.Delete, AccessControlType.Deny));
            var bytes = sec.GetSecurityDescriptorBinaryForm();

But actually, you could skip denying delete actions because anything that is not explicitly allowed in this security descriptor will be denied automatically:

            var sec = new FileSecurity();
            sec.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.ReadAndExecute, AccessControlType.Allow));
            var bytes = sec.GetSecurityDescriptorBinaryForm();

Great, it works! Thank you! But how to prevent drive renaming but allow all actions with all subdirectories and files? Because all security rights are inherited for all content I cannot rename or delete directories and create files. Ttried to add FileSystemRight.DeleteSubdirectoriesAndFiles. Also tried setting FullControl for all directories and files in the GetFileSecurity method. Another attempt is to use inheritance to all subdirectories and files when adding FileSystemRight.DeleteSubdirectoriesAndFiles. All attempts fail. Can you help me with this? I'm not strong with FileSystemRights yet.

stroev-ao avatar Sep 08 '23 03:09 stroev-ao

I found that the FileSystemRights.WriteData right disables disk renaming when it's denied. But it also prevent files to being created. I tried this but to no avail: fileSecurity.AddAccessRule(new FileSystemAccessRule(securityIdentifier, FileSystemRights.WriteData, InheritanceFlags.None, PropagationFlags.None, AccessControlType.Deny));

stroev-ao avatar Sep 08 '23 04:09 stroev-ao

I think you should try to allow everything and then deny delete, but make sure that the denial does not propagate to anything else (i.e. "this object only"). But I am not really sure. This is a kind of generic question about disk volume permissions. There could be discussions about it in other places that could be useful to read through.

LTRData avatar Sep 08 '23 09:09 LTRData

@stroev-ao Have you been able to resolve this issue ?

Liryna avatar Oct 14 '23 17:10 Liryna

@stroev-ao Have you been able to resolve this issue ?

No, the problem is not solved. The advice above from @LTRData did not help.

stroev-ao avatar Oct 15 '23 04:10 stroev-ao

@stroev-ao Have you been able to resolve this issue ?

No, the problem is not solved. The advice above from @LTRData did not help.

Like I said in my last comment, this is a more kind of general question not Dokan specific and you might want to search for hints about how to do it in other places. I would assume that you would need to create an ACL with some propagating allow permissions for all users and then some non-propagating deny permissions specifically denying deletion. The inheritance parts of it are most important in this specific case.

LTRData avatar Oct 15 '23 04:10 LTRData