Setup vsftpd with virtual users using MySQL
I’d like to outline the procedure on how to setup an FTP server using vsftpd virtual users. Using a separate MySQL table to store the credentials of users provides a secure implementation without all the hassle of creating user accounts on your machine. A very detailed tutorial is provided here and is the basis for what follows. I’ve made some changes and added some important steps that will hopefully save you the several wonderful days I’ll never get back.
The main problem you will have is that it will vary per distribution. I’m using an Amazon Linux EC2 instance which is essentially based on CentOS and Red Hat Enterprise Linux. So I can’t verify how this will work on other distributions but hopefully you can find the similar packages.
1. Install and configure MySQL
yum install mysql-server
I won’t go through the MySQL setup. I already had a server running so I used that, but feel free to follow the tutorial for the details on how to create a username and password table to be used with vsftpd.
2. Install and configure vsftpd
yum install vsftpd
First I want to create a user called “vsftpd” that belongs to a group called users. Eventually I want to have all my “virtual” users to have accounts like /home/vsftpd/joe,/home/vsftpd/cathy, etc. The bottom line here is that everything will be stored under /home/vsftpd.
groupadd users (only if you don't have the users group already) useradd -G users -s /sbin/nologin -d /home/vsftpd vsftpd
By the way, the /sbin/nologin command politely refuses a login. It displays a message that an account is not available and exits non-zero. Now let’s make a backup copy of the default configuration file you need to edit and start from scratch.
cp -v /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf-orig vim /etc/vsftpd/vsftpd.conf
It is really up to you on what you need to add but let me show some key ones. Here is the standard setup stuff:
#No ANONYMOUS users allowed anonymous_enable=NO # Allow 'local' users with WRITE permissions (0755) local_enable=YES write_enable=YES local_umask=022 dirmessage_enable=YES xferlog_enable=YES pasv_enable=YES pasv_min_port=14000 pasv_max_port=14100
Here are a number of options specific to our vsftpd user:
nopriv_user=vsftpd chroot_local_user=YES listen=YES # here we use the authentication module for vsftpd to check users name and passw pam_service_name=vsftpd userlist_enable=YES tcp_wrappers=YES # here the vsftpd will allow the 'vsftpd' user to login into '/home/vsftpd/$USER directory guest_enable=YES guest_username=vsftpd local_root=/home/vsftpd/$USER user_sub_token=$USER virtual_use_local_privs=YES
I won’t go into each one but for an exhaustive list of options see the vsftpd configuration options.
3. Configure PAM
Now that we have vsftpd and MySQL setup we can now configure PAM (Password Authentication) so that it uses the MySQL database to authenticate with our virtual FTP users. We will make a backup of the file and edit to replace with these lines:
cp /etc/pam.d/vsftpd /etc/pam.d/vsftpd-orig vim /etc/pam.d/vsftpd
#%PAM-1.0 session optional pam_keyinit.so force revoke auth required pam_mysql.so verbose=1 user=mydbusername passwd=mydbpass host=localhost db=mydb table=mydb_table usercolumn=username passwdcolumn=password crypt=3 account required pam_mysql.so verbose=1 user=mydbusername passwd=mydbpass host=localhost db=mydb table=mydb_table usercolumn=username passwdcolumn=password crypt=3
Just fill in your username/password for your database above along with the database name and table. In addition make sure the parameters for “usercolumn” and “passwdcolumn” match what column names you gave in your MySQL table. I’m using crypt=3 here, this represents MD5 hashing. But I could have gone with SHA1 with crypt=4. Those are really the only 2 secure(ish) options in my opinion.
4. Install Pam for MySQL
I’ve found 2 options to make this work. The easy way, and the pull my hair out and scream way. Take your pick.
a) The easy way
First of all check if you have pam_mysql available with:
yum install pam_mysql
Probably not. BUT you can install the Fedora EPEL repo (in my case I selected version 6):
rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm yum install pam_mysql
Now it should work. Easy right?
b) Pull my hair out and scream way
I must admit this option blows chunks. If the easy way doesn’t work, I’m afraid this is your last resort. This requires you to install pam and configure it to work. Easy right? First get pam_mysql source here.
tar xvfz pam_mysql0.7RC1.tar.gz cd pam_mysql0.7RC1 ./configure --with-openssl=/usr make make install
At this point we are not even close to done. When you try to get this all working you will find out that there is an error from pam something about “make_scrambled_password”. Apparently this function is deprecated in the latest libmysql library. Fortunately I found a patch that fixes this. You need to download that patch (which is a source rpm), install the rpm and find the patch file that is part of it. Once you have the patch file (you might need the patching software like I did so you may need to run “yum install patch”):
cd pam_mysql0.7RC1 patch < pam_mysql0.7RC1-scrambled.patch make clean make make install
See what I mean? Brutal.
5. Check everything is working
You will want to enter an account to test this all works. Depending on how you setup the DB, something like:
INSERT INTO accounts (username, password) VALUES('joe', md5('secret'));
Now you have to create the user home directory:
mkdir /home/vsftpd/joe chown vsftpd:users /home/vsftpd/joe
Rejoice, that should be it! vsftpd is now working with virtual users right from the MySQL DB.