Announcement

Collapse
No announcement yet.

vsftpd how-to with mangement script

Collapse
This topic is closed.
X
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    vsftpd how-to with mangement script

    Hi,

    I setup vsftpd because I needed a really secure FTP setup. Here is the how-to that came out of it. I also needed a way to mange it via ssh and I couldn't find anything on the net so I wrote this script. Hope someone else finds it useful.

    Don H.

    Code:
    #!/bin/bash
    # writen for vsftpd 2.06, MySQL 5,
    # Version 1.01	2008-10-30 by Don Hess
    # This script will provide a menu to manipulate the mysql database 
    # and manage the files for all type of user administration. It is 
    # intended that the server only need ftp and ssh open and you can secure
    # ssh to lock out IP address apon a certain number of failures. The mysql
    # should be setup similar to this how-to [url]http://www.howtoforge.com/vsftpd_mysql_debian_etch[/url]
    # with the addition of a description field in the db. 
    
    
    chrootftploc=/storage/sharedfiles/ftp		# ftp root directory
    vsftpduserconfloc=/etc/vsftpd_user_conf		# location of user specific config override files
    vsftpduserconflocdef=$vsftpduserconfloc/default	# location of default template for above
    vsftpsysuser=vsftpdvirtual 			# the system user that vsftpd runs under
    myuserlogin=""					# mysql login this script will use
    myuserpass=""					# "" "" ""
    db="vsftpd_db"					# database used to store our information
    mysqlhost="localhost"				# host computer for mysql server
    mysqlloginstr="" # used in sql queries instead of long string, set in getmysqllogin function
    mysqltables="username, LEFT(pass, 6) AS pass, description" #used inplace of * for SELECT statements so password display is shorter.
    # mysql syntax reference [url]http://dev.mysql.com/doc/refman/5.0/en/sql-syntax-data-manipulation.html[/url]
    
    
    mainprompt() 
    {
    	USERINPUT=1
    	echo "-------------------------------"
    	echo "vsftp mysql database utility"
    	echo ""
    	echo "1 Query user(s)"
    	echo "2 Add new user"
    	echo "3 Update user"
    	echo "4 Delete user"
    	echo "5 Change this scripts MySQL login"
    	echo "6 Quit"
    	echo ""
    	echo -n "--> "
    	read USERINPUT
    }
    hideechoing()
    {
     local stty_orig=`stty -g`	# set the original stty state to variable
     stty -echo			# turn off terminal echoing so we don't see password
     read hidinput;		# read user input
     sanitizeinput "$hidinput" password; # sanitize input
     stty $stty_orig		# put terminal back the way it was
    }
    sanitizeinput()
    {
     # $1 is input to be sanitized 
     # $2 tells us which options to use to sanitize
     parm1=`echo "$1" | tr -d '[\000-\037][\041-\054]\057[\072-\077]\100[\133-\136]\140[\173-\176]' | tr -d '[:cntrl:]'`; 
    	# remove non-alpha characters using octets, [url]http://en.wikipedia.org/wiki/ASCII[/url]
    	# only non-alpha characters allowed are space, underscore "_", hyphen "-", and period "."
     parm2="$2"
     case "$parm2" in
      username)
    	UNIN=`echo $parm1 | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]' | sed 's/^\(..............................\).*$/\1/'`;; # use sed to crop to 30 chars
      password) 
    	PASSIN=`echo $parm1 | tr -d '[:space:]' | sed 's/^\(..............................\).*$/\1/'`;; # use sed to crop to 30 chars
      description) 
    	DESCIN=`echo $parm1 | sed 's/^\(........................................\).*$/\1/'`;; # use sed to crop to 40 chars
      * ) echo -n "";;
     esac
    }
    getmysqllogin()
    {
     echo "You must enter the connection information for MySQL before continuing."
     echo -n "Enter MySQL username (case sensitive): "; read aa;
     myuserlogin=`echo "$aa"`;
     echo -n "Enter MySQL password (case sensitive): "; # this is a one-off hidding of password because we may need special chars
     local stty_orig=`stty -g`	# set the original stty state to variable
     stty -echo			# turn off terminal echoing so we don't see password
     read bb			# read user input
     stty $stty_orig		# put terminal back the way it was
     myuserpass=`echo "$bb"`;
     mysqlloginstr="--host=$mysqlhost --user="$myuserlogin" --password="$myuserpass" --database="$db"" #reset the login variable with new data
     echo ""; echo "";
     echo "Username and password for MySQL set."
     echo Using MySQL host "'$mysqlhost'" with database "'$db'".
    }
    printusers()
    {
    # --skip-column-names removes coloumn headers
    # mysql --host=host_name --user=user_name --password=your_password --database=dbname -e "statement;"
     clear
     echo -n "Input at least part of the username or press [Enter] key to show all: "; read UNIN; sanitizeinput "$UNIN" username;
     if [ "$UNIN" = "" ]; then
       echo ""
       echo "First 1000 ftp users in database: "
       mysql $mysqlloginstr -e "SELECT $mysqltables FROM accounts a LIMIT 0,1000;"
       echo "Password field is truncated for display purposes only."
     else	#search for similar names.
       echo "Here are the closes matches to '$UNIN' "
       mysql $mysqlloginstr -e "SELECT $mysqltables FROM accounts WHERE username LIKE '%$UNIN%';"
       echo "Password field is truncated for display purposes only."
     fi
    }
    adduser()
    {
     echo ""
     echo "Note you must have sudo privileges to add a user."
     # tell sanitize function how sanitize (username, password, etc, UNIN var is globalally available so we won't pass
     echo -n "Enter new ftp username (30 char max) [cancel]: "; read UNIN; sanitizeinput "$UNIN" username; 
     echo "The username that will be used after sanitizing is '$UNIN'. "
     echo -n "Enter new ftp user's password (30 char max, only _ - . puncuation allowed): "; echo ""; hideechoing; # use hideechoing function
     echo -n "Enter user description (40 char max) [NULL]: "; read DESCIN; sanitizeinput "$DESCIN" description; 
     if [ "$UNIN" = "" ]; then
       echo "OOPS, you didn't enter anything for a username."
     else
      if [ "$PASSIN" = "" ]; then
        echo "OOPS, you didn't enter anything for a password."
      else
        mysql $mysqlloginstr -e "INSERT INTO accounts (id, username, pass, description) VALUES(DEFAULT, '$UNIN', PASSWORD('$PASSIN'), '$DESCIN');"
        PASSIN=""; # clear password because we are done with it.
    
        # create user home directory?
        echo ""
        echo -n "Do you want to create a ftp home directory for the user? "; read YN;
         case "$YN" in
    	  [yY]) sudo mkdir "$chrootftploc/$UNIN";
    	     sudo chown $vsftpsysuser:$vsftpsysuser "$chrootftploc/$UNIN";
    	     sudo chmod 775 "$chrootftploc/$UNIN";;
    	   * ) echo -n "";;
         esac
        # copy the default file to username so we can configure them independently
        echo ""
        echo "Copying default user configuration to $vsftpduserconfloc/$UNIN "
        sudo cp "$vsftpduserconflocdef" "$vsftpduserconfloc/$UNIN"
        echo ""
        echo -n "Do you want to edit the $vsftpduserconfloc/$UNIN configuration file? [y/N]: "; read YN;
         case "$YN" in
    	  [yY]) sudo vi "$vsftpduserconfloc/$UNIN";;
    	   * ) echo -n "";;
         esac
      fi
     fi
    }
    updateuser()
    {
     echo -n "Enter ftp username to update: "; read UNIN; sanitizeinput "$UNIN" username;
     if [ "$UNIN" = "" ]; then
       echo "OOPS, you didn't enter anything."
     else #check if name is in db, if it is continue. If not search for similar names.
      UU=`mysql --skip-column-names $mysqlloginstr -e "SELECT username FROM accounts a WHERE username='$UNIN';"`
    
      if [ "$UNIN" = "$UU" ]; then
       echo -n "Do you want to update password for '$UNIN'? [y/N]: "; read YN; 
       case "$YN" in
    	[yY]) echo -n "Enter new password for '$UNIN' (30 char max, only _ - . puncuation allowed): "; echo ""; hideechoing; # use hideechoing function
    	   mysql $mysqlloginstr -e "UPDATE accounts SET pass=PASSWORD('$PASSIN') WHERE username='$UNIN';" 
    	   PASSIN="";; # clear password because we are done with it.
    	 * ) echo -n "";;
       esac
       echo -n "Do you want to update description for '$UNIN'? [y/N]: "; read YN;
       case "$YN" in
    	[yY]) echo -n "Enter new description for '$UNIN' (40 char max): "; read DESCIN; sanitizeinput "$DESCIN" description;
    	   mysql $mysqlloginstr -e "UPDATE accounts SET description='$DESCIN' WHERE username='$UNIN';" ;;
    	 * ) echo -n "";;
       esac
       else echo ""
    	 echo "FTP username '$UNIN' not in database."
    	 echo "but here are some names that are close: "
    	 mysql $mysqlloginstr -e "SELECT $mysqltables FROM accounts WHERE username LIKE '%$UNIN%';"
      fi
     fi
    }
    deleteuser()
    {
     echo ""
     echo "Note you must have sudo privileges to properly delete a user."
     echo -n "Input the username or part of the username to delete [cancel]: "; read UNIN; sanitizeinput "$UNIN" username;
     if [ "$UNIN" = "" ]; then
       echo "OOPS, you didn't enter anything."
     else	#check if name is in db, if it is delete. If not, search for similar names.
       UU=`mysql --skip-column-names $mysqlloginstr -e "SELECT username FROM accounts WHERE username='$UNIN';"`
       if [ "$UNIN" = "$UU" ]; then
        echo -n "Are you sure you want to delete user '$UNIN'? [y/N]: "; read YN;
         case "$YN" in
    	  [yY]) mysql $mysqlloginstr -e "DELETE FROM accounts WHERE username='$UNIN';"
    		sudo rm "$vsftpduserconfloc/$UNIN"; # delete user specific config file
    		 if [ -e "$chrootftploc/$UNIN" ]; then # check if user has a ftp root folder created for them	
    		  echo -n "Are you sure you want to delete the folder $chrootftploc/$UNIN? [y/N]: "; read YN;
    		  case "$YN" in
    			 [yY]) sudo rm -r "$chrootftploc/$UNIN";; # delete users ftp root folder
    			  * ) echo "";;
    		  esac
    		 else
    		  echo "Username '$UNIN' deleted"
    		 fi 
    		 echo "Username '$UNIN' deleted";;
    	  * ) echo ""; echo -n "User '$UNIN' kept safe";;
         esac
       else echo ""
    	 echo "The FTP username '$UNIN' not in database "
    	 echo "but here are some names that are close: "
    	 mysql $mysqlloginstr -e "SELECT $mysqltables FROM accounts WHERE username LIKE '%$UNIN%';"
       fi
     fi
    }
    
    clear
    getmysqllogin;
    mainprompt;
    
    while [ "$USERINPUT" != "6" ] 
    do
    
     case "$USERINPUT" in
    	"1") printusers;;
    	"2") adduser;;
    	"3") updateuser;;
    	"4") deleteuser;;
    	"5") getmysqllogin;;
    	"6") echo "Good Bye";;
    	 * ) clear
    	   echo "Please select a number";;
     esac
    
     echo ""
     echo ""
     mainprompt;
     
    done
    Attached Files

    #2
    Re: vsftpd how-to with mangement script

    Helps I attach the how-to.
    Attached Files

    Comment


      #3
      Re: vsftpd how-to with mangement script

      I updated the code a bit.


      Code:
      #!/bin/bash
      # writen for vsftpd 2.06, MySQL 5,
      # Version 1.01 2008-10-30 by Don Hess
      # This script will provide a menu to manipulate the mysql database
      # and manage the files for all type of user administration. It is
      # intended that the server only need ftp and ssh open and you can secure
      # ssh to lock out IP address apon a certain number of failures. The mysql
      # should be setup similar to this how-to [url]http://www.howtoforge.com/vsftpd_mysql_debian_etch[/url]
      # with the addition of a description field in the db.
      
      
      chrootftploc=/home/ftp     # ftp root directory
      vsftpduserconfloc=/etc/vsftpd_user_conf     # location of user specific config override files
      vsftpduserconflocdef=$vsftpduserconfloc/default # location of default template for above
      vsftpsysuser=vsftpd           # the system user that vsftpd runs under
      myuserlogin="vsftpd"                  # mysql login this script will use
      myuserpass="yourppassword"                  # "" "" ""
      db="vsftpd"                   # database used to store our information
      mysqlhost="localhost"              # host computer for mysql server
      mysqlloginstr="" # used in sql queries instead of long string, set in getmysqllogin function
      mysqltables="username, LEFT(pass, 6) AS pass, description" #used inplace of * for SELECT statements so password display is shorter.
      # mysql syntax reference [url]http://dev.mysql.com/doc/refman/5.0/en/sql-syntax-data-manipulation.html[/url]
      
      
      mainprompt()
      {
          USERINPUT=1
          echo "-------------------------------"
          echo "vsftp mysql database utility"
          echo ""
          echo "1 Query user(s)"
          echo "2 Add new user"
          echo "3 Update user"
          echo "4 Delete user"
          echo "5 Change this scripts MySQL login"
          echo "6 Quit"
          echo ""
          echo -n "--> "
          read USERINPUT
      }
      hideechoing()
      {
       local stty_orig=`stty -g`   # set the original stty state to variable
       stty -echo          # turn off terminal echoing so we don't see password
       read hidinput;        # read user input
       sanitizeinput "$hidinput" password; # sanitize input
       stty $stty_orig        # put terminal back the way it was
      }
      sanitizeinput()
      {
       # $1 is input to be sanitized
       # $2 tells us which options to use to sanitize
       parm1=`echo "$1" | tr -d '[\000-\037][\041-\054]\057[\072-\077]\100[\133-\136]\140[\173-\176]' | tr -d '[:cntrl:]'`;
          # remove non-alpha characters using octets, [url]http://en.wikipedia.org/wiki/ASCII[/url]
          # only non-alpha characters allowed are space, underscore "_", hyphen "-", and period "."
       parm2="$2"
       case "$parm2" in
        username)
          UNIN=`echo $parm1 | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]' | sed 's/^\(..............................\).*$/\1/'`;; # use sed to crop to 30 chars
        password)
          PASSIN=`echo $parm1 | tr -d '[:space:]' | sed 's/^\(..............................\).*$/\1/'`;; # use sed to crop to 30 chars
        description)
          DESCIN=`echo $parm1 | sed 's/^\(........................................\).*$/\1/'`;; # use sed to crop to 40 chars
        * ) echo -n "";;
       esac
      }
      getmysqllogin()
      {
       echo "You must enter the connection information for MySQL before continuing."
       echo -n "Enter MySQL username (case sensitive): "; read aa;
       myuserlogin=`echo "$aa"`;
       echo -n "Enter MySQL password (case sensitive): "; # this is a one-off hidding of password because we may need special chars
       local stty_orig=`stty -g`   # set the original stty state to variable
       stty -echo          # turn off terminal echoing so we don't see password
       read bb            # read user input
       stty $stty_orig        # put terminal back the way it was
       myuserpass=`echo "$bb"`;
       mysqlloginstr="--host=$mysqlhost --user="$myuserlogin" --password="$myuserpass" --database="$db"" #reset the login variable with new data
       echo ""; echo "";
       echo "Username and password for MySQL set."
       echo Using MySQL host "'$mysqlhost'" with database "'$db'".
      }
      printusers()
      {
      # --skip-column-names removes coloumn headers
      # mysql --host=host_name --user=user_name --password=your_password --database=dbname -e "statement;"
       clear
       echo -n "Input at least part of the username or press [Enter] key to show all: "; read UNIN; sanitizeinput "$UNIN" username;
       if [ "$UNIN" = "" ]; then
         echo ""
         echo "First 1000 ftp users in database: "
         mysql $mysqlloginstr -e "SELECT $mysqltables FROM accounts a LIMIT 0,1000;"
         echo "Password field is truncated for display purposes only."
       else #search for similar names.
         echo "Here are the closes matches to '$UNIN' "
         mysql $mysqlloginstr -e "SELECT $mysqltables FROM accounts WHERE username LIKE '%$UNIN%';"
         echo "Password field is truncated for display purposes only."
       fi
      }
      adduser()
      {
       echo ""
       echo "Note you must have sudo privileges to add a user."
       # tell sanitize function how sanitize (username, password, etc, UNIN var is globalally available so we won't pass
       echo -n "Enter new ftp username (30 char max) [cancel]: "; read UNIN; sanitizeinput "$UNIN" username;
       echo "The username that will be used after sanitizing is '$UNIN'. "
       echo -n "Enter new ftp user's password (30 char max, only _ - . puncuation allowed): "; echo ""; hideechoing; # use hideechoing function
       echo -n "Enter user description (40 char max) [NULL]: "; read DESCIN; sanitizeinput "$DESCIN" description;
       if [ "$UNIN" = "" ]; then
         echo "OOPS, you didn't enter anything for a username."
       else
        if [ "$PASSIN" = "" ]; then
          echo "OOPS, you didn't enter anything for a password."
        else
          mysql $mysqlloginstr -e "INSERT INTO accounts (id, username, pass, description) VALUES(DEFAULT, '$UNIN', PASSWORD('$PASSIN'), '$DESCIN');"
          PASSIN=""; # clear password because we are done with it.
      
          # create user home directory?
          echo ""
          echo -n "Do you want to create a ftp home directory for the user? "; read YN;
           case "$YN" in
            [yY]) sudo mkdir "$chrootftploc/$UNIN";
               sudo chown $vsftpsysuser:nogroup "$chrootftploc/$UNIN";
               sudo chmod 775 "$chrootftploc/$UNIN";;
             * ) echo -n "";;
           esac
          # copy the default file to username so we can configure them independently
          echo ""
          echo "Copying default user configuration to $vsftpduserconfloc/$UNIN "
          sudo cp "$vsftpduserconflocdef" "$vsftpduserconfloc/$UNIN"
          echo ""
          echo -n "Do you want to edit the $vsftpduserconfloc/$UNIN configuration file? [y/N]: "; read YN;
           case "$YN" in
            [yY]) sudo vi "$vsftpduserconfloc/$UNIN";;
             * ) echo -n "";;
           esac
        fi
       fi
      }
      updateuser()
      {
       echo -n "Enter ftp username to update: "; read UNIN; sanitizeinput "$UNIN" username;
       if [ "$UNIN" = "" ]; then
         echo "OOPS, you didn't enter anything."
       else #check if name is in db, if it is continue. If not search for similar names.
        UU=`mysql --skip-column-names $mysqlloginstr -e "SELECT username FROM accounts a WHERE username='$UNIN';"`
      
        if [ "$UNIN" = "$UU" ]; then
         echo -n "Do you want to update password for '$UNIN'? [y/N]: "; read YN;
         case "$YN" in
          [yY]) echo -n "Enter new password for '$UNIN' (30 char max, only _ - . puncuation allowed): "; echo ""; hideechoing; # use hideechoing function
             mysql $mysqlloginstr -e "UPDATE accounts SET pass=PASSWORD('$PASSIN') WHERE username='$UNIN';"
             PASSIN="";; # clear password because we are done with it.
           * ) echo -n "";;
         esac
         echo -n "Do you want to update description for '$UNIN'? [y/N]: "; read YN;
         case "$YN" in
          [yY]) echo -n "Enter new description for '$UNIN' (40 char max): "; read DESCIN; sanitizeinput "$DESCIN" description;
             mysql $mysqlloginstr -e "UPDATE accounts SET description='$DESCIN' WHERE username='$UNIN';" ;;
           * ) echo -n "";;
         esac
         else echo ""
           echo "FTP username '$UNIN' not in database."
           echo "but here are some names that are close: "
           mysql $mysqlloginstr -e "SELECT $mysqltables FROM accounts WHERE username LIKE '%$UNIN%';"
        fi
       fi
      }
      deleteuser()
      {
       echo ""
       echo "Note you must have sudo privileges to properly delete a user."
       echo -n "Input the username or part of the username to delete [cancel]: "; read UNIN; sanitizeinput "$UNIN" username;
       if [ "$UNIN" = "" ]; then
         echo "OOPS, you didn't enter anything."
       else #check if name is in db, if it is delete. If not, search for similar names.
         UU=`mysql --skip-column-names $mysqlloginstr -e "SELECT username FROM accounts WHERE username='$UNIN';"`
         if [ "$UNIN" = "$UU" ]; then
          echo -n "Are you sure you want to delete user '$UNIN'? [y/N]: "; read YN;
           case "$YN" in
            [yY]) mysql $mysqlloginstr -e "DELETE FROM accounts WHERE username='$UNIN';"
              sudo rm "$vsftpduserconfloc/$UNIN"; # delete user specific config file
               if [ -e "$chrootftploc/$UNIN" ]; then # check if user has a ftp root folder created for them
                echo -n "Are you sure you want to delete the folder $chrootftploc/$UNIN? [y/N]: "; read YN;
                case "$YN" in
                   [yY]) sudo rm -r "$chrootftploc/$UNIN";; # delete users ftp root folder
                    * ) echo "";;
                esac
               else
                echo "Username '$UNIN' deleted"
               fi
               echo "Username '$UNIN' deleted";;
            * ) echo ""; echo -n "User '$UNIN' kept safe";;
           esac
         else echo ""
           echo "The FTP username '$UNIN' not in database "
           echo "but here are some names that are close: "
           mysql $mysqlloginstr -e "SELECT $mysqltables FROM accounts WHERE username LIKE '%$UNIN%';"
         fi
       fi
      }
      
      clear
      getmysqllogin;
      mainprompt;
      
      while [ "$USERINPUT" != "6" ]
      do
      
       case "$USERINPUT" in
          "1") printusers;;
          "2") adduser;;
          "3") updateuser;;
          "4") deleteuser;;
          "5") getmysqllogin;;
          "6") echo "Good Bye";;
           * ) clear
             echo "Please select a number";;
       esac
      
       echo ""
       echo ""
       mainprompt;
      
      done


      Here is my vsftpd.conf


      Code:
      listen=YES
      
      log_ftp_protocol=YES
      
      anonymous_enable=NO
      local_enable=YES
      write_enable=YES
      local_umask=022
      
      pasv_address=EXTERNAL IPADDRESS
      dirmessage_enable=YES
      
      vsftpd_log_file=/var/log/vsftpd.log
      xferlog_enable=YES
      
      connect_from_port_20=YES
      idle_session_timeout=600
      data_connection_timeout=120
      ##
      #Welcome Banner
      ##
      ftpd_banner=Welcome to the FTP service.
      
      nopriv_user=vsftpd
      chroot_local_user=YES
      
      secure_chroot_dir=/var/run/vsftpd
      
      pam_service_name=vsftpd
      
      
      rsa_cert_file=/etc/ssl/certs/vsftpd.pem
      guest_enable=YES
      guest_username=vsftpd
      local_root=/home/ftp/$USER
      user_sub_token=$USER
      virtual_use_local_privs=YES
      user_config_dir=/etc/vsftpd_user_conf
      
      #Enable SSL, a very good thing
      ##
      ssl_enable=YES
      allow_anon_ssl=NO
      ##
      #Set up for SSL access conections
      ##
      rsa_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
      rsa_private_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
      ##
      #Have to leave these as NO so that the web-ftp in ispconfig can access ftp folders
      ##
      force_local_data_ssl=NO
      force_local_logins_ssl=NO
      ssl_tlsv1=YES
      ssl_sslv2=YES
      ssl_sslv3=YES
      # Filezilla uses port 21 if you don't set any port
      # in Servertype "FTPES - FTP over explicit TLS/SSL"
      # Port 990 is the default used for FTPS protocol.
      # Uncomment it if you want/have to use port 990.
      ##
      #Since I can only use either 21 or 990 I will use port 21.
      #I used a port forward on my firewall to match port 990 --> port 21
      ##
      #listen_port=990
      ##
      #I didn't use pasv becuase I only want people to use SFTP or FTPS.
      #I only need FTP for the ISPConfig web interface which is on the local server.
      #I should set up a rule to only allow local listening for FTP unsecure.
      ##
      pasv_min_port=12000
      pasv_max_port=12100





      Comment

      Working...
      X