#!/bin/sh -
# 
# Copyright (c) 1998-2002 Daniel J. Gregor, Jr., All rights reserved.
# 
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
#    notice, this list of conditions and the following disclaimer in the
#    documentation and/or other materials provided with the distribution.
# 3. All advertising materials mentioning features or use of this software
#    must display the following acknowledgement:
# 	This product includes software developed by Daniel J. Gregor, Jr.
# 4. The name of Daniel J. Gregor, Jr. may not be used to endorse or promote
#    products derived from this software without specific prior written
#    permission.
# 
# THIS SOFTWARE IS PROVIDED BY DANIEL J. GREGOR, JR. ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.  IN NO EVENT SHALL DANIEL J. GREGOR, JR. BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
#

usage="usage: `basename $0` [-h] [-v] [-l <user>] [-i <identity file>] [-I <identity file to install>] [-k <auth_keys>] [-o] [-1] [-2] <host>"
overwrite=""

inst_identity=""
auth_keys=""

versions=""

basename="`basename $0`"
die() {
    echo "${basename}: $*" >&2
	exit 1
}

while getopts hvl:i:I:k:o12 c
do
	case $c in
		h)
			cat << EOF
$usage

This script is used for installing SSH public keys onto remote servers.

Options:
    -v              Verbose.
    -h              Show this help information.
    -l <user>       Login to remote server as and install SSH key for <user>
    -o              Replace the entirety of the remote authorized keys file
		    with this key, instead of appending the key (default).
    -i <identity>   Identity file to pass to SSH for authenticating to
    		    the remote server.
    -I <identity>   Identity file to copy to remote server (the default is
    		    $HOME/.ssh/identity.pub for version 1 keys, and
		    $HOME/.ssh/id_[rd]sa.pub for version 2 keys).
    -k <auth_keys>  Location of the remote authorized keys file (the default
		    is $HOME/.ssh/authorized_key for version 1 keys, or
		    $HOME/.ssh/authorized_keys2 for version 2 keys).
    -1		    Use version 1 default file locations (identity.pub,
		    authorized_keys).  Default is both 1 and 2, if they exist.
    -2              Use version 2 default file locations (id_[rd]sa.pub,
		    authorized_keys2).  Default is both 1 and 2, if they exist.

EOF
			exit 0
		;;
		v)
			verbose="-v"
		;;

		l)
			remote_user="-l $OPTARG"
		;;

		i)
			identity="-i $OPTARG"
		;;

		I)
			inst_identity="$OPTARG"
		;;

		k)
			auth_keys="$OPTARG"
		;;

		o)
			overwrite="yes"
		;;

		1|2)
			versions="$versions $c"
		;;

		\?)
			echo "$usage" >&2
			exit 1
		;;
	esac
done
shift `expr $OPTIND - 1`

if [ $# -ne 1 ]
then
	echo "$usage" >&2
	exit 2
fi

host="$1"; shift

# Check these problem cases:
#	- inst_identity or auth_keys are set and multiple versions are specified
#	- inst_identity and not auth_keys are set and not a single version
#	- not inst_identity and auth_keys are set and not a single version

if [ \( X"$inst_identity" != X"" -o X"$auth_keys" != X"" \) -a \
    `echo "$versions" | wc -w` -ne 1 ]; then
	die "-I or -k options require a single version to be specified (-1, -2)"
fi

if [ X"$versions" = X"" ]; then
	if [ -r $HOME/.ssh/identity.pub ]; then
		versions="$versions 1"
	fi
	if [ -r $HOME/.ssh/id_dsa.pub -o -r $HOME/.ssh/id_rsa.pub ]; then
		versions="$versions 2 2-in-1"
	fi
fi

for version in $versions
do
	if [ X"$inst_identity" = X"" ]; then
		if [ X"$version" = X"1" ]; then
			inst_identities=$HOME/.ssh/identity.pub
		else
			inst_identities="$HOME/.ssh/id_dsa.pub $HOME/.ssh/id_rsa.pub"
		fi
	else
		inst_identities="$inst_identity"
	fi 

	found_one=""
	for this_identity in $inst_identities
	do
		test -r $this_identity || continue
		if [ X"$auth_keys" = X"" ]; then
			if [ X"$version" = X"1" -o X"$version" = X"2-in-1" ]
			then
				auth_keys=\$HOME/.ssh/authorized_keys
			else
				auth_keys=\$HOME/.ssh/authorized_keys2
			fi
		fi
	
		if [ X"$version" = X"1" ]; then
			identity_comment="`cat $this_identity | \
				awk '{ print $4 }'`"
		else
			identity_comment="`cat $this_identity | \
				awk '{ print $3 }'`"
		fi
		
		if [ X"$overwrite" != X"" ]; then
			ssh $verbose $remote_user $identity "$host" '\
				test -d $HOME/.ssh || \
					mkdir -m 755 $HOME/.ssh ; \
				chmod go-w $HOME/.ssh ; \
				touch '"$auth_keys"' ; \
				chmod 600 '"$auth_keys"' ; \
				cat > '"$auth_keys" < $this_identity
		else
			ssh $verbose $remote_user $identity "$host" '\
				test -d $HOME/.ssh || \
					mkdir -m 755 $HOME/.ssh ; \
				chmod go-w $HOME/.ssh ; \
				touch '"$auth_keys"' ; \
				chmod 600 '"$auth_keys"' ; \
				grep '"\"$identity_comment\"" "$auth_keys"' \
				   > /dev/null || \
				cat >> '"$auth_keys" < $this_identity
		fi
	done

	if [ x"$found_one" != x"" ]
	then
		die "Cannot read any identity files"
	fi

	inst_identity=""
	auth_keys=""
done
