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