#!/bin/sh

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

. ${GLOBUS_LOCATION}/libexec/globus-script-initializer

secconfdir=/etc/grid-security

#
# Sample script to generate a certificate request which can be sent 
# to the Globus CA, who will sign it. This script uses the 
# globus-ssl.conf file.
#
# When generating a certificate request and private key for a 
# globus gatekeeper daemon, use the -nopw option, so the
# key is not protected by pass phrase. 
#
PROGRAM_NAME=`echo $0 | ${GLOBUS_SH_SED-sed} 's|.*/||g'`

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

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

${short_usage}

  Options:
    -cn <name>         : Common name of the user
    -service <name>    : Create certificate for a service named <name>
    -host <FQDN>       : Create certificate for a host named <FQDN>
    -dir <dir_name>    : User certificate directory [ '$HOME/.globus' ]
    -cert <file>       : File name of the certificate
    -key <file>        : File name of the user key
    -req <file>        : File name of the certificate request
    -nopw              : Create certificate without a passwd
    -int[eractive]     : Prompt user for each component of the DN
    -force             : Overwrites prexisting certifictes

EOF
}

. $libexecdir/globus-args-parser-header

#SSL related needs
PATH=${GLOBUS_LOCATION}/bin:${PATH}
SSL_EXEC="${GLOBUS_LOCATION}/bin/openssl"
SSL_CONFIG="${secconfdir}/globus-user-ssl.conf"
SSL_USER_CONFIG="${secconfdir}/globus-user-ssl.conf"
SSL_HOST_CONFIG="${secconfdir}/globus-host-ssl.conf"


# TEMP FILES
REQ_HEAD=${secure_tmpdir}/$PROGRAM_NAME.$$.head
REQ_INPUT=${secure_tmpdir}/$PROGRAM_NAME.$$.input
REQ_OUTPUT=${secure_tmpdir}/$PROGRAM_NAME.$$.output
RAND_TEMP=${secure_tmpdir}/$PROGRAM_NAME.$$.random


# DEFault Generated Files
DEF_GLOBUS_DIR="${HOME}/.globus"
DEF_CERT_FILE='${GLOBUS_DIR}/usercert.pem'
DEF_KEY_FILE='${GLOBUS_DIR}/userkey.pem'
DEF_REQUEST_FILE='${GLOBUS_DIR}/usercert_request.pem'



# Info sent with the certificate
SUBJECT=
USERID="`${GLOBUS_SH_WHOAMI-whoami}`"
HOST="`${bindir}/globus-hostname`"
SERVICE=
SERVICE_HOST=
INTERACTIVE=
NO_DES=

CERTREQ="${bindir}/grid-cert-request"


cleanup () {
  : 
  # ${GLOBUS_SH_RM-rm} -f ${REQ_HEAD} ${REQ_INPUT} ${REQ_OUTPUT}
  ${GLOBUS_SH_RM-rm} -f ${RAND_TEMP}
}

trap cleanup 0

security_conf=${secconfdir}/grid-security.conf

# See if we can proceed
. ${security_conf}



## Other cleanup routines.


abort_cleanup () {
  :
  cleanup
  ${GLOBUS_SH_RM-rm} -f ${CERT_FILE} ${KEY_FILE} ${REQUEST_FILE}
}

readCommandLine () {
  # Expects $* from the shell invocation

  while [ "X$1" !=  "X" ]
  do
    case $1 in
      -\?|-h|-help|-usage)
         long_usage
         exit 0
         ;;

     -cn | -commonname)
       	 COMMON_NAME="$2"
         shift ; shift
         ;;

     -service)
         SERVICE="$2"
         NO_DES="-nodes"
         shift ; shift
         ;;


     -host)
         SERVICE=${SERVICE:-"host"}
	 SERVICE_HOST="$2"
         NO_DES="-nodes"

         shift ; shift
         ;;

     -dir)
         DEF_GLOBUS_DIR="$2"
         shift ; shift
         ;;

     -cert|-certificate)
         DEF_CERT_FILE="$2"
         shift ; shift
        ;;

     -key)
	 DEF_KEY_FILE="$2"
	 shift ; shift
	 ;;

     -req|-request)
	 DEF_REQUEST_FILE="$2"
	 shift ; shift
	 ;;

     -nopw|-nodes|-nopassphrase)
         NO_DES="-nodes"
         shift
         ;;

     -int|-interactive)
         INTERACTIVE="TRUE"
         shift
         ;;
     -force)
         FORCE="TRUE"
         shift
         ;;
     *)
	 globus_args_unrecognized_option "$1"
         ;;
    esac
  done
  if [ -z "${SERVICE}" ] ; then
	emitDirections ${SERVICE}
	exit 0
  elif [ -z "${SERVICE_HOST}" ] ; then
       echo "Missing -host parameter"
       exit 0
  fi
}

###########################################################
# createInputFile
#   Generate a inputfile to be given to SSL that fully 
#   specifies the DN of the user
#   files
###########################################################
createInputFile () {
  _common_name="$1"
  _config_file="$2"

# Parse the ssleay configuration file, to determine the
# correct default parameters

${GLOBUS_SH_AWK-awk}  < $_config_file '
 
  /^\[ req_distinguished_name \]/ {
     start_parsing=1;
     next;
  }

  /^\[ .*/ {
     start_parsing=0;
     next;
  }

  /^[a-zA-Z0-9\.]*_default[ \t]*=/ && start_parsing==1 {
     split($0, a, "=");
     # default value is in a[2], but we should strip of leading ws
     for(i=1;substr(a[2],i,1) == " " || substr(a[2],i,1) == "\t"; i++);
     print substr(a[2], i);
     next;
}
'

   echo ${_common_name}
}


###########################################################
# createServiceRequestHeader
###########################################################
createServiceRequestHeader () {

    ${GLOBUS_SH_CAT-cat} <<EOF
This is a Certificate Request file:
   
=========================================================================
Certificate Subject:

    ${SUBJECT}

The above string is known as your ${SERVICE} certificate subject, and it 
uniquely identifies this ${SERVICE}.


EOF
  
}

###########################################################
# createRequestHeader
###########################################################
createRequestHeader () {
  # This is the information that is sent with the certificate

  # The following two lines are provided by the Globus CA

  #: Enclosed is your new Globus certificate for
  #:
  #:"${SUBJECT}"
  #:


    ${GLOBUS_SH_CAT-cat} <<EOF
This is a Certificate Request file:

=========================================================================
Certificate Subject:

    ${SUBJECT}

The above string is known as your certificate subject, and it 
uniquely identifies you.

To start using Globus services you must perform two steps.

   1. Have your subject name added to the gridmap file at 
      each resource you intend to do.  You will need to make
      a request to the system administrator at each of these
      sites.

   2. Save this e-mail message into the following file.

 
${CERT_FILE}


      You need not edit this message in any way. Simply 
      save this e-mail message to the file.

EOF
  
}



###########################################################
# checkGlobusSystem:  
#   Ensure that the Globus SSL Configuration files
#   have been created by the Globus Sys.Admin
###########################################################
checkGlobusSystem () {

  #if [ ! -r "$SSL_USER_CONFIG" ] ||
  if [ ! -r "$SSL_HOST_CONFIG" ] ; then
    echo
    echo "The Globus Configuration files have not been setup." 1>&2
    echo "Please have the local Globus Administrator run"      1>&2
    echo "    \"${sbindir}/grid-security-config\""             1>&2
    echo "to configure Globus at your site."                   1>&2
    exit 1
  fi
}



###########################################################
# check4Certs:  
#   Ensure that the user does not overwrite their
#   security files.
###########################################################
check4Certs () {
  _exists="FALSE"

  if [ -r ${REQUEST_FILE} ] ; then
     ${GLOBUS_SH_PRINTF-printf} "\n    ${REQUEST_FILE} already exists" 1>&2
     ${GLOBUS_SH_CHMOD-chmod} u+w ${REQUEST_FILE}
    _exists=TRUE
  fi
  if [ -r ${CERT_FILE} ] ; then
     ${GLOBUS_SH_PRINTF-printf} "\n    ${CERT_FILE} already exists" 1>&2
     ${GLOBUS_SH_CHMOD-chmod} u+w ${CERT_FILE}
    _exists=TRUE
  fi
  if [ -r ${KEY_FILE} ] ; then
     ${GLOBUS_SH_PRINTF-printf} "\n    ${KEY_FILE} already exists" 1>&2
     ${GLOBUS_SH_CHMOD-chmod} u+w ${KEY_FILE}
    _exists=TRUE
  fi

  
  if [ "X$_exists" = "XTRUE" ] ; then
    if [ "X$FORCE" = "XTRUE" ] ; then
      ${GLOBUS_SH_RM-rm} -f ${CERT_FILE} ${KEY_FILE} ${REQUEST_FILE}
      echo
      echo
    else 
      ${GLOBUS_SH_PRINTF-printf} "\n\nIf you wish to overwrite, run the script again with -force.\n" 1>&2
      exit 1
    fi
  fi

}

###########################################################


###########################################################
# setupGlobusDir:  
#   Create a directory in the HOME directory of the user
#   to store globus related stuff.
###########################################################
setupGlobusDir () {
 
  if [ ! -d ${GLOBUS_DIR} ] ; then
    ${GLOBUS_SH_MKDIR-mkdir} ${GLOBUS_DIR}
    if [ $? -ne 0 ] ; then
      exit $?
    fi 
  fi
}

#############################################################


###########################################################
# getUserCN
#   Determine the name of the user
###########################################################
getUserCN () {

   _common_name="${COMMON_NAME}"

   # 1. Command line argument
   # 2. Query the system
   # 3. Prompt the user

   if [ -z "${_common_name}" ] ; then 
     ${GLOBUS_SH_FINGER-finger} -lm ${USERID}  >/dev/null 2>&1
     if [ $? -eq 0 ] ; then 
       _common_name="`${GLOBUS_SH_FINGER-finger} -lm ${USERID}         |\
                      ${GLOBUS_SH_GREP-grep} ${USERID}               |\
                      ${GLOBUS_SH_AWK-awk} -F: '{ print $3; exit }' |\
                      ${GLOBUS_SH_CUT-cut} -c2- `"
     fi
   fi

   if [ -z "${_common_name}" ] ;  then
      ${GLOBUS_SH_PRINTF-printf} "Enter your name, e.g., John Smith: " 1>&2
      read _common_name
   fi

   echo ${_common_name}
}



###########################################################
# getHostCN
#   Determine the name of the host for a host certificate
###########################################################
getHostCN () {

   _common_name="${COMMON_NAME}"

   # 1. Command line -cn argument
   # 2. Create from -host argument

   if [ -z "${_common_name}" ] ; then 
      # Check SERVICE_HOST and make sure it looks like a FQDN
      ${GLOBUS_SH_ECHO-echo} ${SERVICE_HOST} | ${GLOBUS_SH_GREP-grep} "\." >/dev/null 2>&1
      if [ $? -eq 1 ] ; then
	${GLOBUS_SH_ECHO-echo} "The hostname ${SERVICE_HOST} does not appear to be fully qualified." 1>&2
	${GLOBUS_SH_PRINTF-printf} "Do you wish to continue? [n] " 1>&2
	read _response

	case X${_response} in
	Xy|XY|Xyes|XYES|XYes)
	  ;;

	*)
	  ${GLOBUS_SH_ECHO-echo} "Aborting" 1>&2
	  exit 1
	  ;;
	esac
      fi
      
      _common_name="${SERVICE}/${SERVICE_HOST}"
   fi

   echo ${_common_name}
}



###########################################################
# createCerts
#   Create the certificate, key, and certificate request
#   files
###########################################################
createCerts () {
  
  if [ -z "${SERVICE}" ] ; then
    echo "A certificate request and private key is being created."
    echo "You will be asked to enter a PEM pass phrase."
    echo "This pass phrase is akin to your account password, "
    echo "and is used to protect your key file."
    echo "If you forget your pass phrase, you will need to"
    echo "obtain a new certificate."
    echo
  fi

  #------------------------
  # Create the Certificate File
  umask 022
  ${GLOBUS_SH_TOUCH-touch} ${CERT_FILE}


  #------------------------
  # Create some semi random data for key generation 
  umask 066
  ${GLOBUS_SH_TOUCH-touch} ${RAND_TEMP}
  if [ -r /dev/urandom ] ; then
	head -c 1000 /dev/urandom >> ${RAND_TEMP} 2>&1
  fi
  date >> ${RAND_TEMP} 2>&1
  netstat -in >> ${RAND_TEMP} 2>&1
  ps -ef >> ${RAND_TEMP} 2>&1
  ls -ln ${HOME} >> ${RAND_TEMP} 2>&1
  ls -ln /tmp >> ${RAND_TEMP} 2>&1

  umask 266
  #------------------------
  # Create the Key and Request Files

  if [ -n "${INTERACTIVE}" ] ; then
    ${SSL_EXEC} req -new -keyout ${KEY_FILE} -out ${REQ_OUTPUT} \
              -rand ${RAND_TEMP}:/var/adm/wtmp:/var/log/messages \
              -config ${SSL_USER_CONFIG} ${NO_DES}
    RET=$?
    ${GLOBUS_SH_RM-rm} -f ${REQ_TEMP}
  else
    if [ -z "${SERVICE}" ]; then
        used_config="${SSL_USER_CONFIG}"
    else
        used_config="${SSL_HOST_CONFIG}"
    fi
    createInputFile "${COMMON_NAME}" "${used_config}" >${REQ_INPUT}

    ${SSL_EXEC} req -new -keyout ${KEY_FILE} \
              -rand ${RAND_TEMP}:/var/adm/wtmp:/var/log/messages \
              -out ${REQ_OUTPUT} -config ${used_config} \
              ${NO_DES} < ${REQ_INPUT} 
    RET=$?
    ${GLOBUS_SH_RM-rm} -f ${REQ_TEMP}

    # You can't separate the SSL output, it all goes to stderr
    # including the prompts.
    # Don't remove ssleay output on error as it may be useful
    if [ ${RET} -eq 0 ] ; then
      ${GLOBUS_SH_CLEAR-clear}
    fi

    ${GLOBUS_SH_RM-rm} -f ${REQ_INPUT}
  fi

  if [ ${RET} -ne 0 ] ; then
     echo "Error number ${RET} was returned by " 1>&2
     echo "   ${SSL_EXEC}"                    1>&2
     exit ${RET}
  fi

  umask 022
  #------------------------
  # Insert instructions into the request file


  SUBJECT="`${SSL_EXEC} req -text -noout < ${REQ_OUTPUT} 2>&1 |\
            ${GLOBUS_SH_GREP-grep} 'Subject:' | ${GLOBUS_SH_AWK-awk} -F: '{print $2}' |\
            ${GLOBUS_SH_CUT-cut} -c2- `"

  #Convert the subject to the correct form.
  SUBJECT=`echo "/"${SUBJECT} | ${GLOBUS_SH_SED-sed} -e 's|, |/|g'`

  if [ -z "${SERVICE}" ] ; then
	  createRequestHeader >${REQ_HEAD}
  else
	  createServiceRequestHeader >${REQ_HEAD}
  fi

  # Finalize the Request file.
  ${GLOBUS_SH_CAT-cat} ${REQ_HEAD} ${REQ_OUTPUT} >${REQUEST_FILE}
  ${GLOBUS_SH_RM-rm} -f ${REQ_HEAD} ${REQ_OUTPUT}
}



# DEFUNCT ###
###########################################################
# getPassPhrase
#   Prompt the user for the PEM pass phrase
###########################################################
getPassPhrase () {

   _pass_phrase=
   _double_check=

   ${GLOBUS_SH_PRINTF-printf} "Enter PEM pass phrase:  " 
   ${GLOBUS_SH_STTY-stty} -echo
   read _pass_phrase
   while [ "X${_pass_phrase}" != "X${_double_check}" ]
   do
     ${GLOBUS_SH_PRINTF-printf} "\nReenter PEM pass phrase: "
     read _double_check

     if [ "X${_pass_phrase}" != "X${_double_check}" ] ; then 
       _double_check=
       ${GLOBUS_SH_PRINTF-printf} "\nEnter PEM pass phrase:   "
       read _pass_phrase
     fi
   done
   echo
   ${GLOBUS_SH_STTY-stty} echo

   PASS_PHRASE="${_pass_phrase}"
}


###########################################################
# emitDirections
#   Provide instructions to the end user
###########################################################
emitDirections () {

  if [ -z "${SERVICE}" ] ; then
    echo 
    echo "To obtain a personal certificate, please follow the directions"
    echo "outlined on the ESnet DOE Science Grid Certification Authority at:"
    echo "http://envisage.es.net/pages/cert-request.htm"
  else 
    echo 
    echo "A private ${SERVICE} key and a certificate request has been generated"
    echo "with the subject:" 
    echo 
    echo "${SUBJECT}"
    echo
    echo "----------------------------------------------------------"
    echo
    echo "The private key is stored in ${KEY_FILE}"
    echo "The request is stored in ${REQUEST_FILE}"
    echo
     echo "Please go to https://pki1.doesciencegrid.org and choose the "
    echo "Grid or server->ssl server menu item on the Enrollment page" 
    echo "Then and cut and paste the"
    echo "${REQUEST_FILE} into the PKCS#10 text field."
    echo
    echo "To install this ${SERVICE} certificate, follow the URL link in the" 
    echo "message sent to you by the CA, and cut and paste the" 
    echo "\"Base64 encoded certificate\" into the ${CERT_FILE}"
    echo
  
  fi

}




###########################################################
# MAIN
###########################################################

readCommandLine "$@"

# Set the actual file names

#Make these absolute file names if thy are not

absolutePath () {
   _file_name="$1"

   case $_file_name in
      /*)
        echo ${_file_name}
        ;;
      *)
        echo ${PWD}/${_file_name}
    esac
}



GLOBUS_DIR="`eval echo      ${DEF_GLOBUS_DIR}`"
CERT_FILE="`eval echo       ${DEF_CERT_FILE}`"
KEY_FILE="`eval echo        ${DEF_KEY_FILE}`"
REQUEST_FILE="`eval echo    ${DEF_REQUEST_FILE}`"


GLOBUS_DIR="`absolutePath      ${GLOBUS_DIR}`"
CERT_FILE="`absolutePath       ${CERT_FILE}`"
KEY_FILE="`absolutePath        ${KEY_FILE}`"
REQUEST_FILE="`absolutePath    ${REQUEST_FILE}`"




checkGlobusSystem

# Only set up the Globus Directory for users.
if [ -z "${SERVICE}" ] ; then
  setupGlobusDir
fi

check4Certs

trap abort_cleanup 0

if [ -z "${SERVICE}" ] ; then
  COMMON_NAME="`getUserCN`"
else
  COMMON_NAME="`getHostCN`"
fi

    # Check for abort
if [ -z "${COMMON_NAME}" ]; then
    exit 1
fi

createCerts
RET=$?

COMMON_NAME="`echo ${SUBJECT} | ${GLOBUS_SH_SED-sed} -e 's|^.*/CN=||'`"
emitDirections ${SERVICE}
trap cleanup 0

exit ${RET}





