#!/bin/sh # # ssh-import-id - authorize a user by fetching their key # from a public SSH keyserver; Launchpad.net # by default # # Copyright (C) 2010 Canonical Ltd. # # Authors: Dustin Kirkland # Scott Moser # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, version 3 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # Abort on any unhandled error set -e usage() { cat <&2; echo "$@" 1>&2; exit 1; } error() { printf "ERROR: %s\n" "$@" 1>&2 exit 1 } warn() { printf "WARNING: %s\n" "$@" 1>&2 } info() { printf "INFO: %s\n" "$@" 1>&2 } url_encode() { # from http://andy.wordpress.com/2008/09/17/urlencode-in-bash-with-perl/ printf "%s" "$1" | perl -pe's/([^-_.~A-Za-z0-9])/sprintf("%%%02X", ord($1))/seg' } validate_keys() { # Prune blank lines, join lines that don't have a '= ', # remove invalid characters sed -i -e '/^$/d' -e '/^\r/d' \ -e ':join /=[ ]/!{ N; s/[\n\r]//g ; b join }' \ -e 's/[^a-zA-Z0-9@: .\/=+-]//g' "$1" # Count lines lines=$(wc -l < "${1}") # Count valid keys keys=$(grep -c "^ssh-[dr]s[sa] [a-zA-Z0-9: .\/=+-]\+ " "$1") # Validate counts match, and >0 [ $lines -gt 0 ] && [ $keys -eq $lines ] } get_authkeypath() { # Only support writing to this user's authorized_keys file local home="${HOME}" if [ -z "$HOME" ]; then uid=$(id -u) || error "Cannot determine user id" [ -n "$uid" ] || error "User id cannot be empty" pwline=$(getent passwd "$uid") || error "Cannot get passwd entry" home=$(echo "$pwline" | awk -F: '{print $6}') || error "Cannot determine home directory" [ -n "$home" ] || error "Home directory cannot be empty" fi _RET="${home}/.ssh/authorized_keys" } # Obtain the URL string if [ -z "$URL" ]; then URL="https://launchpad.net/~%s/+sshkeys" { [ ! -e /etc/ssh/ssh_import_id ] || . /etc/ssh/ssh_import_id ; } || error "failed to source /etc/ssh/ssh_import_id" fi [ -n "$URL" ] || error "URL must be set" short_opts="ho:" long_opts="help,output:" getopt_out=$(getopt --shell sh --name "${0##*/}" \ --options "${short_opts}" --long "${long_opts}" -- "$@") && eval set -- "${getopt_out}" || bad_usage output="" while [ $# -ne 0 ]; do cur=${1}; next=${2}; case "$cur" in -h|--help) usage; exit 0;; -o|--output) output="${2}"; shift;; --) shift; break;; esac shift; done [ -n "$1" ] || bad_usage "must give user" if [ -z "${output}" ]; then get_authkeypath output=${_RET} dir=${output%/*} mkdir -p -m 0700 "${dir}" 2>/dev/null || true [ -d "$dir" ] || error "Cannot create directory [$dir]" [ -e "$output" ] || (umask 0177 && touch "$output") || error "Cannot create [$output]" fi tmp=$(mktemp) trap "rm -f $tmp" EXIT HUP INT QUIT TERM rc=0 for i in "$@"; do i=$(url_encode "$i") || error "Failed encoding [$i]" url=$(printf "$URL" "$i") if ! env -i wget --quiet -O- "$url" > "$tmp"; then rc=$(($rc+1)); warn "Failed to retrieve key for [$i] from [$url]" continue fi echo >> "$tmp" # needed for wc if ! validate_keys "$tmp"; then warn "Invalid keys at [$url]" rc=$(($rc+1)); continue fi if [ "${output}" = "-" ]; then cat "$tmp" || error "Could not write to stdout"; else cat "$tmp" >> "$output" || error "Could not write to [$output]"; fi info "Successfully authorized [$i]" done exit $rc # vi: ts=4 noexpandtab