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