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