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