diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/monkeysphere | 168 | ||||
-rwxr-xr-x | src/monkeysphere-authentication | 49 | ||||
-rwxr-xr-x | src/monkeysphere-host | 79 | ||||
-rw-r--r-- | src/share/common | 110 | ||||
-rw-r--r-- | src/share/m/gen_subkey | 83 | ||||
-rw-r--r-- | src/share/m/import_subkey | 72 | ||||
-rw-r--r-- | src/share/m/ssh_proxycommand | 39 | ||||
-rw-r--r-- | src/share/m/subkey_to_ssh_agent | 15 | ||||
-rw-r--r-- | src/share/ma/add_certifier | 125 | ||||
-rw-r--r-- | src/share/ma/diagnostics | 18 | ||||
-rw-r--r-- | src/share/ma/list_certifiers | 1 | ||||
-rw-r--r-- | src/share/ma/remove_certifier | 2 | ||||
-rw-r--r-- | src/share/ma/setup | 27 | ||||
-rw-r--r-- | src/share/ma/update_users | 2 | ||||
-rw-r--r-- | src/share/mh/add_hostname | 4 | ||||
-rw-r--r-- | src/share/mh/add_revoker | 132 | ||||
-rw-r--r-- | src/share/mh/diagnostics | 37 | ||||
-rw-r--r-- | src/share/mh/import_key | 27 | ||||
-rw-r--r-- | src/share/mh/publish_key | 8 | ||||
-rw-r--r-- | src/share/mh/revoke_hostname | 6 | ||||
-rw-r--r-- | src/share/mh/revoke_key | 28 | ||||
-rw-r--r-- | src/share/mh/set_expire | 2 | ||||
-rwxr-xr-x | src/transition_0.22_0.23 | 69 | ||||
-rwxr-xr-x | src/transitions/0.23 | 180 | ||||
-rw-r--r-- | src/transitions/README.txt | 16 |
25 files changed, 791 insertions, 508 deletions
diff --git a/src/monkeysphere b/src/monkeysphere index da5f406..a65cef6 100755 --- a/src/monkeysphere +++ b/src/monkeysphere @@ -45,12 +45,8 @@ Monkeysphere client tool. subcommands: update-known_hosts (k) [HOST]... update known_hosts file update-authorized_keys (a) update authorized_keys file - import-subkey (i) import existing ssh key as gpg subkey - --keyfile (-f) FILE key file to import - --expire (-e) EXPIRE date to expire gen-subkey (g) [KEYID] generate an authentication subkey --length (-l) BITS key length in bits (2048) - --expire (-e) EXPIRE date to expire ssh-proxycommand monkeysphere ssh ProxyCommand subkey-to-ssh-agent (s) store authentication subkey in ssh-agent version (v) show version number @@ -59,45 +55,128 @@ subcommands: EOF } +# user gpg command to define common options +gpg_user() { + gpg --no-greeting --quiet --no-tty "$@" +} + +# take a secret key ID and check that only zero or one ID is provided, +# and that it corresponds to only a single secret key ID +check_gpg_sec_key_id() { + local gpgSecOut + + case "$#" in + 0) + gpgSecOut=$(gpg_user --fixed-list-mode --list-secret-keys --with-colons 2>/dev/null | egrep '^sec:') + ;; + 1) + gpgSecOut=$(gpg_user --fixed-list-mode --list-secret-keys --with-colons "$keyID" | egrep '^sec:') || failure + ;; + *) + failure "You must specify only a single primary key ID." + ;; + esac + + # check that only a single secret key was found + case $(echo "$gpgSecOut" | grep -c '^sec:') in + 0) + failure "No secret keys found. Create an OpenPGP key with the following command: + gpg --gen-key" + ;; + 1) + echo "$gpgSecOut" | cut -d: -f5 + ;; + *) + echo "Multiple primary secret keys found:" | log error + echo "$gpgSecOut" | cut -d: -f5 | log error + echo "Please specify which primary key to use." | log error + failure + ;; + esac +} + +# check that a valid authentication subkey does not already exist +check_gpg_authentication_subkey() { + local keyID + local IFS + local line + local type + local validity + local usage + + keyID="$1" + + # check that a valid authentication key does not already exist + IFS=$'\n' + for line in $(gpg_user --fixed-list-mode --list-keys --with-colons "$keyID") ; do + type=$(echo "$line" | cut -d: -f1) + validity=$(echo "$line" | cut -d: -f2) + usage=$(echo "$line" | cut -d: -f12) + + # look at keys only + if [ "$type" != 'pub' -a "$type" != 'sub' ] ; then + continue + fi + # check for authentication capability + if ! check_capability "$usage" 'a' ; then + continue + fi + # if authentication key is valid, prompt to continue + if [ "$validity" = 'u' ] ; then + echo "A valid authentication key already exists for primary key '$keyID'." + if [ "$PROMPT" = "true" ] ; then + read -p "Are you sure you would like to generate another one? (y/N) " OK; OK=${OK:N} + if [ "${OK/y/Y}" != 'Y' ] ; then + failure "aborting." + fi + break + else + failure "aborting." + fi + fi + done +} + ######################################################################## # MAIN ######################################################################## -# unset variables that should be defined only in config file -unset KEYSERVER +# set unset default variables +GNUPGHOME=${GNUPGHOME:="${HOME}/.gnupg"} +KNOWN_HOSTS="${HOME}/.ssh/known_hosts" +HASH_KNOWN_HOSTS="true" +AUTHORIZED_KEYS="${HOME}/.ssh/authorized_keys" + +# unset the check keyserver variable, since that needs to have +# different defaults for the different functions unset CHECK_KEYSERVER -unset KNOWN_HOSTS -unset HASH_KNOWN_HOSTS -unset AUTHORIZED_KEYS # load global config -[ -r "${SYSCONFIGDIR}/monkeysphere.conf" ] && . "${SYSCONFIGDIR}/monkeysphere.conf" +[ -r "${SYSCONFIGDIR}/monkeysphere.conf" ] \ + && . "${SYSCONFIGDIR}/monkeysphere.conf" # set monkeysphere home directory MONKEYSPHERE_HOME=${MONKEYSPHERE_HOME:="${HOME}/.monkeysphere"} mkdir -p -m 0700 "$MONKEYSPHERE_HOME" # load local config -[ -e ${MONKEYSPHERE_CONFIG:="${MONKEYSPHERE_HOME}/monkeysphere.conf"} ] && . "$MONKEYSPHERE_CONFIG" - -# set empty config variables with ones from the environment, or from -# config file, or with defaults -LOG_LEVEL=${MONKEYSPHERE_LOG_LEVEL:=${LOG_LEVEL:="INFO"}} -GNUPGHOME=${MONKEYSPHERE_GNUPGHOME:=${GNUPGHOME:="${HOME}/.gnupg"}} -KEYSERVER=${MONKEYSPHERE_KEYSERVER:="$KEYSERVER"} -# if keyserver not specified in env or monkeysphere.conf, -# look in gpg.conf +[ -e ${MONKEYSPHERE_CONFIG:="${MONKEYSPHERE_HOME}/monkeysphere.conf"} ] \ + && . "$MONKEYSPHERE_CONFIG" + +# set empty config variables with ones from the environment +GNUPGHOME=${MONKEYSPHERE_GNUPGHOME:=$GNUPGHOME} +LOG_LEVEL=${MONKEYSPHERE_LOG_LEVEL:=$LOG_LEVEL} +KEYSERVER=${MONKEYSPHERE_KEYSERVER:=$KEYSERVER} +# if keyserver not specified in env or conf, then look in gpg.conf if [ -z "$KEYSERVER" ] ; then if [ -f "${GNUPGHOME}/gpg.conf" ] ; then KEYSERVER=$(grep -e "^[[:space:]]*keyserver " "${GNUPGHOME}/gpg.conf" | tail -1 | awk '{ print $2 }') fi fi -# if it's still not specified, use the default -KEYSERVER=${KEYSERVER:="subkeys.pgp.net"} -CHECK_KEYSERVER=${MONKEYSPHERE_CHECK_KEYSERVER:=${CHECK_KEYSERVER:="true"}} -KNOWN_HOSTS=${MONKEYSPHERE_KNOWN_HOSTS:=${KNOWN_HOSTS:="${HOME}/.ssh/known_hosts"}} -HASH_KNOWN_HOSTS=${MONKEYSPHERE_HASH_KNOWN_HOSTS:=${HASH_KNOWN_HOSTS:="true"}} -AUTHORIZED_KEYS=${MONKEYSPHERE_AUTHORIZED_KEYS:=${AUTHORIZED_KEYS:="${HOME}/.ssh/authorized_keys"}} +PROMPT=${MONKEYSPHERE_PROMPT:=$PROMPT} +KNOWN_HOSTS=${MONKEYSPHERE_KNOWN_HOSTS:=$KNOWN_HOSTS} +HASH_KNOWN_HOSTS=${MONKEYSPHERE_HASH_KNOWN_HOSTS:=$HASH_KNOWN_HOSTS} +AUTHORIZED_KEYS=${MONKEYSPHERE_AUTHORIZED_KEYS:=$AUTHORIZED_KEYS} # other variables not in config file AUTHORIZED_USER_IDS=${MONKEYSPHERE_AUTHORIZED_USER_IDS:="${MONKEYSPHERE_HOME}/authorized_user_ids"} @@ -117,49 +196,26 @@ shift case $COMMAND in 'update-known_hosts'|'update-known-hosts'|'k') - MODE='known_hosts' - - # touch the known_hosts file so that the file permission check - # below won't fail upon not finding the file - (umask 0022 && touch "$KNOWN_HOSTS") - - # check permissions on the known_hosts file path - check_key_file_permissions "$USER" "$KNOWN_HOSTS" || failure + # whether or not to check keyservers + CHECK_KEYSERVER=${MONKEYSPHERE_CHECK_KEYSERVER:=${CHECK_KEYSERVER:="true"}} - # if hosts are specified on the command line, process just - # those hosts + # if hosts are specified on the command line, process just + # those hosts if [ "$1" ] ; then update_known_hosts "$@" RETURN="$?" - # otherwise, if no hosts are specified, process every host - # in the user's known_hosts file + # otherwise, if no hosts are specified, process every host + # in the user's known_hosts file else - # exit if the known_hosts file does not exist - if [ ! -e "$KNOWN_HOSTS" ] ; then - log error "known_hosts file '$KNOWN_HOSTS' does not exist." - exit - fi - process_known_hosts RETURN="$?" fi ;; 'update-authorized_keys'|'update-authorized-keys'|'a') - MODE='authorized_keys' - - # check permissions on the authorized_user_ids file path - check_key_file_permissions "$USER" "$AUTHORIZED_USER_IDS" || failure - - # check permissions on the authorized_keys file path - check_key_file_permissions "$USER" "$AUTHORIZED_KEYS" || failure - - # exit if the authorized_user_ids file is empty - if [ ! -e "$AUTHORIZED_USER_IDS" ] ; then - log error "authorized_user_ids file '$AUTHORIZED_USER_IDS' does not exist." - exit - fi + # whether or not to check keyservers + CHECK_KEYSERVER=${MONKEYSPHERE_CHECK_KEYSERVER:=${CHECK_KEYSERVER:="true"}} # process authorized_user_ids file process_authorized_user_ids "$AUTHORIZED_USER_IDS" diff --git a/src/monkeysphere-authentication b/src/monkeysphere-authentication index 8a4146f..497470d 100755 --- a/src/monkeysphere-authentication +++ b/src/monkeysphere-authentication @@ -56,7 +56,8 @@ Monkeysphere authentication admin tool. subcommands: update-users (u) [USER]... update user authorized_keys files - add-id-certifier (c+) KEYID import and tsign a certification key + + add-id-certifier (c+) [KEYID|FILE] import and tsign a certification key --domain (-n) DOMAIN limit ID certifications to DOMAIN --trust (-t) TRUST trust level of certifier (full) --depth (-d) DEPTH trust depth for certifier (1) @@ -75,7 +76,7 @@ gpg_core() { GNUPGHOME="$GNUPGHOME_CORE" export GNUPGHOME - gpg "$@" + gpg --no-greeting --quiet --no-tty "$@" } # function to interact with the gpg sphere keyring @@ -84,16 +85,16 @@ gpg_core() { gpg_sphere() { GNUPGHOME="$GNUPGHOME_SPHERE" export GNUPGHOME - - su_monkeysphere_user "gpg $@" + + su_monkeysphere_user "gpg --no-greeting --quiet --no-tty $@" } # output to stdout the core fingerprint from the gpg core secret # keyring core_fingerprint() { log debug "determining core key fingerprint..." - gpg_core --quiet --list-secret-key \ - --with-colons --fixed-list-mode --with-fingerprint \ + gpg_core --list-secret-key --with-colons \ + --fixed-list-mode --with-fingerprint \ | grep ^fpr: | cut -d: -f10 } @@ -101,37 +102,31 @@ core_fingerprint() { gpg_core_sphere_sig_transfer() { log debug "exporting core local sigs to sphere..." gpg_core --export-options export-local-sigs --export | \ - gpg_sphere "--import-options import-local-sigs --import" \ - 2>&1 | log debug + gpg_sphere "--import-options import-local-sigs --import" } ######################################################################## # MAIN ######################################################################## -# unset variables that should be defined only in config file of in -# MONKEYSPHERE_ variables -unset LOG_LEVEL -unset KEYSERVER -unset AUTHORIZED_USER_IDS -unset RAW_AUTHORIZED_KEYS -unset MONKEYSPHERE_USER -unset PROMPT +# set unset default variables +AUTHORIZED_USER_IDS="%h/.monkeysphere/authorized_user_ids" +RAW_AUTHORIZED_KEYS="%h/.ssh/authorized_keys" # load configuration file -[ -e ${MONKEYSPHERE_AUTHENTICATION_CONFIG:="${SYSCONFIGDIR}/monkeysphere-authentication.conf"} ] && . "$MONKEYSPHERE_AUTHENTICATION_CONFIG" - -# set empty config variable with ones from the environment, or with -# defaults -LOG_LEVEL=${MONKEYSPHERE_LOG_LEVEL:=${LOG_LEVEL:="INFO"}} -KEYSERVER=${MONKEYSPHERE_KEYSERVER:=${KEYSERVER:="pool.sks-keyservers.net"}} -AUTHORIZED_USER_IDS=${MONKEYSPHERE_AUTHORIZED_USER_IDS:=${AUTHORIZED_USER_IDS:="%h/.monkeysphere/authorized_user_ids"}} -RAW_AUTHORIZED_KEYS=${MONKEYSPHERE_RAW_AUTHORIZED_KEYS:=${RAW_AUTHORIZED_KEYS:="%h/.ssh/authorized_keys"}} -MONKEYSPHERE_USER=${MONKEYSPHERE_MONKEYSPHERE_USER:=${MONKEYSPHERE_USER:="monkeysphere"}} -PROMPT=${MONKEYSPHERE_PROMPT:=${PROMPT:="true"}} +[ -e ${MONKEYSPHERE_AUTHENTICATION_CONFIG:="${SYSCONFIGDIR}/monkeysphere-authentication.conf"} ] \ + && . "$MONKEYSPHERE_AUTHENTICATION_CONFIG" + +# set empty config variable with ones from the environment +LOG_LEVEL=${MONKEYSPHERE_LOG_LEVEL:=$LOG_LEVEL} +KEYSERVER=${MONKEYSPHERE_KEYSERVER:=$KEYSERVER} +CHECK_KEYSERVER=${MONKEYSPHERE_CHECK_KEYSERVER:=$CHECK_KEYSERVER} +MONKEYSPHERE_USER=${MONKEYSPHERE_MONKEYSPHERE_USER:=$MONKEYSPHERE_USER} +PROMPT=${MONKEYSPHERE_PROMPT:=$PROMPT} +AUTHORIZED_USER_IDS=${MONKEYSPHERE_AUTHORIZED_USER_IDS:=$AUTHORIZED_USER_IDS} +RAW_AUTHORIZED_KEYS=${MONKEYSPHERE_RAW_AUTHORIZED_KEYS:=$RAW_AUTHORIZED_KEYS} # other variables -CHECK_KEYSERVER=${MONKEYSPHERE_CHECK_KEYSERVER:="true"} REQUIRED_USER_KEY_CAPABILITY=${MONKEYSPHERE_REQUIRED_USER_KEY_CAPABILITY:="a"} GNUPGHOME_CORE=${MONKEYSPHERE_GNUPGHOME_CORE:="${MADATADIR}/core"} GNUPGHOME_SPHERE=${MONKEYSPHERE_GNUPGHOME_SPHERE:="${MADATADIR}/sphere"} diff --git a/src/monkeysphere-host b/src/monkeysphere-host index c7e011b..4c7df88 100755 --- a/src/monkeysphere-host +++ b/src/monkeysphere-host @@ -32,10 +32,6 @@ MHSHAREDIR="${SYSSHAREDIR}/mh" # datadir for host functions MHDATADIR="${SYSDATADIR}/host" -# temp directory for temp gnupghome directories for add_revoker -MHTMPDIR="${MHDATADIR}/tmp" -export MHTMPDIR - # host pub key files HOST_KEY_FILE="${SYSDATADIR}/ssh_host_rsa_key.pub.gpg" @@ -58,16 +54,15 @@ usage: $PGRM <subcommand> [options] [args] Monkeysphere host admin tool. subcommands: + import-key (i) FILE [NAME[:PORT]] import existing ssh key to gpg show-key (s) output all host key information - set-expire (e) EXPIRE set host key expiration + set-expire (e) [EXPIRE] set host key expiration add-hostname (n+) NAME[:PORT] add hostname user ID to host key revoke-hostname (n-) NAME[:PORT] revoke hostname user ID - add-revoker (o) FINGERPRINT add a revoker to the host key + add-revoker (o) [KEYID|FILE] add a revoker to the host key revoke-key (r) revoke host key publish-key (p) publish host key to keyserver - import-key (i) [NAME[:PORT]] import existing ssh key to gpg - version (v) show version number help (h,?) this help @@ -77,7 +72,7 @@ EOF # function to interact with the gpg keyring gpg_host() { - GNUPGHOME="$GNUPGHOME_HOST" gpg "$@" + GNUPGHOME="$GNUPGHOME_HOST" gpg --no-greeting --quiet --no-tty "$@" } # command to list the info about the host key, in colon format, to @@ -90,12 +85,8 @@ gpg_host_list() { } # command for edit key scripts, takes scripts on stdin -# FIXME: should we supress all the edit script spew? or pipe it -# through log debug? gpg_host_edit() { - gpg_host --no-greeting --quiet \ - --command-fd 0 --no-tty --edit-key \ - "0x${HOST_FINGERPRINT}!" "$@" 2>&1 | log debug + gpg_host --command-fd 0 --edit-key "0x${HOST_FINGERPRINT}!" "$@" } # export the host public key to the monkeysphere gpg pub key file @@ -119,7 +110,7 @@ load_fingerprint() { && rm -rf "$FUBAR") <"$HOST_KEY_FILE" \ | grep '^fpr:' | cut -d: -f10 ) else - HOST_FINGERPRINT= + failure "host key gpg pub file not found." fi } @@ -127,8 +118,7 @@ load_fingerprint() { # gpg host secret key load_fingerprint_secret() { HOST_FINGERPRINT=$( \ - gpg_host --quiet --list-secret-key \ - --with-colons --with-fingerprint \ + gpg_host --list-secret-key --with-colons --with-fingerprint \ | grep '^fpr:' | cut -d: -f10 ) } @@ -142,7 +132,7 @@ check_host_key() { check_host_no_key() { [ -s "$HOST_KEY_FILE" ] \ || failure "You don't appear to have a Monkeysphere host key on this server. -Please run 'monkeysphere-host import-key' first." +Please run 'monkeysphere-host import-key...' first." } # output the index of a user ID on the host key @@ -174,7 +164,7 @@ show_key() { local GNUPGHOME # tmp gpghome dir - export GNUPGHOME=$(mktemp -d) + export GNUPGHOME=$(msmktempdir) # trap to remove tmp dir if break trap "rm -rf $GNUPGHOME" EXIT @@ -182,6 +172,11 @@ show_key() { # import the host key into the tmp dir gpg --quiet --import <"$HOST_KEY_FILE" + # create the ssh key + TMPSSH="$GNUPGHOME"/ssh_host_key_rsa_pub + openpgp2ssh <"$HOST_KEY_FILE" 2>/dev/null >"$TMPSSH" + + # get the gpg fingerprint HOST_FINGERPRINT=$(gpg --quiet --list-keys --with-colons --with-fingerprint \ | grep '^fpr:' | cut -d: -f10 ) @@ -198,9 +193,7 @@ show_key() { # list the ssh fingerprint echo -n "ssh fingerprint: " - ssh-keygen -l -f /dev/stdin \ - <<<$(openpgp2ssh <"$HOST_KEY_FILE" 2>/dev/null) \ - | awk '{ print $1, $2, $4 }' + ssh-keygen -l -f "$TMPSSH" | awk '{ print $1, $2, $4 }' # remove the tmp file trap - EXIT @@ -211,38 +204,31 @@ show_key() { # MAIN ######################################################################## -# unset variables that should be defined only in config file or in -# MONKEYSPHERE_ variables -unset LOG_LEVEL -unset KEYSERVER -unset MONKEYSPHERE_USER -unset PROMPT - # load configuration file -[ -e ${MONKEYSPHERE_HOST_CONFIG:="${SYSCONFIGDIR}/monkeysphere-host.conf"} ] && . "$MONKEYSPHERE_HOST_CONFIG" +[ -e ${MONKEYSPHERE_HOST_CONFIG:="${SYSCONFIGDIR}/monkeysphere-host.conf"} ] \ + && . "$MONKEYSPHERE_HOST_CONFIG" # set empty config variable with ones from the environment, or with # defaults -LOG_LEVEL=${MONKEYSPHERE_LOG_LEVEL:=${LOG_LEVEL:="INFO"}} -KEYSERVER=${MONKEYSPHERE_KEYSERVER:=${KEYSERVER:="pool.sks-keyservers.net"}} -MONKEYSPHERE_USER=${MONKEYSPHERE_MONKEYSPHERE_USER:=${MONKEYSPHERE_USER:="monkeysphere"}} -PROMPT=${MONKEYSPHERE_PROMPT:=${PROMPT:="true"}} +LOG_LEVEL=${MONKEYSPHERE_LOG_LEVEL:=$LOG_LEVEL} +KEYSERVER=${MONKEYSPHERE_KEYSERVER:=$KEYSERVER} +CHECK_KEYSERVER=${MONKEYSPHERE_CHECK_KEYSERVER:=$CHECK_KEYSERVER} +MONKEYSPHERE_USER=${MONKEYSPHERE_MONKEYSPHERE_USER:=$MONKEYSPHERE_USER} +PROMPT=${MONKEYSPHERE_PROMPT:=$PROMPT} # other variables -CHECK_KEYSERVER=${MONKEYSPHERE_CHECK_KEYSERVER:="true"} GNUPGHOME_HOST=${MONKEYSPHERE_GNUPGHOME_HOST:="${MHDATADIR}"} # export variables needed in su invocation export DATE -export MODE export LOG_LEVEL export KEYSERVER +export CHECK_KEYSERVER export MONKEYSPHERE_USER export PROMPT -export CHECK_KEYSERVER export GNUPGHOME_HOST export GNUPGHOME -export HOST_FINGERPRINT= +export HOST_FINGERPRINT # get subcommand COMMAND="$1" @@ -250,6 +236,12 @@ COMMAND="$1" shift case $COMMAND in + 'import-key'|'i') + check_host_key + source "${MHSHAREDIR}/import_key" + import_key "$@" + ;; + 'show-key'|'show'|'s') check_host_no_key show_key @@ -297,18 +289,17 @@ case $COMMAND in publish_key ;; - 'import-key'|'i') - check_host_key - source "${MHSHAREDIR}/import_key" - import_key "$@" - ;; - 'diagnostics'|'d') load_fingerprint source "${MHSHAREDIR}/diagnostics" diagnostics ;; + 'update-gpg-pub-file') + load_fingerprint_secret + update_gpg_pub_file + ;; + 'version'|'v') echo "$VERSION" ;; diff --git a/src/share/common b/src/share/common index 4120259..653d58b 100644 --- a/src/share/common +++ b/src/share/common @@ -8,7 +8,7 @@ # Jamie McClelland <jm@mayfirst.org> # Daniel Kahn Gillmor <dkg@fifthhorseman.net> # -# Copyright 2008, released under the GPL, version 3 or later +# Copyright 2008-2009, released under the GPL, version 3 or later # all-caps variables are meant to be user supplied (ie. from config # file) and are considered global @@ -21,7 +21,22 @@ SYSCONFIGDIR=${MONKEYSPHERE_SYSCONFIGDIR:-"/etc/monkeysphere"} export SYSCONFIGDIR # monkeysphere version -VERSION=__VERSION__ +VERSION=0.23~pre + +# default log level +LOG_LEVEL="INFO" + +# default keyserver +KEYSERVER="pool.sks-keyservers.net" + +# whether or not to check keyservers by defaul +CHECK_KEYSERVER="true" + +# default monkeysphere user +MONKEYSPHERE_USER="monkeysphere" + +# default about whether or not to prompt +PROMPT="true" ######################################################################## ### UTILITY FUNCTIONS @@ -134,6 +149,16 @@ cutline() { head --line="$1" "$2" | tail -1 } +# make a temporary directory +msmktempdir() { + mktemp -d ${TMPDIR:-/tmp}/monkeysphere.XXXXXXXXXX +} + +# make a temporary file +msmktempfile() { + mktemp ${TMPDIR:-/tmp}/monkeysphere.XXXXXXXXXX +} + # this is a wrapper for doing lock functions. # # it lets us depend on either lockfile-progs (preferred) or procmail's @@ -271,7 +296,7 @@ get_gpg_expiration() { keyExpire="$1" - if [ -z "$keyExpire" ]; then + if [ -z "$keyExpire" -a "$PROMPT" = 'true' ]; then cat >&2 <<EOF Please specify how long the key should be valid. 0 = key does not expire @@ -795,6 +820,9 @@ process_host_known_hosts() { local sshKey local tmpfile + # set the key processing mode + export MODE='known_hosts' + host="$1" userID="ssh://${host}" @@ -874,6 +902,13 @@ update_known_hosts() { nHostsOK=0 nHostsBAD=0 + # touch the known_hosts file so that the file permission check + # below won't fail upon not finding the file + (umask 0022 && touch "$KNOWN_HOSTS") + + # check permissions on the known_hosts file path + check_key_file_permissions "$USER" "$KNOWN_HOSTS" || failure + # create a lockfile on known_hosts: lock create "$KNOWN_HOSTS" # FIXME: we're discarding any pre-existing EXIT trap; is this bad? @@ -928,6 +963,11 @@ update_known_hosts() { process_known_hosts() { local hosts + # exit if the known_hosts file does not exist + if [ ! -e "$KNOWN_HOSTS" ] ; then + failure "known_hosts file '$KNOWN_HOSTS' does not exist." + fi + log debug "processing known_hosts file..." hosts=$(meat "$KNOWN_HOSTS" | cut -d ' ' -f 1 | grep -v '^|.*$' | tr , ' ' | tr '\n' ' ') @@ -951,6 +991,9 @@ process_uid_authorized_keys() { local ok local sshKey + # set the key processing mode + export MODE='authorized_keys' + userID="$1" log verbose "processing: $userID" @@ -1012,6 +1055,9 @@ update_authorized_keys() { nIDsOK=0 nIDsBAD=0 + # check permissions on the authorized_keys file path + check_key_file_permissions "$USER" "$AUTHORIZED_KEYS" || failure + # create a lockfile on authorized_keys lock create "$AUTHORIZED_KEYS" # FIXME: we're discarding any pre-existing EXIT trap; is this bad? @@ -1077,6 +1123,14 @@ process_authorized_user_ids() { authorizedUserIDs="$1" + # exit if the authorized_user_ids file is empty + if [ ! -e "$authorizedUserIDs" ] ; then + failure "authorized_user_ids file '$authorizedUserIDs' does not exist." + fi + + # check permissions on the authorized_user_ids file path + check_key_file_permissions "$USER" "$authorizedUserIDs" || failure + log debug "processing authorized_user_ids file..." if ! meat "$authorizedUserIDs" > /dev/null ; then @@ -1095,3 +1149,53 @@ process_authorized_user_ids() { update_authorized_keys "${userIDs[@]}" } + +# takes a gpg key or keys on stdin, and outputs a list of +# fingerprints, one per line: +list_primary_fingerprints() { + local fake=$(msmktempdir) + GNUPGHOME="$fake" gpg --no-tty --quiet --import + GNUPGHOME="$fake" gpg --with-colons --fingerprint --list-keys | \ + awk -F: '/^fpr:/{ print $10 }' + rm -rf "$fake" +} + + +check_cruft_file() { + local loc="$1" + local version="$2" + + if [ -e "$loc" ] ; then + printf "! The file '%s' is no longer used by\n monkeysphere (as of version %s), and can be removed.\n\n" "$loc" "$version" | log info + fi +} + +check_upgrade_dir() { + local loc="$1" + local version="$2" + + if [ -d "$loc" ] ; then + printf "The presence of directory '%s' indicates that you have\nnot yet completed a monkeysphere upgrade.\nYou should probably run the following script:\n %s/transitions/%s\n\n" "$loc" "$SYSSHAREDIR" "$version" | log info + fi +} + +## look for cruft from old versions of the monkeysphere, and notice if +## upgrades have not been run: +report_cruft() { + check_upgrade_dir "${SYSCONFIGDIR}/gnupg-host" 0.23 + check_upgrade_dir "${SYSCONFIGDIR}/gnupg-authentication" 0.23 + + check_cruft_file "${SYSCONFIGDIR}/gnupg-authentication.conf" 0.23 + check_cruft_file "${SYSCONFIGDIR}/gnupg-host.conf" 0.23 + + local found= + for foo in "${SYSDATADIR}/backup-from-"*"-transition" ; do + if [ -d "$foo" ] ; then + printf "! %s\n" "$foo" | log info + found=true + fi + done + if [ "$found" ] ; then + printf "The directories above are backups left over from a monkeysphere transition.\nThey may contain copies of sensitive data (host keys, certifier lists), but\nthey are no longer needed by monkeysphere.\nYou may remove them at any time.\n\n" | log info + fi +} diff --git a/src/share/m/gen_subkey b/src/share/m/gen_subkey index cbefaa3..dbd9dd6 100644 --- a/src/share/m/gen_subkey +++ b/src/share/m/gen_subkey @@ -15,10 +15,10 @@ gen_subkey(){ local keyLength - local keyExpire + local gpgSecOut local keyID - local gpgOut - local userID + local editCommands + local fifoDir # get options while true ; do @@ -27,10 +27,6 @@ gen_subkey(){ keyLength="$2" shift 2 ;; - -e|--expire) - keyExpire="$2" - shift 2 - ;; *) if [ "$(echo "$1" | cut -c 1)" = '-' ] ; then failure "Unknown option '$1'. @@ -41,63 +37,11 @@ Type '$PGRM help' for usage." esac done - case "$#" in - 0) - gpgSecOut=$(gpg --quiet --fixed-list-mode --list-secret-keys --with-colons 2>/dev/null | egrep '^sec:') - ;; - 1) - gpgSecOut=$(gpg --quiet --fixed-list-mode --list-secret-keys --with-colons "$1" | egrep '^sec:') || failure - ;; - *) - failure "You must specify only a single primary key ID." - ;; - esac - - # check that only a single secret key was found - case $(echo "$gpgSecOut" | grep -c '^sec:') in - 0) - failure "No secret keys found. Create an OpenPGP key with the following command: - gpg --gen-key" - ;; - 1) - keyID=$(echo "$gpgSecOut" | cut -d: -f5) - ;; - *) - echo "Multiple primary secret keys found:" - echo "$gpgSecOut" | cut -d: -f5 - failure "Please specify which primary key to use." - ;; - esac + # check that the keyID is unique + keyID=$(check_gpg_sec_key_id "$@") - # check that a valid authentication key does not already exist - IFS=$'\n' - for line in $(gpg --quiet --fixed-list-mode --list-keys --with-colons "$keyID") ; do - type=$(echo "$line" | cut -d: -f1) - validity=$(echo "$line" | cut -d: -f2) - usage=$(echo "$line" | cut -d: -f12) - - # look at keys only - if [ "$type" != 'pub' -a "$type" != 'sub' ] ; then - continue - fi - # check for authentication capability - if ! check_capability "$usage" 'a' ; then - continue - fi - # if authentication key is valid, prompt to continue - if [ "$validity" = 'u' ] ; then - echo "A valid authentication key already exists for primary key '$keyID'." - read -p "Are you sure you would like to generate another one? (y/N) " OK; OK=${OK:N} - if [ "${OK/y/Y}" != 'Y' ] ; then - failure "aborting." - fi - break - fi - done - - # set subkey defaults - # prompt about key expiration if not specified - keyExpire=$(get_gpg_expiration "$keyExpire") + # check that an authentication subkey does not already exist + check_gpg_authentication_subkey "$keyID" # generate the list of commands that will be passed to edit-key editCommands=$(cat <<EOF @@ -108,19 +52,24 @@ E A Q $keyLength -$keyExpire +0 save EOF ) - log verbose "generating subkey..." - fifoDir=$(mktemp -d ${TMPDIR:-/tmp}/tmp.XXXXXXXXXX) + # setup the temp fifo dir for retrieving the key password + log debug "creating password fifo..." + fifoDir=$(msmktempdir) + trap "rm -rf $fifoDir" EXIT (umask 077 && mkfifo "$fifoDir/pass") - echo "$editCommands" | gpg --passphrase-fd 3 3< "$fifoDir/pass" --expert --command-fd 0 --edit-key "$keyID" & + + log verbose "generating subkey..." + echo "$editCommands" | gpg_user --passphrase-fd 3 3< "$fifoDir/pass" --expert --command-fd 0 --edit-key "$keyID" & # FIXME: this needs to fail more gracefully if the passphrase is incorrect passphrase_prompt "Please enter your passphrase for $keyID: " "$fifoDir/pass" + trap - EXIT rm -rf "$fifoDir" wait log verbose "done." diff --git a/src/share/m/import_subkey b/src/share/m/import_subkey index aa89958..8d60f26 100644 --- a/src/share/m/import_subkey +++ b/src/share/m/import_subkey @@ -13,41 +13,55 @@ # import an existing ssh key as a gpg subkey +## 2009-02-20 00:49:11-0500: This is not implemented yet, because we +## don't currently have a good way to manipulate the user's OpenPGP +## secret key such that we could make a proper subkey binding +## signature. + import_subkey() { - local keyFile="~/.ssh/id_rsa" - local keyExpire + local sshKeyFile local keyID - local gpgOut - local userID - - # get options - while true ; do - case "$1" in - -f|--keyfile) - keyFile="$2" - shift 2 - ;; - -e|--expire) - keyExpire="$2" - shift 2 - ;; - *) - if [ "$(echo "$1" | cut -c 1)" = '-' ] ; then - failure "Unknown option '$1'. -Type '$PGRM help' for usage." - fi - break - ;; - esac - done - - log verbose "importing ssh key..." - fifoDir=$(mktemp -d ${TMPDIR:-/tmp}/tmp.XXXXXXXXXX) + local gpgSecOut + local fifoDir + + # FIXME: implement! + failure "import-subkey is not implemented yet. We welcome patches. Sorry!" + + sshKeyFile="$1" + shift + + # check that key file specified + if [ -z "$sshKeyFile" ] ; then + failure "Must specify ssh key file to import, or specify '-' for stdin." + fi + + # check that the keyID is unique + keyID=$(check_gpg_sec_key_id "$@") + + # check that an authentication subkey does not already exist + check_gpg_authentication_subkey "$keyID" + + # setup the temp fifo dir for retrieving the key password + log debug "creating password fifo..." + fifoDir=$(msmktempdir) + trap "rm -rf $fifoDir" EXIT (umask 077 && mkfifo "$fifoDir/pass") - ssh2openpgp | gpg --passphrase-fd 3 3< "$fifoDir/pass" --expert --command-fd 0 --import & + # import ssh key to as authentication subkey + if [ "$sshKeyFile" = '-' ] ; then + log verbose "importing ssh key from stdin..." + PEM2OPENPGP_USAGE_FLAGS=authenticate pem2openpgp "$userID" \ + | gpg_user --passphrase-fd 3 3< "$fifoDir/pass" --expert --command-fd 0 --import & + else + log verbose "importing ssh key from file '$sshKeyFile'..." + PEM2OPENPGP_USAGE_FLAGS=authenticate pem2openpgp "$userID" <"$sshKeyFile" \ + | gpg_user --passphrase-fd 3 3< "$fifoDir/pass" --expert --command-fd 0 --import & + fi + + # get the password if needed passphrase_prompt "Please enter your passphrase for $keyID: " "$fifoDir/pass" + trap - EXIT rm -rf "$fifoDir" wait log verbose "done." diff --git a/src/share/m/ssh_proxycommand b/src/share/m/ssh_proxycommand index cd0a1fb..bd09588 100644 --- a/src/share/m/ssh_proxycommand +++ b/src/share/m/ssh_proxycommand @@ -15,8 +15,6 @@ # established. Can be added to ~/.ssh/config as follows: # ProxyCommand monkeysphere ssh-proxycommand %h %p -ssh_proxycommand() { - # "marginal case" ouput in the case that there is not a full # validation path to the host output_no_valid_key() { @@ -45,7 +43,7 @@ EOF # found? # get the gpg info for userid - gpgOut=$(gpg --list-key --fixed-list-mode --with-colon \ + gpgOut=$(gpg_user --list-key --fixed-list-mode --with-colon \ --with-fingerprint --with-fingerprint \ ="$userID" 2>/dev/null) @@ -66,14 +64,14 @@ An OpenPGP key matching the ssh key offered by the host was found: EOF - # do some crazy "Here Strings" redirection to get the key to - # ssh-keygen, since it doesn't read from stdin cleanly - sshFingerprint=$(ssh-keygen -l -f /dev/stdin \ - <<<$(echo "$sshKeyGPG") | \ + sshKeyGPGFile=$(msmktempfile) + printf "%s" "$sshKeyGPG" >"$sshKeyGPGFile" + sshFingerprint=$(ssh-keygen -l -f "$sshKeyGPGFile" | \ awk '{ print $2 }') + rm -f "$sshKeyGPGFile" # get the sigs for the matching key - gpgSigOut=$(gpg --check-sigs \ + gpgSigOut=$(gpg_user --check-sigs \ --list-options show-uid-validity \ "$keyid") @@ -136,10 +134,9 @@ EOF EOF } -######################################################################## -# export the monkeysphere log level -export MONKEYSPHERE_LOG_LEVEL +# the ssh proxycommand function itself +ssh_proxycommand() { if [ "$1" = '--no-connect' ] ; then NO_CONNECT='true' @@ -170,12 +167,13 @@ URI="ssh://${HOSTP}" # intentionally different than that of running monkeyesphere normally, # and keyserver checking is intentionally done under certain # circumstances. This can be overridden by setting the -# MONKEYSPHERE_CHECK_KEYSERVER environment variable. +# MONKEYSPHERE_CHECK_KEYSERVER environment variable, or by setting the +# CHECK_KEYSERVER variable in the monkeysphere.conf file. # if the host is in the gpg keyring... -if gpg --list-key ="${URI}" 2>&1 >/dev/null ; then +if gpg_user --list-key ="${URI}" 2>&1 >/dev/null ; then # do not check the keyserver - CHECK_KEYSERVER="false" + CHECK_KEYSERVER=${CHECK_KEYSERVER:="false"} # if the host is NOT in the keyring... else @@ -188,20 +186,21 @@ else # FIXME: more nuanced checking should be done here to properly # take into consideration hosts that join monkeysphere by # converting an existing and known ssh key - CHECK_KEYSERVER="false" + CHECK_KEYSERVER=${CHECK_KEYSERVER:="false"} # if the host key is not found in the known_hosts file... else # check the keyserver - CHECK_KEYSERVER="true" + CHECK_KEYSERVER=${CHECK_KEYSERVER:="true"} fi fi -# set and export the variable for use by monkeysphere -MONKEYSPHERE_CHECK_KEYSERVER=${MONKEYSPHERE_CHECK_KEYSERVER:="$CHECK_KEYSERVER"} -export MONKEYSPHERE_CHECK_KEYSERVER + +# finally look in the MONKEYSPHERE_ environment variable for a +# CHECK_KEYSERVER setting to override all else +CHECK_KEYSERVER=${MONKEYSPHERE_CHECK_KEYSERVER:=$CHECK_KEYSERVER} # update the known_hosts file for the host -monkeysphere update-known_hosts "$HOSTP" +update_known_hosts "$HOSTP" # output on depending on the return of the update-known_hosts # subcommand, which is (ultimately) the return code of the diff --git a/src/share/m/subkey_to_ssh_agent b/src/share/m/subkey_to_ssh_agent index 012c95f..818f4f7 100644 --- a/src/share/m/subkey_to_ssh_agent +++ b/src/share/m/subkey_to_ssh_agent @@ -46,7 +46,8 @@ For more details, see: # get list of secret keys (to work around bug # https://bugs.g10code.com/gnupg/issue945): - secretkeys=$(gpg --list-secret-keys --with-colons --fixed-list-mode --fingerprint | \ + secretkeys=$(gpg_user --list-secret-keys --with-colons --fixed-list-mode \ + --fingerprint | \ grep '^fpr:' | cut -f10 -d: | awk '{ print "0x" $1 "!" }') if [ -z "$secretkeys" ]; then @@ -54,7 +55,7 @@ For more details, see: You might want to run 'gpg --gen-key'." fi - authsubkeys=$(gpg --list-secret-keys --with-colons --fixed-list-mode \ + authsubkeys=$(gpg_user --list-secret-keys --with-colons --fixed-list-mode \ --fingerprint --fingerprint $secretkeys | \ cut -f1,5,10,12 -d: | grep -A1 '^ssb:[^:]*::[^:]*a[^:]*$' | \ grep '^fpr::' | cut -f3 -d: | sort -u) @@ -64,7 +65,8 @@ You might want to run 'gpg --gen-key'." You might want to 'monkeysphere gen-subkey'" fi - workingdir=$(mktemp -d ${TMPDIR:-/tmp}/tmp.XXXXXXXXXX) + workingdir=$(msmktempdir) + trap "rm -rf $workingdir" EXIT umask 077 mkfifo "$workingdir/passphrase" keysuccess=1 @@ -79,19 +81,19 @@ You might want to 'monkeysphere gen-subkey'" # fingerprint, but filtering out all / characters to make sure # the filename is legit. - primaryuid=$(gpg --with-colons --list-key "0x${subkey}!" | grep '^pub:' | cut -f10 -d: | tr -d /) + primaryuid=$(gpg_user --with-colons --list-key "0x${subkey}!" | grep '^pub:' | cut -f10 -d: | tr -d /) #kname="[monkeysphere] $primaryuid" kname="$primaryuid" if [ "$1" = '-d' ]; then # we're removing the subkey: - gpg --export "0x${subkey}!" | openpgp2ssh "$subkey" > "$workingdir/$kname" + gpg_user --export "0x${subkey}!" | openpgp2ssh "$subkey" > "$workingdir/$kname" (cd "$workingdir" && ssh-add -d "$kname") else # we're adding the subkey: mkfifo "$workingdir/$kname" - gpg --quiet --passphrase-fd 3 3<"$workingdir/passphrase" \ + gpg_user --passphrase-fd 3 3<"$workingdir/passphrase" \ --export-options export-reset-subkey-passwd,export-minimal,no-export-attributes \ --export-secret-subkeys "0x${subkey}!" | openpgp2ssh "$subkey" > "$workingdir/$kname" & (cd "$workingdir" && DISPLAY=nosuchdisplay SSH_ASKPASS=/bin/false ssh-add "$@" "$kname" </dev/null )& @@ -104,6 +106,7 @@ You might want to 'monkeysphere gen-subkey'" rm -f "$workingdir/$kname" done + trap - EXIT rm -rf "$workingdir" # FIXME: sort out the return values: we're just returning the diff --git a/src/share/ma/add_certifier b/src/share/ma/add_certifier index d34f0de..f2cadf2 100644 --- a/src/share/ma/add_certifier +++ b/src/share/ma/add_certifier @@ -31,7 +31,6 @@ local domain= local trust=full local depth=1 local keyID -local importinfo local fingerprint local ltsignCommand local trustval @@ -51,6 +50,9 @@ while true ; do depth="$2" shift 2 ;; + -) + break + ;; *) if [ "$(echo "$1" | cut -c 1)" = '-' ] ; then failure "Unknown option '$1'. @@ -62,67 +64,13 @@ Type '$PGRM help' for usage." done keyID="$1" + +# check that key ID or file is specified if [ -z "$keyID" ] ; then failure "You must specify the key ID of a key to add, or specify a file to read the key from." fi -if [ -f "$keyID" ] ; then - log info "Reading key from file '$keyID':" - importinfo=$(gpg_sphere "--import" < "$keyID" 2>&1) || failure "could not read key from '$keyID'" - # FIXME: if this is tried when the key database is not - # up-to-date, i got these errors (using set -x): - - # ++ su -m monkeysphere -c '\''gpg --import'\'' - # Warning: using insecure memory! - # gpg: key D21739E9: public key "Daniel Kahn Gillmor <dkg@fifthhorseman.net>" imported - # gpg: Total number processed: 1 - # gpg: imported: 1 (RSA: 1) - # gpg: can'\''t create `/var/monkeysphere/gnupg-host/pubring.gpg.tmp'\'': Permission denied - # gpg: failed to rebuild keyring cache: Permission denied - # gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model - # gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u - # gpg: next trustdb check due at 2009-01-10' - # + failure 'could not read key from '\''/root/dkg.gpg'\''' - # + echo 'could not read key from '\''/root/dkg.gpg'\''' - - keyID=$(echo "$importinfo" | grep '^gpg: key ' | cut -f2 -d: | cut -f3 -d\ ) - if [ -z "$keyID" ] || [ $(echo "$keyID" | wc -l) -ne 1 ] ; then - failure "There was not exactly one gpg key in the file." - fi -else - # get the key from the key server - log debug "retrieving key from keyserver..." - gpg_sphere "--keyserver $KEYSERVER --recv-key '0x${keyID}!'" || failure "Could not receive a key with this ID from the '$KEYSERVER' keyserver." -fi - -export keyID - -# get the full fingerprint of new certifier key -log debug "getting fingerprint of certifier key..." -fingerprint=$(gpg_sphere "--list-key --with-colons --with-fingerprint 0x${keyID}!" \ - | grep '^fpr:' | grep "$keyID" | cut -d: -f10) - -if [ -z "$fingerprint" ] ; then - failure "Key '$keyID' not found." -fi - -log info "key found:" -gpg_sphere "--fingerprint 0x${fingerprint}!" - -if [ "$PROMPT" = "true" ] ; then - echo "Are you sure you want to add the above key as a" - read -p "certifier of users on this system? (y/N) " OK; OK=${OK:-N} - if [ "${OK/y/Y}" != 'Y' ] ; then - failure "Identity certifier not added." - fi -else - log debug "adding key without prompting." -fi - -# export the key to the core keyring so that the core can sign the -# new certifier key -log debug "exporting retrieved certifier key to core keyring..." -gpg_sphere "--export 0x${fingerprint}!" | gpg_core --import +# check the trust value case "$trust" in 'marginal') trustval=1 @@ -135,6 +83,64 @@ case "$trust" in ;; esac +# if file is specified +if [ -f "$keyID" -o "$keyID" = '-' ] ; then + # load the key from stdin + if [ "$keyID" = '-' ] ; then + # make a temporary file to hold the key from stdin + keyID=$(msmktempfile) + trap "rm -f $keyID" EXIT + log verbose "reading key from stdin..." + cat > "$keyID" + + # load the key from the file + elif [ -f "$keyID" ] ; then + log verbose "reading key from file '$keyID'..." + fi + + # check the key is ok as monkeysphere user before loading + log debug "checking keys in file..." + fingerprint=$(su_monkeysphere_user \ + ". ${SYSSHAREDIR}/common; list_primary_fingerprints" < "$keyID") + + if [ $(printf "%s" "$fingerprint" | egrep -c '^[A-F0-9]{40}$') -ne 1 ] ; then + failure "There was not exactly one gpg key in the file." + fi + + # load the key + gpg_sphere "--import" <"$keyID" \ + || failure "could not read key from '$keyID'" + +# else, get the key from the keyserver +else + log verbose "searching keyserver $KEYSERVER for keyID $keyID..." + gpg_sphere "--keyserver $KEYSERVER --recv-key '0x${keyID}!'" \ + || failure "Could not receive a key with this ID from the '$KEYSERVER' keyserver." + + # get the full fingerprint of new certifier key + log debug "getting fingerprint of certifier key..." + fingerprint=$(gpg_sphere "--list-key --with-colons --with-fingerprint 0x${keyID}!" \ + | grep '^fpr:' | grep "$keyID" | cut -d: -f10) + + log info "key found:" + gpg_sphere "--fingerprint 0x${fingerprint}!" + + if [ "$PROMPT" = "true" ] ; then + echo "Are you sure you want to add the above key as a" + read -p "certifier of users on this system? (Y/n) " OK; OK=${OK:-Y} + if [ "${OK/y/Y}" != 'Y' ] ; then + failure "Identity certifier not added." + fi + else + log debug "adding key without prompting." + fi +fi + +# export the key to the core keyring so that the core can sign the +# new certifier key +log debug "loading key into core keyring..." +gpg_sphere "--export 0x${fingerprint}!" | gpg_core --import + # edit-key script to ltsign key # NOTE: *all* user IDs will be ltsigned ltsignCommand=$(cat <<EOF @@ -151,8 +157,7 @@ EOF # core ltsigns the newly imported certifier key log debug "executing core ltsign script..." if echo "$ltsignCommand" | \ - gpg_core --quiet --command-fd 0 --no-tty --edit-key "0x${fingerprint}!" \ - 2>&1 | log debug ; then + gpg_core --command-fd 0 --edit-key "0x${fingerprint}!" ; then # transfer the new sigs back to the sphere keyring gpg_core_sphere_sig_transfer diff --git a/src/share/ma/diagnostics b/src/share/ma/diagnostics index 0411080..ce463b2 100644 --- a/src/share/ma/diagnostics +++ b/src/share/ma/diagnostics @@ -28,6 +28,8 @@ local badhostkeys local sshd_config local problemsfound=0 +report_cruft + if ! id monkeysphere >/dev/null ; then echo "! No monkeysphere user found! Please create a monkeysphere system user with bash as its shell." problemsfound=$(($problemsfound+1)) @@ -45,7 +47,10 @@ if ! [ -d "$MADATADIR" ] ; then exit fi -# FIXME: what's the correct, cross-platform answer? +# FIXME: what's the correct, cross-platform way to determine where +# sshd_config lives? +sshd_config=/etc/ssh/sshd_config + seckey=$(gpg_core --list-secret-keys --fingerprint --with-colons --fixed-list-mode) keysfound=$(echo "$seckey" | grep -c ^sec:) curdate=$(date +%s) @@ -95,7 +100,16 @@ fi # FIXME: look to see that the ownertrust rules are set properly on the # sphere keyring -# FIXME: make sure that at least one identity certifier exists +# make sure that at least one identity certifier exists +echo +echo "Checking for Identity Certifiers..." +if ! monkeysphere-authentication list-identity-certifiers | egrep -q '^[A-F0-9]{40}:' then + echo "! No Identity Certifiers found!" + echo " - Recommendation: once you know who should be able to certify identities for + connecting users, you should add their key, with: + monkeysphere-authentication add-identity-certifier" + problemsfound=$(($problemsfound+1)) +fi # FIXME: look at the timestamps on the monkeysphere-generated # authorized_keys files -- warn if they seem out-of-date. diff --git a/src/share/ma/list_certifiers b/src/share/ma/list_certifiers index a02487d..38a3222 100644 --- a/src/share/ma/list_certifiers +++ b/src/share/ma/list_certifiers @@ -86,5 +86,4 @@ gpg_sphere "--fingerprint --with-colons --fixed-list-mode --check-sigs" | \ esac done - } diff --git a/src/share/ma/remove_certifier b/src/share/ma/remove_certifier index 10aa67b..a9a1451 100644 --- a/src/share/ma/remove_certifier +++ b/src/share/ma/remove_certifier @@ -27,7 +27,7 @@ fi gpg_core --list-key --fingerprint "0x${keyID}!" || failure if [ "$PROMPT" = "true" ] ; then - read -p "Really remove above listed identity certifier? (y/N) " OK; OK=${OK:-N} + read -p "Really remove the identity certifier above? (Y/n) " OK; OK=${OK:-Y} if [ "${OK/y/Y}" != 'Y' ] ; then failure "Identity certifier not removed." fi diff --git a/src/share/ma/setup b/src/share/ma/setup index a17e4f2..e77afff 100644 --- a/src/share/ma/setup +++ b/src/share/ma/setup @@ -13,13 +13,18 @@ setup() { # make all needed directories + log debug "checking authentication directory structure..." mkdir -p "${MADATADIR}" + chmod 0750 "${MADATADIR}" + chgrp "$MONKEYSPHERE_USER" "${MADATADIR}" mkdir -p "${MATMPDIR}" + chmod 0750 "${MATMPDIR}" + chgrp "$MONKEYSPHERE_USER" "${MATMPDIR}" mkdir -p "${GNUPGHOME_CORE}" - chmod 700 "${GNUPGHOME_CORE}" + chmod 0700 "${GNUPGHOME_CORE}" mkdir -p "${GNUPGHOME_SPHERE}" - chmod 700 "${GNUPGHOME_SPHERE}" - mkdir -p "${MADATADIR}"/authorized_keys + chmod 0700 "${GNUPGHOME_SPHERE}" + mkdir -p "${SYSDATADIR}"/authorized_keys # deliberately replace the config files via truncation # FIXME: should we be dumping to tmp files and then moving atomically? @@ -29,7 +34,6 @@ setup() { # This file is maintained by the Monkeysphere software. # Edits will be overwritten. no-greeting -list-options show-uid-validity EOF log debug "writing sphere gpg.conf..." @@ -43,9 +47,8 @@ EOF # make sure the monkeysphere user owns everything in the sphere # gnupghome - log debuf "fixing sphere gnupg home ownership..." - chown -R "$MONKEYSPHERE_USER" "${GNUPGHOME_SPHERE}" - chgrp -R "$MONKEYSPHERE_USER" "${GNUPGHOME_SPHERE}" + log debug "fixing sphere gnupg home ownership..." + chown "$MONKEYSPHERE_USER:$MONKEYSPHERE_USER" "${GNUPGHOME_SPHERE}" "${GNUPGHOME_SPHERE}"/gpg.conf # get fingerprint of core key. this should be empty on unconfigured systems. local CORE_FPR=$(core_fingerprint) @@ -59,7 +62,7 @@ EOF log debug "generating monkeysphere authentication trust core key ($CORE_KEYLENGTH bits)..." PEM2OPENPGP_USAGE_FLAGS=certify \ PEM2OPENPGP_NEWKEY=$CORE_KEYLENGTH pem2openpgp "$CORE_UID" \ - | gpg_core --import 2>&1 | log debug \ + | gpg_core --import \ || failure "Could not import new key for Monkeysphere authentication trust core" # get fingerprint of core key. should definitely not be empty at this point @@ -75,17 +78,17 @@ EOF # export the core key to the sphere keyring log debug "exporting core pub key to sphere keyring..." - gpg_core --quiet --export | gpg_sphere "--quiet --import" + gpg_core --export | gpg_sphere "--import" # ensure that the authentication sphere checker has absolute ownertrust on the expected key. log debug "setting ultimate owner trust on core key in gpg_sphere..." - printf "%s:6:\n" "$CORE_FPR" | gpg_sphere "--quiet --import-ownertrust" + printf "%s:6:\n" "$CORE_FPR" | gpg_sphere "--import-ownertrust" gpg_sphere "--export-ownertrust" 2>&1 | log debug # check the owner trust log debug "checking gpg_sphere owner trust set properly..." local ORIG_TRUST - if ORIG_TRUST=$(gpg_sphere "--quiet --export-ownertrust" | grep '^[^#]') ; then + if ORIG_TRUST=$(gpg_sphere "--export-ownertrust" | grep '^[^#]') ; then if [ "${CORE_FPR}:6:" != "$ORIG_TRUST" ] ; then failure "Monkeysphere authentication trust sphere should explicitly trust the core. It does not have proper ownertrust settings." fi @@ -98,7 +101,7 @@ EOF # our preferences are reasonable (i.e. 3 marginal OR 1 fully # trusted certifications are sufficient to grant full validity. log debug "checking trust model for authentication ..." - local TRUST_MODEL=$(gpg_sphere "--quiet --with-colons --fixed-list-mode --list-keys" \ + local TRUST_MODEL=$(gpg_sphere "--with-colons --fixed-list-mode --list-keys" \ | head -n1 | grep "^tru:" | cut -d: -f3,6,7) log debug "sphere trust model: $TRUST_MODEL" if [ "$TRUST_MODEL" != '1:3:1' ] ; then diff --git a/src/share/ma/update_users b/src/share/ma/update_users index e9e3cc6..092d108 100644 --- a/src/share/ma/update_users +++ b/src/share/ma/update_users @@ -35,7 +35,7 @@ MODE="authorized_keys" GNUPGHOME="$GNUPGHOME_SPHERE" # the authorized_keys directory -authorizedKeysDir="${MADATADIR}/authorized_keys" +authorizedKeysDir="${SYSDATADIR}/authorized_keys" # check to see if the gpg trust database has been initialized if [ ! -s "${GNUPGHOME}/trustdb.gpg" ] ; then diff --git a/src/share/mh/add_hostname b/src/share/mh/add_hostname index 70bbec3..0da6a06 100644 --- a/src/share/mh/add_hostname +++ b/src/share/mh/add_hostname @@ -34,8 +34,8 @@ find_host_userid > /dev/null && \ if [ "$PROMPT" = "true" ] ; then echo "The following user ID will be added to the host key:" echo " $userID" - read -p "Are you sure you would like to add this user ID? (y/N) " OK; OK=${OK:=N} - if [ ${OK/y/Y} != 'Y' ] ; then + read -p "Are you sure you would like to add this user ID? (Y/n) " OK; OK=${OK:=Y} + if [ "${OK/y/Y}" != 'Y' ] ; then failure "User ID not added." fi else diff --git a/src/share/mh/add_revoker b/src/share/mh/add_revoker index b4113df..428b958 100644 --- a/src/share/mh/add_revoker +++ b/src/share/mh/add_revoker @@ -15,91 +15,99 @@ add_revoker() { -local domain= -local trust=full -local depth=1 local keyID -local importinfo +local tmpDir local fingerprint -local ltsignCommand -local trustval +local addrevokerCommand keyID="$1" + +# check that key ID or file is specified if [ -z "$keyID" ] ; then failure "You must specify the key ID of a revoker key, or specify a file to read the key from." fi -if [ -f "$keyID" ] ; then - log info "Reading key from file '$keyID':" - importinfo=$(gpg_host --import < "$keyID" 2>&1) || failure "could not read key from '$keyID'" - # FIXME: if this is tried when the key database is not - # up-to-date, i got these errors (using set -x): - - # ++ su -m monkeysphere -c '\''gpg --import'\'' - # Warning: using insecure memory! - # gpg: key D21739E9: public key "Daniel Kahn Gillmor <dkg@fifthhorseman.net>" imported - # gpg: Total number processed: 1 - # gpg: imported: 1 (RSA: 1) - # gpg: can'\''t create `/var/monkeysphere/gnupg-host/pubring.gpg.tmp'\'': Permission denied - # gpg: failed to rebuild keyring cache: Permission denied - # gpg: 3 marginal(s) needed, 1 complete(s) needed, PGP trust model - # gpg: depth: 0 valid: 1 signed: 0 trust: 0-, 0q, 0n, 0m, 0f, 1u - # gpg: next trustdb check due at 2009-01-10' - # + failure 'could not read key from '\''/root/dkg.gpg'\''' - # + echo 'could not read key from '\''/root/dkg.gpg'\''' - - keyID=$(echo "$importinfo" | grep '^gpg: key ' | cut -f2 -d: | cut -f3 -d\ ) - if [ -z "$keyID" ] || [ $(echo "$keyID" | wc -l) -ne 1 ] ; then + +# make a temporary directory for storing keys during import, and set +# the trap to delete it on exit +tmpDir=$(msmktempdir) +trap "rm -rf $tmpDir" EXIT + +# if file is specified +if [ -f "$keyID" -o "$keyID" = '-' ] ; then + # load the key from stdin + if [ "$keyID" = '-' ] ; then + # make a temporary file to hold the key from stdin + keyID="$tmpDir"/importkey + log verbose "reading key from stdin..." + cat > "$keyID" + + # load the key from the file + elif [ -f "$keyID" ] ; then + log verbose "reading key from file '$keyID'..." + fi + + # check the key is ok as monkeysphere user before loading + log debug "checking keys in file..." + fingerprint=$(su_monkeysphere_user \ + ". ${SYSSHAREDIR}/common; list_primary_fingerprints" < "$keyID") + + if [ $(printf "%s" "$fingerprint" | egrep -c '^[A-F0-9]{40}$') -ne 1 ] ; then failure "There was not exactly one gpg key in the file." fi + + # load the key + gpg_host --import <"$keyID" \ + || failure "could not read key from '$keyID'" + +# else, get the key from the keyserver else - # create a temporary directory for storing the downloaded key - TMPLOC=$(mktemp -d "${MHTMPDIR}"/tmp.XXXXXXXXXX) || failure "Could not create temporary directory!" + # fix permissions and ownership on temporary directory which will + # be used by monkeysphere user for storing the downloaded key + chmod 0700 "$tmpDir" + chown "$MONKEYSPHERE_USER":"$MONKEYSPHERE_USER" "$tmpDir" # download the key from the keyserver as the monkeysphere user - su_monkeysphere_user \ - "GNUPGHOME=$TMPLOC gpg --keyserver $KEYSERVER --recv-key 0x${keyID}!" + log verbose "searching keyserver $KEYSERVER for keyID $keyID..." + su_monkeysphere_user "GNUPGHOME=$tmpDir gpg --quiet --keyserver $KEYSERVER --recv-key 0x${keyID}!" \ + || failure "Could not receive a key with this ID from the '$KEYSERVER' keyserver." + + # get the full fingerprint of new revoker key + log debug "getting fingerprint of revoker key..." + fingerprint=$(su_monkeysphere_user "GNUPGHOME=$tmpDir gpg --list-key --with-colons --with-fingerprint 0x${keyID}!" \ + | grep '^fpr:' | grep "$keyID" | cut -d: -f10) + + log info "key found:" + su_monkeysphere_user "GNUPGHOME=$tmpDir gpg --fingerprint 0x${fingerprint}!" + + if [ "$PROMPT" = "true" ] ; then + echo "Are you sure you want to add the above key as a" + read -p "revoker of the host key? (Y/n) " OK; OK=${OK:-Y} + if [ "${OK/y/Y}" != 'Y' ] ; then + failure "revoker not added." + fi + else + log debug "adding revoker without prompting." + fi # export the new key to the host keyring - su_monkeysphere_user "GNUPGHOME=$TMPLOC gpg --export 0x${keyID}!" \ + log debug "loading key into host keyring..." + su_monkeysphere_user "GNUPGHOME=$tmpDir gpg --quiet --export 0x${fingerprint}!" \ | gpg_host --import fi -export keyID - -# get the full fingerprint of the revoker key ID -fingerprint=$(gpg_host --list-key --with-colons --with-fingerprint "0x${keyID}!" \ - | grep '^fpr:' | grep "$keyID" | cut -d: -f10) - -if [ -z "$fingerprint" ] ; then - failure "Key '$keyID' not found." -fi - -log info "key found:" -gpg_host --fingerprint "0x${fingerprint}!" - -if [ "$PROMPT" = "true" ] ; then - echo "Are you sure you want to add the above key as a" - read -p "revoker of the host key? (y/N) " OK; OK=${OK:-N} - if [ "${OK/y/Y}" != 'Y' ] ; then - failure "revoker not added." - fi -else - log debug "adding revoker without prompting." -fi - # edit-key script to add revoker addrevokerCommand=$(cat <<EOF addrevoker +$fingerprint +y +save EOF ) -# FIXME: implement! -failure "not implemented yet!" - # core ltsigns the newly imported revoker key -if echo "$addrevokerCommand" | \ - gpg_core_edit ; then +log debug "executing add revoker script..." +if echo "$addrevokerCommand" | gpg_host_edit ; then update_gpg_pub_file @@ -108,4 +116,8 @@ else failure "Problem adding revoker." fi +# remove the temporary directory +trap - EXIT +rm -rf "$tmpDir" + } diff --git a/src/share/mh/diagnostics b/src/share/mh/diagnostics index d774723..2f65f89 100644 --- a/src/share/mh/diagnostics +++ b/src/share/mh/diagnostics @@ -25,11 +25,10 @@ local expire local uid local fingerprint local badhostkeys -local sshd_config local problemsfound=0 -# FIXME: what's the correct, cross-platform answer? -sshd_config=/etc/ssh/sshd_config +report_cruft + seckey=$(gpg_host --list-secret-keys --fingerprint --with-colons --fixed-list-mode) keysfound=$(echo "$seckey" | grep -c ^sec:) curdate=$(date +%s) @@ -50,7 +49,7 @@ fi echo "Checking host GPG key..." if (( "$keysfound" < 1 )); then echo "! No host key found." - echo " - Recommendation: run 'monkeysphere-host gen-key' or 'monkeysphere-host import-key'" + echo " - Recommendation: run 'monkeysphere-host import-key'" problemsfound=$(($problemsfound+1)) elif (( "$keysfound" > 1 )); then echo "! More than one host key found?" @@ -114,35 +113,9 @@ else # FIXME: propose adding a revoker to the host key if none exist (do we # have a way to do that after key generation?) - # Ensure that the ssh_host_rsa_key file is present and non-empty: - echo - echo "Checking host SSH key..." - if [ ! -s "${SYSDATADIR}/ssh_host_rsa_key" ] ; then - echo "! The host key as prepared for SSH (${SYSDATADIR}/ssh_host_rsa_key) is missing or empty." - problemsfound=$(($problemsfound+1)) - else - if [ $(ls -l "${SYSDATADIR}/ssh_host_rsa_key" | cut -f1 -d\ ) != '-rw-------' ] ; then - echo "! Permissions seem wrong for ${SYSDATADIR}/ssh_host_rsa_key -- should be 0600." - problemsfound=$(($problemsfound+1)) - fi +# FIXME: test (with ssh-keyscan?) that the running ssh +# daemon is actually offering the monkeysphere host key. - # propose changes needed for sshd_config (if any) - if ! grep -q "^HostKey[[:space:]]\+${SYSDATADIR}/ssh_host_rsa_key$" "$sshd_config"; then - echo "! $sshd_config does not point to the monkeysphere host key (${SYSDATADIR}/ssh_host_rsa_key)." - echo " - Recommendation: add a line to $sshd_config: 'HostKey ${SYSDATADIR}/ssh_host_rsa_key'" - problemsfound=$(($problemsfound+1)) - fi - if badhostkeys=$(grep -i '^HostKey' "$sshd_config" | grep -v "^HostKey[[:space:]]\+${SYSDATADIR}/ssh_host_rsa_key$") ; then - echo "! $sshd_config refers to some non-monkeysphere host keys:" - echo "$badhostkeys" - echo " - Recommendation: remove the above HostKey lines from $sshd_config" - problemsfound=$(($problemsfound+1)) - fi - - # FIXME: test (with ssh-keyscan?) that the running ssh - # daemon is actually offering the monkeysphere host key. - - fi fi # FIXME: look at the ownership/privileges of the various keyrings, diff --git a/src/share/mh/import_key b/src/share/mh/import_key index 557bb7f..040b41c 100644 --- a/src/share/mh/import_key +++ b/src/share/mh/import_key @@ -13,15 +13,22 @@ import_key() { +local sshKeyFile local hostName local domain local userID -hostName="$1" +sshKeyFile="$1" +hostName="$2" + +# check that key file specified +if [ -z "$sshKeyFile" ] ; then + failure "Must specify ssh key file to import, or specify '-' for stdin." +fi # use the default hostname if not specified if [ -z "$hostName" ] ; then - hostName=$(hostname -f) + hostName=$(hostname -f) || failure "Could not determine hostname." # test that the domain is not obviously illegitimate domain=${foo##*.} case $domain in @@ -39,14 +46,20 @@ userID="ssh://${hostName}" # create host home mkdir -p "${MHDATADIR}" -mkdir -p "${MHTMPDIR}" mkdir -p "${GNUPGHOME_HOST}" chmod 700 "${GNUPGHOME_HOST}" -log verbose "importing ssh key..." -# translate ssh key to a private key -PEM2OPENPGP_USAGE_FLAGS=authenticate pem2openpgp "$userID" \ - | gpg_host --import 2>&1 | log debug +# import ssh key to a private key +if [ "$sshKeyFile" = '-' ] ; then + log verbose "importing ssh key from stdin..." + PEM2OPENPGP_USAGE_FLAGS=authenticate pem2openpgp "$userID" \ + | gpg_host --import +else + log verbose "importing ssh key from file '$sshKeyFile'..." + PEM2OPENPGP_USAGE_FLAGS=authenticate pem2openpgp "$userID" \ + <"$sshKeyFile" \ + | gpg_host --import +fi # load the new host fpr into the fpr variable. this is so we can # create the gpg pub key file. we have to do this from the secret key diff --git a/src/share/mh/publish_key b/src/share/mh/publish_key index b433ad7..b0ffd93 100644 --- a/src/share/mh/publish_key +++ b/src/share/mh/publish_key @@ -18,8 +18,8 @@ publish_key() { local GNUPGHOME if [ "$PROMPT" = "true" ] ; then - read -p "Really publish host key to $KEYSERVER? (y/N) " OK; OK=${OK:=N} - if [ ${OK/y/Y} != 'Y' ] ; then + read -p "Really publish host key to $KEYSERVER? (Y/n) " OK; OK=${OK:=Y} + if [ "${OK/y/Y}" != 'Y' ] ; then failure "key not published." fi else @@ -27,7 +27,9 @@ else fi # create a temporary gnupg directory from which to publish the key -export GNUPGHOME=$(mktemp -d) +export GNUPGHOME=$(msmktempdir) +chmod 0700 "$GNUPGHOME" +chown "$MONKEYSPHERE_USER":"$MONKEYSPHERE_USER" "$GNUPGHOME" # trap to remove tmp dir if break trap "rm -rf $GNUPGHOME" EXIT diff --git a/src/share/mh/revoke_hostname b/src/share/mh/revoke_hostname index 77f1f0d..71b56ed 100644 --- a/src/share/mh/revoke_hostname +++ b/src/share/mh/revoke_hostname @@ -28,7 +28,7 @@ if [ -z "$1" ] ; then fi echo "WARNING: There is a known bug in this function." -echo "This function has been known to occasionally revoke the wrong user ID." +echo "This function has been known to occasionally revoke the wrong hostname." echo "Please see the following bug report for more information:" echo "https://labs.riseup.net/code/issues/show/422" read -p "Are you sure you would like to proceed? (y/N) " OK; OK=${OK:=N} @@ -45,8 +45,8 @@ uidIndex=$(find_host_userid) || \ if [ "$PROMPT" = "true" ] ; then echo "The following host key user ID will be revoked:" echo " $userID" - read -p "Are you sure you would like to revoke this user ID? (y/N) " OK; OK=${OK:=N} - if [ ${OK/y/Y} != 'Y' ] ; then + read -p "Are you sure you would like to revoke this user ID? (N/y) " OK; OK=${OK:=Y} + if [ "${OK/y/Y}" != 'Y' ] ; then failure "User ID not revoked." fi else diff --git a/src/share/mh/revoke_key b/src/share/mh/revoke_key index cccdc22..380236b 100644 --- a/src/share/mh/revoke_key +++ b/src/share/mh/revoke_key @@ -15,7 +15,31 @@ revoke_key() { -# FIXME: implement! -failure "not implemented yet!" +# Coming in here, we expect $HOST_FINGERPRINT to be set, and we +# believe that there is in fact a key. + # our current implementation is very simple: we just want to + # generate the revocation certificate on stdout. This provides + # for the two most likely (but hopefully not common) scenarios: + + # an admin wants a revocation certificate for the host which they + # can store securely offline. In this case, the admin can + # redirect stdout to a file, or can simply copy/paste or + # transcribe from the terminal. + + # Alternately, an admin might want to publish the revocation + # certificate immediately. here's a quick way to do this: + + + # tmp=$(mktemp -d) + # export GNUPGHOME="$tmp" + # gpg --import < /var/lib/monkeysphere/ssh_host_rsa_key.pub.gpg + # monkeysphere-host revoke-key | gpg --import + # gpg --keyserver pool.sks-keyservers.net --send $(hostname -f) + + + # note: we're not using the gpg_host function because we actually + # want to use gpg's UI in this case, so we want to omit --no-tty + + GNUPGHOME="$GNUPGHOME_HOST" gpg --no-greeting --quiet --armor --gen-revoke "0x${HOST_FINGERPRINT}!" } diff --git a/src/share/mh/set_expire b/src/share/mh/set_expire index ae7c13a..63e5c55 100644 --- a/src/share/mh/set_expire +++ b/src/share/mh/set_expire @@ -22,7 +22,7 @@ local extendTo extendTo=$(get_gpg_expiration "$1") if [ "$PROMPT" = "true" ] ; then - read -p "Are you sure you want to change the expiration on the host key to '$extendTo'? (y/N) " OK; OK=${OK:-N} + read -p "Are you sure you want to change the expiration on the host key to '$extendTo'? (Y/n) " OK; OK=${OK:-Y} if [ "${OK/y/Y}" != 'Y' ] ; then failure "expiration not set." fi diff --git a/src/transition_0.22_0.23 b/src/transition_0.22_0.23 deleted file mode 100755 index 3328e8c..0000000 --- a/src/transition_0.22_0.23 +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/bash - -# This is a post-install script for monkeysphere, to transition an old -# (<=0.22) setup to the new (>0.22) setup - -SYSDATADIR=${MONKEYSPHERE_SYSDATADIR:-"/var/lib/monkeysphere"} - -MADATADIR="${SYSDATADIR}/authentication" -MHDATADIR="${SYSDATADIR}/host" - -############################################################ -### transfer host setup - -if [ -d "$SYSDATADIR"/gnupg-host ] ; then - - if [ -s "$SYSDATADIR"/ssh_host_rsa_key ] ; then - - # This would be simple, but it would generate a new pgp key, - #and we don't want that, right? - #monkeysphere-host expert import_key "$SYSDATADIR"/ssh_host_rsa_key - - # create host home - mkdir -p "${MHDATADIR}" - mkdir -p "${MHTMPDIR}" - mkdir -p "${GNUPGHOME_HOST}" - chmod 700 "${GNUPGHOME_HOST}" - - # transfer the host secret key from the old home to the new - GNUPGHOME="$SYSDATADIR"/gnupg-host gpg --export-secret-keys \ - GNUPGHOME="$MHDATADIR" gpg --import - - # make sure the ssh_host_rsa_key.pub and ssh_host_rsa_key.pub.gpg - # files exist - - # anything else? - - fi - - #rm -rf "$SYSDATADIR"/gnupg-host - -fi - -############################################################ -### transfer authentication setup - -# should we test for something else/better than the existence of this -# directory to know that we should go through the setup? -if [ -d "$SYSDATADIR"/gnupg-authentication ] ; then - - # run the authentication setup - monkeysphere-authentication setup - - # transfer certifiers - # FIXME: how? - # i think we'll need to run something like - # gpg_core_sphere_sig_transfer after transfering certifiers ltsigs - - # do we need to do some sort of transfer of ownertrust? - - # move the authorized_keys directory - mv "$SYSDATADIR"/authorized_keys "$MADATADIR"/ - - # do we need to transfer anything else? running update-users will - # regenerate everything else in the sphere keyring, right? - - #rm -rf "$SYSDATADIR"/gnupg-authentication - -fi - diff --git a/src/transitions/0.23 b/src/transitions/0.23 new file mode 100755 index 0000000..f09dfff --- /dev/null +++ b/src/transitions/0.23 @@ -0,0 +1,180 @@ +#!/bin/bash + +# This is a post-install script for monkeysphere, to transition an old +# (<0.23) setup to the new (>=0.23) setup. + +# You should be able to run this script after any version >= 0.23 is +# installed. This script should be well-behaved, even if it is run +# repeatedly. + +# Written by +# Jameson Rollins <jrollins@finestructure.net> +# Daniel Kahn Gillmor <dkg@fifthhorseman.net> +# +# Copyright 2009, released under the GPL, version 3 or later + +# NOTE: the reverse operation (downgrading) is not directly supported, +# and MAY LOCK YOU OUT OF YOUR SYSTEM, depending on how you have +# configured the monkeysphere! + +# any unexpected errors should cause this script to bail: +set -e + +SYSDATADIR=${MONKEYSPHERE_SYSDATADIR:-"/var/lib/monkeysphere"} + +MADATADIR="${SYSDATADIR}/authentication" +MHDATADIR="${SYSDATADIR}/host" + +STASHDIR="${SYSDATADIR}/backup-from-0.23-transition" + + +log() { + printf "$@" >&2 +} + +# FIXME: implement this function better. here, we only care about +# dots, *and* about reversing the regexification of them. +gpg_unescape_and_unregex() { + sed 's/\\x5c\././g' +} + + +is_domain_name() { + printf "%s" "$1" | egrep -q '^[[:alnum:]][[:alnum:]-.]*[[:alnum:]]$' +} + +# run the authentication setup (this is also the first chance to bail +# if 0.23 is not fully-installed, because m-a did not exist before +# 0.23) +monkeysphere-authentication setup + +# before 0.23, the old gnupg-host data directory used to contain the +# trust core and the system's ssh host key. + +if [ -d "$SYSDATADIR"/gnupg-host ] ; then + +### transfer identity certifiers, if they don't already exist in the +### current setup: + + if monkeysphere-authentication list-identity-certifiers | \ + grep -q '^[A-F0-9]{40}:$' ; then + log 'There are already certifiers in the new system!\nNot transferring any certifiers.\n' + else + # get the old host keygrip (don't know why there would be more + # than one, but we'll transfer all tsigs made by any key that + # had been given ultimate ownertrust): + for authgrip in $(GNUPGHOME="$SYSDATADIR"/gnupg-host gpg --no-permission-warning --export-ownertrust | \ + grep ':6:$' | \ + sed -r 's/^[A-F0-9]{24}([A-F0-9]{16}):6:$/\1/') ; do + + # we're assuming that old id certifiers were only added by old + # versions of m-s c+, which added certifiers by ltsigning + # entire keys. + + # so we'll walk the list of tsigs from the old host key, and + # add those keys as certifiers to the new system. + + # FIXME: if an admin has run "m-s add-id-certifier $foo" + # multiple times for the same $foo, we'll only transfer + # one of those certifications (even if later + # certifications had different parameters). + + GNUPGHOME="$SYSDATADIR"/gnupg-host gpg --no-permission-warning --fingerprint --with-colons --fixed-list-mode --check-sigs | \ + cut -f 1,2,5,8,9,10 -d: | \ + egrep '^(fpr:::::|sig:!:'"$authgrip"':[[:digit:]]+ [[:digit:]]+:)' | \ + while IFS=: read -r type validity grip trustparams trustdomain fpr ; do + case $type in + 'fpr') # this is a new key + keyfpr=$fpr + ;; + 'sig') # deal with all trust signatures, including + # regexes if present. + if [ "$keyfpr" ] ; then + trustdepth=${trustparams%% *} + trustlevel=${trustparams##* } + if [ "$trustlevel" -ge 120 ] ; then + truststring=full + elif [ "$trustlevel" -ge 60 ] ; then + truststring=marginal + else + # trust levels below marginal are ignored. + continue + fi + + finaldomain= + if [ "$trustdomain" ] ; then + # FIXME: deal with translating + # $trustdomain back to a domain. + if [ printf "%s" "$trustdomain" | egrep -q '^<\[\^>\]\+\[@\.\][^>]+>\$$' ] ; then + dpart=$(printf "%s" "$trustdomain" | sed -r 's/^<\[\^>\]\+\[@\.\]([^>]+)>\$$/\1/' | gpg_unescape_and_unregex) + if [ is_domain_name "$dpart" ]; then + finaldomain="--domain $dpart" + else + log "Does not seem to be a domain name (%s), not adding certifier\n" "$dpart" + continue + fi + else + log "Does not seem to be a standard gpg domain-based tsig (%s), not adding certifier\n" "$trustdomain" + continue + fi + fi + + CERTKEY=$(mktemp ${TMPDIR:-/tmp}/mstransition.XXXXXXXX) + log "Adding identity certifier with fingerprint %s\n" "$keyfpr" + GNUPGHOME="$SYSDATADIR"/gnupg-host gpg --no-permission-warning --export "0x$keyfpr" --export-options export-clean >"$CERTKEY" + MONKEYSPHERE_PROMPT=false monkeysphere-authentication add-identity-certifier $finaldomain --trust "$truststring" --depth "$trustdepth" "$CERTKEY" + rm -f "$CERTKEY" + # clear the fingerprint so that we don't + # make additional tsigs on it if more uids + # are present: + keyfpr= + fi + ;; + esac + done + done + fi + +### transfer host key information (if present) into the new spot + + if [ -d "${MHDATADIR}" ] ; then + log "Not transferring host key info because host directory already exists.\n" + else + if [ -s "$SYSDATADIR"/ssh_host_rsa_key ] || \ + GNUPGHOME="$SYSDATADIR"/gnupg-host gpg --no-permission-warning --with-colons --list-secret-keys | grep -q '^sec:' ; then + + # create host home + mkdir -p "${MHDATADIR}" + chmod 0700 "${MHDATADIR}" + + log "importing host key from old monkeysphere installation\n" + GNUPGHOME="$SYSDATADIR"/gnupg-host gpg --no-permission-warning --export-secret-keys | \ + GNUPGHOME="$MHDATADIR" gpg --quiet --no-tty --import + + monkeysphere-host update-gpg-pub-file + else + log "No host key found in old monkeysphere install; not importing any host key.\n" + fi + fi + + +### get rid of this old stuff, since we've transferred it all: + + mkdir -p "$STASHDIR" + chmod 0700 "$STASHDIR" + mv "${SYSDATADIR}/gnupg-host" "$STASHDIR" +fi + + +# There is nothing in the old authentication directory that we should +# need to keep around, but it is not unreasonable to transfer keys to +# the new authentication keyring. +if [ -d "${SYSDATADIR}/gnupg-authentication" ] ; then + + GNUPGHOME="${SYSDATADIR}/gnupg-authentication" gpg --no-permission-warning --export | \ + monkeysphere-authentication gpg-cmd --import + + mkdir -p "$STASHDIR" + chmod 0700 "$STASHDIR" + mv "${SYSDATADIR}/gnupg-authentication" "$STASHDIR" +fi diff --git a/src/transitions/README.txt b/src/transitions/README.txt new file mode 100644 index 0000000..7488c74 --- /dev/null +++ b/src/transitions/README.txt @@ -0,0 +1,16 @@ +This directory contains transition scripts for major changes to +monkeysphere infrastructure. + +They are expected to be run immediately after upgrading to the named +version or later. + +For example: you upgrade to from version 0.8 to version 0.15, and the +directory contains 0.6, 0.12 and 0.15, you should run 0.12 followed by +0.15. + +The scripts are supposed to be cleverly-written enough that you can +run them repeatedly, and they should only make their intended changes +once. If they do not behave that way, this is a bug. Please report +it! + + https://labs.riseup.net/code/projects/monkeysphere/ |