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

by on January 21, 2009 · 50 comments· LAST UPDATED February 18, 2011

in , ,

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
TwitterFacebookGoogle+PDF versionFound an error/typo on this page? Help us!

{ 50 comments… read them below or add one }

1 Chris July 6, 2009 at 9:32 pm

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 at 9:50 am

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

Reply

3 nixCraft July 10, 2009 at 1:22 pm

@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 at 1:41 pm

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

Reply

5 nixCraft July 10, 2009 at 2:05 pm

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

Reply

6 Krishantha August 7, 2009 at 10:51 am

waititng for above inquary ;)

Reply

7 robin August 9, 2009 at 8:17 am

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 at 1:22 pm

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 at 10:20 pm

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 jken September 28, 2012 at 6:47 am

I think you should turn off the iptables and then take a try again!

Reply

11 Nick September 24, 2009 at 10:31 pm

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

12 Jojo November 12, 2009 at 3:06 am

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

Reply

13 madapaka November 14, 2009 at 3:52 am

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

14 Gunflak January 21, 2010 at 7:00 am

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

15 nixCraft January 21, 2010 at 8:19 am

Check your local or remote firewall settings.

Reply

16 Mathiau July 23, 2010 at 9:44 pm

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

17 Julio July 4, 2011 at 11:47 pm

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

18 Julio August 22, 2011 at 4:08 am

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

19 Random February 27, 2010 at 12:08 pm

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

20 vampir3x June 16, 2010 at 8:59 am

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

Thanks,

Reply

21 Mathiau July 23, 2010 at 9:42 pm

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

22 leo_rockway October 15, 2010 at 4:26 pm

> 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

23 leo_rockway October 15, 2010 at 4:36 pm

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

Reply

24 Ankit February 3, 2011 at 7:18 am

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

25 AndySouth March 20, 2011 at 7:08 pm

Very thanks!
You saved me some time.

Reply

26 snap March 27, 2011 at 1:31 pm

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

27 Ali Ismayilov April 27, 2011 at 12:30 pm

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

28 Guy Armitage April 29, 2011 at 8:48 am

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

29 Ali Ismayilov April 29, 2011 at 11:17 am

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

Sincerely,

Ismayilov Ali

Reply

30 Eli May 4, 2011 at 4:02 pm

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

31 George May 12, 2012 at 8:21 pm

Thanks so much – this was the bit I was stuck on!

Reply

32 Eman July 9, 2014 at 5:12 pm

Thanks a lot dude !

Reply

33 anand August 23, 2011 at 6:25 am

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

34 Figo Kim November 4, 2011 at 2:52 am

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

how to enable local user along with the virtual user?

Reply

35 Sam Pizzuto December 6, 2011 at 6:17 pm

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

36 Andrew Bowns August 1, 2012 at 10:30 pm

Were you ever able to get this figured out? I’m having the same issue.
Command: USER john
Response: 331 Please Specify the password.
Command: PASS ************************
Response: 500 OOPS: cannot change directory:/home/vftp/john
Error: Critical Error
Error: Could not connect to server

Reply

37 Sam Pizzuto August 5, 2012 at 11:47 am

At this time, no I have not. I just let it go.

Reply

38 Mike Knox March 17, 2013 at 4:38 am

Check your SELinux settings:
getsebool -a | grep ftp

If you see the following:
ftp_home_dir –> off

Use this to enable it:
setsebool -P ftp_home_dir on

An alternative option is to disable SELinux altogether, however I don’t recommend that for a public facing server.

Reply

39 Shailendra Kumar January 24, 2012 at 12:37 pm

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

40 Shailendra Kumar January 25, 2012 at 11:35 am

Edit the vsftpd configuration file.

virtual_use_local_privs=YES
pam_service_name=vsftpd.virtual

Reply

41 Marius March 16, 2012 at 3:45 pm

very good job ! but… How can i edit PAM DB..add user, detele user, change user password ?

Reply

42 dilip March 19, 2012 at 2:54 pm

Dear All, Currently I have VSFTPD running with Virtual users and PAM bases authentication.

Now, I want to convert the authentication method, from Virtual PAM based to LDAP bases authentication. I do have a LDAP server, and I access it using the url: ldap://ldap..com.

Could any one can tell me how to convert this authentication.

Dilip

Reply

43 sudharsan April 20, 2012 at 2:34 pm

unable to create virtual users in cenot6 .. im new to this …when i give this command # cd /etc/vsftpd
# cat > vusers.txt

empty no users ….

how to create virtual users

Reply

44 Tim June 14, 2012 at 4:28 pm

With this type of configuration, has anyone tested or expect the ability to delete files from the FTP directory?

The clients attempt RMD “file or folder name” and the server responds with “550 Permission Denied”.

Any help would be appreciated!

Reply

45 raystrach July 24, 2012 at 7:52 am

hey tim
maybe a bit late but you need to set the permissions (chmod) for the files/folders so that the ftp user can work with them
rs

Reply

46 hoangthao November 6, 2012 at 3:35 pm

I can’t login with user and pass in vusers.txt.
Can you help me

Reply

47 SAtishCM December 18, 2012 at 4:57 am

Thanks for the document. It really helped me lot. Very nicely written.

Reply

48 Frowny Ball April 5, 2013 at 11:48 pm

Not sure if anyone’s made better scritps for dealing with users.. I looked at the perl script someone pointed to but it didn’t write out in the correct format, or it didn’t work for me at least. Since I’m no good at perl, I made these…

addftpuser.sh:

#!/bin/bash
if [ "$1" = "-?" ] || [ "$#" -ne 1 ]
then
        echo "Usage: $0 "
        exit 1
else
        if [ `grep -c $1 /etc/vsftpd/vsftpd-virtual-user.txt` -gt 0 ]
        then
                echo "Error: User \"$1\" may already exist. Check the virtual user file."
                exit 1
        else
                echo -n "Enter password for $1: "
                oldmodes=`stty -g`
                stty -echo
                read pass
                stty $oldmodes
                echo
                echo $1 >> /etc/vsftpd/vsftpd-virtual-user.txt
                echo $pass >> /etc/vsftpd/vsftpd-virtual-user.txt
                rm /etc/vsftpd/vsftpd-virtual-user.db
                db_load -T -t hash -f /etc/vsftpd/vsftpd-virtual-user.txt /etc/vsftpd/vsftpd-virtual-user.db
                mkdir /home/ftp/$1
                chown ftp.ftp /home/ftp/$1
                echo "Done."
                exit 0
        fi
fi

and

delftpuser.sh:

#!/bin/bash
if [ "$1" = "-?" ] || [ "$#" -ne 1 ]
then
        echo "Usage: $0 "
        exit 1
else
        if [ `grep -c $1 /etc/vsftpd/vsftpd-virtual-user.txt` -ne 1 ]
        then
                echo "Error: User \"$1\" might not exist. Check the virtual user file."
                exit 1
        else
                echo -n "Are you sure you want to remove user "$1" ? "
                read reply
                reply=$(tr '[:upper:]' '[:lower:]' <<< $reply)
                if [ "$reply" = "y" ]
                then
                        echo -n "Do you want to remove the ftp directory and all its contents? "
                        read deldir
                        deldir=$(tr '[:upper:]' '[:lower:]' <<< $deldir)
                        echo "Processing.."
                        pass=`grep -A1 $1 /etc/vsftpd/vsftpd-virtual-user.txt|tail -1`
                        sed -i '/'$1'/d' /etc/vsftpd/vsftpd-virtual-user.txt
                        sed -i '/'$pass'/d' /etc/vsftpd/vsftpd-virtual-user.txt
                        rm /etc/vsftpd/vsftpd-virtual-user.db
                        db_load -T -t hash -f /etc/vsftpd/vsftpd-virtual-user.txt /etc/vsftpd/vsftpd-virtual-user.db
                        echo "The user has been removed from the virtual user file."
                        if [ "$deldir" = "y" ] && [ -d /home/ftp/$1 ]
                        then
                                rm -rf /home/ftp/$1
                                echo "The user's ftp directory and all its contents have been deleted!"
                        else
                                echo "The user's ftp directory was NOT deleted!"
                        fi
                        echo "Done."
                        exit 0
                else
                        echo "Aborted."
                        exit 0
                fi
        fi
fi

Reply

49 Frowny Ball April 5, 2013 at 11:51 pm

Oops. That should say “scripts”, and then in the chown line there shouldn’t be an http:// in there, but hopefully people will figure that out.

Reply

50 Steve C September 25, 2014 at 9:54 pm

Okay but about the right of the virtual USer …
how to create or make a directory or a file by a virtual user …. ??????

Reply

Leave a Comment

Tagged as: , , , , , , , , , , , , ,

Previous post:

Next post: