OSDN Git Service

2013.10.24
[uclinux-h8/uClinux-dist.git] / freeswan / utils / _confread
1 #!/bin/sh
2 # configuration-file reader utility
3 # Copyright (C) 1999-2002  Henry Spencer.
4
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>.
9
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
13 # for more details.
14 #
15 # RCSID $Id: _confread,v 1.47 2002/03/26 17:49:42 henry Exp $
16 #
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:
21 #       =       sectionname
22 #       :       parameter       value
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)
28 #
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.
35 #
36 # Typical usage:
37 # eval `ipsec _confread --varprefix IPSEC --type config setup`
38 # if test " $IPSEC_confreadstatus" != " "
39 # then
40 #       echo "$0: $IPSEC_confreadstatus -- aborting" 2>&1
41 #       exit 1
42 # fi
43
44 config=${IPSEC_CONFS-/etc}/ipsec.conf
45 include=yes
46 type=conn
47 fieldfmt=yes
48 prefix=
49 search=
50 export=0
51 me="ipsec _confread"
52
53 for dummy
54 do
55         case "$1" in
56         --config)       config="$2" ; shift     ;;
57         --noinclude)    include=                ;;
58         --type)         type="$2" ; shift       ;;
59         --varprefix)    fieldfmt=
60                         prefix="$2"
61                         shift                   ;;
62         --export)       export=1                ;;
63         --search)       search="$2" ; shift     ;;
64         --version)      echo "$me $IPSEC_VERSION" ; exit 0      ;;
65         --)             shift ; break           ;;
66         -*)             echo "$0: unknown option \`$1'" >&2 ; exit 2    ;;
67         *)              break                   ;;
68         esac
69         shift
70 done
71
72 if test "$include"
73 then
74         ipsec _include --inband $config
75 else
76         cat $config
77 fi |
78 awk 'BEGIN {
79         type = "'"$type"'"
80         names = "'"$*"'"
81         prefix = "'"$prefix"'"
82         export = "'"$export"'"
83         search = "'"$search"'"
84         searching = 0
85         if (search != "") {
86                 searching = 1
87                 searchpat = "^[ \t]+" search "[ \t]*=[ \t]*"
88         }
89         fieldfmt = 0
90         if ("'"$fieldfmt"'" == "yes")
91                 fieldfmt = 1
92         including = 0
93         if ("'"$include"'" == "yes")
94                 including = 1
95         filename = "'"$config"'"
96         lineno = 0
97         originalfilename = filename
98         if (fieldfmt)
99                 bq = eq = "\""
100         else
101                 bq = eq = "\\\""
102         failed = 0
103         insection = 0
104         indefault = 0
105         outputting = 0
106         sawnondefault = 0
107         OFS = "\t"
108         o_status = "!"
109         o_parm = ":"
110         o_section = "="
111         o_names = "%"
112         o_end = "."
113         n = split(names, na, " ")
114         if (n == 0)
115                 fail("no section names supplied")
116         for (i = 1; i <= n; i++) {
117                 if (na[i] in wanted)
118                         fail("section " bq na[i] eq " requested more than once")
119                 wanted[na[i]] = 1
120                 pending[na[i]] = 1
121                 if (!searching && na[i] !~ /^[a-zA-Z][a-zA-Z0-9._-]*$/)
122                         fail("invalid section name " bq na[i] eq)
123         }
124
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"
136         right = left
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
141
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"
149         n = split(good, g)
150         for (i = 1; i <= n; i++)
151                 goodnames["config:" g[i]] = 1
152
153         goodtypes["conn"] = 1
154         goodtypes["config"] = 1
155
156         badchars = ""
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 "]"
162
163         seen[""] = ""
164         default[""] = ""
165         usesdefault [""] = ""
166 }
167
168
169
170 function output(code, v1, v2) {
171         if (code == o_parm) {
172                 if (v2 == "")           # suppress empty parameters
173                         return
174                 if (privatename(v1))    # and private ones
175                         return
176                 if (v2 ~ badchar)
177                         fail("parameter value " bq v2 eq " contains unprintable character")
178         }
179
180         if (fieldfmt) {
181                 print code, v1, v2
182                 return
183         }
184
185         if (code == o_status) {
186                 v2 = v1
187                 v1 = "_confreadstatus"
188         } else if (code == o_section) {
189                 v2 = v1
190                 v1 = "_confreadsection"
191         } else if (code == o_names) {
192                 v2 = v1
193                 v1 = "_confreadnames"
194         } else if (code != o_parm)
195                 return          # currently no variable version of o_end
196
197         print prefix v1 "=\"" v2 "\""
198         if (export)
199                 print "export " prefix v1
200 }
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)
207                 else
208                         seen[reflist[i]] = 1
209         seen[sectionname] = 1
210 }
211 function fail(msg) {
212         output(o_status, ("(" filename ", line " lineno ") " msg))
213         failed = 1
214         while ((getline junk) > 0)
215                 continue
216         exit
217 }
218 function badname(n) {
219         if ((type ":" n) in goodnames)
220                 return 0
221         if (privatename(n))
222                 return 0
223         return 1
224 }
225 function privatename(n) {
226         if (n ~ /^[xX][-_]/)
227                 return 1
228         return 0
229 }
230 function addref(from, to) {
231         if (to in refsto)
232                 refsto[to] = refsto[to] ";" from
233         else
234                 refsto[to] = from
235 }
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)
242         }
243         addref(from, to)
244 }
245
246
247
248 {
249         lineno++
250         # lineno is now the number of this line
251 }
252 including && $0 ~ /^#[<>:]/ {
253         # _include control line
254         if ($1 ~ /^#[<>]$/) {
255                 filename = $2
256                 lineno = $3 - 1
257         } else if ($0 ~ /^#:/) {
258                 msg = substr($0, 3)
259                 gsub(/"/, "\\\"", msg)
260                 fail(msg)
261         }
262         next
263 }
264 $0 !~ /^[ \t]/ {
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)
268         ###     output(o_end)
269         insection = 0
270         indefault = 0
271         outputting = 0
272 }
273 {
274         # strip trailing comments and space
275         sub(/[ \t]+(#.*)?$/, "")
276 }
277 $0 == "" || $0 ~ /^#/ {
278         # empty lines and comments are ignored
279         next
280 }
281 $0 !~ /^[ \t]/ && NF != 2 {
282         # bad section header
283         fail("section header \"" $0 "\" has wrong number of fields (" NF ")")
284 }
285 $0 !~ /^[ \t]/ && !($1 in goodtypes) {
286         # unknown section type
287         fail("section type \"" $1 "\" not recognized")
288 }
289 $0 !~ /^[ \t]/ && $1 == type && $2 != "%default" {
290         # non-default section header of our type
291         sawnondefault = 1
292 }
293 $0 !~ /^[ \t]/ && $1 == type && searching && $2 != "%default" {
294         # section header, during search
295         insection = 1
296         sectionname = $2
297         usesdefault[sectionname] = 1            # tentatively
298         next
299 }
300 $0 !~ /^[ \t]/ && !($1 == type && ($2 in wanted || $2 == "%default")) {
301         # section header, but not one we want
302         insection = 1
303         next
304 }
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)
309         delete pending[$2]
310         tag = bq type " " $2 eq
311         outputting = 1
312         insection = 1
313         output(o_section, $2)
314         next
315 }
316 $0 !~ /^[ \t]/ && $1 == type && $2 == "%default" {
317         # relevant default section header
318         if (sawnondefault)
319                 fail("\"" $1 " %default\" sections must precede non-default ones")
320         tag = bq type " " $2 eq
321         indefault = 1
322         next
323 }
324 $0 !~ /^[ \t]/ {
325         fail("internal error, supposedly cannot happen")
326 }
327 !insection && !indefault {
328         # starts with white space but not in a section... oops
329         fail("parameter is not within a section")
330 }
331 searching && $0 ~ searchpat {
332         # search found the right parameter name
333         match($0, searchpat)
334         rest = substr($0, RLENGTH+1)
335         if (rest ~ /^"/)
336                 rest = substr(rest, 2, length(rest)-2)
337         if (!indefault)
338                 delete usesdefault[sectionname]
339         if (rest in wanted) {   # a hit
340                 if (indefault)
341                         default[search] = rest
342                 else
343                         searchfound(sectionname)
344         } else {
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)
348         }
349         next
350 }
351 !searching && !outputting && !indefault {
352         # uninteresting line
353         next
354 }
355 $0 ~ /"/ && $0 !~ /^[^=]+=[ \t]*"[^"]*"$/ {
356         if (!searching)
357                 fail("mismatched quotes in parameter value")
358         else
359                 gsub(/"/, "", $0)
360 }
361 $0 !~ /^[ \t]+[a-zA-Z_][a-zA-Z0-9_-]*[ \t]*=/ {
362         if (searching)
363                 next                    # just ignore it
364         fail("syntax error or illegal parameter name")
365 }
366 {
367         sub(/^[ \t]+/, "")              # get rid of leading white space
368         sub(/[ \t]*=[ \t]*/, "=")       # and embedded white space
369 }
370 $0 ~ /^also=/ {
371         if (indefault)
372                 fail("%default section may not contain \"also\" parameter")
373         sub(/^also=/, "")
374         if ($0 !~ /^[a-zA-Z][a-zA-Z0-9._-]*$/)
375                 fail("invalid section name " bq $0 eq)
376         if (!searching) {
377                 if ($0 in wanted)
378                         fail("section " bq $0 eq " requested more than once")
379                 wanted[$0] = 1
380                 pending[$0] = 1
381         } else
382                 chainref(sectionname, $0)
383         next
384 }
385 !outputting && !indefault {
386         # uninteresting line even for a search
387         next
388 }
389 {
390         equal = match($0, /[=]/)
391         name = substr($0, 1, equal-1)
392         if (badname(name))
393                 fail("unknown parameter name " bq name eq)
394         value = substr($0, equal+1)
395         if (value ~ /^"/)
396                 value = substr(value, 2, length(value)-2)
397         else if (value ~ /[ \t]/)
398                 fail("white space within non-quoted parameter " bq name eq)
399 }
400 indefault {
401         if (name in default)
402                 fail("duplicated default parameter " bq name eq)
403         default[name] = value
404         next
405 }
406 {
407         if (name in seen)
408                 fail("duplicated parameter " bq name eq)
409         seen[name] = 1
410         output(o_parm, name, value)
411 }
412 END {
413         if (failed)
414                 exit 1
415         filename = originalfilename
416         unseen = ""
417         for (i in pending)
418                 unseen = unseen " " i
419         if (!searching && unseen != "")
420                 fail("did not find " type " section(s) " bq substr(unseen, 2) eq)
421         if (!searching) {
422                 for (name in default)
423                         if (!(name in seen))
424                                 output(o_parm, name, default[name])
425         } else {
426                 if (default[search] in wanted)
427                         for (name in usesdefault)
428                                 seen[name] = 1
429                 if (fieldfmt)
430                         for (name in seen)
431                                 output(o_section, name)
432                 else {
433                         outlist = ""
434                         for (name in seen)
435                                 if (outlist == "")
436                                         outlist = name
437                                 else
438                                         outlist = outlist " " name
439                         output(o_names, outlist)
440                 }
441         }
442         output(o_status, "")
443 }'