# This script creates the backout package for a patch package
#
# directory format options.
#
# @(#) postinstall 1.13 01/01/12 SMI
#
# Copyright (c) 1995 by Sun Microsystems, Inc.
# All rights reserved
#

# Description:
#       Set the TYPE parameter for the remote file
#
# Parameters:
#       none
#
# Globals set:
#	TYPE

set_TYPE_parameter () {
	if [ ${PATCH_UNDO_ARCHIVE:?????} = "/dev" ]; then
		# handle device specific stuff
		TYPE="removable"
	else
		TYPE="filesystem"
	fi
}

#
# Description:
#       Build the remote file that points to the backout data
#
# Parameters:
#       $1:	the un/compressed undo archive
#
# Globals set:
#	UNDO, STATE

build_remote_file () {
	remote_path=$PKGSAV/$SUNW_PATCHID/remote
	set_TYPE_parameter
	STATE="active"

	if [ $1 = "undo" ]; then
		UNDO="undo"
	else
		UNDO="undo.Z"
	fi

	cat > $remote_path << EOF
# Backout data stored remotely
TYPE=$TYPE
FIND_AT=$ARCHIVE_DIR/$UNDO
STATE=$STATE
EOF
}

PATH=/usr/sadm/bin:$PATH

if [ "$PKG_INSTALL_ROOT" = "/" ]; then
	PKG_INSTALL_ROOT=""
fi

if [ -n "$PATCH_BUILD_DIR" -a -d "$PATCH_BUILD_DIR" ]; then
	BUILD_DIR="$PATCH_BUILD_DIR/$SUNW_PATCHID.$PKGINST"
else
	BUILD_DIR="$PKG_INSTALL_ROOT/var/tmp/$SUNW_PATCHID.$PKGINST"
fi

if [ ! -n "$PATCH_UNDO_ARCHIVE" ]; then
	PATCH_UNDO_ARCHIVE="none"
fi

FILE_DIR=$BUILD_DIR/files
RELOC_DIR=$FILE_DIR/reloc
ROOT_DIR=$FILE_DIR/root
BO_Deletes=$FILE_DIR/deletes
THIS_DIR=`dirname $0`
PROTO_FILE=$BUILD_DIR/prototype
TEMP_REMOTE=$PKGSAV/$SUNW_PATCHID/temp

if [ "$PATCH_PROGRESSIVE" = "true" ]; then
        # remove the scripts that are left behind
        install_scripts=`dirname $0`
        rm $install_scripts/checkinstall $install_scripts/patch_checkinstall $install_scripts/patch_postinstall

	# If this is being used in an old-style patch, insert
	# the old-style script commands here.

	#XXXOld_CommandsXXX#

	exit 0
fi

#
# At this point we either have a deletes file or we don't. If we do,
# we create a prototype entry.
#
if [ -f $BO_Deletes ]; then
	echo "i deletes=$BO_Deletes" >> $BUILD_DIR/prototype
fi

#
# Now delete everything in the deletes list after transferring
# the file to the backout package and the entry to the prototype
# file. Remember that the pkgmap will get the CLIENT_BASEDIR path
# but we have to actually get at it using the BASEDIR path. Also
# remember that removef will import our PKG_INSTALL_ROOT
#
Our_Deletes=$THIS_DIR/deletes
if [ -f $Our_Deletes ]; then
	cd $BASEDIR

	cat $Our_Deletes | while read path; do
		Reg_File=0

		if valpath -l $path; then
			Client_Path="$CLIENT_BASEDIR/$path"
			Build_Path="$RELOC_DIR/$path"
			Proto_Path=$BASEDIR/$path
		else	# It's an absolute path
			Client_Path=$path
			Build_Path="$ROOT_DIR$path"
			Proto_Path=$PKG_INSTALL_ROOT$path
		fi

		# If BASEDIR/CLIENTBASEDIR = "/", then the previous prepends
		# an extra / i.e. //. The sed command later can't find a
		# Proto_Path with // and therefore will not substitute the
		# correct build_Path resulting in the backout pkg not being
		# created.

		if [ "$CLIENT_BASEDIR" = "/" ]; then
			Client_Path=`echo $Client_Path | sed 's|^\/\/|\/|'`
			Proto_Path=`echo $Proto_Path | sed 's|^\/\/|\/|'`
		fi
			
		# Note: If the file isn't really there, pkgproto
		# doesn't write anything but displays an error
		# so check for the file before processing.

		if [ -f "$Proto_Path" ]; then
			LINE=`pkgproto $Proto_Path=$path`
		else
			continue
		fi

		ftype=`echo $LINE | nawk '{ print $1 }'`
		if [ "$ftype" = "f" ]; then
			Reg_File=1
		fi

		if [ $Reg_File = 1 ]; then
			# Add source file to the prototype entry
			if [ "$Proto_Path" = "$path" ]; then
				LINE=`echo $LINE | sed -e "s|$Proto_Path|$Build_Path|2"`
			else
				LINE=`echo $LINE | sed -e "s|$Proto_Path|$Build_Path|"`
			fi

			DirName=`dirname $Build_Path`
			# make room in the build tree
			mkdir -p $DirName
			cp -p $Proto_Path $Build_Path
		fi

		# Insert it into the prototype file
		echo $LINE 1>>$PROTO_FILE 2>/dev/null

		# Remove the file only if it's OK'd by removef
		rm `removef $PKGINST $Client_Path` 1>/dev/null 2>&1
	done
	removef -f $PKGINST

	rm $Our_Deletes
fi

#
# Unless specifically denied, make the backout package.
#
if [ "$PATCH_NO_UNDO" != "true" ]; then
	cd $BUILD_DIR	# We have to build from here.

	if [ "$PATCH_UNDO_ARCHIVE" != "none" ]; then
		STAGE_DIR="$PATCH_UNDO_ARCHIVE"
		ARCHIVE_DIR="$PATCH_UNDO_ARCHIVE/$SUNW_PATCHID/$PKGINST"
		mkdir -p $ARCHIVE_DIR
		mkdir -p $PKGSAV/$SUNW_PATCHID
	else
		if [ -d $PKGSAV/$SUNW_PATCHID ]; then
			rm -r $PKGSAV/$SUNW_PATCHID
		fi
		STAGE_DIR=$PKGSAV
		ARCHIVE_DIR=$PKGSAV/$SUNW_PATCHID
		mkdir $ARCHIVE_DIR
	fi

	pkgmk -o -d $STAGE_DIR 1>/dev/null 2>&1
	pkgtrans -s $STAGE_DIR $ARCHIVE_DIR/undo $PKG 1>/dev/null 2>&1
	compress $ARCHIVE_DIR/undo
	retcode=$?
	if [ "$retcode" != 0 ]; then
		echo "compress(1) returned error code $retcode"
		echo "The $PKGINST backout package will not be compressed."
		echo "Continuing to process backout package."
	fi
	if [ "$PATCH_UNDO_ARCHIVE" != "none" ]; then
		if [ $retcode != 0 ]; then
			build_remote_file "undo"
		else
			build_remote_file "undo.Z"
		fi
	fi
	rm -r $STAGE_DIR/$PKG

	cd ..
	rm -r $BUILD_DIR
	# remove the scripts that are left behind
	install_scripts=`dirname $0`
	rm $install_scripts/checkinstall $install_scripts/patch_checkinstall $install_scripts/patch_postinstall
fi

#
# Since this apparently worked, we'll mark as obsoleted the prior
# versions of this patch - installpatch deals with explicit obsoletions.
#
cd ${PKG_INSTALL_ROOT:-/}
cd var/sadm/pkg

active_base=`echo $SUNW_PATCHID | nawk '
	{ print substr($0, 1, match($0, "-")-1) } '`

List=`ls -d $PKGINST/save/${active_base}* 2>/dev/null`
if [ $? -ne 0 ]; then
	List=""
fi

for savedir in $List; do
        patch=`basename $savedir` 
        if [ $patch = $SUNW_PATCHID ]; then
		break
	fi

        # If we get here then the previous patch gets deleted
	if [ -f $savedir/undo ]; then
		mv $savedir/undo $savedir/obsolete
		echo $SUNW_PATCHID >> $savedir/obsoleted_by
	elif [ -f $savedir/undo.Z ]; then
		mv $savedir/undo.Z $savedir/obsolete.Z
		echo $SUNW_PATCHID >> $savedir/obsoleted_by
        elif  [ -f $savedir/remote ]; then
                `grep . $PKGSAV/$patch/remote | sed 's|STATE=.*|STATE=obsolete|' > $TEMP_REMOTE` 
                rm -f $PKGSAV/$patch/remote 
                mv $TEMP_REMOTE $PKGSAV/$patch/remote  
                rm -f $TEMP_REMOTE 
                echo $SUNW_PATCHID >> $savedir/obsoleted_by
	elif  [ -f $savedir/obsolete -o -f $savedir/obsolete.Z ]; then
		echo $SUNW_PATCHID >> $savedir/obsoleted_by
	fi
done

# If additional operations are required for this package, place
# those package-specific commands here.

#XXXSpecial_CommandsXXX#

#
# postinstall script
# Generate security certificates, start Apache, print startup message.

##############################################################################
#
# Default settings
#
##############################################################################
PERL=/usr/perl5/bin/perl
PERLINC=${BASEDIR}/SUNWscvw/lib/perl
HOSTNAME=`hostname`

PASSWORD=sPm30c9o # Must match server-request.conf
PROG=`basename $0`
PKGROOT=${BASEDIR}/SUNWscvw
PKGCONF=${PKGROOT}/conf
PKGSSL=${PKGCONF}/ssl
LOGDIR=${PKG_INSTALL_ROOT}/var/cluster/spm
PERL=/usr/perl5/bin/perl
OPENSSL=${BASEDIR}/SUNWscva/bin/openssl
LOGFILE=${LOGDIR}/messages
ROOTCERT=${PKGSSL}/sun-ca.crt
SERVER_SIGN_CONF=${PKGSSL}/server-sign.conf
RANDFILE=${PKGSSL}/random-bits; export RANDFILE
SERVER_REQUEST_CONF=${PKGSSL}/server-request.conf

##############################################################################
#
# set_hostname
#
# Attempt to get the fully qualified domain name for the host. If this
# succeeds, reset the parameters which rely upon it.
#
##############################################################################

set_hostname()
{
    TEMP=`${PERL} -I${PERLINC} -e "use Net::Domain qw(hostfqdn); print hostfqdn();"`

    if [ "$TEMP" != "" ]
    then
	HOSTNAME=${TEMP}
    fi

    SERVER_KEY=${PKGSSL}/${HOSTNAME}.key
    SERVER_REQUEST=${PKGSSL}/${HOSTNAME}.csr
    SERVER_CERT=${PKGSSL}/${HOSTNAME}.crt
}

##############################################################################
#
# Print internationalized error message
#
##############################################################################
error()
{
    echo "${PROG}: $@"
}

##############################################################################
#
# Generate the server key
#
##############################################################################
generate_server_key()
{
    ${OPENSSL} genrsa -out ${SERVER_KEY} 1024 > ${LOGFILE} 2>&1

    if [ $? -ne 0 ]
    then
	error `gettext "generate server key failed"`
    fi
}

##############################################################################
#
# Generate the certificate request
#
##############################################################################
generate_certificate_request()
{
    ${OPENSSL} req -new -config ${SERVER_REQUEST_CONF} \
		   -key ${SERVER_KEY} -out ${SERVER_REQUEST} \
		   >> ${LOGFILE} 2>&1
    
    if [ $? -ne 0 ]
    then
	error `gettext "generate certificate request failed"`
    fi
}

##############################################################################
#
# Sign the certificate request
#
##############################################################################
sign_server_certificate()
{
    # Generate a random certificate serial number
    RANDVAL=`generate_serial_number`

    # Create the necessary support directories
    mkdir -p ${PKGSSL}/ca.db.certs

    if [ $? -ne 0 ]
    then
	error `gettext "failed to created ca.db.certs directory"`
    fi

    echo ${RANDVAL} > ${PKGSSL}/ca.db.serial

    if [ $? -ne 0 ]
    then
	error `gettext "failed to created ca.db.serial file"`
    fi

    touch $PKGSSL/ca.db.index

    if [ $? -ne 0 ]
    then
	error `gettext "failed to created ca.db.index file"`
    fi

    # Sign the certificate
    ${OPENSSL} ca -config ${SERVER_SIGN_CONF} \
		  -key ${PASSWORD} -out ${SERVER_CERT} \
		  -batch -infiles ${SERVER_REQUEST} \
		  >> ${LOGFILE} 2>&1
    
    if [ $? -ne 0 ]
    then
	error `gettext "sign server certificate failed"`
    fi

    # Remove the support directories
    rm -rf $PKGSSL/ca.db.*

    if [ $? -ne 0 ]
    then
	error `gettext "ca support file removal failed"`
    fi
}

##############################################################################
#
# Verify the server certificate
#
##############################################################################
verify_server_certificate()
{
    ${OPENSSL} verify -CAfile ${ROOTCERT} ${SERVER_CERT} >> ${LOGFILE} 2>&1

    if [ $? -ne 0 ]
    then
	error `gettext "verify server certificate failed"`
    fi
}

##############################################################################
#
# Generate the serial number
#
##############################################################################
generate_serial_number() {
    SER=`${PERL} -e 'srand(time()^($$+($$<<15))); print int(rand 64000) + 1;'`
    NUMCHAR=`echo ${SER} | wc -m`
    ODDCHAR=`echo "(${NUMCHAR} - 1) % 2" | bc`

    if [ ${ODDCHAR} = 1 ]
    then
	echo "0${SER}"
    else
	echo $SER
    fi
}

##############################################################################
#
# Start or restart the server if we're not jumpstarting and if the 
#
##############################################################################
start_apache()
{
    if [ -f /var/cluster/spm/httpd.pid ]
    then
	/opt/SUNWscvw/bin/apachectl restart > /dev/null
    elif [ -f /usr/apache/bin/httpd ]
    then
	/opt/SUNWscvw/bin/apachectl startssl > /dev/null
    fi
    
    if [ $? -ne 0 ]
    then
	error `gettext "Apache start failed"`
	exit 0
    fi
}

##############################################################################
#
# Print out the final message if we're not jumpstarting
#
##############################################################################
print_final_message()
{
    echo
    echo "######################################################################"

    # If the Apache packages are not installed, print out a message telling the
    # user to install them
    if [ ! -f ${PKG_INSTALL_ROOT}/usr/apache/bin/httpd ]
    then
	echo "NOTE: To finish installing the SunPlex Manager, you must install"
	echo "the SUNWapchr and SUNWapchu Solaris packages and any associated"
	echo "patches. Then run '/etc/init.d/initspm start' to start the server."
	echo
    fi
    echo "Welcome to the SunPlex Manager. Your cluster is now ready to be"
    echo "installed or administered from a web browser. You may access the"
    echo "SunPlex Manager through your web browser by securely connecting"
    echo "to port 3000 on any node of your cluster, such as:"
    echo " "
    echo "	  https://${HOSTNAME}:3000"
    echo " "
    echo "If you are using the SunPlex Manager to install Sun Cluster, you"
    echo "must login as root or any other user which has a user id (uid) of"
    echo "0. If this cluster has already been installed, you must login as a"
    echo "user or role which has the solaris.cluster.gui RBAC authorization."
    echo "The user must have the same password on each node. For further "
    echo "instructions about configuring the SunPlex Manager to install or "
    echo "administer your cluster, see the Sun Cluster 3.1 System "
    echo "Administration Guide."
    echo "######################################################################"
}

##############################################################################
#
# Main function
#
##############################################################################

# Set the hostname and related parameters
set_hostname

# Generate the server certificate 
generate_server_key
generate_certificate_request
sign_server_certificate
verify_server_certificate

# Change the ownership of the messages file
chroot ${PKG_INSTALL_ROOT:-/} /usr/bin/chown spmadmin /var/cluster/spm/messages

# Start the server if we're not jumpstarting
if [ "$PKG_INSTALL_ROOT" = "/" ] || [ "$PKG_INSTALL_ROOT" = "" ]
then
    start_apache

    # Start event daemon if in clustered mode
    if [ -x /usr/sbin/clinfo ]; then
	/usr/sbin/clinfo >/dev/null 2>&1
	if [ $? -eq 0 ]; then
	    /var/cluster/spm/bin/scguieventd -d
	fi
    fi
fi

# Print the final message
print_final_message

# Exit 0 so that scinstall will succeed even if there are errors
exit 0
