Last active
June 11, 2020 05:51
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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 $@ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Feedback welcome!