Initial import from FreeBSD RELENG_4:
[dragonfly.git] / contrib / isc-dhcp / client / clparse.c
1 /* clparse.c
2
3    Parser for dhclient config and lease files... */
4
5 /*
6  * Copyright (c) 1996-2002 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 in cooperation with Vixie Enterprises and Nominum, Inc.
38  * To learn more about the Internet Software Consortium, see
39  * ``http://www.isc.org/''.  To learn more about Vixie Enterprises,
40  * see ``http://www.vix.com''.   To learn more about Nominum, Inc., see
41  * ``http://www.nominum.com''.
42  */
43
44 #ifndef lint
45 static char copyright[] =
46 "$Id: clparse.c,v 1.62.2.3 2002/11/17 02:25:43 dhankins Exp $ Copyright (c) 1996-2002 The Internet Software Consortium.  All rights reserved.\n"
47 "$FreeBSD: src/contrib/isc-dhcp/client/clparse.c,v 1.4.2.4 2003/03/02 16:42:37 murray Exp $\n";
48 #endif /* not lint */
49
50 #include "dhcpd.h"
51
52 static TIME parsed_time;
53
54 struct client_config top_level_config;
55
56 char client_script_name [] = "/sbin/dhclient-script";
57
58 u_int32_t default_requested_options [] = {
59         DHO_SUBNET_MASK,
60         DHO_BROADCAST_ADDRESS,
61         DHO_TIME_OFFSET,
62         DHO_ROUTERS,
63         DHO_DOMAIN_NAME,
64         DHO_DOMAIN_NAME_SERVERS,
65         DHO_HOST_NAME,
66         0
67 };
68
69 /* client-conf-file :== client-declarations END_OF_FILE
70    client-declarations :== <nil>
71                          | client-declaration
72                          | client-declarations client-declaration */
73
74 isc_result_t read_client_conf ()
75 {
76         struct client_config *config;
77         struct client_state *state;
78         struct interface_info *ip;
79         isc_result_t status;
80
81         /* Set up the initial dhcp option universe. */
82         initialize_common_option_spaces ();
83
84         /* Initialize the top level client configuration. */
85         memset (&top_level_config, 0, sizeof top_level_config);
86
87         /* Set some defaults... */
88         top_level_config.timeout = 60;
89         top_level_config.select_interval = 0;
90         top_level_config.reboot_timeout = 10;
91         top_level_config.retry_interval = 300;
92         top_level_config.backoff_cutoff = 15;
93         top_level_config.initial_interval = 3;
94         top_level_config.bootp_policy = P_ACCEPT;
95         top_level_config.script_name = path_dhclient_script;
96         top_level_config.requested_options = default_requested_options;
97         top_level_config.omapi_port = -1;
98         top_level_config.do_forward_update = 1;
99
100         group_allocate (&top_level_config.on_receipt, MDL);
101         if (!top_level_config.on_receipt)
102                 log_fatal ("no memory for top-level on_receipt group");
103
104         group_allocate (&top_level_config.on_transmission, MDL);
105         if (!top_level_config.on_transmission)
106                 log_fatal ("no memory for top-level on_transmission group");
107
108         status = read_client_conf_file (path_dhclient_conf,
109                                         (struct interface_info *)0,
110                                         &top_level_config);
111         if (status != ISC_R_SUCCESS) {
112                 ;
113 #ifdef LATER
114                 /* Set up the standard name service updater routine. */
115                 parse = (struct parse *)0;
116                 status = new_parse (&parse, -1, default_client_config,
117                                     (sizeof default_client_config) - 1,
118                                     "default client configuration", 0);
119                 if (status != ISC_R_SUCCESS)
120                         log_fatal ("can't begin default client config!");
121
122                 do {
123                         token = peek_token (&val, (unsigned *)0, cfile);
124                         if (token == END_OF_FILE)
125                                 break;
126                         parse_client_statement (cfile,
127                                                 (struct interface_info *)0,
128                                                 &top_level_config);
129                 } while (1);
130                 end_parse (&parse);
131 #endif
132         }
133
134         /* Set up state and config structures for clients that don't
135            have per-interface configuration statements. */
136         config = (struct client_config *)0;
137         for (ip = interfaces; ip; ip = ip -> next) {
138                 if (!ip -> client) {
139                         ip -> client = (struct client_state *)
140                                 dmalloc (sizeof (struct client_state), MDL);
141                         if (!ip -> client)
142                                 log_fatal ("no memory for client state.");
143                         memset (ip -> client, 0, sizeof *(ip -> client));
144                         ip -> client -> interface = ip;
145                 }
146
147                 if (!ip -> client -> config) {
148                         if (!config) {
149                                 config = (struct client_config *)
150                                         dmalloc (sizeof (struct client_config),
151                                                  MDL);
152                                 if (!config)
153                                     log_fatal ("no memory for client config.");
154                                 memcpy (config, &top_level_config,
155                                         sizeof top_level_config);
156                         }
157                         ip -> client -> config = config;
158                 }
159         }
160         return status;
161 }
162
163 int read_client_conf_file (const char *name, struct interface_info *ip,
164                            struct client_config *client)
165 {
166         int file;
167         struct parse *cfile;
168         const char *val;
169         int token;
170         isc_result_t status;
171         
172         if ((file = open (name, O_RDONLY)) < 0)
173                 return uerr2isc (errno);
174
175         cfile = (struct parse *)0;
176         new_parse (&cfile, file, (char *)0, 0, path_dhclient_conf, 0);
177
178         do {
179                 token = peek_token (&val, (unsigned *)0, cfile);
180                 if (token == END_OF_FILE)
181                         break;
182                 parse_client_statement (cfile, ip, client);
183         } while (1);
184         token = next_token (&val, (unsigned *)0, cfile);
185         status = (cfile -> warnings_occurred
186                   ? ISC_R_BADPARSE
187                   : ISC_R_SUCCESS);
188         close (file);
189         end_parse (&cfile);
190         return status;
191 }
192
193
194 /* lease-file :== client-lease-statements END_OF_FILE
195    client-lease-statements :== <nil>
196                      | client-lease-statements LEASE client-lease-statement */
197
198 void read_client_leases ()
199 {
200         int file;
201         struct parse *cfile;
202         const char *val;
203         int token;
204
205         /* Open the lease file.   If we can't open it, just return -
206            we can safely trust the server to remember our state. */
207         if ((file = open (path_dhclient_db, O_RDONLY)) < 0)
208                 return;
209         cfile = (struct parse *)0;
210         new_parse (&cfile, file, (char *)0, 0, path_dhclient_db, 0);
211
212         do {
213                 token = next_token (&val, (unsigned *)0, cfile);
214                 if (token == END_OF_FILE)
215                         break;
216                 if (token != LEASE) {
217                         log_error ("Corrupt lease file - possible data loss!");
218                         skip_to_semi (cfile);
219                         break;
220                 } else
221                         parse_client_lease_statement (cfile, 0);
222
223         } while (1);
224
225         close (file);
226         end_parse (&cfile);
227 }
228
229 /* client-declaration :== 
230         SEND option-decl |
231         DEFAULT option-decl |
232         SUPERSEDE option-decl |
233         PREPEND option-decl |
234         APPEND option-decl |
235         hardware-declaration |
236         REQUEST option-list |
237         REQUIRE option-list |
238         TIMEOUT number |
239         RETRY number |
240         REBOOT number |
241         SELECT_TIMEOUT number |
242         SCRIPT string |
243         VENDOR_SPACE string |
244         interface-declaration |
245         LEASE client-lease-statement |
246         ALIAS client-lease-statement |
247         KEY key-definition */
248
249 void parse_client_statement (cfile, ip, config)
250         struct parse *cfile;
251         struct interface_info *ip;
252         struct client_config *config;
253 {
254         int token;
255         const char *val;
256         struct option *option;
257         struct executable_statement *stmt, **p;
258         enum statement_op op;
259         int lose;
260         char *name;
261         struct data_string key_id;
262         enum policy policy;
263         int known;
264         int tmp, i;
265         isc_result_t status;
266
267         switch (peek_token (&val, (unsigned *)0, cfile)) {
268               case INCLUDE:
269                 next_token (&val, (unsigned *)0, cfile);
270                 token = next_token (&val, (unsigned *)0, cfile);
271                 if (token != STRING) {
272                         parse_warn (cfile, "filename string expected.");
273                         skip_to_semi (cfile);
274                 } else {
275                         status = read_client_conf_file (val, ip, config);
276                         if (status != ISC_R_SUCCESS)
277                                 parse_warn (cfile, "%s: bad parse.", val);
278                         parse_semi (cfile);
279                 }
280                 return;
281                 
282               case KEY:
283                 next_token (&val, (unsigned *)0, cfile);
284                 if (ip) {
285                         /* This may seem arbitrary, but there's a reason for
286                            doing it: the authentication key database is not
287                            scoped.  If we allow the user to declare a key other
288                            than in the outer scope, the user is very likely to
289                            believe that the key will only be used in that
290                            scope.  If the user only wants the key to be used on
291                            one interface, because it's known that the other
292                            interface may be connected to an insecure net and
293                            the secret key is considered sensitive, we don't
294                            want to lull them into believing they've gotten
295                            their way.   This is a bit contrived, but people
296                            tend not to be entirely rational about security. */
297                         parse_warn (cfile, "key definition not allowed here.");
298                         skip_to_semi (cfile);
299                         break;
300                 }
301                 parse_key (cfile);
302                 return;
303
304                 /* REQUIRE can either start a policy statement or a
305                    comma-seperated list of names of required options. */
306               case REQUIRE:
307                 next_token (&val, (unsigned *)0, cfile);
308                 token = peek_token (&val, (unsigned *)0, cfile);
309                 if (token == AUTHENTICATION) {
310                         policy = P_REQUIRE;
311                         goto do_policy;
312                 }
313                 parse_option_list (cfile, &config -> required_options);
314                 return;
315
316               case IGNORE:
317                 next_token (&val, (unsigned *)0, cfile);
318                 policy = P_IGNORE;
319                 goto do_policy;
320
321               case ACCEPT:
322                 next_token (&val, (unsigned *)0, cfile);
323                 policy = P_ACCEPT;
324                 goto do_policy;
325
326               case PREFER:
327                 next_token (&val, (unsigned *)0, cfile);
328                 policy = P_PREFER;
329                 goto do_policy;
330
331               case DONT:
332                 next_token (&val, (unsigned *)0, cfile);
333                 policy = P_DONT;
334                 goto do_policy;
335
336               do_policy:
337                 token = next_token (&val, (unsigned *)0, cfile);
338                 if (token == AUTHENTICATION) {
339                         if (policy != P_PREFER &&
340                             policy != P_REQUIRE &&
341                             policy != P_DONT) {
342                                 parse_warn (cfile,
343                                             "invalid authentication policy.");
344                                 skip_to_semi (cfile);
345                                 return;
346                         }
347                         config -> auth_policy = policy;
348                 } else if (token != TOKEN_BOOTP) {
349                         if (policy != P_PREFER &&
350                             policy != P_IGNORE &&
351                             policy != P_ACCEPT) {
352                                 parse_warn (cfile, "invalid bootp policy.");
353                                 skip_to_semi (cfile);
354                                 return;
355                         }
356                         config -> bootp_policy = policy;
357                 } else {
358                         parse_warn (cfile, "expecting a policy type.");
359                         skip_to_semi (cfile);
360                         return;
361                 } 
362                 break;
363
364               case OPTION:
365                 token = next_token (&val, (unsigned *)0, cfile);
366
367                 token = peek_token (&val, (unsigned *)0, cfile);
368                 if (token == SPACE) {
369                         if (ip) {
370                                 parse_warn (cfile,
371                                             "option space definitions %s",
372                                             " may not be scoped.");
373                                 skip_to_semi (cfile);
374                                 break;
375                         }
376                         parse_option_space_decl (cfile);
377                         return;
378                 }
379
380                 option = parse_option_name (cfile, 1, &known);
381                 if (!option)
382                         return;
383
384                 token = next_token (&val, (unsigned *)0, cfile);
385                 if (token != CODE) {
386                         parse_warn (cfile, "expecting \"code\" keyword.");
387                         skip_to_semi (cfile);
388                         free_option (option, MDL);
389                         return;
390                 }
391                 if (ip) {
392                         parse_warn (cfile,
393                                     "option definitions may only appear in %s",
394                                     "the outermost scope.");
395                         skip_to_semi (cfile);
396                         free_option (option, MDL);
397                         return;
398                 }
399                 if (!parse_option_code_definition (cfile, option))
400                         free_option (option, MDL);
401                 return;
402
403               case MEDIA:
404                 token = next_token (&val, (unsigned *)0, cfile);
405                 parse_string_list (cfile, &config -> media, 1);
406                 return;
407
408               case HARDWARE:
409                 token = next_token (&val, (unsigned *)0, cfile);
410                 if (ip) {
411                         parse_hardware_param (cfile, &ip -> hw_address);
412                 } else {
413                         parse_warn (cfile, "hardware address parameter %s",
414                                     "not allowed here.");
415                         skip_to_semi (cfile);
416                 }
417                 return;
418
419               case REQUEST:
420                 token = next_token (&val, (unsigned *)0, cfile);
421                 if (config -> requested_options == default_requested_options)
422                         config -> requested_options = (u_int32_t *)0;
423                 parse_option_list (cfile, &config -> requested_options);
424                 return;
425
426               case TIMEOUT:
427                 token = next_token (&val, (unsigned *)0, cfile);
428                 parse_lease_time (cfile, &config -> timeout);
429                 return;
430
431               case RETRY:
432                 token = next_token (&val, (unsigned *)0, cfile);
433                 parse_lease_time (cfile, &config -> retry_interval);
434                 return;
435
436               case SELECT_TIMEOUT:
437                 token = next_token (&val, (unsigned *)0, cfile);
438                 parse_lease_time (cfile, &config -> select_interval);
439                 return;
440
441               case OMAPI:
442                 token = next_token (&val, (unsigned *)0, cfile);
443                 token = next_token (&val, (unsigned *)0, cfile);
444                 if (token != PORT) {
445                         parse_warn (cfile,
446                                     "unexpected omapi subtype: %s", val);
447                         skip_to_semi (cfile);
448                         return;
449                 }
450                 token = next_token (&val, (unsigned *)0, cfile);
451                 if (token != NUMBER) {
452                         parse_warn (cfile, "invalid port number: `%s'", val);
453                         skip_to_semi (cfile);
454                         return;
455                 }
456                 tmp = atoi (val);
457                 if (tmp < 0 || tmp > 65535)
458                         parse_warn (cfile, "invalid omapi port %d.", tmp);
459                 else if (config != &top_level_config)
460                         parse_warn (cfile,
461                                     "omapi port only works at top level.");
462                 else
463                         config -> omapi_port = tmp;
464                 parse_semi (cfile);
465                 return;
466                 
467               case DO_FORWARD_UPDATE:
468                 token = next_token (&val, (unsigned *)0, cfile);
469                 token = next_token (&val, (unsigned *)0, cfile);
470                 if (!strcasecmp (val, "on") ||
471                     !strcasecmp (val, "true"))
472                         config -> do_forward_update = 1;
473                 else if (!strcasecmp (val, "off") ||
474                          !strcasecmp (val, "false"))
475                         config -> do_forward_update = 0;
476                 else {
477                         parse_warn (cfile, "expecting boolean value.");
478                         skip_to_semi (cfile);
479                         return;
480                 }
481                 parse_semi (cfile);
482                 return;
483
484               case REBOOT:
485                 token = next_token (&val, (unsigned *)0, cfile);
486                 parse_lease_time (cfile, &config -> reboot_timeout);
487                 return;
488
489               case BACKOFF_CUTOFF:
490                 token = next_token (&val, (unsigned *)0, cfile);
491                 parse_lease_time (cfile, &config -> backoff_cutoff);
492                 return;
493
494               case INITIAL_INTERVAL:
495                 token = next_token (&val, (unsigned *)0, cfile);
496                 parse_lease_time (cfile, &config -> initial_interval);
497                 return;
498
499               case SCRIPT:
500                 token = next_token (&val, (unsigned *)0, cfile);
501                 parse_string (cfile, &config -> script_name, (unsigned *)0);
502                 return;
503
504               case VENDOR:
505                 token = next_token (&val, (unsigned *)0, cfile);
506                 token = next_token (&val, (unsigned *)0, cfile);
507                 if (token != OPTION) {
508                         parse_warn (cfile, "expecting 'vendor option space'");
509                         skip_to_semi (cfile);
510                         return;
511                 }
512                 token = next_token (&val, (unsigned *)0, cfile);
513                 if (token != SPACE) {
514                         parse_warn (cfile, "expecting 'vendor option space'");
515                         skip_to_semi (cfile);
516                         return;
517                 }
518                 token = next_token (&val, (unsigned *)0, cfile);
519                 if (!is_identifier (token)) {
520                         parse_warn (cfile, "expecting an identifier.");
521                         skip_to_semi (cfile);
522                         return;
523                 }
524                 config -> vendor_space_name = dmalloc (strlen (val) + 1, MDL);
525                 if (!config -> vendor_space_name)
526                         log_fatal ("no memory for vendor option space name.");
527                 strcpy (config -> vendor_space_name, val);
528                 for (i = 0; i < universe_count; i++)
529                         if (!strcmp (universes [i] -> name,
530                                      config -> vendor_space_name))
531                                 break;
532                 if (i == universe_count) {
533                         log_error ("vendor option space %s not found.",
534                                    config -> vendor_space_name);
535                 }
536                 parse_semi (cfile);
537                 return;
538
539               case INTERFACE:
540                 token = next_token (&val, (unsigned *)0, cfile);
541                 if (ip)
542                         parse_warn (cfile, "nested interface declaration.");
543                 parse_interface_declaration (cfile, config, (char *)0);
544                 return;
545
546               case PSEUDO:
547                 token = next_token (&val, (unsigned *)0, cfile);
548                 token = next_token (&val, (unsigned *)0, cfile);
549                 name = dmalloc (strlen (val) + 1, MDL);
550                 if (!name)
551                         log_fatal ("no memory for pseudo interface name");
552                 strcpy (name, val);
553                 parse_interface_declaration (cfile, config, name);
554                 return;
555                 
556               case LEASE:
557                 token = next_token (&val, (unsigned *)0, cfile);
558                 parse_client_lease_statement (cfile, 1);
559                 return;
560
561               case ALIAS:
562                 token = next_token (&val, (unsigned *)0, cfile);
563                 parse_client_lease_statement (cfile, 2);
564                 return;
565
566               case REJECT:
567                 token = next_token (&val, (unsigned *)0, cfile);
568                 parse_reject_statement (cfile, config);
569                 return;
570
571               default:
572                 lose = 0;
573                 stmt = (struct executable_statement *)0;
574                 if (!parse_executable_statement (&stmt,
575                                                  cfile, &lose, context_any)) {
576                         if (!lose) {
577                                 parse_warn (cfile, "expecting a statement.");
578                                 skip_to_semi (cfile);
579                         }
580                 } else {
581                         struct executable_statement **eptr, *sptr;
582                         if (stmt &&
583                             (stmt -> op == send_option_statement ||
584                              (stmt -> op == on_statement &&
585                               (stmt -> data.on.evtypes & ON_TRANSMISSION)))) {
586                             eptr = &config -> on_transmission -> statements;
587                             if (stmt -> op == on_statement) {
588                                     sptr = (struct executable_statement *)0;
589                                     executable_statement_reference
590                                             (&sptr,
591                                              stmt -> data.on.statements, MDL);
592                                     executable_statement_dereference (&stmt,
593                                                                       MDL);
594                                     executable_statement_reference (&stmt,
595                                                                     sptr,
596                                                                     MDL);
597                                     executable_statement_dereference (&sptr,
598                                                                       MDL);
599                             }
600                         } else
601                             eptr = &config -> on_receipt -> statements;
602
603                         if (stmt) {
604                                 for (; *eptr; eptr = &(*eptr) -> next)
605                                         ;
606                                 executable_statement_reference (eptr,
607                                                                 stmt, MDL);
608                         }
609                         return;
610                 }
611                 break;
612         }
613         parse_semi (cfile);
614 }
615
616 /* option-list :== option_name |
617                    option_list COMMA option_name */
618
619 void parse_option_list (cfile, list)
620         struct parse *cfile;
621         u_int32_t **list;
622 {
623         int ix, i;
624         int token;
625         const char *val;
626         pair p = (pair)0, q, r;
627
628         ix = 0;
629         do {
630                 token = next_token (&val, (unsigned *)0, cfile);
631                 if (token == SEMI)
632                         break;
633                 if (!is_identifier (token)) {
634                         parse_warn (cfile, "%s: expected option name.", val);
635                         skip_to_semi (cfile);
636                         return;
637                 }
638                 for (i = 0; i < 256; i++) {
639                         if (!strcasecmp (dhcp_options [i].name, val))
640                                 break;
641                 }
642                 if (i == 256) {
643                         parse_warn (cfile, "%s: expected option name.", val);
644                         skip_to_semi (cfile);
645                         return;
646                 }
647                 r = new_pair (MDL);
648                 if (!r)
649                         log_fatal ("can't allocate pair for option code.");
650                 r -> car = (caddr_t)(long)i;
651                 r -> cdr = (pair)0;
652                 if (p)
653                         q -> cdr = r;
654                 else
655                         p = r;
656                 q = r;
657                 ++ix;
658                 token = next_token (&val, (unsigned *)0, cfile);
659         } while (token == COMMA);
660         if (token != SEMI) {
661                 parse_warn (cfile, "expecting semicolon.");
662                 skip_to_semi (cfile);
663                 return;
664         }
665         /* XXX we can't free the list here, because we may have copied
666            XXX it from an outer config state. */
667         *list = (u_int32_t *)0;
668         if (ix) {
669                 *list = dmalloc ((ix + 1) * sizeof **list, MDL);
670                 if (!*list)
671                         log_error ("no memory for option list.");
672                 else {
673                         ix = 0;
674                         for (q = p; q; q = q -> cdr)
675                                 (*list) [ix++] = (u_int32_t)(long)q -> car;
676                         (*list) [ix] = 0;
677                 }
678                 while (p) {
679                         q = p -> cdr;
680                         free_pair (p, MDL);
681                         p = q;
682                 }
683         }
684 }
685
686 /* interface-declaration :==
687         INTERFACE string LBRACE client-declarations RBRACE */
688
689 void parse_interface_declaration (cfile, outer_config, name)
690         struct parse *cfile;
691         struct client_config *outer_config;
692         char *name;
693 {
694         int token;
695         const char *val;
696         struct client_state *client, **cp;
697         struct interface_info *ip = (struct interface_info *)0;
698
699         token = next_token (&val, (unsigned *)0, cfile);
700         if (token != STRING) {
701                 parse_warn (cfile, "expecting interface name (in quotes).");
702                 skip_to_semi (cfile);
703                 return;
704         }
705
706         if (!interface_or_dummy (&ip, val))
707                 log_fatal ("Can't allocate interface %s.", val);
708
709         /* If we were given a name, this is a pseudo-interface. */
710         if (name) {
711                 make_client_state (&client);
712                 client -> name = name;
713                 client -> interface = ip;
714                 for (cp = &ip -> client; *cp; cp = &((*cp) -> next))
715                         ;
716                 *cp = client;
717         } else {
718                 if (!ip -> client) {
719                         make_client_state (&ip -> client);
720                         ip -> client -> interface = ip;
721                 }
722                 client = ip -> client;
723         }
724
725         if (!client -> config)
726                 make_client_config (client, outer_config);
727
728         ip -> flags &= ~INTERFACE_AUTOMATIC;
729         interfaces_requested = 1;
730
731         token = next_token (&val, (unsigned *)0, cfile);
732         if (token != LBRACE) {
733                 parse_warn (cfile, "expecting left brace.");
734                 skip_to_semi (cfile);
735                 return;
736         }
737
738         do {
739                 token = peek_token (&val, (unsigned *)0, cfile);
740                 if (token == END_OF_FILE) {
741                         parse_warn (cfile,
742                                     "unterminated interface declaration.");
743                         return;
744                 }
745                 if (token == RBRACE)
746                         break;
747                 parse_client_statement (cfile, ip, client -> config);
748         } while (1);
749         token = next_token (&val, (unsigned *)0, cfile);
750 }
751
752 int interface_or_dummy (struct interface_info **pi, const char *name)
753 {
754         struct interface_info *i;
755         struct interface_info *ip = (struct interface_info *)0;
756         isc_result_t status;
757
758         /* Find the interface (if any) that matches the name. */
759         for (i = interfaces; i; i = i -> next) {
760                 if (!strcmp (i -> name, name)) {
761                         interface_reference (&ip, i, MDL);
762                         break;
763                 }
764         }
765
766         /* If it's not a real interface, see if it's on the dummy list. */
767         if (!ip) {
768                 for (ip = dummy_interfaces; ip; ip = ip -> next) {
769                         if (!strcmp (ip -> name, name)) {
770                                 interface_reference (&ip, i, MDL);
771                                 break;
772                         }
773                 }
774         }
775
776         /* If we didn't find an interface, make a dummy interface as
777            a placeholder. */
778         if (!ip) {
779                 isc_result_t status;
780                 status = interface_allocate (&ip, MDL);
781                 if (status != ISC_R_SUCCESS)
782                         log_fatal ("Can't record interface %s: %s",
783                                    name, isc_result_totext (status));
784                 strlcpy (ip -> name, name, IFNAMSIZ);
785                 if (dummy_interfaces) {
786                         interface_reference (&ip -> next,
787                                              dummy_interfaces, MDL);
788                         interface_dereference (&dummy_interfaces, MDL);
789                 }
790                 interface_reference (&dummy_interfaces, ip, MDL);
791         }
792         if (pi)
793                 status = interface_reference (pi, ip, MDL);
794         interface_dereference (&ip, MDL);
795         if (status != ISC_R_SUCCESS)
796                 return 0;
797         return 1;
798 }
799
800 void make_client_state (state)
801         struct client_state **state;
802 {
803         *state = ((struct client_state *)dmalloc (sizeof **state, MDL));
804         if (!*state)
805                 log_fatal ("no memory for client state\n");
806         memset (*state, 0, sizeof **state);
807 }
808
809 void make_client_config (client, config)
810         struct client_state *client;
811         struct client_config *config;
812 {
813         client -> config = (((struct client_config *)
814                              dmalloc (sizeof (struct client_config), MDL)));
815         if (!client -> config)
816                 log_fatal ("no memory for client config\n");
817         memcpy (client -> config, config, sizeof *config);
818         if (!clone_group (&client -> config -> on_receipt,
819                           config -> on_receipt, MDL) ||
820             !clone_group (&client -> config -> on_transmission,
821                           config -> on_transmission, MDL))
822                 log_fatal ("no memory for client state groups.");
823 }
824
825 /* client-lease-statement :==
826         RBRACE client-lease-declarations LBRACE
827
828         client-lease-declarations :==
829                 <nil> |
830                 client-lease-declaration |
831                 client-lease-declarations client-lease-declaration */
832
833
834 void parse_client_lease_statement (cfile, is_static)
835         struct parse *cfile;
836         int is_static;
837 {
838         struct client_lease *lease, *lp, *pl;
839         struct interface_info *ip = (struct interface_info *)0;
840         int token;
841         const char *val;
842         struct client_state *client = (struct client_state *)0;
843
844         token = next_token (&val, (unsigned *)0, cfile);
845         if (token != LBRACE) {
846                 parse_warn (cfile, "expecting left brace.");
847                 skip_to_semi (cfile);
848                 return;
849         }
850
851         lease = ((struct client_lease *)
852                  dmalloc (sizeof (struct client_lease), MDL));
853         if (!lease)
854                 log_fatal ("no memory for lease.\n");
855         memset (lease, 0, sizeof *lease);
856         lease -> is_static = is_static;
857         if (!option_state_allocate (&lease -> options, MDL))
858                 log_fatal ("no memory for lease options.\n");
859
860         do {
861                 token = peek_token (&val, (unsigned *)0, cfile);
862                 if (token == END_OF_FILE) {
863                         parse_warn (cfile, "unterminated lease declaration.");
864                         return;
865                 }
866                 if (token == RBRACE)
867                         break;
868                 parse_client_lease_declaration (cfile, lease, &ip, &client);
869         } while (1);
870         token = next_token (&val, (unsigned *)0, cfile);
871
872         /* If the lease declaration didn't include an interface
873            declaration that we recognized, it's of no use to us. */
874         if (!ip) {
875                 destroy_client_lease (lease);
876                 return;
877         }
878
879         /* Make sure there's a client state structure... */
880         if (!ip -> client) {
881                 make_client_state (&ip -> client);
882                 ip -> client -> interface = ip;
883         }
884         if (!client)
885                 client = ip -> client;
886
887         /* If this is an alias lease, it doesn't need to be sorted in. */
888         if (is_static == 2) {
889                 ip -> client -> alias = lease;
890                 return;
891         }
892
893         /* The new lease may supersede a lease that's not the
894            active lease but is still on the lease list, so scan the
895            lease list looking for a lease with the same address, and
896            if we find it, toss it. */
897         pl = (struct client_lease *)0;
898         for (lp = client -> leases; lp; lp = lp -> next) {
899                 if (lp -> address.len == lease -> address.len &&
900                     !memcmp (lp -> address.iabuf, lease -> address.iabuf,
901                              lease -> address.len)) {
902                         if (pl)
903                                 pl -> next = lp -> next;
904                         else
905                                 client -> leases = lp -> next;
906                         destroy_client_lease (lp);
907                         break;
908                 }
909         }
910
911         /* If this is a preloaded lease, just put it on the list of recorded
912            leases - don't make it the active lease. */
913         if (is_static) {
914                 lease -> next = client -> leases;
915                 client -> leases = lease;
916                 return;
917         }
918                 
919         /* The last lease in the lease file on a particular interface is
920            the active lease for that interface.    Of course, we don't know
921            what the last lease in the file is until we've parsed the whole
922            file, so at this point, we assume that the lease we just parsed
923            is the active lease for its interface.   If there's already
924            an active lease for the interface, and this lease is for the same
925            ip address, then we just toss the old active lease and replace
926            it with this one.   If this lease is for a different address,
927            then if the old active lease has expired, we dump it; if not,
928            we put it on the list of leases for this interface which are
929            still valid but no longer active. */
930         if (client -> active) {
931                 if (client -> active -> expiry < cur_time)
932                         destroy_client_lease (client -> active);
933                 else if (client -> active -> address.len ==
934                          lease -> address.len &&
935                          !memcmp (client -> active -> address.iabuf,
936                                   lease -> address.iabuf,
937                                   lease -> address.len))
938                         destroy_client_lease (client -> active);
939                 else {
940                         client -> active -> next = client -> leases;
941                         client -> leases = client -> active;
942                 }
943         }
944         client -> active = lease;
945
946         /* phew. */
947 }
948
949 /* client-lease-declaration :==
950         BOOTP |
951         INTERFACE string |
952         FIXED_ADDR ip_address |
953         FILENAME string |
954         SERVER_NAME string |
955         OPTION option-decl |
956         RENEW time-decl |
957         REBIND time-decl |
958         EXPIRE time-decl |
959         KEY id */
960
961 void parse_client_lease_declaration (cfile, lease, ipp, clientp)
962         struct parse *cfile;
963         struct client_lease *lease;
964         struct interface_info **ipp;
965         struct client_state **clientp;
966 {
967         int token;
968         const char *val;
969         char *t, *n;
970         struct interface_info *ip;
971         struct option_cache *oc;
972         struct client_state *client = (struct client_state *)0;
973         struct data_string key_id;
974
975         switch (next_token (&val, (unsigned *)0, cfile)) {
976               case KEY:
977                 token = next_token (&val, (unsigned *)0, cfile);
978                 if (token != STRING && !is_identifier (token)) {
979                         parse_warn (cfile, "expecting key name.");
980                         skip_to_semi (cfile);
981                         break;
982                 }
983                 if (omapi_auth_key_lookup_name (&lease -> key, val) !=
984                     ISC_R_SUCCESS)
985                         parse_warn (cfile, "unknown key %s", val);
986                 parse_semi (cfile);
987                 break;
988               case TOKEN_BOOTP:
989                 lease -> is_bootp = 1;
990                 break;
991
992               case INTERFACE:
993                 token = next_token (&val, (unsigned *)0, cfile);
994                 if (token != STRING) {
995                         parse_warn (cfile,
996                                     "expecting interface name (in quotes).");
997                         skip_to_semi (cfile);
998                         break;
999                 }
1000                 interface_or_dummy (ipp, val);
1001                 break;
1002
1003               case NAME:
1004                 token = next_token (&val, (unsigned *)0, cfile);
1005                 ip = *ipp;
1006                 if (!ip) {
1007                         parse_warn (cfile, "state name precedes interface.");
1008                         break;
1009                 }
1010                 for (client = ip -> client; client; client = client -> next)
1011                         if (client -> name && !strcmp (client -> name, val))
1012                                 break;
1013                 if (!client)
1014                         parse_warn (cfile,
1015                                     "lease specified for unknown pseudo.");
1016                 *clientp = client;
1017                 break;
1018
1019               case FIXED_ADDR:
1020                 if (!parse_ip_addr (cfile, &lease -> address))
1021                         return;
1022                 break;
1023
1024               case MEDIUM:
1025                 parse_string_list (cfile, &lease -> medium, 0);
1026                 return;
1027
1028               case FILENAME:
1029                 parse_string (cfile, &lease -> filename, (unsigned *)0);
1030                 return;
1031
1032               case SERVER_NAME:
1033                 parse_string (cfile, &lease -> server_name, (unsigned *)0);
1034                 return;
1035
1036               case RENEW:
1037                 lease -> renewal = parse_date (cfile);
1038                 return;
1039
1040               case REBIND:
1041                 lease -> rebind = parse_date (cfile);
1042                 return;
1043
1044               case EXPIRE:
1045                 lease -> expiry = parse_date (cfile);
1046                 return;
1047
1048               case OPTION:
1049                 oc = (struct option_cache *)0;
1050                 if (parse_option_decl (&oc, cfile)) {
1051                         save_option (oc -> option -> universe,
1052                                      lease -> options, oc);
1053                         option_cache_dereference (&oc, MDL);
1054                 }
1055                 return;
1056
1057               default:
1058                 parse_warn (cfile, "expecting lease declaration.");
1059                 skip_to_semi (cfile);
1060                 break;
1061         }
1062         token = next_token (&val, (unsigned *)0, cfile);
1063         if (token != SEMI) {
1064                 parse_warn (cfile, "expecting semicolon.");
1065                 skip_to_semi (cfile);
1066         }
1067 }
1068
1069 void parse_string_list (cfile, lp, multiple)
1070         struct parse *cfile;
1071         struct string_list **lp;
1072         int multiple;
1073 {
1074         int token;
1075         const char *val;
1076         struct string_list *cur, *tmp;
1077
1078         /* Find the last medium in the media list. */
1079         if (*lp) {
1080                 for (cur = *lp; cur -> next; cur = cur -> next)
1081                         ;
1082         } else {
1083                 cur = (struct string_list *)0;
1084         }
1085
1086         do {
1087                 token = next_token (&val, (unsigned *)0, cfile);
1088                 if (token != STRING) {
1089                         parse_warn (cfile, "Expecting media options.");
1090                         skip_to_semi (cfile);
1091                         return;
1092                 }
1093
1094                 tmp = ((struct string_list *)
1095                        dmalloc (strlen (val) + sizeof (struct string_list),
1096                                 MDL));
1097                 if (!tmp)
1098                         log_fatal ("no memory for string list entry.");
1099
1100                 strcpy (tmp -> string, val);
1101                 tmp -> next = (struct string_list *)0;
1102
1103                 /* Store this medium at the end of the media list. */
1104                 if (cur)
1105                         cur -> next = tmp;
1106                 else
1107                         *lp = tmp;
1108                 cur = tmp;
1109
1110                 token = next_token (&val, (unsigned *)0, cfile);
1111         } while (multiple && token == COMMA);
1112
1113         if (token != SEMI) {
1114                 parse_warn (cfile, "expecting semicolon.");
1115                 skip_to_semi (cfile);
1116         }
1117 }
1118
1119 void parse_reject_statement (cfile, config)
1120         struct parse *cfile;
1121         struct client_config *config;
1122 {
1123         int token;
1124         const char *val;
1125         struct iaddr addr;
1126         struct iaddrlist *list;
1127
1128         do {
1129                 if (!parse_ip_addr (cfile, &addr)) {
1130                         parse_warn (cfile, "expecting IP address.");
1131                         skip_to_semi (cfile);
1132                         return;
1133                 }
1134
1135                 list = (struct iaddrlist *)dmalloc (sizeof (struct iaddrlist),
1136                                                     MDL);
1137                 if (!list)
1138                         log_fatal ("no memory for reject list!");
1139
1140                 list -> addr = addr;
1141                 list -> next = config -> reject_list;
1142                 config -> reject_list = list;
1143
1144                 token = next_token (&val, (unsigned *)0, cfile);
1145         } while (token == COMMA);
1146
1147         if (token != SEMI) {
1148                 parse_warn (cfile, "expecting semicolon.");
1149                 skip_to_semi (cfile);
1150         }
1151 }       
1152
1153 /* allow-deny-keyword :== BOOTP
1154                         | BOOTING
1155                         | DYNAMIC_BOOTP
1156                         | UNKNOWN_CLIENTS */
1157
1158 int parse_allow_deny (oc, cfile, flag)
1159         struct option_cache **oc;
1160         struct parse *cfile;
1161         int flag;
1162 {
1163         enum dhcp_token token;
1164         const char *val;
1165         unsigned char rf = flag;
1166         struct expression *data = (struct expression *)0;
1167         int status;
1168
1169         parse_warn (cfile, "allow/deny/ignore not permitted here.");
1170         skip_to_semi (cfile);
1171         return 0;
1172 }
1173