FTP User Isolation using Active Directory using Visual C#

Author:

Bart De Smet MVP

COMMUNITY SOLUTIONS CONTENT DISCLAIMER

MICROSOFT CORPORATION AND/OR ITS RESPECTIVE SUPPLIERS MAKE NO REPRESENTATIONS ABOUT THE SUITABILITY, RELIABILITY, OR ACCURACY OF THE INFORMATION AND RELATED GRAPHICS CONTAINED HEREIN. ALL SUCH INFORMATION AND RELATED GRAPHICS ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT AND/OR ITS RESPECTIVE SUPPLIERS HEREBY DISCLAIM ALL WARRANTIES AND CONDITIONS WITH REGARD TO THIS INFORMATION AND RELATED GRAPHICS, INCLUDING ALL IMPLIED WARRANTIES AND CONDITIONS OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, WORKMANLIKE EFFORT, TITLE AND NON-INFRINGEMENT. YOU SPECIFICALLY AGREE THAT IN NO EVENT SHALL MICROSOFT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY DIRECT, INDIRECT, PUNITIVE, INCIDENTAL, SPECIAL, CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF USE, DATA OR PROFITS, ARISING OUT OF OR IN ANY WAY CONNECTED WITH THE USE OF OR INABILITY TO USE THE INFORMATION AND RELATED GRAPHICS CONTAINED HEREIN, WHETHER BASED ON CONTRACT, TORT, NEGLIGENCE, STRICT LIABILITY OR OTHERWISE, EVEN IF MICROSOFT OR ANY OF ITS SUPPLIERS HAS BEEN ADVISED OF THE POSSIBILITY OF DAMAGES.

Abstract

IIS 6.0 contains a new feature called FTP user isolation which prevents users from navigating to another user's home folder. Without user isolation it's possible for a user to log on to an FTP site and go to another user's folder by using the cd.. command in the FTP tools. Although the user won't be able to write in the other user's folder (at least, when security is set up right), the user might be able to read the contents of the other user's folder.
 
3 different modi are supported:
- No isolation, which causes users to be able to traverse to folders of other users.
- Isolation based on folders. In this case, a FTP root folder is set up and each user has a dedicated, sandboxed subfolder.
- Isolation based on Active Directory. With this option, the user's FTP settings are stored as attributes of the corresponding user object in Active Directory. A big deal of flexibility is possible using this option.
 
This article focuses on FTP user isolation using Active Directory and assumes you have basic knowledge of Active Directory and that you have set up an Active Directory domain in your enterprise.

Create the new FTP site with Active Directory user isolation

1. Go to the Internet Information Services (IIS) Manager using Start, Run, inetmgr, OK.
2. Navigate to the right computer in the tree structure.
3. Right click on the FTP Sites folder and choose New, FTP Site…
4. Click Next and provide a name for the new FTP site. Click Next again.
5. Specify the IP-address and port settings for the new FTP site. For more information about this, refer to the IIS Help files. Click Next to continue.
6. Now choose the last option: "Isolate users using Active Directory" and click Next.
7. Supply the user credentials for the domain account that will be used to retrieve the Active Directory settings while the FTP service is running in order to read the user's attributes. As a security best practice, use a low-privileged account. In the domain textbox, supply the base domain name, not the fully-qualified domain name. Note: If the password of the used account changes, the FTP settings will need to be updated to reflect the changes. Click Next.
8. Confirm the password and click OK.
9. Set up the permissions on the FTP folders. If you want users to be able to upload files to their folders, tick both the Read and Write options. Click Next.
10. Click Finish to complete the FTP site setup.

FTP user isolation using Active Directory explained

Active Directory-based user isolation is the recommended choice for hosting providers and companies that have to maintain a large amount of FTP user folders. Basically, the user's home folder is determined upon authentication by querying the msIIS-FTPRoot and msIIS-FTPDir attributes of the user object in Active Directory. The concatenation of the msIIS-FTPRoot and msIIS-FTPDir values results in the path to the user's home folder.
 
An example looks as follows:
    msIIS-FTPRoot = D:\FTP Users
    msIIS-FTPDir = \JohnSmith
This will result in "D:\FTP Users\JohnSmith" as the home folder for the user. Note that it's also possible to specify a UNC path as the msIIS-FTPRoot value to connect to another server, e.g. a file server on the servers LAN.
 
This flexibility allows you to change the user's root folder at any time without having to touch the FTP server's configuration, just by changing the msIIS-FTPRoot attribute in Active Directory for the user in question. Since Active Directory manipulation is pretty simple using various technologies (VBScript, .NET Framework) it's possible to change the settings for various users in a fast way. As a result, it's relatively simple to move the FTP folders of the users to another location, just by updating their msIIS-FTPRoot attribute in Active Directory.
 
Remarks:
1. The information that is retrieved from Active Directory is being cached by the FTP service for 10 minutes. It's possible to change this default value using the registry entry DsCacheRefreshSecs. Be careful when you decide to do so since registry changes can cause damage to your system.
2. If you're using a Windows 2000 Server-based Active Directory implementation on your network, you'll need to extend the schema with the msIIS-FTPRoot and msIIS-FTPDir attributes for the user object. Schema extensions can't be undone, so be careful when you want to do this and consult the domain administrator for the needed rights.
3. The user needs to have rights on the specified folder in order to have access to it. If the user hasn't the needed rights or the path is invalid, access will be denied. If you experience problems with this, check security on the level of shares (if you're using a UNC-path for the msIIS-FTPRoot setting) and on the level of the file system (NTFS ACLs).

Enable a user for FTP access by script

To set up a home folder for a user using script, follow the next procedure:
1. Open a command prompt window.
2. Use iisftp.vbs /SetADProp /? to show the syntax information of the iisftp.vbs script.
3. Determine the user's home folder and split it up in a root folder and a user folder. Typically, the user folder is just something like \JohnSmith, while the root folder is the path to a local folder or UNC path containing the folders of the users. I'll be using the next example:
    root folder: \\fileserver\ftproot
    user folder: \JohnSmith
4. Apply the settings to the user by executing the following commands:
    iisftp.vbs /SetADProp JohnSmith FTPRoot \\fileserver\ftproot
    iisftp.vbs /SetADProp JohnSmith FTPDir \JohnSmith
 
Important: Don't forget the \ in front of the FTPDir value. The concatenation of both the root folder's value and the user folder's value have to result in a valid path.
 
If you've set up a user by doing this, check whether you can login to the user's folder with FTP. In order to do so you can use the command-line command ftp.exe or a browser or FTP client application.

Enable a user for FTP access by using C#

You can enable a user for FTP by using managed code as well. This might be useful when you're writing an application to set up user accounts and you want to incorporate FTP access as well. If you're upgrading a large series of users to have an FTP folder on the system, C# might be useful as well. The basic code (in a console application) looks as follows:
 
using System;
using System.DirectoryServices;
using System.Reflection;
using System.Text;
 
class EnableFTP
{
    public static void Main(string[] args)
    {
        if (args.Length < 2)
        {
            Console.WriteLine("Usage: {0} <user> <rootFolder> [<domain>]", Assembly.GetExecutingAssembly().GetName().Name);
            return;
        }
 
        string domain = null;
        if (args.Length == 3)
            domain = args[2];
        else
            domain = Environment.GetEnvironmentVariable("USERDNSDOMAIN");
 
        if (domain == null || domain == String.Empty)
        {
            Console.WriteLine("No valid domain found. Specify the full domain DNS name as 3rd parameter.");
            return;
        }
 
        string dc = GetDC(domain);
        string ldap = String.Format("LDAP://{0}/{1}",domain,dc);
 
        string login = args[0];
        string rootFolder = args[1];
 
        string query = String.Format("(&(samAccountName={0})(objectClass=user))", login);
        SearchResult res = null;
        try
        {
            DirectoryEntry root = new DirectoryEntry(ldap);
            DirectorySearcher src = new DirectorySearcher(root, query);
            res = src.FindOne();
        }
        catch (Exception)
        {
            Console.WriteLine("Cannot connect to domain {0}", domain);
            return;
        }
 
        if (res != null)
        {
            string usrFolder = "\\" + login;
            DirectoryEntry user = res.GetDirectoryEntry();
            user.Properties["msIIS-FTPRoot"].Value = rootFolder;
            user.Properties["msIIS-FTPDir"].Value = usrFolder;
            user.CommitChanges();
            Console.WriteLine("FTP home directory for {0}: {1}{2}", login,rootFolder,usrFolder);
        }
        else
            Console.WriteLine("User {0} not found.", login);
    }

    private static string GetDC(string domain)
    {
        StringBuilder sb = new StringBuilder(domain);
        sb.Replace(".",",DC=");
        sb.Insert(0,"DC=");
        return sb.ToString();
    }
}
 
Note: If you try to compile this in Visual Studio .NET 2003, you'll need to add a reference to the System.DirectoryServices.dll assembly in the solution explorer.
 
The usage of the command is pretty simple, e.g.: EnableFTP.exe JohnSmith "D:\FTP Users"
 
This example can be extended if you want to enable all users of an organizational unit for example. Using the DirectorySearcher class it's possible to retrieve all user objects by using the "(objectClass=user)" query and by using the FindAll method on the class instance to retrieve the results. More information on Active Directory programming in C# can be found in the .NET Framework SDK (search for System.DirectoryServices).
Properties

Article ID: 555205 - Last Review: 14 Feb 2017 - Revision: 1

Microsoft Internet Information Services 6.0, Microsoft Visual C# .NET 2003 Standard Edition

Feedback