Friday, August 13, 2004 6:52 AM bart

Securing FTP on IIS 6

The machine where my websites are hosted, hosts a bunch of other sites as well (now on Windows Server 2003 finally :-)). In fact every user has his/her own user account to log in to the server using FPSE or FTP to modify the site. However, when using the default website with virtual directories that match the user's names, this seems to work correctly (the user is entering the right folder after the login) but in fact the users are still able to cd .. out of their directory and then cd into another user's directory (only with "list folder contents" rights fortunately since the security on the folder was set tight during the FPSE configuration for the user's site). Nevertheless, this is still not secure enough for our server so I started to read pages 797 to 809 of the IIS 6.0 Resource Kit which was lying on my shelf for quite some time now :-). The good news is that IIS 6.0 supports a concept called "User Isolation" which allows you to set up the FTP site so that users can't see each other's folders (as a result, each user thinks he/she's alone on the box after a log in since cd .. can't go higher in the hierarchy than the user's root folder). When creating a new FTP site, you can specify the isolation mode:

The last option was my choice (since we have AD on the server's network and of course since AD is my big love for the moment). The basics of this isolation mode are rather easy: the user's root folder is retrieved from Active Directory when the user has logged on to the system. Let's take a look at the process:

  1. user logs in to the server (using ftp.exe for example)
  2. the system connects to the Active Directory domain on the network (which is specified during the creation of the FTP site using inetmgr.exe or using script) to retrieve attributes of the specified user (and to check the credentials of course)
  3. the msIIS-FTPRoot and msIIS-FTPDir properties of the user are retrieved and concatenated to form the path to the folder that needs to be opened (this can be a UNC path as well) - see further for an example
  4. the user is now living in a sandbox and can't leave this folder

By using this technology, it's possible to configure a user to have his folders on a separate machine using a UNC path to another server, just by changing the user's properties in the directory. Furthermore, when you install a new member server with IIS as a front-end webserver, you just need to set up the Active Directory FTP link (by creating a new FTP Site) and off you go.

You can set the user's FTP properties in AD using the iisftp.vbs script (from %windir%\System32):

iisftp.vbs /SetADProp bart FTPRoot D:\Web
iisftp.vbs /SetADProp bart FTPDir \bartdesmet.net

Which will cause the directory to refer to d:\web\bartdesmet.net. If I decide to put the files on another machine, I just need to change the FTPRoot now. Another advantage of this approach is that you can point to whatever path you want for a particular user, so you don't need to have a strict hierarchy of folders (such as ftproot\thedomain\theuser being the FTP folder for the user "thedomain\theuser") as this is the case with the "Isolate users" (without AD) option.

The vbs-script is nice, but System.DirectoryServices is much cuter and this really has become routine for me right now to write code for AD manipulations. First of all, I have a query tool:

using System;
using System.DirectoryServices;

class FtpAdQuery
{
 public static void Main(string[] args)
 {
  if (args.Length == 0)
   return;

  string ldap = args[0];

  DirectoryEntry e = new DirectoryEntry(ldap);

  DirectorySearcher src = new DirectorySearcher(e, "(objectClass=user)");
  SearchResultCollection res = src.FindAll();

  foreach (SearchResult r in res)
  {
   DirectoryEntry f = r.GetDirectoryEntry();
   Console.WriteLine(f.Name + "\t" + f.Properties["msIIS-FTPRoot"].Value + f.Properties["msIIS-FTPDir"].Value);
  }
 }
}

and secondly I have a manipulation tool as well to set the root for every entry in the directory (in fact, I just need to specify the LDAP path to the location in AD where I'm storing the web users, in my case this is a root-level OU called "Web Users"):

using System;
using System.DirectoryServices;

class FtpAd
{
 public static void Main(string[] args)
 {
  if (args.Length == 0)
   return;

  string ldap = args[0];
  string root = (args.Length >= 2 ? args[1] : null);

  DirectoryEntry e = new DirectoryEntry(ldap);

  DirectorySearcher src = new DirectorySearcher(e, "(objectClass=user)");
  SearchResultCollection res = src.FindAll();

  foreach (SearchResult r in res)
  {
   DirectoryEntry f = r.GetDirectoryEntry();
   Console.WriteLine(f.Name);

   if (root != null)
   {
    f.Properties["msIIS-FTPRoot"].Value = root;
    f.CommitChanges();
   }
  }
 }
}

All this code was editor-free and built through notepad.exe and csc.exe (without compilation errors :-)). That was it for today (in fact, two days seem to be merged again due to overnight work) on the field of System.DirectoryServices. More to follow later. My bed is waiting now...

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Filed under:

Comments

# re: Securing FTP on IIS 6

Monday, August 23, 2004 5:28 AM by bart

Take note that in W2k AD you need to extend the AD schema first, for W2k3, the extended fields are already there.

Cheers.

# re: Securing FTP on IIS 6

Wednesday, January 05, 2005 4:19 PM by bart

Hi I would really like to do this on our server, but a newbie with AD. How can I extend the ad in W2k?

# re: Securing FTP on IIS 6

Friday, January 07, 2005 12:53 AM by bart

On Windows Server 2003 you can just add the server to the "domain controller" role using the "Configure Your Server Wizard". Alternatively, you can run the dcpromo command using Start, Run which will guide you through the process of setting up Active Directory on your machine. Please note that the installation and configuration of DNS is also required (but this will be done automatically if not present already). But it's still important to be aware of the why and how of the DNS requirement.

# re: Securing FTP on IIS 6

Saturday, January 29, 2005 10:17 PM by bart

Very good info. Made some modifications to set a specified users properties.

using System;
using System.DirectoryServices;

class FtpAd
{
public static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("Usage: aduserset.exe path [user [root] [home]]");
return;
}

string ldap = args[0];
string user = (args.Length >= 2 ? args[1] : "*");
string root = (args.Length >= 3 ? args[2] : null);
string home = (args.Length >= 4 ? args[3] : null);

DirectoryEntry e = new DirectoryEntry(ldap);

DirectorySearcher src = new DirectorySearcher(e, "(&(objectClass=user)(sAMAccountName=" + user + "))");
SearchResultCollection res = src.FindAll();

foreach (SearchResult r in res)
{
DirectoryEntry f = r.GetDirectoryEntry();
Console.WriteLine(f.Name);

if (root != null)
{
f.Properties["msIIS-FTPRoot"].Value = root;
if(home != null)
{
f.Properties["msIIS-FTPDir"].Value = home;
}
f.CommitChanges();
}
}
}
}

# re: Securing FTP on IIS 6

Saturday, February 26, 2005 7:16 PM by bart

Excelent info

# re: Securing FTP on IIS 6

Friday, March 11, 2005 11:05 PM by bart

wow, thanks man I've been searching the internet trying to figure out how to do this =)

# re: Securing FTP on IIS 6

Friday, March 18, 2005 1:11 AM by bart

Is there some way to make connections encrypted with IIS without using VPN.

# re: Securing FTP on IIS 6

Friday, March 18, 2005 2:00 AM by bart

Do you mean HTTP connections? In that case you should take a look at HTTPS (SSL/TLS) which is supported in IIS (you need to obtain a certificate for public/private key encryption and so on in order to do this). If you're talking about FTP, you have to go over IPsec or so to have encryption (which is IP-to-IP encryption, thus not on the application level of the "network stack", which SSL is on the topmost level). As an alternative you can use HTTP for editing (FrontPage Extensions, WebDAV) over SSL.

# re: Securing FTP on IIS 6

Thursday, April 21, 2005 11:52 PM by bart

How do i use the code and what is the System.DirectoryServices ?

# re: Securing FTP on IIS 6

Thursday, April 21, 2005 11:55 PM by bart

You have to compile the code - as explained - with the C# compiler (csc.exe) or inside Visual Studio .NET in a C# Console Application project.

System.DirectoryServices is the namespace (and the assembly when you add the .dll extension) where the classes live to talk to "directory services" like AD over LDAP.

# re: Securing FTP on IIS 6

Thursday, May 12, 2005 8:01 PM by bart

Hi, and how do I make web space (such as webhosting) for each user account if i have no AD :( I have isolated access to FTP for LocalUser. Now, if user want to public his own web, he must just connect to ftp and must to his "ftproot" copy content of his webpage. Now i want public his webpage using IIS6 whithout creating many virtual dirs in IIS. How can I do that?

# re: Securing FTP on IIS 6

Friday, August 12, 2005 6:14 PM by bart

HI, i trying to create users with isolated ftp dir on the fly, but...
how does IIS (2k3 sp1) need to be set up?
i've just created the user with System.DirectoryServices and assigned "C:\web" as root and "<login>" as home dir. i have not configured any of the ftp types(normal/iso/isolate with ad).
i dont want to choose the last, cuz i want ad to manage that. thank you

# re: Securing FTP on IIS 6

Friday, August 12, 2005 11:18 PM by bart

Hi JL,

I don't understand your question completely. First you state you want to use Active Directory because you're using System.DirectoryServices etc and then you say you don't want to use the Active Directory Isolation Mode for FTP because you want to use AD?

So, my answer is to reread my post and to use
- IIS with FTP in AD isolation mode
- AD
- System.DirectoryServices

Cheers,

Bart

# re: Securing FTP on IIS 6

Monday, August 15, 2005 10:40 AM by bart

hi, i want to create isolated ftp's with C# +DirectoryServices for users i create with C#+DirectoryServices.
AD is on machine A and IIS is machine B, in domain. maybe i need to redirect "msIIS-FTPRoot" to "\\machine_b\C#\web\"? after user is created. i want to be able to use the user's ftp directly after user creation by logging in to ftp://domain\user:pass@machine_b:21/.
So, i still need to set up ftp iso mode for every user/client manually after i add a user with C#+DirectoryServices? Thank you

# re: Securing FTP on IIS 6

Monday, August 15, 2005 11:35 AM by bart

Bart, i've came i little further.
Filemon told me user was redirected to C:\inetpub\ftproot\<domain>\<user>, and not using ms_ftproot for some reason

# re: Securing FTP on IIS 6

Monday, August 15, 2005 2:42 PM by bart

Hi JL,

Don't forget to setup msIIS-FTPRoot for every user of course. Normally, I don't expect problems if both the ms-FTPRoot and ms-FTPDir are set for the user and the concatenation of both results in the desired path.

# re: Securing FTP on IIS 6

Wednesday, August 17, 2005 12:15 PM by bart

You have been very great help

# Bulk Active Directory operations - an example

Sunday, September 04, 2005 5:22 PM by TrackBack

# Bulk Active Directory operations - an example

Sunday, September 04, 2005 5:32 PM by TrackBack

# re: Securing FTP on IIS 6

Saturday, September 24, 2005 9:28 PM by bart

Hello,

When I try to add a user via LDAP I always get the error "The server is not operational". Does anyone know what this means? Please send me sample code if you have any to dragomirg@abv.bg . Thx.