2 # configuration-file reader utility
3 # Copyright (C) 1999-2002 Henry Spencer.
5 # This program is free software; you can redistribute it and/or modify it
6 # under the terms of the GNU General Public License as published by the
7 # Free Software Foundation; either version 2 of the License, or (at your
8 # option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 # RCSID $Id: _confread,v 1.47 2002/03/26 17:49:42 henry Exp $
17 # Extract configuration info from /etc/ipsec.conf, repackage as assignments
18 # to shell variables or tab-delimited fields. Success or failure is reported
19 # inline, as extra data, due to the vagaries of shell backquote handling.
20 # In the absence of --varprefix, output is tab-separated fields, like:
23 # ! status (empty for success, else complaint)
24 # In the presence of (say) "--varprefix IPSEC", output is like:
25 # IPSEC_confreadsection="sectionname"
26 # IPSECparameter="value"
27 # IPSEC_confreadstatus="status" (same empty/complaint convention)
29 # The "--search parametername" option inverts the search: instead of
30 # yielding the parameters of the specified name(s), it yields the names
31 # of sections with parameter <parametername> having (one of) the
32 # specified value(s). In this case, --varprefix output is a list of
33 # names in the <prefix>_confreadnames variable. Search values with
34 # white space in them are currently not handled properly.
37 # eval `ipsec _confread --varprefix IPSEC --type config setup`
38 # if test " $IPSEC_confreadstatus" != " "
40 # echo "$0: $IPSEC_confreadstatus -- aborting" 2>&1
44 config=${IPSEC_CONFS-/etc}/ipsec.conf
56 --config) config="$2" ; shift ;;
57 --noinclude) include= ;;
58 --type) type="$2" ; shift ;;
59 --varprefix) fieldfmt=
63 --search) search="$2" ; shift ;;
64 --version) echo "$me $IPSEC_VERSION" ; exit 0 ;;
66 -*) echo "$0: unknown option \`$1'" >&2 ; exit 2 ;;
74 ipsec _include --inband $config
81 prefix = "'"$prefix"'"
82 export = "'"$export"'"
83 search = "'"$search"'"
87 searchpat = "^[ \t]+" search "[ \t]*=[ \t]*"
90 if ("'"$fieldfmt"'" == "yes")
93 if ("'"$include"'" == "yes")
95 filename = "'"$config"'"
97 originalfilename = filename
113 n = split(names, na, " ")
115 fail("no section names supplied")
116 for (i = 1; i <= n; i++) {
118 fail("section " bq na[i] eq " requested more than once")
121 if (!searching && na[i] !~ /^[a-zA-Z][a-zA-Z0-9._-]*$/)
122 fail("invalid section name " bq na[i] eq)
125 good = "also type auto authby _plutodevel"
126 left = " left leftsubnet leftnexthop leftfirewall leftupdown"
127 akey = " keyexchange auth pfs pfsgroup keylife rekey rekeymargin rekeyfuzz"
128 akey = akey " compress"
129 obs = " lifetime rekeystart rekeytries"
130 akey = akey " keyingtries ikelifetime disablearrivalcheck ike" obs
131 mkey = " spibase spi esp espenckey espauthkey espreplay_window"
132 left = left " leftespenckey leftespauthkey leftahkey"
133 left = left " leftespspi leftahspi leftid leftrsasigkey"
134 left = left " leftcert leftsubnetwithin leftprotoport"
135 mkey = mkey " ah ahkey ahreplay_window"
137 gsub(/left/, "right", right)
138 n = split(good left right akey mkey, g)
139 for (i = 1; i <= n; i++)
140 goodnames["conn:" g[i]] = 1
142 good = "also interfaces forwardcontrol syslog klipsdebug plutodebug"
143 good = good " dumpdir dump manualstart pluto plutoload plutostart"
144 good = good " plutowait plutobackgroundload prepluto postpluto"
145 good = good " fragicmp no_eroute_pass opportunistic hidetos uniqueids"
146 good = good " packetdefault overridemtu nocrsend"
147 good = good " nat_traversal keep_alive force_keepalive"
148 good = good " disable_port_floating virtual_private"
150 for (i = 1; i <= n; i++)
151 goodnames["config:" g[i]] = 1
153 goodtypes["conn"] = 1
154 goodtypes["config"] = 1
157 for (i = 1; i < 32; i++)
158 badchars = badchars sprintf("%c", i)
159 for (i = 127; i < 128+32; i++)
160 badchars = badchars sprintf("%c", i)
161 badchar = "[" badchars "]"
165 usesdefault [""] = ""
170 function output(code, v1, v2) {
171 if (code == o_parm) {
172 if (v2 == "") # suppress empty parameters
174 if (privatename(v1)) # and private ones
177 fail("parameter value " bq v2 eq " contains unprintable character")
185 if (code == o_status) {
187 v1 = "_confreadstatus"
188 } else if (code == o_section) {
190 v1 = "_confreadsection"
191 } else if (code == o_names) {
193 v1 = "_confreadnames"
194 } else if (code != o_parm)
195 return # currently no variable version of o_end
197 print prefix v1 "=\"" v2 "\""
199 print "export " prefix v1
201 function searchfound(sectionname, n, i, reflist) {
202 # a hit in x is a hit in everybody who refers to x too
203 n = split(refsto[sectionname], reflist, ";")
204 for (i = 1; i <= n; i++)
205 if (reflist[i] in seen)
206 fail("duplicated parameter " bq search eq)
209 seen[sectionname] = 1
212 output(o_status, ("(" filename ", line " lineno ") " msg))
214 while ((getline junk) > 0)
218 function badname(n) {
219 if ((type ":" n) in goodnames)
225 function privatename(n) {
230 function addref(from, to) {
232 refsto[to] = refsto[to] ";" from
236 function chainref(from, to, i, reflist, listnum) {
237 # referencing is transitive: xyz->from->to
238 if (from in refsto) {
239 listnum = split(refsto[from], reflist, ";")
240 for (i = 1; i <= listnum; i++)
241 chainref(reflist[i], to)
250 # lineno is now the number of this line
252 including && $0 ~ /^#[<>:]/ {
253 # _include control line
254 if ($1 ~ /^#[<>]$/) {
257 } else if ($0 ~ /^#:/) {
259 gsub(/"/, "\\\"", msg)
265 # any non-leading-white-space line is a section end
266 ### but not the end of relevant stuff, might be also= sections later
267 ###if (insection && !indefault && !searching && outputting)
274 # strip trailing comments and space
275 sub(/[ \t]+(#.*)?$/, "")
277 $0 == "" || $0 ~ /^#/ {
278 # empty lines and comments are ignored
281 $0 !~ /^[ \t]/ && NF != 2 {
283 fail("section header \"" $0 "\" has wrong number of fields (" NF ")")
285 $0 !~ /^[ \t]/ && !($1 in goodtypes) {
286 # unknown section type
287 fail("section type \"" $1 "\" not recognized")
289 $0 !~ /^[ \t]/ && $1 == type && $2 != "%default" {
290 # non-default section header of our type
293 $0 !~ /^[ \t]/ && $1 == type && searching && $2 != "%default" {
294 # section header, during search
297 usesdefault[sectionname] = 1 # tentatively
300 $0 !~ /^[ \t]/ && !($1 == type && ($2 in wanted || $2 == "%default")) {
301 # section header, but not one we want
305 $0 !~ /^[ \t]/ && $1 == type && ($2 in wanted) {
306 # one of our wanted section headers
307 if (!($2 in pending))
308 fail("duplicate " type " section " bq $2 eq)
310 tag = bq type " " $2 eq
313 output(o_section, $2)
316 $0 !~ /^[ \t]/ && $1 == type && $2 == "%default" {
317 # relevant default section header
319 fail("\"" $1 " %default\" sections must precede non-default ones")
320 tag = bq type " " $2 eq
325 fail("internal error, supposedly cannot happen")
327 !insection && !indefault {
328 # starts with white space but not in a section... oops
329 fail("parameter is not within a section")
331 searching && $0 ~ searchpat {
332 # search found the right parameter name
334 rest = substr($0, RLENGTH+1)
336 rest = substr(rest, 2, length(rest)-2)
338 delete usesdefault[sectionname]
339 if (rest in wanted) { # a hit
341 default[search] = rest
343 searchfound(sectionname)
345 # rather a kludge, but must check this somewhere
346 if (search == "auto" && rest !~ /^(add|route|start|ignore)$/)
347 fail("illegal auto value " bq rest eq)
351 !searching && !outputting && !indefault {
355 $0 ~ /"/ && $0 !~ /^[^=]+=[ \t]*"[^"]*"$/ {
357 fail("mismatched quotes in parameter value")
361 $0 !~ /^[ \t]+[a-zA-Z_][a-zA-Z0-9_-]*[ \t]*=/ {
363 next # just ignore it
364 fail("syntax error or illegal parameter name")
367 sub(/^[ \t]+/, "") # get rid of leading white space
368 sub(/[ \t]*=[ \t]*/, "=") # and embedded white space
372 fail("%default section may not contain \"also\" parameter")
374 if ($0 !~ /^[a-zA-Z][a-zA-Z0-9._-]*$/)
375 fail("invalid section name " bq $0 eq)
378 fail("section " bq $0 eq " requested more than once")
382 chainref(sectionname, $0)
385 !outputting && !indefault {
386 # uninteresting line even for a search
390 equal = match($0, /[=]/)
391 name = substr($0, 1, equal-1)
393 fail("unknown parameter name " bq name eq)
394 value = substr($0, equal+1)
396 value = substr(value, 2, length(value)-2)
397 else if (value ~ /[ \t]/)
398 fail("white space within non-quoted parameter " bq name eq)
402 fail("duplicated default parameter " bq name eq)
403 default[name] = value
408 fail("duplicated parameter " bq name eq)
410 output(o_parm, name, value)
415 filename = originalfilename
418 unseen = unseen " " i
419 if (!searching && unseen != "")
420 fail("did not find " type " section(s) " bq substr(unseen, 2) eq)
422 for (name in default)
424 output(o_parm, name, default[name])
426 if (default[search] in wanted)
427 for (name in usesdefault)
431 output(o_section, name)
438 outlist = outlist " " name
439 output(o_names, outlist)