#!/bin/sh

set -e

# reset flags
apache_reload_needed=""
runmode="normal"

# subfolder name defaults (edit /etc/local/users.conf to override)
mac="mac" # Optimized for sharing through AppleShare (netatalk)
pc="pc" # Optimized for sharing though SMB/CIFS (Samba)
xchange="xchange" # Readable by group

# config (edit /etc/local/users.conf to override) 

# which are user accounts (adduser values are used if empty) 
first_uid=""
last_uid=""     

do_quota="no"    # Manage disk quota 
do_distrib="no"  # Distributed shares (software archive) 
do_personal="no" # Personal shares (mac, pc, public_html) 
do_xchange="no"  # Group-readable shares 
do_public="no"   # Public share (web homepage) 
do_mac="no"      # AppleShare-optimized share (netatalk) 
do_pc="no"       # SMB-ptimized share (Samba) 
do_server="no"   # Personal share on remote SMB server 

quota_roots="" # space-delimited list of disk devices 
quota_soft="100000"
quota_hard="1000000"
quota_newstyle="yes" # Woody used a different syntax... 
                
xchange_root="xchange"
xchange_sharedroot="/home/XCHANGE"
        
mac_root="mac"

pc_root="pc"

server_name="SERVER" # SMB name of remote server
server_desc="remote server"
server_root="server"
server_conf="/etc/security/pam_mount.conf"
server_userconf=".winpassword"

### No servicable parts below this line! ### 

if [ -e /etc/adduser.conf ]; then
	. /etc/adduser.conf
else
	echo "/etc/adduser.conf missing. Exiting..."
	exit 1
fi

[ -r /etc/local/users.conf ] && . /etc/local/users.conf

#TODO: Add conversion like below, and change remaining script to new variable names
#[ -n "$XDIR" ] && xchange_sharedroot="$XDIR"

# exit silently if this system lacks required hints
[ -r /etc/local/volumes ] && . /etc/local/volumes || exit 0

XDIRREAL="$XDIR/users/root"

if [ -n "$XCHANGE" ]; then
	if [ ! -d "$XDIR" ]; then
		echo "XDIR doesn't exist. Ignoring XCHANGE!"
		XCHANGE=""
	fi
fi

if [ $# -gt 0 ]; then
	USERS=$*
else
#	USERS=`getent passwd | awk -F: '{print $1}'`
	echo "uid required!"
	exit 1
fi

[ -n "$NETATALK_HOME" ] && mac="$NETATALK_HOME"
[ -n "$SAMBA_HOME" ] && pc="$SAMBA_HOME"
[ -n "$XCHANGE_HOME" ] && xchange="$XCHANGE_HOME"

echo "Setting up additional folders and permissions..."
for user in $USERS; do
	uid="`getent passwd \"$user\" | awk -F: '{print $3}' | head -1`"
	HOME="`getent passwd \"$user\" | awk -F: '{print $6}' | head -1`"
	if [ -z "$HOME" ]; then
		echo "User $user doesn't exist. Ignoring..."
		continue
	fi

	# Ignore non-human accounts silently
	[ "$uid" -ge "$FIRST_UID" -a "$uid" -le "$LAST_UID" ] || continue

	[ -d "$HOME" ] || continue
#	[ -L "$HOME" ] && continue

	echo -n "$user"

#	if [ -x /etc/local/quota.sh ]; then
#		/etc/local/quota.sh "$user"
#		fi
	[ -n "$QUOTASOFT" ] || QUOTASOFT="0"
	[ -n "$QUOTAHARD" ] || QUOTAHARD="0"
	for QUOTAHOME in $QUOTAHOMES; do
		if [ -n "$NEW_QUOTA" ]; then
			setquota "$user" "$QUOTASOFT" "$QUOTAHARD" 0 0 "$QUOTAHOME"
		else
			setquota "$user" "$QUOTAHOME" "$QUOTASOFT" "$QUOTAHARD" 0 0
		fi
	done

	if [ -n "$NETATALK" ]; then
		mkdir -p "$HOME/$mac"
	fi
	if [ -n "$SAMBA" ]; then
		mkdir -p "$HOME/$pc"
	fi

	if [ -n "$XCHANGE" ]; then
		mkdir -p "$XDIRREAL/$user"
	fi

	if [ -n "$PUBLIC" ]; then
		mkdir -p "$HOME/public_html"
	fi

#TODO: Enable this only when option implemented to do it non-interactively
#	echo # dirty hack: better if being able to lower verbosity of localuserconfig
#	su -s /bin/bash -c localuserconfig "$user"

	if [ "$do_server" = "yes" ] && [ -r "$server_conf" ] && [ -f "$HOME/$server_userconf" ]; then
		server_username="$(grep '^username' \"$HOME/$server_userconf\" | awk -F= '{print $2}' | head -1 | awk '{print $1}')"
		if [ -n "$server_username" ]; then
			if grep -q "^volume $user " "$server_conf"; then
				perl -pi -e "s|^volume $user .*|volume $user smb $server_name $server_username $HOME/$server_root uid=$user,gid=$user - -|" "$server_conf"
			else
				echo "volume $user smb $server_name $server_username $HOME/$server_root uid=$user,gid=$user - -" >> "$server_conf"
			fi
		fi
	fi

	chown "$user": "$HOME"
	chmod u=rwX,go=rX "$HOME"

	# Mail handling
	if [ -n "$MAILDIR" ]; then
		if [ ! -e "$HOME/.procmailrc" ]; then
			echo 'DEFAULT=$HOME/Maildir/' > "$HOME/.procmailrc"
		fi
		mkdir -p "$HOME/Maildir/cur" "$HOME/Maildir/new" "$HOME/Maildir/tmp"
		chown -R "$user": "$HOME/Maildir"
		chmod -R u=rw,go=,u+X "$HOME/Maildir"
		if [ -f "/var/mail/$user" ] && [ ! -s "/var/mail/$user" ]; then
			rm -f "/var/mail/$user"
		elif [ -f "/var/spool/mail/$user" ] && [ ! -s "/var/spool/mail/$user" ]; then
			rm -f "/var/spool/mail/$user"
		fi
	else
		mkdir -p "$HOME/mail"
		if [ -n "$USE_MBOX" ]; then
			touch "$HOME/mail/mbox"
		elif [ -f "$HOME/mail/mbox" ] && [ ! -s "$HOME/mail/mbox" ]; then
			rm -f "$HOME/mail/mbox"
		fi
		chown -R "$user": "$HOME/mail"
		chmod -R u=rw,go=,u+X "$HOME/mail"
		if [ -f "$HOME/.mailboxlist" ]; then
			chown "$user": "$HOME/.mailboxlist"
			chmod 0640 "$HOME/.mailboxlist"
		fi
	fi
	if [ -f "/var/mail/$user" ]; then
		chown "$user":mail "/var/mail/$user"
		chmod ug=rw,o= "/var/mail/$user"
	elif [ -f "/var/spool/mail/$user" ]; then
		chown "$user":mail "/var/spool/mail/$user"
		chmod ug=rw,o= "/var/spool/mail/$user"
	fi
	if [ -f "$HOME/.forward" ]; then
		chown "$user": "$HOME/.forward"
		chmod 0640 "$HOME/.forward"
	fi
	if [ -f "$HOME/.procmailrc" ]; then
		chown "$user": "$HOME/.procmailrc"
		chmod 0640 "$HOME/.procmailrc"
	fi

	# MySQL handling
	if [ -f "$HOME/.my.cnf" ]; then
		chown "$user": "$HOME/.my.cnf"
		chmod 0600 "$HOME/.my.cnf"
	fi

	# Mac dir permissions
	if [ -d "$HOME/$mac" ]; then
		chown -R "$user": "$HOME/$mac"
		chmod -R u=rw,g=r,o=,ug+X "$HOME/$mac"
		rm -rf "$HOME/$mac/Network Trash Folder"
		mkdir "$HOME/$mac/Network Trash Folder"
		chown nobody: "$HOME/$mac/Network Trash Folder"
		chmod a= "$HOME/$mac/Network Trash Folder"
	fi

	# PC dir permissions
	if [ -d "$HOME/$pc" ]; then
		chown -R "$user": "$HOME/$pc"
		chmod -R u=rw,g=r,o=,ug+X "$HOME/$pc"
	fi

#FIXME: something is wrong with prefixing "x" here...
	# Exchange dir permissions
	if [ -d "$XDIRREAL/$user" ]; then
		chown -R "$user":users "$XDIRREAL/$user"
		chmod -R g=r,g+X "$XDIRREAL/$user"
		if [ -e "x$HOME/$xchange" ]; then
			if [ -L "x$HOME/$xchange" ]; then
				ln -sf "$XDIRREAL/$user $HOME/$xchange"
			else
				echo "ERROR: \"$HOME/$xchange\" exists already. Leaving it as is..."
			fi
		else
			ln -s "$XDIRREAL/$user" "$HOME/$xchange"
		fi
	fi

	# Public dir permissions
	for dir in `cd "$HOME" && find . -mindepth 1 -maxdepth 1 -type d -regex '^\./public\(_.*\)?'`; do
		chown -R "$user": "$HOME/$dir"
		chmod -R u+rX,go=r,go+X "$HOME/$dir"
		if [ -n "$NETATALK" ]; then
			rm -rf "$HOME/$dir/Network Trash Folder"
			mkdir "$HOME/$dir/Network Trash Folder"
			chown nobody: "$HOME/$dir/Network Trash Folder"
			chmod a= "$HOME/$dir/Network Trash Folder"
		fi
	done

	# Shared dirs are writable by own primary group
	for dir in `cd "$HOME" && find . -mindepth 1 -maxdepth 1 -type d -regex '^\./shared\(_.*\)?'`; do
		chgrp -R "$user" "$HOME/$dir"
		chmod -R ug=rw,o=,ug+X,g+s "$HOME/$dir"
		if [ -n "$NETATALK" ]; then
			rm -rf "$HOME/$dir/Network Trash Folder"
			mkdir "$HOME/$dir/Network Trash Folder"
			chown nobody: "$HOME/$dir/Network Trash Folder"
			chmod a= "$HOME/$dir/Network Trash Folder"
		fi
	done

	# Private dirs are readable by own primary group
	for dir in `cd "$HOME" && find . -mindepth 1 -maxdepth 1 -type d -regex '^\./private\(_.*\)?$'`; do
		chown -R "$user": "$HOME/$dir"
		chmod -R u+rX,g=r,g+X,o= "$HOME/$dir"
	done

	# Secret dirs are accessible only by self
	for dir in `cd "$HOME" && find . -mindepth 1 -maxdepth 1 -type d -regex '^\./secret\(_.*\)?$'`; do
		chown -R "$user": "$HOME/$dir"
		chmod -R u+rX,go= "$HOME/$dir"
	done

	# Fileshares: <home>/shares.<sharetype>/<rogroup>/<rwgroup>/<sharename>
	#   <sharetype>: Either mac or win depending on which of netatalk and samba provides r/w access to the shares
	#   <rwgroup>:   Group with write access to the share (usually the default group of the owner)
	#   <rogroup>:   Either rwgroup or secondary group with read-only access to the share
	#   owner and rwgroup members must be member of both groups
	#FIXME: Use the below instead, and replace occurrences of "$thisdir" with "$HOME/$dir".
	#for dir in `cd "$HOME" && find . -mindepth 1 -maxdepth 1 -type d -regex '^\./shares\..*'`; do
	find "$HOME" -mindepth 1 -maxdepth 1 -type d -print | egrep "^$HOME/shares\." | (while read thisdir; do
		sharetype="`basename \"$thisdir\" | awk -F. '{print $2}'`"
		# Define dir and file exceptions
		case "$sharetype" in
		    mac)
			dirs_world_rw_create='.AppleDB'
			dirs_group_rw_create='.AppleDesktop/Temporary Items/TheFindByContentFolder'
			dirs_group_ro_create='TheVolumeSettingsFolder'
			dirs_group_ro_update='.AppleDouble'
			files_group_ro_update=':2eDS_Store'
			dirs_no_access_purge='Network Trash Folder'
			;;
		    win)
			;;
		    *)
			continue
			;;
		esac
		exceptions="$dirs_world_rw_create/$dirs_group_rw_create/$dirs_group_ro_create/$dirs_group_ro_update/$files_group_ro_update/$dirs_no_access_purge"
		exception_dirs_create="$dirs_world_rw_create/$dirs_group_rw_create/$dirs_group_ro_create"
		chown "$user": "$thisdir"
		chmod a=rX "$thisdir"
		find "$thisdir" -mindepth 1 -maxdepth 1 -type d -print | (while read thisdir; do
			rogroup="`basename \"$thisdir\"`"
			chown "$user":"$rogroup" "$thisdir"
			chmod ug=rX,o= "$thisdir"
			find "$thisdir" -mindepth 1 -maxdepth 1 -type d -print | (while read thisdir; do
				rwgroup="`basename \"$thisdir\"`"
				chown "$user":"$rwgroup" "$thisdir"
				chmod a=rX,g+s "$thisdir"
				find "$thisdir" -mindepth 1 -maxdepth 1 -type d -print | (while read thisdir; do
					sharename="`basename \"$thisdir\"`"
					chown "$user":"$rwgroup" "$thisdir"
					chmod u=rw,go=r,a+X,g+s "$thisdir"
					ifs="$IFS"
					# Set default permissions
					find "$thisdir" -mindepth 1 -maxdepth 1 -print | (while read thisdir; do
						item="`basename \"$thisdir\"`"
						IFS="/"; for exception in $exceptions; do IFS="$ifs";
							if [ "$item" = "$exception" ]; then
								continue 2
							fi
						done
						chgrp -R "$rwgroup" "$thisdir"
						chmod -R ug=rw,o=r,a+X,g+s "$thisdir"
					done)
					# Handle exception dirs to be created if not existing
					IFS="/"; for dir in $exception_dirs_create; do IFS="$ifs";
						if [ ! -d "$thisdir/$dir" ]; then
							rm -f "$thisdir/$dir"
						fi
						if [ ! -e "$thisdir/$dir" ]; then
							mkdir "$thisdir/$dir"
						fi
						chown "$user":"$rwgroup" "$thisdir/$dir"
					done
					IFS="/"; for dir in $dirs_world_rw_create; do IFS="$ifs";
						if [ "$rogroup" = "$rwgroup" ]; then
							chmod -R ug=rw,o=r,a+X,g+s "$thisdir/$dir"
						else
							chmod -R a=rw,a+X,g+s "$thisdir/$dir"
						fi
					done
					IFS="/"; for dir in $dirs_group_rw_create; do IFS="$ifs";
						chmod -R ug=rw,o=r,a+X,g+s "$thisdir/$dir"
					done
					IFS="/"; for dir in $dirs_group_ro_create; do IFS="$ifs";
						chmod -R u=rw,go=r,a+X,g+s "$thisdir/$dir"
					done
					# Handle exception dirs to be updated if already there
					IFS="/"; for dir in $dirs_group_ro_update; do IFS="$ifs";
						if [ -e "$thisdir/$dir" ]; then
							chmod u=rw,go=r,a+X,g+s "$thisdir/$dir"
						fi
					done
					# Handle exception files to be updated if already there
					IFS="/"; for file in $files_group_ro_update; do IFS="$ifs";
						if [ -e "$thisdir/$file" ]; then
							chmod u=rw,go=r,g+s "$thisdir/$file"
						fi
					done
					# Handle exception dirs to be purged and recreated
					IFS="/"; for dir in $dirs_no_access_purge; do IFS="$ifs";
						rm -rf "$thisdir/$dir"
						mkdir -m a= "$thisdir/$dir"
						chown nobody: "$thisdir/$dir"
					done
					IFS="$ifs"
				done)
			done)
		done)
	done)

	# Ftp shares permissions
	for dir in `cd "$HOME" && find . -mindepth 1 -maxdepth 1 -type d -regex "^\./ftp_$user$"`; do
		chgrp -R "$user" "$HOME/$dir"
		chmod -R ug=rw,o=r,a+X,g+s "$HOME/$dir"
		rm -rf "$HOME/$dir/Network Trash Folder"
		mkdir "$HOME/$dir/Network Trash Folder"
		chown nobody: "$HOME/$dir/Network Trash Folder"
		chmod a= "$HOME/$dir/Network Trash Folder"
	done
	for dir in `cd "$HOME" && find . -mindepth 1 -maxdepth 1 -type d -regex "^\./ftp_${user}_ro$"`; do
		chown -R "$user": "$HOME/$dir"
		chmod -R u=rw,go=r,a+X "$HOME/$dir"
		rm -rf "$HOME/$dir/Network Trash Folder"
		mkdir "$HOME/$dir/Network Trash Folder"
		chown nobody: "$HOME/$dir/Network Trash Folder"
		chmod a= "$HOME/$dir/Network Trash Folder"
	done

	# Web shares permissions
	for dir in `cd "$HOME" && find . -mindepth 1 -maxdepth 1 -type d -regex '^\./web_.*'`; do
		chown -R "$user": "$HOME/$dir"
#		chmod -R u=rw,go=r,a+X $webdir
#TODO: Only cgi scripts (.cgi and .pl) should be executable
		chmod -R u+rw,go+r,a+X "$HOME/$dir"
		# leftover from ancient times with another policy
		if [ $NETATALK ]; then
			rm -rf "$HOME/$dir/Network Trash Folder"
		fi
	done
	
	# Web shares permissions
	for dir in `cd "$HOME" && find . -mindepth 1 -maxdepth 1 -type d -regex '^\./websites$'`; do
		chown root: "$HOME/$dir"
		chmod a=r,u+w,a+X "$HOME/$dir"
	done
	for dir in `cd "$HOME" && find . -mindepth 2 -maxdepth 2 -type d -regex '^\./websites/.*'`; do
		chown -R "$user": "$HOME/$dir"
#		chmod -R u=rw,go=r,a+X $webdir
#TODO: Only cgi scripts (.cgi and .pl) should be executable
		chmod -R u+rw,go+r,a+X "$HOME/$dir"
		# leftover from ancient times with another policy
		if [ $NETATALK ]; then
			rm -rf "$HOME/$dir/Network Trash Folder"
		fi
	done
	for dir in `cd "$HOME" && find . -mindepth 1 -maxdepth 1 -type d -regex '^\./webscripts$'`; do
		chown root: "$HOME/$dir"
		chmod a=r,u+w,a+X "$HOME/$dir"
	done
	for dir in `cd "$HOME" && find . -mindepth 2 -maxdepth 2 -type d -regex '^\./webscripts/.*'`; do
		chown -R $user: "$HOME/$dir"
#		chmod -R u=rw,go=r,a+X $webdir
#TODO: Only cgi scripts (.cgi and .pl) should be executable
		chmod -R u+rw,go+r,a+X "$HOME/$dir"
	done
	for dir in `cd "$HOME" && find . -mindepth 1 -maxdepth 1 -type d -regex '^\./webdata$'`; do
		chown "$user": "$HOME/$dir"
		chmod a=r,u+w,a+X "$HOME/$dir"
	done
	for dir in `cd "$HOME" && find . -mindepth 2 -maxdepth 2 -type d -regex '^\./webdata/.*'`; do
		chown -R "$user": "$HOME/$dir"
		chmod -R u=rw,go=,u+X "$HOME/$dir"
	done
	for dir in `cd "$HOME" && find . -mindepth 1 -maxdepth 1 -type d -regex '^\./webshareddata$'`; do
		chown "$user": "$HOME/$dir"
		chmod a=r,u+w,a+X "$HOME/$dir"
	done
	for dir in `cd "$HOME" && find . -mindepth 2 -maxdepth 2 -type d -regex '^\./webshareddata/.*'`; do
		chown -R "$user:" "$HOME/$dir"
		chmod -R u=rw,go=r,a+X "$HOME/$dir"
	done
	for dir in `cd "$HOME" && find . -mindepth 1 -maxdepth 1 -type d -regex '^\./webphpsites$'`; do
		chown root: "$HOME/$dir"
		chmod u=rw,go=r,a+X "$HOME/$dir"
	done
	for dir in `cd "$HOME" && find . -mindepth 2 -maxdepth 2 -type d -regex '^\./webphpsites/.*'`; do
		chown -R "$user":www-data "$HOME/$dir"
#		chmod -R ug=rw,o=r,a+X $dir
		chmod -R ug=rw,o=,ug+X "$HOME/$dir"
	done
	for dir in `cd "$HOME" && find . -mindepth 1 -maxdepth 1 -type d -regex '^\./webphpdata$'`; do
		chown root: "$HOME/$dir"
		chmod a=r,u+w,a+X "$HOME/$dir"
	done
	for dir in `cd "$HOME" && find . -mindepth 2 -maxdepth 2 -type d -regex '^\./webphpdata/.*'`; do
		chown -R "$user":www-data "$HOME/$dir"
		chmod -R ug=rw,o=,ug+X "$HOME/$dir"
	done
	for dir in `cd "$HOME" && find . -mindepth 1 -maxdepth 1 -type d -regex '^\./weblogs$'`; do
		chown -R "$user": "$HOME/$dir"
		chmod -R u=rw,g=r,o=,ug+X "$HOME/$dir"
	done
	
	# Dummy user restrictions
	if [ -n "$REALUSERS_GROUPNAME" -a -n "$DUMMYSHAREDIR" -a -n "$DUMMYSHAREOWNER" -a -n "$DUMMYSHARENAME" ]; then
		[ -e $DUMMYSHAREDIR/$user ] \
			|| mkdir $DUMMYSHAREDIR/$user
		chown $DUMMYSHAREOWNER: $DUMMYSHAREDIR/$user
		chmod u=rw,go=r,a+X $DUMMYSHAREDIR/$user
		if [ -e $HOME/$DUMMYSHARENAME ]; then
			if [ -L $HOME/$DUMMYSHARENAME ]; then
				ln -sf $DUMMYSHAREDIR/$user $HOME/$DUMMYSHARENAME
				chown $user: $HOME/$DUMMYSHARENAME
			else
				echo "WARNING: $HOME/$DUMMYSHAREDIR exists already. Leaving it as is..."
			fi
		else
			ln -s $DUMMYSHAREDIR/$user $HOME/$DUMMYSHARENAME
			chown $user: $HOME/$DUMMYSHARENAME
		fi
		if [ -n "$DUMMYAPACHECFG" -a -n "$DUMMYAPACHESHAREDIR" ]; then
			if [ -f /etc/apache/include.d/$DUMMYAPACHECFG -a -x /etc/init.d/apache ]; then
				if [ -e /etc/apache/include.d/$DUMMYAPACHECFG-$user ]; then
					echo "/etc/apache/include.d/$DUMMYAPACHECFG-$user exists already. Ignoring..."
				else
					echo "# Created automatically by adduser.local
<Location /$DUMMYAPACHESHAREDIR/$user>
	<Limit GET POST>
		require user $user
	</Limit>
</Location>" \
						> /etc/apache/include.d/$DUMMYAPACHECFG-$user
					apache_reload_needed="1"
				fi
			fi
		fi
	fi

	echo "."
done

if [ $XCHANGE ]; then
	for USER in $(ls $XDIRREAL); do
		id $user >/dev/null 2>&1 || rm -rf $XDIRREAL/$user
	done
fi

if [ "$apache_reload_needed" ]; then
	apache_do_reload=""
	case runmode in
	    interactive)
		echo -n "Apache config changed. Reload Apache now (Y/n)? "
		read apache_reload
		case $apache_reload in
		    y|Y|"")
			apache_do_reload="1"
			;;
		esac
		;;
	    force)
		apache_do_reload="1"
		;;
	    *)
		echo "Apache config has changed. Remember to reload Apache...!"
		;;
	esac
	if "$apache_do_reload" ]; then
		/etc/init.d/apache force-reload
	fi
fi