#!/bin/sh
# $Beard: ykinit,v 1.2 2013/09/10 08:17:59 alexander Exp $

# Initialize a yubikey for login_yubikey on the local host
#
# Copyright (c) 2012-2013 Alexander Hall <alexander@beard.se>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

set -e

die() {
	print -r -- "$@"
	exit 1
}

usage() {
	die "usage: ${0##*/} [-Sstv] [-c code] [-u uid] -1|-2 user"
}

verbose() {
	! $VERBOSE || print -r -- "$@"
}

ACC=000000000000
SECURE=false
SLOT=
TEST=false
UID=$(openssl rand 6 -hex)
VERBOSE=false
while getopts '12c:Sstu:v' opt "$@" 2>/dev/null; do
	case $opt in
		1|2)	SLOT=$opt;;
		c)	ACC=$OPTARG;;
		S)	SECURE=false;;
		s)	SECURE=true;;
		t)	TEST=true;;
		u)	UID=$OPTARG;;
		v)	VERBOSE=true;;
		*)	usage;;
	esac
done
shift $((OPTIND-1))

[ $# = 1 ] || usage
USER=$1

# Sanity checks
[ 1 = "$SLOT" -o 2 = "$SLOT" ] || usage
[ "$USER" = "${USER##*/}" ] || die "Invalid username"
[ ${#UID} = 12 -a "$UID" = "${UID#*[!0-9A-Fa-f]}" ] || die "Invalid uid"

if $SECURE; then # "Not implemented"... D'oh!
	verbose "Programming yubikey"
	KEY=$(openssl rand 16 -hex)
	cat <<- _EOF_ | tee /dev/stderr | ykpersonalize -"$SLOT" -i-
		fixed: m:
		uid: $UID
		key: h:$KEY
		acc_code: h:$ACC
		ticket_flags: APPEND_CR
		config_flags: 
		extended_flags: 
	_EOF_
else
	verbose "Programming yubikey (using less secure method)"
	if ! result=$(openssl rand -base64 40 |
		ykpersonalize -"$SLOT" -y -c "$ACC" \
			-o-static-ticket -o-strong-pw1 -o-strong-pw2 \
			-o-man-update -ouid="$UID" 2>&1); then
		verbose "Programming failed"
		die "$result"
	fi
	KEY=$(print -r -- "$result" | sed '/^key: h:/!d;s///;q')
fi

base=/var/db/yubikey/$USER

verbose "Update yubikey files"
rm -f "$base".{uid,key,ctr} || die "Cannot remove old files in $base"
cat <<- _EOF_ > "$base.key" || die "Cannot write key file"
	$KEY
_EOF_
cat <<- _EOF_ > "$base.uid" || die "Cannot write uid file"
	$UID
_EOF_

if $TEST; then
	verbose "Running test"
	result=$(/usr/libexec/auth/login_yubikey alexander 3>&1 >&2)
	[ "authorize" = "$result" ] || die "Test failed!"
fi

verbose "Yubikey initialization successful!"
verbose ""
verbose "See login.conf(5) for how to enable yubikey authentication."
