X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/distorted-keys/blobdiff_plain/68023101ab409d775673edadb77079a7adf50374..865fc4a1c4add30fbf1b6ab9569682d82e8da7c9:/keyfunc.sh.in?ds=sidebyside diff --git a/keyfunc.sh.in b/keyfunc.sh.in index 82ed9e5..6cba169 100644 --- a/keyfunc.sh.in +++ b/keyfunc.sh.in @@ -28,15 +28,26 @@ quis=${0##*/} ###-------------------------------------------------------------------------- ### Configuration variables. +## Automatically configured pathnames. PACKAGE="@PACKAGE@" VERSION="@VERSION@" bindir="@bindir@" -case ":$PATH:" in *:"$bindir":*) ;; *) PATH=$bindir:$PATH ;; esac - +## Read user configuration. if [ -f $ETC/keys.conf ]; then . $ETC/keys.conf; fi +## Maybe turn on debugging. case "${KEYS_DEBUG+t}" in t) set -x ;; esac +## Fake up caller credentials if not called via userv. +case "${USERV_USER+t}" in + t) ;; + *) USERV_USER=${LOGNAME-${USER-$(id -un)}} USERV_UID=$(id -u) ;; +esac +case "${USERV_GROUP+t}" in + t) ;; + *) USERV_GROUP=$(id -Gn) USERV_GID=$(id -gn) ;; +esac + ###-------------------------------------------------------------------------- ### Cleanup handling. @@ -118,6 +129,17 @@ parse_keylabel () { knub=$KEYS/nub/$kowner/$klabel } +runas () { + user=$1 service=$2; shift 2 + ## If the current (effective) user is not USER then reinvoke via `userv', + ## as the specified service, with the remaining arguments. + + case $(id -un) in + "$user") ;; + *) exec userv "$user" "$service" "$@" ;; + esac +} + ###-------------------------------------------------------------------------- ### Input validation functions. @@ -133,7 +155,7 @@ check () { validp=t case "$thing" in *"$nl"*) validp=nil ;; - *) if ! expr >/dev/null "$thing" : "$ckpat\$"; then validp=nil; fi ;; + *) if ! expr >/dev/null "Q$thing" : "Q$ckpat\$"; then validp=nil; fi ;; esac case $validp in nil) echo >&2 "$quis: bad $ckwhat \`$thing'"; exit 1 ;; @@ -142,10 +164,13 @@ check () { ## Regular expressions for validating input. R_IDENTCHARS="A-Za-z0-9_" -R_WORDCHARS="-$R_IDENTCHARS!%@+=" +R_GOODPUNCT="!%@+=" +R_WORDCHARS="-$R_IDENTCHARS$R_GOODPUNCT" R_IDENT="[$R_IDENTCHARS][$R_IDENTCHARS]*" R_WORD="[$R_WORDCHARS][$R_WORDCHARS]*" +R_ACLCHARS="][$R_IDENTCHARS$R_GOODPUNCT*?:.#" R_WORDSEQ="[$R_WORDCHARS[:space:]][$R_WORDCHARS[:space:]]*" +R_ACL="[$R_ACLCHARS[:space:]-][$R_ACLCHARS[:space:]-]*" R_NUMERIC='\(\([1-9][0-9]*\)\{0,1\}0\{0,1\}\)' R_LABEL="\($R_WORD\(/$R_WORD\)*\)" R_LINE=".*" @@ -215,6 +240,16 @@ EOF done } +dumpprops () { + prefix=$1 + ## Write the properties stored in the variables beginning with PREFIX. + + set | sed -n "/^$prefix/{s/=.*\$//;p}" | sort | while read name; do + eval value=\$$name + echo "${name#$prefix}=$value" + done +} + defprops () { name=$1 ## Define a properties table NAME. @@ -227,9 +262,14 @@ defprops g_props </dev/null \ - if=/dev/${kprop_random-random} bs=1 count=${kprop_nubsz-512} | - openssl dgst -${kprop_nubhash-sha384} -binary | + if=/dev/${kprop_random-random} bs=1 count=${kprop_nub_random_bytes-64} | + openssl dgst -${kprop_nub_hash-sha256} -binary | openssl base64 } nubid () { ## Compute a hash of the key nub in stdin, and write it to stdout in hex. - ## The property `nubidhash' is used. - - { echo "distorted-keys nubid"; cat -; } | - openssl dgst -${kprop_nubidhash-sha256} + ## The property `nubid_hash' is used. + + ## Stupid dance because the output incompatibly grew a filename, in order + ## to demonstrate the same idiocy as GNU mumblesum. + set _ $({ echo "distorted-keys nubid"; cat -; } | + openssl dgst -${kprop_nubid_hash-sha256}) + if [ $# -gt 2 ]; then shift; fi + echo $2 } subst () { @@ -327,9 +372,10 @@ subst () { } read_profile () { - profile=$1 + owner=$1 profile=$2 ## Read property settings from a profile. The PROFILE name has the form - ## [USER:]LABEL. Properties are set using `setprops' with prefix `kprop_'. + ## [USER:]LABEL; USER defaults to OWNER. Properties are set using + ## `setprops' with prefix `kprop_'. reqtmp case "$profile" in @@ -337,7 +383,7 @@ read_profile () { label=${profile#:} uservp=nil ;; *) - user=$USERV_USER label=$profile uservp=t + user=$kowner label=$profile uservp=t ;; *:*) user=${profile%%:*} label=${profile#*:} uservp=t @@ -350,7 +396,7 @@ read_profile () { case $uservp in t) checkword "profile user" "$user" - userv "$user" cryptop-profile "$label" >$tmp/profile + userv "$user" cryptop-profile "$label" >$tmp/profile $tmp/profile @@ -416,6 +462,7 @@ c_verify () { k_verify "$@"; } ## Stub implementations. notsupp () { op=$1; echo >&2 "$quis: operation \`$op' not supported"; } k_info () { :; } +k_import () { :; } k_encrypt () { notsupp encrypt; } k_decrypt () { notsupp decrypt; } k_sign () { notsupp sign; } @@ -424,16 +471,18 @@ k_verify () { notsupp verify; } prepare () { key=$1 op=$2 ## Prepare for a crypto operation OP, using the KEY. This validates the - ## key label, reads the profile, and checks the access-control list. + ## key label, reads the profile, and checks the access-control list. If OP + ## is `-' then allow the operation unconditionally. ## Find the key properties. parse_keylabel "$key" if [ ! -d $kdir ]; then echo >&2 "$quis: unknown key \`$key'"; exit 1; fi readmeta $kdir - read_profile "$profile" + read_profile $kowner "$profile" ## Check whether we're allowed to do this thing. This is annoyingly ## fiddly. + case $op in -) return ;; esac eval acl=\${kprop_acl_$op-!owner} verdict=forbid while :; do @@ -520,6 +569,31 @@ c_sysverify () { c_sysop verify "$1" /dev/null; } ###-------------------------------------------------------------------------- ### Recovery operations. +sharethresh () { + pf=$1 + ## Return the sharing threshold from the parameter file PARAM. + + read param <"$pf" + case "$param" in + shamir-params:*) ;; + *) + echo >&2 "$quis: secret sharing parameter file damaged (wrong header)" + exit 1 + ;; + esac + t=";${param#*:}" + case "$t" in + *";t="*) ;; + *) + echo >&2 "$quis: secret sharing parameter file damaged (missing t)" + exit 1 + ;; + esac + t=${t#*;t=} + t=${t%%;*} + echo "$t" +} + stash () { recov=$1 label=$2 ## Stash a copy of stdin encrypted under the recovery key RECOV, with a @@ -538,21 +612,23 @@ stash () { } recover () { - recov=$1 label=$2 + recov=$1 inst=$2 label=$3 ## Recover a stashed secret, protected by RECOV and stored as LABEL, and ## write it to stdout. checkword "recovery key label" "$recov" + checkword "recovery instance" "$inst" checklabel "secret" "$label" - rdir=$KEYS/recov/$recov/current + rdir=$KEYS/recov/$recov/$inst if [ ! -f $rdir/$label.recov ]; then - echo >&2 "$quis: no blob for \`$label' under recovery key \`$recov'" + echo >&2 "$quis: no blob for \`$label' under recovery key \`$recov/$inst'" exit 1 fi reqsafe - nub=$SAFE/keys.reveal/$recov.current/nub + tag=$recov.$inst + nub=$SAFE/keys.reveal/$tag/nub if [ ! -f $nub ]; then - echo >&2 "$quis: current recovery key \`$recov' not revealed" + echo >&2 "$quis: current recovery key \`$recov/$inst' not revealed" exit 1; fi mktmp @@ -564,7 +640,7 @@ recover () { defhelp () { read umsg - usage="usage: $quis${umsg+ }$umsg" + usage=$umsg help=$(cat) case "$KEYS_HELP" in t) help; exit ;; esac } @@ -572,13 +648,17 @@ defhelp () { help () { showhelp; } showhelp () { cat <&2 "$usage"; exit 1; } +usage () { + : ${cmdargs=$usage} + echo "usage: $quis${cmdname:+ $cmdname}${cmdargs:+ $cmdargs}" +} +usage_err () { usage >&2; exit 1; } ###-------------------------------------------------------------------------- ### Subcommand handling. @@ -587,6 +667,20 @@ version () { echo "$PACKAGE version $VERSION" } +unset cmdargs +unset cmdname +cmds="" +defcmd () { + cmd=$1; shift; args=$* + help=$(cat) + eval help_$cmd=\$help + cmds="${cmds:+$cmds +}$cmd $args" +} + +defcmd help "[COMMAND ...]" <&2 "$quis: unrecognized command \`$i'" - rc=1 - continue - elif ! KEYS_HELP=t "$KEYSLIB/$prefix.$i"; then - rc=1 - fi + foundp=nil + while read cmdname cmdargs; do + case $cmdname in "$cmd") foundp=t; break ;; esac + done <&2 "$quis: unrecognized command \`$cmd'" + rc=1 + continue + elif ! KEYS_HELP=t "$KEYSLIB/$prefix.$cmd"; then + rc=1 + fi + ;; + esac done ;; esac @@ -625,16 +739,28 @@ EOF } dispatch () { - case $# in 0) echo >&2 "$usage"; exit 1 ;; esac + case $# in 0) usage_err ;; esac cmd=$1; shift - case "$cmd" in help) cmd_help "$@"; exit ;; esac - if [ ! -x "$KEYSLIB/$prefix.$cmd" ]; then - echo >&2 "$quis: unrecognized command \`$cmd'" - exit 1 - fi - - unset KEYS_HELP - exec "$KEYSLIB/$prefix.$cmd" "$@" + foundp=nil + while read cmdname cmdargs; do + case $cmdname in "$cmd") foundp=t; break ;; esac + done <&2 "$quis: unrecognized command \`$cmd'" + exit 1 + fi + unset KEYS_HELP + exec "$KEYSLIB/$prefix.$cmd" "$@" + ;; + esac } ###----- That's all, folks --------------------------------------------------