#!/bin/sh # configuration-file reader utility # Copyright (C) 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: _confread,v 1.24 2000/05/31 12:10:40 henry Exp $ # # Extract configuration info from /etc/ipsec.conf, repackage as assignments # to shell variables or tab-delimited fields. Success or failure is reported # inline, as extra data, due to the vagaries of shell backquote handling. # In the absence of --varprefix, output is tab-separated fields, like: # = sectionname # : parameter value # ! status (empty for success, else complaint) # In the presence of (say) "--varprefix IPSEC", output is like: # IPSEC_confreadsection="sectionname" # IPSECparameter="value" # IPSEC_confreadstatus="status" (same empty/complaint convention) # # The "--search parametername" option inverts the search: instead of # yielding the parameters of the specified name(s), it yields the names # of sections with parameter having (one of) the # specified value(s). In this case, --varprefix output is a list of # names in the _confreadnames variable. Search values with # white space in them are currently not handled properly. # # Typical usage: # eval `ipsec _confread --varprefix IPSEC --type config setup` # if test " $IPSEC_confreadstatus" != " " # then # echo "$0: $IPSEC_confreadstatus -- aborting" 2>&1 # exit 1 # fi config=/etc/ipsec.conf include=yes type=conn fieldfmt=yes prefix= search= for dummy do case "$1" in --config) config="$2" ; shift ;; --noinclude) include= ;; --type) type="$2" ; shift ;; --varprefix) fieldfmt= prefix="$2" shift ;; --search) search="$2" ; shift ;; --) shift ; break ;; -*) echo "$0: unknown option \`$1'" >&2 ; exit 2 ;; *) break ;; esac shift done if test "$include" then ipsec _include --inband $config else cat $config fi | awk 'BEGIN { type = "'"$type"'" names = "'"$*"'" prefix = "'"$prefix"'" search = "'"$search"'" searching = 0 if (search != "") { searching = 1 searchpat = "^[ \t]+" search "[ \t]*=[ \t]*" } fieldfmt = 0 if ("'"$fieldfmt"'" == "yes") fieldfmt = 1 including = 0 if ("'"$include"'" == "yes") including = 1 filename = "'"$config"'" lineno = 0 originalfilename = filename if (fieldfmt) bq = eq = "\"" else bq = eq = "\\\"" failed = 0 insection = 0 indefault = 0 outputting = 0 sawnondefault = 0 OFS = "\t" o_status = "!" o_parm = ":" o_section = "=" o_names = "%" n = split(names, na, " ") for (i = 1; i <= n; i++) { if (na[i] in wanted) fail("section " bq na[i] eq " requested more than once") wanted[na[i]] = 1 pending[na[i]] = 1 if (!searching && na[i] !~ /^[a-zA-Z][a-zA-Z0-9._-]*$/) fail("invalid section name " bq na[i] eq) } good = "also type auto authby" left = " left leftsubnet leftnexthop leftfirewall leftupdown" akey = " keyexchange auth pfs keylife rekeymargin rekeyfuzz" obs = " lifetime rekeystart rekeytries" akey = akey " keyingtries ikelifetime" obs mkey = " spibase spi esp espenckey espauthkey espreplay_window" left = left " leftespenckey leftespauthkey leftahkey" left = left " leftespspi leftahspi leftid leftrsasigkey" mkey = mkey " ah ahkey ahreplay_window" right = left gsub(/left/, "right", right) n = split(good left right akey mkey, g) for (i = 1; i <= n; i++) goodnames["conn:" g[i]] = 1 good = "also interfaces forwardcontrol syslog klipsdebug plutodebug" good = good " dumpdir dump manualstart pluto plutoload plutostart" good = good " plutowait plutobackgroundload prepluto postpluto" n = split(good, g) for (i = 1; i <= n; i++) goodnames["config:" g[i]] = 1 goodtypes["conn"] = 1 goodtypes["config"] = 1 badchars = "" for (i = 1; i < 32; i++) badchars = badchars sprintf("%c", i) for (i = 127; i < 128+32; i++) badchars = badchars sprintf("%c", i) badchar = "[" badchars "]" seen[""] = "" default[""] = "" outlist = "" } function output(code, v1, v2) { if (code == o_parm && v2 == "") # suppress empty parameters return if (code == o_parm && v1 !~ /^[xX]-/ && v2 ~ badchar) fail("parameter value " bq v2 eq " contains unprintable character") if (fieldfmt) print code, v1, v2 else if (code == o_status) print prefix "_confreadstatus=\"" v1 "\"" else if (code == o_section) print prefix "_confreadsection=\"" v1 "\"" else if (code == o_names) print prefix "_confreadnames=\"" v1 "\"" else if (code == o_parm) print prefix v1 "=\"" v2 "\"" } function searchfound(name) { if (fieldfmt) { output(o_section, name) return } if (outlist == "") outlist = name else outlist = outlist " " name } function fail(msg) { output(o_status, ("(" filename ", line " lineno ") " msg)) failed = 1 exit } function badname(n) { if ((type ":" n) in goodnames) return 0 if (n ~ /^[xX]-/) return 0 return 1 } { lineno++ # lineno is now the number of this line } including && $0 ~ /^#[<>:]/ { # _include control line if ($1 ~ /^#[<>]$/) { filename = $2 lineno = $3 - 1 } else if ($0 ~ /^#:/) { msg = substr($0, 3) gsub(/"/, "\\\"", msg) fail(msg) } next } $0 !~ /^[ \t]/ { # any non-leading-white-space line is a section end insection = 0 indefault = 0 outputting = 0 } { # strip trailing comments and space sub(/[ \t]+(#.*)?$/, "") } $0 == "" || $0 ~ /^#/ { # empty lines and comments are ignored next } $0 !~ /^[ \t]/ && !($1 in goodtypes) { # unknown section type fail("section type \"" $1 "\" not recognized") } $0 !~ /^[ \t]/ && $1 == type && searching && $2 != "%default" { # section header, during search insection = 1 sectionname = $2 next } $0 !~ /^[ \t]/ && $1 == type && $2 != "%default" { # non-default section header of our type sawnondefault = 1 } $0 !~ /^[ \t]/ && !($1 == type && ($2 in wanted || $2 == "%default")) { # section header, but not one we want insection = 1 next } $0 !~ /^[ \t]/ && $1 == type && ($2 in wanted) { # one of our wanted section headers if (!($2 in pending)) fail("duplicate " type " section " bq $2 eq) delete pending[$2] tag = bq type " " $2 eq outputting = 1 insection = 1 output(o_section, $2) next } $0 !~ /^[ \t]/ && $1 == type && $2 == "%default" { # relevant default section header if (sawnondefault) fail("\"" $1 " %default\" sections must precede non-default ones") tag = bq type " " $2 eq indefault = 1 next } $0 !~ /^[ \t]/ { fail("internal error, supposedly cannot happen") } !insection && !indefault { # starts with white space but not in a section... oops fail("parameter is not within a section") } searching && $0 ~ searchpat { match($0, searchpat) rest = substr($0, RLENGTH+1) if (rest ~ /^"/) rest = substr(rest, 2, length(rest)-2) if (rest in wanted) searchfound(sectionname) next } !outputting && !indefault { # uninteresting line next } $0 ~ /"/ && $0 !~ /^[^=]+=[ \t]*"[^"]*"$/ { fail("mismatched quotes in parameter value") } $0 !~ /^[ \t]+[a-zA-Z][a-zA-Z0-9_-]*[ \t]*=/ { fail("syntax error or illegal parameter name") } { sub(/^[ \t]+/, "") # get rid of leading white space sub(/[ \t]*=[ \t]*/, "=") # and embedded white space } $0 ~ /^also=/ { if (indefault) fail("%default section may not contain \"also\" parameter") sub(/^also=/, "") if ($0 in wanted) fail("section " bq $0 eq " requested more than once") wanted[$0] = 1 pending[$0] = 1 if ($0 !~ /^[a-zA-Z][a-zA-Z0-9._-]*$/) fail("invalid section name " bq $0 eq) next } { equal = match($0, /[=]/) name = substr($0, 1, equal-1) if (badname(name)) fail("unknown parameter name " bq name eq) value = substr($0, equal+1) if (value ~ /^"/) value = substr(value, 2, length(value)-2) } indefault { if (name in default) fail("duplicated default parameter " bq name eq) default[name] = value next } { if (name in seen) fail("duplicated parameter " bq name eq) seen[name] = 1 output(o_parm, name, value) } END { if (failed) exit 1 filename = originalfilename unseen = "" for (i in pending) unseen = unseen " " i if (!searching && unseen != "") fail("did not find " type " section(s) " bq substr(unseen, 2) eq) if (!searching) for (name in default) if (!(name in seen)) output(o_parm, name, default[name]) if (searching && !fieldfmt) output(o_names, outlist) output(o_status, "") }'