]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/dhclient/clparse.c
Install the dhcp-options.5 manpage.
[FreeBSD/FreeBSD.git] / sbin / dhclient / clparse.c
1 /*      $OpenBSD: clparse.c,v 1.18 2004/09/15 18:15:18 henning Exp $    */
2
3 /* Parser for dhclient config and lease files... */
4
5 /*
6  * Copyright (c) 1997 The Internet Software Consortium.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of The Internet Software Consortium nor the names
19  *    of its contributors may be used to endorse or promote products derived
20  *    from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
23  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
24  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26  * DISCLAIMED.  IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
27  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
29  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
30  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  * This software has been written for the Internet Software Consortium
37  * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
38  * Enterprises.  To learn more about the Internet Software Consortium,
39  * see ``http://www.vix.com/isc''.  To learn more about Vixie
40  * Enterprises, see ``http://www.vix.com''.
41  */
42
43 #include "dhcpd.h"
44 #include "dhctoken.h"
45
46 struct client_config top_level_config;
47 struct interface_info *dummy_interfaces;
48 extern struct interface_info *ifi;
49
50 char client_script_name[] = "/sbin/dhclient-script";
51
52 /*
53  * client-conf-file :== client-declarations EOF
54  * client-declarations :== <nil>
55  *                       | client-declaration
56  *                       | client-declarations client-declaration
57  */
58 int
59 read_client_conf(void)
60 {
61         FILE                    *cfile;
62         char                    *val;
63         int                      token;
64         struct client_config    *config;
65
66         new_parse(path_dhclient_conf);
67
68         /* Set up the initial dhcp option universe. */
69         initialize_universes();
70
71         /* Initialize the top level client configuration. */
72         memset(&top_level_config, 0, sizeof(top_level_config));
73
74         /* Set some defaults... */
75         top_level_config.timeout = 60;
76         top_level_config.select_interval = 0;
77         top_level_config.reboot_timeout = 10;
78         top_level_config.retry_interval = 300;
79         top_level_config.backoff_cutoff = 15;
80         top_level_config.initial_interval = 3;
81         top_level_config.bootp_policy = ACCEPT;
82         top_level_config.script_name = client_script_name;
83         top_level_config.requested_options
84             [top_level_config.requested_option_count++] = DHO_SUBNET_MASK;
85         top_level_config.requested_options
86             [top_level_config.requested_option_count++] = DHO_BROADCAST_ADDRESS;
87         top_level_config.requested_options
88             [top_level_config.requested_option_count++] = DHO_TIME_OFFSET;
89         top_level_config.requested_options
90             [top_level_config.requested_option_count++] = DHO_ROUTERS;
91         top_level_config.requested_options
92             [top_level_config.requested_option_count++] = DHO_DOMAIN_NAME;
93         top_level_config.requested_options
94             [top_level_config.requested_option_count++] =
95             DHO_DOMAIN_NAME_SERVERS;
96         top_level_config.requested_options
97             [top_level_config.requested_option_count++] = DHO_HOST_NAME;
98
99         if ((cfile = fopen(path_dhclient_conf, "r")) != NULL) {
100                 do {
101                         token = peek_token(&val, cfile);
102                         if (token == EOF)
103                                 break;
104                         parse_client_statement(cfile, NULL, &top_level_config);
105                 } while (1);
106                 token = next_token(&val, cfile); /* Clear the peek buffer */
107                 fclose(cfile);
108         }
109
110         /*
111          * Set up state and config structures for clients that don't
112          * have per-interface configuration declarations.
113          */
114         config = NULL;
115         if (!ifi->client) {
116                 ifi->client = malloc(sizeof(struct client_state));
117                 if (!ifi->client)
118                         error("no memory for client state.");
119                 memset(ifi->client, 0, sizeof(*(ifi->client)));
120         }
121         if (!ifi->client->config) {
122                 if (!config) {
123                         config = malloc(sizeof(struct client_config));
124                         if (!config)
125                                 error("no memory for client config.");
126                         memcpy(config, &top_level_config,
127                                 sizeof(top_level_config));
128                 }
129                 ifi->client->config = config;
130         }
131
132         return (!warnings_occurred);
133 }
134
135 /*
136  * lease-file :== client-lease-statements EOF
137  * client-lease-statements :== <nil>
138  *                   | client-lease-statements LEASE client-lease-statement
139  */
140 void
141 read_client_leases(void)
142 {
143         FILE    *cfile;
144         char    *val;
145         int      token;
146
147         new_parse(path_dhclient_db);
148
149         /* Open the lease file.   If we can't open it, just return -
150            we can safely trust the server to remember our state. */
151         if ((cfile = fopen(path_dhclient_db, "r")) == NULL)
152                 return;
153         do {
154                 token = next_token(&val, cfile);
155                 if (token == EOF)
156                         break;
157                 if (token != LEASE) {
158                         warning("Corrupt lease file - possible data loss!");
159                         skip_to_semi(cfile);
160                         break;
161                 } else
162                         parse_client_lease_statement(cfile, 0);
163
164         } while (1);
165         fclose(cfile);
166 }
167
168 /*
169  * client-declaration :==
170  *      SEND option-decl |
171  *      DEFAULT option-decl |
172  *      SUPERSEDE option-decl |
173  *      PREPEND option-decl |
174  *      APPEND option-decl |
175  *      hardware-declaration |
176  *      REQUEST option-list |
177  *      REQUIRE option-list |
178  *      TIMEOUT number |
179  *      RETRY number |
180  *      REBOOT number |
181  *      SELECT_TIMEOUT number |
182  *      SCRIPT string |
183  *      interface-declaration |
184  *      LEASE client-lease-statement |
185  *      ALIAS client-lease-statement
186  */
187 void
188 parse_client_statement(FILE *cfile, struct interface_info *ip,
189     struct client_config *config)
190 {
191         int              token;
192         char            *val;
193         struct option   *option;
194
195         switch (next_token(&val, cfile)) {
196         case SEND:
197                 parse_option_decl(cfile, &config->send_options[0]);
198                 return;
199         case DEFAULT:
200                 option = parse_option_decl(cfile, &config->defaults[0]);
201                 if (option)
202                         config->default_actions[option->code] = ACTION_DEFAULT;
203                 return;
204         case SUPERSEDE:
205                 option = parse_option_decl(cfile, &config->defaults[0]);
206                 if (option)
207                         config->default_actions[option->code] =
208                             ACTION_SUPERSEDE;
209                 return;
210         case APPEND:
211                 option = parse_option_decl(cfile, &config->defaults[0]);
212                 if (option)
213                         config->default_actions[option->code] = ACTION_APPEND;
214                 return;
215         case PREPEND:
216                 option = parse_option_decl(cfile, &config->defaults[0]);
217                 if (option)
218                         config->default_actions[option->code] = ACTION_PREPEND;
219                 return;
220         case MEDIA:
221                 parse_string_list(cfile, &config->media, 1);
222                 return;
223         case HARDWARE:
224                 if (ip)
225                         parse_hardware_param(cfile, &ip->hw_address);
226                 else {
227                         parse_warn("hardware address parameter %s",
228                                     "not allowed here.");
229                         skip_to_semi(cfile);
230                 }
231                 return;
232         case REQUEST:
233                 config->requested_option_count =
234                         parse_option_list(cfile, config->requested_options);
235                 return;
236         case REQUIRE:
237                 memset(config->required_options, 0,
238                     sizeof(config->required_options));
239                 parse_option_list(cfile, config->required_options);
240                 return;
241         case TIMEOUT:
242                 parse_lease_time(cfile, &config->timeout);
243                 return;
244         case RETRY:
245                 parse_lease_time(cfile, &config->retry_interval);
246                 return;
247         case SELECT_TIMEOUT:
248                 parse_lease_time(cfile, &config->select_interval);
249                 return;
250         case REBOOT:
251                 parse_lease_time(cfile, &config->reboot_timeout);
252                 return;
253         case BACKOFF_CUTOFF:
254                 parse_lease_time(cfile, &config->backoff_cutoff);
255                 return;
256         case INITIAL_INTERVAL:
257                 parse_lease_time(cfile, &config->initial_interval);
258                 return;
259         case SCRIPT:
260                 config->script_name = parse_string(cfile);
261                 return;
262         case INTERFACE:
263                 if (ip)
264                         parse_warn("nested interface declaration.");
265                 parse_interface_declaration(cfile, config);
266                 return;
267         case LEASE:
268                 parse_client_lease_statement(cfile, 1);
269                 return;
270         case ALIAS:
271                 parse_client_lease_statement(cfile, 2);
272                 return;
273         case REJECT:
274                 parse_reject_statement(cfile, config);
275                 return;
276         default:
277                 parse_warn("expecting a statement.");
278                 skip_to_semi(cfile);
279                 break;
280         }
281         token = next_token(&val, cfile);
282         if (token != SEMI) {
283                 parse_warn("semicolon expected.");
284                 skip_to_semi(cfile);
285         }
286 }
287
288 int
289 parse_X(FILE *cfile, u_int8_t *buf, int max)
290 {
291         int      token;
292         char    *val;
293         int      len;
294
295         token = peek_token(&val, cfile);
296         if (token == NUMBER_OR_NAME || token == NUMBER) {
297                 len = 0;
298                 do {
299                         token = next_token(&val, cfile);
300                         if (token != NUMBER && token != NUMBER_OR_NAME) {
301                                 parse_warn("expecting hexadecimal constant.");
302                                 skip_to_semi(cfile);
303                                 return (0);
304                         }
305                         convert_num(&buf[len], val, 16, 8);
306                         if (len++ > max) {
307                                 parse_warn("hexadecimal constant too long.");
308                                 skip_to_semi(cfile);
309                                 return (0);
310                         }
311                         token = peek_token(&val, cfile);
312                         if (token == COLON)
313                                 token = next_token(&val, cfile);
314                 } while (token == COLON);
315                 val = (char *)buf;
316         } else if (token == STRING) {
317                 token = next_token(&val, cfile);
318                 len = strlen(val);
319                 if (len + 1 > max) {
320                         parse_warn("string constant too long.");
321                         skip_to_semi(cfile);
322                         return (0);
323                 }
324                 memcpy(buf, val, len + 1);
325         } else {
326                 parse_warn("expecting string or hexadecimal data");
327                 skip_to_semi(cfile);
328                 return (0);
329         }
330         return (len);
331 }
332
333 /*
334  * option-list :== option_name |
335  *                 option_list COMMA option_name
336  */
337 int
338 parse_option_list(FILE *cfile, u_int8_t *list)
339 {
340         int      ix, i;
341         int      token;
342         char    *val;
343
344         ix = 0;
345         do {
346                 token = next_token(&val, cfile);
347                 if (!is_identifier(token)) {
348                         parse_warn("expected option name.");
349                         skip_to_semi(cfile);
350                         return (0);
351                 }
352                 for (i = 0; i < 256; i++)
353                         if (!strcasecmp(dhcp_options[i].name, val))
354                                 break;
355
356                 if (i == 256) {
357                         parse_warn("%s: unexpected option name.", val);
358                         skip_to_semi(cfile);
359                         return (0);
360                 }
361                 list[ix++] = i;
362                 if (ix == 256) {
363                         parse_warn("%s: too many options.", val);
364                         skip_to_semi(cfile);
365                         return (0);
366                 }
367                 token = next_token(&val, cfile);
368         } while (token == COMMA);
369         if (token != SEMI) {
370                 parse_warn("expecting semicolon.");
371                 skip_to_semi(cfile);
372                 return (0);
373         }
374         return (ix);
375 }
376
377 /*
378  * interface-declaration :==
379  *      INTERFACE string LBRACE client-declarations RBRACE
380  */
381 void
382 parse_interface_declaration(FILE *cfile, struct client_config *outer_config)
383 {
384         int                      token;
385         char                    *val;
386         struct interface_info   *ip;
387
388         token = next_token(&val, cfile);
389         if (token != STRING) {
390                 parse_warn("expecting interface name (in quotes).");
391                 skip_to_semi(cfile);
392                 return;
393         }
394
395         ip = interface_or_dummy(val);
396
397         if (!ip->client)
398                 make_client_state(ip);
399
400         if (!ip->client->config)
401                 make_client_config(ip, outer_config);
402
403         token = next_token(&val, cfile);
404         if (token != LBRACE) {
405                 parse_warn("expecting left brace.");
406                 skip_to_semi(cfile);
407                 return;
408         }
409
410         do {
411                 token = peek_token(&val, cfile);
412                 if (token == EOF) {
413                         parse_warn("unterminated interface declaration.");
414                         return;
415                 }
416                 if (token == RBRACE)
417                         break;
418                 parse_client_statement(cfile, ip, ip->client->config);
419         } while (1);
420         token = next_token(&val, cfile);
421 }
422
423 struct interface_info *
424 interface_or_dummy(char *name)
425 {
426         struct interface_info   *ip;
427
428         /* Find the interface (if any) that matches the name. */
429         if (!strcmp(ifi->name, name))
430                 return (ifi);
431
432         /* If it's not a real interface, see if it's on the dummy list. */
433         for (ip = dummy_interfaces; ip; ip = ip->next)
434                 if (!strcmp(ip->name, name))
435                         return (ip);
436
437         /*
438          * If we didn't find an interface, make a dummy interface as a
439          * placeholder.
440          */
441         ip = malloc(sizeof(*ip));
442         if (!ip)
443                 error("Insufficient memory to record interface %s", name);
444         memset(ip, 0, sizeof(*ip));
445         strlcpy(ip->name, name, IFNAMSIZ);
446         ip->next = dummy_interfaces;
447         dummy_interfaces = ip;
448         return (ip);
449 }
450
451 void
452 make_client_state(struct interface_info *ip)
453 {
454         ip->client = malloc(sizeof(*(ip->client)));
455         if (!ip->client)
456                 error("no memory for state on %s", ip->name);
457         memset(ip->client, 0, sizeof(*(ip->client)));
458 }
459
460 void
461 make_client_config(struct interface_info *ip, struct client_config *config)
462 {
463         ip->client->config = malloc(sizeof(struct client_config));
464         if (!ip->client->config)
465                 error("no memory for config for %s", ip->name);
466         memset(ip->client->config, 0, sizeof(*(ip->client->config)));
467         memcpy(ip->client->config, config, sizeof(*config));
468 }
469
470 /*
471  * client-lease-statement :==
472  *      RBRACE client-lease-declarations LBRACE
473  *
474  *      client-lease-declarations :==
475  *              <nil> |
476  *              client-lease-declaration |
477  *              client-lease-declarations client-lease-declaration
478  */
479 void
480 parse_client_lease_statement(FILE *cfile, int is_static)
481 {
482         struct client_lease     *lease, *lp, *pl;
483         struct interface_info   *ip;
484         int                      token;
485         char                    *val;
486
487         token = next_token(&val, cfile);
488         if (token != LBRACE) {
489                 parse_warn("expecting left brace.");
490                 skip_to_semi(cfile);
491                 return;
492         }
493
494         lease = malloc(sizeof(struct client_lease));
495         if (!lease)
496                 error("no memory for lease.");
497         memset(lease, 0, sizeof(*lease));
498         lease->is_static = is_static;
499
500         ip = NULL;
501
502         do {
503                 token = peek_token(&val, cfile);
504                 if (token == EOF) {
505                         parse_warn("unterminated lease declaration.");
506                         return;
507                 }
508                 if (token == RBRACE)
509                         break;
510                 parse_client_lease_declaration(cfile, lease, &ip);
511         } while (1);
512         token = next_token(&val, cfile);
513
514         /* If the lease declaration didn't include an interface
515          * declaration that we recognized, it's of no use to us.
516          */
517         if (!ip) {
518                 free_client_lease(lease);
519                 return;
520         }
521
522         /* Make sure there's a client state structure... */
523         if (!ip->client)
524                 make_client_state(ip);
525
526         /* If this is an alias lease, it doesn't need to be sorted in. */
527         if (is_static == 2) {
528                 ip->client->alias = lease;
529                 return;
530         }
531
532         /*
533          * The new lease may supersede a lease that's not the active
534          * lease but is still on the lease list, so scan the lease list
535          * looking for a lease with the same address, and if we find it,
536          * toss it.
537          */
538         pl = NULL;
539         for (lp = ip->client->leases; lp; lp = lp->next) {
540                 if (lp->address.len == lease->address.len &&
541                     !memcmp(lp->address.iabuf, lease->address.iabuf,
542                     lease->address.len)) {
543                         if (pl)
544                                 pl->next = lp->next;
545                         else
546                                 ip->client->leases = lp->next;
547                         free_client_lease(lp);
548                         break;
549                 }
550         }
551
552         /*
553          * If this is a preloaded lease, just put it on the list of
554          * recorded leases - don't make it the active lease.
555          */
556         if (is_static) {
557                 lease->next = ip->client->leases;
558                 ip->client->leases = lease;
559                 return;
560         }
561
562         /*
563          * The last lease in the lease file on a particular interface is
564          * the active lease for that interface.    Of course, we don't
565          * know what the last lease in the file is until we've parsed
566          * the whole file, so at this point, we assume that the lease we
567          * just parsed is the active lease for its interface.   If
568          * there's already an active lease for the interface, and this
569          * lease is for the same ip address, then we just toss the old
570          * active lease and replace it with this one.   If this lease is
571          * for a different address, then if the old active lease has
572          * expired, we dump it; if not, we put it on the list of leases
573          * for this interface which are still valid but no longer
574          * active.
575          */
576         if (ip->client->active) {
577                 if (ip->client->active->expiry < cur_time)
578                         free_client_lease(ip->client->active);
579                 else if (ip->client->active->address.len ==
580                     lease->address.len &&
581                     !memcmp(ip->client->active->address.iabuf,
582                     lease->address.iabuf, lease->address.len))
583                         free_client_lease(ip->client->active);
584                 else {
585                         ip->client->active->next = ip->client->leases;
586                         ip->client->leases = ip->client->active;
587                 }
588         }
589         ip->client->active = lease;
590
591         /* Phew. */
592 }
593
594 /*
595  * client-lease-declaration :==
596  *      BOOTP |
597  *      INTERFACE string |
598  *      FIXED_ADDR ip_address |
599  *      FILENAME string |
600  *      SERVER_NAME string |
601  *      OPTION option-decl |
602  *      RENEW time-decl |
603  *      REBIND time-decl |
604  *      EXPIRE time-decl
605  */
606 void
607 parse_client_lease_declaration(FILE *cfile, struct client_lease *lease,
608     struct interface_info **ipp)
609 {
610         int                      token;
611         char                    *val;
612         struct interface_info   *ip;
613
614         switch (next_token(&val, cfile)) {
615         case BOOTP:
616                 lease->is_bootp = 1;
617                 break;
618         case INTERFACE:
619                 token = next_token(&val, cfile);
620                 if (token != STRING) {
621                         parse_warn("expecting interface name (in quotes).");
622                         skip_to_semi(cfile);
623                         break;
624                 }
625                 ip = interface_or_dummy(val);
626                 *ipp = ip;
627                 break;
628         case FIXED_ADDR:
629                 if (!parse_ip_addr(cfile, &lease->address))
630                         return;
631                 break;
632         case MEDIUM:
633                 parse_string_list(cfile, &lease->medium, 0);
634                 return;
635         case FILENAME:
636                 lease->filename = parse_string(cfile);
637                 return;
638         case SERVER_NAME:
639                 lease->server_name = parse_string(cfile);
640                 return;
641         case RENEW:
642                 lease->renewal = parse_date(cfile);
643                 return;
644         case REBIND:
645                 lease->rebind = parse_date(cfile);
646                 return;
647         case EXPIRE:
648                 lease->expiry = parse_date(cfile);
649                 return;
650         case OPTION:
651                 parse_option_decl(cfile, lease->options);
652                 return;
653         default:
654                 parse_warn("expecting lease declaration.");
655                 skip_to_semi(cfile);
656                 break;
657         }
658         token = next_token(&val, cfile);
659         if (token != SEMI) {
660                 parse_warn("expecting semicolon.");
661                 skip_to_semi(cfile);
662         }
663 }
664
665 struct option *
666 parse_option_decl(FILE *cfile, struct option_data *options)
667 {
668         char            *val;
669         int              token;
670         u_int8_t         buf[4];
671         u_int8_t         hunkbuf[1024];
672         int              hunkix = 0;
673         char            *vendor;
674         char            *fmt;
675         struct universe *universe;
676         struct option   *option;
677         struct iaddr     ip_addr;
678         u_int8_t        *dp;
679         int              len;
680         int              nul_term = 0;
681
682         token = next_token(&val, cfile);
683         if (!is_identifier(token)) {
684                 parse_warn("expecting identifier after option keyword.");
685                 if (token != SEMI)
686                         skip_to_semi(cfile);
687                 return (NULL);
688         }
689         if ((vendor = strdup(val)) == NULL)
690                 error("no memory for vendor information.");
691
692         token = peek_token(&val, cfile);
693         if (token == DOT) {
694                 /* Go ahead and take the DOT token... */
695                 token = next_token(&val, cfile);
696
697                 /* The next token should be an identifier... */
698                 token = next_token(&val, cfile);
699                 if (!is_identifier(token)) {
700                         parse_warn("expecting identifier after '.'");
701                         if (token != SEMI)
702                                 skip_to_semi(cfile);
703                         return (NULL);
704                 }
705
706                 /* Look up the option name hash table for the specified
707                    vendor. */
708                 universe = ((struct universe *)hash_lookup(&universe_hash,
709                     (unsigned char *)vendor, 0));
710                 /* If it's not there, we can't parse the rest of the
711                    declaration. */
712                 if (!universe) {
713                         parse_warn("no vendor named %s.", vendor);
714                         skip_to_semi(cfile);
715                         return (NULL);
716                 }
717         } else {
718                 /* Use the default hash table, which contains all the
719                    standard dhcp option names. */
720                 val = vendor;
721                 universe = &dhcp_universe;
722         }
723
724         /* Look up the actual option info... */
725         option = (struct option *)hash_lookup(universe->hash,
726             (unsigned char *)val, 0);
727
728         /* If we didn't get an option structure, it's an undefined option. */
729         if (!option) {
730                 if (val == vendor)
731                         parse_warn("no option named %s", val);
732                 else
733                         parse_warn("no option named %s for vendor %s",
734                                     val, vendor);
735                 skip_to_semi(cfile);
736                 return (NULL);
737         }
738
739         /* Free the initial identifier token. */
740         free(vendor);
741
742         /* Parse the option data... */
743         do {
744                 for (fmt = option->format; *fmt; fmt++) {
745                         if (*fmt == 'A')
746                                 break;
747                         switch (*fmt) {
748                         case 'X':
749                                 len = parse_X(cfile, &hunkbuf[hunkix],
750                                     sizeof(hunkbuf) - hunkix);
751                                 hunkix += len;
752                                 break;
753                         case 't': /* Text string... */
754                                 token = next_token(&val, cfile);
755                                 if (token != STRING) {
756                                         parse_warn("expecting string.");
757                                         skip_to_semi(cfile);
758                                         return (NULL);
759                                 }
760                                 len = strlen(val);
761                                 if (hunkix + len + 1 > sizeof(hunkbuf)) {
762                                         parse_warn("option data buffer %s",
763                                             "overflow");
764                                         skip_to_semi(cfile);
765                                         return (NULL);
766                                 }
767                                 memcpy(&hunkbuf[hunkix], val, len + 1);
768                                 nul_term = 1;
769                                 hunkix += len;
770                                 break;
771                         case 'I': /* IP address. */
772                                 if (!parse_ip_addr(cfile, &ip_addr))
773                                         return (NULL);
774                                 len = ip_addr.len;
775                                 dp = ip_addr.iabuf;
776 alloc:
777                                 if (hunkix + len > sizeof(hunkbuf)) {
778                                         parse_warn("option data buffer "
779                                             "overflow");
780                                         skip_to_semi(cfile);
781                                         return (NULL);
782                                 }
783                                 memcpy(&hunkbuf[hunkix], dp, len);
784                                 hunkix += len;
785                                 break;
786                         case 'L':       /* Unsigned 32-bit integer... */
787                         case 'l':       /* Signed 32-bit integer... */
788                                 token = next_token(&val, cfile);
789                                 if (token != NUMBER) {
790 need_number:
791                                         parse_warn("expecting number.");
792                                         if (token != SEMI)
793                                                 skip_to_semi(cfile);
794                                         return (NULL);
795                                 }
796                                 convert_num(buf, val, 0, 32);
797                                 len = 4;
798                                 dp = buf;
799                                 goto alloc;
800                         case 's':       /* Signed 16-bit integer. */
801                         case 'S':       /* Unsigned 16-bit integer. */
802                                 token = next_token(&val, cfile);
803                                 if (token != NUMBER)
804                                         goto need_number;
805                                 convert_num(buf, val, 0, 16);
806                                 len = 2;
807                                 dp = buf;
808                                 goto alloc;
809                         case 'b':       /* Signed 8-bit integer. */
810                         case 'B':       /* Unsigned 8-bit integer. */
811                                 token = next_token(&val, cfile);
812                                 if (token != NUMBER)
813                                         goto need_number;
814                                 convert_num(buf, val, 0, 8);
815                                 len = 1;
816                                 dp = buf;
817                                 goto alloc;
818                         case 'f': /* Boolean flag. */
819                                 token = next_token(&val, cfile);
820                                 if (!is_identifier(token)) {
821                                         parse_warn("expecting identifier.");
822 bad_flag:
823                                         if (token != SEMI)
824                                                 skip_to_semi(cfile);
825                                         return (NULL);
826                                 }
827                                 if (!strcasecmp(val, "true") ||
828                                     !strcasecmp(val, "on"))
829                                         buf[0] = 1;
830                                 else if (!strcasecmp(val, "false") ||
831                                     !strcasecmp(val, "off"))
832                                         buf[0] = 0;
833                                 else {
834                                         parse_warn("expecting boolean.");
835                                         goto bad_flag;
836                                 }
837                                 len = 1;
838                                 dp = buf;
839                                 goto alloc;
840                         default:
841                                 warning("Bad format %c in parse_option_param.",
842                                     *fmt);
843                                 skip_to_semi(cfile);
844                                 return (NULL);
845                         }
846                 }
847                 token = next_token(&val, cfile);
848         } while (*fmt == 'A' && token == COMMA);
849
850         if (token != SEMI) {
851                 parse_warn("semicolon expected.");
852                 skip_to_semi(cfile);
853                 return (NULL);
854         }
855
856         options[option->code].data = malloc(hunkix + nul_term);
857         if (!options[option->code].data)
858                 error("out of memory allocating option data.");
859         memcpy(options[option->code].data, hunkbuf, hunkix + nul_term);
860         options[option->code].len = hunkix;
861         return (option);
862 }
863
864 void
865 parse_string_list(FILE *cfile, struct string_list **lp, int multiple)
866 {
867         int                      token;
868         char                    *val;
869         struct string_list      *cur, *tmp;
870
871         /* Find the last medium in the media list. */
872         if (*lp)
873                 for (cur = *lp; cur->next; cur = cur->next)
874                         ;       /* nothing */
875         else
876                 cur = NULL;
877
878         do {
879                 token = next_token(&val, cfile);
880                 if (token != STRING) {
881                         parse_warn("Expecting media options.");
882                         skip_to_semi(cfile);
883                         return;
884                 }
885
886                 tmp = new_string_list(strlen(val) + 1);
887                 if (tmp == NULL)
888                         error("no memory for string list entry.");
889                 strlcpy(tmp->string, val, strlen(val) + 1);
890                 tmp->next = NULL;
891
892                 /* Store this medium at the end of the media list. */
893                 if (cur)
894                         cur->next = tmp;
895                 else
896                         *lp = tmp;
897                 cur = tmp;
898
899                 token = next_token(&val, cfile);
900         } while (multiple && token == COMMA);
901
902         if (token != SEMI) {
903                 parse_warn("expecting semicolon.");
904                 skip_to_semi(cfile);
905         }
906 }
907
908 void
909 parse_reject_statement(FILE *cfile, struct client_config *config)
910 {
911         int                      token;
912         char                    *val;
913         struct iaddr             addr;
914         struct iaddrlist        *list;
915
916         do {
917                 if (!parse_ip_addr(cfile, &addr)) {
918                         parse_warn("expecting IP address.");
919                         skip_to_semi(cfile);
920                         return;
921                 }
922
923                 list = malloc(sizeof(struct iaddrlist));
924                 if (!list)
925                         error("no memory for reject list!");
926
927                 list->addr = addr;
928                 list->next = config->reject_list;
929                 config->reject_list = list;
930
931                 token = next_token(&val, cfile);
932         } while (token == COMMA);
933
934         if (token != SEMI) {
935                 parse_warn("expecting semicolon.");
936                 skip_to_semi(cfile);
937         }
938 }