#! /bin/bash
# set -xv
#=========================================================================
# Copyright (C) GemTalk Systems 1986-2024.  All Rights Reserved..
#
# Name - newuser
# Installed as - newuser
#
# Written By: Martin McClure and Norm Green
#
# Purpose -
#
# Create the certificate and private key for a Database user.
# For a given stone specified by the -s argument, the newstone
# and newuserCA 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.
#
#=========================================================================
#### Create a user certificate, signed by the user CA for the given stone

cmd=`basename $0`

usage(){
    echo "Usage: $cmd -h | -s <stoneName> [-a <cidr>][-d daysValid] <userName>" >&2
    echo "  where: cidr is an IP address restriction in CIDR format (default: no restriction)" >&2    
    echo "         daysValid is the number of days the user 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))
userName=$1

# 48065
if [ $OPTIND -ne $ARGC ]; then
    echo "[Error]: userName 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 "$userName" ]; then
    echo "[Error]: Missing username argument" >&2
    usage
fi

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

userDir=${usersDir}/${userName}

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

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

domkdir ${userDir}

userPrivKey=${userDir}/${userName}.privkey.pem
userCsr=${userDir}/${userName}.csr.pem
userCert=${userDir}/${userName}.cert.pem
userCertChain=${userDir}/${userName}.chain.pem

## Create user private key
doopenssl genpkey -out ${userPrivKey} -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}/userreq.conf -new -key ${userPrivKey} \
	   -out ${userCsr} -subj /gemstone_CertificateType=user/gemstone_SubnetRestriction=${cidrArg}/gemstone_StoneName=${stoneName}/gemstone_UserName=${userName}

## Produce a signed certificate
# Use -batch to tell openssl to not ask questions.
doopenssl ca -batch -config ${configDir}/signuser.conf -name userca -in ${userCsr} \
	   -out ${userCert} -notext -cert ${userCaCert} \
	   -keyfile ${userCaPrivKey} -days ${daysValid}

# Create the cert chain by concating the following 2 PEM files
# 1 - user cert
# 2 - user CA cert
cp -p ${userCert} ${userCertChain} >/dev/null 2>&1
cat ${userCaCert} >> ${userCertChain}
