!!!Chrooted OpenSSH {{category OpenSSH,nolink}}ssh (scp, sftp) アクセスを許可したユーザにホームディレクトリ以外のディレクトリを参照させないようにする、いわゆる chroot 機能を持たせた sshd の構築メモ。暗号化されないとかはないと思うけど、うまく行かないところはあるかも。 OpenBSD 以外の他プラットフォームへのリリース(-p リリース)用のパッチは存在しますが、OpenBSD 用の OpenSSH には、既に組み込まれていたり、追加するためのパッチがありません。ので、-p リリース用のパッチを参考に組み込みます。 ルートを変更(chroot)するユーザは、/etc/passwd ファイルのホームディレクトリの記述を /home/chrooted から /home/chrooted/./ のように変更します。ようは、chroot でルートとする箇所に /./ を挟んで指定する。/./ がないユーザは、通常の sshd と動作は変らない。 !!!sshd with chroot の作成 ssh 関係のソースは、/usr/src/usr.bin/ssh/ 配下にあります。それらのソースファイルに下記のパッチを当てて、sshd を make します。 # cd /usr/src/usr.bin/ssh/ # patch -p0 < chrooted.patch # cd sshd # make # make install !!Chroot patch for OpenSSH 4.3 OpenBSD 3.9 に付いている、OpenSSH_4.3, OpenSSL 0.9.7g を修正した内容(差分)です。 {{code Diff,4, --- session.c.org Tue Feb 28 10:10:21 2006 +++ session.c Wed Nov 29 23:25:44 2006 @@ -67,6 +67,8 @@ #include "kex.h" #include "monitor_wrap.h" +#define CHROOT + #ifdef KRB5 #include #endif @@ -996,7 +998,32 @@ void do_setusercontext(struct passwd *pw) { +#ifdef CHROOT + char *user_dir; + char *new_root; +#endif /* CHROOT */ + if (getuid() == 0 || geteuid() == 0) { +#ifdef CHROOT + user_dir = xstrdup(pw->pw_dir); + new_root = user_dir + 1; + + while((new_root = strchr(new_root, '.')) != NULL) { + new_root--; + if(strncmp(new_root, "/./", 3) == 0) { + *new_root = '\0'; + new_root += 2; + + if(chroot(user_dir) != 0 || chdir("/") != 0) + fatal("Couldn't chroot to user's directory %s", user_dir); + pw->pw_dir = new_root; + break; + } + + new_root += 2; + } +#endif /* CHROOT */ + #ifdef HAVE_LOGIN_CAP if (setusercontext(lc, pw, pw->pw_uid, (LOGIN_SETALL & ~LOGIN_SETPATH)) < 0) { }} !!!chroot 環境の構築 chroot させるユーザの環境構築手順です。スーパーユーザ(root)で作業します。 手始めに、ユーザとグループ名、現在のホームディレクトリをシェル変数にセットする。作業場所は、そのユーザのホームディレクトリ。'''$1'''は、対象ユーザ名に変更のこと。 #!/bin/sh # set chroot user name USERNAME=$1 GROUPNAME=`id -gn $USERNAME` HOMEDIR=`grep /etc/passwd -e "^$USERNAME" | cut -d':' -f 6` cd $HOMEDIR ※一行目が ''''#!/bin/sh'''' の整形済テキストは、sh のコマンド。 !!ホームディレクトリの設定 chrootするユーザであることを示すためにホームディレクトリの記述を変更します。 #!/bin/sh # change home directory usermod -d $HOMEDIR/./ $USERNAME !!必要なディレクトリの作成 chrootした際に必要なファイルを置くディレクトリを作成する。ユーザが触ることはないので、オーナは root にする。 #!/bin/sh # Create Directories DIRS="./bin ./dev ./etc ./usr ./usr/lib ./usr/libexec" mkdir -m 755 -p $DIRS chown -R root:wheel $DIRS !!デバイスファイルを作成する null デバイスファイルが必要なので作ります。 // cd dev // /dev/MAKEDEV std // cd .. // //でもね、/dev/MAKEDEV で作ったけどうまくいかないんだよね。とりあえず、オープン出来れば良いみたいなので、ダミーのファイルを作成する。 // #!/bin/sh // # Make device file // touch ./dev/null // chmod 666 ./dev/null // //!追記 (2008/02/27) //いや、MAKEDEV の使い方が間違ってた…。/dev/MAKEDEV をコピーする必要がある。 #!/bin/sh # Make device file cd dev cp -p /dev/MAKEDEV ./ ./MAKEDEV std cd .. !!パスワードファイルとグループファイルの作成 必要最低限に絞ったパスワードファイルとグループファイルを作成します。また、時間表示をあわせる為、タイムゾーンのファイルもコピーします。 #!/bin/sh # Make /etc/passwd and /etc/group grep /etc/passwd -e "^root" -e "^$USERNAME" > ./etc/passwd grep /etc/group -e "^wheel" -e "kmem" -e "^bin" -e "^$GROUPNAME" > ./etc/group chmod 644 ./etc/passwd ./etc/group chown root:wheel ./etc/passwd ./etc/group cp -p /etc/pwd.db ./etc/pwd.db cp -p /etc/localtime ./etc/localtime ※パスワードファイルは、以下のようにする方が正しい?(未確認) grep /etc/master.passwd -e "^root" -e "^$USERNAME" > ./etc/master.passwd pwd_mkdb -d ./etc ./etc/master.passwd if [ ! -f ./etc/group ] ; then grep /etc/group -e "^wheel" -e "kmem" -e "^bin" > ./etc/group fi grep /etc/group -e "^$GROUPNAME" >> ./etc/group if [ ! -f ./etc/master.passwd ] ; then grep /etc/master.passwd -e "^root" > ./etc/master.passwd fi grep /etc/master.passwd -e "^$USERNAME" >> ./etc/master.passwd pwd_mkdb -d ./etc ./etc/master.passwd !!コマンドファイルと関係ライブラリをコピーする 必要なコマンドファイルとダイナミックリンクされているライブラリをコピーします。/bin/groups は、スクリプトで id を呼び出しているのでパスをあわせて作り直します。 #!/bin/sh # copy command list CMDS="sh ksh csh chmod chown chgrp id ls pwd cp scp mv rm mkdir rmdir vi cat" # Copy command and library for prog in `which $CMDS`; do cp -p $prog ./bin # obtain a list of related libraries ldd $prog > /dev/null 2> /dev/null if [ "$?" = 0 ] ; then LIBS=`ldd $prog | grep rlib | awk '{ print $7 }'` for lib in $LIBS; do cp -p $lib ./usr/lib done fi done # Copy command and library Part2 cp -p /usr/libexec/ld.so ./usr/libexec/ld.so cp -p /usr/libexec/sftp-server ./usr/libexec/sftp-server LIBS=`ldd /usr/libexec/sftp-server | grep rlib | awk '{ print $7 }'` for lib in $LIBS; do cp -p $lib ./usr/lib done # Make groups command echo '#!/bin/sh -'> ./bin/groups echo 'exec /bin/id -Gn $*'>> ./bin/groups chown root:bin ./bin/groups chmod 555 ./bin/groups !!!備考等 !!参考 *Chroot patch for ssh **http://chrootssh.sourceforge.net/ *Chroot patch for ssh (SourceForge.net) **http://sourceforge.net/projects/chrootssh/ *FreeBSDでChroot patch for ssh **http://nadmin.org/howto/chrooted-ssh.html !!ひとりごと 公式にサポートしないですかね。OpenBSD の ftpd の chroot機能が、/etc/ftpchroot に列挙してなので、sshd もならって、/etc/sshchroot とかで出来れば便利かな。 ※ OpenSSH 4.9 (2008/03/30) から公式に chroot 機能が追加された。 やってみてわかったけど、"/./" をホームディレクトリに入れると、普通にコンソールで入った場合に、ホームディレクトリにいてもホームディレクトリにいると見てくれない('~' の表示にならない)。実害はないけど変な感じ。