#!/bin/sh
#
# Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
# Use is subject to license terms.
#
#ident	"@(#)iplsslcfg.sh	1.34	04/04/22 SMI"
#
# iplsslcfg: script for automated installation of cryptographic module
#            for Sun ONE Web Server.
#
# Exit values for the script are as follows:
#	0	Successful
#	1	Path tested is not a directory
#	2	Path tested is not a regular file
#	3	Path tested is not an executable
#	4	Failed running an executable (modutil, openssl)
#	5	Required packages are not on the system
#	6	The required version of software is not present
#	7	Could not create directory
#	8	Could not find web server instance
#	255	User aborted
#

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

TEXTDOMAIN=SUNW_CRYPTO_KCL
export TEXTDOMAIN

TEXTDOMAINDIR=/opt/SUNWconn/cryptov2/lib/locale
export TEXTDOMAINDIR

cryptoinst=/opt/SUNWconn/cryptov2
cryptoconf=/etc/opt/SUNWconn/cryptov2

eval locale=`locale | grep LC_MESSAGES | cut -d= -f2`
yesexpr="^[Yy]"
eval `locale -k yesexpr`

# We need to have vcad running
vcadpid=`pgrep -x vcad`
if [ "${vcadpid}" = "" ]
then
	/etc/init.d/vca start
fi

# ipldirs are "best guesses" for Sun ONE installations.
# Place additional dirs in here if these aren't sufficient.
ipldirs="
	/usr/iplanet/servers
	/usr/local/iplanet/servers
	/opt/iplanet/servers
	/usr/local/netscape/server4
	/opt/netscape/server4
	/usr/netscape/server4
"

s1appdirs="
	/usr/local/SUNWappserver7
	/sun/appserver7
	/usr/local/appserver7
	/opt/SUNWappserver7
"

s1nssbin="/usr/bin/mps"
defdomdir="/var/opt/SUNWappserver7"

# cleandir takes all the args to this function and interprets them
# as a single directory name.  It checks to see if there are any
# bad characters and then echoes back either the good directory
# name or an empty string.  It also returns 0 in the success case
# or 1 otherwise (so you can use $?).
cleandir()
{
	d=`echo "${*}" | sed 's/[^A-Za-z0-9/_.-]//g'`
	if [ "${d}" = "${*}" ]
	then
		echo "${d}"
		return 0
	else
		echo ""
		return 1
	fi
}

# cleanfname is used to strip detect unwanted characters in a
# friendly name.  This is used for creation of PKCS#12.
cleanfname()
{
	d=`echo "${*}" | sed 's/[^A-Za-z0-9-@:-]//g'`
	if [ "${d}" = "${*}" ]
	then
		echo "${d}"
		return 0
	else
		echo ""
		return 1
	fi
}

# cleannum takes all the args to this function and interprets them
# as a single numeric value.  It checks to see if there are any
# bad characters and then returns either a 0 (good int value)
# or a 1 (non-numeric).
cleannum()
{
        d=`echo "${*}" | sed 's/[^0-9]//g'`
        if [ -n "${d}" -a "${d}" = "${*}" ]
        then
                return 0
        else
                return 1
        fi
}


# setipldir sets ${srvdir} and sets LD_LIBRARY_PATH.  This has to
# be run before any other iWS operations and doesn't check for pk12util
# (because it's only in iWS 6.x, not 4.x.).  The function returns 0
# if the checks all pass, and returns non-zero if any of the tests fail.
setipldir()
{
	for tmpsrvdir in ${ipldirs}
	do
		if [ -d ${tmpsrvdir} ]
		then
			break
		fi
	done

	while [ ${retval:=1} -ne 0 ]
	do
		gettext "\nPlease enter the full path of the web server\nroot directory "
		echo "[${tmpsrvdir}]: \c"
		read somedir
		srvdir=`cleandir ${somedir}`
		retval=$?
		if [ "${retval}" -ne 0 ]
		then
			gettext "Error: Invalid characters in directory name.\n"
		fi
	done
	unset retval

	if [ ! -d ${srvdir:=${tmpsrvdir}} ]
	then
		_fmt=`gettext "Error: %s is not a directory."`
		printf "${_fmt}\n" ${srvdir}
		return 1
	elif [ ! -d ${srvdir}/alias ]
	then
		_fmt=`gettext "Error: There is no %s/alias directory."`
		printf "${_fmt}\n" ${srvdir}
		return 1
	elif [ ! -x ${srvdir}/bin/https/admin/bin/modutil ]
	then
		_fmt=`gettext "Error: Cannot find %s/bin/https/admin/bin/modutil."`
		printf "${_fmt}\n" ${srvdir}
		return 3
	elif [ ! -f ${srvdir}/alias/secmod.db ]
	then
		_fmt=`gettext "Error: There is no %s/alias/secmod.db file."`
		printf "${_fmt}\n" ${srvdir}
		gettext "You must create a trust database via the Sun ONE Administration Server.\n"
		return 2
	fi

	LD_LIBRARY_PATH="/usr/share/lib:/usr/lib:${srvdir}/bin/https/lib"
	export LD_LIBRARY_PATH

	return 0
}

# ipladdmodule handles the adding the crypto module software into secmod.db
# It returns a 0 if the add is successful, non-zero if it fails or is
# aborted.
ipladdmodule()
{
	_fmt=`gettext "This script will update your Sun ONE Web Server installation\nin %s to use the Sun Crypto Accelerator\nYou will need to restart your admin server after this has completed."`
	printf "${_fmt}\n" ${srvdir}
	gettext "Ok to proceed? [Y/N]: "

	read isok
	expr "${isok}" : "${yesexpr}" > /dev/null
	if [ $? -eq 0 ]
	then
		cd ${srvdir}

		${srvdir}/bin/https/admin/bin/modutil \
		    -dbdir ${srvdir}/alias \
		    -nocertdb \
		    -force \
		    -add "Sun Crypto Accelerator 4000" \
		    -libfile ${cryptoinst}/lib/libvpkcs11.so \
		    -mechanisms RSA:DSA:DES

		if [ $? -eq 0 ]
		then
			_fmt=`gettext "%s has been configured to use\nthe Sun Crypto Accelerator."`
			printf "${_fmt}\n" ${srvdir}
			echo
			return 0
		else
			gettext "\nInstallation of the Sun Crypto Accelerator failed.\n"
			return 4
		fi
	else
		gettext "Installation aborted.\n"
		return 255
	fi
}

# This is the master subroutine for configuring Sun ONE Web Server
# for use with the Sun Crypto Accelerator.
confipl()
{
	# Set the Sun ONE web server install directory and test
	setipldir
	rv=$?
	if [ "${rv}" -ne 0 ]
	then
		exit ${rv}
	fi

	# Now add the PKCS11 module
	ipladdmodule
	rv=$?
	if [ "${rv}" -ne 0 ]
	then
		exit ${rv}
	fi

	gettext "\n<Press ENTER to continue>"
	read throwaway
}

# This is a helper function to clear out any state left over
# from previous runs through the menu
cleanstate()
{
	unset srvdir
	unset retval
}

# ipl2pkcs12 will take keys out of the software database and export
# them to hardware.
ipl2pkcs12()
{
	# Get all the Sun ONE dirs we need
	setipldir
	rv=$?
	if [ "${rv}" -ne 0 ]
	then
		exit ${rv}
	fi

	if [ ! -x ${srvdir}/bin/https/admin/bin/pk12util ]
	then
		_fmt=`gettext "Error: Cannot find %s/bin/https/admin/bin/pk12util."`
		printf "${_fmt}\n" ${srvdir}
		exit 3
	fi

	# Give user a list of cert/key databases to export from
	slist=`/bin/ls -1 "${srvdir}"/alias/https*cert7.db | \
	    sed -e 's,cert7.db,,' -e 's,'"${srvdir}"'/alias/,,' | uniq`
	if [ -z "${slist}" ]
	then
		gettext "Error: Could not find any certificate databases\nto import your keys to.\n"
		exit 8
	else
		gettext "\nThe following certificate databases were found:\n"
		_fmt=`gettext "%s"`
		printf "${_fmt}\n\n" "${slist}"
	fi

	while [ ${retval:=1} -ne 0 ]
	do
		gettext "Which certificate database do you wish to export from? "
		read someinst
		# We can get away with the same sanity check for
		# files as dirs in this case
		inst=`cleandir ${someinst}`
                retval=$?
		if [ "${retval}" -ne 0 ]
		then
			gettext "Error: Invalid characters in database name.\n"
		elif [ -z "${inst}" ]
		then
			gettext "Error: Certificate database cannot be a blank value.\n"
			# Force reiteration
			retval=-1
		elif [ ! -f "${srvdir}/alias/${inst}cert7.db" ]
		then
			_fmt=`gettext "Error: Could not find %s"`
			printf "${_fmt}\n" "${srvdir}/alias/${inst}cert7.db" 
			retval=-1
		fi
	done
	unset retval

	while [ ${retval:=1} -ne 0 ]
	do
		gettext "\nPlease provide the name for the certificate you wish to\nexport.  If you wish to export from a hardware device,\nyou will need to provide the token name followed by\na \":\" and the certificate name.  Not all external tokens\nwill allow keys to be exported.\n"
		echo
		gettext "Certificate Name [Server-Cert]: "
		read somefname
		fname=`cleanfname ${somefname}`
		retval=$?
		if [ "${retval}" -ne 0 ]
		then
			gettext "Error: Invalid characters in friendly name.\n"
		elif [ -z "${fname}" ]
		then
			fname="Server-Cert"
		fi
	done
	unset retval

	while [ ${retval:=1} -ne 0 ]
	do
		unset pkfile
		while [ ${pkfile:=""} = "" ]
		do
			gettext "\nPlease specify the path where the PKCS#12\nfile will be stored: "
			read pkfile
		done
		# Prompt the user for overwrite if the file exists
		if [ -f "${pkfile}" ]
		then
			_fmt=`gettext "%s already exists.\nDo you wish to overwrite it? [Y/N]: "`
			printf "${_fmt}" ${pkfile}
			read answer
			expr "${answer}" : "${yesexpr}" > /dev/null
			retval=$?
		else
			retval=0
		fi
	done
	unset retval

	${srvdir}/bin/https/admin/bin/pk12util \
	    -o "${pkfile}" \
	    -n "${fname}" \
	    -d "${srvdir}/alias" \
	    -P "${inst}"

	if [ $? -ne 0 ]
	then
		echo
		gettext "Error: Problem creating PKCS#12 file.\n"
		exit 4
	else
		echo
		gettext "Successfully created the PKCS#12 file.\n"
	fi

	gettext "\n<Press ENTER to continue>"
	read throwaway
}

# pkcs12toipl takes keys in PKCS#12 format and imports them into
# Sun ONE Web Server or any PKCS#11 module that is connected to Sun ONE 
# The function has no return value, but exits with error codes from
# other subroutines.
pkcs12toipl()
{
	# Get all the Sun ONE dirs we need
	setipldir
	rv=$?
	if [ "${rv}" -ne 0 ]
	then
		exit ${rv}
	fi

	if [ ! -x ${srvdir}/bin/https/admin/bin/pk12util ]
	then
		_fmt=`gettext "Error: Cannot find %s/bin/https/admin/bin/pk12util."`
		printf "${_fmt}\n" ${srvdir}
		exit 3
	fi

	while [ ${retval:=1} -ne 0 ]
	do
		gettext "Enter the path to the PKCS#12 file: "
		read somefile
		# We can get away with the same sanity check for
		# files as dirs in this case
		pkfile=`cleandir ${somefile}`
                retval=$?
		if [ "${retval}" -ne 0 ]
		then
			gettext "Error: Invalid characters in pathname.\n"
		elif [ -z "${pkfile}" ]
		then
			gettext "Error: Path to PKCS#12 cannot be a blank value.\n"
			# Force reiteration
			retval=-1
		fi
	done
	unset retval

	if [ ! -f ${pkfile} ]
	then
		_fmt=`gettext "Error: Cannot find %s."`
		printf "${_fmt}\n" ${pkfile}
		exit 2
	fi

	gettext "Will you be importing to a hardware device? [Y/N]: "
	read answer
	expr "${answer}" : "${yesexpr}" > /dev/null
	if [ $? -ne 0 ]
	then
		hw=0
		# Give user a list of cert/key databases to import to
		slist=`/bin/ls -1 "${srvdir}"/alias/https*cert7.db | \
		    sed -e 's,cert7.db,,' -e 's,'"${srvdir}"'/alias/,,' | uniq`
		if [ -z "${slist}" ]
		then
			gettext "Error: Could not find any certificate databases\nto import your keys to.\n"
			exit 8
		else
			gettext "\nThe following certificate databases were found:\n"
			_fmt=`gettext "%s"`
			printf "${_fmt}\n\n" "${slist}"
		fi

		while [ ${retval:=1} -ne 0 ]
		do
			gettext "Which certificate database do you wish to import to? "
			read someinst
			# We can get away with the same sanity check for
			# files as dirs in this case
			inst=`cleandir ${someinst}`
			retval=$?
			if [ "${retval}" -ne 0 ]
			then
				gettext "Error: Invalid characters in database name.\n"
			elif [ -z "${inst}" ]
			then
				gettext "Error: Certificate database cannot be a blank value.\n"
				# Force reiteration
				retval=-1
			elif [ ! -f "${srvdir}/alias/${inst}cert7.db" ]
			then
				_fmt=`gettext "Error: Could not find %s"`
				printf "${_fmt}\n" "${srvdir}/alias/${inst}cert7.db" 
				retval=-1
			fi
		done
		unset retval
	else
		hw=1
	fi

	if [ "${hw}" -eq 1 ]
	then
		gettext "Enter the token name: "
		read token

		${srvdir}/bin/https/admin/bin/pk12util \
		    -i "${pkfile}" \
		    -d "${srvdir}/alias" \
		    -h "${token}"
		rv=$?
	else
		${srvdir}/bin/https/admin/bin/pk12util \
		    -i "${pkfile}" \
		    -d "${srvdir}/alias" \
		    -P "${inst}"
		rv=$?
	fi

	if [ "${rv}" -ne 0 ]
	then
		gettext "Import of keys from PKCS#12 file failed.\n"
		exit 4
	else
		gettext "Import successful.\n"
	fi

	gettext "\n<Press ENTER to continue>"
	read throwaway
}

# s1appaddmodule handles the adding the crypto module software into secmod.db
# It returns a 0 if the add is successful, non-zero if it fails or is
# aborted.
s1appaddmodule()
{
	_fmt=`gettext "This script will update your Sun ONE Application Server installation\nin %s to use the Sun Crypto Accelerator.\nYou will need to restart your admin server after this has completed."`
	printf "${_fmt}\n" ${srvdir}
	gettext "Ok to proceed? [Y/N]: "

	read isok
	expr "${isok}" : "${yesexpr}" > /dev/null
	if [ $? -eq 0 ]
	then
		cd ${srvdir}

		${s1nssbin}/modutil \
		    -dbdir ${domaindir}/domains/${appdomain}/${servname}/config \
		    -nocertdb \
		    -force \
		    -add "Sun Crypto Accelerator 4000" \
		    -libfile ${cryptoinst}/lib/libvpkcs11.so \
		    -mechanisms RSA:DSA:DES

		if [ $? -eq 0 ]
		then
			_fmt=`gettext "%s has been configured to use\nthe Sun Crypto Accelerator."`
			printf "${_fmt}\n" ${srvdir}
			echo
			return 0
		else
			gettext "\nInstallation of the Sun Crypto Accelerator failed.\n"
			return 4
		fi
	else
		gettext "Installation aborted.\n"
		return 255
	fi
}

# sets1appdir sets ${srvdir} and sets LD_LIBRARY_PATH.  This has to
# be run before any other iWS operations and doesn't check for pk12util
# (because it's only in iWS 6.x, not 4.x.).  The function returns 0
# if the checks all pass, and returns non-zero if any of the tests fail.
sets1appdir()
{
	for tmpsrvdir in ${s1appdirs}
	do
		if [ -d ${tmpsrvdir} ]
		then
			break
		fi
	done

	gettext "\nYou will now be prompted for four pieces of information:\n"
	gettext "  1. The location of the Sun ONE Application Server binaries\n"
	gettext "  2. The location where Sun ONE Server domains are stored\n"
	gettext "  3. The Application Server domain (e.g. domain1)\n"
	gettext "  4. The Application Server server name (e.g. server1)\n"
	gettext "\n"

	while [ ${retval:=1} -ne 0 ]
	do
		gettext "Full path to Application Server binaries: "
		echo "[${tmpsrvdir}]: \c"
		read somedir
		srvdir=`cleandir ${somedir}`
		retval=$?
		if [ "${retval}" -ne 0 ]
		then
			gettext "Error: Invalid characters in directory name.\n"
		fi
	done
	unset retval

	while [ ${retval:=1} -ne 0 ]
	do
		gettext "Full path to Application Server domains: "
		echo "[${defdomdir}]: \c"
		read somedir
		domaindir=`cleandir ${somedir}`
		retval=$?
		if [ "${retval}" -ne 0 ]
		then
			gettext "Error: Invalid characters in directory name.\n"
		fi
	done

	unset retval
	while [ ${retval:=1} -ne 0 ]
	do
		gettext "Application Server domain: "
		read somedir
		appdomain=`cleandir ${somedir}`
		retval=$?
		if [ "${retval}" -ne 0 ]
		then
			gettext "Error: Invalid characters in domain name.\n"
		fi
	done
	unset retval

	while [ ${retval:=1} -ne 0 ]
	do
		gettext "Application Server server name: "
		read somedir
		servname=`cleandir ${somedir}`
		retval=$?
		if [ "${retval}" -ne 0 ]
		then
			gettext "Error: Invalid characters in server name.\n"
		fi
	done
	unset retval

	if [ ! -d ${srvdir:=${tmpsrvdir}} ]
	then
		_fmt=`gettext "Error: %s is not a directory."`
		printf "${_fmt}\n" ${srvdir}
		return 1
	elif [ ! -d ${domaindir:=${defdomdir}} ]
	then
		_fmt=`gettext "Error: %s is not a directory."`
		printf "${_fmt}\n" ${domaindir}
		return 1
	elif [ ! -d ${domaindir}/domains/${appdomain} ]
	then
		_fmt=`gettext "Error: Domain \"%s\" not found."`
		printf "${_fmt}\n" ${appdomain}
		return 1
	elif [ ! -d ${domaindir}/domains/${appdomain}/${servname} ]
	then
		_fmt=`gettext "Error: Server name \"%s\" not found."`
		printf "${_fmt}\n" ${servname}
		return 1
	elif [ ! -f ${domaindir}/domains/${appdomain}/${servname}/config/secmod.db ]
	then
		_fmt=`gettext "Error: Could not find secmod.db file in %s."`
		printf "${_fmt}\n" ${srvdir}/domains/${appdomain}/${servname}/config
		gettext "You must create a trust database via the Sun ONE Administration Server.\n"
		return 2
	elif [ ! -x ${s1nssbin}/modutil ]
	then
		_fmt=`gettext "Error: Cannot find modutil or the file is not executable.\nIf you do not have modutil in /usr/bin/mps please download the Sun ONE\nApplication Server Add-Ons software."`
		printf "${_fmt}\n" ${s1nssbin}
		return 3
	fi

	LD_LIBRARY_PATH="/usr/share/lib:/usr/lib:/usr/lib/mps"
	export LD_LIBRARY_PATH

	return 0
}

# This is the master subroutine for configuring Sun ONE
# Application Server for use with the Sun Crypto Accelerator.
confs1app()
{
	# Set the Sun ONE Application Server install directory and test
	sets1appdir
	rv=$?
	if [ "${rv}" -ne 0 ]
	then
		exit ${rv}
	fi

	# Now add the PKCS11 module
	s1appaddmodule
	rv=$?
	if [ "${rv}" -ne 0 ]
	then
		exit ${rv}
	fi

	gettext "\n<Press ENTER to continue>"
	read throwaway
}

while [ ${srvtype:=1} -ne 0 ]
do
	clear
	cleanstate
	gettext "Sun Crypto Accelerator Sun ONE Installation\n"
	gettext "---------------------------------------------------------\n"
	gettext "This script will install the Sun Crypto Accelerator\ncryptographic modules for Sun ONE Products.\n"
	echo
	gettext "Please select what you wish to do:\n"
	gettext "---------------------------------------------------------\n"
	gettext "1. Configure Sun ONE Web Server for SSL\n"
	gettext "2. Configure Sun ONE Application Server for SSL\n"
	gettext "3. Export Sun ONE Web Server keys to PKCS#12 format\n"
	gettext "4. Import keys from PKCS#12 format for Sun ONE Web Server\n"
	echo
	gettext "Your selection (0 to quit): "

	read srvtype

	case "${srvtype}" in
	0)
		exit 0
		;;
	1)
		confipl
		;;
	2)
		confs1app
		;;
	3)
		ipl2pkcs12
		;;
	4)
		pkcs12toipl
		;;
	*)
		# Non-numeric data would eval to 0 so force srvtype
		# To be a non-zero value we won't use
		srvtype=-1
		;;
	esac
done

exit 0
