proftpdのモジュール開発

proftpd は比較的軽量で、スタンドアローンでも(x)inetd配下でも動くftpdである。しかも、apache httpdに似たモジュールによる機能追加をサポートしており、コンフィグレーションファイルの書き方も似ている。ftpについて理解していてApache httpdの管理経験があれば、特にドキュメントを読まなくても一通りのことはできる。もちろんmod_tlsSSLには対応済み。ただし、Explicit のみ。

ApacheのようなDSOに対応していないのが弱点で、つまりモジュールを足すには再コンパイルするしか無かった。でも、なんか1.3.0を見るとmod_dsoというモジュールが追加になっているので解消された模様。

というわけで、そんなproftpdのモジュールを開発してみようと思う。本稿はその開発メモである。

staticモジュール

とりあえず、staticモジュールを作るのを目標としよう。

Make段階でmodules/glue.shというスクリプトが走って、これがmodules/mod*.cから、モジュール定義構造体(typedef module_struc module)へのポインタを抜き出す。だから、staticリンクされるモジュールでは、 modules/modモジュール名.c というファイルに module型のグローバル変数 "モジュール名_module"を定義すればよい。そうすれば勝手に、staticロードモジュールリストにリストアップされる。

in mod_example.c

#include "conf.h"
module example_module = {
  /* module構造体の双方向リンクリストのためのポインタ。実行時に使われるのか? */
  /* .next = */ NULL,   /* .prev = */ NULL, 

  /* 準拠しているProftpd Module APIのバージョン。モジュール自体のバージョンではない  */
  /* .api_version = */ 0x20,

  /* モジュール名 */
  /* .name = */ "example",

  /* このモジュールが提供するディレクティブの定義テーブルへのポインタ */
  /* .conftable = */ NULL,

  /* このモジュールが提供するコマンドハンドラの定義テーブルへのポインタ */
  /* FTPコマンドの実行に割り込むにはこれを使うってことか。 */
  /* .cmdtable = */ NULL,

  /* おなじく、認証処理への割り込みのためのハンドラ定義テーブル */
  /* .authtable = */ NULL,

  /* モジュール初期化関数へのポインタ */
  /* .init = */ example_init,

  /* FTPセッション初期化関数へのポインタ */
  /* .sess_init = */ example_sess_init,

  /* モジュールのバージョン文字列 */
  /* .module_version = */"mod_example/example",

  /* よく分からない。NULLで良いっぽい */
  /* .handle = */ NULL,

  /*" Internal Use"と書いてある。実行時の優先順位か? */
  /* .priority = */ 0
}; 

提供しない部分はNULLで良いらしい。example_module変数は定義テーブルって言う性質上constにしたいような気もするけれど、あからさまに実行時にリンクリスト作るぞーって感じだからそれは無理だろう。constにしたらアーキテクチャにもよるけど、たぶんSEGVる。

  • aprとおなじようなネスト可能なpoolオブジェクトによるメモリー管理が提供されている
  • loggingも独自のAPIがある。
  • APIやコールバックは成功時にTRUE, 失敗時にFALSEを返すのが基本らしい。

    • TRUE, FALSEはproftpd.hで独自に定義してある。