#!/bin/bash
# (c) 2010 Websense, Inc. All Rights Reserved. Confidential.

#Samba WCG admin script...
#	... install package, configs paths, domain membership mgmt, kerb init, chroot instance mgmt, mount and fstab mgmt
#** This script is *not* intended to be called for per HTTP transaction authentication tasks.
#** In many cases this script will chroot itself to do tasks in the chroot context.
#   The root filesystem of the chroot has a hard link to this script for in-chroot execution.
#** All invocations of this script (arguments and output) will be logged to smbadmin.log automatically.
#-chartmann


#env var --or-- on single shell line like ... [bash]# SMBDEBUG=1 ./SMBAdmin join etc...
if [ $SMBDEBUG ] ; then
	set -x 
fi

if [ `id -u` -ne 0 ]; then
	echo "ERROR: $0 MUST BE RUN AS ROOT. YOU ARE uid:`id -u`" >&2
fi

for FD in `ls /proc/$$/fd`; do
	# Close all file descriptors that are not STDIN/STDOUT/STDERR

	if [ $FD -lt 3 -o $FD -eq 255 -o ! -e /proc/$$/fd/$FD ]
	then
		continue
	fi

	eval "exec $FD<&-" #close

done

WD=`pwd`
TARNAME='samba482wcg.tar.gz'
PREFIX=${PREFIX:-/opt/WCG/contrib/samba} #can be set from environment
JAILDIR=$PREFIX/jails
TESTDIR=$PREFIX/expert_tests
DALOG=${DALOG:-/opt/WCG/logs/smbadmin.log} #can be set from enviornment -else- use default
PASSEDARGS="$@"
THECMD=$1

KERNELARCH="32" #default
if [ "`uname -m | grep x86_64`" != "" ] ; then
  KERNELARCH="64"
fi

#Check whether the root of the 'init' process (pid 1) is the same as the root of
#the current process. If they are not the same, we are in a chroot, returning 0 (TRUE).
function isChrooted()
{
	if [ "$(stat -c %d:%i /)" != "$(stat -c %d:%i /proc/1/root/.)" ]; then
		#return TRUE
		return 0
	else
		#return FALSE, not in a chroot
		return 1
	fi
}

#redirect script output to the passed log file path $1
#tee everything to log and console if interactive
function start_log()
{
	#dont log the chrooted script invocations. avoids double logging 
        if isChrooted ; then return; fi

	if [ "$1" ]; then DALOG=$1; fi

	#each time this script is run create a new dated "record"
	echo -e "--------" >> $DALOG
	date >> $DALOG
	echo "($$:`id -u`) $0 $PASSEDARGS" >> $DALOG

	#the magic
	exec &> >(tee -a $DALOG) 
}


#start logging all script output to DALOG
#do_join calls start log on it's own so it can log to a diff log
start_log

#always use this as base
cd $PREFIX

#make sure PATH is set for samba and kerb binaries
if [ -x /etc/profile.d/samba.wcg.sh ] ; then
	. /etc/profile.d/samba.wcg.sh
fi

LD_LIBRARY_PATH=$PREFIX/lib

export LD_LIBRARY_PATH
export PATH

SMB_CONF='
[global]
kerberos method = system keytab
workgroup = ${REALM}
security = ads
passdb backend = tdbsam
realm = ${DOMFQDN}
password server = ${DCLIST}
log level = 2
debug pid = yes
winbind use default domain = yes
winbind max domain connections = 10
client ntlmv2 auth = yes
client ldap sasl wrapping = sign
winbind max clients = 3000
client min protocol = SMB2
server min protocol = SMB2
'

#krb5.conf used when not using DNS SRV records to auto locate kdc
KRB_CONF_DEFAULT='
[logging]
default = FILE:$PREFIX/var/krb5libs.log
kdc = FILE:$PREFIX/var/krb5kdc.log
admin_server = FILE:$PREFIX/var/kadmind.log

[libdefaults]
default_realm = ${DOMFQDN_upper}
dns_lookup_realm = false
dns_lookup_kdc = false
ticket_lifetime = 24h
forwardable = yes

[realms]
${DOMFQDN_upper} = {
 kdc = [${DCLIST}]:88
}

[domain_realm]
.${DOMFQDN} = ${DOMFQDN_upper}
${DOMFQDN} = ${DOMFQDN_upper}
'

#krb5.conf used with auto kdc discovery enabled via DNS SRV records
KRB_CONF_AUTO='
[logging]
default = FILE:$PREFIX/var/krb5libs.log
kdc = FILE:$PREFIX/var/krb5kdc.log
admin_server = FILE:$PREFIX/var/kadmind.log

[libdefaults]
default_realm = ${DOMFQDN_upper}
dns_lookup_realm = true
dns_lookup_kdc = true
ticket_lifetime = 24h
forwardable = yes

[realms]
${DOMFQDN_upper} = {
}

[domain_realm]
.${DOMFQDN} = ${DOMFQDN_upper}
${DOMFQDN} = ${DOMFQDN_upper}
'


# /etc/profile.d/samba.wcg.sh
PATH_PROFILE='#generated by '$0'
if ! echo ${PATH} | /bin/grep -q '$PREFIX'/bin ; then
        PATH='$PREFIX'/bin:${PATH}
fi
if ! echo ${PATH} | /bin/grep -q '$PREFIX'/sbin ; then
        if [ `/usr/bin/id -u` = 0 ] ; then
                PATH='$PREFIX'/sbin:${PATH}
        fi
fi
if ! echo ${PATH} | /bin/grep -q /usr/kerberos/bin ; then
        PATH=/usr/kerberos/bin:${PATH}
fi
if ! echo ${PATH} | /bin/grep -q /usr/kerberos/sbin ; then
        if [ `/usr/bin/id -u` = 0 ] ; then
                PATH=/usr/kerberos/sbin:${PATH}
        fi
fi

if ! echo ${PATH} | /bin/grep -q /usr/sbin ; then
        if [ `/usr/bin/id -u` = 0 ] ; then
                PATH=/usr/sbin:${PATH}
        fi
fi

'

function die()
{
	echo "ERROR: $1" >&2
	exit 2
}

function toUpper() 
{
	echo $1 | tr "[:lower:]" "[:upper:]" 
}

function isIPv4()
{
        local IP=$1

        if [[ "$IP" =~ ^[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}$ ]]; then
                #TRUE
                return 0
        else
                #FALSE
                return 1
        fi
}

function isIPv6()
{
        local IP=$1

        if [[ "$IP" =~ ^::$ ]]; then
                #FALSE - :: is not a client IPv6 address
                return 1
        fi

        local list=`echo "$IP" | sed 's/:/ /g'`

        for item in $list
        do
                if [[ ! "$item" =~ ^[0-9a-fA-F]{1,4}$ ]]; then
                        #FALSE - not a valid IPv6 address
                        return 1
                fi
        done

        #TRUE
        return 0
}

#is arg an IP address (vs hostname)
function isIP()
{
        if isIPv4 $1; then
                # TRUE - is an IPv4 address
                return 0
        fi

        if isIPv6 $1 ; then
                # TRUE - is an IPv6 address
                return 0
        fi

        #FALSE
        return 1
}

function do_clean()
{
	kdestroy &>/dev/null
	rm -f /etc/krb5.keytab &>/dev/null
}

#mount and add to fstab in one operation
#scary stuff. dont mess this up
function my_mount()
{
	#device in this case is the source directory
	DEVICE=$1
	DIR=$2
	
	if mount --bind $DEVICE $DIR ; then

		#only add if it's not there. duh
		if ! cat /etc/fstab | /bin/grep -q '$DIR' ; then

			if [ $DEVICE = "/proc" ] ; then
				echo "proc $DIR proc defaults 0 0" >> /etc/fstab
			else
				echo "$DEVICE $DIR bind defaults,bind 0 0" >> /etc/fstab
			fi
		fi
	fi
}

function my_umount()
{
	DIR=$1

	###REMOVE mountpoint from fstab

	#if this mount point is in fstab
	if grep -w $DIR /etc/fstab > /dev/null; then

		#make the .bak file which has everything except the line with DIR in it
		if grep -vw $DIR /etc/fstab > fstab.bak ; then
			#swap and cross fingers that it worked
			mv -f fstab.bak /etc/fstab
		fi
	fi		

	#umount force 	
	umount -lf $DIR 
	return $?
}

#look for filenames formatted as they would be when made with do_backup_all_jails() in the current dir
function do_restore_all_jails()
{
        if [ -z "$1" ] ; then
        RESTOREP=$WD
        else
        RESTOREP=$1
        fi
	#the iwa file may not exit , so we use as follow
        for tarball in `ls $RESTOREP| grep -E "iwa.backup.*.tar.gz"`
	do
		do_restore_jail $(basename $tarball) $RESTOREP
	done
}

function do_restore_jail()
{
	TARFILE=$1
        if [ -z "$2" ] ; then
        RESTOREP=$WD
        else
        RESTOREP=$2 
        fi
	(cd /opt/WCG && tar xvfz $RESTOREP/$TARFILE) || die "restore jail failed with $TARFILE"
	
	#loop through each jail and find the ones that came from this tarball
	#eg. dont appear to have the full jail file system
	#Then create the surrounding filesystem mounts for this restored jail so it is chroot ready
	for jail in $JAILDIR/*
	do
		[ ! -d $jail ] && continue
		
		if [ ! -f $jail/thisjail.name ] ; then
		#meh. use this as "proof" that the jail filesystem isn't done
			do_new_jail $(basename $jail)
		fi

		if [ ! -f $jail/thisjail.name ] ; then
			die "Failed to restore samba jail/realm: $(basename $jail)"
		else
			echo "Restoring samba jail/realm SUCCESS: $(basename $jail)"
		fi
	done
}

function do_new_jail()
{ #create chroot jail filesystem for this instance of samba

	REALM=$1

	#jail needs a name
	if [ -z "$REALM" ] ; then 
		die "Please specify a jail name"
	fi

	THISJAIL=$JAILDIR/$REALM

	if [ -f $THISJAIL/thisjail.name ] ; then
		echo "Realm already joined: $REALM. You must unjoin before rejoining this domain"
		exit 8
	fi

	#--CREATE and hardlink(mount) all shared dirs amongst jailed instances
	#  jail specific config and logs will *not* be in these dirs
	#  my_mount adds to /etc/fstab
	
	#samba shared dirs	
	mkdir -p $THISJAIL/$PREFIX/bin
	mkdir -p $THISJAIL/$PREFIX/sbin
	mkdir -p $THISJAIL/$PREFIX/lib

	#system dirs
	mkdir -p $THISJAIL/lib
	mkdir -p $THISJAIL/bin
	mkdir -p $THISJAIL/sbin
	mkdir -p $THISJAIL/dev
	mkdir -p $THISJAIL/proc
	mkdir -p $THISJAIL/var
	mkdir -p $THISJAIL/usr/lib
	mkdir -p $THISJAIL/usr/bin
	
	if [ "$KERNELARCH" = "64" ] ; then
	  mkdir -p $THISJAIL/lib64
	  mkdir -p $THISJAIL/usr/lib64
	else
	  mkdir -p $THISJAIL/usr/kerberos
	fi
	

	#so we can write logs here
	mkdir -p $THISJAIL/opt/WCG/logs
	mkdir -p $THISJAIL/opt/WCG/config

	mkdir -p $THISJAIL/$PREFIX/expert_tests

	#mount up
	my_mount $PREFIX/sbin $THISJAIL$PREFIX/sbin
	my_mount $PREFIX/bin $THISJAIL$PREFIX/bin
	my_mount $PREFIX/lib $THISJAIL$PREFIX/lib

	my_mount /lib $THISJAIL/lib
	my_mount /bin $THISJAIL/bin
	my_mount /sbin $THISJAIL/sbin

	if [ "$KERNELARCH" = "64" ] ; then
	  my_mount /lib64 $THISJAIL/lib64
	  my_mount /usr/lib64 $THISJAIL/usr/lib64
	else
	  my_mount /usr/kerberos $THISJAIL/usr/kerberos
	fi

	###do not mount /etc since it needs jail specific config for resolv.conf
	my_mount /dev $THISJAIL/dev
	my_mount /proc $THISJAIL/proc
	my_mount /var $THISJAIL/var
	
	#Always create a softlink to ncat,Since Centos7.5 or above have links to etc, that we dont mount
	rm /usr/bin/nc
	ln -s /usr/bin/ncat /usr/bin/nc
	
	my_mount /usr/bin $THISJAIL/usr/bin
	my_mount /usr/lib $THISJAIL/usr/lib
	my_mount /opt/WCG/logs $THISJAIL/opt/WCG/logs
	my_mount /opt/WCG/config $THISJAIL/opt/WCG/config

	my_mount $PREFIX/expert_tests $THISJAIL$PREFIX/expert_tests

	#make directories that are NOT shared amongst jailed instances
	mkdir -p $THISJAIL/tmp
	mkdir -p $THISJAIL/$PREFIX/etc
	mkdir -p $THISJAIL/$PREFIX/private
	mkdir -p $THISJAIL/$PREFIX/var
	mkdir -p $THISJAIL/$PREFIX/var/cache/samba
	chmod 755 $THISJAIL/$PREFIX/var/cache/samba
	mkdir -p $THISJAIL/$PREFIX/var/lib/samba/private
	chmod 755 $THISJAIL/$PREFIX/var/lib/samba
	mkdir -p $THISJAIL/$PREFIX/var/lock/samba
	chmod 755 $THISJAIL/$PREFIX/var/lock/samba
	mkdir -p $THISJAIL/$PREFIX/var/log/samba
	mkdir -p $THISJAIL/$PREFIX/var/run/samba
	mkdir -p $THISJAIL/root
	mkdir -p $THISJAIL/etc

	#interactive chroot stuff
	if [ "$KERNELARCH" = "32" ] ; then
	  echo "export LD_LIBRARY_PATH=$PREFIX/lib" > $THISJAIL/root/.bashrc
	else
	  echo "export LD_LIBRARY_PATH=$PREFIX/lib:$PREFIX/lib64" > $THISJAIL/root/.bashrc
	fi

	echo "$PATH_PROFILE" >> $THISJAIL/root/.bashrc 	
	
	#libresolv stuff. each jail has its own. do not copy search domain since it will be different in each realm
	grep -v "^search" /etc/resolv.conf > $THISJAIL/etc/resolv.conf
	cp /etc/nsswitch.conf $THISJAIL/etc

	#create hosts file in the jail. Remove the .localdomain string sometimes appended to the real hostname
	#the original hosts file is not modified 
	sed 's/.localdomain//g' /etc/hosts > $THISJAIL/etc/hosts

	#timezone (so "date" is not always UTC in jail)
	cp /etc/localtime $THISJAIL/etc

	#for library search path. runtime linker uses this file
	cp /etc/ld.so.cache $THISJAIL/etc

	#samba 3.6 winbindd need this to start now
	cp /etc/passwd $THISJAIL/etc

	#so within chroot can know what is the OS release version
	cp /etc/redhat-release $THISJAIL/etc

	wd=`pwd`
	#so we can run winbindd.REALMNAME so ps or top shows which instance of winbindd is for which realm
	cd $THISJAIL/$PREFIX/sbin
	ln -s ./winbindd winbindd.$REALM
	cd $wd 
	
	#hardlink to this script so it can be used in the jail 
	ln $PREFIX/`basename $0` $THISJAIL
	
	#so within chroot can know its own name
	echo $REALM > $THISJAIL/thisjail.name

}

function do_delete_jail()
{
	REALM=$1
	#jail needs a name
	if [ -z "$REALM" ] ; then 
		die "Please specify a jail name"
	fi

	THISJAIL=$JAILDIR/$REALM

	if [ ! -d $THISJAIL ] ; then
		echo "Jail dir not found -- nothing to do: $THISJAIL"
	else

		do_stop $REALM

		#unmount all hard links for this jail and remove /etc/fstab entries in one fancy swoop
		cat /proc/mounts | grep "${THISJAIL}/" | awk '{print $2}' | while read DIR; do my_umount "$DIR"; done
	
		#check mounts are gone just to be sure
		if [ -z "`cat /proc/mounts | grep ${THISJAIL}/`" ]; then

			#remove symlink for realmified daemon name
			unlink $PREFIX/sbin/winbindd.$REALM

			#CRITICAL that no mounts for this jail are still present
			# when we do rm or the base OS and filesystem will be killed
			if rm -rf $JAILDIR/$REALM
			then
				echo "Samba instance for realm $REALM deleted from disk"
			else
				die "Realm unmounted but not removed from filesystem"
			fi 
		else
			die "jail filesystems still mounted cannot remove realm from disk"
		fi
	fi
}

#sanity test join parameters fqdn,dcfqdn,user,pass
#intention is to give usefull errors for any obvious failures before we call krb and samba
#note that these tests happen in the unjoined state and out of the chroot
function do_join_sanity()
{
	DOMFQDN=$1
	DCLIST=$2
	USER=$3
	PASS=$4
	
	if ! host $DOMFQDN 1>/dev/null; then
		echo ERROR: Unable to resolve name $DOMFQDN 
		return 1
	fi

	if [ "$DCLIST" = '*' ] ; then

		echo -n

	else
		#DCLIST is a comma sparated list of domain controller addresses. loop through each one
		echo "$DCLIST" | tr ',' '\n' | while read DC
		do
			if lsb_release -a | grep -q 'release 7'; then

				if ! isIP $DC && ! host $DC 1>/dev/null; then
					echo ERROR: Unable to resolve name $DC
					return 2
				fi

				if ! nc -w 3 $DC 389 --send-only --recv-only 1>/dev/null; then
					echo ERROR: Unable to connect to port 389 on $DC
					return 3
				fi

				if ! nc -w 3 $DC 445 --send-only --recv-only 1>/dev/null; then
					echo ERROR: Unable to connect to port 445 on $DC
					return 4
				fi

				if ! nc -w 3 $DC 88 --send-only --recv-only 1>/dev/null; then
					echo ERROR: Unable to connect to port 88 on $DC
					return 5
				fi
                        else
				if ! isIP $DC && ! host $DC 1>/dev/null; then
					echo ERROR: Unable to resolve name $DC
					return 2
				fi

				if ! nc -w 3 -z $DC 389 1>/dev/null; then
					echo ERROR: Unable to connect to port 389 on $DC
					return 3
				fi

				if ! nc -w 3 -z $DC 445 1>/dev/null; then
					echo ERROR: Unable to connect to port 445 on $DC
					return 4
				fi

				if ! nc -w 3 -z $DC 88 1>/dev/null; then
					echo ERROR: Unable to connect to port 88 on $DC
					return 5
				fi
			fi
		done
	fi
	
}


#nscd must be stopped when doing the domain join because
#the nscd domain socket which exists in the jail gives the jail access
#to the non-jailed /etc/hosts file which might be incorrect.
#samba uses "hostname -a" to discover it's local fqdn
#the hosts file by default has "hostname.localdomain" which is incorrect
#removing ".localdomain" from the main /etc/hosts causes sendmail issues

#return 0 if nscd was stopped
nscd_stopped=0
function nscd_stop()
{
	if pgrep nscd &>/dev/null; then
		#nscd is running 
		echo "stopping nscd ..."
		/etc/init.d/nscd stop
		nscd_stopped=1
	fi
}

#only start it if we stopped it
function nscd_start()
{
	if [ $nscd_stopped -eq 1 ] ; then
		echo "starting nscd ..."
		/etc/init.d/nscd start
	fi
}

#SMBAdmin join domain.com host.domain.com
#-or-
#SMBAdmin join domain.com 
#if the dc address is not specified DNS SRV will be queried to auto detect them
function do_join()
{
	if ! isChrooted ; then 
		#when we call "ourselves" (chroot SMBAdmin join) below 
		#the new instance inherits our file descriptors to the tee pipe
		#so we dont need to reopen the log inside the chroot instance
		local JLOG="/opt/WCG/logs/smbadmin.join.log"
		cat /dev/null > $JLOG
		start_log $JLOG
	fi

	DOMFQDN=$2
	DCLIST=$3 #optional
	ALTREALMNAME=$4 #optional - never use in production
	
	if [ -z "$DOMFQDN" ]; then
		die "usage: $0 $THECMD DOMAIN_FQDN [DC_ADDRESS]"
	fi

	if [ -z "$DCLIST" -o "$DCLIST" = "-" ] ; then
		# auto detect DC's via DNS SRV records
		DCLIST='*'
	fi

	REALM=$ALTREALMNAME

	if [ -z "$REALM" ] ; then
		#query dc with 'net ads workgroup' to get the realm/nebios domian name
		REALM=`do_getrealmbydnsname "$DOMFQDN" "$DCLIST"`
	fi

	if [ -z "$REALM" ] ; then 
		echo Unable to determine workgroup name with 'net ads workgroup'
		exit 21
	fi

	#Get the first DC online after sanity check from the DCLIST
	if ! [ "$DCLIST" = '*' ] ; then
		DCLIST=`do_getonlinedc "$DOMFQDN" "$DCLIST"`
		if [ -z "$DCLIST" ] ; then
			echo "Unable to determine a DC from given DCLIST"
			exit 22
		fi
	fi

	if ! isChrooted ; then
	#if not chrooted we need to setup a new jail
	#then launch this script again in the jail

		do_new_jail $REALM

		nscd_stop

		#recursive "call SMBAdmin join" inside the chroot
		chroot $THISJAIL /`basename $0` join "$2" "$3" "$REALM"

		EXITCODE=$?

		#once join is done from within the
		#jail - start it if it was stopped by us
		nscd_start 

		#if SMBAdmin join failed in the chroot then remove the jail filesystem
		if [ $EXITCODE -ne 0 ] ; then
			echo ERROR $RET: Join failure - cleaning up >&2
			do_delete_jail $REALM
		fi

		exit $EXITCODE
	fi

	#we are chrooted here on

	DOMFQDN_upper=`toUpper $DOMFQDN`

	#generate smb config from tempate string
	echo "$(eval "echo \"$SMB_CONF\"")" > $PREFIX/etc/smb.conf

	#generate krb config from template string
	if [ "$DCLIST" = '*' ] ; then
		echo "$(eval "echo \"$KRB_CONF_AUTO\"")" > /etc/krb5.conf
	else
		#set kdc as the first dc in the list
		DCLIST=`echo "$DCLIST" | awk -F',' '{print $1}'`
		echo "$(eval "echo \"$KRB_CONF_DEFAULT\"")" > /etc/krb5.conf
	fi

	#read from stdin
	read -p 'Admin Username: ' USER 
	read -sp 'Admin Password: ' PW
	
	do_clean
	
	echo
	echo -n kinit ... 
		if ! kinit $USER@$DOMFQDN_upper <<< "$PW"
		then
			echo "failed"
			exit 42
		fi
	echo done 

	echo
	echo -n joining domain ... 
		if ! net ads join -U $USER%"$PW" 
		then
			echo failed
			exit 43
		fi
	echo done 

	echo
	echo -n creating keytab ...
		if ! net ads keytab create -U $USER%"$PW" 
		then
			echo failed
			exit 44
		fi
	echo done 

	echo
	echo -n adding HTTP service to keytab ... 
		if ! net ads keytab add HTTP -U $USER%"$PW" && chmod 644 /etc/krb5.keytab 
		then
			echo failed
			exit 45
		fi
	echo done 
	echo
	
	#JOIN SUCCESS 

	echo -n adding UPN to keytab to support HTTP LB...
                declare -ar RESULT=("`net ads search "(sAMAccountName=$USER)" msDS-KeyVersionNumber userPrincipalName -U $USER%"$PW"`")       # Get UPN and KVNO from AD
                declare -ar KVNO=(`echo "$RESULT" | awk '/^msDS-KeyVersionNumber:[[:space:]][0-9]*$/ {print $2}'`)      # Extract KVNO from result
                declare -ar UPN=("`echo "$RESULT" | awk '/^userPrincipalName:[[:space:]].*$/ {print $2}'`")               # Extract UPN from result - this ensures correct formatting of UPN in keytab
                declare -ar UPN_user=("`echo "$UPN" | awk -F@ '{print $1}'`")                                           # Extract User from UPN
                declare -ar UPN_domain=("`echo "$UPN" | awk -F@ '{print $2}' | tr "[:lower:]" "[:upper:]"`")            # Extract domain from UPN and convert to uppercase
                printf "\n\tUPN: $UPN_user@$UPN_domain"
                printf "\n\tKVNO: $KVNO\n"
		{
			for s_enctype in des-cbc-crc des-cbc-md5 aes128-cts-hmac-sha1-96 aes256-cts-hmac-sha1-96 arcfour-hmac; do
				echo add_entry -password -p $UPN_user@$UPN_domain -e $s_enctype -k $KVNO
				echo "$PW"
			done
			echo wkt /etc/krb5.keytab
		} | ktutil >/dev/null
	echo done


	#wipe pw
	PW='xxx'

	do_stop $REALM
	do_start $REALM

}

#"net ads leave" requires domain admin credentials -- dont do it yet
function do_unjoin()
{
	if [ -z "$1" ] ; then 
		die "usage: $0 $THECMD REALM_NAME"
	fi

	do_delete_jail $1
}

function do_unjoinall()
{
  for j in `do_listjails`; do
    do_unjoin $j
  done
}

#list jails ordered by date created (last to be joined first)
function do_listjails()
{
	[ ! -d $JAILDIR ] && return

	ls -1t $JAILDIR
}

#list jails that have a valid join membership
function do_listunjoinedjails()
{
	[ ! -d $JAILDIR ] && return

	for jail in $JAILDIR/*
	do
		[ ! -d $jail ] && continue

		if ! chroot $jail net ads testjoin -P >>$DALOG 2>&1
		then
			echo "`basename $jail`"
		fi
	done
}

#list jails that have a valid join membership
function do_listjoinedjails()
{
	[ ! -d $JAILDIR ] && return

	for jail in $JAILDIR/*
	do
		[ ! -d $jail ] && continue

		if chroot $jail net ads testjoin -P >>$DALOG 2>&1
		then
			echo "`basename $jail`"
		fi
	done
}

function getini()
{
 	sed -n "s/$2.*=[[:space:]]*\(.*\)/\1/p" "$1"
}

function setini()
{
	sed -i "/$2/ c $3" "$1"
}

function do_getspn()
{
	REALM=$1

	if isChrooted ; then
		KEYTAB_PATH=/etc/krb5.keytab
	else
		if [ -z "$REALM" ]; then
			die "usage: $0 $THECMD [REALM_NAME]"
		fi
	
		KEYTAB_PATH=${JAILDIR}/${REALM}/etc/krb5.keytab
	fi

	krb5_keytab=$(mktemp /tmp/krb5_keytab.$$.XXXXXX.txt)
	klist -k $KEYTAB_PATH > ${krb5_keytab}
	grep HTTP ${krb5_keytab} | head -1 | awk -F/ '{print $2}' | awk -F@ '{print $1}'
}

function do_getdc()
{
	REALM=$1
		
	if isChrooted ; then
		CONFFILE=${PREFIX}/etc/smb.conf
	else
		if [ -z "$REALM" ]; then
			die "usage: $0 $THECMD [REALM_NAME]"
		else
			CONFFILE=${JAILDIR}/${REALM}/${PREFIX}/etc/smb.conf
		fi
	fi

	if [ -r $CONFFILE ]; then
		getini $CONFFILE 'password server'
	fi
}


#DCLIST can be '-' or '*'
function do_setdc()
{
	REALM="$2"
	DCLIST="$3"

	if [ -z "$REALM" ] ; then 
		die "usage: $0 $THECMD [REALM_NAME] [DC_LIST]"
	fi

	if [ -z "$DCLIST" ] ; then 
		die "usage: $0 $THECMD [REALM_NAME] [DC_LIST]"
	elif [ "$DCLIST" = '-' ] ; then
		DCLIST='*'
	fi
	
	CONFFILE=${JAILDIR}/${REALM}/${PREFIX}/etc/smb.conf
	if [ -r $CONFFILE ]; then
		setini $CONFFILE "password server" "password server = $DCLIST"
	else
		die "$CONFFILE not found"
	fi
}

function do_gethostname()
{
	hostname
}

function do_sethostname()
{
	HNAME="$1"
	if [ -z "$HNAME" ] ; then
		die "usage: $0 $THECMD [HOSTNAME]"
	fi

	OLDHNAME=`hostname`
	if [ -z $OLDHNAME ] ; then
		echo failed to get current hostname >&2
		exit 2
	fi

	if [ $OLDHNAME = $HNAME ] ; then
		#already done
		exit 0
	fi
	
	#set current hostname
	hostname $HNAME	

	#persist hostname in config file
	setini /etc/sysconfig/network "HOSTNAME" "HOSTNAME=$HNAME"

	#update /etc/hosts ...
	sed -i "s/$OLDHNAME/$HNAME/g" /etc/hosts

	#if we are on appliance, call api to do some updates
	if [ -f /etc/appliance_build.env ] ; then
		touch /tmp/wcg_join_domain
		if [ ! -f /tmp/wcg_join_domain ] ; then
			echo "create join domain lock file failed on appliance" >&2
			exit 2
		fi
		chmod 400 /tmp/wcg_join_domain
		/usr/bin/curl -i -X PUT -u `cat /opt/appliance/api/api_key.txt`:NONE "169.254.254.130/api/app/v1/sys/hostname/wcg?hostname=${HNAME}"
	fi
	
	#... and the copy to each jail
	for jail in $JAILDIR/*
	do
		[ ! -d $jail ] && continue

		cp -f /etc/hosts $jail/etc/hosts
	done
}


#loop through all dc's until we find one
#return first online DC
function do_getonlinedc()
{
	DOMFQDN=$1
	DCLIST=$2
	
	#DCLIST can be comma or line delimited 
	echo "$DCLIST" | tr ',' '\n' | while read DC
	do
		#use netcat to do a faster test before we commit to the 10 second wait time
		#alot of lag if there are dozens of DC's
		#not perfect but TCP 389 needs to be open too
		if lsb_release -a | grep -q 'release 7'; then
			if nc -v -w 3 $DC 389 --send-only --recv-only > /dev/null ; then
				if do_join_sanity "$DOMFQDN" "$DC" ; then
					echo $DC
					break
				fi
			fi
		else
			if nc -v -w 3 -z $DC 389 > /dev/null ; then
				if do_join_sanity "$DOMFQDN" "$DC" ; then
					echo "$DC"
					break
				fi
			fi
		fi
	done
}

#loop through all dc's until we find one to call net ads workgroup on
#dclist can be passed or detected
#return the output of the net command looks like "Workgroup: CHRIS-DOMAIN"
function do_getrealmbydnsname()
{
	DOMFQDN=$1

	#OPTIONAL: can specify a list of dc's to query for the realm
	DCLIST=$2

	if [ -z "$DOMFQDN" ] ; then
		die "usage: $0 $THECMD [DOMAIN_FQDN]"
	fi

	if [ -z "$DCLIST" -o "$DCLIST" = '*' -o "$DCLIST" = '-' ] ; then
		DCLIST=`do_getdcsbydnsname $DOMFQDN 2>/dev/null`
	fi

	if [ $? -eq 0 ] ; then

		#DCLIST can be comma or line delimited 
		echo "$DCLIST" | tr ',' '\n' | while read DC
		do
			#net ads workgroup has a 10 second timeout before failing
			#use netcat to do a faster test before we commit to the 10 second wait time
			#alot of lag if there are dozens of DC's
			#note 'net ads workgroup' uses UDP 389. netcat tests TCP. 
			#not perfect but TCP 389 needs to be open too
			if lsb_release -a | grep -q 'release 7'; then

				if nc -v -w 3 $DC 389 --send-only --recv-only > /dev/null ; then

					RESP=`net ads workgroup -S $DC`
					if [ $? -eq 0 ]; then
						echo $RESP | awk '{print $2}'
						break
					fi

				fi
                        else
				if nc -v -w 3 -z $DC 389 > /dev/null ; then

					RESP=`net ads workgroup -S $DC`
					if [ $? -eq 0 ]; then
						echo $RESP | awk '{print $2}'
						break
					fi

				fi
                        fi
		done
		
	fi

}

#get the list of domain controllers for this domain
#DNS A record of the fqdn contains each DC ip address
function do_getdcsbydnsname()
{
	DOMFQDN=$1

	if [ -z "$DOMFQDN" ] ; then
		die "usage: $0 $THECMD [DOMAIN_FQDN]"
	fi

	HOSTS=`host $DOMFQDN 2>/dev/null`
	EXITCODE=$?

	if [ $EXITCODE -eq 0 ] ; then
		# Get IPv4 address firstly, then get IPv6 address if there is no IPv4 result.
		# Only use the first address if there is more than one result get back.
		DC=`echo "$HOSTS" | grep "has address" | awk '{if(NR==1) print $NF}'`
                if [ -z "$DC" ] ; then
                        DC=`echo "$HOSTS" | grep "has IPv6 address" | awk '{if(NR==1) print $NF}'`
                fi
	fi

	echo $DC

	return $EXITCODE
}


#get the list of name servers for this domain
#DNS NS record of the fqdn contains each name server
function do_getnsbydnsname()
{
	DOMFQDN=$1

	if [ -z "$DOMFQDN" ] ; then
		die "usage: $0 $THECMD [DOMAIN_FQDN]"
	fi

	HOSTS=`host -t ns $DOMFQDN 2>/dev/null`
	EXITCODE=$?

	if [ $EXITCODE -eq 0 ] ; then
		echo "$HOSTS" | grep 'name server' | awk '{print $4}'
	fi

	return $EXITCODE
}

#get the global catalog server address
function do_getgcbydnsname()
{
	DOMFQDN=$1

	if isChrooted ; then
		DOMFQDN=`do_getdomain`
	fi

	if [ -z "$DOMFQDN" ] ; then
		die "usage: $0 $THECMD [DOMAIN_FQDN]"
	fi

	GC="_ldap._tcp.gc._msdcs.$DOMFQDN"
	SERVERS=`host -t SRV $GC 2>/dev/null`

	EXITCODE=$?

	if [ $EXITCODE -eq 0 -a ! -z "$SERVERS" ]; then
		echo "$SERVERS" | head -1 | awk '{print $8}'
	fi

	return $EXITCODE
}

#the configured fqdn/dns domain name for realm
function do_getdomain()
{
	REALM=$1

	if isChrooted ; then
		CONFFILE=${PREFIX}/etc/smb.conf
	else
		if [ -z "$REALM" ] ; then 
			die "usage: $0 $THECMD [REALM_NAME]"
		fi

		CONFFILE=${JAILDIR}/${REALM}/${PREFIX}/etc/smb.conf
	fi

	if [ -r $CONFFILE ]; then
		getini $CONFFILE 'realm'	
	fi

}

function do_install()
{
	tar xvfz $TARNAME -C / --no-same-owner || die "unable to extract `pwd`/$TARNAME"
	
	#this will neuter the base samba install enough so it will not run outside of a jail
	#generate smb config from tempate string
	echo "$(eval "echo \"$SMB_CONF\"")" > $PREFIX/etc/smb.conf

    #create krb5.conf to bypass /etc/krb5.conf, KRB5_CONF should set to this file path
    #DOMFQDN is really not important here, /etc/krb5.conf use example.com or kerberos.com
    DOMFQDN="example.com"
    DOMFQDN_upper=`toUpper $DOMFQDN`
    echo "$(eval "echo \"$KRB_CONF_AUTO\"")" > $PREFIX/etc/krb5.conf

	#copy libraries
	cp -f /opt/WCG/lib/libgnutls.so.26 $PREFIX/lib/
	cp -f /opt/WCG/lib/libtasn1.so.3 $PREFIX/lib/

	#setup lib search path	
	if [ "$KERNELARCH" = "32" ] ; then
	  echo $PREFIX/lib > /etc/ld.so.conf.d/samba.wcg.ld.conf
	else
	  echo $PREFIX/lib > /etc/ld.so.conf.d/samba.wcg.ld.conf
	  echo $PREFIX/lib64 >> /etc/ld.so.conf.d/samba.wcg.ld.conf
	fi

	ldconfig

	#setup bin search path	
	local PFILE='/etc/profile.d/samba.wcg.sh'
	echo "$PATH_PROFILE" > $PFILE
	chmod 755 $PFILE

	#source to update PATH
	#/etc/profile sources everything in profile.d
	. /etc/profile
}

#do_uninstall - to uninstall all realms
#wcg_uninstall.sh calls this to uninstall samba
function do_uninstall()
{
	for jail in $JAILDIR/*
	do
		do_delete_jail `basename $jail`
	done
}

#Check if a process is running given its pid file, return 0 if it is running.
function is_process_running()
{
	pid_file=$1

	# Get the process id from the pid file
	if [ -f $pid_file ]; then
		pid=`head -n 1 $pid_file`

		#Now check the process with the 'pid' is running
		if ps -p $pid > /dev/null ; then
			#Process is running
			return 0
		fi
	fi		
	#Process is not running
	return 1
}

function do_start()
{
	if [ "`hostname -i 2>/dev/null`" = "127.0.0.1" ] ; then
		#sneak this test in finally
		echo Warning: /etc/hosts has 127.0.0.1 associated to `hostname 2>/dev/null` | logger -s
	fi

	REALM=$1

	if [ -z "$REALM" ] ; then 
		#start all realm instances 
		do_startall
	else
		THISJAIL=$JAILDIR/$REALM

		if ! isChrooted ; then
			#after appliance wcg container upgraded to CentOs7.4, /dev is mounted as tmpfs instead of devtmpfs.
			#that is why /dev needs to be mounted again afer appliance reboot.
			#only mount /dev if it's not mounted.
			if ! cat /proc/mounts | grep "$THISJAIL/dev" ; then
				mount --bind /dev $THISJAIL/dev
			fi
			chroot $THISJAIL /`basename $0` start $REALM
		else
			winbindd_pid_file=$PREFIX/var/run/samba/winbindd.pid
			if is_process_running $winbindd_pid_file ; then
				echo "winbindd is already running for $REALM"
			else
				$PREFIX/sbin/winbindd.$REALM
				if [ $? -eq 0 ]; then 
					echo "winbindd started for $REALM"
				else
					echo "failed to start winbindd ($?) for realm $REALM"
				fi
			fi
		fi

	fi
}

function do_startall()
{
	[ ! -d $JAILDIR ] && return

	for jail in $JAILDIR/*
	do
		[ ! -d $jail ] && continue

		do_start `basename $jail`
	done
}

function do_stop()
{
	REALM=$1

	if [ -z "$REALM" ] ; then 
		#stop all realm instances
		do_stopall
	else	
		PIDFILE=${JAILDIR}/${REALM}/${PREFIX}/var/run/samba/winbindd.pid

		if [ -r $PIDFILE ] ; then

			PID=`cat $PIDFILE`
			
			kill -9 $PID

			if [ $? -eq 0 ]; then 
				echo "winbindd stopped for $1"
				#this file caches the last known good DC IP among other things
				#if the WCG admin changes the DC IP we want that to take effect instantly on restart
				rm -f ${JAILDIR}/${REALM}/${PREFIX}/var/cache/samba/gencache.tdb
			else
				echo "failed to stop winbindd ($?) for realm $1"
			fi
		fi
	fi
}

function do_restart()
{
	RET=0
	if ! do_stop $1 ; then
		RET=1
	fi

	sleep 1

	if ! do_start $1 ; then
		RET=1
	fi	

	exit $RET
}


#this simply backs up the state, key and config files for this samba instance
#no need to backup all of the binaries
function do_backup_jail()
{
	REALM=$1
        if [ -z "$3" ] ; then
        BACKUPP=$WD
        else
        BACKUPP=$3
        fi
	TARFILE=$BACKUPP/$(basename $2)

	if [ -z "$REALM" -o -z "$TARFILE" ]; then
		die "usage: $0 $THECMD [REALM] [tarball filename]"
	fi

	if [ -f $TARFILE ] ; then
		die "$TARFILE exists. not overwriting"
	fi

	cd $PREFIX/../..

	FILES="
	contrib/samba/jails/$REALM/etc/krb5.conf
	contrib/samba/jails/$REALM/etc/krb5.keytab
	contrib/samba/jails/$REALM/opt/WCG/contrib/samba/private/secrets.tdb
 	contrib/samba/jails/$REALM/opt/WCG/contrib/samba/etc/smb.conf
	"

	tar cvfz $TARFILE $FILES && echo "Realm $REALM backup complete $TARFILE"
}

#loop through all jails and save each one to a separate backup package
function do_backup_all_jails()
{
	for jail in $JAILDIR/*
	do
		[ ! -d $jail ] && continue
		
		R=$(basename $jail)
		do_backup_jail "$R" "iwa.backup.realm.$R.tar.gz" "$1"
	done
}

function do_stopall()
{
	[ ! -d $JAILDIR ] && return

	for jail in $JAILDIR/*
	do
		[ ! -d $jail ] && continue

		do_stop `basename $jail`
	done
}

function do_expert_test()
{
	REALM=$1
	THETEST=$2	

	if [ -z "$REALM" ]; then 
		#show examples with realm specified
		for j in `do_listjails`; do
			echo $0 $THECMD $j
		done
		exit 0
	fi

	if [ -z "$THETEST" ]; then
	#missing test name. List available tests. Each file in testdir is a test
		for test in $TESTDIR/*
		do
			[ ! -f $test ] && continue

			echo $0 $THECMD $REALM `basename $test`
		done

		exit 2
	fi

	THISJAIL=$JAILDIR/$REALM

	if ! isChrooted ; then
		chroot $THISJAIL /`basename $0` $THECMD $REALM $THETEST
		EXITCODE=$?
		return $EXITCODE
	fi

	cd $TESTDIR
	source $TESTDIR/$THETEST
}

function do_all_expert_tests()
{
	REALM=$1
	if [ -z "$REALM" ]; then 
		#show examples with realm specified
		for j in `do_listjails`; do
			echo $0 $THECMD $j
		done
		exit 0
	fi
	
	THISJAIL=$JAILDIR/$REALM

	if ! isChrooted ; then
		/usr/sbin/chroot $THISJAIL /`basename $0` testall $REALM
		exit $?
	fi

	for testname in $TESTDIR/*
	do
		#loop through every file in the test directory
		[ ! -f $testname ] && continue

		#run all tests in subshell in parallel.
		(
		THETEST=`basename $testname`
		cd $TESTDIR
		source $TESTDIR/$THETEST
		) &
	done		

	# wait for all tests running in subshells (running in parallel) to complete
	wait
	
}

function do_getsite()
{
	REALM=$1

	if ! isChrooted ; then 

		if [ -z "$REALM" ]; then 
			die "usage: $0 $THECMD [REALM]"
		fi

		THISJAIL=$JAILDIR/$REALM
		CHROOT="chroot $THISJAIL "
	else
		CHROOT=
	fi

	$CHROOT net cache list | grep AD_SITENAME | head -1 | tr '\t' '\n' | grep 'Value:' | awk '{print $2}'	
	exit $?

}

function do_listconns()
{
    # Check to see if netstat is available.
    # For CentOS 6, net-tools package should be installed by default, so netstat should be available.
	# The reason we try to use netstat first is that "ss -ntp" runs slower than "netstat -ntp" on CentOS 6.
    # For CentOS 7 or later, net-tools package may not be installed, so netstat may not be available.
    if [ -f /bin/netstat ] ; then
        echo -e "Source IP:Port\t\tDest IP:Port\t\tState\t\tPID/name"
        netstat -ntp | grep winbindd | awk '{print $4"\t"$5"\t\t"$6"\t"$7}'
    # Check to see if ss is available.
    # For CentOS 7 or later, iproute package should be installed by default, so ss should be available.
    elif [ -f /usr/sbin/ss ] ; then
        out=(`ss -ntp | grep winbindd | awk '{print $4" "$5" "$1" "$6}'`)
        if [ "${#out[@]}" == 0 ]
        then
            echo "No winbindd process"
            return 0
        fi
        numberOfFields=4 #number of elements we were interested in with our awk call: change the awk call, change this
        for(( i=0; i<"${#out[@]}"/${numberOfFields}; i++ ))
        do
            if [ $i == 0 ]
            then
                printf "%-15s\t%-15s\t%-15s\t%-30s\t\n" "Source IP:Port" "Dest IP:Port" "State" "users:((ProcessName,PID,FD))"
                printf "==========%.0s\t" $(seq 1 ${numberOfFields})
                printf "\n"
            fi
            for(( j=0; j<${numberOfFields}; j++))
            do
                printf "%s\t" "${out[${i} * ${numberOfFields} + j]}"
            done
            printf "\n"
        done | column -t -s$'\t'
    else
        echo "both netstat and ss commands are not installed on the WCG node."
    fi
}

function do_techsupport()
{
	REALM=$1
	if [ -z "$REALM" ]; then 
		#show techsupport and testcase output for all realms
		for j in `do_listjails`; do
			( do_techsupport $j )
			( do_all_expert_tests $j )
		done
		exit 0
	fi

	THISJAIL=$JAILDIR/$REALM

	if ! isChrooted ; then
		/usr/sbin/chroot $THISJAIL /`basename $0` $THECMD $REALM
		exit $?
	fi

	echo TechSupport info for realm: $REALM `date`
	echo Note: All directory paths are relative to $THISJAIL

	DOMFQDN=`do_getdomain $REALM`

	# One command per line (all executed within the chroot).
	# This 'SMBAdmin techsupport' option should ONLY print informational info.
	# Any "smart" test cases should be done as an expert test in 'SMBAdmin test|testall'
	COMMANDS="
	cat /etc/resolv.conf
	cat /etc/hosts
	hostname
	hostname -f
	net ads testjoin
	wbinfo -p
	net ads info
	wbinfo -D $REALM
	wbinfo --online-status
	wbinfo -m
	wbinfo -t
	net ads keytab list
	klist
	klist -k 
        ps aux | head -1 ; ps aux | egrep 'ntlm_auth|winbindd|content_gateway|content_manager' | grep -v grep
	$0 getdcsbydnsname $DOMFQDN
	$0 getgcbydnsname $DOMFQDN
	$0 getsite $REALM 
	$0 listconns
	dig -t SRV _ldap._tcp.$DOMFQDN
	dig -t SRV _kerberos._tcp.$DOMFQDN
        ping -w 2 -c 3 -i 0.1 $DOMFQDN
	cat /proc/loadavg
	net ads search -P '(serverReferenceBL=*)'
	net cache list
	grep winauth /opt/WCG/config/records.config
	egrep -v '^#' /opt/WCG/config/auth.config
	echo 'read proxy.process.winauth.nego.txns' | nc 127.0.0.1 8087 
	echo 'read proxy.process.winauth.total.nego.txns.time' | nc 127.0.0.1 8087 
	echo 'read proxy.process.winauth.nego.success' | nc 127.0.0.1 8087 
	echo 'read proxy.process.winauth.nego.denied' | nc 127.0.0.1 8087 
	echo 'read proxy.process.winauth.nego.errors' | nc 127.0.0.1 8087 
	echo 'read proxy.process.winauth.nego.avg_msec_per_txn' | nc 127.0.0.1 8087 
	echo 'read proxy.process.winauth.ntlm.txns' | nc 127.0.0.1 8087 
	echo 'read proxy.process.winauth.total.ntlm.txns.time' | nc 127.0.0.1 8087 
	echo 'read proxy.process.winauth.ntlm.success' | nc 127.0.0.1 8087 
	echo 'read proxy.process.winauth.ntlm.denied' | nc 127.0.0.1 8087 
	echo 'read proxy.process.winauth.ntlm.errors' | nc 127.0.0.1 8087 
	echo 'read proxy.process.winauth.ntlm_in_nego.txns' | nc 127.0.0.1 8087 
	echo 'read proxy.process.winauth.ntlm.avg_msec_per_txn' | nc 127.0.0.1 8087 
	echo 'read proxy.process.winauth.basic.txns' | nc 127.0.0.1 8087 
	echo 'read proxy.process.winauth.total.basic.txns.time' | nc 127.0.0.1 8087 
	echo 'read proxy.process.winauth.basic.success' | nc 127.0.0.1 8087 
	echo 'read proxy.process.winauth.basic.denied' | nc 127.0.0.1 8087 
	echo 'read proxy.process.winauth.basic.errors' | nc 127.0.0.1 8087 
	echo 'read proxy.process.winauth.basic.avg_msec_per_txn' | nc 127.0.0.1 8087 
	echo 'read proxy.process.winauth.avg_helper_latency_msec' | nc 127.0.0.1 8087 
	echo 'read proxy.process.winauth.down_time' | nc 127.0.0.1 8087 
	echo 'read proxy.process.winauth.num_fail_opens' | nc 127.0.0.1 8087 
	cat /etc/krb5.conf
	cat $PREFIX/etc/smb.conf
	egrep -i -A 1 -m 1000 'winauth|winbind' /var/log/messages*
	cat /proc/mounts
	"

	echo "$COMMANDS" | while read LINE
	do
		[ -z "$LINE" ] && continue

		echo ------------------------------------
		echo "> $LINE"
		echo ------------------------------------
		eval $LINE
	done
}

function do_usage()
{
	echo "$0 join DOMAIN_FQDN [DC_ADDRESS]"
	echo "$0 unjoin REALM_NAME"
	echo "$0 unjoinall"
	echo "$0 [start|stop|restart] [REALM_NAME]"
	echo "$0 [list|listjoined|listunjoined|listconns] REALM_NAME"
	echo "$0 [getdc|setdc|getdomain|getspn|getsite] REALM_NAME"
	echo "$0 [getdcsbydnsname|getgcbydnsname|getrealmbydnsname] DOMAIN_FQDN"
	echo "$0 [testall|test|techsupport] REALM_NAME"
}

case $1 in
    'join')
	do_join "$@";;
    'unjoin')
	do_unjoin $2;;
    'unjoinall')
       do_unjoinall;;
    'install')
	do_install;;
    'uninstall')
	do_uninstall $2;;
    'start')
	do_start $2;;
    'stop')
	do_stop $2;;
    'restart')
	do_restart $2;;
    'backupall')
	do_backup_all_jails "$2" ;;
    'backup')
	do_backup_jail "$2" "$3" "$4";;
    'restoreall')
	do_restore_all_jails "$2" ;;
    'restore')
	do_restore_jail "$2" "$3";;
    'list')
	do_listjails;;
    'listunjoined')
	do_listunjoinedjails;;
    'listjoined')
	do_listjoinedjails;;
    'getdc')
	do_getdc $2;;
    'setdc')
	do_setdc "$@";;
    'getsite')
	do_getsite $2;;
    'getspn')
	do_getspn $2;;
    'gethostname')
	do_gethostname;;
    'sethostname')
	do_sethostname $2;;
    'getdomain')
	do_getdomain $2;;
    'getdcsbydnsname')
	do_getdcsbydnsname $2;;
    'getnsbydnsname')
	do_getnsbydnsname $2;;
    'getgcbydnsname')
	do_getgcbydnsname $2;;
    'getrealmbydnsname')
	do_getrealmbydnsname "$2" "$3";;
    'listconns')
	do_listconns $2;;
    'test')
	do_expert_test $2 $3
	exit $?;;
    'testall')
	do_all_expert_tests $2;;
    'techsupport')
	do_techsupport $2;;
    *)
	do_usage;
esac

exit 0

