#!/bin/ksh
#
# Copyright 1999-2001,2003 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#
# ident	"@(#)CDESmartCardAdmin.sh	1.6	03/03/17 SMI"
#
#
# This script enables and disables smart card usage for CDE
# (dtlogin and dtsession). It modifies CDE X properties to
# add or remove properties that specify whether or not to use
# smart cards, and it edits /etc/pam.conf to add or remove
# pam_smartcard.so actions.
#

BASENAME="/bin/basename"
     MOD="`$BASENAME $0`"
 DIRNAME="/bin/dirname"

EGREP="/bin/egrep"
   CP="/bin/cp"
   MV="/bin/mv"
   RM="/bin/rm"
MKDIR="/bin/mkdir"
  NAWK="/bin/nawk"
  SED="/bin/sed"

# override these variables for debugging
ETC="/etc"
USR="/usr"

  DTLOGIN_PROPS_FILE="dt/config/Xconfig"
DTSESSION_PROPS_FILE="dt/app-defaults/C/Dtsession"

PAM_CONF="$ETC/pam.conf"
TMP_CONF="$PAM_CONF.tmp"

PAMSC=pam_smartcard.so
PAMDIR='/usr/lib/security/$ISA'
PATTERN="[ 	]+auth[ 	]+[^ 	]+[ 	]+.*$PAMSC"

#
# Remove the appname + auth + pam_smartcard from pam.conf.
#
#    Usage: remove_sc_from_PAM {appname}
#
function remove_sc_from_PAM {
    APPNAME="$1"

    # Do nothing if no smartcard entry exists for $APPNAME + auth
    if ! $EGREP -is "^$APPNAME$PATTERN" $PAM_CONF ; then
       	return 0
    fi

    $CP -p $PAM_CONF $TMP_CONF

    # Remove pam_smartcard.so from the stack.

    $EGREP -iv "^$APPNAME$PATTERN" $PAM_CONF > $TMP_CONF.2

    # If pam_unix.so is at the top of the stack or after pam_tp_auth.so,
    # remove "xxx_first_pass" from its argument.

    $NAWK "
	BEGIN {flag = 0}

	(flag == 0) && (\$1 == \"$APPNAME\") && (\$2 == \"auth\"){

	    if (match(\$4, \"pam_tp_auth.so\")) {
		print \$0
		continue
	    }

	    if (match(\$4, \"pam_unix.so\") && match(\$0, \"_first_pass\")) {
		sub(\"..._first_pass\", \"\", \$0)
	    }

	    print \$0
	    flag = 1
	    continue
	}
	
	{
	    print \$0
	}" $TMP_CONF.2 > $TMP_CONF

    $RM $TMP_CONF.2
    $MV $TMP_CONF $PAM_CONF
}

#
# Enable smart card authentication for CDE.
#
# Inserting this line at the top of the stack of "appname	auth ...."
#
# "appname	auth requisite		pam_smartcard.so.1"
#
function add_sc_to_PAM {
    APPNAME=$1

    # If pam_smartcard already exists for $APPNAME + auth, do nothing.
    if $EGREP -is "^$APPNAME$PATTERN" $PAM_CONF ; then
       	return 0
    fi

    $CP -p $PAM_CONF $TMP_CONF

    # Insert pam_smartcard.so at the top of the stack 
    # (after pam_tp_auth.so if it exists).
    # If pam_unix.so follows pam_smartcard.so, add "use_first_pass"
    # unless "xxx_first_pass" is already there.

    $NAWK "
	BEGIN {flag = 0}

	(flag == 0) && (\$1 == \"$APPNAME\") && (\$2 == \"auth\"){

	    if (match(\$4, \"pam_tp_auth.so\")) {
		print \$0
		continue
	    }

	    print \"$APPNAME\tauth requisite\t\t$PAMDIR/$PAMSC.1\"

	    if (match(\$4, \"pam_unix.so\") && !match(\$0, \"_first_pass\")) {
		print \$0, \"use_first_pass\"
	    } else {
		print \$0
	    }

	    flag = 1
	    continue
	}
	
	{
	    print \$0
	}" $PAM_CONF > $TMP_CONF

    $MV $TMP_CONF $PAM_CONF
}


#
# Copy entries "other" to $1.
#
function copy_others_to_CDE {
    APPNAME=$1

    # If a CDE entry already exists, do nothing.
    if $EGREP -is "^$APPNAME[ 	]+auth" $PAM_CONF ; then
       	return 0
    fi

    # Store "other	auth" entries to a temporary file
    $EGREP -i '^other[		]+auth' $PAM_CONF > $TMP_CONF.other

    $CP -p $PAM_CONF $TMP_CONF
    echo >> $TMP_CONF
    echo "# $APPNAME settings added by /usr/bin/smartcard" >> $TMP_CONF

    # Replace "other" with "$APPNAME" and append to the file
    /bin/sed -e 's/^other/'$APPNAME'/' $TMP_CONF.other >> $TMP_CONF

    $RM $TMP_CONF.other

    $MV $TMP_CONF $PAM_CONF
}


#
# Check if the /etc versions of the dtlogin and dtsession proeprties
# files exist - if they don't copy them from /usr to /etc
# If the CDE files in /usr don't exist and we need to copy them to /etc,
# then bail out. Note that it's possible to have only the /etc files
# and not the /usr files.
#
function check_CDEetc_file {

    FNAME="$1"

    if test ! -f $ETC/$FNAME ; then
	if test ! -f $USR/$FNAME ; then
	    echo "$MOD: unable to read $USR/$FNAME"
	    exit 1
	fi
	$MKDIR -p `$DIRNAME $ETC/$FNAME`
	$CP -frp $USR/$FNAME $ETC/$FNAME
    fi

}


function print_line_no {
    PATTERN="$1"
    PROPFILE="$2"

    $EGREP -s "$PATTERN" $PROPFILE

    if [ $? -eq 0 ] ; then
	$EGREP -n "$PATTERN" $PROPFILE | tail -1 | cut -d: -f1
    fi
}


#
# Update the smart card properties in CDE files.
#
#    Usage: update_SCprop {propertyname} {propfile}
#
function update_SCprop {

    PROPNAME="$1.useSmartCard"
    PROPFILE="$ETC/$2"
    FLAG="$3"
    sc_prop="$PROPNAME: $FLAG"
    PATTERN="[	 ]*$PROPNAME"

    line_no=`print_line_no "^$PATTERN" $PROPFILE`

    if [ -z "$line_no" ] ; then

	line_no=`print_line_no "^!#$PATTERN:" $PROPFILE`

	if [ -z "$line_no" ] ; then
	    line_no=`print_line_no "^#$PATTERN:" $PROPFILE`
	fi
    fi

    if [ -n "$line_no" ]
	then
	    $CP -p $PROPFILE $PROPFILE.tmp
	    $SED -e "$line_no c\\
$sc_prop" $PROPFILE > $PROPFILE.tmp
	    $MV $PROPFILE.tmp $PROPFILE
	else
	    echo "$PROPNAME property not found"
	    echo "$sc_prop" >> $PROPFILE
    fi

}

function update_dtlogin_config {

    update_SCprop Dtlogin $DTLOGIN_PROPS_FILE $1
}

function update_dtsession_config {

    update_SCprop Dtsession $DTSESSION_PROPS_FILE $1
}

########################################################################
#                                                                      #
#			Main code starts here.                         #
#                                                                      #
########################################################################

    #
    # Check whether pam.conf exists.
    #
    if test ! -f $PAM_CONF ; then
	echo "$MOD: $PAM_CONF does not exist"
	exit 1
    fi

    umask 022

    # check if /etc versions of files exist; if not, create them
    check_CDEetc_file $DTLOGIN_PROPS_FILE
    check_CDEetc_file $DTSESSION_PROPS_FILE

    if [ "$1" = "-e" ] ; then

	# if there is no entry for CDE, copy it from "other" entries
	copy_others_to_CDE dtlogin
	copy_others_to_CDE dtsession

	# enable smart card authentication for CDE in $PAM_CONF
	add_sc_to_PAM dtlogin
	add_sc_to_PAM dtsession

	# enable smart card in CDE X properties
	update_dtlogin_config True
	update_dtsession_config true

    elif [ "$1" = "-d" ] ; then

        # remove pam_smartcard lines
	remove_sc_from_PAM dtlogin
	remove_sc_from_PAM dtsession

	# disable smart card in CDE X properties
	update_dtlogin_config False
	update_dtsession_config false

    else
	echo "Invalid option: $1"
	exit 1
    fi

    exit 0
