FreeBSDのftpdで作るFTPサーバ

補足: あまりにも内容が古くなっていたので2002年春に書き直しました。


FreeBSDに標準のftpdは普通に必要な機能はきちんと有し設定が簡単で優れています。雑誌やインストール本を読んで何も考えずにProFTPDやwu-ftpd等の導入を考えている人も今一度FreeBSDのftpdを見直してみてはどうでしょうか?

目次

  1. ftpdの起動
  2. chroot機能を利用する
  3. ユーザーを拒絶する
  4. ログを録る
  5. 補足

ftpdの起動

ftpdの起動方法として3つを挙げます。

  1. スタンドアロンでの起動
  2. inetdによる起動
  3. tcpserver(ucspi-tcp)による起動

1. スタンドアロンでの起動

スタンドアロンでの起動はinetdによる起動よりも負荷が低いのでアクセスの多いFTPサーバでは特に有効です。ftpdに -D オプションを付けて起動します。
FTPサーバにアクセスがあれば必要なだけ自動的にコプロセスを立ち上げるので複数回起動する必要はありません。
ただし、スタンドアロンでの起動では起動プロセス数を制限したり、アクセス制御は殆どできないのでアクセス要求があれば可能な限り受けてしまいます。

起動例

# /usr/libexec/ftpd -D

2. inetdでの起動

inetdでの起動はinetdによる起動回数制限ができます。また、FreeBSDは3.2R以降TCP Wrapperがシステムに組み込まれたので /etc/hosts.allow でIPアドレスによるアクセス制御を簡単に行うことができます。FreeBSDではこれがftpdのデフォルトの起動方法です。アクセス数が少ない場合に お勧めです。

/etc/inetd.confから抜粋

ftp stream tcp nowait root /usr/libexec/ftpd ftpd -l

(上の例の行末にある -l については ログを録る を参照して下さい)


3. tcpserver(ucspi-tcp)での起動

tcpserverは接続制御に特化したツールだけあってTCP Wrapperより更に細かな接続制御が可能でDOSアタックに強いという利点があります。
アクセス数が多いサーバでアクセス制御も行いたい場合に特に有効ですが、アクセス数が少なくてもTCP Wrapperよりしっかりしているでお勧めです。


tcpserverのインストール

# cd /usr/ports/sysutils/ucspi-tcp
# make install

これだけです。その後の設定などは特にありません。

tcpserverによる起動方法。

# tcpserver [option][アクセス制御db] 0 ftp /usr/libexec/ftpd -l &

例1 制御無し,最大接続数40(default)の場合

# /usr/local/bin/tcpserver -H -R -g 0 -u 0 0 ftp /usr/libexec/ftpd -l &

例2 制御あり,最大接続数10の場合

# /usr/local/bin/tcpserver -H -R -g 0 -u 0 -c 10 -x /etc/ftpd.cdb 0 ftp /usr/libexec/ftpd -l &

tcpserverのオプション

-H リモートホスト名を調べない。
-R IDENTを行わない
-c ## 最大同時接続数 -u uid ユーザIDを uid に切り替える -g gid グループIDを gid に切り替える

詳しくはtcpserverのマニュアルを読んで下さい。


/usr/local/etc/ftpd.cdbの作り方

/usr/local/etc/ftpd.rules

IPアドレス:allow ユーザー名@IPアドレス:allow :deny
# tcprules /usr/local/etc/ftpd.cdb /tmp/ftpd_rules.tmp < /usr/local/etc/ftpd.rules

chroot機能を利用する

chroot機能を利用するとFTPサーバにアカウントを持つユーザーのアクセスに対しルートディレクトリを変更してユーザーをユーザーディレクトリに閉じ込めます。
これによりシステム関連で公開してはいけないディレクトリやファイルに気を使う必要が無くなるのでセキュリティの面で管理者にとってかなり負担が軽減されます。また、ユーザーにとっても他のユーザーに自分のホームディレクトリを覗かれることがなくなるという利点があります。(ユーザー全員にchrootを適用した場合)

通常のFTPディレクトリ構造
FTP chroot 1
設定が悪いとユーザーは全てのディレクトリを移動閲覧できるかもしれません。

chroot機能を利用した場合のFTPディレクトリ構造( user-c の場合)
FTP chroot 2
user-cは赤字の部分のみ移動閲覧できる。また、黒字の部分は存在すらわからない。

chrootを利用可能にする

/etc/ftpchroot というファイル(デフォルトでは存在しません)を作成してそこにユーザー名、またはグループ名を記入します

/etc/ftpchroot の記入例

user-a
user-b
user-c
@group-a
@group-b
@group-c

上の例のように1行につき1ユーザー名や1グループ名(/etc/groupに登録されたグループ名)を記述。
グループを指定する場合はグループ名の先頭に @ を付けます。


ユーザーを拒絶する

ユーザーを個別に拒絶したい場合
/etc/ftpusers ファイルにFTPアクセスを拒絶したいユーザー名を1行づつ記述します。


ログを録る

ftpdはログを録るように指定するとsyslogを利用してログを録ります。

  1. /usr/libexec/ftpd ftpd -l の様に -l をオプションとして指定するとFTPセッションを記録します。
  2. /usr/libexec/ftpd ftpd -l -l の様に -l を2回繰り返して指定するとretrieve (get), store (put), append, delete, make directory, remove directory, renameの操作とファイル名を記録します。
  3. /usr/libexec/ftpd ftpd -l -l -l の様に-l オプションを3回繰り返して指定すると上の2に加えて転送バイト数も記録します。
    (3は現在syslog.confで指定することになっています。)

syslogの設定

ftpdのログを独立させる場合(現在はこちらが標準)
/etc/syslog.confに追加

!ftpd *.* /var/log/ftpd.log

さらに touch /var/log/ftpd.log としてログファイルを作成する。(なければ)
chmod 640 /var/log/ftpd.log として属性を制限する。

/etc/newsyslog.confに追加

/var/log/ftpd.log 640 10 * $W0D0 Z

この例では 属性640で /var/log/ftpd.log ログファイルを毎週日曜日の0時に入れ替え、古いログはgzipで圧縮して10個まで保存となる。(ファイルサイズ制限無し)

ftpdのログを/var/log/messagesに含ませる場合
/etc/syslog.confを編集

*.notice;kern.debug;lpr.info;mail.crit;news.err;ftp.debug /var/log/messages

補足

/etc/shellsを確認する
ftpdは/etc/passwdで/etc/shellsに登録されていないshellを指定しているユーザーのアクセスは受け付けない。
例えばユーザーのshellを/sbin/nologin(アクセスお断りのメッセージを表示して切断するダミーshell)などにした場合、/etc/shellsに/sbin/nologin行を追加しておく必要がある。

ftpchrootでファイル転送した時間が9時間ずれて表示される
ホストマシンの内蔵時計を日本時間に合わせているとftpchrootでファイル転送した時間が本来より9時間ずれます。
昔のftpdの記事で古いftpdではftpchrootするとls出来なくなることに触れていますが、時間がずれるのも全く同じことが原因です。
FreeBSDでTIMEZONEをAsia/Tokyoに設定するとホストはJST(日本標準時間)となりGMT(世界標準時間)より+9:00であるとされます。
FreeBSDでTIMEZONEをJSTにするには/usr/share/zoneinfo/Asia/Tokyoを/etc/localtimeにコピーするわけですが(/stand/sysinstallで設定した場合も自動で行われる)、chrootすると/etc/localtimeが参照できなくなり、ホストマシンの内蔵時計を参照しそれをGMTとして認識します。
GMTはJSTより-9:00ですから、パソコンの内部時計を日本時間に合わせている場合に本来の時間より9時間遅れて表示されることになります。
試しにあるユーザーのホームディレクトリ(/home/UserA)にetcディレクトリを作成し、/etc/localtimeを/home/UserA/etc/にコピーしてファイル転送を行うとそのユーザーに限りファイル転送した時間が正しく表示されます。
解決方法としてはホストの内臓時計をGMT(日本時間より9時間遅れ)に合わせる方法があります。
合わせて/etc/wall_cmos_clock を削除し、マシンを再起動する必要があります。