#!/bin/ksh -p
#
# ident "@(#)utgenpam.ksh	1.36	08/07/07 SMI"
#
# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#

#
# This module configures/unconfigures the PAM stack for all of SRSS
# and replaces the preremove/postinstall actions previously performed by
# SUNWuto and SUNWutps
#
# Arg #1 DEF_OPTION specifies the option to use the entries for the "other"
#	service as the default if the specified OLDAPP is not defined. 
#	See -o option for utpamcfg.  Valid values are DEF_YES and DEF_NO.
# Arg #2 TAG_OPTION specifies if tag is desired.  Valid values are TAG_YES
#	and TAG_NO.
# Arg #3 APPNAME is the application name with the optional module type.  It
#	should be in the "<appname>[:<mod-type>]".  See utpamcfg for more info.
# Arg #4 OLDAPP is the template to be used to create the stack.
# Arg #5 STACK defines if this is an old style pam.conf (i.e. < S8) or newer
#	ones (i.e. > S9).
# Arg #6 MODULE specifies the module to be added on top of the new stack.
# Arg #7 MODOPTS specifies the options to be specified with the module.
#

PATH=/usr/bin:/bin:/usr/sbin:/sbin
export PATH

create_stack() {
    typeset DEF_OPTION="$1"
    typeset TAG_OPTION="$2"
    typeset APPNAME="$3"
    typeset OLDAPP="$4"
    typeset STACK="${5-}"
    typeset MODULE="${6-}"
    typeset MODOPTS="${7-}"

    typeset FLAGSTR=""
    if [ "$DEF_OPTION" == "DEF_NO" ]; then
	# specify the -o option to utpamcfg
   	FLAGSTR="-o"
    fi

    if [ "$TAG_OPTION" == "TAG_YES" ]; then
	# add tag
	typeset PAMCL=`print $APPNAME | sed -n -e 's/\([^:]*\).*$/\1/p'`
	FLAGSTR="$FLAGSTR -T \"$SRTAG -- $PAMCL\""
    fi

    if [ -n "$STACK" ]; then
	FLAGSTR="$FLAGSTR -n $STACK"
    fi

    typeset MODSTR=
    if [ -n "$MODULE" ]; then
	MODSTR="-m $MODULE"
    fi
    if [ -n "$MODOPTS" ]; then
	MODSTR="$MODSTR -M $MODOPTS"
    fi

    eval "$UTPAMCFG -c $APPNAME -t $OLDAPP $FLAGSTR $MODSTR"
}


#
# This module adds one entry to the top of the stack for the APPNAME specified.
#
# Arg #1 TAG_OPTION specifies if tag is desired.  Valid values are TAG_YES
#	and TAG_NO.
# Arg #2 APPNAME is the application name with the optional module type.  It
#	should be in the "<appname>[:<mod-type>]".  See utpamcfg for more info.
# Arg #3 MODULE specifies the module to be added to the top of the stack.
# Arg #4 MODOPTS specifies the options to be specified with the module.
# Arg #5 FLAG specifies the control flag to be added with the module.
#
add_module() {
    typeset TAG_OPTION="$1"
    typeset APPNAME="$2"
    typeset MODULE="$3"
    typeset MODOPTS="${4-}"
    typeset FLAG="${5-}"

    add_module_ext -a "$TAG_OPTION" "$APPNAME" "$MODULE" "$MODOPTS" "$FLAG"
}


#
# This module adds one entry to the bottom of the stack for the APPNAME specified.
#
# Arg #1 TAG_OPTION specifies if tag is desired.  Valid values are TAG_YES
#	and TAG_NO.
# Arg #2 APPNAME is the application name with the optional module type.  It
#	should be in the "<appname>[:<mod-type>]".  See utpamcfg for more info.
# Arg #3 MODULE specifies the module to be added to the bottom of the stack.
# Arg #4 MODOPTS specifies the options to be specified with the module.
# Arg #5 FLAG specifies the control flag to be added with the module.
#
append_module() {
    typeset TAG_OPTION="$1"
    typeset APPNAME="$2"
    typeset MODULE="$3"
    typeset MODOPTS="${4-}"
    typeset FLAG="${5-}"

    add_module_ext -A "$TAG_OPTION" "$APPNAME" "$MODULE" "$MODOPTS" "$FLAG"
}

#
# This is the extended add_module routine which adds one entry either to the top or
# bottom of the stack for the APPNAME specified depending the first option passed in.
# -a adds to the top and -A adds to the bottom.  These options are chosen based on
# the options from utpamcfg.
#
# Arg #1 ADD_OPTION -a adds to the top and -A adds to the bottom.
# Arg #2 TAG_OPTION specifies if tag is desired.  Valid values are TAG_YES
#	and TAG_NO.
# Arg #3 APPNAME is the application name with the optional module type.  It
#	should be in the "<appname>[:<mod-type>]".  See utpamcfg for more info.
# Arg #4 MODULE specifies the module to be added to the top or to the bottom of
#	the stack depending on the ADD_OPTION flag.
# Arg #5 MODOPTS specifies the options to be specified with the module.
# Arg #6 FLAG specifies the control flag to be added with the module.
#
add_module_ext() {
    typeset ADD_OPTION="$1"
    typeset TAG_OPTION="$2"
    typeset APPNAME="$3"
    typeset MODULE="$4"
    typeset MODOPTS="${5-}"
    typeset FLAG="${6-}"
    typeset MODSTR=""

    if [ -n "$MODOPTS" ]; then
	MODSTR="-M '$MODOPTS'"
    fi

    typeset FLAGSTR=""
    if [ "$TAG_OPTION" == "TAG_YES" ]; then
	# add tag
	typeset PAMCL=`print $APPNAME | sed -n -e 's/\([^:]*\).*$/\1/p'`
	FLAGSTR="-T \"$SRTAG -- $PAMCL\""
    fi
    if [ -n "$FLAG" ]; then
	FLAGSTR="$FLAGSTR -f $FLAG"
    fi
    eval "$UTPAMCFG $ADD_OPTION $APPNAME -m $MODULE $MODSTR $FLAGSTR"
}

#
# This module delete the PAM stack for the APPNAME specified.
#
# Arg #1 APPNAME is the application name with the optional module type.  It
#	should be in the "<appname>[:<mod-type>]".  See utpamcfg for more info.
# Arg #2 TAG_OPTION specifies if tag is desired.  Valid values are TAG_YES
#	and TAG_NO.

delete_stack() {
    typeset APPNAME="$1"
    typeset TAG_OPTION="$2"
    typeset FLAGSTR=""

    if [ "$TAG_OPTION" == "TAG_YES" ]; then
	# add tag
	typeset PAMCL=`print $APPNAME | sed -n -e 's/\([^:]*\).*$/\1/p'`
	FLAGSTR="-T \"$SRTAG -- $PAMCL\""
    fi
    eval "$UTPAMCFG -u $APPNAME $FLAGSTR"
}

add_Xserver_Class() {
    # Tell dtlogin that SunRay is a valid X server class so that
    # it can register with PAM as the client name "dtlogin-SunRay".
    # This will also take care of dtsession, which will register
    # with PAM as the client name "dtsession-SunRay".
    #
    # This requires the following bugfix to be installed:
    #	4452627 dtlogin should register with PAM using a different
    #		client name when on SunRay
    #
    # Xconfig changes that need to be preserved over reboots need
    # to be made to a prototype Xconfig file. If that file does
    # not exist, we create it.
    #
    # XXX Even more XXX, this shouldn't happen here, it should happen in the
    # XXX utacleanup init script where we do the rest of the Xconfig fixups.  

    if test -f $XCONFIG_USR_DIR/$GENERIC_XCONFIG; then
	if test ! -f $XCONFIG_ETC_DIR/$PROTO_XCONFIG ; then
	    mkdir -p $XCONFIG_ETC_DIR
	    cp $XCONFIG_USR_DIR/$GENERIC_XCONFIG $XCONFIG_ETC_DIR/$PROTO_XCONFIG
	fi

	egrep -is "$VALID_PAM_CLASS_TAG" $XCONFIG_ETC_DIR/$PROTO_XCONFIG
	if [ $? -eq 1 ]; then
	    echo "$VALID_PAM_CLASS_TAG: $SUNRAY_XSERVER_CLASS_TYPE" \
		>>$XCONFIG_ETC_DIR/$PROTO_XCONFIG
	fi
    fi
}

delete_Xserver_Class() {
    # Remove $SUNRAY_XSERVER_CLASS_TYPE from Xconfig.
    #
    # This requires the following bugfix to be installed:
    #	4452627 dtlogin should register with PAM using a different
    #		client name when on SunRay
    #
    if test -f $XCONFIG_USR_DIR/$GENERIC_XCONFIG; then
	if test -f $XCONFIG_ETC_DIR/$PROTO_XCONFIG; then
	    SCTMP="/var/run"
	    TMP="$SCTMP/$MOD.$$"
	    TMP_SR="$TMP.PAMsr"

	    egrep -is $VALID_PAM_CLASS_TAG $XCONFIG_ETC_DIR/$PROTO_XCONFIG
	    if [ $? -ne 1 ]; then
		egrep -vi "$VALID_PAM_CLASS_TAG" $XCONFIG_ETC_DIR/$PROTO_XCONFIG >$TMP_SR
		mv $TMP_SR $XCONFIG_ETC_DIR/$PROTO_XCONFIG
	    fi
	fi
    fi
}

utpam_configure() {
    if [ "$OS" = "SunOS" -a "$OS_REL" = "5.8" ]; then
	NEWSTACK=false
    else
	NEWSTACK=true
    fi

    # Note: Kiosk will not necessarily be installed ( e.g. on a TX system )
    #       so we configure it only if it's available.
    if [ $OS = "Linux" ]; then
	add_module "TAG_YES" $GDM $AMGHLIB clearuser required
	add_module "TAG_NO" $GDM $SRLIB_GU prompt required
	if [ -d $LIB_SUNWKIO ] ; then
		add_module "TAG_NO" $GDM $KIOSKLIB "log=user" requisite
		add_module "TAG_NO" $GDM $KIOSKLIB "log=user ignoreuser" sufficient
	fi
	add_module "TAG_NO" $GDM $AMGHLIB "" required
	add_module "TAG_NO" $GDM $SRLIB_GU property=username requisite
	[ -d $LIB_SUNWKIO ] &&
		add_module "TAG_NO" $GDM:session $KIOSKLIB "log=user" required
	[ -d $LIB_SUNWKIO ] &&
		add_module "TAG_NO" $GDM:account $KIOSKLIB "log=user" sufficient
	add_module "TAG_NO" $GDM $HOTDESKLIB "" requisite
	add_module "TAG_NO" $GDM:session $HOTDESKLIB "" requisite
	add_module "TAG_YES" $ADMINGUI $ADMINGUILIB "" sufficient
	if [ -f /etc/pam.d/$SYS_AUTH ]; then
	    # RHEL 3 and 4 import the system-auth stack by default
	    add_module "TAG_YES" $SELFREG $STACKLIB service=$SYS_AUTH required
	else
	    add_module "TAG_YES" $SELFREG $UNIX2LIB "" required
	fi

	# Template for hotdesk stack 
	# XXX: maybe we should search for an existing stack here?
	hdtmpl=gnome-screensaver
	# XXX: DEF_YES makes little sense, because the 'other' stack is usually 
	#      pam_deny on Linux, but the hardcoded fallback in utpamcfg is 
	#      worse
	# Copy all modules (we need auth, account and passwd)
	create_stack "DEF_YES" "TAG_YES" $HOTDESK $hdtmpl 
    else
	create_stack "DEF_YES" "TAG_YES" $XSCREENSAVER:auth other $NEWSTACK $SRLIB syncondisplay

	# we add specific "auth" type service for the dtlogin-SunRay to make sure
	# that we copy the "dtlogin auth" entries currently configured on the system
	# to dtlogin-SunRay stack.  This can either be from the "dtlogin" service
	# stack itself or from the "other" service stack if it's not defined in the
	# dtlogin stack.
	#
	create_stack "DEF_YES" "TAG_YES" $DTLOGIN dtlogin $NEWSTACK
	create_stack "DEF_YES" "TAG_NO" $DTLOGIN:auth dtlogin $NEWSTACK
	add_module "TAG_NO" $DTLOGIN:auth $AMGHLIB clearuser required
	add_module "TAG_NO" $DTLOGIN:auth $SRLIB_GU prompt requisite
	add_module "TAG_NO" $DTLOGIN:auth $SRLIB "" sufficient
	if [ -f $KIOSKLIB ] ; then
		add_module "TAG_NO" $DTLOGIN:auth $KIOSKLIB "log=user" requisite
		add_module "TAG_NO" $DTLOGIN:auth $KIOSKLIB "log=user ignoreuser" sufficient
	fi
	add_module "TAG_NO" $DTLOGIN:auth $AMGHLIB "" required
	add_module "TAG_NO" $DTLOGIN:auth $SRLIB_GU property=username requisite
	create_stack "DEF_YES" "TAG_NO" $DTLOGIN:account dtlogin $NEWSTACK
	add_module "TAG_NO" $DTLOGIN:account $SRLIB "" sufficient
	[ -f $KIOSKLIB ] &&
		add_module "TAG_NO" $DTLOGIN:account $KIOSKLIB "log=user" sufficient
	create_stack "DEF_YES" "TAG_NO" $DTLOGIN:session dtlogin $NEWSTACK
	[ -f $KIOSKLIB ] &&
		add_module "TAG_NO" $DTLOGIN:session $KIOSKLIB "log=user" required
	add_module "TAG_NO" $DTLOGIN $HOTDESKLIB "" requisite
	add_module "TAG_NO" $DTLOGIN:session $HOTDESKLIB "" requisite

	
	# we add specific "auth" type service for the dtsession-SunRay to make sure
	# that we copy the "dtsession auth" entries currently configured on the system
	# to dtsession-SunRay stack.  This can either be from the "dtsession" service
	# stack itself or from the "other" service stack if it's not defined in the
	# dtsession stack.
	create_stack "DEF_YES" "TAG_YES" $DTSESSION dtsession $NEWSTACK
	create_stack "DEF_YES" "TAG_NO" $DTSESSION:auth dtsession $NEWSTACK $SRLIB syncondisplay

	create_stack "DEF_YES" "TAG_YES" $NSCLOGIN dtlogin $NEWSTACK
	create_stack "DEF_YES" "TAG_NO" $NSCLOGIN:auth dtlogin $NEWSTACK
	add_module "TAG_NO" $NSCLOGIN:auth $AMGHLIB "" required
	add_module "TAG_NO" $NSCLOGIN:auth $SRLIB_GU property=username requisite

        # admingui has to be created from scratch - no existing stack to dup
	create_stack "DEF_NO" "TAG_YES" $ADMINGUI "NONE" $NEWSTACK
	add_module "TAG_NO" $ADMINGUI $ADMINGUILIB "" sufficient

        # need to create the specific "auth" type service for utgulogin.  This will
	# be based on "dtlogin" service stack if it exists.  Otherwise, it should fall
	# back to the "other" service stack.
	create_stack "DEF_NO" "TAG_YES" $GULOGIN "NONE" $NEWSTACK
	add_module "TAG_NO" $GULOGIN:auth $AMGHLIB "" required
	add_module "TAG_NO" $GULOGIN:auth $SRLIB_GU prompt requisite
	add_module "TAG_NO" $GULOGIN:auth $AMGHLIB "" required
	add_module "TAG_NO" $GULOGIN:auth $SRLIB_GU token=auth,JavaBadge requisite
	add_module "TAG_NO" $GULOGIN:auth $SRLIB_GU property=username requisite

	add_Xserver_Class
	hdtmpl=dtsession
	# XXX: DEF_YES makes little sense, because the 'other' account stack on TX
	#      contains pam_tsol_account so doesn't work, but the
	#      hardcoded fallback in utpamcfg is worse
	# Copy all modules (we need auth, account and passwd)
	create_stack "DEF_YES" "TAG_YES" $HOTDESK:account $hdtmpl
    fi
}

clean_gdm_stack() {
    if [ $OS != "SunOS" -a -d $PAM_DIR ]; then
	PAM_CONF=$PKG_INSTALL_ROOT/${PAM_DIR}/gdm
    else
	PAM_CONF=$PKG_INSTALL_ROOT/$PAM_CONF
    fi
    TAGSTR="$SRTAG -- gdm"
    egrep -v \
	-e "\<pam_sunray_amgh.so." \
	-e "\<sunray_get_user.so." \
	-e "\<pam_sunray_hotdesk.so." \
	-e "\<pam_kiosk.so" \
	-e "$TAGSTR" \
	$PAM_CONF > /tmp/pam.conf.$$
    cp /tmp/pam.conf.$$ $PAM_CONF
    rm -f /tmp/pam.conf.$$
}

utpam_unconfigure() {
    if [ $OS != "SunOS" ]; then
	clean_gdm_stack
	delete_stack $ADMINGUI "TAG_NO"
	delete_stack $SELFREG "TAG_NO"
	delete_stack $HOTDESK "TAG_NO"
	return
    fi

    # Edit pam.conf to remove any configuration for utnsclogin
    # and utgulogin
    #

    delete_stack $DTLOGIN "TAG_NO"
    delete_stack $DTSESSION "TAG_NO"
    # XXX NOTE:
    # For 4.0 new setup, utpamcfg adds "# BEGIN:" prefix to the tag so that we
    # can distiguish from the old setup when removing the entries from pam.conf.
    # This is needed for backward compatibility and to avoid removing the
    # xscreensaver:account entries that no were not added by Sun Ray.
    # So, check if pam.conf has the new setup by looking for "^# BEGIN:" in the
    # pam.conf file.  If it exists, then it's a new format and we only remove the
    # "auth" type for xscreensaver.  Otherwise, remove all the xscreensaver entries.
    if grep "^# BEGIN: .* ${SRTAG}" /etc/pam.conf >/dev/null 2>&1; then
	# new form
	delete_stack ${XSCREENSAVER}:auth  "TAG_YES"
    elif grep "^# added .* ${SRTAG}" /etc/pam.conf >/dev/null 2>&1; then
	# old form
	delete_stack ${XSCREENSAVER} "TAG_NO"
#   else
#	# there is no sunray specific entry for xscreensaver, nothing to delete
    fi
    delete_stack $NSCLOGIN "TAG_NO"
    delete_stack $GULOGIN "TAG_NO"
    delete_stack $ADMINGUI "TAG_NO"
    delete_stack $HOTDESK "TAG_NO"

    delete_Xserver_Class
}

Usage() {
    printf "Usage: %s: [-r alternate_root] disable|enable\n" $0
}

# main

if [ -z "$DEBUG_ROOT" ]; then DEBUG_ROOT=""; fi
if [ -z "$PKG_INSTALL_ROOT" ]; then PKG_INSTALL_ROOT=""; fi
if [ -z "$CLIENT_BASEDIR" ]; then CLIENT_BASEDIR="/opt"; fi

disable=false
while getopts d:hr: opt; do
    case $opt in
	d)	DEBUG_ROOT="$OPTARG";;
	r)	PKG_INSTALL_ROOT="$OPTARG";;
	h)	Usage
		exit 0;;
	?)	Usage
		exit 1;;
    esac
done
shift $(($OPTIND - 1))

action=
if [ "$1" == "disable" ]; then
    action=disable
    shift
elif [ "$1" == "enable" ]; then
    action=enable
    shift
fi
if [ -n "$*" -o -z "$action" ]; then
    Usage
    exit 1
fi

if [ -z "$BASEDIR_DEFAULT" ]; then
    BASEDIR_DEFAULT="$PKG_INSTALL_ROOT$CLIENT_BASEDIR"
fi

OS=`uname -s`
OS_REL=`uname -r`

PRODINFO=/etc/opt/SUNWut/basedir/lib/utprodinfo
ETCDIR_LIB=/etc/opt/SUNWut/lib

if [ $action = "disable" ] ; then
    BASEDIR_PS="$DEBUG_ROOT`$PRODINFO -r SUNWutps`"
    BASEDIR_O="$DEBUG_ROOT`$PRODINFO -r SUNWuto`"
    BASEDIR_GSM="$DEBUG_ROOT`$PRODINFO -r SUNWutgsm`"
    BASEDIR_KIOSK="$DEBUG_ROOT`$PRODINFO -r SUNWkio`"
    BASEDIR_KIOSK="${BASEDIR_KIOSK:-$BASEDIR_DEFAULT}"
else
    BASEDIR_PS=$BASEDIR_DEFAULT
    BASEDIR_O=$BASEDIR_DEFAULT
    BASEDIR_GSM=$BASEDIR_DEFAULT
    BASEDIR_KIOSK=$BASEDIR_DEFAULT
fi

LIB_SUNWUTO="$BASEDIR_O/SUNWut/lib"
LIB_SUNWKIO="$BASEDIR_KIOSK/SUNWkio/lib"
if [ $OS = "Linux" ]; then
	LIB_SUNWUTPS="$ETCDIR_LIB/\$\PLATFORM"
	LIB_SUNWUTGSM="$ETCDIR_LIB/\$\PLATFORM"
	LIB_SUNWUTKIOSK="$ETCDIR_LIB/\$\PLATFORM"
else
	LIB_SUNWUTPS="$BASEDIR_PS/SUNWut/lib"
	LIB_SUNWUTGSM="$BASEDIR_GSM/SUNWut/lib"
	LIB_SUNWUTKIOSK="$LIB_SUNWKIO"
fi

UTPAMCFG=$LIB_SUNWUTO/utpamcfg
SRLIB_GU="$LIB_SUNWUTPS/sunray_get_user.so.1"
HOTDESKLIB="$LIB_SUNWUTPS/pam_sunray_hotdesk.so.1"
AMGHLIB="$LIB_SUNWUTGSM/pam_sunray_amgh.so.1"
SRLIB="$LIB_SUNWUTPS/pam_sunray.so"
ADMINGUILIB="$BASEDIR_PS/SUNWut/lib/pam_sunray_admingui.so.1"
KIOSKLIB="$LIB_SUNWUTKIOSK/pam_kiosk.so.1"
STACKLIB=pam_stack.so
UNIX2LIB=pam_unix2.so

# PAM client name X server class (dtlogin/dtsession)
# requires fix for 4452627
XCONFIG_USR_DIR="$PKG_INSTALL_ROOT/usr/dt/config"
XCONFIG_ETC_DIR="$PKG_INSTALL_ROOT/etc/dt/config"
GENERIC_XCONFIG="Xconfig"
PROTO_XCONFIG="Xconfig.SUNWut.prototype"
VALID_PAM_CLASS_TAG="Dtlogin.validPAMclasses"
SUNRAY_XSERVER_CLASS_TYPE="SunRay"

# SunRay-qualified CDE application names in pam.conf
DTLOGIN="dtlogin-$SUNRAY_XSERVER_CLASS_TYPE"
DTSESSION="dtsession-$SUNRAY_XSERVER_CLASS_TYPE"

# GDM app name in pam.conf
GDM="gdm"

# GNOME application name in pam.conf
XSCREENSAVER="xscreensaver"

PAM_CONF="/etc/pam.conf"
PAM_DIR="/etc/pam.d"

NSCLOGIN=utnsclogin
GULOGIN=utgulogin
ADMINGUI=utadmingui
SELFREG=utselfreg
HOTDESK=uthotdesk
# We don't manage a uthotdesk stack on Solaris - that's for users to (de)configure

SYS_AUTH=system-auth

SRTAG="SunRay Server Software"

export PKG_INSTALL_ROOT

utpam_unconfigure
if [ $action = enable ] ; then
    utpam_configure
fi

exit 0
