home(h) links(l) memo(m) translation(t) profile(r)
memo(m) ftp

メモ〜ftp関係

ftpクライアントの起動

Windowsのコマンドプロンプトや、Macのターミナル、Linuxの端末などでftpと入力すれば、ftpクライアントが起動し、コマンド待ち受け状態となる。起動の際、オプションや接続先を指定して起動することもできる。

【書式】
ftp オプション 接続先
  
-a
通常のログイン手続き(ユーザ名、パスワードの入力)を省略して、anonymous(匿名)ログインを行う。
-i
複数ファイル転送中の対話的プロンプトモードをオフにする。
-P ポート番号
ftpサーバ側の制御セッション用ポートを指定する。指定がなければ21。
接続先
ftp|http://ユーザ名:パスワード@ホスト名:ポート番号/パス/;type=AI
XXが16進数文字コードであるとしてデコードされる(例:"%2F"→ "/" 、"%7E"→"~")。最後のtypeはAを指定するとアスキーモード、Iを指定するとバイナリモードとなる。既定の転送タイプはバイナリ。
例:ftp://hoge:password@ftp.fuga.com:2121/subdir

ftpクライアントの終了についてはbyeコマンドを用いる。

ftpのセキュア版(sftp、ftps)

sftp(SSH File Transfer Protocol)はSSHの仕組みを利用してファイルを安全に転送するためのプロトコル名、およびそのクライアントコマンド名。既定のポートはSSHと同じ22/tcp[5]

ftps(File Transfer Protocol over SSL/TLS)はFTPでやりとりするデータをSSLまたはTLSで暗号化するプロトコル名。既定のポートは990/tcp[5]。Linux系OSで使えるコマンドラインクライアントとして「lftp」がある[6]

FTPクライアントコマンド

通信方法など

通信モードについて

ftpの通信モードにはアクティブモードとパッシブモードがある。

【例】通信モードを変更する
passive
【例】通信モードをONにする
passive on
【例】通信モードをOFFにする
passive off
      

対話モードについて

promptコマンドは対話モードを変更する。引数を指定しなければ、もう一方のモードに変更する(現在ONであればOFFに、現在OFFであればONにする)。対話モードをOFFにすると、mgetなど複数ファイルを処理するコマンドで問い合わせが行われなくなる(全て「はい」が指定されたものとみなされ無条件に該当するファイル全てに対し処理が実行される)。

【例】対話モードを変更する
prompt
【例】対話モードをONにする
prompt on
【例】対話モードをOFFにする
prompt off
      

ファイル操作

ファイルの送受信、リモートファイルの削除

put(送信)、get(受信)、delete(削除)はファイルを1個だけ扱う。ワイルドカード(*→任意の0文字以上の文字列、?→任意の1文字)を用いた場合、最初に条件に適合したファイルだけを対象として処理し、処理を終了する。複数のファイルを扱いたい場合はmput(送信)、mget(受信)、mdelete(削除)を用いる。

【書式】
put ファイル名(パターン)
mput ファイル名(パターン)
get ファイル名(パターン)
mget ファイル名(パターン)
delete ファイル名(パターン)
mdelete ファイル名(パターン)
      

mputmgetmdeleteの場合、扱い方法が問われる。

【例】
ftp> mput *.txt
mput text01.txt [anpqy?]
      
  • a (all)→以降のファイルは「はい」と答えたものとして処理する。p とは異なり、対話モード(→prompt参照)はONのまま変更しない。
  • n (no)→このファイルは処理しない。
  • p (prompt off)→対話モードはOFFにし、以降処理するかどうかの問い合わせは行わない。
  • q (quit)→処理を中止する。
  • y (yes)→このファイルは処理する。

リモートファイルが新しかった場合にのみファイルの取得(get)するにはnewerコマンドを用いる。なお、ローカルにファイルがなかった場合は、リモートファイルが新しかったものとして処理される(ダウンロードされる)。このコマンドの引数には単一のファイルしか指定できないみたい(ワイルドカードは使えない)。

【例】
ftp> newer hoge.txt
      

リモートファイルの移動、名称変更(rename)

ファイルの移動や名称変更にはrenameコマンドを用いる。

【例1】hoge.txt を hoge.txt.bak に名称変更する
ftp> ls                     ↓最初4つの数値はIPアドレス
227 Entering Passive Mode (xxx,xxx,xxx,xxx,xxx,xxx). ←後2つはftpクライアント側の通信待ち受けポートを示す
150 Opening ASCII mode data connection for file list   16進表示の上下2桁ずつを10進表示に直したもの
drwxrwxrwx   1 hoge     hoge          56 Oct  8 15:01 old
-rw-rw-rw-   1 hoge     hoge         123 Oct  8 15:00 hoge.txt
226 Transfer complete.
ftp> rename hoge.txt hoge.txt.bak
350 File or directory exists, ready for destination name.
250 Rename successful
ftp> ls
227 Entering Passive Mode (xxx,xxx,xxx,xxx,xxx,xxx).
150 Opening ASCII mode data connection for file list
drwxrwxrwx   1 hoge     hoge          56 Oct  8 15:01 old
-rw-rw-rw-   1 hoge     hoge         123 Oct  8 15:05 hoge.txt.bak
226 Transfer complete.
【例2】hoge.txt.bak を old ディレクトリの下に hoge.txt の名称で移動する
ftp> rename hoge.txt.bak old/hoge.txt
350 File or directory exists, ready for destination name.
250 Rename successful
ftp> ls
227 Entering Passive Mode (xxx,xxx,xxx,xxx,xxx,xxx).
150 Opening ASCII mode data connection for file list
drwxrwxrwx   1 hoge     hoge          56 Oct  8 15:01 old
226 Transfer complete.
ftp> ls old
227 Entering Passive Mode (xxx,xxx,xxx,xxx,xxx,xxx).
150 Opening ASCII mode data connection for file list
-rw-rw-rw-   1 hoge     hoge         123 Oct  8 15:08 hoge.txt
226 Transfer complete.
      

FTPクライアントコマンド一覧(アルファベット順)

A

B

C

D

E

F

G

H

I

L

M

N

O

P

Q

R

S

T

U

V

X

Others

スクリプトの実行

UNIX系OS(Mac OS Xを含む)の場合

【例】
#!/bin/sh # シェルのフルパス
HOST_NAME="ftp.sample.net" # FTPサーバの完全修飾ドメイン名
USER_NAME="user" # FTPサーバへ接続するためのユーザ名
PASSWORD="pass" # 上記ユーザのパスワード
LOCAL_DIR="/home/user/" # ローカルの初期ディレクトリ
REMOTE_DIR="/work/" # サーバ側の初期ディレクトリ
FILES_GET=(*.html *.css) # アップロードするファイル
FILES_PUT=(*.pdf *.doc) # ダウンロードするファイル

cd ${LOCAL_DIR}

ftp -n ${HOST_NAME} << _EOF_
user ${USER_NAME} ${PASSWORD}
lcd ${LOCAL_DIR}
cd ${REMOTE_DIR}
mget ${FILES_GET[*]}
mput ${FILES_PUT[*]}
bye
_EOF_
    

参考文献・サイト

ftpサーバ設定

ここでは主にvsftpサーバについて記す。vsftpはCentOSの場合、標準で用意されている(入っていなければ yum install vsftpd でインストールされる)。

RPMパッケージの構築

RHEL/CentOS 5系のデフォルト設定ではvsftp2.0.5までしかRPMが提供されないよう(2014/04/09現在)。自身でRPMパッケージを構築する方法について[7]

1. ビルド環境の準備

一般ユーザでビルドするにはrpmの環境変数を変更する必要がある。既定では「%_topdir /usr/src/redhat」という設定になっているが、この場所ではrootでしかビルドできないので、一般ユーザが読み書き可能な別の場所を指定する。設定方法はパッケージの作成(ソースコードより)を参照のこと。/home/usrname/rpmなどが例としてよく挙げられているようだが、筆者の扱う環境ではこの領域がNFSマウント領域になっていて、この場所でビルドすると速度が遅いので別のローカルディスク領域(/opt/rpmwork)を利用した。

[user@server ~]$ vim ~/.rpmmacro
# 下記1行を追記(%_topdirが既にあれば値を編集、以下は/opt/rpmworkをビルドルートにする場合)
%_topdir  /opt/rpmwork

[user@server ~]$ cd /opt/rpmwork
[user@server rpmwork]$ ls
BUILD  RPMS  SOURCES  SPECS  SRPMS
[user@server rpmwork]$ cd SOURCES
# ソースをダウンロード、展開
[user@server SOURCES]$ wget https://security.appspot.com/downloads/vsftpd-3.0.2.tar.gz
[user@server SOURCES]$ tar -zxvf vsftpd-3.0.2.tar.gz

# 一部パッケージにないものを既存バージョンから流用
[user@server SOURCES]$ cp /etc/init.d/vsftpd ./vsftpd-3.0.2-vsftpd.init
[user@server SOURCES]$ sudo cp /etc/vsftpd/ftpusers ./vsftpd-3.0.2-vsftpd.ftpusers
[user@server SOURCES]$ sudo cp /etc/vsftpd/user_list ./vsftpd-3.0.2-vsftpd.user_list

# 必要なファイルを作る
[user@server SOURCES]$ wget -O vsftpd-3.0.2-vsftpd.pam http://network.station.ez-net.jp/server/ftp/vsftpd/3.0.2/vsftpd-3.0.2-vsftpd.pam.txt
[user@server SOURCES]$ wget -O vsftpd-3.0.2-vsftpd.vsftpd_conf_migrate.sh http://network.station.ez-net.jp/server/ftp/vsftpd/3.0.2/vsftpd-3.0.2-vsftpd.vsftpd_conf_migrate.sh.txt
[user@server SOURCES]$ wget -O vsftpd-3.0.2-vsf_findlibs.sh.patch http://network.station.ez-net.jp/server/ftp/vsftpd/3.0.2/vsftpd-3.0.2-vsf_findlibs.sh.patch.txt
[user@server SOURCES]$ wget -O vsftpd-3.0.2-builddefs.h.patch http://network.station.ez-net.jp/server/ftp/vsftpd/3.0.2/vsftpd-3.0.2-builddefs.h.patch.txt
[user@server SOURCES]$ wget -O ../SPECS/vsftpd.spec http://network.station.ez-net.jp/server/ftp/vsftpd/3.0.2/vsftpd.spec.txt

# ビルド実行
[user@server SOURCES]$ cd ../SPECS
[user@server SPECS]$ rpmbuild -ba --define="dist .el5" vsftpd.spec
エラー: ビルド依存性の失敗:
	gcc > gcc-3.2.3-13 は vsftpd-3.0.2-7_es.el5.x86_64 に必要とされています
	binutils > binutils-2.14.90.0.4-24 は vsftpd-3.0.2-7_es.el5.x86_64 に必要とされています
	glibc-devel >= 2.3.2-45 は vsftpd-3.0.2-7_es.el5.x86_64 に必要とされています
	libcap-devel は vsftpd-3.0.2-7_es.el5.x86_64 に必要とされています
	openssl-devel は vsftpd-3.0.2-7_es.el5.x86_64 に必要とされています
# おぉ、いろいろ要るものがないと言われた
# でも調べると全て入っている。
# rootで、デフォルトの/usr/src/redhat配下でRPMビルドを行うと
# こんなエラーは出ない。
# 但し、/lib/libcap.so.1: could not read symbols: File in wrong format
# のエラーが出て、コンパイルステップでこける。
# これに対するパッチを当てているにも関わらず

vsf_findlibs.shに関して、どうもlibpam.soに関するところも修正が必要らしい[8]。オリジナルを編集し、libpam.soに関する修正も追加してパッチを作成。

[root@server ~]# cd /usr/src/redhat/SOURCES/vsftpd-3.0.2
[root@server vsftpd-3.0.2]# cp vsf_findlibs.sh vsf_findlibs.sh.orig
[root@server vsftpd-3.0.2]# vi vsf_findlibs.sh ←編集
[root@server vsftpd-3.0.2]# diff -ru vsf_findlibs.sh.orig vsf_findlibs.sh >../vsftpd-3.0.2-vsf_findlibs.sh.patch
[root@server vsftpd-3.0.2]# cat ../vsftpd-3.0.2-vsf_findlibs.sh.patch
--- vsf_findlibs.sh.orig	2014-04-09 16:05:13.000000000 +0900
+++ vsf_findlibs.sh	2014-04-10 16:06:44.000000000 +0900
@@ -13,10 +13,11 @@
 # Look for PAM (done weirdly due to distribution bugs (e.g. Debian) or the
 # crypt library.
 if find_func pam_start sysdeputil.o; then
-  locate_library /lib/libpam.so.0 && echo "/lib/libpam.so.0";
-  locate_library /usr/lib/libpam.so && echo "-lpam";
-  locate_library /usr/lib64/libpam.so && echo "-lpam";
-  locate_library /lib/x86_64-linux-gnu/libpam.so.0 && echo "-lpam";
+#  locate_library /lib/libpam.so.0 && echo "/lib/libpam.so.0";
+#  locate_library /usr/lib/libpam.so && echo "-lpam";
+#  locate_library /usr/lib64/libpam.so && echo "-lpam";
+#  locate_library /lib/x86_64-linux-gnu/libpam.so.0 && echo "-lpam";
+  echo "-lpam";
   # HP-UX ends shared libraries with .sl
   locate_library /usr/lib/libpam.sl && echo "-lpam";
   # AIX ends shared libraries with .a
@@ -48,15 +49,15 @@
 locate_library /usr/lib/libsec.sl && echo "-lsec";
 
 # Look for libcap (capabilities)
-if locate_library /lib/libcap.so.1; then
-  echo "/lib/libcap.so.1";
-elif locate_library /lib/libcap.so.2; then
-  echo "/lib/libcap.so.2";
-else
+#if locate_library /lib/libcap.so.1; then
+#  echo "/lib/libcap.so.1";
+#elif locate_library /lib/libcap.so.2; then
+#  echo "/lib/libcap.so.2";
+#else
   locate_library /usr/lib/libcap.so && echo "-lcap";
   locate_library /lib/libcap.so && echo "-lcap";
   locate_library /lib64/libcap.so && echo "-lcap";
-fi
+#fi
 
 # Solaris needs this for nanosleep()..
 locate_library /lib/libposix4.so && echo "-lposix4";

これでRPMビルド成功

[root@server vsftpd-3.0.2]# cd /usr/src/redhat/SRPMS
[root@server SRPMS]# rpmbuild -ba vsftpd.spec

RPMに署名し、RPMレポジトリに配置して、yumコマンドによりUpgrade。

Upgrade後、vsftpdの設定ファイルに「background=YES」を追記しておく。

[root@server ~]# yum update vsftpd
...
Running Transaction
  Updating       : vsftpd                                                                       1/2 
  Cleanup        : vsftpd                                                                       2/2 

Updated:
  vsftpd.x86_64 0:3.0.2-7_es                                                                        

Complete!
[root@server ~]# /etc/init.d/vsftpd restart
vsftpd を停止中:                                      [  OK  ]
vsftpd 用の vsftpd を起動中: 
# ここで [ OK ] が返ってこない
Ctrl + C で一旦止める
[root@server ~]# cat - >>/etc/vsftpd/vsftpd.conf
background=YES
[Ctrl + D]
# これでOK
[root@server ~]# /etc/init.d/vsftpd start
vsftpd 用の vsftpd を起動中:                     [  OK  ]

ftpサーバの起動

vsftpd 設定ファイル名
    

設定ファイルの既定値は/etc/vsftpd.conf

インタフェース関係

項目 既定値 内容
ftpd_banner 絶対パス (なし) 最初にftpで接続した時にvsftpdが表示するあいさつメッセージを指定した値に設定する。 ftpd_banner=Welcome to our ftp site!
banner_file ファイル名 (なし) 誰かがサーバに接続したときに表示するテキストを格納するファイル名を指定する。このオプションが設定された場合、ftpd_bannerで指定される文字列よりも優先される。banner_file、ftpd_bannerいずれも指定が無い場合はアプリケーション名とバージョン番号(例:(vsFTPd 2.0.5))を表示する。 banner_file=/var/vsftpd/vsftpd_banner

anonymousアクセスの制御

Mac OS Xの場合

  1. 設定ファイルをコピーする
    設定ファイル(inetd.conf,OS 10.2以降はxinetd.conf)はMacOS Xの場合、以下の場所にあります。
    /etc/ これは所有者がrootになっていてそのまま書き換えられないので、一旦ホームディレクトリ(Users/[ユーザ名])など適当な場所にコピーします。
    cp /etc/inetd.conf ~

vsftp(CentOSなどLinux系OS)

既定では/etc/vsftpd/vsftpd.confに設定ファイルが置かれる。 このファイルに記載される各項目の内容は以下の通り。 項目自体を記さないか、またはコメントアウトする(行頭にシャープ #を記す)と既定値が設定されたものとみなされる。

項目 既定値 内容
anonymous_enable YES 匿名アクセス(ftp_usernameで定義されたユーザ, anomymous)を許可 anomymous_enable=YES
NO 匿名アクセスを拒否 anomymous_enable=NO
anon_root 絶対パス (なし) 匿名アクセスでログイン後に変更するディレクトリを指定する。指定が無ければftp_usernameで定義されたユーザ(既定値はftp)のホームディレクトリにとどまる。 anon_root=/var/hogeftp
ftp_username ユーザ名 ftp 匿名アクセスに使うユーザ名 ftp_username=ftp2
no_anon_password YES 匿名アクセス時、パスワードの問い合わせを行わない(パスワードなしでのログインを許可) no_anon_password=YES
NO 匿名アクセス時、パスワードの問い合わせを行う。 no_anon_password=NO

localユーザアクセスの制御

項目 既定値 内容
chroot_local_user YES ローカルユーザのホームディレクトリをルートに設定する(ftpでログインした直後のディレクトリはルート"/"に見える) chroot_local_user=YES
NO ftpでログインした直後のディレクトリはlocal_rootと同じ値に設定される chroot_local_user=NO
local_enable YES ローカルユーザのログインを許可する local_enable=YES
NO ローカルユーザのログインを禁止する local_enable=NO
local_root パス (なし) ローカルログイン(非匿名ログイン)の後に変更するディレクトリを指定する。指定がなければログイン後ディレクトリを変更しない(各ユーザのホームディレクトリのまま)。 local_root=/var/myftp

ログ関係

項目 既定値 内容
use_localtime YES ファイルディレクトリリストの表示や、MDTMコマンドでローカルタイムを使用する。 use_localtime=YES
NO ファイルディレクトリリストの表示や、MDTMコマンドで世界標準時(GMT)を使用する。 use_localtime=NO

ディレクトリトラバーサル対策

vsftpの設定ファイル(/etc/vsftpd.conf)に以下の1行を追記する。

chroot_local_user=YES
    

これにより、ログイン直後のホームディレクトリがルートディレクトリ(/)に見えて、それより上には行けなくなる。

shell> ftp ftpserver
Connected to ftpserver.
220 (vsFTPd 2.0.5)
530 Please login with USER and PASS.
530 Please login with USER and PASS.
KERBEROS_V4 rejected as an authentication type
Name (ftpserver:user): user
331 Please specify the password.
Password: 
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
====上記設定のない場合====
ftp> pwd
257 "/var/ftp"
ftp> cd ..
250 Directory successfully changed.
ftp> pwd
257 "/var" ←ホームディレクトリ(/var/ftp)の上に行けてしまう(そのディレクトリに移動する権限があれば)

====上記設定を行った場合====
ftp> pwd ←ホームディレクトリがルート(/)
257 "/"
ftp> cd ..
250 Directory successfully changed. ←ルートの上への移動はエラーにならないが...
ftp> pwd
257 "/" ←場所はルートのまま(ルートより上には行けない)
    

参考文献・サイト

xferlog

FTPサーバデーモンのログファイルの書式は以下の通り[3]

項目 書式 備考
アクセス時刻(current-time) DDD MMM dd hh:mm:ss YYYY DDD は曜日の英語3文字表記、MMM は月の英語3文字表記、dd は日付(上位空白桁は空白埋め)、hh,mm,ss はそれぞれ時間、分、秒で上位空白桁は0埋め、YYYY は西暦4桁。例:Mon Apr 1 00:10:00 2013
転送に要した時間(transfer-time) s 転送に要した総時間を秒単位で表示。
リモートホスト(remote-host) nnn.nnn.nnn.nnn リモートホストのIPアドレス
ファイルサイズ(file-size) 転送されたファイルのサイズをバイト単位で表示。
ファイル名(filename) 転送されたファイルのファイル名(ドキュメントルートからのパスを含む)。
転送タイプ(transfer-type) 転送のタイプを表示。a であればアスキー転送、b であればバイナリ転送。
特殊処理(special-action-flag) 特殊処理の有無を表示。次のいずれかの文字を1文字以上で指定。C = ファイルは圧縮された、U = ファイルは解凍された、T = ファイルは tar された、_ = なにも行われていない
転送方向(direction) 転送方向を以下のいずれかで表示。o = サーバから出て行く方向(クライアントから見るとget)、i = 入ってくる方向(同 put)。
アクセスモード(access-mode) どのユーザモードでアクセスしたかを表示。以下のいずれか一つ。a = 匿名(anonymous)、g = パスワード設定されたゲストユーザ(guest、ftpaccess(5) の guestgroup コマンドを参照)、r = ローカルで認証されたユーザ(real)。
ユーザ名?(username) ローカルで認証されたユーザであればそのユーザ名、ゲストであればID文字列。匿名の場合は「<no_password>」?
サービス名(service-name) 起動しているサービス名。たいていftpである。
認証手法(authentication-method) 使用された認証のメソッド。指定できるのは次のどちらか。0 = なし、1 = RFC931 認証。
認証ユーザID(authenticated-user-id) 認証メソッドにより復帰したユーザID(って何?)* は認証されたユーザIDが使用不可の場合に使用される。
転送完了したかどうか(completion-status) 転送の状態を示す文字を指定。指定できるのは次のどちらか。c = 転送完了、i = 転送未完了

トラブルシューティング

500 OOPS: cannot change directory

vsftpによるftpサーバへアクセスした際、表題のエラーが表示された場合の原因と対処方法。

アクセス先ディレクトリのアクセス権設定、SELinuxによるアクセスブロックが考えられる[9]

500 OOPS: prctl PR_SET_SECCOMP failed

vsftpd設定ファイルに下記設定を記述すればいいとのこと[11]

seccomp_sandbox=no

Macでファイル転送開始までに時間がかかる

MacでFTPサーバにアクセスすると、ファイル転送開始までに時間がかかる(ファイル名一覧取得などは早い、またファイル転送も一旦始まるとその後は問題なし)。現象は「クライアント:Mac OS X 10.4.11 の ターミナルftpコマンド、サーバ:@niftyのホームページコンテンツアップロード先FTPサーバ」で発生。

原因は、通信モード「アクティブ」(サーバ側通信用ポートは20番固定)ではうまくいってないため。モードを「パッシブ」(サーバ側通信用ポートはサーバから通知された1024〜65535の間の任意値)に変更すれば問題は解消した(転送の前に passive コマンドを実行)。なお、制御用のサーバ側ポートはいずれのモードも21番で固定[10]

接続が拒否される

サーバ側での原因として考えられるもの。

iptablesでアクセス先ポートへのアクセスが許可されていない
ftpサーバが起動していない

クライアント側での原因として考えられるもの。

Personal Firewall等でアクセス先IP、Portへのアクセスが拒否されている
ftpサーバで設定されたlisten IPアドレス(FTPリクエストに対して応答するIPアドレス)とは異なるIPアドレスにアクセスしている

ログインはできるがftpコマンドが実行できない

iptablesを必要ポートを開けているつもりでも、環境によっては「ftpログインはできるものの、ftpコマンドの実行ができない(No route to hostなどのエラーになる)あるいは実行はできるが一旦サーバにrefuseされPassiveモードに切り替えて再試行しているメッセージが出る」といった現象がおきる場合、ftpサーバの /etc/sysconfig/iptables-config 中にある IPTABLES_MODULES の指定値に「ip_conntrack_ftp」を追加して iptables を再起動する[12]

【例】
IPTABLES_MODULES=""
↓
IPTABLES_MODULES="ip_conntrack_ftp"