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を作成します。

C++スーパープログラマになるための学習項目リスト

4月は新入社員の季節です。うちの会社にも一人だけですが、中途採用の社員が入ってくる(C/C++の若干の知識あり)ので、その人に何を教えるべきか考えています。下記は個人的に教えたいなぁと考えている項目。

  1. ポータブルなコード
    1. マクロ
    2. 64bit
    3. intよりsize_t
    4. 国際化(文字列の扱い、ローカライズなど)
  2. セキュリティ
    1. バッファオーバーラン
    2. 機密情報の取り扱い(memsetなど)
    3. 暗号について
    4. 暗号乱数について
  3. C言語に戻る
    1. 関数ポインタ
    2. 呼び出し規約
    3. DLL/Shared Object
  4. カプセル化
    1. 情報隠蔽(変数の隠蔽)
    2. 遅延評価
    3. 変数の保護
    4. 何でも仮想化 (lock/unlock)
    5. コンテキスト
    6. オブジェクト指向について
    7. structとclassの違い
    8. オブジェクト指向 継承・virtual関数・仮想デストラクタ
  5. 設計
    1. Design by Contract
    2. 森を見て木を見る
    3. 嘘つきになる
  6. 例外
    1. 例外について
    2. 従来のエラー処理よりも例外の方が良い理由
    3. RAII
    4. AutoPtr
  7. スレッド
    1. CreateThread, _beginthreadex
    2. CoInitialize
    3. 原子性(Atomicity)/競合状態
    4. Mutex
    5. Win32スレッドの基礎 WaitFor*Object(s)
    6. CriticalSection
    7. Semaphore
    8. Interlocked API
    9. Event
  8. template
    1. STL
    2. コンパイル時計算性/定数性/インライン
    3. traits
    4. concept