#!/bin/sh
#  $Id: security_certuse.sh 109677 2015-03-31 12:24:31Z pc161604 $
#  Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
#  This software code contains proprietary information 
#  and should be treated as confidential.
#
#  Author: Patrick Caulfield
#
#  Installs a Certificate and optionally a key for SSL use.
#

# be paranoid about the current path
if [ -d /bin ]; then
  PATH=/bin:$PATH
fi
if [ -d /sbin ]; then
  PATH=/sbin:$PATH
fi
if [ -d /usr/bin ]; then
  PATH=/usr/bin:$PATH
fi
if [ -d /usr/sbin ]; then
  PATH=/usr/sbin:$PATH
fi
if [ -d /etc ]; then
  PATH=/etc:$PATH
fi
export PATH

N=""
C=""
if echo -n | grep n > /dev/null
then
  C="\c"
else
  N="-n"
fi
case "$MACHINEARCH" in
i3li*|ppli*) N="$N -e" ;;
esac
_ss_headlines="--------------------------------------------------------------------------"

if [ -f $TTAMSG/common -a -f $TTAMSG/security_certuse ]; then
  . $TTAMSG/common
  . $TTAMSG/security_certuse
else
  echo "Unable to open message file: $TTAMSG/security_certuse"
  exit 1
fi

GetPrivUsrGrp()
{
    cat $TTADATADIR/serverconfig/global/array.properties 2>/dev/null | awk -F= \
	'BEGIN { u="ttasys"; wu="ttaserv"; g="ttaserv" }
	$1 == "tarantella.config.array.privilegeduser" { u = $2 }
	$1 == "tarantella.config.array.webserveruser" { wu = $2 }
	$1 == "tarantella.config.array.privilegedgroup" { g = $2 }
	END { print u " " wu " " g }'
}
_privusrgrp=`GetPrivUsrGrp`
privusr=`expr "$_privusrgrp" : '\([^ ]*\) .*'`
webservusr=`expr "$_privusrgrp" : '.* \([^ ]*\) .*'`
privgrp=`expr "$_privusrgrp" : '.* \([^ ]*\)$'`

MkTtaDir()
{
    _newdirs="" _pflag=""
    case "$1" in
    -p) _pflag="-p"; shift
    esac
    for _d in "$@"; do
	while [ -n "$_d" ]; do
	    [ -d "$_d" ] && break
	    _newdirs="$_newdirs $_d"
	    _d=`dirname $_d`
	done
    done
    mkdir $_pflag "$@"
    [ -n "$_newdirs" ] && { chgrp $privgrp $_newdirs 2>/dev/null; chown $privusr $_newdirs 2>/dev/null; }
}


OPENSSL_BINARY=openssl
OPENSSL_HELPER=$TTABINDIR/scripts/openssl_lib.sh
TTA_COMMAND="$TTABINDIR/tarantella"
TSPDIR=$TTADATADIR/tsp
KEY_FILE=$TSPDIR/key.pem
KEY_PENDING_FILE=$TSPDIR/key.pending.pem
CERT_FILE=$TSPDIR/cert.pem
CSR_FILE=$TSPDIR/csr.pem
TMP_KEY=$TSPDIR/tmp.pem

A_VER=`cat ${TTADIR}/var/info/apacheversion 2>/dev/null`; A_DIR="${TTADIR}/webserver/apache/${A_VER}"

certfile=""
keyfile=""
usesamekey=""


usage() 
{
  echo "$lf_certuse_usage"
}

short_usage() {
    echo "$1" 1>&2
    echo "$sf_certuse_usage" 1>&2
}

#
# Does a "shift" only if there are some parameters left
#
SHIFT='if [ $# -ge 1 ]; then 
    last_shift=$1; 
    shift; 
else 
    short_usage "$l_missing_arg1$last_shift$l_missing_arg2";
    exit 1; 
fi'

#
# Does a quick check on a certificate file and exits if it's not valid. The
# error message depends on $2 which is only filled in if the certificate
# is in a file and NOT from stdin
#
validate_cert()
{
  grep "BEGIN.*CERTIFICATE" $1 >/dev/null 2>/dev/null
  if [ $? != 0 ];then
    if [ -n "$2" ];then
      echo "$l_invalid_cert_1$2$l_invalid_cert_2"
    else
      echo "$l_invalid_cert_3"
    fi
    exit 1
  fi
}

#
# Validate the key file similarly. A key can only come in a file so we don't
# need to customise the error for the stdin case
#
validate_key()
{
  grep "BEGIN.*PRIVATE KEY" $1 >/dev/null 2>/dev/null

  if [ $? != 0 ];then

    # if there is no specified keyfile, then we check the certificate
    # for a key, if no it is possible that the user wishes to reuse the
    # key already installed (ie. does not want to install the certificate
    # using the stdin option
    if [ "$3" = "reusecheck" ];then

	samekey_ans=${s_no}
[ -z "${i18n_yes}" ] && i18n_yes="${a_yes}"
[ -z "${i18n_no}" ] && i18n_no="${a_no}"
[ -z "${i18n_case_yes}" ] && i18n_case_yes="${a_case_yes}"
[ -z "${i18n_case_no}" ] && i18n_case_no="${a_case_no}"
[ -z "${i18n_s_yes}" ] && i18n_s_yes="${s_yes}"
[ -z "${i18n_s_no}" ] && i18n_s_no="${s_no}"
[ "${l_ex_key_comment}" != "NOPROMPT" ] && echo "${l_ex_key_comment}"
echo # blank line between prompt and question
_valid=false
while [ $_valid = false ]
do
  echo $N "${q_ex_key_q} [$samekey_ans] $C"
  read _answer
  if [ -z "$_answer" ]
  then
    _answer="$samekey_ans"   # default
  fi
  case "$_answer" in
    [${i18n_case_yes}]* )
	    _answer=$i18n_s_yes
	    _valid=true
	    ;;
    [${i18n_case_no}]* )
	    _answer=$i18n_s_no
	    _valid=true
	    ;;
  esac
done
samekey_ans="$_answer"

    
	case "$samekey_ans" in
	    ${s_yes})
		usesamekey="yes"
		;;
	    *)  echo "${l_notinstalled}"
		exit 1
	esac

    elif [ "$3" = "reuse" ]; then
        # Don't ask, just reuse the keyfile
        usesamekey="yes"
    else
	echo "$l_invalid_key_1$2$l_invalid_key_2"
	exit 1
    fi

  fi
}

#
# Parse command-line parameters
#
while [ -n "$1" ]; do
    case $1 in
        --certfile ) certfile=$2; eval "$SHIFT"; eval "$SHIFT";;
        --keyfile ) keyfile=$2; eval "$SHIFT"; eval "$SHIFT";;
        --help ) usage; exit 0;;
	* ) short_usage "$l_invalid_arg1$1$l_invalid_arg2"; exit 1;;
    esac
done


#
# Create $TSPDIR if it doesn't exist
#
if [ ! -d $TSPDIR ]; then
  MkTtaDir $TSPDIR
  if [ $? != 0 ]; then
    echo "$l_cant_create_tspdir"
    exit 1
  fi
  chmod 751 $TSPDIR
fi

#
# Ensure protection on the files
#
umask 077


### Check special conditions ###

#
# If we have --keyfile make sure we also have --certfile
#
if [ -n "$keyfile" -a -z "$certfile" ]; then
  echo "$l_keyfile_needs_certfile"
  usage
  exit 1
fi

#
# See if we have a private key. If we don't then a certificate is useless.
#
if [ ! -f "$KEY_FILE" -a -z "$keyfile" -a -z "$certfile" -a ! -f "$KEY_PENDING_FILE" ]; then
  echo "$l_no_key"
  exit 1
fi


#
# If we are installing a certificate but the key file is linked elsewhere
# then this is an error
#
if [ -z "$keyfile" -a -z "$certfile" -a -h "$KEY_FILE" -a ! -f "$KEY_PENDING_FILE" ];then
  echo "$l_cant_use_linked_key"
  exit 1
fi


### Check all KEY_FILE, KEY_PENDING_FILE & keyfile combinations ###

if [ -f "$KEY_FILE" -a -f "$KEY_PENDING_FILE" -a ! -h "$KEY_FILE" ]; then
# A key file already exists 
# A key pending file exists
# A keyfile arg may or may not have been gievn
# Confirm that we should over-write the keyfile with the key pending file, 
# unless the KEY_FILE is a link then just over-write it.
  newkey_ans=${s_no}

[ -z "${i18n_yes}" ] && i18n_yes="${a_yes}"
[ -z "${i18n_no}" ] && i18n_no="${a_no}"
[ -z "${i18n_case_yes}" ] && i18n_case_yes="${a_case_yes}"
[ -z "${i18n_case_no}" ] && i18n_case_no="${a_case_no}"
[ -z "${i18n_s_yes}" ] && i18n_s_yes="${s_yes}"
[ -z "${i18n_s_no}" ] && i18n_s_no="${s_no}"
[ "${l_key_already_exists}" != "NOPROMPT" ] && echo "${l_key_already_exists}"
echo # blank line between prompt and question
_valid=false
while [ $_valid = false ]
do
  echo $N "${q_newkey} [$newkey_ans] $C"
  read _answer
  if [ -z "$_answer" ]
  then
    _answer="$newkey_ans"   # default
  fi
  case "$_answer" in
    [${i18n_case_yes}]* )
	    _answer=$i18n_s_yes
	    _valid=true
	    ;;
    [${i18n_case_no}]* )
	    _answer=$i18n_s_no
	    _valid=true
	    ;;
  esac
done
newkey_ans="$_answer"


  case "$newkey_ans" in
    ${s_yes})
        ;;
    *)  echo "${l_notinstalled}"
        exit 1
    esac

elif [ -f "$KEY_FILE" -a -n "$keyfile" -a ! -h "$KEY_FILE" ]; then
# A key file already exists
# A key pending file doesn't exist
# A keyfile arg has been given
# Confirm that we should over-write the keyfile with the keyfile arg, 
# unless the KEY_FILE is a link then just over-write it.
  newkey_ans=${s_no}

[ -z "${i18n_yes}" ] && i18n_yes="${a_yes}"
[ -z "${i18n_no}" ] && i18n_no="${a_no}"
[ -z "${i18n_case_yes}" ] && i18n_case_yes="${a_case_yes}"
[ -z "${i18n_case_no}" ] && i18n_case_no="${a_case_no}"
[ -z "${i18n_s_yes}" ] && i18n_s_yes="${s_yes}"
[ -z "${i18n_s_no}" ] && i18n_s_no="${s_no}"
[ "${l_key_already_exists}" != "NOPROMPT" ] && echo "${l_key_already_exists}"
echo # blank line between prompt and question
_valid=false
while [ $_valid = false ]
do
  echo $N "${q_newkey} [$newkey_ans] $C"
  read _answer
  if [ -z "$_answer" ]
  then
    _answer="$newkey_ans"   # default
  fi
  case "$_answer" in
    [${i18n_case_yes}]* )
	    _answer=$i18n_s_yes
	    _valid=true
	    ;;
    [${i18n_case_no}]* )
	    _answer=$i18n_s_no
	    _valid=true
	    ;;
  esac
done
newkey_ans="$_answer"


  case "$newkey_ans" in
    ${s_yes})
        ;;
    *)  echo "${l_notinstalled}"
        exit 1
    esac
fi

# Any other combinations have either been ruled out by the special checks
# Or don't require any extra checks/prompts

#
# Link to a pre-exisiting key and certificate
#
if [ -n "$certfile" ]; then

#
# Make certfile and keyfile into full pathnames
#
  if [ "`echo $certfile|cut -b1`" != "/" ]; then
    certfile="$PWD/$certfile"
  fi

  if [ -n "$keyfile" ]; then
    if [ "`echo $keyfile|cut -b1`" != "/" ]; then
      keyfile="$PWD/$keyfile"
    fi
  fi

#
# Check that the files exist
#
  if [ ! -f "$certfile" ]; then
    echo "$l_certfile_does_not_exist"
    exit 2
  fi

  if [ -n "$keyfile" -a ! -f "$keyfile" ]; then
    echo "$l_keyfile_does_not_exist"
    exit 2
  fi

#
# Validate the certificate file and the key file. Of course they
# may be the same file but in this case we need to make sure that
# file has both a certificate and a key in it.
#
  validate_cert "$certfile" "$certfile"
  if [ -n "$keyfile" ]; then
    validate_key "$keyfile" "$keyfile"
  else
    validate_key "$certfile" "$certfile" "reuse"
  fi

  if [ -n "$usesamekey" ];then
    echo "$l_use_ex_key"
    if [ -f "$KEY_PENDING_FILE" ]; then
      keyfile=$KEY_PENDING_FILE
    else
      keyfile=$KEY_FILE
    fi
  fi

#
# print out certificate information
#
  # if there is no keyfile link the certfile
  if [ -n "$keyfile" ]; then
    ln -s $keyfile $TMP_KEY
  else
    ln -s $certfile $TMP_KEY
  fi

echo $_ss_headlines
echo "$h_ssleay_cert_check"
echo $_ss_headlines

    # Validate Key and Cert, then text summary.
  ${OPENSSL_HELPER} checkkey --cert=${certfile} --key=${TMP_KEY}
  
  [ $? -eq 0 ] && {
    ${OPENSSL_HELPER} textsummary --cert=${certfile}
  }

  errcode=$?

  # print out the correct message depending on the errorcode.

  echo ""

  if [ $errcode -eq 0 ]; then 
    # a match!
    echo "$l_ssleay_key_match"
  else 
    if [ $errcode -eq 7 ]; then 
      # NOT a match
      echo "$l_ssleay_key_mismatch"
      echo "$l_ssleay_wrong_key"
    else
      # various errors due to ssleay
      echo "$l_ssleay_check_failure"
      if [ $errcode -eq 6 ]; then 
  	echo "$l_ssleay_no_key"
      elif [ $errcode -eq 5 ]; then 
          echo "$l_ssleay_cert_extract"
      elif [ $errcode -eq 4 ]; then 
  	echo "$l_ssleay_bad_cert"
      elif [ $errcode -eq 3 ]; then 
  	echo "$l_ssleay_ctx_failure"
      elif [ $errcode -eq 2 ]; then 
    	echo "$l_ssleay_key_mismatch" 
      elif [ $errcode -eq 1 ]; then 
  	echo "$l_ssleay_bad_options"
      else
  	# unknown error 
  	echo "$l_ssleay_unknown"
      fi
    fi
    echo "${l_notinstalled}"
    rm -f $TMP_KEY
    exit 1
  fi
  echo ""

  rm -f $TMP_KEY


#
# Do we already have a certificate we want to keep ?
#
  if [ -f "$CERT_FILE" ]; then
    newcert_ans=${s_no}

[ -z "${i18n_yes}" ] && i18n_yes="${a_yes}"
[ -z "${i18n_no}" ] && i18n_no="${a_no}"
[ -z "${i18n_case_yes}" ] && i18n_case_yes="${a_case_yes}"
[ -z "${i18n_case_no}" ] && i18n_case_no="${a_case_no}"
[ -z "${i18n_s_yes}" ] && i18n_s_yes="${s_yes}"
[ -z "${i18n_s_no}" ] && i18n_s_no="${s_no}"
[ "${l_certificate_already_exists}" != "NOPROMPT" ] && echo "${l_certificate_already_exists}"
echo # blank line between prompt and question
_valid=false
while [ $_valid = false ]
do
  echo $N "${q_newcert} [$newcert_ans] $C"
  read _answer
  if [ -z "$_answer" ]
  then
    _answer="$newcert_ans"   # default
  fi
  case "$_answer" in
    [${i18n_case_yes}]* )
	    _answer=$i18n_s_yes
	    _valid=true
	    ;;
    [${i18n_case_no}]* )
	    _answer=$i18n_s_no
	    _valid=true
	    ;;
  esac
done
newcert_ans="$_answer"


    case "$newcert_ans" in
	${s_yes})
	;;
    *)  echo "${l_notinstalled}"
    exit 1
    esac
  fi


  rm -f $CERT_FILE
  ln -s $certfile $CERT_FILE
  
  # if we're not re-using the private key, link in the new key file
  if [ -z "$usesamekey" ];then
    rm -f $KEY_FILE
  
    # If a keyfile was specified then link to that, else link the key to the
    # certificate file in the assumption it has both in it.
    if [ -n "$keyfile" ]; then
	ln -s $keyfile $KEY_FILE
    else
	ln -s $certfile $KEY_FILE
    fi
  elif [ -f "$KEY_PENDING_FILE" ]; then
    mv "$KEY_PENDING_FILE" "$KEY_FILE"
  fi
 
  # Set file owners
  chown -R $privusr $TSPDIR 2>/dev/null
  chgrp -R $privgrp $TSPDIR 2>/dev/null

  # Update our root certs, we don't want the internal ones any more.
  $TTA_COMMAND security setrootcerts

 echo "$l_linked_to_certfile"
 exit 0

fi

#
# Read a certificate file from stdin
#
TMPFILE=$TSPDIR/cert.tmp
rm -f $TMPFILE

cat >$TMPFILE
if [ -f "$TMPFILE" ]
then
  validate_cert $TMPFILE ""

  rm -f $CERT_FILE
  mv $TMPFILE $CERT_FILE
  if [ $? != 0 ]; then
    echo "$l_error_copying"
    exit 1
  fi

  # echo the cert to stderr and check that the key and cert match
echo $_ss_headlines
echo "$h_ssleay_cert_check"
echo $_ss_headlines


  if [ -f "$KEY_PENDING_FILE" ]; then 
    # Validate Key and Cert, then text summary.

    ${OPENSSL_HELPER} checkkey --cert=${CERT_FILE} --key=${KEY_PENDING_FILE}
    errcode=$?
  else
    # Validate Key and Cert, then text summary.

    ${OPENSSL_HELPER} checkkey --cert=${CERT_FILE} --key=${KEY_FILE}
    errcode=$?
  fi

  if [ $errcode -eq 0 ]; then 
    # a match!
    ${OPENSSL_HELPER} textsummary --cert=${CERT_FILE}
    echo ""
    echo "$l_ssleay_key_match"
  else
    if [ $errcode -eq 7 ]; then 
      # NOT a match
      echo "$l_ssleay_key_mismatch"
      echo "$l_ssleay_wrong_key"
    else
      # various errors due to ssleay
      echo "$l_ssleay_check_failure"
      if [ $errcode -eq 6 ]; then 
  	echo "$l_ssleay_no_key"
      elif [ $errcode -eq 5 ]; then 
        echo "$l_ssleay_cert_extract"
      elif [ $errcode -eq 4 ]; then 
    	echo "$l_ssleay_bad_cert"
      elif [ $errcode -eq 3 ]; then 
  	echo "$l_ssleay_ctx_failure"
      elif [ $errcode -eq 2 ]; then 
  	echo "$l_ssleay_key_mismatch" 
      elif [ $errcode -eq 1 ]; then 
  	echo "$l_ssleay_bad_options"
      else
	# unknown error 
        echo "$l_ssleay_unknown"
      fi
    fi
    echo "${l_notinstalled}"
    rm -f $TMP_KEY
    exit 1
  fi

  if [ -f "$KEY_PENDING_FILE" ]; then
    mv "$KEY_PENDING_FILE" "$KEY_FILE"
  fi

  echo ""
  echo "$l_cert_installed"
  echo
else
  rm -f $TMPFILE
  echo "$l_notinstalled"
fi

# Set file owners
chown -R $privusr $TSPDIR 2>/dev/null
chgrp -R $privgrp $TSPDIR 2>/dev/null

# Update our root certs, we don't want the internal ones any more.
$TTA_COMMAND security setrootcerts

exit 0
