#!/bin/ksh -p
#
#*******************************************************************************
#
# ident "@(#)utkioskconfig.sh	1.16	09/09/18 SMI"
#
# Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#
#*******************************************************************************
#

theModule=kiosk:utkioskconfig

export PATH=/usr/bin:/bin

UTPRODINFO=/etc/opt/SUNWut/basedir/lib/utprodinfo
UTBASEDIR=`$UTPRODINFO -r SUNWuto 2>/dev/null`
SUNWUT=${UTBASEDIR:-/opt}/SUNWut
UTKIOSK=$SUNWUT/sbin/utkiosk
UTKIOSKOVERRIDE=$SUNWUT/sbin/utkioskoverride
UTCONFFILE=/etc/opt/SUNWut/utadmin.conf

# Use KIOSK_DEBUG setting from KIOSKRC
KIOSKRC=/etc/opt/SUNWkio/kioskrc
KIOSK_DEBUG=0
if [ -x $KIOSKRC ] ; then
	. $KIOSKRC
fi	

# Prepare/check the kiosk environment
function InitKiosk
{
	if $UTPRODINFO -t installed SUNWkio ; then
		KIOBASEDIR=`$UTPRODINFO -r SUNWkio 2>/dev/null`
		SUNWKIO=${KIOBASEDIR:-/opt}/SUNWkio
		KIOSKCONFIG=$SUNWKIO/bin/kioskconfig
		KIOSK_INSTALLED=true
	else
		KIOSKCONFIG="false"
		KIOSK_INSTALLED=false
	fi	
}

function usage
{
	cat << !
Usage:
      utkioskconfig enable|disable -d <display> [-r <raw>] [-t <token] [-e]
      utkioskconfig refresh -d <display>

      enable         enable Kiosk Mode for the specified display
      disable        disable Kiosk Mode for the specified display
      refresh        refresh Kiosk configuration for the specified display
      -d <display>   specifies the display for which Kiosk should be configured 
      -r <raw>       specifies the raw insert token for the configured session
      -t <token>     specifies the session token for the configured session
      -e             save effective policy, overrides will not be refreshed
!
}

#
## Some utility functions
##
## We don't use kiosk utils here, as this might run wher 
##
## Kiosk isn't even installed
#

function logDebug
{
        if [ "0" != "${KIOSK_DEBUG:-0}" ] ; then 
		logger -i -t "$theModule" -p user.debug "$@"
		# echo "$@" >&2    
	fi	
}
function logInfo
{
	logger -i -t "$theModule" -p user.info "$@"
	# echo "$@" >&2    
}
function logWarning
{
	logger -i -t "$theModule" -p user.warn "$@"
	echo "Warning: $@" >&2    
}
function logError
{
	logger -i -t "$theModule" -p user.error "$@"
	echo "Error: $@" >&2    
}

#
## stores policy for a single display
##
## param inModule
##  a module name used in log messages
##
## param inDisplay
##  the display to be activated
##
## param inConfigDir
##  the directory where kiosk config. for $inDisplay is stored
##
## param inPolicy
##  the policy to save
##
## param inSession
##  the session name to save
##  may be empty to suppress saving
##
## param inRawToken (optional)
##  the raw token to save
##
## param inToken (must be provided iif inRawToken is provided)
##  the session token to save
##
## param inEffectivePolicy (optional)
##  the current effective policy, 
##  if default policy and tokens were saved for future 
##  recomputing of effective policy
##
## returns 0 on success
##         nonzero otherwise
#
function savePolicy
{
	typeset inDisplay=$1
	typeset inConfigDir=$2
	typeset inPolicy=$3
	typeset inSession="$4"

	typeset thePolicyFile=$inConfigDir/policy

	logDebug "Storing policy for display '$inDisplay'"

	echo "policy $inPolicy" > $thePolicyFile
	if [ $? -ne 0 ] ; then
		logError "Failed to save policy for display '$inDisplay'"
		return 1
	fi

	if [ -n "$inSession" ] ; then
		echo "session $inSession" >> $thePolicyFile
		if [ $? -ne 0 ] ; then
			logError "Failed to save session name for display '$inDisplay'"
			return 1
		fi
	fi

	if [ $# -gt 4 ] ; then
		typeset theRC=0
		if [ -n "$5" ] ; then
			echo "raw $5" >> $thePolicyFile
			[ $? -eq 0 ] || theRC=1
		fi	
		if [ -n "$6" ] ; then
			echo "token $6" >> $thePolicyFile
			[ $? -eq 0 ] || theRC=1
		fi	
		if [ -n "$7" ] ; then
			echo "effective $7" >> $thePolicyFile
		fi	
		if [ $theRC -ne 0 ] ; then
			logError "Failed to save override tokens for display '$inDisplay'"
			return 1
		fi
	fi

	return 0
}

#
## reset stored policy for a single display
##
## param inDisplay
##  the display to be deactivate
##
## param inConfigDir
##  the directory where kiosk config. for $inDisplay is stored
##
## returns 0 on success
##         nonzero otherwise
#
function resetPolicy
{
	typeset inDisplay=$1
	typeset inConfigDir=$2

	typeset thePolicyFile=$inConfigDir/policy
	typeset theRC=0

	logDebug "Removing stored policy for display '$inDisplay'"
	rm -f $thePolicyFile
	if [ $? -ne 0 ] ; then
		theRC=1
		logError "Failed to remove stored policy for display '$inDisplay'"
	fi
	return $theRC
}

#
## enable a single display
##
## param inDisplay
##  the display to be disabled
##
## param inSessionFile
##  the session settings to use
##
## param inLogFunc
##  the command/function to use to log success
##  Allows callers to control how much attention the policy 
##  decision deserves.
##
## returns 0 on success
##         nonzero otherwise
#
function enable
{
	typeset inDisplay=$1
	typeset inSessionFile=$2
	typeset inLogFunc=${3:-logInfo}

	typeset theRC=0

	if $KIOSK_INSTALLED ; then
		logDebug "Enabling Kiosk Mode for display '$inDisplay'"
		$KIOSKCONFIG enable -d $inDisplay -c $inSessionFile > /dev/null
		if [ $? -eq 0 ] ; then
			theRC=0
			$inLogFunc "Enabled Kiosk Mode for display '$inDisplay'"
		else
			theRC=1
			logError "Failed to enable Kiosk Mode for display '$inDisplay'"
		fi
	else
		theRC=1
		logError "Failed to enable Kiosk Mode for display '$inDisplay' - kiosk software not installed"
	fi	
	return $theRC
}

#
## disable a single display
##
## param inDisplay
##  the display to be disabled
##
## param inLogFunc
##  the command/function to use to log success
##  Allows callers to control how much attention the policy 
##  decision deserves.
##
## returns 0 on success
##         nonzero otherwise
#
function disable
{
	typeset inDisplay=$1
	typeset inLogFunc=${2:-logInfo}

	typeset theRC=0

	if $KIOSK_INSTALLED ; then
		logDebug "Disabling Kiosk Mode for display '$inDisplay'"
		$KIOSKCONFIG disable -d $inDisplay > /dev/null
		if [ $? -eq 0 ] ; then
			theRC=0
			$inLogFunc "Disabled Kiosk Mode for display '$inDisplay'"
		else
			theRC=1
			logError "Failed to disable Kiosk Mode for display '$inDisplay'"
		fi
	else
		logDebug "Nothing to disable for display '$inDisplay' - kiosk not installed"
	fi	
	return $theRC
}

#
## read session settings from srds
##
## param inSessionName
##  the session name in srds to read
##
## param inSessionFile
##  the file name to store the srds session settings to
##
## param inApplistFile
##  the file name to store the srds application list to
##
## output
##  the KIOSK_ENABLE value in the srds settings, if set
##  default "yes" if settings are available, "no" otherwise
##
## returns 0 on success
##         nonzero otherwise
#
function readSrdsSettings
{
	typeset inSession=$1
	typeset inSessionFile=$2
	typeset inApplistFile=$3

	$UTKIOSK -e "$inSession" -s > $inSessionFile
	if [ $? -ne 0 ] ; then
		logError "Failed to retrieve Kiosk configuration"
		rm -f $inApplistFile	
		echo "no"
		return 1
	fi
	
	$UTKIOSK -e "$inSession" -a > $inApplistFile
	if [ $? -ne 0 ] ; then
		logError "Failed to retrieve Kiosk application list"
		# don't start a real session if critical applications may be absent	
		echo > $inSessionFile
		echo "no"
		return 1
	fi

	if [ -s "$inSessionFile" ] ; then
		typeset theSrdsPolicy=`sed -n 's/^KIOSK_ENABLED=//p' $inSessionFile`
		echo ${theSrdsPolicy:-yes}
	else
		echo "no"
	fi
	return 0	
}

#
## read override settings from srds
##
## param inRawToken
##  the raw token for the session
##
## param inToken
##  the session token for the session
##
## output
##  the SESSION_TYPE value in the override settings
##
## returns 0 on success
##         nonzero otherwise
#
function readOverrides
{
	typeset inRawToken="$1"
	typeset inToken="$2"

	typeset theOverrideArgs=
	if [ -n "$inRawToken" ] ; then
		theOverrideArgs="$theOverrideArgs -r $inRawToken"
	fi
	if [ -n "$inToken" ] ; then
		theOverrideArgs="$theOverrideArgs -t $inToken"
	fi
	typeset theOverrideData=`$UTKIOSKOVERRIDE $theOverrideArgs`
	if [ $? -ne 0 ] ; then
		logError "Failed to retrieve kiosk override data"
		return 1
	fi
	if echo "$theOverrideData" | grep '^KIOSK' > /dev/null ; then 
		logWarning "Kiosk overrides (raw='$inRawToken',token='$inToken') \
			contain settings overrides - not supported"
	fi		
	echo "$theOverrideData" 
}

#
## find the effective policy and session for a single display with overrides
##
## param inDisplay
##  the display to be enabled
##
## param inPolicy
##  the primary policy
##
## param inSession
##  the primary kiosk session name
##  may be empty to use the default session name "session"
##
## param inRawToken
##  the raw token for the session
##
## param inToken
##  the session token for the session
##
## output
##  the effective policy that should be applied
##
## returns 0 on success
##         nonzero otherwise
#
function getEffectivePolicyAndSession
{
	typeset inDisplay=$1
	typeset inPolicy=$2
	typeset inSession="$3"
	typeset inRawToken=$4
	typeset inToken=$5

	logDebug  "Determining policy for display '$inDisplay'"
	logDebug  "  primary policy   = '$inPolicy'"
	logDebug  "  primary session  = '$inSession'"

	
	# retrieve policy override
	typeset theEffectivePolicy=$inPolicy
	typeset theEffectiveSession=${inSession:-session}

	if isDsConfigured ; then
	    if [ -n "$inRawToken$inToken" ] ; then
		logDebug  "Fetching overrides"
		[ -n "$inRawToken" ] && 
			logDebug  "  raw token        = '$inRawToken'"
		[ -n "$inToken" ] && 
			logDebug  "  token            = '$inToken'"

		typeset theOverrides=`readOverrides $inRawToken $inToken`
		if [ $? -ne 0 ] ; then
			return 1
		fi
		
		typeset theOverrideType=`
			echo "$theOverrides" | sed -n 's/^SESSION_TYPE=//p' `
		if [ $? -ne 0 ] ; then
			return 1
		fi
		
		typeset theOverrideSession=`
			echo "$theOverrides" | sed -n 's/^SESSION_CONFIG=//p' `
		
		logDebug  "  override session type   = '$theOverrideType'"
		logDebug  "  override session config = '$theOverrideSession'"
		case "$theOverrideType" in
		'default') theEffectivePolicy=$inPolicy ;;
		'regular') theEffectivePolicy="disable" ;;
		'kiosk')   theEffectivePolicy="enable" ;;
		*)
			logWarning "Unknown override session type '$theOverride' - using default policy"
		esac
		if [ -n "$theOverrideSession" ] ; then
			theEffectiveSession=$theOverrideSession
		fi	
	    else
		logDebug  "  no override tokens available"
	    fi
	else
	    logDebug  "No overrides - SRDS is not configured."
	fi
	logDebug  "  effective policy  = '$theEffectivePolicy'"
	logDebug  "  effective session = '$theEffectiveSession'"

	echo $theEffectivePolicy $theEffectiveSession
}

#
## apply effective policy for a single display
##
## token parameters may be supported later for retrieving settings overrides,
## but this is not implemented yet
##
## param inDisplay
##  the display to be enabled
##
## param inConfigDir
##  the directory where kiosk config. for $inDisplay is stored
##
## param inPriorPolicy
##  the prior or default policy
##  (this is used to control logging - only changes vs prior policy are logged)
##
## param inEffectivePolicy
##  the policy to apply
##
## param inSession
##  the session name to use for enabling
##
## output
##  the effective policy that is applied
##
## returns 0 on success
##         nonzero otherwise
#
function applyPolicy
{
	typeset inDisplay=$1
	typeset inConfigDir=$2
	typeset inPriorPolicy=$3
	typeset inEffectivePolicy=$4
	typeset inSession=$5
#	typeset inRawToken=$6
#	typeset inToken=$7

	logDebug  "Applying policy '$inEffectivePolicy' with session '$inSession' for display '$inDisplay'"
	
	typeset logFunc=logDebug
	if [ "$inPriorPolicy" != "$inEffectivePolicy" ] ; then
		logFunc=logInfo
	fi
		
	if [ "$inEffectivePolicy" != "disable" ] ; then
		# retrieve configuration from srds
		typeset theSessionFile=$inConfigDir/srdsConfig
		typeset theAppListFile=$inConfigDir/srdsApplist 

		typeset theDataEnabled=`
			readSrdsSettings "$inSession" $theSessionFile $theAppListFile`
		# ignoring error here: theDataEnabled is set even in error cases

		# TODO: add support for merging override settings
		
		# If the session data calls itself disabled (or is absent 
		# or unavailable) we still must obey the policy.
		if [ "$theDataEnabled" != "yes" ] ; then
			logWarning "No valid session data for kiosk session on display '$inDisplay'"
			# TODO: Configure an error session
		elif [ -s $theAppListFile ] ; then
			echo "KIOSK_SESSION_APPLIST=$theAppListFile" >> $theSessionFile
		fi
		enable $inDisplay $theSessionFile $logFunc >&2
	else
		disable $inDisplay $logFunc >&2
	fi			
}

#
## creates the kiosk configuration for a single display
##
## param inDisplay
##  the display to be enabled
##
## param inConfigDir
##  the directory where kiosk config. for $inDisplay is stored
##
## param inPolicy
##  the primary policy
##
## param inSaveTokens
##  "yes" to save tokens and primary policy, "no" to save effective policy
##
## param inRawToken
##  the raw token for the session
##
## param inToken
##  the session token for the session
##
## returns 0 on success
##         nonzero otherwise
#
function configure
{
	typeset inDisplay=$1
	typeset inConfigDir=$2
	typeset inPolicy=$3
	typeset inSaveTokens=$4
	typeset inRawToken=$5
	typeset inToken=$6

	logDebug  "Creating Kiosk configuration for display '$inDisplay'"

	mkdir -p $inConfigDir 
	if [ $? -ne 0 ] ; then
		logError "Failed to create directory '$inConfigDir'"
		return 1
	fi

	typeset theEffectivePolicyAndSession=`
	        getEffectivePolicyAndSession $inDisplay "$inPolicy" "" "$inRawToken" "$inToken"`

	# don't log info on initialize without override (inPolicy as reference)
	applyPolicy $inDisplay $inConfigDir $inPolicy $theEffectivePolicyAndSession 
		
	typeset theResult=$?

	if [ $theResult -eq 0 ] ; then
		if [ $inSaveTokens != "no" ] ; then
			savePolicy $inDisplay $inConfigDir \
				"$inPolicy" "" "$inRawToken" "$inToken" $theEffectivePolicyAndSession
		else
			savePolicy $inDisplay $inConfigDir $theEffectivePolicyAndSession	
		fi
		theResult=$?
	else
		resetPolicy $inDisplay $inConfigDir
		disable $inDisplay logInfo
	fi		
	return $theResult
}

#
## refreshes the kiosk configuration for a single display
##
## param inDisplay
##  the display to be enabled
##
## param inConfigDir
##  the directory where kiosk config. for $inDisplay is stored
##
## returns 0 on success
##         nonzero otherwise
#
function refresh
{
	typeset inDisplay=$1
	typeset inConfigDir=$2

	typeset thePolicyFile=$inConfigDir/policy

	logDebug  "Refreshing Kiosk configuration for display '$inDisplay'"
	if [ ! -s $thePolicyFile ] ; then
		logDebug  "No stored policy found for display '$inDisplay'"
		disable $inDisplay logDebug
		return $?
	fi

	typeset thePolicy=
	typeset theSession=
	typeset theRawToken=
	typeset theToken=
	typeset theEffPolicy=

	logDebug  "Reading policy file '$thePolicyFile'"
	while read theItem theValue ; do
		case $theItem in 
		policy)	 thePolicy="$theValue" ;;
		session) theSession="$theValue" ;;
		raw) 	 theRawToken="$theValue" ;;	
		token) 	 theToken="$theValue" ;;	
		effective)	 theEffPolicy="$theValue" ;;
		*) 	 logWarning "Unrecognized item '$theItem' in stored policy for display '$theDisplay'" ;;
		esac
	done < $thePolicyFile
	
	if [ -z "$thePolicy" ] ; then
		logError  "No preserved policy found in file '$thePolicyFile'"
		disable $inDisplay logInfo
		return 1
	fi	
	
	typeset theEffectivePolicyAndSession=`
	        getEffectivePolicyAndSession $inDisplay "$thePolicy" "$theSession" "$theRawToken" "$theToken"`

	applyPolicy $inDisplay $inConfigDir ${theEffPolicy:-$thePolicy} $theEffectivePolicyAndSession > /dev/null

	typeset theResult=$?
	if [ $theResult -ne 0 ] ; then
		disable $inDisplay
	fi		
	return $theResult
}

#
## Tests if Kiosk is installed on the current system
##
## returns 0 if Kiosk is installed
##         1 otherwise
function isKioskInstalled
{
	typeset theRC=1
	# if Kiosk is not installed, it obviously isn't configured
	if [ -x $KIOSKSTATUS ] ; then    
		if $KIOSKSTATUS -c > /dev/null 2>&1 ; then
			theRC=0
		fi
	fi
	return $theRC
}

#
## Tests if Kiosk has been configured or not on the current system
##
## returns 0 if Kiosk is configured
##         1 otherwise
function isConfigured
{
	typeset theRC=1
	# if Kiosk is not installed, it obviously isn't configured
	if [ -x $KIOSKSTATUS ] ; then    
		if $KIOSKSTATUS -c > /dev/null 2>&1 ; then
			theRC=0
		fi
	fi
	return $theRC
}


#
## Tests if the SRDS has been configured or not on the current system
##
## returns 0 if SRDS is configured
##         1 otherwise
function isDsConfigured
{
    test -f "$UTCONFFILE"
}

#
## Main
#

inDisplay=
inRawToken=
inToken=
inSaveTokens=yes
thePolicy=

#
## Parse arguments
#
if [ $# -lt 1 ] ; then
	usage
	exit 1
fi
inCommand=$1
shift

while getopts d:er:t: opt; do
	case $opt in
	d)	inDisplay=$OPTARG
		;;
	e)	inSaveTokens=no
		;;
	r)	inRawToken=$OPTARG
		;;
	t)	inToken=$OPTARG
		;;
	\?)	usage
		exit 1
		;;
	esac
done

#
## Check arguments
#
case "$inCommand" in
enable | disable)
	theModule="${theModule}:configure"

	thePolicy=$inCommand
	;;
refresh)
	theModule="${theModule}:refresh"

	if [ -n "$inRawToken" -o -n "$inToken" ] ; then 
		logWarning "Override tokens cannot be altered during refresh - ignored"
	fi
	if [ $inSaveTokens != "yes" ] ; then 
		logWarning "Storage policy cannot be altered during refresh - option ignored"
	fi
	;;
*)		
	logError "Invalid command '$inCommand' specified."
	usage
	exit 1
	;;
esac

if [ -z "$inDisplay" ] ; then 
	logError "Required argument 'display' missing"
	usage
	exit 1
fi

if [ $OPTIND -le $# ]; then
	logError "Extra arguments on command line"
	usage
	exit 1
fi

#
## Prepare/check the kiosk setup
#
InitKiosk

theConfigDir=/var/opt/SUNWut/kiosk/$inDisplay/config

#
## Dispatch the request
#
if [ "$inCommand" = refresh ] ; then
	refresh $inDisplay "$theConfigDir"
else	
	configure $inDisplay "$theConfigDir" "$thePolicy" \
		$inSaveTokens "$inRawToken" "$inToken"
fi	
