#! /bin/sh

# catch the kill signal (ctrl-c) and do cleanup
trap do_trap 1 2 3 6 9 13 15

if test "`echo -n \"testecho\"`" = "testecho"; then
    ECHOOPTION=" -n "
    ECHOTAIL=""
else
    ECHOOPTION=""
    ECHOTAIL='\c'
fi

recho() {

    echo $ECHOOPTION $@ $ECHOTAIL
}

############################################################
# main code section
############################################################
if test -z "${GLOBUS_LOCATION}"; then
    echo ""
    echo "ERROR: Please set GLOBUS_LOCATION to the" 
    echo "Globus installation directory before"
    echo "running this script"
    echo ""
    exit 1
fi

. ${GLOBUS_LOCATION}/libexec/globus-script-initializer
globus_source ${libexecdir}/globus-sh-tools.sh

PROGRAM_NAME=`echo $0 | ${GLOBUS_SH_SED-sed} 's|.*/||g'`

short_usage="$PROGRAM_NAME [-help] [ options ...]"

openssl_options=""

long_usage () {
    ${GLOBUS_SH_CAT-cat} >&2 <<EOF

${short_usage}

  Expects a certificate request as input from the -in argument, and prints
  the signed certificate to file specified by -out.

  Options:
    -force             : Sign a certificate request with subject that
                         matches an already signed certificate.
    -dir <cadir>       : Set the configure directory of the CA
    -in  <cert req>    : The cert request to sign, if not 
                         given a request is expected from stdin
    -out <signed cert> : The newly signed cert.  If not given,
                         the cert is written to stdout
    -<openssl option>  : Any of the options alllowed with the openssl ca command
    -openssl-help      : List possible options to the openssl ca command and exit
EOF
}

. $libexecdir/globus-args-parser-header

readCommandLine() {

    while test -n "$1" 
    do
        case $1 in
            -\?|-h|-help|-usage)
                long_usage
                exit 0
                ;;
            -force)
                force_sign="true"
                shift;
                ;;
            -dir)
                shift;
                GRID_CA_DIR=$1;
                shift;
                ;;
            -in)
                shift;
                INPUT_REQ_FILE=$1;
                shift;
                ;;
            -out)
                shift;
                SIGNED_OUTPUT_FILE=$1;
                shift;
                ;;
            -openssl-help)
                shift;
		openssl ca -help;
		exit;
		;;
	    *)
                openssl_options="$openssl_options $1"
                shift;
                ;;
        esac
    done
    
    if test -z "$INPUT_REQ_FILE"; then
        echo ""
        echo "ERROR: Please specify a request file using the -in option"
        echo ""
        exit 1
    else
        if test ! -r ${INPUT_REQ_FILE}; then
            echo ""
            echo "ERROR: The file: ${INPUT_REQ_FILE} is not readable"
            echo ""
            exit 1
        fi
    fi

    if test -z "$SIGNED_OUTPUT_FILE"; then
        echo ""
        echo "ERROR: Please specify a output file using the -out option"
        echo ""
        exit 1
    fi
}

do_trap() {

    echo ""
    echo "Normal program execution interrupted.  Exiting."
    echo ""
    do_cleanup
    exit 1
}

do_cleanup() {

    ${GLOBUS_SH_RM-rm} -f ${tmp_output}

    ${GLOBUS_SH_RM-rm} -f ${TMP_REQ_FILE} ${TMP_CERT_FILE}
}

readCommandLine "$@"

if test -z "$GRID_CA_DIR"; then
    GRID_CA_DIR=${HOME}/.globus/simpleCA/
fi

if test ! -f ${GRID_CA_DIR}/cacert.pem; then
    echo ""
    echo "No simple CA directory found.  Run setup-simple-ca before"
    echo "signing certificates."
    echo ""
    exit 1
fi

grid_ca_conf=${GRID_CA_DIR}/grid-ca-ssl.conf
openssl_cmd=${GLOBUS_LOCATION}/bin/openssl

TMP_REQ_FILE=/tmp/tmp_cert_req.pem.$$
TMP_CERT_FILE=/tmp/tmp_cert.pem.$$

${GLOBUS_SH_CP-cp} ${INPUT_REQ_FILE} ${TMP_REQ_FILE}

echo ${openssl_options} | grep "\-passin" > /dev/null
res1=$?
if test ! $res1 = 0; then
    echo ${openssl_options} | grep "\-key" > /dev/null
    res1=$?
fi

if test ! $res1 = 0; then
	echo ""
	recho "Enter password for the CA key: "
	${GLOBUS_SH_STTY-stty} -echo
	read password 0<&2
	${GLOBUS_SH_STTY-stty} echo
	echo ""
        openssl_options="$openssl_options -key ${password}"
fi

do_sign() {
 
tmp_output=/tmp/tmp_output.$$
${openssl_cmd} ca $openssl_options -batch -config ${grid_ca_conf} \
                  -in ${TMP_REQ_FILE} -out ${TMP_CERT_FILE} \
                  2> $tmp_output 

openssl_result=$?

SIGNED_SERIAL=`cat ${tmp_output} | ${GLOBUS_SH_GREP-grep} "Serial Number" | \
               ${GLOBUS_SH_SED-sed} -e "s/Serial Number ://"`

# check to see if an error occurred while signing
if test "${openssl_result}" = "1"; then

    echo ""
    echo "========== ERROR MESSAGES FROM OPENSSL =========="
    cat ${tmp_output} 1>&2
    echo "================================================="

    # check if the error was with 
    no_config_file=`${GLOBUS_SH_GREP-grep} "error loading the config file" ${tmp_output}`
    if test -n "${no_config_file}"; then

        echo ""
        echo "ERROR: No CA config file found."
        echo "Either simple CA setup package is not installed,"
        echo "or the config file is not located at:"
        echo ""
        echo "  ${grid_ca_conf}"
        echo ""
        do_cleanup
        exit 1
    fi

    # check if the CA's private key could be loaded
    wrong_password=`${GLOBUS_SH_GREP-grep} "unable to load CA private key" ${tmp_output}`
    if test -n "${wrong_password}"; then
    
        echo ""
        echo "ERROR: The CA private key could not be loaded."
        echo "Possibly an incorrect password for the CA key was used."
        echo ""
        do_cleanup
        exit 1
    fi

    # check that a certificate with the same subject has not
    # already been signed
    already_signed=`${GLOBUS_SH_GREP-grep} "ERROR:There is already a certificate" \
                                       ${tmp_output}`
    if test -n "${already_signed}"; then

        SIGNED_EXP_DATE=`cat ${tmp_output} | ${GLOBUS_SH_GREP-grep} "Expires on" | \
                     ${GLOBUS_SH_SED-sed} -e "s|Expires on[^:]*:\(.\{6\}\).*|\1|"`
        TZ="GMT"   
        export TZ
        CURRENT_DATE=`date +%y%m%d`
    
        if test "${SIGNED_EXP_DATE}" -lt "${CURRENT_DATE}" || test -n "${force_sign}"; then

            echo ""
            echo "Revoking previous certificate"

            tmp_revoke_output=/tmp/tmp_revoke_out.$$

            ${openssl_cmd} ca $openssl_options -batch -config ${grid_ca_conf} \
                    -revoke ${GRID_CA_DIR}/newcerts/${SIGNED_SERIAL}.pem \
                    2> ${tmp_revoke_output}
        
            ${GLOBUS_SH_RM-rm} -f ${tmp_revoke_output}

            echo "Signing new certificate"
            do_sign;
            return;

        else
            echo ""
            echo "There is already a valid certificate that matches this subject at:"
            echo
            echo "${GRID_CA_DIR}/newcerts/${SIGNED_SERIAL}.pem"
            echo
            echo "You can use the -force option to overwrite"
            echo "this certificate and create a new one."
            echo ""

            ${GLOBUS_SH_RM-rm} -f ${tmp_output}

            do_cleanup
            exit 1
        fi
    fi

    # check that the cert request matches the CA cert
    wrong_org=`${GLOBUS_SH_GREP-grep} "field needed to be the same" ${tmp_output}`
    if test -n "${wrong_org}"; then
    
        echo "" 
        echo "ERROR: The cert request does not match CA cert"
        echo "Check that the correct security config files are"
        echo "set during grid-cert-request"
        echo ""
        echo "The default configuration can be set using either"
        echo "the command:  grid-default-ca, or via the -ca option"
        echo "to grid-cert-request."
        echo ""
        do_cleanup
        exit 1
    fi

    echo ""
    do_cleanup
    exit 1
fi

}

do_sign;

NEW_SERIAL=`${openssl_cmd} x509 -in ${TMP_CERT_FILE} -noout -serial | ${GLOBUS_SH_SED-sed} -e "s|serial=||"`

echo ""
echo "The new signed certificate is at: ${GRID_CA_DIR}/newcerts/${NEW_SERIAL}.pem"
echo ""

CERT_OUTPUT_DIR=`dirname ${SIGNED_OUTPUT_FILE}`
if test -w "${CERT_OUTPUT_DIR}"; then
    ${GLOBUS_SH_CP-cp} ${TMP_CERT_FILE} ${SIGNED_OUTPUT_FILE}
else
    echo ""
    echo "ERROR: Cannot create the requested output certificate file"
    echo "   ${SIGNED_OUTPUT_FILE}"
    echo "Instead manually copy and rename the new signed certificate at"
    echo "   ${GRID_CA_DIR}/newcerts/${NEW_SERIAL}.pem"
    echo ""
fi

do_cleanup
exit

