summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common228
-rw-r--r--src/keytrans/gnutls-helpers.c26
-rw-r--r--src/keytrans/gnutls-helpers.h13
-rw-r--r--src/keytrans/openpgp2ssh.c134
-rwxr-xr-xsrc/monkeysphere22
-rwxr-xr-xsrc/monkeysphere-server109
-rwxr-xr-xsrc/monkeysphere-ssh-proxycommand13
7 files changed, 384 insertions, 161 deletions
diff --git a/src/common b/src/common
index 4021263..ead3736 100644
--- a/src/common
+++ b/src/common
@@ -16,10 +16,6 @@
# managed directories
ETC="/etc/monkeysphere"
export ETC
-CACHE="/var/cache/monkeysphere"
-export CACHE
-ERR=0
-export ERR
########################################################################
### UTILITY FUNCTIONS
@@ -111,15 +107,13 @@ translate_ssh_variables() {
echo "$path"
}
-### CONVERTION UTILITIES
+### CONVERSION UTILITIES
# output the ssh key for a given key ID
gpg2ssh() {
local keyID
- #keyID="$1" #TMP
- # only use last 16 characters until openpgp2ssh can take all 40 #TMP
- keyID=$(echo "$1" | cut -c 25-) #TMP
+ keyID="$1"
gpg --export "$keyID" | openpgp2ssh "$keyID" 2> /dev/null
}
@@ -265,7 +259,7 @@ process_user_id() {
fi
requiredPubCapability=$(echo "$requiredCapability" | tr "[:lower:]" "[:upper:]")
- # if CHECK_KEYSERVER variable set, check the keyserver
+ # if CHECK_KEYSERVER variable set to true, check the keyserver
# for the user ID
if [ "$CHECK_KEYSERVER" = "true" ] ; then
gpg_fetch_userid "$userID"
@@ -344,9 +338,9 @@ process_user_id() {
# 0 = ok, 1 = bad
if [ "$keyOK" -a "$uidOK" -a "$lastKeyOK" ] ; then
log " * acceptable key found."
- echo 0 "$fingerprint"
+ echo "0:${fingerprint}"
else
- echo 1 "$fingerprint"
+ echo "1:${fingerprint}"
fi
;;
'sub') # sub keys
@@ -379,116 +373,199 @@ process_user_id() {
# 0 = ok, 1 = bad
if [ "$keyOK" -a "$uidOK" -a "$lastKeyOK" ] ; then
log " * acceptable key found."
- echo 0 "$fingerprint"
+ echo "0:${fingerprint}"
else
- echo 1 "$fingerprint"
+ echo "1:${fingerprint}"
fi
;;
esac
done
}
-# process hosts in the known_host file
-process_hosts_known_hosts() {
+# process a single host in the known_host file
+process_host_known_hosts() {
local host
local userID
local ok
local keyid
local tmpfile
+ local returnCode
+
+ # default return code is 1, which assumes no key was found
+ returnCode=1
+
+ host="$1"
+
+ log "processing host: $host"
+
+ userID="ssh://${host}"
+
+ for line in $(process_user_id "ssh://${host}") ; do
+ ok=$(echo "$line" | cut -d: -f1)
+ keyid=$(echo "$line" | cut -d: -f2)
+
+ sshKey=$(gpg2ssh "$keyid")
+ # remove the old host key line
+ remove_line "$KNOWN_HOSTS" "$sshKey"
+ # if key OK, add new host line
+ if [ "$ok" -eq '0' ] ; then
+ # hash if specified
+ if [ "$HASH_KNOWN_HOSTS" = 'true' ] ; then
+ # FIXME: this is really hackish cause ssh-keygen won't
+ # hash from stdin to stdout
+ tmpfile=$(mktemp)
+ ssh2known_hosts "$host" "$sshKey" > "$tmpfile"
+ ssh-keygen -H -f "$tmpfile" 2> /dev/null
+ cat "$tmpfile" >> "$KNOWN_HOSTS"
+ rm -f "$tmpfile" "${tmpfile}.old"
+ else
+ ssh2known_hosts "$host" "$sshKey" >> "$KNOWN_HOSTS"
+ fi
+ # set return code to be 0, since a key was found
+ returnCode=0
+ fi
+ return "$returnCode"
+ done
+
+ return "$returnCode"
+}
+
+# update the known_hosts file for a set of hosts listed on command
+# line
+update_known_hosts() {
+ local host
+ local returnCode
+
+ # default return code is 0, which assumes a key was found for
+ # every host. code will be set to 1 if a key is not found for at
+ # least one host
+ returnCode=0
+
+ # set the trap to remove any lockfiles on exit
+ trap "lockfile-remove $KNOWN_HOSTS" EXIT
# create a lockfile on known_hosts
lockfile-create "$KNOWN_HOSTS"
for host ; do
- log "processing host: $host"
-
- userID="ssh://${host}"
-
- process_user_id "ssh://${host}" | \
- while read -r ok keyid ; do
- sshKey=$(gpg2ssh "$keyid")
- # remove the old host key line
- remove_line "$KNOWN_HOSTS" "$sshKey"
- # if key OK, add new host line
- if [ "$ok" -eq '0' ] ; then
- # hash if specified
- if [ "$HASH_KNOWN_HOSTS" = 'true' ] ; then
- # FIXME: this is really hackish cause ssh-keygen won't
- # hash from stdin to stdout
- tmpfile=$(mktemp)
- ssh2known_hosts "$host" "$sshKey" > "$tmpfile"
- ssh-keygen -H -f "$tmpfile" 2> /dev/null
- cat "$tmpfile" >> "$KNOWN_HOSTS"
- rm -f "$tmpfile" "${tmpfile}.old"
- else
- ssh2known_hosts "$host" "$sshKey" >> "$KNOWN_HOSTS"
- fi
- fi
- done
+ # process the host, change return code if host key not found
+ process_host_known_hosts "$host" || returnCode=1
+
# touch the lockfile, for good measure.
lockfile-touch --oneshot "$KNOWN_HOSTS"
done
# remove the lockfile
lockfile-remove "$KNOWN_HOSTS"
+
+ return "$returnCode"
+}
+
+# process known_hosts file, going through line-by-line, extract each
+# host, and process with the host processing function
+process_known_hosts() {
+ local returnCode
+
+ # default return code is 0, which assumes a key was found for
+ # every host. code will be set to 1 if a key is not found for at
+ # least one host
+ returnCode=0
+
+ # take all the hosts from the known_hosts file (first field), grep
+ # out all the hashed hosts (lines starting with '|')...
+ for line in $(cat "$KNOWN_HOSTS" | meat | cut -d ' ' -f 1 | grep -v '^|.*$') ; do
+ # break up hosts into separate words
+ update_known_hosts $(echo "$line" | tr , ' ') || returnCode=1
+ done
+
+ return "$returnCode"
}
# process uids for the authorized_keys file
-process_uids_authorized_keys() {
+process_uid_authorized_keys() {
local userID
local ok
local keyid
+ local returnCode
+
+ # default return code is 1, which assumes no key was found
+ returnCode=1
+
+ userID="$1"
+
+ log "processing user ID: $userID"
+
+ for line in $(process_user_id "$userID") ; do
+ ok=$(echo "$line" | cut -d: -f1)
+ keyid=$(echo "$line" | cut -d: -f2)
+
+ sshKey=$(gpg2ssh "$keyid")
+ # remove the old host key line
+ remove_line "$AUTHORIZED_KEYS" "$sshKey"
+ # if key OK, add new host line
+ if [ "$ok" -eq '0' ] ; then
+ ssh2authorized_keys "$userID" "$sshKey" >> "$AUTHORIZED_KEYS"
+
+ # set return code to be 0, since a key was found
+ returnCode=0
+ fi
+ done
+
+ return "$returnCode"
+}
+
+# update the authorized_keys files from a list of user IDs on command
+# line
+update_authorized_keys() {
+ local userID
+ local returnCode
+
+ # default return code is 0, which assumes a key was found for
+ # every user ID. code will be set to 1 if a key is not found for
+ # at least one user ID
+ returnCode=0
+
+ # set the trap to remove any lockfiles on exit
+ trap "lockfile-remove $AUTHORIZED_KEYS" EXIT
# create a lockfile on authorized_keys
lockfile-create "$AUTHORIZED_KEYS"
for userID ; do
- log "processing user ID: $userID"
-
- process_user_id "$userID" | \
- while read -r ok keyid ; do
- sshKey=$(gpg2ssh "$keyid")
- # remove the old host key line
- remove_line "$AUTHORIZED_KEYS" "$sshKey"
- # if key OK, add new host line
- if [ "$ok" -eq '0' ] ; then
- ssh2authorized_keys "$userID" "$sshKey" >> "$AUTHORIZED_KEYS"
- fi
- done
+ # process the user ID, change return code if key not found for
+ # user ID
+ process_uid_authorized_keys "$userID" || returnCode=1
+
# touch the lockfile, for good measure.
lockfile-touch --oneshot "$AUTHORIZED_KEYS"
done
# remove the lockfile
lockfile-remove "$AUTHORIZED_KEYS"
-}
-# process known_hosts file
-# go through line-by-line, extract each host, and process with the
-# host processing function
-process_known_hosts() {
- local hosts
- local host
-
- # take all the hosts from the known_hosts file (first field),
- # grep out all the hashed hosts (lines starting with '|')...
- cat "$KNOWN_HOSTS" | meat | \
- cut -d ' ' -f 1 | grep -v '^|.*$' | \
- while IFS=, read -r -a hosts ; do
- process_hosts_known_hosts ${hosts[@]}
- done
+ return "$returnCode"
}
# process an authorized_user_ids file for authorized_keys
process_authorized_user_ids() {
local userid
+ local returnCode
+
+ # default return code is 0, and is set to 1 if a key for a user ID
+ # is not found
+ returnCode=0
authorizedUserIDs="$1"
- cat "$authorizedUserIDs" | meat | \
- while read -r userid ; do
- process_uids_authorized_keys "$userid"
+ # set the IFS to be newline for parsing the authorized_user_ids
+ # file. can't find it in BASH(1) (found it on the net), but it
+ # works.
+ IFS=$'\n'
+ for userid in $(cat "$authorizedUserIDs" | meat) ; do
+ update_authorized_keys "$userid" || returnCode=1
done
+
+ return "$returnCode"
}
# EXPERIMENTAL (unused) process userids found in authorized_keys file
@@ -498,6 +575,11 @@ process_authorized_user_ids() {
process_authorized_keys() {
local authorizedKeys
local userID
+ local returnCode
+
+ # default return code is 0, and is set to 1 if a key for a user
+ # is not found
+ returnCode=0
authorizedKeys="$1"
@@ -522,8 +604,10 @@ process_authorized_keys() {
# process the userid
log "processing userid: '$userID'"
- process_user_id "$userID" > /dev/null
+ process_user_id "$userID" > /dev/null || returnCode=1
done
+
+ return "$returnCode"
}
##################################################
diff --git a/src/keytrans/gnutls-helpers.c b/src/keytrans/gnutls-helpers.c
index 5b4c46a..7c4348d 100644
--- a/src/keytrans/gnutls-helpers.c
+++ b/src/keytrans/gnutls-helpers.c
@@ -44,11 +44,11 @@ void init_keyid(gnutls_openpgp_keyid_t keyid) {
void make_keyid_printable(printable_keyid out, gnutls_openpgp_keyid_t keyid)
{
assert(sizeof(out) >= 2*sizeof(keyid));
- hex_print_data((char*)out, (const char*)keyid, sizeof(keyid));
+ hex_print_data((char*)out, (const unsigned char*)keyid, sizeof(keyid));
}
/* you must have twice as many bytes in the out buffer as in the in buffer */
-void hex_print_data(char* out, const char* in, size_t incount)
+void hex_print_data(char* out, const unsigned char* in, size_t incount)
{
static const char hex[16] = "0123456789ABCDEF";
unsigned int inix = 0, outix = 0;
@@ -73,7 +73,6 @@ unsigned char hex2bin(unsigned char x) {
void collapse_printable_keyid(gnutls_openpgp_keyid_t out, printable_keyid in) {
unsigned int pkix = 0, outkix = 0;
-
while (pkix < sizeof(printable_keyid)) {
unsigned hi = hex2bin(in[pkix]);
unsigned lo = hex2bin(in[pkix + 1]);
@@ -92,6 +91,27 @@ void collapse_printable_keyid(gnutls_openpgp_keyid_t out, printable_keyid in) {
}
}
+unsigned int hexstring2bin(unsigned char* out, const char* in) {
+ unsigned int pkix = 0, outkix = 0;
+ int hi = 0; /* which nybble is it? */
+
+ while (in[pkix]) {
+ unsigned char z = hex2bin(in[pkix]);
+ if (z != 0xff) {
+ if (!hi) {
+ if (out) out[outkix] = (z << 4);
+ hi = 1;
+ } else {
+ if (out) out[outkix] |= z;
+ hi = 0;
+ outkix++;
+ }
+ pkix++;
+ }
+ }
+ return outkix*8 + (hi ? 4 : 0);
+}
+
int convert_string_to_keyid(gnutls_openpgp_keyid_t out, const char* str) {
printable_keyid p;
int ret;
diff --git a/src/keytrans/gnutls-helpers.h b/src/keytrans/gnutls-helpers.h
index f196456..bf54af0 100644
--- a/src/keytrans/gnutls-helpers.h
+++ b/src/keytrans/gnutls-helpers.h
@@ -49,7 +49,18 @@ int convert_string_to_keyid(gnutls_openpgp_keyid_t out, const char* str);
int convert_string_to_printable_keyid(printable_keyid out, const char* str);
/* you must have twice as many bytes in the out buffer as in the in buffer */
-void hex_print_data(char* out, const char* in, size_t incount);
+void hex_print_data(char* out, const unsigned char* in, size_t incount);
+
+/* expects a null-terminated string as in, containing an even number
+ of hexadecimal characters.
+
+ returns length in *bits* of raw data as output.
+
+ the out buffer must be at least half as long as in to hold the
+ output. if out is NULL, no output will be generated, but the
+ length will still be returned.
+*/
+unsigned int hexstring2bin(unsigned char* out, const char* in);
/* functions to get data into datum objects: */
diff --git a/src/keytrans/openpgp2ssh.c b/src/keytrans/openpgp2ssh.c
index 92bdc19..5cc6cfa 100644
--- a/src/keytrans/openpgp2ssh.c
+++ b/src/keytrans/openpgp2ssh.c
@@ -35,15 +35,16 @@
/* FIXME: keyid should be const as well */
-int convert_private_pgp_to_x509(gnutls_x509_privkey_t* output, const gnutls_openpgp_privkey_t* pgp_privkey, gnutls_openpgp_keyid_t* keyid) {
+int convert_private_pgp_to_x509(gnutls_x509_privkey_t* output, const gnutls_openpgp_privkey_t* pgp_privkey, const unsigned char* keyfpr, unsigned int fprlen) {
gnutls_datum_t m, e, d, p, q, u, g, y, x;
gnutls_pk_algorithm_t pgp_algo;
unsigned int pgp_bits;
int ret;
- gnutls_openpgp_keyid_t curkeyid;
int subkeyidx;
int subkeycount;
int found = 0;
+ unsigned char fingerprint[20];
+ size_t fingerprint_length = sizeof(fingerprint);
init_datum(&m);
init_datum(&e);
@@ -61,20 +62,27 @@ int convert_private_pgp_to_x509(gnutls_x509_privkey_t* output, const gnutls_open
return 1;
}
- if ((keyid == NULL) &&
+ if ((keyfpr == NULL) &&
(subkeycount > 0)) {
- err(0,"No keyid passed in, but there were %d keys to choose from\n", subkeycount + 1);
+ err(0,"No key identifier passed in, but there were %d keys to choose from\n", subkeycount + 1);
return 1;
}
- if (keyid != NULL) {
- ret = gnutls_openpgp_privkey_get_key_id(*pgp_privkey, curkeyid);
+ if (keyfpr != NULL) {
+ ret = gnutls_openpgp_privkey_get_fingerprint(*pgp_privkey, fingerprint, &fingerprint_length);
if (ret) {
- err(0,"Could not get keyid (error: %d)\n", ret);
+ err(0,"Could not get fingerprint (error: %d)\n", ret);
return 1;
}
+ if (fprlen > fingerprint_length) {
+ err(0, "Requested key identifier is longer than computed fingerprint\n");
+ return 1;
+ }
+ if (fingerprint_length > fprlen) {
+ err(0, "Only comparing last %d bits of key fingerprint\n", fprlen*8);
+ }
}
- if ((keyid == NULL) || (memcmp(*keyid, curkeyid, sizeof(gnutls_openpgp_keyid_t)) == 0)) {
+ if ((keyfpr == NULL) || (memcmp(fingerprint + (fingerprint_length - fprlen), keyfpr, fprlen) == 0)) {
/* we want to export the primary key: */
err(0,"exporting primary key\n");
@@ -106,12 +114,19 @@ int convert_private_pgp_to_x509(gnutls_x509_privkey_t* output, const gnutls_open
} else {
/* lets trawl through the subkeys until we find the one we want: */
for (subkeyidx = 0; (subkeyidx < subkeycount) && !found; subkeyidx++) {
- ret = gnutls_openpgp_privkey_get_subkey_id(*pgp_privkey, subkeyidx, curkeyid);
+ ret = gnutls_openpgp_privkey_get_subkey_fingerprint(*pgp_privkey, subkeyidx, fingerprint, &fingerprint_length);
if (ret) {
- err(0,"Could not get keyid of subkey with index %d (error: %d)\n", subkeyidx, ret);
+ err(0,"Could not get fingerprint of subkey with index %d (error: %d)\n", subkeyidx, ret);
return 1;
}
- if (memcmp(*keyid, curkeyid, sizeof(gnutls_openpgp_keyid_t)) == 0) {
+ if (fprlen > fingerprint_length) {
+ err(0, "Requested key identifier is longer than computed fingerprint\n");
+ return 1;
+ }
+ if (fingerprint_length > fprlen) {
+ err(1, "Only comparing last %d bits of key fingerprint\n", fprlen*8);
+ }
+ if (memcmp(fingerprint + (fingerprint_length - fprlen), keyfpr, fprlen) == 0) {
err(0,"exporting subkey index %d\n", subkeyidx);
/* FIXME: this is almost identical to the block above for the
@@ -172,8 +187,7 @@ int convert_private_pgp_to_x509(gnutls_x509_privkey_t* output, const gnutls_open
}
/* FIXME: keyid should be const also */
-int emit_public_openssh_from_pgp(const gnutls_openpgp_crt_t* pgp_crt, gnutls_openpgp_keyid_t* keyid) {
- gnutls_openpgp_keyid_t curkeyid;
+int emit_public_openssh_from_pgp(const gnutls_openpgp_crt_t* pgp_crt, const unsigned char* keyfpr, size_t fprlen) {
int ret;
int subkeyidx;
int subkeycount;
@@ -188,6 +202,9 @@ int emit_public_openssh_from_pgp(const gnutls_openpgp_crt_t* pgp_crt, gnutls_ope
algorithm name: */
char output_data[20];
+ unsigned char fingerprint[20];
+ size_t fingerprint_length = sizeof(fingerprint);
+
/* variables for the output conversion: */
int pipestatus;
int pipefd, child_pid;
@@ -208,20 +225,27 @@ int emit_public_openssh_from_pgp(const gnutls_openpgp_crt_t* pgp_crt, gnutls_ope
return 1;
}
- if ((keyid == NULL) &&
+ if ((keyfpr == NULL) &&
(subkeycount > 0)) {
- err(0,"No keyid passed in, but there were %d keys to choose from\n", subkeycount + 1);
+ err(0,"No key identifier passed in, but there were %d keys to choose from\n", subkeycount + 1);
return 1;
}
- if (keyid != NULL) {
- ret = gnutls_openpgp_crt_get_key_id(*pgp_crt, curkeyid);
+ if (keyfpr != NULL) {
+ ret = gnutls_openpgp_crt_get_fingerprint(*pgp_crt, fingerprint, &fingerprint_length);
if (ret) {
- err(0,"Could not get keyid (error: %d)\n", ret);
+ err(0,"Could not get key fingerprint (error: %d)\n", ret);
return 1;
}
+ if (fprlen > fingerprint_length) {
+ err(0, "Requested key identifier is longer than computed fingerprint\n");
+ return 1;
+ }
+ if (fingerprint_length > fprlen) {
+ err(0, "Only comparing last %d bits of key fingerprint\n", fprlen*8);
+ }
}
- if ((keyid == NULL) || (memcmp(*keyid, curkeyid, sizeof(gnutls_openpgp_keyid_t)) == 0)) {
+ if ((keyfpr == NULL) || (memcmp(fingerprint + (fingerprint_length - fprlen), keyfpr, fprlen) == 0)) {
/* we want to export the primary key: */
err(0,"exporting primary key\n");
@@ -252,12 +276,19 @@ int emit_public_openssh_from_pgp(const gnutls_openpgp_crt_t* pgp_crt, gnutls_ope
} else {
/* lets trawl through the subkeys until we find the one we want: */
for (subkeyidx = 0; (subkeyidx < subkeycount) && !found; subkeyidx++) {
- ret = gnutls_openpgp_crt_get_subkey_id(*pgp_crt, subkeyidx, curkeyid);
+ ret = gnutls_openpgp_crt_get_subkey_fingerprint(*pgp_crt, subkeyidx, fingerprint, &fingerprint_length);
if (ret) {
- err(0,"Could not get keyid of subkey with index %d (error: %d)\n", subkeyidx, ret);
+ err(0,"Could not get fingerprint of subkey with index %d (error: %d)\n", subkeyidx, ret);
return 1;
}
- if (memcmp(*keyid, curkeyid, sizeof(gnutls_openpgp_keyid_t)) == 0) {
+ if (fprlen > fingerprint_length) {
+ err(0, "Requested key identifier is longer than computed fingerprint\n");
+ return 1;
+ }
+ if (fingerprint_length > fprlen) {
+ err(1, "Only comparing last %d bits of key fingerprint\n", fprlen*8);
+ }
+ if (memcmp(fingerprint + (fingerprint_length - fprlen), keyfpr, fprlen) == 0) {
err(0,"exporting subkey index %d\n", subkeyidx);
/* FIXME: this is almost identical to the block above for the
@@ -351,7 +382,7 @@ int emit_public_openssh_from_pgp(const gnutls_openpgp_crt_t* pgp_crt, gnutls_ope
int main(int argc, char* argv[]) {
gnutls_datum_t data;
- int ret;
+ int ret = 0;
gnutls_x509_privkey_t x509_privkey;
gnutls_openpgp_privkey_t pgp_privkey;
gnutls_openpgp_crt_t pgp_crt;
@@ -359,18 +390,54 @@ int main(int argc, char* argv[]) {
char output_data[10240];
size_t ods = sizeof(output_data);
- gnutls_openpgp_keyid_t keyid;
- gnutls_openpgp_keyid_t* use_keyid;
+ unsigned char * fingerprint = NULL;
+ size_t fpr_size;
+ char * prettyfpr = NULL;
init_gnutls();
- /* figure out what keyid we should be looking for: */
- use_keyid = NULL;
+ /* figure out what key we should be looking for: */
if (argv[1] != NULL) {
- ret = convert_string_to_keyid(keyid, argv[1]);
- if (ret != 0)
- return ret;
- use_keyid = &keyid;
+ if (strlen(argv[1]) > 81) {
+ /* safety check to avoid some sort of wacky overflow situation:
+ there's no reason that the key id should be longer than twice
+ a sane fingerprint (one byte between chars, and then another
+ two at the beginning and end) */
+ err(0, "Key identifier is way too long. Please use at most 40 hex digits.\n");
+ return 1;
+ }
+
+ fpr_size = hexstring2bin(NULL, argv[1]);
+ if (fpr_size > 40*4) {
+ err(0, "Key identifier is longer than 40 hex digits\n");
+ return 1;
+ }
+ /* since fpr_size is initially in bits: */
+ if (fpr_size % 8 != 0) {
+ err(0, "Please provide an even number of hex digits for the key identifier\n");
+ return 1;
+ }
+ fpr_size /= 8;
+
+ fingerprint = malloc(sizeof(unsigned char) * fpr_size);
+ bzero(fingerprint, sizeof(unsigned char) * fpr_size);
+ hexstring2bin(fingerprint, argv[1]);
+
+ prettyfpr = malloc(sizeof(unsigned char)*fpr_size*2 + 1);
+ if (prettyfpr != NULL) {
+ hex_print_data(prettyfpr, fingerprint, fpr_size);
+ prettyfpr[sizeof(unsigned char)*fpr_size*2] = '\0';
+ err(1, "searching for key with fingerprint '%s'\n", prettyfpr);
+ free(prettyfpr);
+ }
+
+ if (fpr_size < 4) {
+ err(0, "You MUST provide at least 8 hex digits in any key identifier\n");
+ return 1;
+ }
+ if (fpr_size < 8)
+ err(0, "You should provide at least 16 hex digits in any key identifier (proceeding with %d digits anyway)\n", fpr_size*2);
+
}
@@ -397,7 +464,7 @@ int main(int argc, char* argv[]) {
return 1;
}
- ret = convert_private_pgp_to_x509(&x509_privkey, &pgp_privkey, use_keyid);
+ ret = convert_private_pgp_to_x509(&x509_privkey, &pgp_privkey, fingerprint, fpr_size);
gnutls_openpgp_privkey_deinit(pgp_privkey);
if (ret)
@@ -423,7 +490,7 @@ int main(int argc, char* argv[]) {
/* we're dealing with a public key */
err(0,"Translating public key\n");
- ret = emit_public_openssh_from_pgp(&pgp_crt, use_keyid);
+ ret = emit_public_openssh_from_pgp(&pgp_crt, fingerprint, fpr_size);
} else {
/* we have no idea what kind of key this is at all anyway! */
@@ -433,5 +500,6 @@ int main(int argc, char* argv[]) {
}
gnutls_global_deinit();
+ free(fingerprint);
return 0;
}
diff --git a/src/monkeysphere b/src/monkeysphere
index 9b315e2..d8d4667 100755
--- a/src/monkeysphere
+++ b/src/monkeysphere
@@ -24,6 +24,9 @@ DATE=$(date -u '+%FT%T')
# unset some environment variables that could screw things up
GREP_OPTIONS=
+# default return code
+ERR=0
+
########################################################################
# FUNCTIONS
########################################################################
@@ -125,15 +128,17 @@ 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"}
CHECK_KEYSERVER=${CHECK_KEYSERVER:="true"}
-REQUIRED_HOST_KEY_CAPABILITY=${REQUIRED_HOST_KEY_CAPABILITY:-"a"}
-REQUIRED_USER_KEY_CAPABILITY=${REQUIRED_USER_KEY_CAPABILITY:-"a"}
KNOWN_HOSTS=${KNOWN_HOSTS:-"${HOME}/.ssh/known_hosts"}
-AUTHORIZED_KEYS=${AUTHORIZED_KEYS:-"${HOME}/.ssh/authorized_keys"}
HASH_KNOWN_HOSTS=${HASH_KNOWN_HOSTS:-"true"}
+AUTHORIZED_KEYS=${AUTHORIZED_KEYS:-"${HOME}/.ssh/authorized_keys"}
+
+# other variables
+AUTHORIZED_USER_IDS=${AUTHORIZED_USER_IDS:-"${MS_HOME}/authorized_user_ids"}
+REQUIRED_HOST_KEY_CAPABILITY=${REQUIRED_HOST_KEY_CAPABILITY:-"a"}
+REQUIRED_USER_KEY_CAPABILITY=${REQUIRED_USER_KEY_CAPABILITY:-"a"}
export GNUPGHOME
@@ -143,7 +148,6 @@ mkdir -p -m 0700 "$GNUPGHOME"
# make sure the user monkeysphere home directory exists
mkdir -p -m 0700 "$MS_HOME"
touch "$AUTHORIZED_USER_IDS"
-touch "$AUTHORIZED_KEYS"
case $COMMAND in
'update-known_hosts'|'update-known-hosts'|'k')
@@ -156,7 +160,7 @@ case $COMMAND in
# if hosts are specified on the command line, process just
# those hosts
if [ "$1" ] ; then
- process_hosts_known_hosts "$@"
+ update_known_hosts "$@" || ERR=1
# otherwise, if no hosts are specified, process every host
# in the user's known_hosts file
@@ -165,7 +169,7 @@ case $COMMAND in
failure "known_hosts file '$KNOWN_HOSTS' is empty."
fi
log "processing known_hosts file..."
- process_known_hosts
+ process_known_hosts || ERR=1
fi
log "known_hosts file updated."
@@ -181,7 +185,7 @@ case $COMMAND in
# process authorized_user_ids file
log "processing authorized_user_ids file..."
- process_authorized_user_ids "$AUTHORIZED_USER_IDS"
+ process_authorized_user_ids "$AUTHORIZED_USER_IDS" || ERR=1
log "authorized_keys file updated."
;;
@@ -202,3 +206,5 @@ case $COMMAND in
Type '$PGRM help' for usage."
;;
esac
+
+exit "$ERR"
diff --git a/src/monkeysphere-server b/src/monkeysphere-server
index f68f391..ac7c1cb 100755
--- a/src/monkeysphere-server
+++ b/src/monkeysphere-server
@@ -11,9 +11,12 @@
########################################################################
PGRM=$(basename $0)
-SHAREDIR=${SHAREDIR:-"/usr/share/monkeysphere"}
-export SHAREDIR
-. "${SHAREDIR}/common"
+SHARE=${SHARE:-"/usr/share/monkeysphere"}
+export SHARE
+. "${SHARE}/common"
+
+VARLIB="/var/lib/monkeysphere"
+export VARLIB
# date in UTF format if needed
DATE=$(date -u '+%FT%T')
@@ -21,6 +24,9 @@ DATE=$(date -u '+%FT%T')
# unset some environment variables that could screw things up
GREP_OPTIONS=
+# default return code
+ERR=0
+
########################################################################
# FUNCTIONS
########################################################################
@@ -31,7 +37,7 @@ usage: $PGRM <subcommand> [args]
MonkeySphere server admin tool.
subcommands:
- update-users (s) [USER]... update users authorized_keys files
+ update-users (u) [USER]... update users authorized_keys files
gen-key (g) [HOSTNAME] generate gpg key for the server
show-fingerprint (f) show server's host key fingerprint
publish-key (p) publish server's host key to keyserver
@@ -46,8 +52,9 @@ gen_key() {
local hostName
hostName=${1:-$(hostname --fqdn)}
- service=${SERVICE:-"ssh"}
- userID="${service}://${hostName}"
+
+ SERVICE=${SERVICE:-"ssh"}
+ userID="${SERVICE}://${hostName}"
if gpg --list-key ="$userID" > /dev/null 2>&1 ; then
failure "Key for '$userID' already exists"
@@ -118,8 +125,8 @@ EOF
# write the key to the file
# NOTE: assumes that the primary key is the proper key to use
- (umask 077 && gpgsecret2ssh "$keyID" > "${MS_HOME}/ssh_host_rsa_key")
- log "Private SSH host key output to file: ${MS_HOME}/ssh_host_rsa_key"
+ (umask 077 && gpgsecret2ssh "$keyID" > "${VARLIB}/ssh_host_rsa_key")
+ log "Private SSH host key output to file: ${VARLIB}/ssh_host_rsa_key"
}
# gpg output key fingerprint
@@ -151,24 +158,26 @@ 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"}
+MONKEYSPHERE_USER=${MONKEYSPHERE_USER:-"monkeysphere"}
KEYSERVER=${KEYSERVER:-"subkeys.pgp.net"}
CHECK_KEYSERVER=${CHECK_KEYSERVER:="true"}
-REQUIRED_USER_KEY_CAPABILITY=${REQUIRED_USER_KEY_CAPABILITY:-"a"}
AUTHORIZED_USER_IDS=${AUTHORIZED_USER_IDS:-"%h/.config/monkeysphere/authorized_user_ids"}
-USER_CONTROLLED_AUTHORIZED_KEYS=${USER_CONTROLLED_AUTHORIZED_KEYS:-"%h/.ssh/authorized_keys"}
+RAW_AUTHORIZED_KEYS=${RAW_AUTHORIZED_KEYS:-"%h/.ssh/authorized_keys"}
-export GNUPGHOME
+# other variables
+REQUIRED_USER_KEY_CAPABILITY=${REQUIRED_USER_KEY_CAPABILITY:-"a"}
+GNUPGHOME_HOST=${GNUPGHOME_HOST:-"${VARLIB}/gnupg-host"}
+GNUPGHOME_AUTHENTICATION=${GNUPGHOME_AUTHENTICATION:-"${VARLIB}/gnupg-authentication"}
-# make sure the monkeysphere home directory exists
-mkdir -p "${MS_HOME}/authorized_user_ids"
-# make sure gpg home exists with proper permissions
+# set default GNUPGHOME, and make sure the directory exists. this is
+# true for all functions expect user authentication
+# (ie. update-users).
+GNUPGHOME="$GNUPGHOME_HOST"
+export GNUPGHOME
mkdir -p -m 0700 "$GNUPGHOME"
-# make sure the authorized_keys directory exists
-mkdir -p "${CACHE}/authorized_keys"
case $COMMAND in
- 'update-users'|'update-user'|'s')
+ 'update-users'|'update-user'|'u')
if [ "$1" ] ; then
# get users from command line
unames="$@"
@@ -177,22 +186,32 @@ case $COMMAND in
unames=$(getent passwd | cut -d: -f1)
fi
+ # set mode
+ MODE="authorized_keys"
+
+ # make sure the authorized_keys directory exists
+ mkdir -p "${VARLIB}/authorized_keys"
+
+ # set GNUPGHOME, and make sure the directory exists
+ GNUPGHOME="$GNUPGHOME_AUTHENTICATION"
+ export GNUPGHOME
+ mkdir -p -m 0700 "$GNUPGHOME"
+
# loop over users
for uname in $unames ; do
- MODE="authorized_keys"
-
# check all specified users exist
if ! getent passwd "$uname" >/dev/null ; then
error "----- unknown user '$uname' -----"
continue
fi
- # set authorized_user_ids variable,
- # translate ssh-style path variables
+ # set authorized_user_ids and raw authorized_keys variables,
+ # translating ssh-style path variables
authorizedUserIDs=$(translate_ssh_variables "$uname" "$AUTHORIZED_USER_IDS")
+ rawAuthorizedKeys=$(translate_ssh_variables "$uname" "$RAW_AUTHORIZED_KEYS")
- # skip user if authorized_user_ids file does not exist
- if [ ! -f "$authorizedUserIDs" ] ; then
+ # if neither is found, skip user
+ if [ ! -s "$authorizedUserIDs" -a ! -s "$rawAuthorizedKeys" ] ; then
continue
fi
@@ -201,30 +220,42 @@ case $COMMAND in
# temporary authorized_keys file
AUTHORIZED_KEYS=$(mktemp)
- # skip if the user's authorized_user_ids file is empty
- if [ ! -s "$authorizedUserIDs" ] ; then
- log "authorized_user_ids file '$authorizedUserIDs' is empty."
- continue
- fi
+ # trap to delete file on exit
+ trap "rm -f $AUTHORIZE_KEYS" EXIT
# process authorized_user_ids file
- log "processing authorized_user_ids file..."
- process_authorized_user_ids "$authorizedUserIDs"
+ if [ -s "$authorizedUserIDs" ] ; then
+ log "processing authorized_user_ids file..."
+ process_authorized_user_ids "$authorizedUserIDs"
+ fi
# add user-controlled authorized_keys file path if specified
- if [ "$USER_CONTROLLED_AUTHORIZED_KEYS" != '-' ] ; then
- userAuthorizedKeys=$(translate_ssh_variables "$uname" "$USER_CONTROLLED_AUTHORIZED_KEYS")
- if [ -f "$userAuthorizedKeys" ] ; then
- log -n "adding user's authorized_keys file... "
- cat "$userAuthorizedKeys" >> "$AUTHORIZED_KEYS"
+ if [ "$RAW_AUTHORIZED_KEYS" != '-' ] ; then
+ if [ -s "$rawAuthorizedKeys" ] ; then
+ log -n "adding raw authorized_keys file... "
+ cat "$rawAuthorizedKeys" >> "$AUTHORIZED_KEYS"
loge "done."
fi
fi
- # move the temp authorized_keys file into place
- mv -f "$AUTHORIZED_KEYS" "${CACHE}/authorized_keys/${uname}"
+ # if the resulting authorized_keys file is not empty, move
+ # the temp authorized_keys file into place
+ if [ -s "$AUTHORIZED_KEYS" ] ; then
+ # openssh appears to check the contents of the
+ # authorized_keys file as the user in question, so the
+ # file must be readable by that user at least.
+ # FIXME: is there a better way to do this?
+ chgrp $(getent passwd "$uname" | cut -f4 -d:) "$AUTHORIZED_KEYS"
+ chmod g+r "$AUTHORIZED_KEYS"
+
+ mv -f "$AUTHORIZED_KEYS" "${VARLIB}/authorized_keys/${uname}"
- log "authorized_keys file updated."
+ log "authorized_keys file updated."
+
+ # else destroy it
+ else
+ rm -f "$AUTHORIZED_KEYS"
+ fi
done
;;
diff --git a/src/monkeysphere-ssh-proxycommand b/src/monkeysphere-ssh-proxycommand
index f4d4b0d..6dcb723 100755
--- a/src/monkeysphere-ssh-proxycommand
+++ b/src/monkeysphere-ssh-proxycommand
@@ -31,6 +31,8 @@ fi
HOST="$1"
PORT="$2"
+MS_HOME=${MS_HOME:-"${HOME}/.config/monkeysphere"}
+
if [ -z "$HOST" ] ; then
log "host must be specified."
usage
@@ -58,11 +60,12 @@ else
# FIXME: this only works for default known_hosts location
hostKey=$(ssh-keygen -F "$HOST")
if [ "$hostKey" ] ; then
- # if the check keyserver variable is NOT set to true...
- if [ "$CHECK_KEYSERVER" != 'true' ] ; then
- # schedule a keyserver check for host at a later time
- echo "monkeysphere update-known_hosts $HOST" | at noon
- fi
+ # do not check the keyserver
+ # 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"
+
# if the host key is not found in the known_hosts file...
else
# check the keyserver