Welcome to MSDN Blogs Sign in | Join | Help

SYSK 162: P/Invoke Required. Or Is It?

This is one of those examples when not being able to see the publication timestamp can lead you to make false conclusions...  So, “trust but verify”…

 

Say, you want to secure your application and disallow users from opening network files (or think of your own cases where you may need to call GetDriveType API, which determines whether a disk drive is a removable, fixed, CD-ROM, RAM disk, or network drive).  All web articles/posts I came across (as of July 21, 2006) indicated that you have to do P/Invoke as follows:

 

const int DRIVE_UNKNOWN = 0;

const int DRIVE_NO_ROOT_DIR = 1;

const int DRIVE_REMOVABLE = 2;

const int DRIVE_FIXED = 3;

const int DRIVE_REMOTE = 4;

const int DRIVE_CDROM = 5;

const int DRIVE_RAMDISK = 6;

 

[System.Runtime.InteropServices.DllImport("KERNEL32")]

public static extern int GetDriveType(string s);

 

public bool IsLocalDrive(string driveRoot)

{

    int driveType = GetDriveType(driveRoot);

 

    if (driveType == DRIVE_UNKNOWN)

        throw new ApplicationException(string.Format("Unable to determine drive type for {0}", driveRoot));

    else if (driveType == DRIVE_NO_ROOT_DIR)

        throw new ApplicationException(string.Format("Invalid argument {0}", driveRoot));

 

    return (driveType != DRIVE_REMOTE);

}

 

However, .NET 2.0 has DriveInfo support.  So, you can do same using .NET native code:

 

public bool IsLocalDrive(string path)

{

    bool result = false;

 

    System.IO.DirectoryInfo di = new System.IO.DirectoryInfo(path);

    System.IO.DriveInfo[] drives = System.IO.DriveInfo.GetDrives();

    foreach (System.IO.DriveInfo driveInfo in drives)

    {

        if (string.Compare(driveInfo.RootDirectory.FullName, di.Root.FullName, true) == 0)

        {

            if (driveInfo.DriveType == System.IO.DriveType.Unknown)

                throw new ApplicationException(string.Format("Unable to determine drive type for {0}", path));

            else if (driveInfo.DriveType == System.IO.DriveType.NoRootDirectory)

                throw new ApplicationException(string.Format("Invalid argument {0}", path));

 

            result = (driveInfo.DriveType != System.IO.DriveType.Network);

 

            break;

        }

    }

 

    return result;

}

 

Published Monday, July 24, 2006 7:13 AM by irenak

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# re: SYSK 162: P/Invoke Required. Or Is It?

Monday, July 24, 2006 12:56 PM by Peter Ritchie
The benefit to using DriveInfo over PInvoke is that you don't have to elevate your assembly's permission to include UnmanagedCode permissions; which may not be possible in all policies.

It also ensures the user has PathDiscovery permission, where the IsLocaDrive sample code does not.

# re: SYSK 162: P/Invoke Required. Or Is It?

Monday, July 24, 2006 1:45 PM by Gabe
This is a nice function, but it is not good for security. A volume mount point could exist, allowing a path that looks like a hard drive actually point to a removable or network drive. For example, if you make C:\CDROM point to a CD-ROM drive, you will look at C:\ and determine that it's safe because it's a local disk.

# SYSK 162: Reply to Gabe

Monday, July 24, 2006 10:00 PM by irenak
Excellent point.  One should also iterate through every folder (e.g. c:\Folder1\Folder2 would go through 3 checks -- c:\Folder1\Folder2, c:\Folder1 and c:\) and check whether it's a reparse point or not...  Since a junction point described by Gabe is just a reparse point, this kind of check will catch it.  To do that, just check File/Folder attribute ReparsePoint.  

Leave a Comment

(required) 
required 
(required) 

  
Enter Code Here: Required
 
Page view tracker