Ubuntu 编译安装vsftpd 3.0.3
背景
最近有一台Ubuntu 12.04的生产服务器,需要架设vsftpd,在使用ACL来进行权限控制并限制账户的chroot之后,出现无法登录的情况。
报错:500 OOPS: vsftpd: refusing to run with writable root inside chroot ()
不限制chroot之后,则可以正常登陆。
Ubuntu 12.04的老旧源内vsftpd的版本是2.3.5,起初是直接使用包安装的,出现问题后去查看了vsftpd官网的更新日志,发现2.3.5起会对目录权限有要求,要求账户的主目录只有550权限,在主目录下新建一个权限750的账户,然后在这个新目录内上传。
但是目前的需求则是这个目录必须带有权限。
为了解决这个问题,搜索了一番,天下文章一大抄,很多人都说要在vsftpd.conf
内添加一个配置allow_writeable_chroot=YES
,大D尝试之后运行vsftpd都会报错。
到官网去看了一下vsftpd的changelog,发现端倪。
这项新参数是3.0.0版本才开始支持的新特性,于是只好安装一个3.0.0+的版本了。
花了点时间开了个虚拟机复现了一下问题,整理成文,避免以后又他人踩坑。
Ubuntu 12.04.5编译安装vsftpd 3.0.3
解决依赖
首先来解决依赖,由于是在新开的虚拟机内测试的,所以还需要安装编译工具包。
1 |
apt-get install build-essential db4.7-util libpam0g libpam0g-dev libssl-dev libpcap-dev libcap2 |
下载源码并解压
1 2 3 |
wget https://security.appspot.com/downloads/vsftpd-3.0.3.tar.gz tar -zxvf vsftpd-3.0.3.tar.gz cd vsftpd-3.0.3 |
配置builddefs.h
由于需要配置SSL加密FTP,所以需要开启SSL功能。如下:
1 2 3 |
将 #undef VSF_BUILD_SSL 更改为 #define VSF_BUILD_SSL |
可以根据需要自行调整功能参数。
编译安装
1 |
make && mkdir -p /usr/local/man/man8 && mkdir -p /usr/local/man/man5 && make install |
这里需要新建两个目录,否则可能会遇到找不到目录的错误。
如果一切正常,则有如下输出:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
if [ -x /usr/local/sbin ]; then \ install -m 755 vsftpd /usr/local/sbin/vsftpd; \ else \ install -m 755 vsftpd /usr/sbin/vsftpd; fi if [ -x /usr/local/man ]; then \ install -m 644 vsftpd.8 /usr/local/man/man8/vsftpd.8; \ install -m 644 vsftpd.conf.5 /usr/local/man/man5/vsftpd.conf.5; \ elif [ -x /usr/share/man ]; then \ install -m 644 vsftpd.8 /usr/share/man/man8/vsftpd.8; \ install -m 644 vsftpd.conf.5 /usr/share/man/man5/vsftpd.conf.5; \ else \ install -m 644 vsftpd.8 /usr/man/man8/vsftpd.8; \ install -m 644 vsftpd.conf.5 /usr/man/man5/vsftpd.conf.5; fi if [ -x /etc/xinetd.d ]; then \ install -m 644 xinetd.d/vsftpd /etc/xinetd.d/vsftpd; fi |
可能遇到的问题
这部分的问题是大D在生产环境中遇到的问题,测试环境中并未遇到,列出来仅供参考。
make之后有如下错误
1 2 3 4 5 6 7 8 9 10 11 12 13 |
sysdeputil.o: In function `vsf_sysdep_has_capabilities': sysdeputil.c:(.text+0x1da): undefined reference to `cap_get_proc' sysdeputil.c:(.text+0x1e5): undefined reference to `cap_free' sysdeputil.o: In function `vsf_sysdep_adopt_capabilities': sysdeputil.c:(.text+0x219): undefined reference to `cap_init' sysdeputil.c:(.text+0x22f): undefined reference to `cap_set_proc' sysdeputil.c:(.text+0x247): undefined reference to `cap_free' sysdeputil.c:(.text+0x276): undefined reference to `cap_set_flag' sysdeputil.c:(.text+0x293): undefined reference to `cap_set_flag' sysdeputil.c:(.text+0x2be): undefined reference to `cap_set_flag' sysdeputil.c:(.text+0x2db): undefined reference to `cap_set_flag' collect2: error: ld returned 1 exit status make: *** [vsftpd] Error 1 |
这个是由于libcap
库导致的,缺少软连接,手动建立一下:
1 |
ln -s /lib/x86_64-linux-gnu/libcap.so /lib64/libcap.so |
还有可能遇到如下错误
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
sysdeputil.o: In function `vsf_sysdep_check_auth': sysdeputil.c:(.text+0xeca): undefined reference to `pam_start' sysdeputil.c:(.text+0xef4): undefined reference to `pam_set_item' sysdeputil.c:(.text+0xf1c): undefined reference to `pam_set_item' sysdeputil.c:(.text+0xf46): undefined reference to `pam_set_item' sysdeputil.c:(.text+0xf64): undefined reference to `pam_authenticate' sysdeputil.c:(.text+0xf8a): undefined reference to `pam_get_item' sysdeputil.c:(.text+0xfb8): undefined reference to `pam_acct_mgmt' sysdeputil.c:(.text+0xfd6): undefined reference to `pam_setcred' sysdeputil.c:(.text+0x1010): undefined reference to `pam_open_session' sysdeputil.c:(.text+0x1046): undefined reference to `pam_end' sysdeputil.c:(.text+0x107e): undefined reference to `pam_end' sysdeputil.c:(.text+0x109e): undefined reference to `pam_end' sysdeputil.c:(.text+0x10b6): undefined reference to `pam_end' sysdeputil.c:(.text+0x10e2): undefined reference to `pam_setcred' sysdeputil.o: In function `vsf_auth_shutdown': sysdeputil.c:(.text+0x1115): undefined reference to `pam_close_session' sysdeputil.c:(.text+0x112b): undefined reference to `pam_setcred' sysdeputil.c:(.text+0x1141): undefined reference to `pam_end' collect2: ld returned 1 exit status make: *** [vsftpd] Error 1 |
解决方法:
1 2 |
vim Makefile LIBS = `./vsf_findlibs.sh` -lpam |
配置vsftpd
新建用户
1 2 3 4 5 6 7 |
groupadd ftpgroup useradd ftpuser -g ftpgroup -d /home/wwwroot/123 -s /sbin/nologin #添加用户 ftpuser 到 ftpgroup用户组,指定用户工作目录为 /usr/local/apache/htdocs,同时禁止使用ftp账户登录系统 passwd ftpuser New UNIX password: Retype new UNIX password: passwd: all authentication tokens updated successfully. |
处理配置文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#关闭匿名登录 anonymous_enable=NO # 以下为删除注释#号 #开启本地用户登录 local_enable=YES write_enable=YES chroot_local_user=YES chroot_list_enable=YES # (default follows) chroot_list_file=/etc/vsftpd.chroot_list #添加参数 解决开启chroot之后错误 #500 OOPS: vsftpd: refusing to run with writable root inside chroot() allow_writeable_chroot=YES #将允许chroot操作的用户名写入vsftpd.chroot_list vim vsftpd.chroot_list #用户名一行一个 #新建empty目录 mkdir /usr/share/empty |
启动vsftpd
1 |
/usr/local/sbin/vsftpd & |
这样就可以正常使用了。测试如图:
vsftpd启动脚本
搜索了一下,找到一份可以用的,感谢原作者:https://serverfault.com/questions/464264/vsftpd-3-0-2-on-ubuntu-12-04-init-file
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
#! /bin/sh ### BEGIN INIT INFO # Provides: vfstpd # Required-Start: $remote_fs $syslog # Required-Stop: $remote_fs $syslog # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: VSFTPD init script # Description: File created for starting VSFTPD manually # installed on Ubuntu 12.04 ### END INIT INFO PATH=/usr/local/sbin:/sbin:/usr/sbin:/bin:/usr/bin DESC="VSFTP Daemon" NAME=vsftpd DAEMON=/usr/local/sbin/$NAME DAEMON_ARGS=" " PIDFILE=/var/run/$NAME.pid SCRIPTNAME=/etc/init.d/$NAME [ -x "$DAEMON" ] || exit 0 [ -r /etc/default/$NAME ] && . /etc/default/$NAME . /lib/init/vars.sh . /lib/lsb/init-functions RED=$(tput setaf 1) GREEN=$(tput setaf 2) NORMAL=$(tput sgr0) col=80 # change this to whatever column you want the output to start at do_start() { echo -n "* Starting vsftpd " $DAEMON & >/dev/null 2>&1 if [ "$?" -eq "0" ] then printf '%*s[%s%s]\n' $col "$NORMAL" "OK" "$NORMAL" pidof $NAME > $PIDFILE return 0 else printf '%*s[%s%s]\n' $col "$NORMAL" "${RED}fail" "$NORMAL" return 2 fi } do_stop() { echo -n "* Stopping vsftpd " kill -KILL `cat $PIDFILE` >/dev/null 2>&1 if [ "$?" -eq "0" ] then rm -f $PIDFILE printf '%*s[%s%s]\n' $col "$NORMAL" "OK" "$NORMAL" return 0 else printf '%*s[%s%s]\n' $col "$NORMAL" "${RED}fail" "$NORMAL" return 2 fi } do_status() { echo -n "* Service vsftpd is " pidof $NAME >/dev/null 2>&1 if [ "$?" -eq "0" ] then echo "running" return 0 else echo "not running" return 2 fi } do_reload() { kill -HUP `cat $PIDFILE` return 0 } case "$1" in start) [ "$VERBOSE" != no ] && log_daemon_msg "Starting $DESC" "$NAME" do_start case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; stop) [ "$VERBOSE" != no ] && log_daemon_msg "Stopping $DESC" "$NAME" do_stop case "$?" in 0|1) [ "$VERBOSE" != no ] && log_end_msg 0 ;; 2) [ "$VERBOSE" != no ] && log_end_msg 1 ;; esac ;; status) do_status ;; restart|force-reload) log_daemon_msg "Restarting $DESC" "$NAME" do_stop case "$?" in 0|1) do_start case "$?" in 0) log_end_msg 0 ;; 1) log_end_msg 1 ;; # Old process is still running *) log_end_msg 1 ;; # Failed to start esac ;; *) log_end_msg 1 ;; esac ;; *) echo "Usage: $SCRIPTNAME {start|stop|status|restart|force-reload}" >&2 exit 3 ;; esac |
在上述代码保存文件到/etc/init.d/
,文件名 vsftpd
,随后就可以使用/etc/init.d/vsftpd start/stop/restart/status
来进行操作了。
新建加密FTP和使用ACL以前就写过了,这里不再赘述。需要说明的就是Ubuntu下使用ACL要调整硬盘挂载参数用来支持ACL。