#! /bin/sh # user interface to automatic keying and Pluto in general # Copyright (C) 1998, 1999, 2000 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 . # # 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: auto.in,v 1.17 2006/04/20 04:42:12 as Exp $ me='ipsec auto' usage="Usage: $me [--showonly] [--asynchronous] --up connectionname $me [--showonly] [-- type conn|ca] --{add|delete|replace|down} name $me [--showonly] --{route|unroute} connectionname $me [--showonly] --ready $me [--showonly] --{status|statusall} [connectionname] $me [--showonly] --{rereadsecrets|rereadgroups} $me [--showonly] --{rereadcacerts|rereadaacerts|rereadocspcerts} $me [--showonly] --{rereadacerts|rereadcrls|rereadall} $me [--showonly] [--utc] --{listalgs|listpubkeys|listcerts} $me [--showonly] [--utc] --{listcacerts|listaacerts|listocspcerts} $me [--showonly] [--utc] --{listacerts|listgroups|listcainfos} $me [--showonly] [--utc] --{listcrls|listocsp|listcards|listall} $me [--showonly] --purgeocsp other options: [--config ipsecconfigfile] [--verbose] [--show]" showonly= config= info=/var/run/ipsec.info shopts= noinclude= async= logfilter='$1 != "002"' op= argc= utc= type="conn" name="--name" for dummy do case "$1" in --help) echo "$usage" ; exit 0 ;; --version) echo "$me $IPSEC_VERSION" ; exit 0 ;; --show) shopts=-x ;; --showonly) showonly=yes ;; --utc) utc="$1" ;; --config) config="--config $2" ; shift ;; --noinclude) noinclude=--noinclude ;; --asynchronous) async="--asynchronous" ;; --verbose) logfilter='1' ;; --type) type="$2" ; shift ;; --up|--down|--add|--delete|--replace|--route|--unroute) if test " $op" != " " then echo "$usage" >&2 exit 2 fi op="$1" argc=1 if test "$type" = "ca" then name="--caname" case "$op" in --add|--delete|--replace) ;; --*) echo "$op option not supported for --type ca"; exit 3 ;; esac fi ;; --status|--statusall) if test " $op" != " " then echo "$usage" >&2 exit 2 fi op="$1" argc=1 if test $# -eq 1 then argc=0; name= fi ;; --ready|--rereadsecrets|--rereadgroups|\ --rereadcacerts|--rereadaacerts|--rereadocspcerts|\ --rereadacerts|--rereadcrls|--rereadall|\ --listalgs|--listpubkeys|--listcerts|\ --listcacerts|--listaacerts|--listocspcerts|\ --listacerts|--listgroups|--listcainfos|\ --listcrls|--listocsp|--listcards|--listall|\ --purgeocsp) if test " $op" != " " then echo "$usage" >&2 exit 2 fi op="$1" argc=0 ;; --) shift ; break ;; -*) echo "$me: unknown option \`$1'" >&2 ; exit 2 ;; *) break ;; esac shift done names= case "$op" in --*) if test " $argc" -ne $# then echo "$usage" >&2 exit 2 fi names="$*" ;; *) echo "$usage" >&2 ; exit 2 ;; esac runit() { if test "$showonly" then cat else ( echo '(' cat echo ')' echo 'echo = $?' ) | sh $shopts | awk "/^= / { exit \$2 } $logfilter { print }" fi } case "$op" in --ready) echo "ipsec whack --listen" | runit ; exit ;; --rereadsecrets) echo "ipsec whack --rereadsecrets" | runit ; exit ;; --rereadgroups) echo "ipsec whack --listen" | runit ; exit ;; --rereadcacerts) echo "ipsec whack --rereadcacerts" | runit ; exit ;; --rereadaacerts) echo "ipsec whack --rereadaacerts" | runit ; exit ;; --rereadocspcerts) echo "ipsec whack --rereadocspcerts" | runit ; exit ;; --rereadacerts) echo "ipsec whack --rereadacerts" | runit ; exit ;; --rereadcrls) echo "ipsec whack --rereadcrls" | runit ; exit ;; --rereadall) echo "ipsec whack --rereadall" | runit ; exit ;; --listalgs) echo "ipsec whack --listalgs" | runit ; exit ;; --listpubkeys) echo "ipsec whack $utc --listpubkeys" | runit ; exit ;; --listcerts) echo "ipsec whack $utc --listcerts" | runit ; exit ;; --listcacerts) echo "ipsec whack $utc --listcacerts" | runit ; exit ;; --listaacerts) echo "ipsec whack $utc --listaacerts" | runit ; exit ;; --listocspcerts) echo "ipsec whack $utc --listocspcerts" | runit ; exit ;; --listacerts) echo "ipsec whack $utc --listacerts" | runit ; exit ;; --listgroups) echo "ipsec whack $utc --listgroups" | runit ; exit ;; --listcainfos) echo "ipsec whack $utc --listcainfos" | runit ; exit ;; --listcrls) echo "ipsec whack $utc --listcrls" | runit ; exit ;; --listocsp) echo "ipsec whack $utc --listocsp" | runit ; exit ;; --listcards) echo "ipsec whack $utc --listcards" | runit ; exit ;; --listall) echo "ipsec whack $utc --listall" | runit ; exit ;; --purgeocsp) echo "ipsec whack $utc --purgeocsp" | runit ; exit ;; --up) echo "ipsec whack $async --name $names --initiate" | runit ; exit ;; --down) echo "ipsec whack --name $names --terminate" | runit ; exit ;; --delete) echo "ipsec whack $name $names --delete" | runit ; exit ;; --route) echo "ipsec whack --name $names --route" | runit ; exit ;; --unroute) echo "ipsec whack --name $names --unroute" | runit ; exit ;; --status) echo "ipsec whack $name $names --status" | runit ; exit ;; --statusall) echo "ipsec whack $name $names --statusall" | runit ; exit ;; esac if test -s $info then . $info fi ipsec _confread $config $noinclude --type $type $names | awk -v section="$type" ' BEGIN { FS = "\t" op = "'"$op"'" err = "cat >&2" draddr = "'"$defaultrouteaddr"'" drnexthop = "'"$defaultroutenexthop"'" failed = 0 s[""] = "" init() print "PATH=\"'"$PATH"'\"" print "export PATH" flip["left"] = "right" flip["right"] = "left" } function init(n) { for (n in s) delete s[n] name = "" seensome = 0 } $1 == ":" { s[$2] = $3 seensome = 1 next } $1 == "!" { if ($2 != "") fail($2) next } $1 == "=" { if (name == "") name = $2 next } $1 == "." { if (section == "ca") output_ca() else output() init() next } { fail("internal error, unknown type code " v($1)) } function fail(m) { print "ipsec_auto: fatal error in " v(name) ": " m |err failed = 1 exit } function yesno(k) { if ((k in s) && s[k] != "yes" && s[k] != "no") fail("parameter " v(k) " must be \"yes\" or \"no\"") } function setdefault(k, val) { if (!(k in s)) s[k] = val } function was(new, old) { if (!(new in s) && (old in s)) s[new] = s[old] } function need(k) { if (!(k in s)) fail("connection has no " v(k) " parameter specified") if (s[k] == "") fail("parameter " v(k) " value must be non-empty") } function integer(k) { if (!(k in s)) return if (s[k] !~ /^[0-9]+$/) fail("parameter " v(k) " value must be integer") } function duration(k, n, t) { if (!(k in s)) return t = s[k] n = substr(t, 1, length(t)-1) if (t ~ /^[0-9]+$/) s[k] = t else if (t ~ /^[0-9]+s$/) s[k] = n else if (t ~ /^[0-9]+(\.[0-9]+)?m$/) s[k] = int(n*60) else if (t ~ /^[0-9]+(\.[0-9]+)?h$/) s[k] = int(n*3600) else if (t ~ /^[0-9]+(\.[0-9]+)?d$/) s[k] = int(n*3600*24) else fail("parameter " v(k) " not valid time, must be nnn[smhd]") } function nexthopset(dir, val, k) { k = dir "nexthop" if (k in s) fail("non-default value of " k " is being overridden") if (val != "") s[k] = val else if (k in s) delete s[k] } function id(dir, k) { k = dir "id" if (!(k in s)) k = dir return s[k] } function whackkey(dir, which, flag, rk, n) { if (id(dir) == "%opportunistic") return rk = s[dir which] if (rk == "%dnsondemand") { kod="--dnskeyondemand" return } if (rk == "" || rk == "%none" || rk == "%cert" || rk == "0x00") return n = "\"\\\"" name "\\\" " dir which"\"" if (rk == "%dns" || rk == "%dnsonload") { if (id(flip[dir]) == "%opportunistic" || s[flip[dir]] == "%any") return print "ipsec whack --label", n, flag, "--keyid", q(id(dir)), "\\" } else { print "ipsec whack --label", n, flag, "--keyid", q(id(dir)), "--pubkeyrsa", q(rk), "\\" } print "\t|| exit $?" } function q(str) { # quoting for shell return "\"" str "\"" } function qs(k) { # utility abbreviation for q(s[k]) return q(s[k]) } function v(str) { # quoting for human viewing return "\"" str "\"" } function output() { if (!seensome) fail("internal error, output called inappropriately") setdefault("type", "tunnel") type_flags = "" t = s["type"] if (t == "tunnel") { # do NOT default subnets to side/32, despite what # the docs say... type_flags = "--tunnel" } else if (t == "transport") { if ("leftsubnet" in s) fail("type=transport incompatible with leftsubnet") if ("rightsubnet" in s) fail("type=transport incompatible with rightsubnet") type_flags = "" } else if (t == "passthrough") { type_flags = "--pass" } else if (t == "drop") { type_flags = "--drop" } else if (t == "reject") { type_flags = "--reject" } else fail("unknown type " v(t)) setdefault("failureshunt", "none") t = s["failureshunt"] if (t == "passthrough") type_flags = type_flags " --failpass"; else if (t == "drop") type_flags = type_flags " --faildrop"; else if (t == "reject") type_flags = type_flags " --failreject"; else if (t != "none") fail("unknown failureshunt value " v(t)) need("left") need("right") if (s["left"] == "%defaultroute") { if (s["right"] == "%defaultroute") fail("left and right cannot both be %defaultroute") if (draddr == "") fail("%defaultroute requested but not known") s["left"] = draddr nexthopset("left", drnexthop) } else if (s["right"] == "%defaultroute") { if (draddr == "") fail("%defaultroute requested but not known") s["right"] = draddr nexthopset("right", drnexthop) } setdefault("keyexchange", "ike") if (s["keyexchange"] != "ike") fail("only know how to do keyexchange=ike") setdefault("auth", "esp") if (("auth" in s) && s["auth"] != "esp" && s["auth"] != "ah") fail("only know how to do auth=esp or auth=ah") yesno("pfs") setdefault("pfs", "yes") duration("dpddelay") duration("dpdtimeout") if ("dpdaction" in s) { setdefault("dpddelay",30) setdefault("dpdtimeout",120) } yesno("compress") setdefault("compress", "no") setdefault("keylife", "1h") duration("keylife") yesno("rekey") setdefault("rekey", "yes") setdefault("rekeymargin", "9m") duration("rekeymargin") setdefault("keyingtries", "%forever") if (s["keyingtries"] == "%forever") s["keyingtries"] = 0 integer("keyingtries") if ("rekeyfuzz" in s) { if (s["rekeyfuzz"] !~ /%$/) fail("rekeyfuzz must be nnn%") r = s["rekeyfuzz"] s["rekeyfuzz"] = substr(r, 1, length(r)-1) integer("rekeyfuzz") } duration("ikelifetime") setdefault("disablearrivalcheck", "no") setdefault("leftsendcert", "always") setdefault("rightsendcert", "always") setdefault("leftnexthop", "%direct") setdefault("rightnexthop", "%direct") if (s["leftnexthop"] == s["left"]) fail("left and leftnexthop must not be the same") if (s["rightnexthop"] == s["right"]) fail("right and rightnexthop must not be the same") if (s["leftnexthop"] == "%defaultroute") { if (drnexthop == "") fail("%defaultroute requested but not known") s["leftnexthop"] = drnexthop } if (s["rightnexthop"] == "%defaultroute") { if (drnexthop == "") fail("%defaultroute requested but not known") s["rightnexthop"] = drnexthop } if ("leftfirewall" in s && "leftupdown" in s) fail("cannot have both leftfirewall and leftupdown") if ("rightfirewall" in s && "rightupdown" in s) fail("cannot have both rightfirewall and rightupdown") setdefault("leftupdown", "ipsec _updown") setdefault("rightupdown", "ipsec _updown") setdefault("lefthostaccess", "no") setdefault("righthostaccess", "no") yesno("lefthostaccess") yesno("righthostaccess") lha = "" if (s["lefthostaccess"] == "yes") lha = "--hostaccess" rha = "" if (s["righthostaccess"] == "yes") rha = "--hostaccess" setdefault("leftfirewall", "no") setdefault("rightfirewall", "no") yesno("leftfirewall") yesno("rightfirewall") if (s["leftfirewall"] == "yes") s["leftupdown"] = s["leftupdown"] " iptables" if (s["rightfirewall"] == "yes") s["rightupdown"] = s["rightupdown"] " iptables" setdefault("authby", "rsasig") t = s["authby"] if (t == "rsasig" || t == "secret|rsasig" || t == "rsasig|secret") { authtype = "--rsasig" type_flags = "--encrypt " type_flags if (!("leftcert" in s)) { setdefault("leftrsasigkey", "%cert") if (id("left") == "%any" && !(s["leftrsasigkey"] == "%cert" || s["leftrsasigkey"] == "0x00") ) fail("ID " v(id("left")) " cannot have RSA key") } if (!("rightcert" in s)) { setdefault("rightrsasigkey", "%cert") if (id("right") == "%any" && !(s["rightrsasigkey"] == "%cert" || s["rightrsasigkey"] == "0x00") ) fail("ID " v(id("right")) " cannot have RSA key") } if (t != "rsasig") authtype = authtype " --psk" } else if (t == "secret") { authtype = "--psk" type_flags = "--encrypt " type_flags } else if (t == "never") { authtype = "" } else { fail("unknown authby value " v(t)) } settings = type_flags setdefault("ike", "3des-sha,3des-md5") if (s["ike"] != "") settings = settings " --ike " qs("ike") setdefault("esp", "3des") if (s["esp"] != "") settings = settings " --esp " qs("esp") if (s["auth"] == "ah") settings = settings " --authenticate" if (s["pfs"] == "yes") { settings = settings " --pfs" if (s["pfsgroup"] != "") settings = settings " --pfsgroup " qs("pfsgroup") } if (s["dpdaction"]) settings = settings " --dpdaction " qs("dpdaction") if (s["dpddelay"]) settings = settings " --dpddelay " qs("dpddelay") if (s["dpdtimeout"]) settings = settings " --dpdtimeout " qs("dpdtimeout") if (s["compress"] == "yes") settings = settings " --compress" if (op == "--replace") settings = settings " --delete" if ("ikelifetime" in s) settings = settings " --ikelifetime " qs("ikelifetime") if (s["disablearrivalcheck"] == "yes") settings = settings " --disablearrivalcheck" settings = settings " " authtype lc = "" rc = "" if ("leftsubnet" in s) lc = "--client " qs("leftsubnet") if ("rightsubnet" in s) rc = "--client " qs("rightsubnet") if ("leftsubnetwithin" in s) lc = lc " --clientwithin " qs("leftsubnetwithin") if ("rightsubnetwithin" in s) rc = rc " --clientwithin " qs("rightsubnetwithin") lp = "" rp = "" if ("leftprotoport" in s) lp = "--clientprotoport " qs("leftprotoport") if ("rightprotoport" in s) rp = "--clientprotoport " qs("rightprotoport") lud = "--updown " qs("leftupdown") rud = "--updown " qs("rightupdown") lid = "" if ("leftid" in s) lid = "--id " qs("leftid") rid = "" if ("rightid" in s) rid = "--id " qs("rightid") lsip = "" if ("leftsourceip" in s) lsip = "--srcip " qs("leftsourceip") rsip = "" if ("rightsourceip" in s) rsip = "--srcip " qs("rightsourceip") lscert = "" if ("leftsendcert" in s) lscert = "--sendcert " qs("leftsendcert") rscert = "" if ("rightsendcert" in s) rscert = "--sendcert " qs("rightsendcert") lcert = "" if ("leftcert" in s) lcert = "--cert " qs("leftcert") rcert = "" if ("rightcert" in s) rcert = "--cert " qs("rightcert") lca = "" if ("leftca" in s) lca = "--ca " qs("leftca") rca = "" if ("rightca" in s) rca = "--ca " qs("rightca") lgr = "" if ("leftgroups" in s) lgr = "--groups " qs("leftgroups") rgr = "" if ("rightgroups" in s) rgr = "--groups " qs("rightgroups") fuzz = "" if ("rekeyfuzz" in s) fuzz = "--rekeyfuzz " qs("rekeyfuzz") rk = "" if (s["rekey"] == "no") rk = "--dontrekey" pd = "" if ("_plutodevel" in s) pd = "--plutodevel " s["_plutodevel"] # not qs() lkod = "" rkod = "" if (authtype != "--psk") { kod = "" whackkey("left", "rsasigkey", "") whackkey("left", "rsasigkey2", "--addkey") lkod = kod kod = "" whackkey("right", "rsasigkey", "") whackkey("right", "rsasigkey2", "--addkey") rkod = kod } print "ipsec whack --name", name, settings, "\\" print "\t--host", qs("left"), lc, lp, "--nexthop", qs("leftnexthop"), lud, lha, lid, lkod, lscert, lcert, lca, lsip, lgr, "\\" print "\t--to", "--host", qs("right"), rc, rp, "--nexthop", qs("rightnexthop"), rud, rha, rid, rkod, rscert, rcert, rca, rsip, rgr, "\\" print "\t--ipseclifetime", qs("keylife"), "--rekeymargin", qs("rekeymargin"), "\\" print "\t--keyingtries", qs("keyingtries"), fuzz, rk, pd, "\\" print "\t|| exit $?" } function output_ca() { if (!seensome) fail("internal error, output called inappropriately") settings = "" if (op == "--replace") settings = "--delete" cacert = "" if ("cacert" in s) cacert = "--cacert " qs("cacert") ldaphost = "" if ("ldaphost" in s) ldaphost = "--ldaphost " qs("ldaphost") ldapbase = "" if ("ldapbase" in s) ldapbase = "--ldapbase " qs("ldapbase") crluri = "" if ("crluri" in s) crluri = "--crluri " qs("crluri") crluri2 = "" if ("crluri2" in s) crluri2 = "--crluri2 " qs("crluri2") ocspuri = "" if ("ocspuri" in s) ocspuri = "--ocspuri " qs("ocspuri") yesno("strictcrlpolicy") setdefault("strictcrlpolicy", "no") if (s["strictcrlpolicy"] == "yes") settings = settings " --strictcrlpolicy" yesno("cachecrls") setdefault("cachecrls", "no") if (s["cachecrls"] == "yes") settings = settings " --cachecrls" print "ipsec whack --caname", name, settings, cacert, ldaphost, ldapbase, crluri, crluri2, ocspuri, "\\" print "\t|| exit $?" } END { if (failed) { print "# fatal error discovered, force failure using \"false\" command" print "false" exit 1 # just on general principles } if (seensome) { if (section == "ca") output_ca() else output() } }' | runit