#!/bin/sh
#
# SliTaz Secure File Storage server side tool. Use virtual disk with a minimal
# chroot for more security and to protect server host.
#
# Copyright (C) SliTaz GNU/Linux - BSD License
# Author: Christophe Lincoln <pankso@slitaz.org>
#

app=$(basename $0)
[ -f "/etc/ssfs/$app.conf" ] && . /etc/ssfs/$app.conf
[ -f "./data/$app.conf" ] && . ./data/$app.conf
state=/var/lib/ssfs
share=/usr/share/ssfs

# Internationalization
. /usr/bin/gettext.sh
TEXTDOMAIN='ssfs'
export TEXTDOMAIN

# Be sure we're root.
[ $(id -u) != 0 ] && gettext "You must be root to run:" && \
	echo " $app" && exit 0

# Parse cmdline options.
for opt in $@
do
	case "$opt" in
		--login=*)
			login=${opt#--login=} ;;
		--id=*)
			id=${opt#--id=} ;;
		--pass=*)
			pass=${opt#--pass=} ;;
		--root=*)
			root=${opt#--root=} ;;
		--vdisk=*)
			vdisk=${opt#--vdisk=} ;;
		--size=*)
			size=${opt#--size=} ;;
		*)
			continue ;;
	esac
done

[ "$root" ] || root=${SSFS_CHROOT}
[ "$vdisk" ] || vdisk=${SSFS_VDISK}
[ "$size" ] || size=${SSFS_SIZE}

#
# Functions
#

# Built-in help usage.
help() {
	cat << EOT

$(echo -e "\033[1m$(gettext "Usage:")\033[0m") $app [command] [--option=]

$(echo -e "\033[1m$(gettext "Commands:")\033[0m")
  help          $(gettext "Display this short help usage.")
  users         $(gettext "List user accounts and stats.")
  adduser       $(gettext "Add a user to the system with \$HOME in chroot.")
  deluser       $(gettext "Delete a user and remove \$HOME files.")
  chroot        $(gettext "Chroot to Ssfs storage root.")
  gen-vdisk     $(gettext "Create a vdisk with chroot for files storage.")
  clean-vdisk   $(gettext "Clean the vdisk but skip home and root.")
  check-vdisk   $(gettext "Check the vdisk filesystem with e2fsck.")
  up-vdisk      $(gettext "Update a vdisk filesystem.")
  mount-vdisk   $(gettext "Mount a ssfs virtual disk.")
  umount-vdisk  $(gettext "Unmount the vdisk and free loop device.")
  note          $(gettext "Write a public note for users.")

$(echo -e "\033[1m$(gettext "Options:")\033[0m")
  --login=      $(gettext "Login name to add or del a user.")
  --id=         $(gettext "User id for adduser command.")
  --pass=       $(gettext "User password for adduser.")
  --root=       $(gettext "The path to the Ssfs vdisk chroot.")
  --vdisk=      $(gettext "Set the Ssfs vdisk path and name.")
  --size=       $(gettext "Set the ext3 vdisk size in Gb.")

EOT
}

status() {
	[ $? = 0 ] && echo " OK" 
	[ $? = 1 ] && echo -e " ERROR\n" && exit 1
}

separator() {
	echo "================================================================================"
}

# We have custom config when adding user to handle quota and user info.
user_paths() {
	config=$SSFS_USERS/$login.conf
	home=$root/./home/$login
}

user_info() {
	cat << EOT

$(gettext "User login :") $login
$(gettext "User quota :") $QUOTA
$(gettext "Home usage :") $usage

EOT
}

user_config() {
	gettext "Creating Ssfs user configuration file..."
	cat > $config << EOT
# Ssfs user configuration file.

LOGIN="$login"
QUOTA="$DEFAULT_QUOTA"
EOT
	chmod 0600 $config && status
	echo ""
}

vdisk_config() {
	cat > $root/etc/vdisk.conf << EOT
# /etc/vdisk.conf: Ssfs virtual disk auto-generated config file.

VDATE="$date"
VSIZE="$size"
FILES="$files"
EOT
}

# Handle Ssfs virtual disk.
umount_vdisk() {
	if mount | fgrep -q "$root "; then
		loop=$(mount | fgrep "$root " | awk '{print $1}')
		gettext "Unmounting Ssfs vdisk:"; echo " $vdisk"
		umount $root && sleep 1
		gettext "Detaching loop device:"; echo " $loop"
		losetup  -d $loop
	else
		gettext "Ssfs vdisk is not mounted:"; echo " $vdisk"
	fi
}

mount_vdisk() {
	if ! mount | fgrep -q "$root "; then
		[ -d "$root" ] || mkdir -p $root
		gettext "Mounting virtual disk:"
		mount -o loop -t ext3 $vdisk $root
	else
		gettext "Ssfs vdisk is already mounted:"
	fi
	echo " $vdisk $root"
}

#
# Commands
#

case "$1" in
	users)
		echo "" && gettext "Checking:"; echo " /etc/passwd"
		fgrep "Ssfs User" /etc/passwd | while read line
		do
			login=$(echo $line | cut -d ":" -f 1)
			home="$root/home/$login"
			usage=$(du -sm $home | awk '{print $1}')
			config=$SSFS_USERS/$login.conf
			. $config || gettext "WARNING: No config file"
			user_info
		done 
		users=$(ls $SSFS_USERS | wc -l)
		gettext "Users:"; echo -e " $users\n" ;;
	adduser)
		# Add a Ssfs user to the system with $HOME in chroot.
		[ -z "$login" ] && gettext "Missing user login name." && exit 0
		[ -z "$id" ] && gettext "Missing user id." && exit 0
		[ -z "$pass" ] && gettext "Missing user password." && exit 0
		user_paths

		# We need chroot command allowed for users to chroot them on SSH
		# login. Ssfs users have /bin/ssfs-sh as SHell.
		grep -q ^chroot /etc/busybox.conf ||
			echo 'chroot = ssx root.root' >> /etc/busybox.conf

		echo ""
		gettext "Checking:"; echo " /etc/passwd"
		if grep ^$login: /etc/passwd; then
			gettext "Exiting, user already exists:"
			echo -e " $login\n" && exit 0
		fi
		
		gettext "Creating user: $login..."
		echo -e "$pass\n$pass" | \
			adduser -h "$home" -g "Ssfs User" -u $id \
				-s /bin/ssfs-sh $login >/dev/null
		status

		# Add user to chroot /etc/passwd
		gettext "Checking vdisk chroot:"; echo " $root/etc/passwd"
		if ! grep -q ^$login: $root/etc/passwd; then
			echo "$login:x:$id:$id:Ssfs User:/home/$login:/bin/sh" >> \
				$root/etc/passwd
			echo "$login:x:$id:" >> $root/etc/group
		fi
		
		# We don't want any files from /etc/skel.
		gettext "Cleaning home and creating: Sync/..."
		rm -rf $home && mkdir -p $home/Sync $home/.ssh && status
		gettext "Changing mode on user home: 0700..."
		chown -R $login.$login $home
		chmod 0700 $home && status

		# Create a custom config per user in SSFS_USERS.
		[ ! -d "$SSFS_USERS" ] && mkdir -p $SSFS_USERS
		user_config ;;
	deluser)
		[ -z "$login" ] && gettext "Missing user login name." && exit 0
		user_paths
		echo ""
		gettext "Deleting user:"; echo -n " $login..."
		sed -i /^$login:/d $root/etc/passwd
		sed -i /^$login:/d $root/etc/group
		deluser $login || status && status
		gettext "Removing all files in:"; echo -n " $home..."
		rm -rf $home && status
		gettext "Removing user config:"; echo -n " $login.conf..."
		rm -rf $config && status
		echo "" ;;
	chroot)
		echo ""
		gettext "Changing root to:"; echo -e " $root\n"
		chroot $root
		echo ""
		gettext "Back to the host system:"
		echo -e " $(hostname)\n" ;;
	note)
		# Admin notes for users and displayed on the web interface.
		note="$2"
		date=$(date "+%Y-%m-%d %H:%M")
		if [ "$note" ]; then
			gettext "Adding note to:"; echo " $state/notes"
			echo "$date : $note" >> $state/notes
		fi ;;
	gen-vdisk)
		# Generate a virtual disk with a minimal chroot for Ssfs users home.
		rootfs=$share/rootfs
		if [ -d "$root/bin" ]; then
			gettext "A chroot already exists in:"; echo " $root"
			exit 0
		fi
		if [ ! -f "$rootfs/etc/busybox.conf" ]; then
			gettext "Missing package ssfs-busybox"; echo
			exit 0
		fi
		echo ""
		gettext "Creating Sshs vdisk minimal chroot"; echo
		separator
		echo "Chroot path: $root"
		
		# Create vdisk if missing.
		if [ ! -f "$vdisk" ]; then
			gettext "Creating virtual disk:"; echo " $vdisk ${size}Gb"
			dd if=/dev/zero of=$vdisk bs=1G count=$size
			chmod 0600 $vdisk && du -sh $vdisk
			gettext "Creating ext3 filesystem..."
			mkfs.ext3 -q -T ext3 -L "Ssfs" -F $vdisk
			status
			mount_vdisk
		fi

		# Create a radically minimal chroot with all libs in /lib.
		gettext "Creating base files..."
		mkdir -p $root && cd $root
		for d in etc lib home root
		do
			mkdir -p $d
		done && status

		# /etc files.
		cp -f /etc/slitaz-release $root/etc
		if [ ! -f "$root/etc/passwd" ]; then
			echo "root:x:0:0:root:/root:/bin/sh" > $root/etc/passwd
			echo "root:x:0:" > $root/etc/group
		fi
		
		# Ssfs Busybox package installs files in $share and allows easy vdisk
		# upgrade following SliTaz repo.
		gettext "Installing Ssfs root filesystem..."
		cp -a $rootfs/* $root
		status

		gettext "Setting files permissions..."
		chmod 0700 $root/root
		chmod 4755 $root/bin/busybox
		chmod 0600 $root/etc/busybox.conf
		status

		# Glib minimal libs, use host lib since package should be installed
		# from same repo. ? libnss_compat*
		gettext "Installing Glibc libraries..."
		for l in  ld-*.*so* libc-*.*so libc.so.* libnss_files* 
		do
			cp -a /lib/$l* $root/lib
		done && status
		
		# Ssfs chroot SHell and declare vdisk config.
		gettext "Installing Ssfs SHell..."
		install -m 0755 /bin/ssfs-sh $root/bin
		touch $root/etc/vdisk.conf
		status

		# List of all system files.
		gettext "Creating the list of files... "
		cd $root && rm -f $state/vdisk.files
		for d in bin etc lib
		do
			find ./$d | sed s'/^.//' >> $state/vdisk.files
		done
		files=$(cat $state/vdisk.files | wc -l)
		echo "$files"

		# Create chroot /etc/vdisk.conf
		size=$(du -sh $vdisk | awk '{print $1}')
		used=$(du -sh $root | awk '{print $1}')
		date=$(date '+%Y-%m-%d %H:%M')
		vdisk_config
		separator
		gettext "Vdisk used space:"; echo -e " $used - $date\n" ;;
	mount-vdisk)
		mount_vdisk ;;
	umount-vdisk)
		umount_vdisk ;;
	check-vdisk)
		# Check vdisk with e2fsck.
		echo ""
		gettext "Checking Ssfs virtual disk"; echo
		separator
		gettext "Virtual disk     : "; du -sh $vdisk
		gettext "Filesystem usage : "; du -sh $root
		gettext "Remounting vdisk read/only before e2fsck -p..."
		mount -o remount,loop,ro $vdisk $root && status
		e2fsck -p $vdisk
		gettext "Remounting vdisk read/write..."
		mount -o remount,loop,rw $vdisk $root && status
		separator && echo "" ;;
	up-vdisk)
		$0 clean-vdisk
		$0 gen-vdisk ;;
	clean-vdisk)
		# clean up the vdisk storage chroot.
		if [ ! -d "$root/bin" ] || [ ! -d "$root/lib" ]; then
			gettext "No chroot found in:"; echo " $root"
			exit 0
		fi
		echo ""
		gettext "Cleaning virtual disk\n"
		separator
		echo "Chroot path: $root"
		cd $root
		for dir in *
		do
			size=$(du -sh $dir | awk '{print $1}')
			case "$dir" in
				etc|home|root|lost*)
					gettext "Skipping:"; echo " $dir $size *" ;;
				*)
					gettext "Removing:"; echo " $dir $size"
					rm -rf $dir ;;
			esac
		done && separator && echo "" ;;
	*)
		help ;;
esac
exit 0
