#!/bin/sh
#  $Id$
#  Copyright (c) 2004, 2019, Oracle and/or its affiliates. All rights reserved.
#  This software code contains proprietary information 
#  and should be treated as confidential.
#
#  Component:
#  Author: mikemc
# 
#  This script generates a CA certificate, a peer certificate, signs the
#  peer certificate with the CA certificate and puts all the certificates
#  into a java keystore. 
#  These certificates are used by the intra-array SSL.

. "common-env.sh"


# Set port numbers. Start by sourcing info/ports.properties.
if [ -r $TTAINSTDIR/var/info/ports.properties ]; then
	. $TTAINSTDIR/var/info/ports.properties
fi

# Use these as defaults for config
tarantella_config_array_externalport=${externalport:-3144}
tarantella_config_array_port=${peerport:-5427}
tarantella_config_array_secureport=${secureport:-5307}
#also include proxiedhttpsurl for firewall traversal
tarantella_config_server_proxiedhttpsurl=${proxiedhttpsurl:-""}
tarantella_config_array_privilegeduser=${privilegeduser:-""}
tarantella_config_array_privilegedgroup=${privilegedgroup:-""}
#also include privileged username for web authentication
tarantella_config_array_webserveruser=${webserveruser:-""}
# Include web auth key refresh
tarantella_config_login_webauth_refreshkeyonrestart=${refreshkeyonrestart:-""}

#Include attribute to tell ttawebtop whether to be verbose or not
tarantella_config_server_cgiverbose=${cgiverbose:-""}

#Include attribute used to modify the archive names
tarantella_config_server_archivemodifier=${archivemodifier:-""}

#Attribute for cgi-bin to tell client to bootstrap from
tarantella_config_server_cgibin_bootscript=${bootscript:-""}

#Attribute passed to client so it knows the route to the server.
tarantella_config_array_netservice_proxy_routes=${routes:-""}

#Attribute passed to client so it knows the correct external name of the server
tarantella_config_server_netservice_proxy_externalnames=${externalnames:-""}

#SHould we use ssl on peer connections? Admin tools need to know
tarantella_config_security_peerssl_enabled=${peerssl:-"0"}

# Use the bootstrap.properties file if we can.
_propfile="$TTAINSTDIR/var/serverconfig/global/bootstrap.properties"
[ -s "${_propfile}" -a -r "${_propfile}" ] && {
eval `tr -d '\\\\' <"${_propfile}" | egrep -v "^[ 	]*#|'|^tarantella\.config\.(name|type)=" | sed "/=/!d
:dotloop
s/^\([^=]*\)\.\([^=]*=.*\)\$/\1_\2/
tdotloop
s/^\([^=]*\)=\(.*\)/\1='\2'/"`
}

# Set the values in the expected variables.
externalport=$tarantella_config_array_externalport
secureport=$tarantella_config_array_secureport
peerport=$tarantella_config_array_port

# Set DNS names. Use the bootstrap.properties file if we can.
_propfile="$TTAINSTDIR/var/serverconfig/local/bootstrap.properties"
[ -s "${_propfile}" -a -r "${_propfile}" ] && {
eval `tr -d '\\\\' <"${_propfile}" | egrep -v "^[ 	]*#|'|^tarantella\.config\.(name|type)=" | sed "/=/!d
:dotloop
s/^\([^=]*\)\.\([^=]*=.*\)\$/\1_\2/
tdotloop
s/^\([^=]*\)=\(.*\)/\1='\2'/"`
}

# We need defaults if the properties file is unreadable or corrupt.
peerhost=${tarantella_config_server_dns_peer:-`$TTAINSTDIR/bin/bin/ttahostname`}
externalhost="${tarantella_config_server_dns_external:-$peerhost}"
auxhost="$peerhost"

# Get the value of proxiedhttpsurl/cgiverbose/archivemodifier/bootscript from 
# server.properties
_propfile="$TTAINSTDIR/var/serverconfig/local/server.properties"
[ -s "${_propfile}" -a -r "${_propfile}" ] && {
eval `tr -d '\\\\' <"${_propfile}" | egrep -v "^[ 	]*#|'|^tarantella\.config\.(name|type)=" | sed "/=/!d
:dotloop
s/^\([^=]*\)\.\([^=]*=.*\)\$/\1_\2/
tdotloop
s/^\([^=]*\)=\(.*\)/\1='\2'/"`
}

# Get the properties from array.properties
_propfile="$TTAINSTDIR/var/serverconfig/global/array.properties"
[ -s "${_propfile}" -a -r "${_propfile}" ] && {
eval `tr -d '\\\\' <"${_propfile}" | egrep -v "^[ 	]*#|'|^tarantella\.config\.(name|type)=" | sed "/=/!d
:dotloop
s/^\([^=]*\)\.\([^=]*=.*\)\$/\1_\2/
tdotloop
s/^\([^=]*\)=\(.*\)/\1='\2'/"`
}

# Get web auth properties
_propfile="$TTAINSTDIR/var/serverconfig/global/webauth.properties"
[ -s "${_propfile}" -a -r "${_propfile}" ] && {
eval `tr -d '\\\\' <"${_propfile}" | egrep -v "^[ 	]*#|'|^tarantella\.config\.(name|type)=" | sed "/=/!d
:dotloop
s/^\([^=]*\)\.\([^=]*=.*\)\$/\1_\2/
tdotloop
s/^\([^=]*\)=\(.*\)/\1='\2'/"`
}

# Get peerssl properties
_propfile="$TTAINSTDIR/var/serverconfig/global/security.properties"
[ -s "${_propfile}" -a -r "${_propfile}" ] && {
eval `tr -d '\\\\' <"${_propfile}" | egrep -v "^[ 	]*#|'|^tarantella\.config\.(name|type)=" | sed "/=/!d
:dotloop
s/^\([^=]*\)\.\([^=]*=.*\)\$/\1_\2/
tdotloop
s/^\([^=]*\)=\(.*\)/\1='\2'/"`
}

proxiedhttpsurl=$tarantella_config_server_proxiedhttpsurl
privilegeduser=$tarantella_config_array_privilegeduser
privilegedgroup=$tarantella_config_array_privilegedgroup
webauthrefresh=$tarantella_config_login_webauth_refreshkeyonrestart
cgiverbose=$tarantella_config_server_cgiverbose
archivemodifier=$tarantella_config_server_archivemodifier
bootscript=$tarantella_config_server_cgibin_bootscript
routes=$tarantella_config_array_netservice_proxy_routes
externalnames=$tarantella_config_server_netservice_proxy_externalnames
peerssl=$tarantella_config_security_peerssl_enabled
peersslciphers=$tarantella_config_security_peerssl_ciphers
webserveruser=$tarantella_config_array_webserveruser

INSTALLDIR=$TTAINSTDIR
export INSTALLDIR

# 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_keystoregen ]; then
  . $TTAMSG/common
  . $TTAMSG/security_keystoregen
else
  echo "Unable to open message file: $TTAMSG/security_keystoregen"
  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; }
}

GetSafeName()
{
   MAX_LENGTH=64

   in_name="$1"
   var_name="$2"
   template_str="$3"

   safe_name="${in_name}"
   [ -x "/usr/bin/nawk" ] && AWK="nawk" || AWK="awk"

   # Calculate the length of the name passed in
   in_len=`echo "${in_name}" | ${AWK} '{print length($0)}'`

   # Calculate the max length of the name which can be
   # substituted in
   templateLen=`echo "${template_str}" | sed -e "s/${var_name}//g" | ${AWK} '{print length($0)}'`
   maxLen=`expr $MAX_LENGTH - ${templateLen}`
   # Check the limit
   if [ ${in_len} -gt ${maxLen} ]; then
      containsDots=`echo "${in_name}" | grep "\."`
      if [ -z "${containsDots}" ]; then
         # Cut to the max length
         safe_name=`echo "${in_name}" | cut -c -${maxLen}`
      else
         # Cut to the first .
         safe_name=`echo "${in_name}" | cut -d"." -f1`
      fi
   fi

   # Check the resulting string is short enough.
   # If not, repeat the process
   safe_len=`echo "${safe_name}" | ${AWK} '{print length($0)}'`
   if [ ${safe_len} -gt $MAX_LENGTH ]
   then
      safe_name=`GetSafeName "${safe_name}" "${var_name}" "${template_str}"`
   fi

   echo "${safe_name}"
}


OPENSSL_CONF="$TTAINSTDIR/etc/data/openssl.cnf"
TMPDIR="$TTADATADIR/tmp"
export OPENSSL_CONF
OPENSSL_BINARY=openssl
KEYTOOL="${SGD_JAVA_DIR}/keytool"
KEYSTOREPASSFILE="$TTADATADIR/info/key"
KEYSTOREDIR="$TTADATADIR/info/certs"
EXTERNALCERTSDIR="$TTADATADIR/info/certs/external"
KEYSTORE="$KEYSTOREDIR/keystore"
TRUSTSTORE="$KEYSTOREDIR/truststore"
CACERT_FILE="$KEYSTOREDIR/PeerCAcert.pem"
CAKEY_FILE="$KEYSTOREDIR/PeerCAkey.pem"
CAKEY_DER_FILE="$KEYSTOREDIR/PeerCAkey.der"
CSR_FILE="$KEYSTOREDIR/PeerServer.csr"
PEERCERT_FILE="$TTADATADIR/info/certs/PeerServercert.pem"
EXTERNALCERT_FILE="$EXTERNALCERTSDIR/$peerhost.cert.pem"
EXTERNALKEY_FILE="$EXTERNALCERTSDIR/$peerhost.key.pem"
EXTERNALCSR_FILE="$EXTERNALCERTSDIR/$peerhost.csr.pem"
CASERIAL_FILE="$KEYSTOREDIR/PeerCA.srl"
RAND_SOURCE="/dev/random"
RAND_FILE="$TTADATADIR/tmp/randfile"
TSPDIR=$TTADATADIR/tsp

safepeerhost=`GetSafeName "${peerhost}" "%HOST%" "/CN=%HOST% CA Cert"`
CADN="/CN=$safepeerhost CA Cert"
safepeerhost=`GetSafeName "${peerhost}" "%HOST%" "%HOST% CA"`
CAALIAS="$safepeerhost CA"
safepeerhost=`GetSafeName "${peerhost}" "%HOST%" "CN=%HOST%"`
PEERDN="CN=$safepeerhost"
safepeerhost=`GetSafeName "${peerhost}" "%HOST%" "%HOST% Peer Server"`
PEERALIAS="$safepeerhost Peer Server"
safeexternalhost=`GetSafeName "${externalhost}" "%HOST%" "/CN=%HOST%"`
EXTERNALDN="/CN=$safeexternalhost"
VALIDITY="3650"
KEYALG="rsa"
STOREPASS=`cat $KEYSTOREPASSFILE`
KEYPASS=`cat $KEYSTOREPASSFILE`
KEYLEN="2048"


while [ -n "$1" ]; do
    case "$1" in
    --peerca)
       DO_PEER_CA="t"
    ;;
    esac
    shift
done


usage()
{
  echo "$lf_keystoregen_usage" 1>&2
}

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

create_randfile() {
  ${OPENSSL_BINARY} rand -rand ${RAND_SOURCE} 1024 > ${RAND_FILE}
  chmod 0600  ${RAND_FILE}
  chown -R $privusr ${RAND_FILE}
  chgrp -R $privgrp ${RAND_FILE}
}

generate_external_cert() {

  #
  # Generate a key pair
  #
  $OPENSSL_BINARY req -newkey ${KEYALG}:${KEYLEN} -new -keyout ${EXTERNALKEY_FILE} -out ${EXTERNALCSR_FILE} -nodes -batch -subj "$EXTERNALDN" -rand "$RAND_FILE"
  if [ $? != 0 ]; then
    echo "$l_keygen_error"
    rm -f ${EXTERNALKEY_FILE} ${EXTERNALCSR_FILE}
    exit 2
  fi

  # 
  # Sign cert
  #
  $OPENSSL_BINARY x509 -req -sha256 -CA "${CACERT_FILE}" -CAkey "${CAKEY_FILE}" -CAserial "${CASERIAL_FILE}" -days "${VALIDITY}" < "${EXTERNALCSR_FILE}" > "${EXTERNALCERT_FILE}"
}
  
umask 0077

if [ ! -d "${KEYSTOREDIR}" ]; then
  mkdir ${KEYSTOREDIR}
fi
chmod 750 ${KEYSTOREDIR}

if [ ! -z "$TTARANDSOURCE" ] ; then
  RAND_SOURCE="$TTARANDSOURCE"
elif [ -r "/dev/urandom" ] ; then
    RAND_SOURCE="/dev/urandom"
fi

create_randfile
RANDFILE="$RAND_FILE"
export RANDFILE

if [ ! -f "${CASERIAL_FILE}" ]; then
  echo "01" > ${CASERIAL_FILE}
  chown -R $privusr ${CASERIAL_FILE}
  chgrp -R $privgrp ${CASERIAL_FILE}
fi

if [ ! -f "$KEYSTORE" -o -n "${DO_PEER_CA}" ]; then
  $OPENSSL_BINARY req -newkey ${KEYALG}:${KEYLEN} -new -x509 -keyout ${CAKEY_FILE} -out ${CACERT_FILE} -nodes -batch -subj "$CADN" -days "${VALIDITY}" -rand "$RAND_FILE"
 
  # 
  # Creates a version of the key in pkcs8 format
  #
  $OPENSSL_BINARY pkcs8 -topk8 -nocrypt -inform PEM -in ${CAKEY_FILE} -outform DER -out ${CAKEY_DER_FILE} 

  # Delete the CA cert from the KEYSTORE, if already exists
  ${KEYTOOL} -delete -alias "${CAALIAS}" -noprompt -keystore "${KEYSTORE}" -storepass "${STOREPASS}"
  # Delete the Peer cert from the KEYSTORE, if already exists
  ${KEYTOOL} -delete -alias "${PEERALIAS}" -noprompt -keystore "${KEYSTORE}" -storepass "${STOREPASS}"
  # Delete the CA cert from the TRUSTSTORE, if already exists
  ${KEYTOOL} -delete -alias "${CAALIAS}" -noprompt -keystore "${TRUSTSTORE}" -storepass "${STOREPASS}"
  
  # Generate our peer cert and key
  ${KEYTOOL} -genkey -keystore "${KEYSTORE}" -keyalg "${KEYALG}" -noprompt -storepass "${STOREPASS}" -alias "${PEERALIAS}" -dname "${PEERDN}" -validity "${VALIDITY}" -keypass "${KEYPASS}"

  # Import our CA cert to our key/trust store
  ${KEYTOOL} -import -alias "${CAALIAS}" -file "${CACERT_FILE}" -storepass "${STOREPASS}" -noprompt -keystore "${KEYSTORE}"

  # Generate CSR
  ${KEYTOOL} -certreq -file "${CSR_FILE}" -alias "${PEERALIAS}" -noprompt -storepass "${STOREPASS}" -keystore "${KEYSTORE}"

  # Sign CSR 
  $OPENSSL_BINARY x509 -sha256 -req -CA "${CACERT_FILE}" -CAkey "${CAKEY_FILE}" -CAserial "${CASERIAL_FILE}" -days "${VALIDITY}" < "${CSR_FILE}" > "${PEERCERT_FILE}"


  # import signed cert into keystore
  ${KEYTOOL} -import -trustcacerts -file "${PEERCERT_FILE}" -noprompt -storepass "${STOREPASS}" -keystore "${KEYSTORE}" -alias "${PEERALIAS}"

  # Create a trust store with only the CA cert in it.
  ${KEYTOOL} -import -alias "${CAALIAS}" -file "${CACERT_FILE}" -storepass "${STOREPASS}" -noprompt -keystore "${TRUSTSTORE}"

  # Sort out file ownership
  chown -R $privusr ${KEYSTOREDIR}
  chgrp -R $privgrp ${KEYSTOREDIR}

  # public keys in truststore need to be readable to all you may run the admin programs
  chmod a+r "${TRUSTSTORE}"
fi

# Generate certificates for the external cert
if [ ! -f "$EXTERNALCERT_FILE" ]; then
  [ ! -d "${EXTERNAL_CERTSDIR}" ] && { 
    mkdir ${EXTERNALCERTSDIR};
  }
  generate_external_cert
fi

# Make sure tsp directory exists for historical reasons.
if [ ! -d $TSPDIR ]; then
  MkTtaDir $TSPDIR
  if [ $? != 0 ]; then
    echo "$l_cant_create_tspdir"
    exit 1
  fi
  chmod 751 $TSPDIR
fi

