#! /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.104 2005/01/11 17:52:49 ken Exp $ me='ipsec auto' usage="Usage: $me [--showonly] [--asynchronous] --up connectionname $me [--showonly] --{add|delete|replace|down} connectionname $me [--showonly] --{route|unroute} connectionname $me [--showonly] --{ready|status|rereadsecrets|rereadgroups} $me [--showonly] --{rereadcacerts|rereadaacerts|rereadocspcerts} $me [--showonly] --{rereadacerts|rereadcrls|rereadall} $me [--showonly] [--utc] --{listpubkeys|listcerts} $me [--showonly] [--utc] --{listcacerts|listaacerts|listocspcerts} $me [--showonly] [--utc] --{listacerts|listgroups} $me [--showonly] [--utc] --{listcrls|listocsp|listcards|listall} $me [--showonly] --purgeocsp other options: [--config ipsecconfigfile] [--verbose] [--show]" showonly= config= info=/var/run/pluto/ipsec.info shopts= noinclude= async= logfilter='$1 != "002"' op= argc= utc= 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' ;; --up|--down|--add|--delete|--replace|--route|--unroute) if test " $op" != " " then echo "$usage" >&2 exit 2 fi op="$1" argc=1 ;; --ready|--status|--rereadsecrets|--rereadgroups|\ --rereadcacerts|--rereadaacerts|--rereadocspcerts|\ --rereadacerts|--rereadcrls|--rereadall|\ --listpubkeys|--listcerts|\ --listcacerts|--listaacerts|--listocspcerts|\ --listacerts|--listgroups|\ --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$#:$1:$2" in 2:*:up|2:*:down|2:*:add|2:*:delete|2:*:replace|2:*:route|2:*:unroute) echo "$me: warning: obsolete command syntax used" >&2 names="$1" op="--$2" ;; 1:ready:|1:status:|1:rereadsecrets:|\ 1:rereadcacerts:|1:rereadaacerts:|1:rereadocspcerts:|\ 1:rereadacerts:|1:rereadcrls:|1:rereadall:\ 1:listpubkeys:|1:listcerts:|\ 1:listcacerts:|1:listaacerts:|1:listocspcerts:|\ 1:listacerts:|1:listgroups:|\ 1:listcrls:|1:listocsp:|1:listcards:|1:listall:|1:purgeocsp:) echo "$me: warning: obsolete command syntax used" >&2 op="--$1" ;; --*) if test " $argc" -ne $# then echo "$usage" >&2 exit 2 fi names="$*" ;; *) echo "$usage" >&2 ; exit 2 ;; esac # before we go any further, duplicate stdin/stdout to fds 3/4 exec 3<&0 exec 4>&1 runit() { if test "$showonly" then cat else ( echo '(' echo 'exec <&3' # regain stdin 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 ;; --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 ;; --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 --status" | runit ; exit ;; esac if test -s $info then . $info fi ipsec _confread $config $noinclude $names | awk ' 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 == "." { 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 default(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") default("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)) default("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) } default("keyexchange", "ike") if (s["keyexchange"] != "ike") fail("only know how to do keyexchange=ike") default("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") default("pfs", "yes") yesno("aggrmode") default("aggrmode", "no") duration("dpddelay") duration("dpdtimeout") if(("dpddelay" in s) && !("dpdtimeout" in s)) default("dpdtimeout",120) if(!("dpddelay" in s) && ("dpdtimeout" in s)) default("dpddelay",30) default("dpdaction","hold") yesno("forceencaps") default("forceencaps", "no") yesno("xauth") default("xauth", "no") yesno("xauthserver") default("xauthserver", "no") yesno("xauthclient") default("xauthclient", "no") yesno("modecfgserver") default("modecfgserver", "no") yesno("modecfgclient") default("modecfgclient", "no") yesno("modecfgpull") default("modecfgpull", "no") yesno("compress") default("compress", "no") default("keylife", "8h") duration("keylife") yesno("rekey") default("rekey", "yes") default("rekeymargin", "9m") duration("rekeymargin") default("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") default("disablearrivalcheck", "no") default("leftsendcert", "always") default("rightsendcert", "always") default("leftnexthop", "%direct") default("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 } default("leftupdown", "ipsec _updown") default("rightupdown", "ipsec _updown") default("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)) { default("leftrsasigkey", "%dnsondemand") if (id("left") == "%any" && !(s["leftrsasigkey"] == "%cert" || s["leftrsasigkey"] == "0x00") ) fail("ID " v(id("left")) " cannot have RSA key") } if (!("rightcert" in s)) { default("rightrsasigkey", "%dnsondemand") 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 # BEGIN IPv6 default("connaddrfamily", "ipv4") if (s["connaddrfamily"] == "ipv6") { settings = settings " --ipv6" } else if (s["connaddrfamily"] != "ipv4") { fail("unknown connaddrfamily value " s["connaddrfamily"]) } # END IPv6 if (s["ike"] != "") settings = settings " --ike " qs("ike") 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["aggrmode"] == "yes") settings = settings " --aggrmode" if (s["forceencaps"] == "yes") settings = settings " --forceencaps" if (s["modecfgpull"] == "yes") settings = settings " --modecfgpull" if (s["compress"] == "yes") settings = settings " --compress" if (s["dpddelay"]) settings = settings " --dpddelay " qs("dpddelay") if (s["dpdtimeout"]) settings = settings " --dpdtimeout " qs("dpdtimeout") if (s["dpdaction"]) settings = settings " --dpdaction " qs("dpdaction") 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") if ("leftxauthserver" in s) lxauth = "--xauthserver" if ("leftxauthclient" in s) lxauth = "--xauthclient" if ("rightxauthserver" in s) rxauth = "--xauthserver" if ("rightxauthclient" in s) rxauth = "--xauthclient" if ("leftmodecfgserver" in s) lmodecfg = "--modecfgserver" if ("leftmodecfgclient" in s) lmodecfg = "--modecfgclient" if ("rightmodecfgserver" in s) rmodecfg = "--modecfgserver" if ("rightmodecfgclient" in s) rmodecfg = "--modecfgclient" if ("leftsendcert" in s) lscert = "--sendcert " qs("leftsendcert") 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") lcerttype="" if ("leftcerttype" in s) { lcerttype = "--certtype " qs("leftcerttype") } rcerttype="" if ("rightcerttype" in s) { rcerttype = "--certtype " qs("rightcerttype") } 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, lid, lkod, lcert, lscert, lcerttype, lca, lxauth, lmodecfg, lsip, lgr, "\\" print "\t--to", "--host", qs("right"), rc, rp, "--nexthop", qs("rightnexthop"), rud, rid, rkod, rcert,rscert, rcerttype, rca, rxauth, rmodecfg, rsip, rgr, "\\" print "\t--ipseclifetime", qs("keylife"), "--rekeymargin", qs("rekeymargin"), "\\" print "\t--keyingtries", qs("keyingtries"), fuzz, rk, pd, "\\" 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) output() }' | runit