|||||||||||||||||||||

なんぶ電子

- 更新: 

vsftpdのトラブルとproftpd

ProFTPD

Debianでvsftpdを利用していましたが、再構成したらトラブルに遭遇しました。その原因と追究と、非常時用に代替候補となる proftpd の使い方を学習しました。

トラブルの症状と対応

Debian12 で vsftpd を構成しようとしたところ、FTPS接続において「 SSL: error:0A000126:SSL routines::unexpected eof while reading 」という表示がでて、FTPS接続の初期化に失敗するようになりました。

のちに、待ち受けポートを変更をしたら改善され、環境(VPS)に移行した都合によるものではないかという結論になったのですが、それに至るまでの試行錯誤を書き残しておきます。

先のエラーメッセージをネット検索してみたところ、こちらのOpenSSLの記事がヒットし、OpenSSLの1系と3系のメソッドの違いからくるのではないかと考えました。

Debian12 でインストールされる vsftpd のバージョンを確認します。

#vsftpd -v
#vsftpd: version 3.0.3

また、apt でインストール可能な vsftpd の依存関係を、「 apt-cache depends vsftpd 」で調べて見ると OpenSSL3系(libssl3)が依存となっており、3系が組み込まれていることも分かりました。

ただ、公式サイトにある最新版の3.0.5のソースは、OpenSSLの3系には対応していないようで、libssl3の環境でビルドしたら非推奨のエラーにより作業が完了しませんでしたが、バージョン1系をビルドしたかったので逆に幸いでした。

libsslのビルド用のパッケージが必要なら、通常はaptコマンドを使って「 libssl-dev 」を指定すればいいのですが、Debian12用のレポジトリでは libssl3がダウンロードされます。

なので、OpenSSLのサイトから1.1.1wのソースをダウンロードしてビルドします。

# cd /usr/local/src
# curl https://www.openssl.org/source/openssl-1.1.1w.tar.gz -o openssl-1.1.1w.tar.gz
...
# tar vzxf openssl-1.1.1w.tar.gz
...
# cd openssl-1.1.1w
# ./config
...
# make
...
# make test
...
# make install
...

OpenSSLをビルドしてインストールできたら、作成したlibssl.so.1.1ライブラリを「 ldconfig 」コマンドで認識させます。

次に vsftp をビルドします。デフォルトでは ssl は無効の構成になっています。設定は、ソースディレクトリの builddefs.h ファイルに存在します。

builddefs.h

#undef VSF_BUILD_SSL
↓ のように変更します
#define VSF_BUILD_SSL

あとは make でビルド、 make install でインストールという流れは通常通りです。

install時、Debianだとヘルプファイル(man)配置用のディレクトリがなくてエラーになります。筆者は無視しましたが、気になるようなら MakeFile ファイルを編集してください。

バイナリは、/usr/local/sbin/vsftpd に配置されます。このバイナリを実行する際に、設定ファイル /etc/vsftpd.confを引数に渡します。

この作業では、改善されませんでした。

サーバー証明書の署名アルゴリズムが変わったのかとも思いましたが、それも違いました。

最終的には試行錯誤で待ち受けポートを変えてみたらうまくいきました。ローカルで同じバージョンで環境を作っても現象が再現されないことから、VPS環境の影響ではないか、という結論になりました。

ProFTPD

今回は事なきを得ましたが vsftpd がしばらくメンテナンスされていないことが判明したので、再度何かあった時のために、代替となりうるProFTPDによる構成を確認しておきます。

$sudo su
...
# apt update
...
# apt install proftpd-core
...

Debian12(bookwarm)における ProFTPD の設定ファイルは /etc/proftpd ディレクトリにあり、機能別に .conf ファイルが分割されています。

インストール後から、OSユーザーが自身のIDとパスワードを使ってアクセスできる構成になっているようです(chrootなし)。

メインの設定ファイルは proftpd.conf となります。ここから、他の confファイルが Include されています。設定上 モジュールの読み込みの設定が必要なら、ここから読みだされることになっている modules.conf を編集します。

ここに設定する項目の多くはGlobal(mod_core)設定となります。

主な設定項目を見てみます。

proftpd.conf

...
# IPv6の利用
UseIP6 off
...
# 全ユーザを対象としたの chroot 設定 
# 下記でユーザーホームを chrootに
DefaultRoot ~
...
# ポート
Port 21
...
# 認証順
# コメントアウトの状態だとmod_auth_unix.c(OSユーザー)で判定します
# PAMを含める (/etc/pam.d/proftpd)
# AuthOrder mod_auth_pam.c* mod_auth_unix.c

# ログファイルの設定
TransferLog /var/log/proftpd/xferlog
SystemLog /var/log/proftpd/proftpd.log

# FTPS の設定読み込み
# (デフォルトでは利用できません)
# Include /etc/proftpd/tls.conf

# バーチャルホスト、ルートの設定読み込み
# Include /etc/proftpd/virtuals.conf

# パッシブポートの範囲指定
# PassivePorts 50000 51000

...

Auth Orderについてですが、ここには認証モジュールを複数指定する事ができます。

mod_auth_pam.c モジュールにおいては、公式のマニュアルに単一で使用しないようにとあります。これはPAM経由ではユーザIDやグループID、ホームディレクトリが取得できないからだそうです。PAMモジュール名の後に * 記号がついていますが、こうすることで認証の結果はPAMのものに従うようにした上で、残りのパラメータを別のモジュールで取得するようになります。

ProFTPDでバーチャルユーザー

OSユーザーによるログインはインストールしただけで利用可能になったので、バーチャルユーザーを作成していきたいと思います。

ProFTPDではモジュールとしてその機能が用意されています。

mod_auth_file.c がそれにあたります。

このモジュールだけで、一応目的は達成できますが、パスワードが8文字までという制限があるので近年のセキュリティ要件を満たせない事が多いと思います。

これを回避するため、mod_auth_pam と mod_auth_file を併用します。

まず AuthOrderを次のようにします。

AuthOrder mod_auth_pam.c* mod_auth_file.c

次に PAM を設定します。Debianの apt からインストールした場合のデフォルトは /etc/pam.d/proftpd にPAM設定がありますので、vsftpd でPAMの設定をしたのと同様に、pam-pwd-fileの構成をします。

不足している情報を proftpd に同梱されている ftpasswd コマンドを用いて行います。

バーチャルユーザー名に対して、ユーザーID、グループID、ホームディレクトリ、シェルを結びつける設定をし、保存先を指定します。

ユーザーIDやグループIDは /etc/passwdファイル等を参考に数値で指定します。バーチャルユーザーのユーザーアカウント別に結びつけるOSアカウントを変更できるので vsftpd より細かな設定が可能です。

ホームディレクトリも、バーチャルユーザーのアカウント毎に設定できます。シェルは nologin または false にしておきます。

最後に出力先を指定します。

# ftpasswd --passwd --name [ユーザー名] --uid [ユーザーID] --gid [グループID] --home [ホームディレクトリ] --shell /usr/sbin/nologin --file /etc/proftpd/proftpd.users

パスワードの設定を求められますがPAMでの認証が優先されますので、適当な値でもいいです。

バーチャルユーザーはシェルにはアクセスできないようにしますが、通常は /etc/shells に記載したシェルを利用できないと、ログインできない設定となっています。ですので、これを解除します。

proftpd.conf

...
RequireValidShells off 
...

さきほど作成したユーザーデータを、mod_auth_file に適用させる記述をします。

proftpd.conf

...
<IfModule mod_auth_file.c>
  AuthUserFile /etc/proftpd/proftpd.users
</IfModule>
...

これでバーチャルユーザーでの FTP接続が可能となります。

ProFTPDでFTPS

次に FTPSの設定をしたいのですが、apt でインストールする proftpd は mod_tls が含まれていませんでした。

現行のビルドでバンドル済のモジュールを確認するには、proftpd -l とします。この中に mod_tls が設定されていれば、そのまま FTPS が利用できます。

また、通常は /usr/lib/proftpd 内に追加モジュールが配置されています。先の出力中に mod_dsoがあり(DSOが利用可能で)、追加モジュールのファイル群に mod_tls.so が存在すれば、設定により FTPS が利用できます。

今回はそのどちらにも存在しないため、ソースからビルドします。いつもはネットなどで公開されている最新のバージョンのソースを取得するのですが、今回はビルドオプションの問題だけなので、レポジトリからソースを取得します。

# cd /usr/local/src
# mkdir proftpd
# cd proftpd
# apt update
# apt-get source proftpd-core
...
Picking 'proftpd-dfsg' as source package instead of 'proftpd-core'
NOTICE: 'proftpd-dfsg' packaging is maintained in the 'Git' version control system at:
https://salsa.debian.org/debian-proftpd-team/proftpd.git
Please use:
git clone https://salsa.debian.org/debian-proftpd-team/proftpd.git
to retrieve the latest (possibly unreleased) updates to the package.
Need to get 19.5 MB of source archives.
Get:1 http://deb.debian.org/debian bookworm/main proftpd-dfsg 1.3.8+dfsg-4+deb12u2 (dsc) [3433 B]
Get:2 http://deb.debian.org/debian bookworm/main proftpd-dfsg 1.3.8+dfsg-4+deb12u2 (tar) [19.4 MB]
Get:3 http://deb.debian.org/debian bookworm/main proftpd-dfsg 1.3.8+dfsg-4+deb12u2 (diff) [79.6 kB]
Fetched 19.5 MB in 9s (2079 kB/s)
dpkg-source: info: extracting proftpd-dfsg in proftpd-dfsg-1.3.8+dfsg
dpkg-source: info: unpacking proftpd-dfsg_1.3.8+dfsg.orig.tar.gz
dpkg-source: info: unpacking proftpd-dfsg_1.3.8+dfsg-4+deb12u2.debian.tar.xz
dpkg-source: info: using patch list from debian/patches/series
dpkg-source: info: applying autotools
dpkg-source: info: applying change_pam_name
dpkg-source: info: applying ftpasswd.cracklib.location
dpkg-source: info: applying mod_sql_mysql.c
dpkg-source: info: applying mod_wrap_noparanoid
dpkg-source: info: applying ftpstats
dpkg-source: info: applying odbc
dpkg-source: info: applying upstream_bug_1568.diff
dpkg-source: info: applying upstream_bug_1581.diff
dpkg-source: info: applying upstream_bug_1584.diff
dpkg-source: info: applying upstream_1592.diff
dpkg-source: info: applying upstream_bug_1597.diff
dpkg-source: info: applying 01_disable_inet_connect_ipv4_test.diff
dpkg-source: info: applying 02_disable_redis_sentinel_conn_new_test.diff
dpkg-source: info: applying 03_disable_all_non_api_tests.diff
dpkg-source: info: applying upstream_1707.diff

apt-get source でソースを取得する際 /etc/apt/sources.list 中に deb-src のエントリーが無いと取得できませんので注意してください。

proftpd-core のかわりに proftpd-dfsg が選択されたようですが、この dfsg は Debian Free Software Guidelines を意味するようで特に意識する必要はなさそうです。

apt-get source はカレントディレクトリにファイルを保存します。今回実行してみたところ、次のようなファイルとディレクトリがダウンロードされました。

  • proftpd-dfsg-1.3.8+dfsg

    ディレクトリです。これは apt-get source での作業過程でダウンロードした tar.xz ファイルを展開したディレクトリになると思います。

  • proftpd-dfsg_1.3.8+dfsg-4+deb12u2.debian.tar.xz

    .debian.tar.xz 末尾がつくファイルはDebianパッケージの為にカスタマイズされたソースです。または、.diff.gz となることもあるようです。

  • proftpd-dfsg_1.3.8+dfsg-4+deb12u2.dsc

    通常 .dscファイルはソースパッケージのメタデータが格納されます。電子署名が入っていました。

  • proftpd-dfsg_1.3.8+dfsg.orig.tar.gz

    オリジナルのソースです

ビルドには、ビルド用のパッケージに加え、libssl-dev や libpam0g-dev、libcap-devなどが必要になると思います。

# apt install libssl-dev libpam0g-dev(PAM) libcap-dev(capabilities:権限管理) libpcre2-dev(正規表現) libmemcached-dev libhiredis-dev(Redis軽量版) zlib1g-dev(圧縮)
...
# ldconfig
...

ソース内の debian/rules ファイルがバイナリを make する際のスクリプトになっているそうです。これを参考に configure オプションを設定します。または、proftpd -V でもビルドオプションを表示できます。

./configure --enable-sendfile --enable-facl --enable-dso --enable-autoshadow --enable-ctrls --enable-openssl --enable-nls --enable-memcache --enable-pcre2 --disable-strip --enable-redis

そのあと 目的の tlsモジュールを指定する為に、--with-modules=mod_tlsを指定します。

--with-modules=mod_tls

--with-shared オプションを使って、modules.conf で利用している DSO(Dynamic Shared Object:共有ライブラリ)を指定して、あわせてDSOモジュールもビルドする必要があります。先ほどの --with-modules に mod_tls を指定するかわりに、こちらに含めてももいいです。

--with-shared=mod_ctrls_admin:mod_radius:mod_quotatab:mod_quotatab_file:mod_rewrite:mod_load:mod_ban:mod_wrap2:mod_wrap2_file:mod_dynmasq:mod_exec:mod_shaper:mod_ratio:mod_site_misc:mod_facl:mod_unique_id:mod_copy:mod_deflate:mod_ifversion:mod_memcache:mod_readme:mod_ifsession

./confiure の結果は通常同じフォルダ内の configure.log に出力されます。configure 通過後に buildでエラーになるのは筆者の場合、ほとんど開発ライブラリのインストール不足が原因でした。

ビルドが終わったら、設定をしていきます。これは、aptでインストールした際の /etc/proftpd/ にあるファイル群の流用が可能です。同様の内容のテンプレートが ソースディレクトリ/debian/templates にあります。

シンタックスチェックは、proftpd -t -c [設定ファイルへのパス] とすることで可能です。

proftpd.conf の主な設定は先ほどと同様ですがaptから得たファイルを利用する場合は、次の修正が必要だと思われます。

proftpd.conf

...
<IfModule mod_ctrls.c>
ControlsEngine off
ControlsMaxClients 2
ControlsLog /var/log/proftpd/controls.log
ControlsInterval 5
ControlsSocket /usr/local/var/proftpd.sock
</IfModule>
...
# tls.confへのパスを追加します
Include /path/to/tls.conf
...
# コメントアウト
#Include /etc/proftpd/conf.d/

次に modules.confの設定です。

今回の筆者の環境ではビルドしてインストールした DSO モジュールは /usr/local/libexec に入るようになっていました。ここは通常プログラム個別のスクリプトや実行ファイルを配置する場所ですが、気になるなら、/usr/local/lib/proftpd などに動かしてください。

modules.conf

# モジュールのパスが変更されますのでそれにあわせます
ModulePath /usr/local/libexec

# もし tls を DSO 化した場合はコメントアウトを解除します。
LoadModule mod_tls.c
...

tls.confは次のようになると思います。

tls.conf

...
# FTPSを有効に
TLSEngine on

# ログファイルの場所
TLSLog /var/log/proftpd/tls.log

# バージョン TLSv1 1.1 1.2 をサポートという事なので 1.2という選択になると思います
TLSProtocol TLSv1.2

# TLS接続を必須にするか
TLSRequired on

# サーバーの証明書とキー(ここでは仮のものを使います)
TLSRSACertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem
TLSRSACertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key

# 必要に応じてCAの証明書を設定
# TLSCACertificateFile /etc/ssl/certs/CA.pem

# クライアント認証はOFFに
TLSVerifyClient off
...

最後に、サービスファイルの生成をして、/etc/systemd/system/ に配置します。

元となるファイルは ソースディレクトリの contrib/dist/rpm/proftpd.service にあります。

TLSRequired on として SSL接続を強制しても設定不備等で、mod_tls 利用できない場合は、プレーンパスワードでの接続を受け付けます。また、PIDFileのパスを適切に指定しないと、起動できても、再起動できないので注意してください。

proftpd.service

[Unit]
Description=ProFTPD FTP Server
Wants=network-online.target
After=network-online.target nss-lookup.target local-fs.target remote-fs.target

[Service]
# 制御を戻すようにするために simple から forking に変更
Type=forking
Environment=OPTIONS= CONFIG_FILE=/etc/proftpd/proftpd.conf
EnvironmentFile=-/etc/default/proftpd
ExecStartPre=/usr/local/sbin/proftpd --configtest -c $CONFIG_FILE $OPTIONS
# type=forking デーモン化(バックグランド化)したので --nodaemonは外します
ExecStart=/usr/sbin/proftpd -c $CONFIG_FILE $OPTIONS
ExecReload=/bin/kill -HUP $MAINPID
# ビルドしたproftpdに合わせてpidを指定します
PIDFile=/usr/local/var/proftpd.pid

[Install]
WantedBy=multi-user.target

デフォルトの設定ファイル群は、debian/templates にありますので、適当な場所にコピーします。その後、サービスの EnvironmentFile エントリーで指定したファイル(ここでは/etc/default/proftpd)の中に CONFIG_FILE= として新たな設定ファイルへのパスを記します。

事前に用意されている tls.conf ファイルを読み込むように、proftpd.conf ファイルのコメントアウトも解除します。

proftpd.conf

...
# コメントアウトを解除
Include /etc/proftpd/tls.conf
...

ビルドしたモジュールだけ利用する

先ほどはビルドした proftpd を使用しましたが、mod_tls をDSOモジュールとしてビルドすれば、バイナリはAPTでインストールしたものを利用し、不足している mod_tls.so だけを元の環境に配置して設定することで FTPS接続が可能になります。

詳しくはmod_tls.html#Installationを確認してください。

先ほどビルドした、mod_tls を標準のライブラリがある場所へコピーし、先ほど同様に設定をします。

cp /usr/local/libexec/mod_tls.so /usr/lib/proftpd/

筆者の環境ではうまくいきましたが、APTのバイナリと、ビルドした時とライブラリのバージョンの違いによる齟齬等が原因で正常に動かないこともあるかもしれません。


執筆にあたり chatGPTの回答を参考にしています。動作確認などのファクトチェックを行っていますが、用語の意味等の一部は鵜呑みの部分もございますご容赦ください。

筆者紹介


自分の写真
がーふぁ、とか、ふぃんてっく、とか世の中すっかりハイテクになってしまいました。プログラムのコーディングに触れることもある筆者ですが、自分の作業は硯と筆で文字をかいているみたいな古臭いものだと思っています。 今やこんな風にブログを書くことすらAIにとって代わられそうなほど技術は進んでいます。 生活やビジネスでPCを活用しようとするとき、そんな第一線の技術と比べてしまうとやる気が失せてしまいがちですが、おいしいお惣菜をネットで注文できる時代でも、手作りの味はすたれていません。 提示されたもの(アプリ)に自分を合わせるのでなく、自分の活動にあったアプリを作る。それがPC活用の基本なんじゃなかと思います。 そんな意見に同調していただける方向けにLinuxのDebianOSをはじめとした基本無料のアプリの使い方を紹介できたらなと考えています。

広告