Skip to content

Instantly share code, notes, and snippets.

@devthejo
Created March 27, 2018 11:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save devthejo/7d93d9c0785173b4b18fad56e8c935e3 to your computer and use it in GitHub Desktop.
Save devthejo/7d93d9c0785173b4b18fad56e8c935e3 to your computer and use it in GitHub Desktop.
vsftpd virtual user management with quota CLI
#!/bin/bash
VIRTUAL_USERS_DIR=${VIRTUAL_USERS_DIR:-/ftp_users}
DISKS_DIR=${DISKS_DIR:-/ftp_disks}
ROOT_DIR=${ROOT_DIR:-/ftp_mountpoints}
USER_QUOTA=${USER_QUOTA:-100MB}
DEFAULT_FTP_USER_ID=${DEFAULT_FTP_USER_ID:-14}
DEFAULT_FTP_GROUP_ID=${DEFAULT_FTP_GROUP_ID:-50}
CHMOD=${CHMOD:-0777}
OWN_USER=$(id -u ftp 2>/dev/null)
OWN_GROUP=$(id -g ftp 2>/dev/null)
OWN_USER=${OWN_USER:-$DEFAULT_FTP_USER_ID}
OWN_GROUP=${OWN_GROUP:-$DEFAULT_FTP_GROUP_ID}
VUSER_TXT="${VIRTUAL_USERS_DIR}/virtual_users.txt"
VUSER_DB="${VIRTUAL_USERS_DIR}/virtual_users.db"
function vsftpduser_add()
{
USER=$1
PASSWORD=$2
if [ "$USER" == "" ]; then
echo "error: missing user parameter"
exit 1
fi
if [ "$PASSWORD" == "" ]; then
echo "error: password can not be empty"
exit 1
fi
find_user $USER
if [ $? = 0 ]; then
echo "adding $USER to virtual users registry"
echo -e "${USER}\n${PASSWORD}" >> $VUSER_TXT
make_db
else
echo "user: $USER already exists in registry"
fi
make_user_disk $USER
make_user_dir $USER
mount_user_disk $USER
echo "new user $USER created"
}
function vsftpduser_del()
{
USER=$1
if [ "$USER" == "" ]; then
echo "error: missing user parameter"
exit 1
fi
find_user $USER
if [ $? = 1 ]
then
echo "removing $USER from virtual users registry"
sed -i '/\<'$USER'\>/{N;d}' $VUSER_TXT > /dev/null
make_db
else
echo "user: $USER does not exists in registry"
fi
remove_user_storage $USER
}
function vsftpduser_passwd()
{
USER=$1
PASSWORD=$2
if [ "$USER" == "" ]; then
echo "error: missing user parameter"
exit 1
fi
if [ "$PASSWORD" == "" ]; then
echo "error: password can not be empty"
exit 1
fi
find_user $USER
if [ $? = 1 ]; then
sed -i '/\<'$USER'\>/{n;d}' $VUSER_TXT > /dev/null
sed -i '/\<'$USER'\>/a\'$PASSWORD'' $VUSER_TXT > /dev/null
echo "password for user ${USER} has been modified"
make_db
else
echo "user: $USER does not exists in registry"
return 1
fi
}
function vsftpduser_ls()
{
echo $(sed -n '1~2p' $VUSER_TXT) | tr " " "\n"
}
function vsftpduser_rebuild()
{
FORCE="NO"
POSITIONAL=()
while [[ $# -gt 0 ]]
do
key="$1"
case $key in
-f|--force)
FORCE="YES"
shift
;;
*)
POSITIONAL+=("$1")
shift
;;
esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters
if [ "$1" == "" ]; then
rebuild_all $FORCE $@
else
USER=$1
shift
need_user $USER
rebuild_user $USER $FORCE $@
fi
}
function vsftpduser_mount()
{
if [ "$1" == "" ]; then
mount_all $@
else
USER=$1
shift
need_user $USER
mount_user_disk $USER
fi
}
function vsftpduser_umount()
{
if [ "$1" == "" ]; then
umount_all $@
else
USER=$1
shift
need_user $USER
umount_user_disk $USER
fi
}
function vsftpduser_remount()
{
vsftpduser_umount $@
vsftpduser_mount $@
}
function rebuild_user()
{
USER=$1
FORCE=$2
echo "rebuilding user $USER"
if [ "$FORCE" == "YES" ]; then
remove_user_storage $USER
fi
make_user_disk $USER
make_user_dir $USER
mount_user_disk $USER
}
function rebuild_all()
{
FORCE=$1
USER_LIST_ARRAY=($(sed -n '1~2p' $VUSER_TXT))
for USER in "${USER_LIST_ARRAY[@]}" ; do
rebuild_user $USER $FORCE
done
}
function mount_all()
{
USER_LIST_ARRAY=($(sed -n '1~2p' $VUSER_TXT))
for USER in "${USER_LIST_ARRAY[@]}" ; do
mount_user_disk $USER
done
}
function umount_all()
{
USER_LIST_ARRAY=($(sed -n '1~2p' $VUSER_TXT))
for USER in "${USER_LIST_ARRAY[@]}" ; do
umount_user_disk $USER
done
}
function need_user(){
USER=$1
find_user $USER
if [ $? = 0 ]; then
echo "user: $USER does not exists in registry"
exit 1
fi
}
function find_user()
{
if [ -f $VUSER_TXT ];then
ACCOUNTDB_TOTALLINES=`grep '.' -c $VUSER_TXT`
else
ACCOUNTDB_TOTALLINES=0
fi
C=1;
if [ "$ACCOUNTDB_TOTALLINES" != "0" ]; then
while [ $C -lt $ACCOUNTDB_TOTALLINES ]; do
VALIDUSER=`sed -n -e "$C p" $VUSER_TXT`
if [ "$1" == "$VALIDUSER" ];then
USERNAMEOK=1
break;
else
USERNAMEOK=0
fi
let C=$C+2;
done
fi
return $USERNAMEOK
}
function make_db()
{
db_load -T -t hash -f $VUSER_TXT $VUSER_DB
}
function make_user_disk()
{
USER=$1
USER_DISK="${DISKS_DIR}/${USER}.ext3"
if [ ! -f "$USER_DISK" ]
then
echo "creating ${USER_DISK}"
touch "${USER_DISK}"
dd if=/dev/zero of="${USER_DISK}" bs="${USER_QUOTA}" count=1
/sbin/mkfs --type=ext3 -F "${USER_DISK}"
else
echo "disk allready exists ${USER_DISK}"
fi
}
function make_user_dir()
{
USER_DIR="$ROOT_DIR/$1"
if [ ! -d "$USER_DIR" ]
then
echo "creating ${USER_DIR}"
mkdir -p "${USER_DIR}"
chown $OWN_USER:$OWN_GROUP "${USER_DIR}"
chmod $CHMOD "${USER_DIR}"
else
echo "directory already exists ${USER_DIR}"
fi
}
function mount_user_disk()
{
USER=$1
USER_DISK="${DISKS_DIR}/${USER}.ext3"
USER_DIR="$ROOT_DIR/$1"
if mount | grep $USER_DIR > /dev/null; then
echo "mountpoint allready mounted ${USER_DIR}"
elif [ ! -f "$USER_DISK" ]; then
echo "missing disk file ${USER_DISK} for user ${USER}"
else
echo "mounting ${USER_DISK} in ${USER_DIR}"
mount -o loop,rw "${USER_DISK}" "${USER_DIR}"
chmod $CHMOD "${USER_DIR}"
if [ -d "${USER_DIR}/lost+found" ]; then
if [ -z "$(ls -A ${USER_DIR}/lost+found)" ]; then
rm -r "${USER_DIR}/lost+found"
fi
fi
fi
}
function remove_user_storage()
{
USER=$1
USER_DIR="${ROOT_DIR}/${USER}"
USER_DISK="${DISKS_DIR}/${USER}.ext3"
umount_user_disk $USER
if [ -d "$USER_DIR" ]; then
echo "removing $USER_DIR"
rm -r "$USER_DIR"
fi
if [ -f "$USER_DISK" ]; then
echo "removing $USER_DISK"
unlink "$USER_DISK"
fi
}
function umount_user_disk(){
USER=$1
USER_DIR="${ROOT_DIR}/${USER}"
if mount | grep $USER_DIR > /dev/null; then
echo "unmounting $USER_DIR"
umount "$USER_DIR"
fi
}
function main()
{
if [ $# -lt 1 ];
then
echo "usage: vsftpduser add | del | passwd | ls | rebuild | mount | umount | remount"
exit 1
fi
CMD=$1
shift
if [ $CMD = "add" ]; then
vsftpduser_add $@
elif [ $CMD = "del" ]; then
vsftpduser_del $@
elif [ $CMD = "passwd" ]; then
vsftpduser_passwd $@
elif [ $CMD = "ls" ]; then
vsftpduser_ls $@
elif [ $CMD = "rebuild" ]; then
vsftpduser_rebuild $@
elif [ $CMD = "mount" ]; then
vsftpduser_mount $@
elif [ $CMD = "umount" ]; then
vsftpduser_umount $@
elif [ $CMD = "remount" ]; then
vsftpduser_remount $@
else
echo [$CMD] a bad argument.
fi
}
main $@
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment