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