IIS FTPで一時的にフォルダを公開する
ユーザー認証はしない(anonymous)けど、接続元IPを限定することによって、ある程度のセキュリティは維持でき、一定時間が過ぎると仮想ディレクトリごと削除する。そんな機能が必要になったので、適当に作ってみました。やってみると、意外と難しくない。というか、Microsoft製品のAPIって良くできているなぁと改めて思うほど。
// ftpvdir.cs - A sample code for creating FTP virtual directory using System; using System.Collections; using System.IO; using System.DirectoryServices; using System.Security.AccessControl; using System.Reflection; using System.Net; using System.Net.Sockets; class FtpVDirTest { public static void Main(string[] args) { if(args.Length < 3) { Console.WriteLine("ftpvdir <VDIR> <PDIR> <GRANT_PEER_ADDRESS>"); return; } CreateWriteOnlyFtpDirectory(args[0], args[1], IPAddress.Parse(args[2])); Console.WriteLine("Hit any key to close {0}.", args[0]); Console.ReadKey(); DeleteFtpDirectory(args[0]); } static string IIS_FTP_ROOT = "IIS://localhost/msftpsvc/1/Root"; static string IIS_FTP_SCHEMA = "IIsFtpVirtualDir"; static void CreateWriteOnlyFtpDirectory(string virtualDirName, string physhicalDirPath, IPAddress userIpAddress) { string ipWithMask; if(userIpAddress.AddressFamily == AddressFamily.InterNetwork) ipWithMask = userIpAddress.ToString() + ", 255.255.255.255"; else if(userIpAddress.AddressFamily == AddressFamily.InterNetworkV6) ipWithMask = userIpAddress.ToString() + "::1/64"; else throw new ArgumentException("Unsupported Address family: {0}", userIpAddress.AddressFamily.ToString()); DirectoryEntry ftpRoot = new DirectoryEntry(IIS_FTP_ROOT); ftpRoot.RefreshCache(); DirectoryEntry deNewVDir = ftpRoot.Children.Add(virtualDirName, IIS_FTP_SCHEMA); deNewVDir.Properties["Path"].Insert(0, physhicalDirPath); // READ=1, WRITE=2, READWRITE=3 deNewVDir.Properties["AccessFlags"].Insert(0, 2); // Grant only accesses from the specified peer object ipSecurity = deNewVDir.Properties["IPSecurity"][0]; SetProperty(ipSecurity, "GrantByDefault", false); SetProperty(ipSecurity, "IPGrant", new object[] {ipWithMask}); deNewVDir.Properties["IPSecurity"][0] = ipSecurity; deNewVDir.CommitChanges(); ftpRoot.CommitChanges(); deNewVDir.CommitChanges(); ftpRoot.CommitChanges(); deNewVDir.Close(); ftpRoot.Close(); } static void DeleteFtpDirectory(string virtualDirName) { DirectoryEntry ftpRoot = new DirectoryEntry(IIS_FTP_ROOT); ftpRoot.RefreshCache(); DirectoryEntry vDir = ftpRoot.Children.Find(virtualDirName, IIS_FTP_SCHEMA); ftpRoot.Children.Remove(vDir); ftpRoot.CommitChanges(); vDir.Close(); ftpRoot.Close(); } static object SetProperty(object obj, string name, object val) { return obj.GetType().InvokeMember( name, BindingFlags.DeclaredOnly | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.SetProperty, null, obj, new object[] {val}); } }
このコードは、
ftpvdir hogehoge c:\foobar 192.168.11.56
とやると、localhost上に、192.168.11.56からしかアクセスできないFTPの仮想フォルダhogehogeを作成します。