#! /bin/sh
# show key for this host, in DNS (or other) format
# Copyright (C) 2000, 2001  Henry Spencer.
# 
# 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; either version 2 of the License, or (at your
# option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
# 
# 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.
#
# RCSID $Id: showhostkey.in,v 1.20 2003/11/07 02:58:08 mcr Exp $

me="ipsec showhostkey"
usage="Usage: $me [--file secrets] [--left] [--right] [--txt gateway] [--id id]
                  [--dhclient] [--reverse X]"

file=/etc/ipsec.secrets
fmt=""
gw=
id=

reverseip() {
	IFS="." set -- $1
	a=$1; b=$2; c=$3; d=$4;
	echo $d.$c.$b.$a.in-addr.arpa.
}

for dummy
do
	case "$1" in
	--key)	fmt="dns"		;;
	--reverse) fmt="dns"; gw="$2"; id=`reverseip $2`; shift ;;
	--file)	file="$2" ; shift	;;
	--left)	fmt="left"		;;
	--right)	fmt="right"	;;
	--dhclient)	fmt="dhclient"	;;
	--txt)	fmt="txt" ; gw="$2" ; shift	;;
	--wavesec) fmt="wavesec" ;;
	--id)	id="$2" ; shift		;;
	--version)	echo "$me $IPSEC_VERSION" ; exit 0	;;
	--help)	echo "$usage" ; exit 0	;;
	--)	shift ; break		;;
	-*)	echo "$me: unknown option \`$1'" >&2 ; exit 2	;;
	*)	break			;;
	esac
	shift
done
if test " $fmt" = " "
then
	echo "$me: must specify a format for the result" >&2
	exit 2
fi
if test " $fmt" = " txt" -a " $gw" = " "
then
	echo "$me: --txt gateway value cannot be empty" >&2
	exit 2
fi

if test ! -f $file
then
	echo "$me: file \`$file' does not exist" >&2
	exit 1
elif test ! -r $file
then
	echo "$me: permission denied (cannot read \`$file')" >&2
	exit 1
fi

host="`hostname --fqdn`"

awk '	BEGIN {
		inkey = 0
		seenkey = 0
		nfound = 0
		err = "cat >&2"
		me = "'"$me"'"
		host = "'"$host"'"
		file = "'"$file"'"
		fmt = "'"$fmt"'"
		gw = "'"$gw"'"
		id = "'"$id"'"
		comment = ""
		s = "[ \t]+"
		os = "[ \t]*"
		x = "[^ \t]+"
		oc = "(#.*)?"
		suffix = ":" os "[rR][sS][aA]" os "{" os oc "$"
		if (id == "") {
			pat = "^" suffix
			printid = "default"
		} else {
			pat = "^(" x s ")*" id "(" s x ")*" os suffix
			printid = quote(id)
		}
		paydirt = "^[ \t]+#pubkey=0s"
		status = 0
	}
	$0 ~ pat {
		inkey = 1
		seenkey = 1
	}
	/^[ \t]+}$/ {
		inkey = 0
	}
	inkey && $0 ~ /^[ \t]+# RSA [0-9]+ bits/ {
		comment = $0
		if (fmt == "dns" || fmt == "txt" || fmt == "dhclient")
			sub(/^[ \t]+#/, "#", comment)
		host = $5
	}
	inkey && $0 ~ /^[ \t]+#pubkey=0s/ {
		
	}
	inkey && fmt == "dns" && $0 ~ paydirt {
		out = $0
		sub(paydirt, (host ".\tIN\tKEY\t0x4200 4 1 "), out)
		nfound++
	}
	inkey && fmt == "dhclient" && $0 ~ paydirt {
		# NOT YET ADJUSTED TO KEY RR elimination
		boilerplate = "option oe-key code 159 = string;\n" \
			"option oe-gateway code 160 = ip-address;\n" \
			"send oe-key = "
		out = $0
		sub(paydirt, "0x4200 4 1 ", out)
		out = "option oe-key code 159 = string;\n" \
			"option oe-gateway code 160 = ip-address;\n" \
			"send oe-key = " quote(out) ";"
		nfound++
	}
	inkey && fmt == "txt" && $0 ~ paydirt {
		if (gw !~ /^@/ && gw !~ /^[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$/ )
		{
			grump("gateway must be @FQDN or IPv4 address, not " quote(gw))
			exit(status)
		}
		out = $0
		gsub(/[ \t]+/, " ", out)
		sub(paydirt, "", out)
		out = " " out
		str = "X-IPsec-Server(10)=" gw 
		if (length(str) < 255 && length(str) + length(out) > 255) {
			str = " " quote(str)
		} else {
			out = str out
			str = ""
		}
		while (length(out) > 255) {
			str = str " " quote(substr(out, 1, 255))
			out = substr(out, 256)
		}
		if (length(out) > 0)
			str = str " " quote(out)
		out = "\tIN\tTXT\t" substr(str, 2)
		nfound++
	}
	inkey && (fmt == "left" || fmt == "right") && $0 ~ /^[ \t]+#pubkey=/ {
		out = $0
		sub(/^[ \t]+#pubkey=/, ("\t" fmt "rsasigkey="), out)
		nfound++
	}
	function quote(s) {
		return "\"" s "\""
	}
	function grump(s) {
		print me ": " s |err
		status = 1
	}
	END {
		if (status != 0)
			exit(status)
		if (!seenkey)
			grump("no " printid " key in " quote(file))
		else if (nfound == 0) {
			grump("no pubkey line found -- key information old?")
		} else if (nfound > 1)
			grump("multiple " printid " keys found!?!")
		else {
			if (comment != "")
				print comment
			print out
		}
		exit(status)
	}' $file
