Contents
vsftpd (“Very Secure FTP Daemon”) is an FTP server for Linux and supports PAM (“pluggable authentication modules”). A virtual user cannot login to the Linux system and is considered more secure than using a “real” user whom can login to a Linux system. This guide offers a script that demonstrates one way to setup a vsftpd server using PAM with a Berkeley DB while using virtual users with encrypted passwords.
This test box is a CentOS 7.2 minimal install. It had iptables installed and no firewalld. I wanted to work with firewalld so installed firewalld.
#!/bin/bash #------------------------------------------------------------------------------------ # Install vsFTPd #------------------------------------------------------------------------------------ yum install -y vsftpd systemctl enable vsftpd.service mkdir -p /etc/vsftpd/vconf #------------------------------------------------------------------------------------ # Configure vsFTPd data directory and user #------------------------------------------------------------------------------------ mkdir -p /data/ftp useradd -s /sbin/nologin -d /data/ftp vsftpd chown -R vsftpd:vsftpd /data/ftp #------------------------------------------------------------------------------------ # Configure vsFTPd (/etc/vsftpd/vsftpd.conf) #------------------------------------------------------------------------------------ cp /etc/vsftpd/vsftpd.conf{,.original} sed -i -e "s/^.*anonymous_enable.*/anonymous_enable=NO/g" \ -e "/^xferlog_std_format*a*/ s/^/#/" \ -e "s/#idle_session_timeout=600/idle_session_timeout=900/" \ -e "s/#nopriv_user=ftpsecure/nopriv_user=vsftpd/" \ -e "/#chroot_list_enable=YES/i\chroot_local_user=YES" \ -e 's/listen=NO/listen=YES/' \ -e 's/listen_ipv6=YES/listen_ipv6=NO/' \ /etc/vsftpd/vsftpd.conf echo 'allow_writeable_chroot=YES guest_enable=YES guest_username=vsftpd local_root=/data/ftp/$USER user_sub_token=$USER virtual_use_local_privs=YES user_config_dir=/etc/vsftpd/vconf' >> /etc/vsftpd/vsftpd.conf systemctl start vsftpd.service #------------------------------------------------------------------------------------ # Configure pam (/etc/pam.d/vsftpd) #------------------------------------------------------------------------------------ cp /etc/pam.d/vsftpd{,.original} echo '#%PAM-1.0 auth required pam_userdb.so db=/etc/vsftpd/password crypt=crypt account required pam_userdb.so db=/etc/vsftpd/password crypt=crypt session required pam_loginuid.so' > /etc/pam.d/vsftpd #------------------------------------------------------------------------------------ # Configure firewalld #------------------------------------------------------------------------------------ yum install -y firewalld systemctl start firewalld.service systemctl enable firewalld.service firewall-cmd --permanent --add-service=ftp firewall-cmd --reload #------------------------------------------------------------------------------------ # Configure selinux #------------------------------------------------------------------------------------ setsebool -P ftpd_full_access 1
Create a user.
#!/bin/bash # Create FTP user directory and set ownership mkdir -p /data/ftp/testuser1 chown -R vsftpd:vsftpd /data/ftp # Create vsftpd configuration for the user cat <<EOF > /etc/vsftpd/vconf/testuser1 dirlist_enable=YES download_enable=YES local_root=/data/ftp/testuser1 write_enable=YES EOF # Add user to password files echo 'testuser1' | tee /etc/vsftpd/password{,-nocrypt} > /dev/null # Generate a random password and update password files myval=$(openssl rand -base64 6) { echo "$myval" >> /etc/vsftpd/password-nocrypt echo "$(openssl passwd -crypt "$myval")" >> /etc/vsftpd/password } # Create password database db_load -T -t hash -f /etc/vsftpd/password /etc/vsftpd/password.db
It is worth explaining what is accomplished with the myval variable. Since pam has two lines with crypt=crypt appended. The passwords need to be encrypted. The goal here is to generate a random password using openssl rand then encrypting that password with openssl passwd -crypt. The output to two files, one for the encrypted password to be added to the database, the other for the non encrypted password to test the user. Using tee allows this script to create two files with the username. To append to the files rather than overwrite them, tee -a may be used. This one-liner replaces the following two lines.
echo 'testuser1' > /etc/vsftpd/password echo 'testuser1' > /etc/vsftpd/password-nocrypt
If you remove the crypt=crypt from the PAM file, the clear text password is readable via db_dump -d a /etc/vsftpd/password.db. The example below is with the crypt=crypt appendices.
[root@test]# db_dump -d a /etc/vsftpd/password.db | grep len [000] 4086 len: 9 data: testuser1 [001] 4072 len: 13 data: MV5Bh.YsxmsB6 [root@test]# cat password testuser1 MV5Bh.YsxmsB6 [root@test]# cat password-nocrypt testuser1 3ySBG56Y
For this example, use your favorite ftp client with your host IP (ie. 127.0.0.1), username: testuser1, and password (from the password-nocrypt file): 3ySBG56Y and all should work.
[root@test]# ftp 127.0.0.1 Connected to 127.0.0.1 (127.0.0.1). 220 (vsFTPd 3.0.2) Name (127.0.0.1:root): testuser1 331 Please specify the password. Password: 230 Login successful. Remote system type is UNIX. Using binary mode to transfer files. ftp>
I tried to work out all the kinks, but some additional tweaking may be needed. This is at least a fairly good start to get things going.
Source(s)
- http://www.alexlinux.com/vsftpd-virtual-users-centos-7-example/
- http://yhz.me/blog/Centos-7-Install-Vsftp.html
- https://it.megocollector.com/scripts/vsftpd-ftp-server-with-virtual-users-mysql-pam/
- http://www.netkiller.cn/storage/ftp/vsftpd.html
- http://edvoncken.net/2011/03/tip-encrypted-passwords-just-add-salt/
- http://www.neant.ro/2012/04/secure-ftp-with-vsftpd/
- http://stackoverflow.com/questions/15767273/encrypted-password-in-berkeley-db-for-vsftpd-using-pam-userdb-so
- http://www.howtogeek.com/howto/30184/10-ways-to-generate-a-random-password-from-the-command-line/
- http://stackoverflow.com/questions/4505339/bash-ambiguous-redirect-redirect-to-multiple-files