为OpenSSH添加chroot功能

目标

为 OpenSSH 的 sshd 添加将登录用户 chroot 的功能。

原理介绍

OpenSSH 的 sshd 本身没有提供 chroot 的功能,所以必须依靠一些其他的方法来提供 chroot 的功能。而 OpenSSH 所提供的 sshd 拥有使用 Pluggable Authentication Module(简称为 PAM,下同)的能力,因而我们可以利用这个东西来提供这样的功能。正好 FreeBSD 同时提供了一个叫做 pam_chroot(8) 的 PAM 模块,这个模块的作用就是提供 chroot 的功能。于是通过 FreeBSD 已有的代码,我们可以为 OpenSSH 的 sshd 提供 chroot 的功能。

软件需求

FreeBSD 7.0-RELEASE(实际上未必需要这么新,但是其他的版本我没有测试过)。

实现过程

配置 /etc/ssh/sshd_config

设置 UsePAM 为 yes。

配置 /etc/pam.d/sshd

pam_chroot(8) 的简介

PAM 模块可以提供 4 种功能,分别是 authentication、account management、session management 和 password management。而 pam_chroot(8) 本身只提供了 session management 的功能。这个 PAM 模块可以有 4 个参数 also_root,always,cwd,dir,以下逐一解释。

also_root

如果设置了 also_root,那么即使是 root 登录上来,也会被 chroot。

always

always 告诉 pam_chroot(8) 无论如何都要 chroot,如果找不到合适的 root directory,那么 pam_chroot(8) 模块就报告失败。如果不设置这个选项,查找合适的 root directory 失败之后,pam_chroot(8) 模块报告的就是成功。

dir

dir 是默认的 root directory,如果用户的 home directory 在 passwd 中的描述不符合 pam_chroot(8) 的要求,那么用户就会被 dir 就将是用户的 root directory。

cwd

cwd 提供一个默认的 working directory 给 pam_chroot(8),如果用户的 home directory 在 passwd 中的描述不符合 pam_chroot(8) 的要求,那么将会 chdir 到这个目录,该参数默认为 /。

配置合适的参数

由于 pam_chroot(8) 只有 session management 功能,那么 /etc/pam.d/sshd 这个文件的 session 部分的第一行加上

session         requisite       pam_chroot.so      dir=/tmp cwd=/

这一行代码告诉 PAM,如果 pam_chroot(8) 模块失败了,那么 PAM 系统宣告管理失败,那么将会导致用户不能登录,并且用户默认会被丢在 /tmp 里面。

准备必须的文件

chroot 发生在 sshd 内,而后续创建的进程的 root directory 已经是被 chroot 过了的,此时如果在新的 root directory 中没有合适的文件,那么最终 sshd 将无法启动程序(譬如用户的 shell 等)。
按照上面的例子,用户将会被 chroot 到 /tmp,则需要在 /tmp 中安装合适的文件:
cp -pR /bin /tmp/bin
cp -pR /lib /tmp/lib
cp -pR /libexec /tmp/libexec
mkdir /tmp/etc
mkdir -p /tmp/usr/share/misc
cp /usr/share/misc/termcap /tmp/usr/share/misc

这里假设登录的用户使用了系统附带的 shell 之一。

优点与缺点

优点

与单独启 jail 把用户锁在固定的目录相比,这样做可以避免启动很多 jail,也就省下了很多 IP 地址,并且总共只启动了一个 sshd 进程用于监听 22 端口。

缺点

因为 pam_chroot(8) 非常简陋,所以导致了某些事情做出来让人很不爽:

1、必须对几乎所有的用户 chroot

严格的说并不是这样,但是一般情况下是几乎是一旦在 sshd 的 PAM 配置中启用 pam_chroot(8),那么所有用户都会被 chroot 掉。有个很丑的方法可以改善这种状况,就是使用 pam_ftpusers(8)跳过某些用户。但是 pam_ftpusers(8) 的实现也很简陋,它必须使用 /etc/ftpusers 来指定用户名称,于是……

2、pam_chroot(8) 要求登录的用户必须在 passwd 里面有对应的条目

根据 pam_chroot(8) 的代码,如果登录的用户在 passwd 里面不存在对应的条目,那么 pam_chroot(8) 将返回失败,于是登录也将失败……这样就限制了从其他途径通过认证的用户的使用了。

3、为了使用 pam_chroot(8) 可能要修改 passwd 中对用户 home directory 的描述

pam_chroot(8) 要求当用户的 home directory 中间有 ”/./” 这样的字符串时,前面部分会成为用户所属的 sshd 的 root directory,而后面部分会成为用户的 working directory。但是默认情况下有谁会特意设置这样的 home directory 呢?而且根据 pam_chroot(8) 的代码,如果你不这样设置,并且你没有给 pam_chroot(8) 传递 dir 参数,那么 pam_chroot(8) 会一直失败或总是成功。

4、要装一堆文件

这个没办法,只能这样了……谁让 sshd 本身不是个 shell 呢?

原文链接:http://wiki.freebsdchina.org/howto/c/chrootssh