Skip to content

Instantly share code, notes, and snippets.

@bdurrow
Last active June 11, 2020 05:51
Show Gist options
  • Save bdurrow/5873083ed4f8f52f50a22a240b5a2543 to your computer and use it in GitHub Desktop.
Save bdurrow/5873083ed4f8f52f50a22a240b5a2543 to your computer and use it in GitHub Desktop.
kinit wrapper that supports pkinit to allow for 2FA (typically saved as /usr/local/bin/kinit)
#!/bin/bash
# (c) 2020 by I. S. Consulting, LLC use and remix allowed with attribution.
# Initially created by [bgdurrow]
# Available from https://gist.github.com/bdurrow/5873083ed4f8f52f50a22a240b5a2543
#I don't think that I have used any bash specific features other
#than these "strict mode" settings.
set -euo pipefail
IFS=$'\n\t'
function kinit() {
local OUR_ARGS=( "$@" )
#local KINIT="${0}" #or kinit
local KINIT="/usr/bin/kinit"
local KLIST_OUTPUT=""
local KLIST_TICKET_CACHE=""
local KLIST_DEFAULT_PRINCIPAL=""
local ANONYMOUS_PRINCIPAL="WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS"
local TRUE=0
local FALSE=1
function parse_klist_output() {
KLIST_TICKET_CACHE=$(printf '%s' "$KLIST_OUTPUT" | sed -nE 's/^.*\scache:\s+(.*)$/\1/p')
KLIST_DEFAULT_PRINCIPAL=$(printf '%s' "$KLIST_OUTPUT" | sed -nE 's/^Default principal:\s+(.*)$/\1/p')
}
function get_info_from_klist() {
if KLIST_OUTPUT=$(klist 2>/dev/null); then
parse_klist_output
fi
}
function principal_already_present() {
if [ "$#" -eq 0 ]; then
#No Args
return $FALSE;
elif [ "$#" -eq 1 ]; then
#Only one arg, has to be principal
return $TRUE;
else
#For two or more arguments it is more complicated,
#Look at the second to last argument and if that takes
#another argument then the last argument is not a principal
local SECOND_TO_LAST=$(echo $(eval "printf \"%s\n\" \"\$$(($#-1))\""));
case ${SECOND_TO_LAST} in
#SYNOPSIS
#kinit [-V] [-l lifetime] [-s start_time] [-r renewable_life] [-p | -P] [-f | -F] [-a] [-A] [-C] [-E] [-v] [-R]
#[-k [-t keytab_file]] [-c cache_name] [-n] [-S service_name] [-I input_ccache] [-T armor_ccache] [-X
#attribute[=value]] [principal]
-l|-s|-r|-k|-t|-c|-S|-I|-T|-X)
return $FALSE
;;
-V|-p|-P|-f|-F|-a|-A|-C|-E|-v|-R|-n)
return $TRUE
;;
-*)
echo "FATAL: unknown argument"
exit 1
;;
*)
return $TRUE
;;
esac
fi
}
function compute_principal() {
if principal_already_present $@; then
return
fi
if [ -n "${KLIST_DEFAULT_PRINCIPAL}" ]; then
if [ "${KLIST_DEFAULT_PRINCIPAL}" = "${ANONYMOUS_PRINCIPAL}" ]; then
printf "%s" "${USER}"
else
printf "%s" "${KLIST_DEFAULT_PRINCIPAL}"
fi
else
printf "%s" "${USER}"
fi
}
function arg_present() {
search_arg=$1; shift
for arg; do
if [ "${arg}" = "${search_arg}" ]; then
return $TRUE
fi
done
return $FALSE
}
#If pkinit isn't available this script isn't helpful
if ! [ -e /usr/lib*/krb5/plugins/preauth/pkinit.so ]; then
#Perhaps we should print a warning and suggest installing
#pkinit support, ie: yum -y krb5_pkinit
command $KINIT $@
return $?
fi
#Special case: if called with -n just run kinit as called
if arg_present "-n" $@; then
command $KINIT $@
return $?
fi
#Special case: if called with -T just run kinit as called
if arg_present "-T" $@; then
command $KINIT $@
return $?
fi
get_info_from_klist
#Set the PRINCIPAL, note this will be empty if the argument list appears to end with a principal
PRINCIPAL=$(compute_principal $@)
if [ -z "${KLIST_TICKET_CACHE}" ]; then
command $KINIT -n
#kinit -n adds an anonymous auth to the ticket cache
#it is a bit of a pain to have it there as it changes the default
#principal and will prevent kdestroy from operating with the expected
#behavior. We don't need it any more after we auth so we will set
#this cleanup operation.
function finish {
#Don't depend on the local variable for this :(
kdestroy -p "WELLKNOWN/ANONYMOUS@WELLKNOWN:ANONYMOUS"
}
trap finish EXIT
get_info_from_klist
#FATAL: If we still don't have a defined TICKET_CACHE
if [ -z "${KLIST_TICKET_CACHE}" ]; then
echo "FATAL: Could not setup Ticket Cache"
return 1
fi
fi
command $KINIT -T ${KLIST_TICKET_CACHE} $@ ${PRINCIPAL}
return $?
}
kinit $@
@bdurrow
Copy link
Author

bdurrow commented Jun 11, 2020

Feedback welcome!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment