#! /bin/bash
#set -xv
#=========================================================================
# Copyright (C) GemTalk Systems 1986-2024.  All Rights Reserved..
#
# Name - newhost
# Installed as - newhost
#
# Written By: Martin McClure and Norm Green
#
# Purpose -
#
# Creates a new host certificate chain
# For a given stone specified by the -s argument, the newstone
# and newhostCA scripts must be run before this one.
#
# Requirements -
#
# The following environment variables must be defined:
#
# GEMSTONE or OPENSSL_PREFIX_DIR
# GEMSTONE_CERT_DIR - A directory where newly created certificates and
#                     subdirectories will be placed.
#
#=========================================================================

cmd=`basename $0`

usage(){
    echo "Usage: $cmd -h | -s <stoneName> [-a <cidr>][-d <daysValid>] <hostName>" >&2
    echo "  where: cidr is an IP address restriction in CIDR format (default: no restriction)" >&2  
    echo "         daysValid is the number of days the host cert will be valid (default: 30 days)" >&2
    exit 1
}

stoneName=""
daysValid=30
ARGC=$#

while getopts "hs:a:d:" opt; do
    case $opt in
        h)
            usage
            ;;
	d)
	    daysValid=${OPTARG}
	    ;;
        s)
          stoneName=${OPTARG}
          ;;
        a)
          cidr=${OPTARG}
          ;;
        \?)
          usage
          ;;
        :)
          echo "Option -${OPTARG} requires an argument." >&2
          usage
          ;;
    esac
done

shift $((OPTIND-1))
hostName=$1

# 48065
if [ $OPTIND -ne $ARGC ]; then
    echo "[Error]: hostName must be the last argument."
    usage
fi

# 47501 - handle symlinks
fullPath=`readlink -e -n $0`
scriptDir=`dirname $fullPath`
if [ ! -f $scriptDir/environment.sh ]; then
    echo "[Error]: Cannot find environment.sh setup script"
    exit 1
fi
. ${scriptDir}/environment.sh

checkStoneExists $stoneName
checkDaysValid $daysValid

if [ -z "$hostName" ]; then
    echo "[Error]: Missing host argument" >&2
    usage
fi

## IP address restriction defaults to unrestricted if not set.
unused=${cidr:=0.0.0.0/0}
checkCidrAddress $cidr

hostDir=${hostsDir}/${hostName}

if [ -d ${hostDir} ]; then
    echo "[Error]: Host named '$hostName' already exists for stone '$stoneName'." >&2
    echo "[Error]: To remove, execute 'rmhost -s $stoneName $hostName'" >&2
    echo "[Error]: Otherwise, select a new and unique host name." >&2
    exit 1
fi


if [ ! -f ${hostCaCert} ]; then
    echo "[Error]: Cannot find the host CA cert for stone '$stoneName'." >&2
    echo "[Error]: Use the newhostCA command to create it." >&2
    exit 1
fi

domkdir ${hostDir}

hostPrivKey=${hostDir}/${hostName}.privkey.pem
hostCsr=${hostDir}/${hostName}.csr.pem
hostCert=${hostDir}/${hostName}.cert.pem
hostCertChain=${hostDir}/${hostName}.chain.pem

## Create host private key
doopenssl genpkey -out ${hostPrivKey} -algorithm RSA \
	  -pkeyopt rsa_keygen_bits:${rsaKeyBits}


## Must escape the slash in the CIDR before passing it to openssl
## First / indicates pattern replacement
## Second / -- having / as the first character of a pattern means replace every occurrence
## Third / is the pattern, we want to replace each /
## Fourth / divides the pattern from the replacement
## First \ escapes the second \
## \/ is the replacement. So every / in $cidr is replaced with \/
cidrArg=${cidr////\\/}


## Certificate signing request
doopenssl req -config ${configDir}/hostreq.conf -new -key ${hostPrivKey} \
	  -out ${hostCsr} -subj \
	  /gemstone_CertificateType=host/gemstone_SubnetRestriction=${cidrArg}/gemstone_StoneName=${stoneName}/CN=${hostName}

## Produce a certificate signed by the host CA
# Use -batch to tell openssl to not ask questions.
doopenssl ca -batch -config ${configDir}/signhost.conf -name hostca \
	  -in ${hostCsr} -out ${hostCert} -notext \
	  -cert ${hostCaCert} -keyfile ${hostCaPrivKey} \
	  -days ${daysValid} 

# Create the cert chain by concating the following 2 PEM files
# 1 - host cert
# 2 - host CA cert
cp -p ${hostCert} ${hostCertChain} >/dev/null 2>&1
cat ${hostCaCert} >> ${hostCertChain}

