Vsftpd FTP Server With Virtual Users ( Berkeley DB + PAM )

by Vivek Gite on January 21, 2009 · 34 comments

Vsftpd supports virtual users with PAM (pluggable authentication modules). A virtual user is a user login which does not exist as a real login on the system in /etc/passwd and /etc/shadow file. Virtual users can therefore be more secure than real users, because a compromised account can only use the FTP server but cannot login to system to use other services such as ssh or smtp.

Required software

  • Berkeley DB (version 4) databases
  • pam_userdb.so

Install Berkeley DB And Utilities Under RHEL / CentOS

Type the following command:
# yum install db4-utils db4

Create The Virtual Users Database

To create a "db4" format file, first create a plain text files with the usernames and password on alternating lines. For e.g. create user called "vivek" with password called "vivekpass" and sayali with password "sayalipass":
# cd /etc/vsftpd
# cat > vusers.txt

Sample output:

vivek
vivekpass
sayali
sayalipass

Next, create the actual database file like this:
# db_load -T -t hash -f vusers.txt vsftpd-virtual-user.db
# chmod 600 vsftpd-virtual-user.db
# rm vusers.txt

Configure VSFTPD for virtual user

Edit the vsftpd configuration file. Add or correct the following configuration options:

anonymous_enable=NO
local_enable=YES
# Virtual users will use the same privileges as local users.
# It will grant write access to virtual users. Virtual users will use the
# same privileges as anonymous users, which tends to be more restrictive
# (especially in terms of write access).
virtual_use_local_privs=YES
write_enable=YES
 
# Set the name of the PAM service vsftpd will use
# RHEL / centos user should use /etc/pam.d/vsftpd
pam_service_name=vsftpd.virtual
 
# Activates virtual users
guest_enable=YES
 
# Automatically generate a home directory for each virtual user, based on a template.
# For example, if the home directory of the real user specified via guest_username is
# /home/virtual/$USER, and user_sub_token is set to $USER, then when virtual user vivek
# logs in, he will end up (usually chroot()'ed) in the directory /home/virtual/vivek.
# This option also takes affect if local_root contains user_sub_token.
user_sub_token=$USER
 
# Usually this is mapped to Apache virtual hosting docroot, so that
# Users can upload files
local_root=/home/vftp/$USER
 
# Chroot user and lock down to their home dirs
chroot_local_user=YES
 
# Hide ids from user
hide_ids=YES

Save and close the file.

Create a PAM File Which Uses Your New Database

The following PAM is used to authenticate users using your new database. Create /etc/pam.d/vsftpd.virtual:
# cat > /etc/pam.d/vsftpd.virtual
Append the following:

#%PAM-1.0
auth       required     pam_userdb.so db=/etc/vsftpd/vsftpd-virtual-user
account    required     pam_userdb.so db=/etc/vsftpd/vsftpd-virtual-user
session    required     pam_loginuid.so

Create The Location Of The Files

You need to set up the location of the files / dirs for the virtual users. Type the following command:
# mkdir /home/vftp
# mkdir -p /home/vftp/{vivek,sayali}
# chown -R ftp:ftp /home/vftp

Restart The FTP Server

Type the following command:
# service vsftpd restart

Test Your Setup

Open another shell session and type:
$ ftp ftp.nixcraft.net
Sample output:

Connected to ftp.nixcraft.net.in.
Name (localhost:root): vivek
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> 

Sample log from /var/log/secure:
# tail -f /var/log/secure
Output

May 21 16:54:28 xentest vsftpd: pam_userdb(vsftpd.virtual:auth): user 'vivek' granted access
This blog post is 5 of 5 in the "Redhat / CentOS VSFTPD FTP Server Tutorial" series. Keep reading the rest of the series:
Share this with other sys admins!
Facebook it - Tweet it - Print it -

We're here to help you make the most of sysadmin work. So, subscribe!

{ 34 comments… read them below or add one }

1 Chris July 6, 2009

Thanks for the helpful article. When running vsftpd on CentOS 5, one small correction I had to make on the configuration of vsftpd.virtual was to add crypt=hash to end of the auth and account lines.

#%PAM-1.0
auth required pam_userdb.so db=/etc/vsftpd/vsftpd-virtual-user crypt=hash
account required pam_userdb.so db=/etc/vsftpd/vsftpd-virtual-user crypt=hash
session required pam_loginuid.so

Reply

2 Krishantha July 10, 2009

it is working.. fine. but I have problem. How to delete user or how to edit user from PAM DB

Reply

3 Vivek Gite July 10, 2009

@Krishantha,

I will add another entry to this series to manage users after vsftpd is configured, such as deleting users, changing passwords and so on.

Reply

4 Krishantha July 10, 2009

Good.. and thanks… please send me the link to that article..

Reply

5 Vivek Gite July 10, 2009

It will be added to this page automatically, bookmark this page.

Reply

6 Krishantha August 7, 2009

waititng for above inquary ;)

Reply

7 robin August 9, 2009

hi Gents,

does anybody know this error msg? Fatal error: gnutls_record_recv: A record packet with illegal version was received.

@t61:~$ lftp localhost
lftp localhost:~> user daniel
Password:
daniel@localhost:~> ls
ls: Fatal error: gnutls_record_recv: A record packet with illegal version was received.
lftp daniel@localhost:~> exit
I'm using Debian, vsftpd 2.1.1
@t61:~$ sudo vsftpd -v
vsftpd: version 2.1.1
@t61:~$ uname -a
Linux t61 2.6.26-2-686 #1 SMP Sun Jun 21 04:57:38 UTC 2009 i686 GNU/Linux
@t61:~$
Here is the vsftpd log:
Sun Aug  9 10:09:54 2009 [pid 20797] CONNECT: Client "127.0.0.1"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", "220-                       +-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", "220-                       |D|e|b|i|a|n| |G|N|U|/|L|i|n|u|x|"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", "220-                       +-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+-+"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", "220-"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", "220-"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", "220-You are accessing my private Linux machine that is provided for authorized use only."
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", "220-"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", "220 "
Sun Aug  9 10:09:54 2009 [pid 20797] FTP command: Client "127.0.0.1", "FEAT"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", "211-Features:"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", " AUTH SSL??"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", " AUTH TLS??"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", " EPRT??"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", " EPSV??"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", " MDTM??"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", " PASV??"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", " PBSZ??"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", " PROT??"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", " REST STREAM??"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", " SIZE??"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", " TVFS??"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", " UTF8??"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", "211 End"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP command: Client "127.0.0.1", "AUTH TLS"
Sun Aug  9 10:09:54 2009 [pid 20797] FTP response: Client "127.0.0.1", "234 Proceed with negotiation."
Sun Aug  9 10:09:55 2009 [pid 20797] FTP command: Client "127.0.0.1", "OPTS UTF8 ON"
Sun Aug  9 10:09:55 2009 [pid 20797] FTP response: Client "127.0.0.1", "200 Always in UTF8 mode."
Sun Aug  9 10:09:55 2009 [pid 20797] FTP command: Client "127.0.0.1", "USER daniel"
Sun Aug  9 10:09:55 2009 [pid 20797] [daniel] FTP response: Client "127.0.0.1", "331 Please specify the password."
Sun Aug  9 10:09:55 2009 [pid 20797] [daniel] FTP command: Client "127.0.0.1", "PASS "
Sun Aug  9 10:09:55 2009 [pid 20796] [daniel] OK LOGIN: Client "127.0.0.1"

Reply

8 Tim SUtton August 13, 2009

Great article and thanks for putting it out there!

One little addition that you may need is if you are running SELinux it may prevent the users from locating their home dir. To correct this you can turn SELinux off if you wish or tweak it with /usr/sbin/setsebool -P ftp_home_dir 1

I’m really looking forward to the rest of the series especially the management of users and data.

One question though – how could you set up multiple users to use the same home dir? for example say I’m working on a project (Project456) and I want one place for all the data but have to issue external parties with their own user accounts.

Reply

9 Nick September 24, 2009

Great article, however I’m having a very frustrating problem (been working on it all day) where I can login just fine, but then cannot list the directory, nor can I upload any files. I can’t for the life of me figure out whats wrong. I’ve done everything by the book and read several different articles on setting this up. Here is my vsftpd.conf (minus comments).


local_enable=YES
write_enable=YES
local_umask=022
dirmessage_enable=YES
xferlog_enable=YES
connect_from_port_20=YES
xferlog_file=/var/log/xferlog
xferlog_std_format=NO
listen=YES
pam_service_name=vsftpd
userlist_enable=YES
tcp_wrappers=YES
log_ftp_protocol=YES
anonymous_enable=NO
local_enable=YES
virtual_use_local_privs=YES
write_enable=YES
guest_enable=YES
user_sub_token=$USER
local_root=/home/clients/$USER
chroot_local_user=YES
hide_ids=YES

Also, is there any way to get any useful debug output from vsftpd so I can try to trouble-shoot what is actually going wrong? The vsftpd.log doesn’t tell me anything that I don’t already get from the ftp-client end.

Thanks for any help.

Reply

10 Nick September 24, 2009

To add to that.

I think I am suddenly able to list the directory now… however I still cannot upload anything.

Is there any special thing I need to do to allow users to upload?

Reply

11 Jojo November 12, 2009

is it possible to use multiple pam? i mean is it ok to use the virtualdb pam and the local users pam?

Reply

12 madapaka November 14, 2009

Hi Vivek,

Thanks for the guide! I wish I have read this before during my previous deployment without the use of MySQL, anyways is it possible to add new users by re-creating the virtual users text file containing new users and passwords respectively and then run db_load all over again?

TIA.

Reply

13 Gunflak January 21, 2010

Hi Vivek, awesome guide. Managed to go through all the way except that when I try and FTP in, it authenticates successfully but gets stuck at :

Response: 227 Entering Passive Mode (IP address here)
Command: LIST
Error: Connection timed out
Error: Failed to retrieve directory listing

Reply

14 Vivek Gite January 21, 2010

Check your local or remote firewall settings.

Reply

15 Mathiau July 23, 2010

GunFlak,
\

First, try to connect to the server with Passive mode turned OFF, if it works, then you need to set vsftpd to use a specific passive mode port range

https://www.redhat.com/docs/manuals/enterprise/RHEL-3-Manual/ref-guide/s1-ftp-vsftpd-conf.html

see the options if you search for Passive on the site starting at pasv_address

then you need to open the same ports on your firewall to access the server externally.

Reply

16 Julio July 4, 2011

Im installing the vsftpd with PAM as you show in this excellent article. but im stucked with
227 Entering Passive Mode (50,57,88,197,91,107)
LIST

Error: Cannot retrieve directory list.

Im already

/sbin/iptables -I RH-Firewall-1-INPUT 1 -p tcp –dport ftp -j ACCEPT
/sbin/iptables -I RH-Firewall-1-INPUT 1 -p tcp –dport ftp-data -j ACCEPT
/sbin/service iptables save
/sbin/service iptables restart

Howhever i think could be the firewall???

Reply

17 Julio August 22, 2011

After some working around this issue ive abled to loggin successfully with the following commands

/sbin/modprobe ip_conntrack
/sbin/modprobe ip_conntrack_ftp

Was the firewall(iptables) that need to follow the ftp data!!

Reply

18 Random February 27, 2010

Is it possible to enable UTF8 in the log file? Currently, the high characters are replaced as question marks though they appear in the file lists correctly.

Reply

19 vampir3x June 16, 2010

Hello, can you advice how to delete users and manage the db4 database?

Thanks,

Reply

20 Mathiau July 23, 2010

Great guide! I can not thank you enough for it!!

I had done something wrong originally, but cleaning everything and starting over i have a working TLS / SSL based FTP server running under CentOS 5.5 with Virtual users.

Question, is using:

Explicit SSL with (Auth SSL)
different then
Explicit SSL with (Auth TSL)

since the server is allowing either one to log in successfully, is this normal?

Also, i was now curious as to how i can set permissions for specific people, this vsftpd is very new to me, as is most things CentOS over the last 3 weeks!

i plan to have users who have access to the apache doc root for website modification, but i do want to limit some things like what they can and can not delete or access.

Reply

21 leo_rockway October 15, 2010

> May 21 16:54:28 xentest vsftpd: pam_userdb(vsftpd.virtual:auth): user ‘vivek’ granted access

I noticed that that line doesn’t list the IP of the user. I recently had someone trying to access one of my servers repeatedly and I’d like to know the IP address of the person that did that, is there any way?

Reply

22 leo_rockway October 15, 2010

I found the information I was looking for in /var/log/audit/audit.log.

Reply

23 Ankit February 3, 2011

You also have to add

guest_username=virtual

in vsftpd.conf file otherwise you will get the error

Starting vsftpd for vsftpd: 500 OOPS: unrecognised variable in config file: guest_enable

Reply

24 AndySouth March 20, 2011

Very thanks!
You saved me some time.

Reply

25 snap March 27, 2011

There is a simple perl script for managing pam_userdb / virtual vsftpd accounts available at:

http://dist.epipe.com/perl/pam_userdb_admin.pl

I thought it might be helpful starting point for people who do not like db_load.

Reply

26 Ali Ismayilov April 27, 2011

Thank you for great post.

However, I have the problem when I install OS via pxe. Can I allow any virtual user to install OS via pxe?

Thank you for the answer

Reply

27 Guy Armitage April 29, 2011

Awesome post! It was all going so well until I came up to a world of pain, I’ve managed to get the system working with virtual users, but as soon as I start trying to write to the ftp server I get “553 Could not create file”.

I’ve looked everywhere, and I know it has to do with permissions, but I can’t get my head around it without compromising the security of the server. Do you have any tips? Is that something you came accross?

Cheers,

Guy

Reply

28 Ali Ismayilov April 29, 2011

I did it, myself :) Thank you again for the awesome post, it helps me, so much:)

Sincerely,

Ismayilov Ali

Reply

29 Eli May 4, 2011

Hello, in case you are running ubuntu the path for pam db are different:

auth required /lib/i386-linux-gnu/security/pam_userdb.so db=/etc/vsftpd_login
account required /lib/i386-linux-gnu/security/pam_userdb.so db=/etc/vsftpd_login

now it works! cheers

Reply

30 anand August 23, 2011

hi ,me also met with the same error while uploading the file “553 Could not create file.” but thing s that when i change my se linux context selinux to “permissive mode ,” uploading s data is possible,since i can’t compromise on security of server, i changed selinux context to enfoceing mode. in that context i can’t upload the file… what might be the reason im using Redhat 6

Reply

31 Figo Kim November 4, 2011

Thanks for the great document. Though, i have one question.

how to enable local user along with the virtual user?

Reply

32 Sam Pizzuto December 6, 2011

This did not work for me. Any ideas?

C:\Documents and Settings\sam>ftp 50.17.xxx.xxx
Connected to 50.17.xxx.xxx.
220 (vsFTPd 2.2.2)
User (50.17.xxx.xxx:(none)): sam
331 Please specify the password.
Password:
500 OOPS: cannot change directory:/home/vftp/samConnection closed by remote host.
C:\Documents and Settings\sam>

Reply

33 Shailendra Kumar January 24, 2012

Jan 24 18:05:38 mann vsftpd[1804]: pam_unix(vsftpd:auth): check pass; user unknown
Jan 24 18:05:38 mann vsftpd[1804]: pam_unix(vsftpd:auth): authentication failure; logname= uid=0 euid=0 tty=ftp ruser=anonymous rhost=192.168.0.198
Jan 24 18:05:38 mann vsftpd[1804]: pam_succeed_if(vsftpd:auth): error retrieving information about user anonymous
Jan 24 18:05:59 mann vsftpd[1806]: pam_unix(vsftpd:auth): check pass; user unknown
Jan 24 18:05:59 mann vsftpd[1806]: pam_unix(vsftpd:auth): authentication failure; logname= uid=0 euid=0 tty=ftp ruser=vivek rhost=192.168.0.198
Jan 24 18:05:59 mann vsftpd[1806]: pam_succeed_if(vsftpd:auth): error retrieving information about user vivek

Reply

34 Shailendra Kumar January 25, 2012

Edit the vsftpd configuration file.

virtual_use_local_privs=YES
pam_service_name=vsftpd.virtual

Reply

Leave a Comment

You can use these HTML tags and attributes for your code and commands: <strong> <em> <ol> <li> <u> <ul> <blockquote> <pre> <a href="" title="">
What is 13 + 4 ?
Please leave these two fields as-is:
Are you a human being? Solve the simple math so we know that you are a human and not a bot.




Previous post:

Next post: