Debugging your custom FTP authentication provider module

If you are reading this article, I will make the assumption that you already know that in Microsoft FTP server that comes with IIS 7.5 or above, you have three possibilities for authentication:

  • Anonymous: you let all users in without requiring credentials from their side
  • Basic Authentication: users have to provide a username and password which will be matched by IIS to a local or domain account (the username and password will be sent in clear text via the control port 21 if you have not setup FTPS).
  • Custom authentication: you write your own authentication module to validate the username password combination that a user provides you with according to your own business rules.

There is a very complete article about how to create a custom authentication provider with FTP, written by Robert McMurray – which you can find here:

https://blogs.msdn.com/b/robert_mcmurray/archive/2011/06/30/how-to-create-an-authentication-provider-for-ftp-7-5-using-blogengine-net-s-xml-membership-files.aspx

Since this article dates a bit, you can follow the article below which provides a detailed walk through on how to install an FTP custom authentication provider once you have built one. This can be done by the IIS Manager Console GUI, contrary to what the article from Robert indicates (as I have said, the first article is a bit old):

https://www.iis.net/configreference/system.applicationhost/sites/site/ftpserver/security/authentication/customauthentication/providers

The question is, what happens if you try and install the provider, and it does not work. How do you get started with troubleshooting it. This article intends to give you a basic workflow:

1. Start with the GAC

In order for the custom authentication provider to be found and loaded by the FTP server, it must be present in the GAC (Global Assembly Cache). Hence, as per the articles above, when you are writing your module, you must make sure that it is signed, so that it can be deployed to the GAC.

Open a Windows Explorer and navigate to the C:\Windows\Assembly folder. This is where all the GAC dlls are located. If you have not deployed your module to the GAC, deploying it is a simple as dragging and dropping the dll from another Windows Explorer window to the one open to C:\Windows\Assembly.

(Note: in Windows 8.1 and Windows 10 the Assembly GAC shell is not present, so deployment to the GAC is only possible with GacUtil)

Please note that in some case, Windows Explorer will not refresh the contents of the GAC right away, after the drag and drop, hence I recommend you close all Windows Explorer windows and then start with a new instance of Windows Explorer and check for the presence of the assembly in the GAC. If the assembly is not present in the GAC (ie. you cannot find YouFTPModule.dll present in the GAC), then go no further, you have to fix this first.

You may use an elevated command line prompt to see the contents of the GAC as well. Navigate to the C:\Windows\Assembly folder. Running the dir command will list the contents of the GAC's folders (Windows Explorer has a special shell to display the GAC – if you want to see the real structure, you can use the command line as shown below):

As you can see from the screenshot above, there are several folders inside the GAC (these may vary if you are on 32 or 64 bit machine), but the folder we are interested in is the GAC_MSIL (short for Microsoft Intermediary Language – the assembly language your .Net code will be compiled in). It is this folder (GAC_MSIL) we should be navigating to, to see if the assembly we have developed is present in. Use the dir /p command to list the assemblies page per page instead of all at once. If the assembly is not present, it means there was an error in deploying it to the GAC.

You may use tools like gacutil (that comes with Visual Studio) to try and deploy the assembly via command line – since this tool will give you explicit error messages. You can learn more about the gacutil tool here:

https://msdn.microsoft.com/en-us/library/ex0ss12c%28v=vs.110%29.aspx?f=255&MSPPError=-2147217396

2. Where does the assembly get loaded once you try and authenticate?

Once the FTP server is configured to use your own authentication provider, and you try and authenticate a first time, the provider should get loaded into IIS. But where? The answer is that it will get loaded into a dllhost.exe process, and will be executed and hosted inside the process. Which dllhost.exe process is it – since you are likely to have more than one such process on the machine?

Open an elevated command prompt window and type in the following command: tasklist -svc . You need to look for a service called DcomLaunch which is running in a svchost.exe process (with PID 720 in my screenshot):

You will then need to download a tool called Process Explorer from the Microsoft site (https://linqto.me/Procmon). Unzip the tool and launch it with administrative privileges (right click and select 'Run as Administrator). This tool will let you peak into what is loaded inside each process in Windows.

Locate the svchots.exe process with the PID corresponding to the DcomLaunch service (which you have gotten from the previous step using the command line). Underneath this process, there should be a dllhost.exe process which should be loading the assembly containing your authentication provider. To view the dlls in this process, chose the View > Lower Panel > Dlls menus from the Process Explorer window.

If the assembly is not present on loaded inside this process, then there might be an ACL problem when trying to load the file – which is quite rare. You can download Process Explorer (https://linqto.me/Procmon) and use the tool to trace loading attempts. After you have downloaded and unzipped the tool, launch it and then click on the 'magnifier' button to stop tracing, the clear button (button with a gum) to clear the trace. Setup a filter in procmon by pressing the filter button:

Setup a filter where:

  • PID is the ID of the dllhost.exe you have identified
  • Path contains the name of the dll which contains your provider

Re-start the procmon capture and try and authenticate to the FTP server again. Personally, I recommend using a client such as FileZilla, since this will give you great, color-coded output of the authentication attempt. Stop the procmon trace. If there is no load attempt for the dll containing your provider, the FTP server is not configured to use the authentication provider you developed. If there are failed load attempts, inspect these since the tool will tell you why these fail.

3. My provider loads, but still does not work.

If you have gone through points 1 and 2 in this blog and your provider does load but still fails to authenticate, then it is possible that the code is throwing an error when called. You can either debug this with Visual Studio, if VS is installed on the same server you are setting the provider up on, or you can use Debug Diag (https://linqto.me/DebugDiag) to trace errors.

Setup a Debug Diag crash rule as explained in this blog post:

https://blogs.msdn.com/b/chaun/archive/2013/11/12/steps-to-catch-a-simple-crash-dump-of-a-crashing-process.aspx .

The rule will not produce crash dumps, but will record all .Net Exceptions that will be encountered by the process while the crash rule is tracking it. Hence, once the rule is setup, you can try and authenticate to the FTP server one or more times, then come and stop (kill) the dllhost.exe process that you were monitoring. This will prompt Debug Diag to create a log of the lifetime of the process and all errors encountered during the execution.

The log thus created can be found in: C:\Program Files\Debug Diag\Logs\<NameOfCrashRule>\ . There will be a text file inside this folder that will also contain dllhost.exe and the PID of the process that was tracked by the rule. If you open this file, you should see the details of the errors encountered during the execution of the process – with .Net callstacks – they will be located towards the end of the file. You will need to examine these stacks and error messages to understand what errors are raised in your code and why.

Happy debugging for all the FTP auth module developers out there.

by Paul Cociuba
https://linqto.me/about/pcociuba