#
#*******************************************************************************
#
# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#
#*******************************************************************************
#
# ident "$Id$ SMI"
#

KIOSK_PREFIX=/opt/SUNWkio
KIOSK_DEFAULT_CONFIG_DIR=/etc/opt/SUNWkio
KIOSK_DEFAULT_VAR_DIR=/var/opt/SUNWkio
KIOSK_DEFAULT_APPS_DIR=$KIOSK_DEFAULT_CONFIG_DIR/applications
KIOSK_DEFAULT_SESSIONS_DIR=$KIOSK_DEFAULT_CONFIG_DIR/sessions
KIOSK_DEFAULT_PROTOS_DIIR=$KIOSK_DEFAULT_CONFIG_DIR/prototypes
KIOSK_DEFAULT_TMP_DIRS="/tmp /var/tmp"    
KIOSK_DEFAULT_TEXTDOMAIN=kiosk
KIOSK_DEFAULT_TEXTDOMAINDIR=$KIOSK_PREFIX/lib/locale

KIOSK_DEFAULT_LOGPRI_ERROR=error
KIOSK_DEFAULT_LOGPRI_WARN=warn
KIOSK_DEFAULT_LOGPRI_NOTICE=notice
KIOSK_DEFAULT_LOGPRI_INFO=info
KIOSK_DEFAULT_LOGPRI_DEBUG=debug
KIOSK_DEFAULT_LOG_FACILITY=user

KIOSK_LOGPRI_ERROR=${KIOSK_LOGPRI_ERROR:-$KIOSK_DEFAULT_LOGPRI_ERROR}
KIOSK_LOGPRI_WARN=${KIOSK_LOGPRI_WARN:-$KIOSK_DEFAULT_LOGPRI_WARN}
KIOSK_LOGPRI_NOTICE=${KIOSK_LOGPRI_NOTICE:-$KIOSK_DEFAULT_LOGPRI_NOTICE}
KIOSK_LOGPRI_INFO=${KIOSK_LOGPRI_INFO:-$KIOSK_DEFAULT_LOGPRI_INFO}
KIOSK_LOGPRI_DEBUG=${KIOSK_LOGPRI_DEBUG:-$KIOSK_DEFAULT_LOGPRI_DEBUG}
KIOSK_LOG_FACILITY=${KIOSK_LOG_FACILITY:-$KIOSK_DEFAULT_LOG_FACILITY}

KIOSK_RESULT_SUCCESS=0
KIOSK_RESULT_FAILED=1

KIOSK_FALSE=0
KIOSK_TRUE=1

# Determine where logger is - distros don't agree
KIOSK_LOGGER_=
if [ -x /usr/bin/logger ] ; then 
	KIOSK_LOGGER_=/usr/bin/logger
elif [ -x /bin/logger ] ; then 
	KIOSK_LOGGER_=/bin/logger
else
	# No logger found - just don't log
	echo 1>&2 "kiosk:utils: Cannot log to syslog - no logger found"
	KIOSK_LOGGER_=/bin/true
fi	

#
## Do a full clean up for a Kiosk user. This includes
##  - kill off any processes owned by the user
##  - remove any residual temporary files owned by the user
##  - remove the user's home directory
##
## param _inModule
##  the module name of the calling module
##
## param _inUser
##  the name of the user for which the clean up should be done
##
## param _inHome
##  the home directory of the user for which the clean up should be done
##
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED otherwise
##
## Note: parameters are not checked
## Note: this function continues thru. each of the stages mentioned above
##       regardless of an error ocurring
#
cleanup()
{
 _inModule=$1
 _inUser=$2
 _inHome=$3

 theRC=$KIOSK_RESULT_SUCCESS
 cleanupProcesses $_inModule $_inUser
 if [ $? -ne $KIOSK_RESULT_SUCCESS ] ; then
  theRC=$KIOSK_RESULT_FAILED
 fi
 cleanupHome $_inModule $_inHome
 if [ $? -ne $KIOSK_RESULT_SUCCESS ] ; then
  theRC=$KIOSK_RESULT_FAILED
 fi
 cleanupTempFiles $_inModule $_inUser
 if [ $? -ne $KIOSK_RESULT_SUCCESS ] ; then
  theRC=$KIOSK_RESULT_FAILED
 fi
 return $theRC
}

#
## Remove the home directory of a Kiosk user
##
## param _inModule
##  the module name of the calling module
##
## param _inHome
##  the home directory to be removed
##
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED otherwise
##
## Note: parameters are not checked
#
cleanupHome()
{
 _inModule=$1
 _inHome=$2

logDebug -m "$_inModule" -l "removing Kiosk home directory '$_inHome'"

 if [ -d "$_inHome" ] ; then
 /bin/rm -rf "$_inHome"
 if [ $? -ne 0 ] ; then
  logError -m "$_inModule" \
           -l "Error: failed to remove Kiosk home directory '$_inHome'"
  return $KIOSK_RESULT_FAILED
 else
  logDebug -m "$_inModule" \
     	   -l "Success: removed Kiosk home directory '$_inHome'"
  return $KIOSK_RESULT_SUCCESS
 fi
else
  logDebug -m "$_inModule" \
      	   -l "Success: Kiosk home directory '$_inHome' does not exist"
  return $KIOSK_RESULT_SUCCESS
fi
}

#
## Kill processes for a given user
##
## param _inModule
##  the module name of the calling module
##
## param _inUser
##  the name of the user whose processes should be killed
##
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED otherwise
##
## Note: parameters are not checked
#
cleanupProcesses()
{
 _inModule=$1
 _inUser=$2
 msg=

 logDebug -m "$_inModule" -l "killing processes for user '$_inUser'"

 pids=`/usr/bin/pgrep -U "$_inUser"`
 if [ -z "$pids" ] ; then
  logDebug -m "$_inModule" \
      	   -l "Success: no running processes for user '$_inUser'"
  return $KIOSK_RESULT_SUCCESS
 fi

 if [ -x /usr/bin/prun ] ; then
  /usr/bin/prun $pids
 else
  kill -CONT $pids
 fi

 msg="`/usr/bin/pkill -U $_inUser 2>&1`" 
 if [ $? -eq 0 ] ; then
  logDebug -m "$_inModule" -l "Success: killed processes for user '$_inUser'"
  return $KIOSK_RESULT_SUCCESS
 else
  logError -m "$_inModule" \
           -l "Error: failed to kill processes for user '$_inUser': $msg"
  return $KIOSK_RESULT_FAILED
 fi
}

#
## Remove any temporary files & directories owned by a given Kiosk user
##
## param _inModule
##  the module name of the calling module
##
## param _inUser
##  the user whose temporary files should be removed
##
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED otherwise
##
## Note: parameters are not checked
## Note: removing parameters in KIOSK_TMP_DIRS
#
cleanupTempFiles()
{
 _inModule=$1
 _inUser=$2
 errorSeen=0

 logDebug -m "$_inModule" \
      -l "removing temporary files and directories for user '$_inUser'"
 /usr/bin/find ${KIOSK_TMP_DIRS:-$KIOSK_DEFAULT_TMP_DIRS} -user $_inUser \
				! -type d -exec /bin/rm -f {} \; 2>/dev/null
 if [ $? -ne 0 ] ; then
  # CR 6602248 find exit code is unreliable to detect non-fulfillment
  # More checks below
  errorSeen=1
 fi

 /usr/bin/find ${KIOSK_TMP_DIRS:-$KIOSK_DEFAULT_TMP_DIRS} -user $_inUser \
				-depth -exec /bin/rmdir {} \; 2>/dev/null
 if [ $? -ne 0 ] ; then
  errorSeen=1
 fi

 if [ $errorSeen -ne 0 ] ; then
  # Extra check: if we have seen errors, we check for lost files
  # Don't fail, if we leave directories: 
  # They might be shared-use (like .ICE-unix) and 
  # directory existence should not be security relevant  
  leaked="`/usr/bin/find ${KIOSK_TMP_DIRS:-$KIOSK_DEFAULT_TMP_DIRS} \
                         -user $_inUser -type f 2>/dev/null`"
  if [ -n "$leaked" ] ; then
   logError -m "$_inModule" \
    -l "Error: failed to remove some temporary files for user '$_inUser':
$leaked"
   return $KIOSK_RESULT_FAILED
  fi

  # Extra check: warn about anything else lost (directories, etc)
  leaked="`/usr/bin/find ${KIOSK_TMP_DIRS:-$KIOSK_DEFAULT_TMP_DIRS} \
		     -user $_inUser 2>/dev/null`"
  if [ -n "$leaked" ] ; then
   logWarning -m "$_inModule" \
    -l "Warning: failed to remove some temporary objects for user '$_inUser':
$leaked"
   return $KIOSK_RESULT_SUCCESS
  fi
 fi 

 logDebug -m "$_inModule" \
       -l "Success: removed temporary files and directories for user '$_inUser'"
 return $KIOSK_RESULT_SUCCESS
}

#
## Create home directory for a Kiosk user and "install" the user prototype
##
## param _inModule
##  the module name of the calling module
##
## param _inUser
##  the user whose home directory should be created
##
## param _inGroup
##  the primary group of $_inUser
##
## param _inHome
##  the home directory to be created
##
## param _inPrototype
##  the user prototype to be "installed"
##
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED otherwise
##
## Note: parameters are not checked
#
createHome()
{
 _inModule=$1
 _inUser=$2
 _inGroup=$3
 _inHome=$4
 _inProto=$5

 logDebug -m "$_inModule" \
      -l "creating home directory '$_inHome' for user '$_inUser'"

 if [ -d $_inHome ] ; then
  logError -m "$_inModule" -l "Error: directory '$_inHome' already exists"
  return $KIOSK_RESULT_FAILED
 fi

 /bin/mkdir -p $_inHome && chown $_inUser:$_inGroup $_inHome && chmod 755 $_inHome
 if [ $? -ne 0 ] ; then
  logError -m "$_inModule" -l "Error: failed to create directory '$_inHome'"
  return $KIOSK_RESULT_FAILED
 fi

 installPrototype $_inModule $_inProto $_inHome $_inUser $_inGroup
}

#
## Read a config file, checking if it can be read first 
## and reporting any errors
##
## param _inModule
##  the module name of the calling module 
##
## param _inFile
##  the file to be read
##
## param 2...n
##  additional flags (-e/-E) or filters to readcfg
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED if _inFile can't be read or 
##			       if reading _inFile fails
##
## Note: parameters are not checked
#
readConfigFile()
{
 _inModule=$1
 _inFile=$2
 shift 2

 logDebug -m "$_inModule" -l "reading config file '$_inFile'"
 if [ ! -r "$_inFile" ] ; then
  # Non-existence of the file
  logDebug -m "$_inModule" -l "Error: can't read file '$_inFile'"
  return $KIOSK_RESULT_FAILED
 fi
 eval `$KIOSK_LIB_DIR/readcfg -xs -f "$_inFile" -E KIOSK_ "$@"` 
 if [ $? -ne 0 ] ; then
  logDebug -m "$_inModule" -l "Error: failed to read config file '$_inFile'"
  return $KIOSK_RESULT_FAILED
 else
  logDebug -m "$_inModule" -l "Success: read config file '$_inFile'"
  return $KIOSK_RESULT_SUCCESS
 fi
}

#
## Read a value  from a config file, checking if it can be read first 
##  and reporting any errors
##
## param _inModule
##  the module name of the calling module 
##
## param _inFile
##  the file to be read
##
## param 2...n
##  additional flags (-e/-E) to readcfg and the value(s) to be read
##  reading multiple values in unreliable, unless they are all guaranteed 
##   to be present
##
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED if _inFile can't be read or 
##			       if reading _inFile fails
##
## Note: parameters are not checked
#
readConfigValue()
{
 _inModule=$1
 _inFile=$2
 shift 2

 logDebug -m "$_inModule" -l "reading value from config file '$_inFile'"
 if [ ! -r "$_inFile" ] ; then
  logDebug -m "$_inModule" -l "Error: can't read file '$_inFile'"
  return $KIOSK_RESULT_FAILED
 fi
 $KIOSK_LIB_DIR/readcfg -xk -f "$_inFile" -E KIOSK_ "$@" 
 if [ $? -ne 0 ] ; then
  logDebug -m "$_inModule" -l "Error: failed to read config file '$_inFile'"
  return $KIOSK_RESULT_FAILED
 else
  logDebug -m "$_inModule" -l "Success: read config file '$_inFile'"
  return $KIOSK_RESULT_SUCCESS
 fi
}


#
## Normalize a display name to a standard form
##
## param _inModule
##  the module name of the calling module 
##
## param _inDisplay
##  the display name to normalize
##
## outputs the normalized display name or 
##         nothing, if _inDisplay is not a valid display name
##
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED if _inDisplay is not a valid display name
##
#
normalizeDisplay()
{
 _inDisplay=$1
 
# Normalize host part
 case $_inDisplay in
  localhost:*) theReducedDisplay=`echo $_inDisplay | /bin/sed 's/^localhost//'` ;;
  unix:*)      theReducedDisplay=`echo $_inDisplay | /bin/sed 's/^unix//'` ;;
  *:*)	       theReducedDisplay=$_inDisplay ;;
  *)	       return $KIOSK_RESULT_FAILED ;; # invalid display name
 esac 

#strip screen part if present and check that the display number is numeric 
 echo $theReducedDisplay | 
 	/bin/sed -n \
		 -e '/^.*:[0-9][0-9]*$/p' \
		 -e 's/^\(.*:[0-9][0-9]*\)\.[0-9][0-9]*/\1/p' 
}

#
## Create an application descriptor based on an executable
##
## This function accepts the path to an executable and creates an application
## descriptor reflecting same. The resulting descriptor can be "launched"
## using the kioskapplaunch utility.
##
## param _inModule
##  the module name of the calling module
##
## param _inExec
##  the path to the executable for which a descriptor should be created
##
## param _inDesc
##  the path to the descriptor to be created
##
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED if creating the descriptor fails
##
## Note: parameters are not checked
## Note: the parent directory of _inDesc is automatically created if it doesn't
##       already exist
#
execToApplicationDescriptor()
{
 _inModule=$1
 _inExec=$2
 _inDesc=$3

 logDebug -m "$_inModule" \
       -l "creating descriptor '$_inDesc' for executable '$_inExec'"
 /bin/mkdir -p `/usr/bin/dirname "$_inDesc"` &&
 app_label=`/bin/basename "$_inExec"`
 app_desc="Temporary descriptor created for executable '$_inExec'"
 cat << ! > "$_inDesc"
KIOSK_APP_EXEC=$_inExec
KIOSK_APP_LABEL=$app_label
KIOSK_APP_DESCRIPTION=$app_desc
!
 if [ $? -ne 0 ] ; then
  logError -m "$_inModule" \
    -l "Error: failed to create descriptor '$_inDesc' for executable '$_inExec'"
  return $KIOSK_RESULT_FAILED
 fi
 return $KIOSK_RESULT_SUCCESS
}

#
## Install a specified prototype in a specified location
##
## param _inModule
##  the module name of the calling module
##
## param _inPrototypeName
##  the prototype name ( as it appears in a Session Descriptor )
##
## param _inTargetDir
##  the directory where the prototype should be "installed"
##
## param _inUser
##  the user who should own the resulting files
##
## param _inGroup
##  the group that should own the resulting files
##
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED otherwise
##
## Note: parameters are not checked
#
installPrototype()
{
 _inModule=$1
 _inPrototypeName=$2
 _inTargetDir=$3
 _inUser=$4
 _inGroup=$5

 logDebug -m "$_inModule" \
          -l "installing prototype '$_inPrototypeName' for user '$_inUser'"

 if [ ! -d "$_inTargetDir" ] ; then
  logError -m "$_inModule" \
           -l "Error: target directory '$_inTargetDir' doesn't exist"
  return $KIOSK_RESULT_FAILED
 fi

 isAbsolutePath $_inPrototypeName
 if [ $? -eq $KIOSK_TRUE ] ; then
  _thePrototyeDir=$_inPrototypeName
 else
  _thePrototyeDir=$KIOSK_PROTOS_DIR/$_inPrototypeName
 fi
 if [ ! -d "$_thePrototyeDir" ] ; then
  logError -m "$_inModule" \
           -l "Error: prototype directory '$_thePrototyeDir' doesn't exist"
  return $KIOSK_RESULT_FAILED
 fi
 
 ( cd "$_thePrototyeDir" && tar cf - . |
  ( cd "$_inTargetDir" && tar xf - ) && 
      /bin/chown -R $_inUser:$_inGroup "$_inTargetDir")
 if [ $? -eq 0 ] ; then
  logDebug -m "$_inModule" -l "Success: installed prototype"
  return $KIOSK_RESULT_SUCCESS
 else
  logError -m "$_inModule" -l "Error: failed to install prototype"
  return $KIOSK_RESULT_FAILED
 fi
}

#
## Load an Application Descriptor
##
## param _inModule
##  the module name of the calling module
##
## param _inName
##  the name of the application for which the Descriptor should be loaded
##
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED otherwise
##
## Note: parameters are not checked
## Note: all known Kiosk application settings are unset before reading the
##       relevant Application Descriptor. This allows the function to be
##       called multiple times while ensuring that settings from a previous
##       call ( for a different application ) are not inherited. The list of
##       settings handled in this way is ...
##       KIOSK_APP_EXEC, KIOSK_APP_ARGS, KIOSK_APP_PROTOTYPE
##       KIOSK_APP_LABEL, KIOSK_APP_DESCRIPTION, KIOSK_APP_ICON
##       KIOSK_APP_PRE, KIOSK_APP_POST, 
##	 KIOSK_APP_TEXTDOMAIN, KIOSK_APP_TEXTDOMAINDIR
#
loadApplicationDescriptor()
{
 _inModule=$1
 _inAppName=$2

 logDebug -m "$_inModule" \
          -l "loading Application Descriptor for '$_inAppName'"


 unset KIOSK_APP_EXEC KIOSK_APP_ARGS KIOSK_APP_PROTOTYPE
 unset KIOSK_APP_LABEL KIOSK_APP_DESCRIPTION KIOSK_APP_ICON
 unset KIOSK_APP_PRE KIOSK_APP_POST
 unset KIOSK_APP_TEXTDOMAIN KIOSK_APP_TEXTDOMAINDIR

 if [ "${USER+u}${HOME+h}${DISPLAY+d}" != "uhd" ] ; then
  logError -m "$_inModule" \
      -l "Error: incomplete session environment loading Application Descriptor"
  return $KIOSK_RESULT_FAILED
 fi
 _envopts="-e USER -e HOME -e DISPLAY"

 #
 ## Figure out Application Descriptor file based on $_inAppName
 #
 _theAppDescriptorFile=`appNameToDescriptorFile "$_inAppName"`

 #
 ## Load the Application Descriptor
 #
 readConfigFile "$_inModule" "$_theAppDescriptorFile" $_envopts "KIOSK_APP_*"
 if [ $? -ne $KIOSK_RESULT_SUCCESS ] ; then
  logError -m "$_inModule" -l "Error: failed to load Application Descriptor"
  return $KIOSK_RESULT_FAILED
 else
  logDebug -m "$_inModule" -l "Success: loaded Application Descriptor"
  return $KIOSK_RESULT_SUCCESS
 fi
}

#
## Activate Session Configuration for a session
##   The configuration that has been set up using kioskconfig(1M) for the 
##   given display is copied to the kiosk session directory for the 
##   given kiosk user account.
##   This copy prevents inconsistencies that could occur if kioskconfig is 
##   used to change configuration for furture sessions while a kiosk session 
##   is active.
##   This function should usually be called only from initsession and assumes 
##   a sane $PATH.
##
## param _inModule
##  the module name of the calling module
##
## param _inUser
##  the user name of the kiosk account to use for the target session
##
## param _inDisplay
##  the display for the target session and whose configuration is to be used.
##
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED otherwise
##
## Note: parameters are not checked
#
activateSessionConfiguration()
{
 _inModule=$1
 _inUser=$2
 _inDisplay=$3

 theDisplayConfigFile=$KIOSK_VAR_DIR/config/$_inDisplay 
 theSessionUserDynDir=$KIOSK_DYN_DIR/sessions/$_inUser
 theSessionConfigFile=$theSessionUserDynDir/session.conf

 logDebug -m "$_inModule" \
      -l "Staging Session Configuration of display '$_inDisplay' for $_inUser"

 rm -f $theSessionConfigFile

 if [ -r $theDisplayConfigFile ] ; then
  cp $theDisplayConfigFile $theSessionConfigFile 
  if [ $? -ne 0 ] ; then
   logError -m "$_inModule" \
      -l "Error: could not create file $theSessionConfigFile"
   return $KIOSK_RESULT_FAILED     
  fi
 else 
   logError -m "$_inModule" \
      -l "Error: no kiosk session configured - missing file $theDisplayConfigFile"
   return $KIOSK_RESULT_FAILED     
 fi	

 return $KIOSK_RESULT_SUCCESS
}

#
## Load the Session Descriptor for the current session
##   The configuration must have been activated before
##
## param _inModule
##  the module name of the calling module
##
## Environment: 
##  USER
##       the user account for the current session
##  HOME
##       the home directory of the current session
##  DISPLAY
##       the display for the current session
##
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED otherwise
##
## Note: parameters are not checked
##
## Note 2: For backward compatibility we ignore a second argument
##        (this used to be the display, but running without $DISPLAY or $USER 
##         set was never supported)
#
loadSessionConfiguration()
{
 _inModule=$1
 
 theSessionUserDynDir=$KIOSK_DYN_DIR/sessions/$USER
 theSessionConfigFile=$theSessionUserDynDir/session.conf

 if [ -r $theSessionConfigFile ] ; then  
  loadSessionConfigurationFromFile "$_inModule" $theSessionConfigFile
 else
  # Don't log an error - this might be called in a non-kiosk session context
  logDebug -m "$_inModule" \
    -l "Cannot load kiosk session configuration: No session activated - missing file $theSessionConfigFile"
 fi 
}


#
## Load the Session Descriptor for the current session
##   The current configuration is read from the provided file
##
## param _inModule
##  the module name of the calling module
##
## param _inConfigFile
##  the file name of the session configuration file
##
## Environment: 
##  USER
##       the user account for the current session
##  HOME
##       the home directory of the current session
##  DISPLAY
##       the display for which the Session Descriptor should be loaded
##
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED otherwise
##
## Note: parameters are not checked
#
loadSessionConfigurationFromFile()
{
 _inModule=$1
 _inConfigFile=$2

 logDebug -m "$_inModule" \
          -l "loading Session Configuration from file '$_inConfigFile'"

 #
 ## Set up supported environment variables for use in config resolution
 #
 export KIOSK_CONFIG_DIR
 export KIOSK_SESSIONS_DIR
 export KIOSK_APPS_DIR
 export KIOSK_PROTOS_DIR
 export KIOSK_TEXTDOMAIN
 export KIOSK_TEXTDOMAINDIR

 if [ "${USER+u}${HOME+h}${DISPLAY+d}" != "uhd" ] ; then
  logError -m "$_inModule" \
      -l "Error: incomplete environment loading Session Descriptor"
  return $KIOSK_RESULT_FAILED
 fi
 _envopts="-e USER -e HOME -e DISPLAY"

 #
 ## Load the Kiosk Session Configuration first to figure out KIOSK_ENABLED and
 ## KIOSK_SESSION
 #
 enableVal=`readConfigValue "$_inModule" "$_inConfigFile" KIOSK_ENABLED`
 if [ $? -ne $KIOSK_RESULT_SUCCESS ] ; then
  return $KIOSK_RESULT_FAILED
 fi

 #
 ## Don't continue any further if Kiosk is not enabled
 #
 if [ "x$enableVal" != "xyes" ] ; then
  logError -m "$_inModule" \
           -l "Error: Kiosk is not enabled for display '$_inDisplay'"
  return $KIOSK_RESULT_FAILED
 fi

 #
 ## Next verify that KIOSK_SESSION has been set
 ## (KIOSK_SESSION must depend at most on DISPLAY)
 #
 kioskSession=`readConfigValue "$_inModule" \
 		"$_inConfigFile" -e DISPLAY KIOSK_SESSION`
 if [ -z "$kioskSession" ] ; then
  logError -m "$_inModule" -l "Error: \$KIOSK_SESSION not specified"
  return $KIOSK_RESULT_FAILED
 fi

 #
 ## Figure out Kiosk Session Descriptor file based on $KIOSK_SESSION
 #
 _theSessionDescriptorFile=`sessionNameToDescriptorFile "$kioskSession"`

 #
 ## Set KIOSK_SESSION_DIR relative to Kiosk Session Descriptor file,
 ## if it wasn't set before and exists
 #
 if [ -z "$KIOSK_SESSION_DIR" ] ; then
   _theSessionDir=`echo $_theSessionDescriptorFile | 
		   /bin/sed 's/\.[A-Za-z]*$//'`
   if [ -d "$_theSessionDir" ] ; then
     KIOSK_SESSION_DIR="$_theSessionDir"
   fi     
 fi		     
 export KIOSK_SESSION_DIR

 #
 ## Next, load the Kiosk Session Descriptor
 #
 readConfigFile "$_inModule" "$_theSessionDescriptorFile" \
 					$_envopts KIOSK_SESSION_*
 if [ $? -ne $KIOSK_RESULT_SUCCESS ] ; then
  logError -m "$_inModule" -l "Error: failed to load Session Descriptor"
  return $KIOSK_RESULT_FAILED
 fi

 #
 ## Finally, to allow Kiosk Session configuration to  
 ## override the Kiosk Session Descriptor, we load 
 ## the Session configuration (again).
 #
 readConfigFile "$_inModule" "$_inConfigFile" $_envopts KIOSK_SESSION_*
 if [ $? -ne $KIOSK_RESULT_SUCCESS ] ; then
  logError -m "$_inModule" -l "Error: failed to load Session Configuration"
  return $KIOSK_RESULT_FAILED
 fi
 logDebug -m "$_inModule" \
          -l "Success: Session Configuration for display '$_inDisplay' loaded"
 return $KIOSK_RESULT_SUCCESS
}

#
## Some logging functions which simply wrap the syslog function
#
logDebug()
{
 if [ "${KIOSK_DEBUG:-0}" != "0" ] ; then
     syslog -p ${KIOSK_LOG_FACILITY}.${KIOSK_LOGPRI_DEBUG} "$@"
 fi 	 
}
logError()
{
 syslog -p ${KIOSK_LOG_FACILITY}.${KIOSK_LOGPRI_ERROR} "$@"
}
logInfo()
{
 syslog -p ${KIOSK_LOG_FACILITY}.${KIOSK_LOGPRI_INFO} "$@"
}
logWarning()
{
 syslog -p ${KIOSK_LOG_FACILITY}.${KIOSK_LOGPRI_WARN} "$@"
}

# 
## Make the KIOSK_DYN_DIR directory
#
## param _inModule
##  the module name of the calling module
##
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED otherwise
##
## Note: parameters are not checked
#
makeKioskDynDir() 
{
 _inModule=$1

 # Set up the /var/run/opt directory with proper attributes
 theVarRunOptDir=`/usr/bin/dirname $KIOSK_DYN_DIR`
 if [ ! -d $theVarRunOptDir ] ; then
  theOS=`uname`
  if [ "$theOS" = "Linux" ] ; then
   theSysdirGroup=root
  else
   theSysdirGroup=sys
  fi
  /bin/mkdir -m 755 $theVarRunOptDir 
  if [ $? -eq 0 ] ; then
   # Set correct group ownership
   /bin/chgrp $theSysdirGroup $theVarRunOptDir
   if [ $? -ne 0 ] ; then
    logError -m "$_inModule" \
	       -l "Error: failed to set up directory '$theVarRunOptDir'"
    rmdir "$theVarRunOptDir"	      
    return $KIOSK_RESULT_FAILED
   fi
  elif [ ! -d $theVarRunOptDir ] ; then # maybe someone else beat us to this
   logError -m "$_inModule" \
              -l "Error: failed to create directory '$theVarRunOptDir'"
   return $KIOSK_RESULT_FAILED
  fi
 fi
 # KIOSK_DYN_DIR should be a child of /var/run/opt
 # but to be safe, we mkdir -p anyways
 if [ ! -d $KIOSK_DYN_DIR ] ; then
  /bin/mkdir -p -m 755 $KIOSK_DYN_DIR
  if [ $? -eq 0 ] ; then
   logDebug -m "$_inModule"  -l "Success: created directory '$KIOSK_DYN_DIR'"
   return $KIOSK_RESULT_SUCCESS 
  elif [ ! -d $KIOSK_DYN_DIR ] ; then # recheck to guard against races 
   logError -m "$_inModule" \
	    -l "Error: failed to create directory '$KIOSK_DYN_DIR'"
   return $KIOSK_RESULT_FAILED
  fi 
 fi
 # We rely on valid permissions for existing directories.
 # All ancestry of KIOSK_DYN_DIR is supposed to be writable only for root
 logDebug -m "$_inModule"  -l "Success: directory '$KIOSK_DYN_DIR' already exists"
 return $KIOSK_RESULT_SUCCESS 
}

#
## Create the dynamic data dir for a given session 
## (identified by the user name)
##
## param _inModule
##  the module name of the calling module
##
## param _inUser
##  the user for whom the dir should be created
##
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED otherwise
##
## Note: parameters are not checked
#
makeDynDir()
{
 _inModule=$1
 _inUser=$2

 makeKioskDynDir "$_inModule"
 if [ $? -ne 0 ] ; then
  return $KIOSK_RESULT_FAILED
 fi 

 theSessionsDynDir=$KIOSK_DYN_DIR/sessions
 theSessionUserDynDir=$theSessionsDynDir/$_inUser
 if [ ! -d $theSessionUserDynDir ] ; then
  if [ ! -d $theSessionsDynDir ] ; then
   /bin/mkdir -m 755 $theSessionsDynDir 
   if [ $? -eq 0 ] ; then
    logDebug -m "$_inModule"  -l "Success: created directory '$theSessionsDynDir'"
   elif [ ! -d $theSessionsDynDir ] ; then # recheck to guard against races 
    logError -m "$_inModule" -l "Error: failed to create directory '$theSessionsDynDir'"
    return $KIOSK_RESULT_FAILED
   fi
  fi 

  /bin/mkdir -m 755 $theSessionUserDynDir 
  if [ $? -ne 0 ] ; then
   # no need to guard against races here: there should only ever be one active 
   # session for a given user that attempts to do this.
   logError -m "$_inModule" -l "Error: failed to create directory '$theSessionUserDynDir'"
   return $KIOSK_RESULT_FAILED
  fi
  logDebug -m "$_inModule"  -l "Success: created directory '$theSessionUserDynDir'"
 else
  logDebug -m "$_inModule"  -l "Success: directory '$theSessionUserDynDir' already exists"
 fi 
 return $KIOSK_RESULT_SUCCESS 
}

#
## Remove the dynamic data dir for a given user
##
## param _inModule
##  the module name of the calling module
##
## param _inUser
##  the user for whom the dir should be created
##
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED otherwise
##
## Note: parameters are not checked
#
removeDynDir()
{
 _inModule=$1
 _inUser=$2

 theSessionsDynDir=$KIOSK_DYN_DIR/sessions
 theSessionUserDynDir=$theSessionsDynDir/$_inUser

 /bin/rm -rf $theSessionUserDynDir
 if [ $? -ne 0 ] ; then
  logError -m $_inModule -l "Error: failed to remove directory '$theSessionUserDynDir'"
  return $KIOSK_RESULT_FAILED
 fi
 logDebug -m $_inModule -l "Success: removed directory '$theSessionUserDynDir'"

 # Also remove $theSessionDynDir if it has become empty (ignore result)
 /bin/rmdir $theSessionsDynDir 2>/dev/null &&
     logDebug -m $_inModule -l "Success: removed directory '$theSessionsDynDir'"

 return $KIOSK_RESULT_SUCCESS
}

#
## Iterate over the configured Kiosk Application List, calling the configured
## Kiosk Session specific application launcher for each entry found.
## The intention is that Kiosk Primary Sessions don't need to have any
## knowledge of the format of application lists and the Kiosk framework doesn't
## need to have any knowledge of primary session specific requirements for
## configuring, launching etc. Kiosk applications.
##
## param _inModule
##  the module name of the calling module
##
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED otherwise
##
## Note: parameters are not checked
#
processApplicationList()
{
 _inModule=$1
 
 logDebug -m "$_inModule" -l "processing application list"

 # TODO: (Re)load only APPLIST and APPLAUNCHER
 loadSessionConfiguration "$_inModule" 
 if [ $? -ne $KIOSK_RESULT_SUCCESS ] ; then
  logError -m "$_inModule" \
     -l "Error: failed to load application information from session descriptor"
  return $KIOSK_RESULT_FAILED
 fi
 
 if [ -z "$KIOSK_SESSION_APPLIST" ] ; then
  return $KIOSK_RESULT_SUCCESS
 fi
 
 if [ -z "$KIOSK_SESSION_APPLAUNCHER" ] ; then
  logError -m "$_inModule" -l "Error: \$KIOSK_SESSION_APPLAUNCHER is not set"
  return $KIOSK_RESULT_FAILED
 fi
 
 if [ ! -x "$KIOSK_SESSION_APPLAUNCHER" ] ; then
  logError -m "$_inModule" \
     -l "Error: Kiosk application launcher '$KIOSK_SESSION_APPLAUNCHER' does not exist or cannot be executed"
  return $KIOSK_RESULT_FAILED
 fi
 
 _theAppListFile=`appListNameToAppListFile "$KIOSK_SESSION_APPLIST"`
 if [ ! -f "$_theAppListFile" ] ; then
  logError -m "$_inModule" \
     -l "Error: the Kiosk application list file '$_theAppListFile' was not found"
  return $KIOSK_RESULT_FAILED
 fi
 /bin/cat "$_theAppListFile" |
  processApplicationListFile $_inModule "$KIOSK_SESSION_APPLAUNCHER"
}

#
## Execute the configured Kiosk Application Launcher for each entry in the
## configured Kiosk Application List
##
## param _inModule
##  the module name of the calling module
##
## param _inAppLauncher
##  the Kiosk Application Launcher
##
## returns KIOSK_RESULT_SUCCESS on success
##         KIOSK_RESULT_FAILED otherwise
##
## Note: parameters are not checked
#
processApplicationListFile()
{
 _inModule=$1
 _inAppLauncher=$2

 theRC=$KIOSK_RESULT_SUCCESS
 while read _inAppListEntry ; do
  #
  ## Skip blank lines
  #
  if [ -n "$_inAppListEntry" ] ; then
   _theType=`echo $_inAppListEntry    | /usr/bin/awk 'BEGIN{ FS=":" } { print $1 }'`
   _theAppName=`echo $_inAppListEntry | /usr/bin/awk 'BEGIN{ FS=":" } { print $2 }'`
   _theMode=`echo $_inAppListEntry    |
     /usr/bin/awk 'BEGIN{ FS=":" } { print substr( $3, 0, index($3,";" )-1 ) }'`
   _theArgs=`echo $_inAppListEntry    | /usr/bin/awk 'BEGIN{ FS=";" } { print $2 }'`
   if [ -z "$_theType" -o -z $"_theAppName" -o -z $"_theMode" ] ; then
    theRC=$KIOSK_RESULT_FAILED
    logError -m "$_inModule" \
             -l "Error: invalid application list entry '$_inAppListEntry' found"
    break
   fi
   "$_inAppLauncher" "$_theType" "$_theAppName" "$_theMode" "$_theArgs"
   if [ $? -ne 0 ] ; then
    theRC=$KIOSK_RESULT_FAILED
    logError -m "$_inModule" \
            -l "Error: command '$_inAppLauncher $_theType $_theAppName $_theMode $_theArgs' failed"
    break
   fi
  fi
 done
 return $theRC
}

#
## The next 4 functions are used to convert session or application names into
## descriptor paths and application list names to application list file paths
#
isAbsolutePath()
{
 _inName=$1
 _isAbsolute=`echo $_inName |
	/usr/bin/awk '{
		if ( index( $0, "/" ) == 1 )
		{
			print "true"
		}
		else
		{
			print "false"
		}
	}'`
 if [ $_isAbsolute = "true" ] ; then
  return $KIOSK_TRUE
 else
  return $KIOSK_FALSE
 fi
}
appListNameToAppListFile()
{
 _inName=$1
 isAbsolutePath "$_inName"
 if [ $? -eq $KIOSK_TRUE ] ; then
  echo $_inName
 else
  echo $KIOSK_APPS_DIR/$_inName.list
 fi
}
appNameToDescriptorFile()
{
 _inName=$1
 isAbsolutePath "$_inName"
 if [ $? -eq $KIOSK_TRUE ] ; then
  echo $_inName
 else
  echo $KIOSK_APPS_DIR/$_inName.conf
 fi
}
sessionNameToDescriptorFile()
{
 _inName=$1
 isAbsolutePath "$_inName"
 if [ $? -eq $KIOSK_TRUE ] ; then
  echo $_inName
 else
  echo $KIOSK_SESSIONS_DIR/$_inName.conf
 fi
}

#
## Launch a critical application
##
## param _inModule
##  the module name of the calling module
##
## param _inApp
##  the application to be registered
##
## param _inArgs
##  the application arguments
##
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED otherwise
##
## Note: parameters are not checked
#
launchCriticalApp()
{
 _inModule=$1
 shift

 if [ -z "$USER" ] ; then
  logError -m "$_inModule" -l "Error: \$USER not specified"
  return $KIOSK_RESULT_FAILED
 fi
 
 launchCriticalAppForUser "$_inModule" "$USER" "$@"
}

#
## Launch a critical application
##
## param _inModule
##  the module name of the calling module
##
## param _inApp
##  the application to be registered
##
## param _inArgs
##  the application arguments
##
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED otherwise
##
## Note: parameters are not checked
#
launchCriticalAppForUser()
{
 _inModule=$1
 _inUser=$2    
 _inApp=$3
 shift ; shift ; shift

 logDebug -m "$_inModule" -l "launching critical application '$_inApp $@'"

 theSessionUserDynDir=$KIOSK_DYN_DIR/sessions/$_inUser
 $KIOSK_LIB_DIR/kioskcrit $theSessionUserDynDir/kioskcritd "$_inApp" "$@"
 if [ $? -ne 0 ] ; then
  logError -m "$_inModule" \
           -l "Error: failed to launch critical application '$_inApp $@'"
  return $KIOSK_RESULT_FAILED
 fi
 return $KIOSK_RESULT_SUCCESS
}

#
## Start the Critical Applications Monitor
##
## param _inModule
##  the module name of the calling module
##
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED otherwise
##
## Note: parameters are not checked
#
startCriticalAppsMonitor()
{
 _inModule=$1

 logDebug -m "$_inModule" -l "starting the Critical Applications Monitor" 

 if [ -z "$USER" ] ; then
  logError -m "$_inModule" -l "Error: \$DISPLAY or \$USER not specified"
  return $KIOSK_RESULT_FAILED
 fi

 theSessionUserDynDir=$KIOSK_DYN_DIR/sessions/$USER
 theKioskcritDir="$theSessionUserDynDir/kioskcritd"
 if [ -s "$theKioskcritDir/kioskcritd.pid" ] ; then
 	stopCriticalAppsMonitor "$_inModule"
 fi	
 /bin/rm -rf "$theKioskcritDir" && 
 	/bin/mkdir -p -m 700 "$theKioskcritDir" && 
	/bin/chown $USER "$theKioskcritDir"
 if [ $? -ne 0 ] ; then
  logError -m "$_inModule" \
           -l "failed to create directory '$theKioskcritDir'"
  return $KIOSK_RESULT_FAILED
 fi
 $KIOSK_LIB_DIR/kioskcritd "$theKioskcritDir" $USER
 if [ $? -ne 0 ] ; then
  logError -m "$_inModule" \
      	   -l "failed to start the Critical Applications Monitor"
  return $KIOSK_RESULT_FAILED
 fi
 return $KIOSK_RESULT_SUCCESS
}

#
## Stop the Critical Applications Monitor
##
## param _inModule
##  the module name of the calling module
##
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED otherwise
##
## Note: parameters are not checked
#
stopCriticalAppsMonitor()
{
 _inModule=$1

 logDebug -m "$_inModule" -l "stopping the Critical Applications Monitor"

 if [ -z "$USER" ] ; then
  logError -m "$_inModule" -l "Error: \$USER not specified"
  return $KIOSK_RESULT_FAILED
 fi

 theSessionUserDynDir=$KIOSK_DYN_DIR/sessions/$USER
 thePID=`/bin/cat $theSessionUserDynDir/kioskcritd/kioskcritd.pid`
 if [ $? -eq 0 -a -n "$thePID" ] ; then
  kill $thePID
  if [ $? -ne 0 ] ; then
   logError -m "$_inModule" -l "stopping kioskcritd failed: Could not signal kioskcritd process $thePID."
  fi
 else 
  logDebug -m "$_inModule" -l "not stopping kioskcritd: No kioskcritd PID found."
 fi
 return $KIOSK_RESULT_SUCCESS
}

#
## Localize a text according to the passed in Textdomain and
## associated directory
##
## param _inText
##  the text to translate
##
## param _inTextdomain
##  the textdomain to use
##  if empty do not localize the text
##
## param _inTextdomainDir
##  optional: the locale directory to use for the textdomain
##  default:  $TEXTDOMAINDIR
##
## returns KIOSK_RESULT_SUCCESS if successful
##         KIOSK_RESULT_FAILED otherwise
##
## Note: parameters are not checked
#
localize() 
{
 typeset inText="$1"
 typeset inTextdomain="$2"
 typeset inTextdomainDir="$3"
 
 # suppress newlines
 typeset newlineopt=-n

 # Only try localizing if a textdomain is passed
 if [ -n "$inTextdomain" ] ; then
 	TEXTDOMAINDIR="${inTextdomainDir:-$TEXTDOMAINDIR}" \
	    /usr/bin/gettext $newlineopt -s -d "$inTextdomain" "$inText"
 else
 	print $newlineopt "$inText"
 fi
}

#
## Log a message to syslog ( by wrapping logger )
##
## Usage: -p <priority> -m <module> -l <message>
#
syslog()
{
 OPTIND=1
 _thePriority=user.info
 _theModule=kiosk
 _theMessage=
 while getopts p:m:l: inOpt ; do
  case $inOpt in
   p)  _thePriority="$OPTARG";;
   m)  _theModule="$OPTARG";;
   l)  _theMessage="$OPTARG";;
   \?) $KIOSK_LOGGER_ -i -p user.error \
		      -t "$_theModule" "invalid syslog argument specified"
       OPTIND=1
       return $KIOSK_RESULT_FAILED
  esac
 done
 $KIOSK_LOGGER_ -i -p "$_thePriority" -t "$_theModule" "$_theMessage"
 OPTIND=1
 return $KIOSK_RESULT_SUCCESS
}

#
## Setup basic Kiosk environment and sanity check
#
logDebug -m "kiosk:utils" -l "Reading $KIOSK_DEFAULT_CONFIG_DIR/kioskrc"
. $KIOSK_DEFAULT_CONFIG_DIR/kioskrc

KIOSK_BIN_DIR=$KIOSK_PREFIX/bin
KIOSK_LIB_DIR=$KIOSK_PREFIX/lib
KIOSK_CONFIG_DIR=${KIOSK_CONFIG_DIR:-$KIOSK_DEFAULT_CONFIG_DIR}
KIOSK_VAR_DIR=${KIOSK_VAR_DIR:-$KIOSK_DEFAULT_VAR_DIR}
KIOSK_APPS_DIR=${KIOSK_APPS_DIR:-$KIOSK_DEFAULT_APPS_DIR}
KIOSK_SESSIONS_DIR=${KIOSK_SESSIONS_DIR:-$KIOSK_DEFAULT_SESSIONS_DIR}
KIOSK_PROTOS_DIR=${KIOSK_PROTOS_DIR:-$KIOSK_DEFAULT_PROTOS_DIR}
KIOSK_DYN_DIR=/var/run/opt/SUNWkio
KIOSK_TMP_DIRS=${KIOSK_TMP_DIRS:-$KIOSK_DEFAULT_TMP_DIRS}
KIOSK_TEXTDOMAIN=${KIOSK_TEXTDOMAIN:-$KIOSK_DEFAULT_TEXTDOMAIN}
KIOSK_TEXTDOMAINDIR=${KIOSK_TEXTDOMAINDIR:-$KIOSK_DEFAULT_TEXTDOMAINDIR}

