1238106Sdes#!/bin/sh
2238106Sdes# update-anchor.sh, update a trust anchor.
3238106Sdes# Copyright 2008, W.C.A. Wijngaards
4238106Sdes# This file is BSD licensed, see doc/LICENSE.
5238106Sdes
6238106Sdes# which validating lookup to use.
7238106Sdesubhost=unbound-host
8238106Sdes
9238106Sdesusage ( )
10238106Sdes{
11238106Sdes	echo "usage: update-anchor [-r hs] [-b] <zone name> <trust anchor file>"
12238106Sdes	echo "    performs an update of trust anchor file"
13238106Sdes	echo "    the trust anchor file is overwritten with the latest keys"
14238106Sdes	echo "    the trust anchor file should contain only keys for one zone"
15238106Sdes	echo "    -b causes keyfile to be made in bind format."
16238106Sdes	echo "       without -b the file is made in unbound format."
17238106Sdes	echo "    "
18238106Sdes	echo "alternate:"
19238106Sdes	echo "    update-anchor [-r hints] [-b] -d directory"
20238106Sdes	echo "    update all <zone>.anchor files in the directory."
21238106Sdes	echo "    "
22238106Sdes	echo "    name the files br.anchor se.anchor ..., and include them in"
23238106Sdes	echo "    the validating resolver config file."
24238106Sdes	echo "    put keys for the root in a file with the name root.anchor."
25238106Sdes	echo ""
26238106Sdes	echo "-r root.hints	use different root hints. Strict option order."
27238106Sdes	echo ""
28238106Sdes	echo "Exit code 0 means anchors updated, 1 no changes, others are errors."
29238106Sdes	exit 2
30238106Sdes}
31238106Sdes
32238106Sdesif test $# -eq 0; then
33238106Sdes	usage
34238106Sdesfi
35238106Sdesbindformat="no"
36238106Sdesfilearg='-f'
37238106Sdesroothints=""
38238106Sdesif test X"$1" = "X-r"; then
39238106Sdes	shift
40238106Sdes	roothints="$1"
41238106Sdes	shift
42238106Sdesfi
43238106Sdesif test X"$1" = "X-b"; then
44238106Sdes	shift
45238106Sdes	bindformat="yes"
46238106Sdes	filearg='-F'
47238106Sdesfi
48238106Sdesif test $# -ne 2; then
49238106Sdes	echo "arguments wrong."
50238106Sdes	usage
51238106Sdesfi
52238106Sdes
53238106Sdesdo_update ( ) {
54238106Sdes	# arguments: <zonename> <keyfile>
55238106Sdes	zonename="$1"
56238106Sdes	keyfile="$2"
57238106Sdes	tmpfile="/tmp/update-anchor.$$"
58238106Sdes	tmp2=$tmpfile.2
59238106Sdes	tmp3=$tmpfile.3
60238106Sdes	rh=""
61238106Sdes	if test -n "$roothints"; then
62238106Sdes		echo "server: root-hints: '$roothints'" > $tmp3
63238106Sdes		rh="-C $tmp3"
64238106Sdes	fi
65238106Sdes	$ubhost -v $rh $filearg "$keyfile" -t DNSKEY "$zonename" >$tmpfile
66238106Sdes	if test $? -ne 0; then
67238106Sdes		rm -f $tmpfile
68238106Sdes		echo "Error: Could not update zone $zonename anchor file $keyfile"
69238106Sdes		echo "Cause: $ubhost lookup failed" 
70238106Sdes		echo "    (Is the domain decommissioned? Is connectivity lost?)"
71238106Sdes		return 2
72238106Sdes	fi
73238106Sdes
74238106Sdes	# has the lookup been DNSSEC validated?
75238106Sdes	if grep '(secure)$' $tmpfile >/dev/null 2>&1; then
76238106Sdes		:
77238106Sdes	else
78238106Sdes		rm -f $tmpfile
79238106Sdes		echo "Error: Could not update zone $zonename anchor file $keyfile"
80238106Sdes		echo "Cause: result of lookup was not secure" 
81238106Sdes		echo "    (keys too far out of date? domain changed ownership? need root hints?)"
82238106Sdes		return 3
83238106Sdes	fi
84238106Sdes
85238106Sdes	if test $bindformat = "yes"; then
86238106Sdes		# are there any KSK keys on board?
87238106Sdes		echo 'trusted-keys {' > "$tmp2"
88238106Sdes		if grep ' has DNSKEY record 257' $tmpfile >/dev/null 2>&1; then
89238106Sdes			# store KSK keys in anchor file
90238106Sdes			grep '(secure)$' $tmpfile | \
91238106Sdes			grep ' has DNSKEY record 257' | \
92238106Sdes			sed -e 's/ (secure)$/";/' | \
93238106Sdes			sed -e 's/ has DNSKEY record \([0-9]*\) \([0-9]*\) \([0-9]*\) /. \1 \2 \3 "/' | \
94238106Sdes			sed -e 's/^\.\././' | sort >> "$tmp2"
95238106Sdes		else
96238106Sdes			# store all keys in the anchor file
97238106Sdes			grep '(secure)$' $tmpfile | \
98238106Sdes			sed -e 's/ (secure)$/";/' | \
99238106Sdes			sed -e 's/ has DNSKEY record \([0-9]*\) \([0-9]*\) \([0-9]*\) /. \1 \2 \3 "/' | \
100238106Sdes			sed -e 's/^\.\././' | sort >> "$tmp2"
101238106Sdes		fi
102238106Sdes		echo '};' >> "$tmp2"
103238106Sdes	else #not bindformat
104238106Sdes		# are there any KSK keys on board?
105238106Sdes		if grep ' has DNSKEY record 257' $tmpfile >/dev/null 2>&1; then
106238106Sdes			# store KSK keys in anchor file
107238106Sdes			grep '(secure)$' $tmpfile | \
108238106Sdes			grep ' has DNSKEY record 257' | \
109238106Sdes			sed -e 's/ (secure)$//' | \
110238106Sdes			sed -e 's/ has DNSKEY record /. IN DNSKEY /' | \
111238106Sdes			sed -e 's/^\.\././' | sort > "$tmp2"
112238106Sdes		else
113238106Sdes			# store all keys in the anchor file
114238106Sdes			grep '(secure)$' $tmpfile | \
115238106Sdes			sed -e 's/ (secure)$//' | \
116238106Sdes			sed -e 's/ has DNSKEY record /. IN DNSKEY /' | \
117238106Sdes			sed -e 's/^\.\././' | sort > "$tmp2"
118238106Sdes		fi
119238106Sdes	fi # endif-bindformat
120238106Sdes
121238106Sdes	# copy over if changed
122238106Sdes	diff $tmp2 $keyfile >/dev/null 2>&1
123238106Sdes	if test $? -eq 1; then   # 0 means no change, 2 means trouble.
124238106Sdes		cat $tmp2 > $keyfile
125238106Sdes		no_updated=0
126238106Sdes		echo "$zonename key file $keyfile updated."
127238106Sdes	else
128238106Sdes		echo "$zonename key file $keyfile unchanged."
129238106Sdes	fi
130238106Sdes
131238106Sdes	rm -f $tmpfile $tmp2 $tmp3
132238106Sdes}
133238106Sdes
134238106Sdesno_updated=1
135238106Sdesif test X"$1" = "X-d"; then
136238106Sdes	tdir="$2"
137238106Sdes	echo "start updating in $2"
138238106Sdes	for x in $tdir/*.anchor; do
139238106Sdes		if test `basename "$x"` = "root.anchor"; then
140238106Sdes			zname="."
141238106Sdes		else
142238106Sdes			zname=`basename "$x" .anchor`
143238106Sdes		fi
144238106Sdes		do_update "$zname" "$x"
145238106Sdes	done
146238106Sdes	echo "done updating in $2"
147238106Sdeselse
148238106Sdes	# regular invocation
149238106Sdes	if test X"$1" = "X."; then
150238106Sdes		zname="$1"
151238106Sdes	else
152238106Sdes		# strip trailing dot from zone name
153238106Sdes		zname="`echo $1 | sed -e 's/\.$//'`"
154238106Sdes	fi
155238106Sdes	kfile="$2"
156238106Sdes	do_update $zname $kfile
157238106Sdesfi
158238106Sdesexit $no_updated
159