#!/bin/bash 
#
# FILE:
#    pamrsakp 
#
# DEPENDS ON:
#    bash 
#    (yes, this script is NOT portable, as it uses '!' to express 
#    negation, and probably other things too that are not portable. 
#    Actually it seems that almost NOTHING is portable in the wonderful
#    world of shell scripts. Just consider 'echo' with options.
# 
#    openssl executable 
#    some very basic Unix utilities
#
# PURPOSE:
#    creates keypairs that can be used with pam_rsa PAM authentication 
#    module. The public key is actually in a certificate that can 
#    contain other information too.
#
# pamrsakp.cnf is a configuration file for OpenSSL
#
# (c) 2006 Vesa-Matti Kari <hyperllama@laamanaama.helsinki.fi>
#

O=${OPENSSL-openssl}
CF=${PAMRSAKPCNF-/etc/security/pamrsakp.cnf}


if [ $# -ne 6 ]; then
	echo "usage: `basename ${0}` [user] [hostname] [pubdir] [privdir] [hash: sha1 | none] [usepassphrase: yes|no]"
	exit 1
fi


USER=${1}
TARGETHOST=${2}
PUBDIR=${3}
PRIVDIR=${4}
HASHTYPE=${5}
USEPASSPHRASE=${6}

# remove trailing slash from pathname if there is one
PUBDIR=`echo ${PUBDIR} | sed 's/\/$//'`
PRIVDIR=`echo ${PRIVDIR} | sed 's/\/$//'`


if [ x${HASHTYPE} = "xsha1" ]; then
	PRIVKEY=`echo -n ${USER} | ${O} dgst -sha1 | cut -b -8`.pem
elif [ x${HASHTYPE} = "xnone" ]; then
	PRIVKEY=${USER}.pem
else 
	echo "'${HASHTYPE}' is not valid hashtype, please specify 'sha1' or 'none'"
	exit 1
fi

if ! ( [ x${USEPASSPHRASE} = "xyes" ] || [ x${USEPASSPHRASE} = "xno" ] ); then
	echo "'${USEPASSPHRASE}' is not valid, usepassphrase must be 'yes' or 'no'"
	exit 1
fi


HOSTHASH=`echo -n ${TARGETHOST} | ${O} dgst -sha1 | cut -b -8`


# Create the public and private key directories if they do not exist


if [ ! -d ${PUBDIR} ]; then
	mkdir ${PUBDIR}
	if [ $? -ne 0 ]; then
		echo "error: mkdir ${PUBDIR} failed"
		exit 1
	fi

	chmod 0755 ${PUBDIR}
	if [ $? -ne 0 ]; then
		echo "error: chmod 0755 ${PUBDIR} failed"
		exit 1
	fi
fi


if [ ! -d ${PRIVDIR} ]; then
	mkdir ${PRIVDIR}
	if [ $? -ne 0 ]; then
		echo "error: mkdir ${PRIVDIR} failed"
		exit 1
	fi

	chmod 0755 ${PRIVDIR}
	if [ $? -ne 0 ]; then
		echo "error: chmod 0755 ${PRIVDIR} failed"
		exit 1
	fi
fi

if [ ! -d ${PRIVDIR}/${HOSTHASH} ]; then
	mkdir ${PRIVDIR}/${HOSTHASH}
	if [ $? -ne 0 ]; then
		echo "error: mkdir ${PRIVDIR}/${HOSTHASH} failed"
		exit 1
	fi

	chmod 0755 ${PRIVDIR}/${HOSTHASH}
	if [ $? -ne 0 ]; then
		echo "error: chmod 0755 ${PRIVDIR}/${HOSTHASH} failed"
		exit 1
	fi
fi

CERT=${USER}.pem

if [ -a ${PUBDIR}/${CERT} ]; then
	echo "error: ${PUBDIR}/${CERT} already exists"
	exit 2
fi

if [ -a ${PRIVDIR}/${HOSTHASH}/${PRIVKEY} ]; then
	echo "error: ${PRIVDIR}/${HOSTHASH}/${PRIVKEY} already exists"
	exit 3
fi

echo "Generating a certificate and a secret private key for ${USER}"
echo "Please wait..."

${O} req -new -x509 -nodes -config ${CF} -out ${PUBDIR}/${CERT} -keyout ${PRIVDIR}/${HOSTHASH}/${PRIVKEY}.plain
if [ $? -ne 0 ]; then
	rm -f ${PRIVDIR}/${HOSTHASH}/${PRIVKEY}.plain
	echo "error: ${O} creating key(s) failed"
	exit 1
fi

if [ x${USEPASSPHRASE} = "xyes" ]; then
	echo "Generated RSA private key will now be encrypted with a passphrase..."
	${O} rsa -des3 -in ${PRIVDIR}/${HOSTHASH}/${PRIVKEY}.plain -out ${PRIVDIR}/${HOSTHASH}/${PRIVKEY}
	if [ $? -ne 0 ]; then
		rm -f ${PRIVDIR}/${HOSTHASH}/${PRIVKEY}.plain
		echo "error: ${O} encrypting RSA private key failed"
		exit 1
	fi
else
	mv ${PRIVDIR}/${HOSTHASH}/${PRIVKEY}.plain ${PRIVDIR}/${HOSTHASH}/${PRIVKEY}
fi

rm -f ${PRIVDIR}/${HOSTHASH}/${PRIVKEY}.plain

chmod 0400 ${PRIVDIR}/${HOSTHASH}/${PRIVKEY}
if [ $? -ne 0 ]; then
	echo "error: chmod 0400 ${PRIVDIR}/${HOSTHASH}/${PRIVKEY} failed"
	exit 1
fi

chmod 0444 ${PUBDIR}/${CERT}
if [ $? -ne 0 ]; then
	echo "error: chmod 0444 ${PUBDIR}/${CERT} failed"
	exit 1
fi

${O} x509 -subject -fingerprint -noout -in ${PUBDIR}/${CERT} 
if [ $? -ne 0 ]; then
	echo "error: ${O} certificate signing failed"
	exit 1
fi

echo ""
echo "###############################################################################"
echo ""
echo "RSA Keypair created for authenticating user '${USER}' on host '${TARGETHOST}'"
echo "Cert/Public Key: ${PUBDIR}/${CERT}"
echo "RSA Private Key: ${PRIVDIR}/${HOSTHASH}/${PRIVKEY}"

if [ x${USEPASSPHRASE} != "xyes" ]; then
	echo ""
	echo "WARNING: Generated RSA private key is NOT encrypted!!!"
	echo "WARNING: DO NOT USE IT UNLESS YOU ARE SURE OF WHAT YOU ARE DOING"
fi

echo ""
echo "###############################################################################"
echo ""
