diff options
author | Jameson Graef Rollins <jrollins@phys.columbia.edu> | 2008-06-10 17:17:51 -0400 |
---|---|---|
committer | Jameson Graef Rollins <jrollins@phys.columbia.edu> | 2008-06-10 17:17:51 -0400 |
commit | 4793624c65673268128fb0146cd9bd1b3cfeb6c4 (patch) | |
tree | ccc0f83373ac7e47dd71202ee4376e952652c675 | |
parent | 6c335e70360c7502a2205d21e9f96d4bf2679cbd (diff) |
New client/server components:
- broke out all common functions to "common" file
- put all client commands into "monkeysphere" script
- put all server commands into "monkeysphere-server" script
- moved all code into src directory to clean things up a bit
- this effectively makes obsolete rhesus and howler
- added proposed monkeysphere-ssh-proxycommand script that can be
called to update known_hosts from ssh ProxyCommand
- updated monkeysphere.conf to work as global client config
- added monkeysphere-server.conf for server config
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | langur/README | 4 | ||||
-rw-r--r-- | monkeysphere-server.conf | 23 | ||||
-rw-r--r-- | monkeysphere.conf | 37 | ||||
-rwxr-xr-x | src/common | 353 | ||||
-rw-r--r-- | src/gpg2ssh/Makefile (renamed from gpg2ssh/Makefile) | 0 | ||||
-rw-r--r-- | src/gpg2ssh/gnutls-helpers.c (renamed from gpg2ssh/gnutls-helpers.c) | 0 | ||||
-rw-r--r-- | src/gpg2ssh/gnutls-helpers.h (renamed from gpg2ssh/gnutls-helpers.h) | 0 | ||||
-rw-r--r-- | src/gpg2ssh/gpg2ssh.c (renamed from gpg2ssh/gpg2ssh.c) | 0 | ||||
-rw-r--r-- | src/gpg2ssh/main.c (renamed from gpg2ssh/main.c) | 0 | ||||
-rw-r--r-- | src/gpg2ssh/ssh2gpg.c (renamed from gpg2ssh/ssh2gpg.c) | 0 | ||||
-rwxr-xr-x | src/howler/howler (renamed from howler/howler) | 0 | ||||
-rwxr-xr-x | src/monkeysphere | 154 | ||||
-rwxr-xr-x | src/monkeysphere-server | 219 | ||||
-rwxr-xr-x | src/monkeysphere-ssh-proxycommand | 16 | ||||
-rw-r--r-- | src/rhesus/README (renamed from rhesus/README) | 0 | ||||
-rwxr-xr-x | src/rhesus/rhesus (renamed from rhesus/rhesus) | 0 |
17 files changed, 784 insertions, 25 deletions
@@ -1,5 +1,2 @@ *~ *.[ao] -monkeysphere -gpg2ssh -ssh2gpg diff --git a/langur/README b/langur/README deleted file mode 100644 index ee60701..0000000 --- a/langur/README +++ /dev/null @@ -1,4 +0,0 @@ -Langur is the policy editor/viewer for the monkeysphere. - -Its goals are to provide a human-friendly interface to the simple and -intelligible policies monkeysphere supports. diff --git a/monkeysphere-server.conf b/monkeysphere-server.conf new file mode 100644 index 0000000..bed5c09 --- /dev/null +++ b/monkeysphere-server.conf @@ -0,0 +1,23 @@ +# MonkeySphere server configuration file. + +# GPG home directory for server +#GNUPGHOME=/etc/monkeysphere/gnupg + +# GPG keyserver to search for keys +#KEYSERVER=subkeys.pgp.net + +# Required key capabilities +# Must be quoted, lowercase, space-seperated list of the following: +# e = encrypt +# s = sign +# c = certify +# a = authentication +#REQUIRED_KEY_CAPABILITY="e a" + +# Whether to add user controlled authorized_keys file to +# monkeysphere-generated authorized_keys file. Should be path to file +# where '%h' will be substituted for the user's home directory. +#USER_CONTROLLED_AUTHORIZED_KEYS=%h/.ssh/authorized_keys + +# where to cache user authorized_keys lines +#STAGING_AREA=/var/lib/monkeysphere/stage diff --git a/monkeysphere.conf b/monkeysphere.conf index 6401203..385165a 100644 --- a/monkeysphere.conf +++ b/monkeysphere.conf @@ -1,30 +1,31 @@ -# monkeysphere system configuration file +# MonkeySphere system-wide client configuration file. -# This is particular configuration is meant to be sourced by the -# rhesus shell script when run in administrative mode to maintain -# authorized_keys files for users. +# authorized_user_ids file +#AUTHORIZED_USER_IDS=~/.config/monkeysphere/authorized_user_ids -AUTHORIZED_USER_IDS=/etc/monkeysphere/authorized_user_ids/"$USER" +# GPG home directory +#GNUPGHOME=~/.gnupg -STAGING_AREA=/var/lib/monkeysphere/stage/"$USER" +# GPG keyserver to search for keys +#KEYSERVER=subkeys.pgp.net -# gpg home directory for server -GNUPGHOME=/etc/monkeysphere/gnupg - -# gpg keyserver to search for keys -KEYSERVER=subkeys.pgp.net - -# required capabilities of keys -# must be quoted, lowercase, space-seperated list of the following: +# Required key capabilities +# Must be quoted, lowercase, space-seperated list of the following: # e = encrypt # s = sign # c = certify # a = authentication -REQUIRED_KEY_CAPABILITY="e a" +#REQUIRED_KEY_CAPABILITY="e a" # Path to user-controlled authorized_keys file to add to # Monkeysphere-generated authorized_keys file. If empty, then no -# user-controlled file will be added. To specify the user's home -# directory, use the string "~${USER}" -USER_CONTROLLED_AUTHORIZED_KEYS="~${USER}/.ssh/authorized_keys" +# user-controlled file will be added. +#USER_CONTROLLED_AUTHORIZED_KEYS=~/.ssh/authorized_keys + +# User known_hosts file +#USER_KNOWN_HOSTS=~/.ssh/known_hosts + +# Whether or not to hash the generated known_hosts lines +# (empty mean "no"). +#HASH_KNOWN_HOSTS= diff --git a/src/common b/src/common new file mode 100755 index 0000000..8643080 --- /dev/null +++ b/src/common @@ -0,0 +1,353 @@ +# -*-shell-script-*- + +# Shared bash functions for the monkeysphere +# +# Written by +# Jameson Rollins <jrollins@fifthhorseman.net> +# +# Copyright 2008, 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 + +######################################################################## +# managed directories +ETC="/etc/monkeysphere" +export ETC +LIB="/var/lib/monkeysphere" +export LIB +######################################################################## + +failure() { + echo "$1" >&2 + exit ${2:-'1'} +} + +# write output to stdout +log() { + echo -n "ms: " + echo "$@" +} + +# write output to stderr +loge() { + echo -n "ms: " 1>&2 + echo "$@" 1>&2 +} + +# cut out all comments(#) and blank lines from standard input +meat() { + grep -v -e "^[[:space:]]*#" -e '^$' +} + +# cut a specified line from standard input +cutline() { + head --line="$1" | tail -1 +} + +# retrieve all keys with given user id from keyserver +# FIXME: need to figure out how to retrieve all matching keys +# (not just first 5) +gpg_fetch_keys() { + local id + id="$1" + echo 1,2,3,4,5 | \ + gpg --quiet --batch --command-fd 0 --with-colons \ + --keyserver "$KEYSERVER" \ + --search ="$id" >/dev/null 2>&1 +} + +# check that characters are in a string (in an AND fashion). +# used for checking key capability +# check_capability capability a [b...] +check_capability() { + local capability + local capcheck + + capability="$1" + shift 1 + + for capcheck ; do + if echo "$capability" | grep -q -v "$capcheck" ; then + return 1 + fi + done + return 0 +} + +# convert escaped characters from gpg output back into original +# character +# FIXME: undo all escape character translation in with-colons gpg output +unescape() { + echo "$1" | sed 's/\\x3a/:/' +} + +# stand in until we get dkg's gpg2ssh program +gpg2ssh_tmp() { + local keyID + local userID + local host + + keyID="$2" + userID="$3" + + if [ "$mode" = 'authorized_keys' ] ; then + gpgkey2ssh "$keyID" | sed -e "s/COMMENT/${userID}/" + + # NOTE: it seems that ssh-keygen -R removes all comment fields from + # all lines in the known_hosts file. why? + # NOTE: just in case, the COMMENT can be matched with the + # following regexp: + # '^MonkeySphere[[:digit:]]{4}(-[[:digit:]]{2}){2}T[[:digit:]]{2}(:[[:digit:]]{2}){2}$' + elif [ "$MODE" = 'known_hosts' ] ; then + host=$(echo "$userID" | sed -e "s|ssh://||") + echo -n "$host "; gpgkey2ssh "$keyID" | sed -e "s/COMMENT/MonkeySphere${DATE}/" + fi +} + +# userid and key policy checking +# the following checks policy on the returned keys +# - checks that full key has appropriate valididy (u|f) +# - checks key has specified capability (REQUIRED_KEY_CAPABILITY) +# - checks that particular desired user id has appropriate validity +# see /usr/share/doc/gnupg/DETAILS.gz +# expects global variable: "MODE" +process_user_id() { + local userID + local cacheDir + local requiredPubCapability + local gpgOut + local line + local type + local validity + local keyid + local uidfpr + local capability + local keyOK + local pubKeyID + local uidOK + local keyIDs + local userIDHash + local keyID + + userID="$1" + cacheDir="$2" + + requiredPubCapability=$(echo "$REQUIRED_KEY_CAPABILITY" | tr "[:lower:]" "[:upper:]") + + # fetch keys from keyserver, return 1 if none found + gpg_fetch_keys "$userID" || return 1 + + # output gpg info for (exact) userid and store + gpgOut=$(gpg --fixed-list-mode --list-key --with-colons \ + ="$userID" 2> /dev/null) + + # return 1 if there only "tru" lines are output from gpg + if [ -z "$(echo "$gpgOut" | grep -v '^tru:')" ] ; then + loge " key not found." + return 1 + fi + + # loop over all lines in the gpg output and process. + # need to do it this way (as opposed to "while read...") so that + # variables set in loop will be visible outside of loop + for line in $(seq 1 $(echo "$gpgOut" | wc -l)) ; do + + # read the contents of the line + type=$(echo "$gpgOut" | cutline "$line" | cut -d: -f1) + validity=$(echo "$gpgOut" | cutline "$line" | cut -d: -f2) + keyid=$(echo "$gpgOut" | cutline "$line" | cut -d: -f5) + uidfpr=$(echo "$gpgOut" | cutline "$line" | cut -d: -f10) + capability=$(echo "$gpgOut" | cutline "$line" | cut -d: -f12) + + # process based on record type + case $type in + 'pub') # primary keys + # new key, wipe the slate + keyOK= + pubKeyID= + uidOK= + keyIDs= + + pubKeyID="$keyid" + + # check primary key validity + if [ "$validity" != 'u' -a "$validity" != 'f' ] ; then + loge " unacceptable primary key validity ($validity)." + continue + fi + # check capability is not Disabled... + if check_capability "$capability" 'D' ; then + loge " key disabled." + continue + fi + # check overall key capability + # must be Encryption and Authentication + if ! check_capability "$capability" $requiredPubCapability ; then + loge " unacceptable primary key capability ($capability)." + continue + fi + + # mark if primary key is acceptable + keyOK=true + + # add primary key ID to key list if it has required capability + if check_capability "$capability" $REQUIRED_KEY_CAPABILITY ; then + keyIDs[${#keyIDs[*]}]="$keyid" + fi + ;; + 'uid') # user ids + # check key ok and we have key fingerprint + if [ -z "$keyOK" ] ; then + continue + fi + # check key validity + if [ "$validity" != 'u' -a "$validity" != 'f' ] ; then + continue + fi + # check the uid matches + if [ "$(unescape "$uidfpr")" != "$userID" ] ; then + continue + fi + + # mark if uid acceptable + uidOK=true + ;; + 'sub') # sub keys + # add sub key ID to key list if it has required capability + if check_capability "$capability" $REQUIRED_KEY_CAPABILITY ; then + keyIDs[${#keyIDs[*]}]="$keyid" + fi + ;; + esac + done + + # hash userid for cache file name + userIDHash=$(echo "$userID" | sha1sum | awk '{ print $1 }') + + # touch/clear key cache file + # (will be left empty if there are noacceptable keys) + > "$cacheDir"/"$userIDHash"."$pubKeyID" + + # for each acceptable key, write an ssh key line to the + # key cache file + if [ "$keyOK" -a "$uidOK" -a "${keyIDs[*]}" ] ; then + for keyID in ${keyIDs[@]} ; do + loge " acceptable key/uid found." + + # export the key with gpg2ssh + # FIXME: needs to apply extra options for authorized_keys + # lines if specified + gpg2ssh_tmp "$keyID" "$userID" >> "$cacheDir"/"$userIDHash"."$pubKeyID" + + # hash the cache file if specified + if [ "$MODE" = 'known_hosts' -a "$HASH_KNOWN_HOSTS" ] ; then + ssh-keygen -H -f "$cacheDir"/"$userIDHash"."$pubKeyID" > /dev/null 2>&1 + rm "$cacheDir"/"$userIDHash"."$pubKeyID".old + fi + done + fi + + # echo the path to the key cache file + echo "$cacheDir"/"$userIDHash"."$pubKeyID" +} + +# process a host for addition to a known_host file +process_host() { + local host + local cacheDir + local hostKeyCachePath + + host="$1" + cacheDir="$2" + + log "processing host: '$host'" + + hostKeyCachePath=$(process_user_id "ssh://${host}" "$cacheDir") + if [ $? = 0 ] ; then + ssh-keygen -R "$host" -f "$USER_KNOWN_HOSTS" + cat "$hostKeyCachePath" >> "$USER_KNOWN_HOSTS" + fi +} + +# process known_hosts file +# go through line-by-line, extract each host, and process with the +# host processing function +process_known_hosts() { + local knownHosts + local cacheDir + local hosts + local host + + knownHosts="$1" + cacheDir="$2" + + # take all the hosts from the known_hosts file (first field), + # grep out all the hashed hosts (lines starting with '|') + cut -d ' ' -f 1 "$knownHosts" | \ + grep -v '^|.*$' | \ + while IFS=, read -r -a hosts ; do + # process each host + for host in ${hosts[*]} ; do + process_host "$host" "$cacheDir" + done + done +} + +# process authorized_keys file +# go through line-by-line, extract monkeysphere userids from comment +# fields, and process each userid +process_authorized_keys() { + local authorizedKeys + local cacheDir + local userID + + authorizedKeys="$1" + cacheDir="$2" + + # take all the monkeysphere userids from the authorized_keys file + # comment field (third field) that starts with "MonkeySphere uid:" + # FIXME: needs to handle authorized_keys options (field 0) + cat "$authorizedKeys" | \ + while read -r options keytype key comment ; do + # if the comment field is empty, assume the third field was + # the comment + if [ -z "$comment" ] ; then + comment="$key" + fi + if ! echo "$comment" | grep '^MonkeySphere userID:.*$' ; then + continue + fi + userID=$(echo "$comment" | sed -e "/^MonkeySphere userID://") + if [ -z "$userID" ] ; then + continue + fi + # process the userid + log "processing userid: '$userID'" + process_user_id "$userID" "$cacheDir" > /dev/null + done +} + +# process an authorized_*_ids file +# go through line-by-line, extract each userid, and process +process_authorized_ids() { + local authorizedIDs + local cacheDir + local userID + + authorizedIDs="$1" + cacheDir="$2" + + # clean out keys file and remake keys directory + rm -rf "$cacheDir" + mkdir -p "$cacheDir" + + # loop through all user ids in file + # FIXME: needs to handle authorized_keys options + cat "$authorizedIDs" | meat | \ + while read -r userID ; do + # process the userid + log "processing userid: '$userID'" + process_user_id "$userID" "$cacheDir" > /dev/null + done +} diff --git a/gpg2ssh/Makefile b/src/gpg2ssh/Makefile index a0b7241..a0b7241 100644 --- a/gpg2ssh/Makefile +++ b/src/gpg2ssh/Makefile diff --git a/gpg2ssh/gnutls-helpers.c b/src/gpg2ssh/gnutls-helpers.c index 6eae29e..6eae29e 100644 --- a/gpg2ssh/gnutls-helpers.c +++ b/src/gpg2ssh/gnutls-helpers.c diff --git a/gpg2ssh/gnutls-helpers.h b/src/gpg2ssh/gnutls-helpers.h index 9ea22a3..9ea22a3 100644 --- a/gpg2ssh/gnutls-helpers.h +++ b/src/gpg2ssh/gnutls-helpers.h diff --git a/gpg2ssh/gpg2ssh.c b/src/gpg2ssh/gpg2ssh.c index c99f03f..c99f03f 100644 --- a/gpg2ssh/gpg2ssh.c +++ b/src/gpg2ssh/gpg2ssh.c diff --git a/gpg2ssh/main.c b/src/gpg2ssh/main.c index d6bac68..d6bac68 100644 --- a/gpg2ssh/main.c +++ b/src/gpg2ssh/main.c diff --git a/gpg2ssh/ssh2gpg.c b/src/gpg2ssh/ssh2gpg.c index b14a540..b14a540 100644 --- a/gpg2ssh/ssh2gpg.c +++ b/src/gpg2ssh/ssh2gpg.c diff --git a/howler/howler b/src/howler/howler index 0b67c02..0b67c02 100755 --- a/howler/howler +++ b/src/howler/howler diff --git a/src/monkeysphere b/src/monkeysphere new file mode 100755 index 0000000..f279d86 --- /dev/null +++ b/src/monkeysphere @@ -0,0 +1,154 @@ +#!/bin/sh + +######################################################################## +PGRM=$(basename $0) + +SHAREDIR=${SHAREDIR:-"/usr/share/monkeysphere"} +export SHAREDIR +. "${SHAREDIR}/common" + +GLOBAL_CONFIG=${GLOBAL_CONFIG:-"${ETC}"/monkeysphere.conf} +[ -r "$GLOBAL_CONFIG" ] && . "$GLOBAL_CONFIG" + +# date in UTF format if needed +DATE=$(date -u '+%FT%T') + +# unset some environment variables that could screw things up +GREP_OPTIONS= + +######################################################################## +# FUNCTIONS +######################################################################## + +usage() { +cat <<EOF +usage: $PGRM <subcommand> [args] +Monkeysphere client tool. + +subcommands: + update-known-hosts (k) [HOST]... update known_hosts file + update-authorized-keys (a) update authorized_keys file + update-userid (u) [USERID]... add/update userid to + authorized_user_ids + help (h,?) this help + +EOF +} + +######################################################################## +# MAIN +######################################################################## + +COMMAND="$1" +[ "$COMMAND" ] || failure "Type '$PGRM help' for usage." +shift + +# set ms home directory +MS_HOME=${MS_HOME:-"$HOME"/.config/monkeysphere} + +# load configuration file +MS_CONF=${MS_CONF:-"$MS_HOME"/monkeysphere.conf} +[ -e "$MS_CONF" ] && . "$MS_CONF" + +# set empty config variable with defaults +AUTHORIZED_USER_IDS=${AUTHORIZED_USER_IDS:-"$MS_HOME"/authorized_user_ids} +GNUPGHOME=${GNUPGHOME:-"$HOME"/.gnupg} +KEYSERVER=${KEYSERVER:-subkeys.pgp.net} +REQUIRED_KEY_CAPABILITY=${REQUIRED_KEY_CAPABILITY:-"e a"} +USER_CONTROLLED_AUTHORIZED_KEYS=${USER_CONTROLLED_AUTHORIZED_KEYS:-%h/.ssh/authorized_keys} +USER_KNOWN_HOSTS=${USER_KNOWN_HOSTS:-"$HOME"/.ssh/known_hosts} +HASH_KNOWN_HOSTS=${HASH_KNOWN_HOSTS:-} + +export GNUPGHOME + +# stagging locations +hostKeysCacheDir="$MS_HOME"/host_keys +userKeysCacheDir="$MS_HOME"/user_keys +msAuthorizedKeys="$MS_HOME"/authorized_keys + +# make sure gpg home exists with proper permissions +mkdir -p -m 0700 "$GNUPGHOME" + +case $COMMAND in + 'update-known-hosts'|'k') + MODE='known_hosts' + + # touch the known_hosts file to make sure it exists + touch "$USER_KNOWN_HOSTS" + + # if hosts are specified on the command line, process just + # those hosts + if [ "$1" ] ; then + for host ; do + process_host "$host" "$hostKeysCacheDir" + done + + # otherwise, if no hosts are specified, process the user + # known_hosts file + else + if [ ! -s "$USER_KNOWN_HOSTS" ] ; then + failure "known_hosts file '$USER_KNOWN_HOSTS' is empty." + fi + log "processing known_hosts file..." + process_known_hosts "$USER_KNOWN_HOSTS" "$hostKeysCacheDir" + fi + ;; + + 'update-authorized-keys'|'a') + MODE='authorized_keys' + + log "processing authorized_user_ids file..." + + # make sure authorized_user_ids file exists + if [ ! -s "$AUTHORIZED_USER_IDS" ] ; then + log "authorized_user_ids file is empty or does not exist." + exit + fi + + process_authorized_ids "$AUTHORIZED_USER_IDS" "$userKeysCacheDir" + + # write output key file + log "writing monkeysphere authorized_keys file... " + touch "$msAuthorizedKeys" + if [ "$(ls "$userKeysCacheDir")" ] ; then + log -n "adding gpg keys... " + cat "$userKeysCacheDir"/* > "$msAuthorizedKeys" + echo "done." + else + log "no gpg keys to add." + fi + if [ "$USER_CONTROLLED_AUTHORIZED_KEYS" ] ; then + userAuthorizedKeys=${USER_CONTROLLED_AUTHORIZED_KEYS/\%h/"$HOME"} + if [ -s "$userAuthorizedKeys" ] ; then + log -n "adding user authorized_keys file... " + cat "$userAuthorizedKeys" >> "$msAuthorizedKeys" + echo "done." + fi + fi + log "monkeysphere authorized_keys file generated:" + log "$msAuthorizedKeys" + ;; + + 'update-userid'|'u') + if [ -z "$1" ] ; then + failure "you must specify at least one userid." + fi + for userID ; do + if ! grep -q "^${userID}\$" "$AUTHORIZED_USER_IDS" ; then + log "userid '$userID' not in authorized_user_ids file." + continue + fi + log "processing user id: '$userID'" + process_user_id "$userID" "$userKeysCacheDir" > /dev/null + done + ;; + + 'help'|'h'|'?') + usage + ;; + + *) + failure "Unknown command: '$COMMAND' +Type 'cereal-admin help' for usage." + ;; +esac diff --git a/src/monkeysphere-server b/src/monkeysphere-server new file mode 100755 index 0000000..f1b4892 --- /dev/null +++ b/src/monkeysphere-server @@ -0,0 +1,219 @@ +#!/bin/sh + +######################################################################## +PGRM=$(basename $0) + +SHAREDIR=${SHAREDIR:-"/usr/share/monkeysphere"} +export SHAREDIR +. "${SHAREDIR}/common" + +# date in UTF format if needed +DATE=$(date -u '+%FT%T') + +# unset some environment variables that could screw things up +GREP_OPTIONS= + +######################################################################## +# FUNCTIONS +######################################################################## + +usage() { +cat <<EOF +usage: $PGRM <subcommand> [args] +Monkeysphere server admin tool. + +subcommands: + update-users (s) [USER]... update authorized_keys file + gen-key (g) generate gpg key for the host + publish-key (p) publish host gpg to keyserver + trust-key (t) KEYID [KEYID]... mark keyid as trusted + update-user-userid (u) USER UID [UID]... add/update userid for user + help (h,?) this help + +EOF +} + +# generate server gpg key +gen_key() { + KEY_TYPE=${KEY_TYPE:-RSA} + KEY_LENGTH=${KEY_LENGTH:-2048} + KEY_USAGE=${KEY_USAGE:-encrypt,auth} + SERVICE=${SERVICE:-ssh} + HOSTNAME_FQDN=${HOSTNAME_FQDN:-$(hostname -f)} + + USERID=${USERID:-"$SERVICE"://"$HOSTNAME_FQDN"} + + echo "key parameters:" + cat <<EOF +Key-Type: $KEY_TYPE +Key-Length: $KEY_LENGTH +Key-Usage: $KEY_USAGE +Name-Real: $USERID +EOF + + read -p "generate key? [Y|n]: " OK; OK=${OK:=Y} + if [ ${OK/y/Y} != 'Y' ] ; then + failure "aborting." + fi + + if gpg --list-key ="$USERID" > /dev/null 2>&1 ; then + failure "key for '$USERID' already exists" + fi + + echo "generating server key..." + gpg --batch --gen-key <<EOF +Key-Type: $KEY_TYPE +Key-Length: $KEY_LENGTH +Key-Usage: $KEY_USAGE +Name-Real: $USERID +%commit +EOF +} + +# publish server key to keyserver +publish_key() { + read -p "publish key to $KEYSERVER? [Y|n]: " OK; OK=${OK:=Y} + if [ ${OK/y/Y} != 'Y' ] ; then + failure "aborting." + fi + + keyID=$(gpg --list-key --with-colons ="$USERID" 2> /dev/null | grep '^pub:' | cut -d: -f5) + + # dummy command so as not to publish fakes keys during testing + # eventually: + #gpg --send-keys --keyserver "$KEYSERVER" "$keyID" + echo "gpg --send-keys --keyserver $KEYSERVER $keyID" +} + +# trust key +trust_key() { + for keyID ; do + # get the key from the key server + gpg --keyserver "$KEYSERVER" --recv-key "$keyID" || failure "could not retrieve key '$keyID'" + + # edit the key to change trust + # FIXME: need to figure out how to automate this, + # in a batch mode or something. + gpg --edit-key "$keyID" + done +} + +######################################################################## +# MAIN +######################################################################## + +COMMAND="$1" +[ "$COMMAND" ] || failure "Type '$PGRM help' for usage." +shift + +# set ms home directory +MS_HOME=${MS_HOME:-"$ETC"} + +# load configuration file +MS_CONF=${MS_CONF:-"$MS_HOME"/monkeysphere-server.conf} +[ -e "$MS_CONF" ] && . "$MS_CONF" + +# set empty config variable with defaults +GNUPGHOME=${GNUPGHOME:-"$MS_HOME"/gnupg} +KEYSERVER=${KEYSERVER:-subkeys.pgp.net} +REQUIRED_KEY_CAPABILITY=${REQUIRED_KEY_CAPABILITY:-"e a"} +USER_CONTROLLED_AUTHORIZED_KEYS=${USER_CONTROLLED_AUTHORIZED_KEYS:-%h/.ssh/authorized_keys} +STAGING_AREA=${STAGING_AREA:-"$LIB"/stage} + +export GNUPGHOME + +# make sure gpg home exists with proper permissions +mkdir -p -m 0700 "$GNUPGHOME" + +case $COMMAND in + 'update-users'|'s') + if [ "$1" ] ; then + unames="$@" + else + unames=$(ls -1 "$MS_HOME"/authorized_user_ids) + fi + + for uname in $unames ; do + MODE="authorized_keys" + authorizedUserIDs="$MS_HOME"/authorized_user_ids/"$uname" + cacheDir="$STAGING_AREA"/"$uname"/user_keys + msAuthorizedKeys="$STAGING_AREA"/"$uname"/authorized_keys + + # make sure authorized_user_ids file exists + if [ ! -s "$authorizedUserIDs" ] ; then + log "authorized_user_ids file for '$uname' is empty or does not exist." + continue + fi + + log "processing authorized_keys for user '$uname'..." + + process_authorized_ids "$authorizedUserIDs" "$cacheDir" + + # write output key file + log "writing monkeysphere authorized_keys file... " + touch "$msAuthorizedKeys" + if [ "$(ls "$cacheDir")" ] ; then + log -n "adding gpg keys... " + cat "$cacheDir"/* > "$msAuthorizedKeys" + echo "done." + else + log "no gpg keys to add." + fi + if [ "$USER_CONTROLLED_AUTHORIZED_KEYS" ] ; then + userHome=$(getent passwd "$uname" | cut -d: -f6) + userAuthorizedKeys=${USER_CONTROLLED_AUTHORIZED_KEYS/\%h/"$userHome"} + if [ -s "$userAuthorizedKeys" ] ; then + log -n "adding user authorized_keys file... " + cat "$userAuthorizedKeys" >> "$msAuthorizedKeys" + echo "done." + fi + fi + log "monkeysphere authorized_keys file generated:" + log "$msAuthorizedKeys" + done + ;; + + 'gen-key'|'g') + gen_key + ;; + + 'publish-key'|'p') + publish_key + ;; + + 'trust-key'|'t') + if [ -z "$1" ] ; then + failure "you must specify at least one key to trust." + fi + trust_key "$@" + ;; + + 'update-user-userid'|'u') + uname="$1" + shift + if [ -z "$uname" ] ; then + failure "you must specify user." + fi + if [ -z "$1" ] ; then + failure "you must specify at least one userid." + fi + for userID ; do + AUTHORIZED_USER_IDS="$MS_HOME"/authorized_user_ids/"$uname" + if ! grep -q "^${userID}\$" "$AUTHORIZED_USER_IDS" ; then + log "userid '$userID' not in authorized_user_ids file." + continue + fi + log "processing user id: '$userID'" + process_user_id "$userID" "$userKeysCacheDir" > /dev/null + done + ;; + + 'help'|'h'|'?') + usage + ;; + + *) + failure "Unknown command: '$COMMAND' +Type 'cereal-admin help' for usage." + ;; +esac diff --git a/src/monkeysphere-ssh-proxycommand b/src/monkeysphere-ssh-proxycommand new file mode 100755 index 0000000..1724966 --- /dev/null +++ b/src/monkeysphere-ssh-proxycommand @@ -0,0 +1,16 @@ +#!/bin/sh -e + +# MonkeySphere ssh ProxyCommand hook +# Proxy command script to initiate a monkeysphere known_hosts update +# before an ssh connection to host is established. +# Can be added to ~/.ssh/config as follows: +# ProxyCommand monkeysphere-ssh-proxycommand %h %p + +HOST="$1" +PORT="$2" + +# update the known_hosts file for the host +monkeysphere update-known-hosts "$HOST" + +# make a netcat connection to host for the ssh connection +exec nc "$HOST" "$PORT" diff --git a/rhesus/README b/src/rhesus/README index 4d383d5..4d383d5 100644 --- a/rhesus/README +++ b/src/rhesus/README diff --git a/rhesus/rhesus b/src/rhesus/rhesus index f607f0b..f607f0b 100755 --- a/rhesus/rhesus +++ b/src/rhesus/rhesus |