1: /* clparse.c
2:
3: Parser for dhclient config and lease files... */
4:
5: /*
6: * Copyright (c) 2004-2012 by Internet Systems Consortium, Inc. ("ISC")
7: * Copyright (c) 1996-2003 by Internet Software Consortium
8: *
9: * Permission to use, copy, modify, and distribute this software for any
10: * purpose with or without fee is hereby granted, provided that the above
11: * copyright notice and this permission notice appear in all copies.
12: *
13: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
14: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
16: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
19: * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20: *
21: * Internet Systems Consortium, Inc.
22: * 950 Charter Street
23: * Redwood City, CA 94063
24: * <info@isc.org>
25: * https://www.isc.org/
26: *
27: * This software has been written for Internet Systems Consortium
28: * by Ted Lemon in cooperation with Vixie Enterprises and Nominum, Inc.
29: * To learn more about Internet Systems Consortium, see
30: * ``https://www.isc.org/''. To learn more about Vixie Enterprises,
31: * see ``http://www.vix.com''. To learn more about Nominum, Inc., see
32: * ``http://www.nominum.com''.
33: */
34:
35: #include "dhcpd.h"
36: #include <errno.h>
37:
38: struct client_config top_level_config;
39:
40: #define NUM_DEFAULT_REQUESTED_OPTS 9
41: struct option *default_requested_options[NUM_DEFAULT_REQUESTED_OPTS + 1];
42:
43: static void parse_client_default_duid(struct parse *cfile);
44: static void parse_client6_lease_statement(struct parse *cfile);
45: #ifdef DHCPv6
46: static struct dhc6_ia *parse_client6_ia_na_statement(struct parse *cfile);
47: static struct dhc6_ia *parse_client6_ia_ta_statement(struct parse *cfile);
48: static struct dhc6_ia *parse_client6_ia_pd_statement(struct parse *cfile);
49: static struct dhc6_addr *parse_client6_iaaddr_statement(struct parse *cfile);
50: static struct dhc6_addr *parse_client6_iaprefix_statement(struct parse *cfile);
51: #endif /* DHCPv6 */
52:
53: /* client-conf-file :== client-declarations END_OF_FILE
54: client-declarations :== <nil>
55: | client-declaration
56: | client-declarations client-declaration */
57:
58: isc_result_t read_client_conf ()
59: {
60: struct client_config *config;
61: struct interface_info *ip;
62: isc_result_t status;
63: unsigned code;
64:
65: /*
66: * TODO: LATER constant is very undescriptive. We should review it and
67: * change it to something more descriptive or even better remove it
68: * completely as it is currently not used.
69: */
70: #ifdef LATER
71: struct parse *parse = NULL;
72: #endif
73:
74: /* Initialize the default request list. */
75: memset(default_requested_options, 0, sizeof(default_requested_options));
76:
77: /* 1 */
78: code = DHO_SUBNET_MASK;
79: option_code_hash_lookup(&default_requested_options[0],
80: dhcp_universe.code_hash, &code, 0, MDL);
81:
82: /* 2 */
83: code = DHO_BROADCAST_ADDRESS;
84: option_code_hash_lookup(&default_requested_options[1],
85: dhcp_universe.code_hash, &code, 0, MDL);
86:
87: /* 3 */
88: code = DHO_TIME_OFFSET;
89: option_code_hash_lookup(&default_requested_options[2],
90: dhcp_universe.code_hash, &code, 0, MDL);
91:
92: /* 4 */
93: code = DHO_ROUTERS;
94: option_code_hash_lookup(&default_requested_options[3],
95: dhcp_universe.code_hash, &code, 0, MDL);
96:
97: /* 5 */
98: code = DHO_DOMAIN_NAME;
99: option_code_hash_lookup(&default_requested_options[4],
100: dhcp_universe.code_hash, &code, 0, MDL);
101:
102: /* 6 */
103: code = DHO_DOMAIN_NAME_SERVERS;
104: option_code_hash_lookup(&default_requested_options[5],
105: dhcp_universe.code_hash, &code, 0, MDL);
106:
107: /* 7 */
108: code = DHO_HOST_NAME;
109: option_code_hash_lookup(&default_requested_options[6],
110: dhcp_universe.code_hash, &code, 0, MDL);
111:
112: /* 8 */
113: code = D6O_NAME_SERVERS;
114: option_code_hash_lookup(&default_requested_options[7],
115: dhcpv6_universe.code_hash, &code, 0, MDL);
116:
117: /* 9 */
118: code = D6O_DOMAIN_SEARCH;
119: option_code_hash_lookup(&default_requested_options[8],
120: dhcpv6_universe.code_hash, &code, 0, MDL);
121:
122: for (code = 0 ; code < NUM_DEFAULT_REQUESTED_OPTS ; code++) {
123: if (default_requested_options[code] == NULL)
124: log_fatal("Unable to find option definition for "
125: "index %u during default parameter request "
126: "assembly.", code);
127: }
128:
129: /* Initialize the top level client configuration. */
130: memset (&top_level_config, 0, sizeof top_level_config);
131:
132: /* Set some defaults... */
133: top_level_config.timeout = 60;
134: top_level_config.select_interval = 0;
135: top_level_config.reboot_timeout = 10;
136: top_level_config.retry_interval = 300;
137: top_level_config.backoff_cutoff = 15;
138: top_level_config.initial_interval = 3;
139:
140: /*
141: * RFC 2131, section 4.4.1 specifies that the client SHOULD wait a
142: * random time between 1 and 10 seconds. However, we choose to not
143: * implement this default. If user is inclined to really have that
144: * delay, he is welcome to do so, using 'initial-delay X;' parameter
145: * in config file.
146: */
147: top_level_config.initial_delay = 0;
148:
149: top_level_config.bootp_policy = P_ACCEPT;
150: top_level_config.script_name = path_dhclient_script;
151: top_level_config.requested_options = default_requested_options;
152: top_level_config.omapi_port = -1;
153: top_level_config.do_forward_update = 1;
154: /* Requested lease time, used by DHCPv6 (DHCPv4 uses the option cache)
155: */
156: top_level_config.requested_lease = 7200;
157:
158: group_allocate (&top_level_config.on_receipt, MDL);
159: if (!top_level_config.on_receipt)
160: log_fatal ("no memory for top-level on_receipt group");
161:
162: group_allocate (&top_level_config.on_transmission, MDL);
163: if (!top_level_config.on_transmission)
164: log_fatal ("no memory for top-level on_transmission group");
165:
166: status = read_client_conf_file (path_dhclient_conf,
167: (struct interface_info *)0,
168: &top_level_config);
169:
170: if (status != ISC_R_SUCCESS) {
171: ;
172: #ifdef LATER
173: /* Set up the standard name service updater routine. */
174: status = new_parse(&parse, -1, default_client_config,
175: sizeof(default_client_config) - 1,
176: "default client configuration", 0);
177: if (status != ISC_R_SUCCESS)
178: log_fatal ("can't begin default client config!");
179: }
180:
181: if (parse != NULL) {
182: do {
183: token = peek_token(&val, NULL, cfile);
184: if (token == END_OF_FILE)
185: break;
186: parse_client_statement(cfile, NULL, &top_level_config);
187: } while (1);
188: end_parse(&parse);
189: #endif
190: }
191:
192: /* Set up state and config structures for clients that don't
193: have per-interface configuration statements. */
194: config = (struct client_config *)0;
195: for (ip = interfaces; ip; ip = ip -> next) {
196: if (!ip -> client) {
197: ip -> client = (struct client_state *)
198: dmalloc (sizeof (struct client_state), MDL);
199: if (!ip -> client)
200: log_fatal ("no memory for client state.");
201: memset (ip -> client, 0, sizeof *(ip -> client));
202: ip -> client -> interface = ip;
203: }
204:
205: if (!ip -> client -> config) {
206: if (!config) {
207: config = (struct client_config *)
208: dmalloc (sizeof (struct client_config),
209: MDL);
210: if (!config)
211: log_fatal ("no memory for client config.");
212: memcpy (config, &top_level_config,
213: sizeof top_level_config);
214: }
215: ip -> client -> config = config;
216: }
217: }
218: return status;
219: }
220:
221: int read_client_conf_file (const char *name, struct interface_info *ip,
222: struct client_config *client)
223: {
224: int file;
225: struct parse *cfile;
226: const char *val;
227: int token;
228: isc_result_t status;
229:
230: if ((file = open (name, O_RDONLY)) < 0)
231: return uerr2isc (errno);
232:
233: cfile = NULL;
234: status = new_parse(&cfile, file, NULL, 0, path_dhclient_conf, 0);
235: if (status != ISC_R_SUCCESS || cfile == NULL)
236: return status;
237:
238: do {
239: token = peek_token (&val, (unsigned *)0, cfile);
240: if (token == END_OF_FILE)
241: break;
242: parse_client_statement (cfile, ip, client);
243: } while (1);
244: token = next_token (&val, (unsigned *)0, cfile);
245: status = (cfile -> warnings_occurred
246: ? ISC_R_BADPARSE
247: : ISC_R_SUCCESS);
248: end_parse (&cfile);
249: return status;
250: }
251:
252:
253: /* lease-file :== client-lease-statements END_OF_FILE
254: client-lease-statements :== <nil>
255: | client-lease-statements LEASE client-lease-statement */
256:
257: void read_client_leases ()
258: {
259: int file;
260: isc_result_t status;
261: struct parse *cfile;
262: const char *val;
263: int token;
264:
265: /* Open the lease file. If we can't open it, just return -
266: we can safely trust the server to remember our state. */
267: if ((file = open (path_dhclient_db, O_RDONLY)) < 0)
268: return;
269:
270: cfile = NULL;
271: status = new_parse(&cfile, file, NULL, 0, path_dhclient_db, 0);
272: if (status != ISC_R_SUCCESS || cfile == NULL)
273: return;
274:
275: do {
276: token = next_token (&val, (unsigned *)0, cfile);
277: if (token == END_OF_FILE)
278: break;
279:
280: switch (token) {
281: case DEFAULT_DUID:
282: parse_client_default_duid(cfile);
283: break;
284:
285: case LEASE:
286: parse_client_lease_statement(cfile, 0);
287: break;
288:
289: case LEASE6:
290: parse_client6_lease_statement(cfile);
291: break;
292:
293: default:
294: log_error ("Corrupt lease file - possible data loss!");
295: skip_to_semi (cfile);
296: break;
297: }
298: } while (1);
299:
300: end_parse (&cfile);
301: }
302:
303: /* client-declaration :==
304: SEND option-decl |
305: DEFAULT option-decl |
306: SUPERSEDE option-decl |
307: PREPEND option-decl |
308: APPEND option-decl |
309: hardware-declaration |
310: ALSO REQUEST option-list |
311: ALSO REQUIRE option-list |
312: REQUEST option-list |
313: REQUIRE option-list |
314: TIMEOUT number |
315: RETRY number |
316: REBOOT number |
317: SELECT_TIMEOUT number |
318: SCRIPT string |
319: VENDOR_SPACE string |
320: interface-declaration |
321: LEASE client-lease-statement |
322: ALIAS client-lease-statement |
323: KEY key-definition */
324:
325: void parse_client_statement (cfile, ip, config)
326: struct parse *cfile;
327: struct interface_info *ip;
328: struct client_config *config;
329: {
330: int token;
331: const char *val;
332: struct option *option = NULL;
333: struct executable_statement *stmt;
334: int lose;
335: char *name;
336: enum policy policy;
337: int known;
338: int tmp, i;
339: isc_result_t status;
340: struct option ***append_list, **new_list, **cat_list;
341:
342: switch (peek_token (&val, (unsigned *)0, cfile)) {
343: case INCLUDE:
344: next_token (&val, (unsigned *)0, cfile);
345: token = next_token (&val, (unsigned *)0, cfile);
346: if (token != STRING) {
347: parse_warn (cfile, "filename string expected.");
348: skip_to_semi (cfile);
349: } else {
350: status = read_client_conf_file (val, ip, config);
351: if (status != ISC_R_SUCCESS)
352: parse_warn (cfile, "%s: bad parse.", val);
353: parse_semi (cfile);
354: }
355: return;
356:
357: case KEY:
358: next_token (&val, (unsigned *)0, cfile);
359: if (ip) {
360: /* This may seem arbitrary, but there's a reason for
361: doing it: the authentication key database is not
362: scoped. If we allow the user to declare a key other
363: than in the outer scope, the user is very likely to
364: believe that the key will only be used in that
365: scope. If the user only wants the key to be used on
366: one interface, because it's known that the other
367: interface may be connected to an insecure net and
368: the secret key is considered sensitive, we don't
369: want to lull them into believing they've gotten
370: their way. This is a bit contrived, but people
371: tend not to be entirely rational about security. */
372: parse_warn (cfile, "key definition not allowed here.");
373: skip_to_semi (cfile);
374: break;
375: }
376: parse_key (cfile);
377: return;
378:
379: case TOKEN_ALSO:
380: /* consume ALSO */
381: next_token(&val, NULL, cfile);
382:
383: /* consume type of ALSO list. */
384: token = next_token(&val, NULL, cfile);
385:
386: if (token == REQUEST) {
387: append_list = &config->requested_options;
388: } else if (token == REQUIRE) {
389: append_list = &config->required_options;
390: } else {
391: parse_warn(cfile, "expected REQUEST or REQUIRE list");
392: skip_to_semi(cfile);
393: return;
394: }
395:
396: /* If there is no list, cut the concat short. */
397: if (*append_list == NULL) {
398: parse_option_list(cfile, append_list);
399: return;
400: }
401:
402: /* Count the length of the existing list. */
403: for (i = 0 ; (*append_list)[i] != NULL ; i++)
404: ; /* This space intentionally left blank. */
405:
406: /* If there's no codes on the list, cut the concat short. */
407: if (i == 0) {
408: parse_option_list(cfile, append_list);
409: return;
410: }
411:
412: tmp = parse_option_list(cfile, &new_list);
413:
414: if (tmp == 0 || new_list == NULL)
415: return;
416:
417: /* Allocate 'i + tmp' buckets plus a terminator. */
418: cat_list = dmalloc(sizeof(struct option *) * (i + tmp + 1),
419: MDL);
420:
421: if (cat_list == NULL) {
422: log_error("Unable to allocate memory for new "
423: "request list.");
424: skip_to_semi(cfile);
425: return;
426: }
427:
428: for (i = 0 ; (*append_list)[i] != NULL ; i++)
429: option_reference(&cat_list[i], (*append_list)[i], MDL);
430:
431: tmp = i;
432:
433: for (i = 0 ; new_list[i] != 0 ; i++)
434: option_reference(&cat_list[tmp++], new_list[i], MDL);
435:
436: cat_list[tmp] = 0;
437:
438: /* XXX: We cannot free the old list, because it may have been
439: * XXX: assigned from an outer configuration scope (or may be
440: * XXX: the static default setting).
441: */
442: *append_list = cat_list;
443:
444: return;
445:
446: /* REQUIRE can either start a policy statement or a
447: comma-separated list of names of required options. */
448: case REQUIRE:
449: next_token (&val, (unsigned *)0, cfile);
450: token = peek_token (&val, (unsigned *)0, cfile);
451: if (token == AUTHENTICATION) {
452: policy = P_REQUIRE;
453: goto do_policy;
454: }
455: parse_option_list (cfile, &config -> required_options);
456: return;
457:
458: case IGNORE:
459: next_token (&val, (unsigned *)0, cfile);
460: policy = P_IGNORE;
461: goto do_policy;
462:
463: case ACCEPT:
464: next_token (&val, (unsigned *)0, cfile);
465: policy = P_ACCEPT;
466: goto do_policy;
467:
468: case PREFER:
469: next_token (&val, (unsigned *)0, cfile);
470: policy = P_PREFER;
471: goto do_policy;
472:
473: case DONT:
474: next_token (&val, (unsigned *)0, cfile);
475: policy = P_DONT;
476: goto do_policy;
477:
478: do_policy:
479: token = next_token (&val, (unsigned *)0, cfile);
480: if (token == AUTHENTICATION) {
481: if (policy != P_PREFER &&
482: policy != P_REQUIRE &&
483: policy != P_DONT) {
484: parse_warn (cfile,
485: "invalid authentication policy.");
486: skip_to_semi (cfile);
487: return;
488: }
489: config -> auth_policy = policy;
490: } else if (token != TOKEN_BOOTP) {
491: if (policy != P_PREFER &&
492: policy != P_IGNORE &&
493: policy != P_ACCEPT) {
494: parse_warn (cfile, "invalid bootp policy.");
495: skip_to_semi (cfile);
496: return;
497: }
498: config -> bootp_policy = policy;
499: } else {
500: parse_warn (cfile, "expecting a policy type.");
501: skip_to_semi (cfile);
502: return;
503: }
504: break;
505:
506: case OPTION:
507: token = next_token (&val, (unsigned *)0, cfile);
508:
509: token = peek_token (&val, (unsigned *)0, cfile);
510: if (token == SPACE) {
511: if (ip) {
512: parse_warn (cfile,
513: "option space definitions %s",
514: " may not be scoped.");
515: skip_to_semi (cfile);
516: break;
517: }
518: parse_option_space_decl (cfile);
519: return;
520: }
521:
522: known = 0;
523: status = parse_option_name(cfile, 1, &known, &option);
524: if (status != ISC_R_SUCCESS || option == NULL)
525: return;
526:
527: token = next_token (&val, (unsigned *)0, cfile);
528: if (token != CODE) {
529: parse_warn (cfile, "expecting \"code\" keyword.");
530: skip_to_semi (cfile);
531: option_dereference(&option, MDL);
532: return;
533: }
534: if (ip) {
535: parse_warn (cfile,
536: "option definitions may only appear in %s",
537: "the outermost scope.");
538: skip_to_semi (cfile);
539: option_dereference(&option, MDL);
540: return;
541: }
542:
543: /*
544: * If the option was known, remove it from the code and name
545: * hash tables before redefining it.
546: */
547: if (known) {
548: option_name_hash_delete(option->universe->name_hash,
549: option->name, 0, MDL);
550: option_code_hash_delete(option->universe->code_hash,
551: &option->code, 0, MDL);
552: }
553:
554: parse_option_code_definition(cfile, option);
555: option_dereference(&option, MDL);
556: return;
557:
558: case MEDIA:
559: token = next_token (&val, (unsigned *)0, cfile);
560: parse_string_list (cfile, &config -> media, 1);
561: return;
562:
563: case HARDWARE:
564: token = next_token (&val, (unsigned *)0, cfile);
565: if (ip) {
566: parse_hardware_param (cfile, &ip -> hw_address);
567: } else {
568: parse_warn (cfile, "hardware address parameter %s",
569: "not allowed here.");
570: skip_to_semi (cfile);
571: }
572: return;
573:
574: case REQUEST:
575: token = next_token (&val, (unsigned *)0, cfile);
576: if (config -> requested_options == default_requested_options)
577: config -> requested_options = NULL;
578: parse_option_list (cfile, &config -> requested_options);
579: return;
580:
581: case TIMEOUT:
582: token = next_token (&val, (unsigned *)0, cfile);
583: parse_lease_time (cfile, &config -> timeout);
584: return;
585:
586: case RETRY:
587: token = next_token (&val, (unsigned *)0, cfile);
588: parse_lease_time (cfile, &config -> retry_interval);
589: return;
590:
591: case SELECT_TIMEOUT:
592: token = next_token (&val, (unsigned *)0, cfile);
593: parse_lease_time (cfile, &config -> select_interval);
594: return;
595:
596: case OMAPI:
597: token = next_token (&val, (unsigned *)0, cfile);
598: token = next_token (&val, (unsigned *)0, cfile);
599: if (token != PORT) {
600: parse_warn (cfile,
601: "unexpected omapi subtype: %s", val);
602: skip_to_semi (cfile);
603: return;
604: }
605: token = next_token (&val, (unsigned *)0, cfile);
606: if (token != NUMBER) {
607: parse_warn (cfile, "invalid port number: `%s'", val);
608: skip_to_semi (cfile);
609: return;
610: }
611: tmp = atoi (val);
612: if (tmp < 0 || tmp > 65535)
613: parse_warn (cfile, "invalid omapi port %d.", tmp);
614: else if (config != &top_level_config)
615: parse_warn (cfile,
616: "omapi port only works at top level.");
617: else
618: config -> omapi_port = tmp;
619: parse_semi (cfile);
620: return;
621:
622: case DO_FORWARD_UPDATE:
623: token = next_token (&val, (unsigned *)0, cfile);
624: token = next_token (&val, (unsigned *)0, cfile);
625: if (!strcasecmp (val, "on") ||
626: !strcasecmp (val, "true"))
627: config -> do_forward_update = 1;
628: else if (!strcasecmp (val, "off") ||
629: !strcasecmp (val, "false"))
630: config -> do_forward_update = 0;
631: else {
632: parse_warn (cfile, "expecting boolean value.");
633: skip_to_semi (cfile);
634: return;
635: }
636: parse_semi (cfile);
637: return;
638:
639: case REBOOT:
640: token = next_token (&val, (unsigned *)0, cfile);
641: parse_lease_time (cfile, &config -> reboot_timeout);
642: return;
643:
644: case BACKOFF_CUTOFF:
645: token = next_token (&val, (unsigned *)0, cfile);
646: parse_lease_time (cfile, &config -> backoff_cutoff);
647: return;
648:
649: case INITIAL_INTERVAL:
650: token = next_token (&val, (unsigned *)0, cfile);
651: parse_lease_time (cfile, &config -> initial_interval);
652: return;
653:
654: case INITIAL_DELAY:
655: token = next_token (&val, (unsigned *)0, cfile);
656: parse_lease_time (cfile, &config -> initial_delay);
657: return;
658:
659: case SCRIPT:
660: token = next_token (&val, (unsigned *)0, cfile);
661: parse_string (cfile, &config -> script_name, (unsigned *)0);
662: return;
663:
664: case VENDOR:
665: token = next_token (&val, (unsigned *)0, cfile);
666: token = next_token (&val, (unsigned *)0, cfile);
667: if (token != OPTION) {
668: parse_warn (cfile, "expecting 'vendor option space'");
669: skip_to_semi (cfile);
670: return;
671: }
672: token = next_token (&val, (unsigned *)0, cfile);
673: if (token != SPACE) {
674: parse_warn (cfile, "expecting 'vendor option space'");
675: skip_to_semi (cfile);
676: return;
677: }
678: token = next_token (&val, (unsigned *)0, cfile);
679: if (!is_identifier (token)) {
680: parse_warn (cfile, "expecting an identifier.");
681: skip_to_semi (cfile);
682: return;
683: }
684: config -> vendor_space_name = dmalloc (strlen (val) + 1, MDL);
685: if (!config -> vendor_space_name)
686: log_fatal ("no memory for vendor option space name.");
687: strcpy (config -> vendor_space_name, val);
688: for (i = 0; i < universe_count; i++)
689: if (!strcmp (universes [i] -> name,
690: config -> vendor_space_name))
691: break;
692: if (i == universe_count) {
693: log_error ("vendor option space %s not found.",
694: config -> vendor_space_name);
695: }
696: parse_semi (cfile);
697: return;
698:
699: case INTERFACE:
700: token = next_token (&val, (unsigned *)0, cfile);
701: if (ip)
702: parse_warn (cfile, "nested interface declaration.");
703: parse_interface_declaration (cfile, config, (char *)0);
704: return;
705:
706: case PSEUDO:
707: token = next_token (&val, (unsigned *)0, cfile);
708: token = next_token (&val, (unsigned *)0, cfile);
709: name = dmalloc (strlen (val) + 1, MDL);
710: if (!name)
711: log_fatal ("no memory for pseudo interface name");
712: strcpy (name, val);
713: parse_interface_declaration (cfile, config, name);
714: return;
715:
716: case LEASE:
717: token = next_token (&val, (unsigned *)0, cfile);
718: parse_client_lease_statement (cfile, 1);
719: return;
720:
721: case ALIAS:
722: token = next_token (&val, (unsigned *)0, cfile);
723: parse_client_lease_statement (cfile, 2);
724: return;
725:
726: case REJECT:
727: token = next_token (&val, (unsigned *)0, cfile);
728: parse_reject_statement (cfile, config);
729: return;
730:
731: default:
732: lose = 0;
733: stmt = (struct executable_statement *)0;
734: if (!parse_executable_statement (&stmt,
735: cfile, &lose, context_any)) {
736: if (!lose) {
737: parse_warn (cfile, "expecting a statement.");
738: skip_to_semi (cfile);
739: }
740: } else {
741: struct executable_statement **eptr, *sptr;
742: if (stmt &&
743: (stmt -> op == send_option_statement ||
744: (stmt -> op == on_statement &&
745: (stmt -> data.on.evtypes & ON_TRANSMISSION)))) {
746: eptr = &config -> on_transmission -> statements;
747: if (stmt -> op == on_statement) {
748: sptr = (struct executable_statement *)0;
749: executable_statement_reference
750: (&sptr,
751: stmt -> data.on.statements, MDL);
752: executable_statement_dereference (&stmt,
753: MDL);
754: executable_statement_reference (&stmt,
755: sptr,
756: MDL);
757: executable_statement_dereference (&sptr,
758: MDL);
759: }
760: } else
761: eptr = &config -> on_receipt -> statements;
762:
763: if (stmt) {
764: for (; *eptr; eptr = &(*eptr) -> next)
765: ;
766: executable_statement_reference (eptr,
767: stmt, MDL);
768: }
769: return;
770: }
771: break;
772: }
773: parse_semi (cfile);
774: }
775:
776: /* option-list :== option_name |
777: option_list COMMA option_name */
778:
779: int
780: parse_option_list(struct parse *cfile, struct option ***list)
781: {
782: int ix;
783: int token;
784: const char *val;
785: pair p = (pair)0, q = (pair)0, r;
786: struct option *option = NULL;
787: isc_result_t status;
788:
789: ix = 0;
790: do {
791: token = peek_token (&val, (unsigned *)0, cfile);
792: if (token == SEMI) {
793: token = next_token (&val, (unsigned *)0, cfile);
794: break;
795: }
796: if (!is_identifier (token)) {
797: parse_warn (cfile, "%s: expected option name.", val);
798: token = next_token (&val, (unsigned *)0, cfile);
799: skip_to_semi (cfile);
800: return 0;
801: }
802: status = parse_option_name(cfile, 0, NULL, &option);
803: if (status != ISC_R_SUCCESS || option == NULL) {
804: parse_warn (cfile, "%s: expected option name.", val);
805: return 0;
806: }
807: r = new_pair (MDL);
808: if (!r)
809: log_fatal ("can't allocate pair for option code.");
810: /* XXX: we should probably carry a reference across this */
811: r->car = (caddr_t)option;
812: option_dereference(&option, MDL);
813: r -> cdr = (pair)0;
814: if (p)
815: q -> cdr = r;
816: else
817: p = r;
818: q = r;
819: ++ix;
820: token = next_token (&val, (unsigned *)0, cfile);
821: } while (token == COMMA);
822: if (token != SEMI) {
823: parse_warn (cfile, "expecting semicolon.");
824: skip_to_semi (cfile);
825: return 0;
826: }
827: /* XXX we can't free the list here, because we may have copied
828: XXX it from an outer config state. */
829: *list = NULL;
830: if (ix) {
831: *list = dmalloc ((ix + 1) * sizeof(struct option *), MDL);
832: if (!*list)
833: log_error ("no memory for option list.");
834: else {
835: ix = 0;
836: for (q = p; q; q = q -> cdr)
837: option_reference(&(*list)[ix++],
838: (struct option *)q->car, MDL);
839: (*list)[ix] = NULL;
840: }
841: while (p) {
842: q = p -> cdr;
843: free_pair (p, MDL);
844: p = q;
845: }
846: }
847:
848: return ix;
849: }
850:
851: /* interface-declaration :==
852: INTERFACE string LBRACE client-declarations RBRACE */
853:
854: void parse_interface_declaration (cfile, outer_config, name)
855: struct parse *cfile;
856: struct client_config *outer_config;
857: char *name;
858: {
859: int token;
860: const char *val;
861: struct client_state *client, **cp;
862: struct interface_info *ip = (struct interface_info *)0;
863:
864: token = next_token (&val, (unsigned *)0, cfile);
865: if (token != STRING) {
866: parse_warn (cfile, "expecting interface name (in quotes).");
867: skip_to_semi (cfile);
868: return;
869: }
870:
871: if (!interface_or_dummy (&ip, val))
872: log_fatal ("Can't allocate interface %s.", val);
873:
874: /* If we were given a name, this is a pseudo-interface. */
875: if (name) {
876: make_client_state (&client);
877: client -> name = name;
878: client -> interface = ip;
879: for (cp = &ip -> client; *cp; cp = &((*cp) -> next))
880: ;
881: *cp = client;
882: } else {
883: if (!ip -> client) {
884: make_client_state (&ip -> client);
885: ip -> client -> interface = ip;
886: }
887: client = ip -> client;
888: }
889:
890: if (!client -> config)
891: make_client_config (client, outer_config);
892:
893: ip -> flags &= ~INTERFACE_AUTOMATIC;
894: interfaces_requested = 1;
895:
896: token = next_token (&val, (unsigned *)0, cfile);
897: if (token != LBRACE) {
898: parse_warn (cfile, "expecting left brace.");
899: skip_to_semi (cfile);
900: return;
901: }
902:
903: do {
904: token = peek_token (&val, (unsigned *)0, cfile);
905: if (token == END_OF_FILE) {
906: parse_warn (cfile,
907: "unterminated interface declaration.");
908: return;
909: }
910: if (token == RBRACE)
911: break;
912: parse_client_statement (cfile, ip, client -> config);
913: } while (1);
914: token = next_token (&val, (unsigned *)0, cfile);
915: }
916:
917: int interface_or_dummy (struct interface_info **pi, const char *name)
918: {
919: struct interface_info *i;
920: struct interface_info *ip = (struct interface_info *)0;
921: isc_result_t status;
922:
923: /* Find the interface (if any) that matches the name. */
924: for (i = interfaces; i; i = i -> next) {
925: if (!strcmp (i -> name, name)) {
926: interface_reference (&ip, i, MDL);
927: break;
928: }
929: }
930:
931: /* If it's not a real interface, see if it's on the dummy list. */
932: if (!ip) {
933: for (ip = dummy_interfaces; ip; ip = ip -> next) {
934: if (!strcmp (ip -> name, name)) {
935: interface_reference (&ip, i, MDL);
936: break;
937: }
938: }
939: }
940:
941: /* If we didn't find an interface, make a dummy interface as
942: a placeholder. */
943: if (!ip) {
944: if ((status = interface_allocate (&ip, MDL)) != ISC_R_SUCCESS)
945: log_fatal ("Can't record interface %s: %s",
946: name, isc_result_totext (status));
947:
948: if (strlen(name) >= sizeof(ip->name)) {
949: interface_dereference(&ip, MDL);
950: return 0;
951: }
952: strcpy(ip->name, name);
953:
954: if (dummy_interfaces) {
955: interface_reference (&ip -> next,
956: dummy_interfaces, MDL);
957: interface_dereference (&dummy_interfaces, MDL);
958: }
959: interface_reference (&dummy_interfaces, ip, MDL);
960: }
961: if (pi)
962: status = interface_reference (pi, ip, MDL);
963: else
964: status = ISC_R_FAILURE;
965: interface_dereference (&ip, MDL);
966: if (status != ISC_R_SUCCESS)
967: return 0;
968: return 1;
969: }
970:
971: void make_client_state (state)
972: struct client_state **state;
973: {
974: *state = ((struct client_state *)dmalloc (sizeof **state, MDL));
975: if (!*state)
976: log_fatal ("no memory for client state\n");
977: memset (*state, 0, sizeof **state);
978: }
979:
980: void make_client_config (client, config)
981: struct client_state *client;
982: struct client_config *config;
983: {
984: client -> config = (((struct client_config *)
985: dmalloc (sizeof (struct client_config), MDL)));
986: if (!client -> config)
987: log_fatal ("no memory for client config\n");
988: memcpy (client -> config, config, sizeof *config);
989: if (!clone_group (&client -> config -> on_receipt,
990: config -> on_receipt, MDL) ||
991: !clone_group (&client -> config -> on_transmission,
992: config -> on_transmission, MDL))
993: log_fatal ("no memory for client state groups.");
994: }
995:
996: /* client-lease-statement :==
997: LBRACE client-lease-declarations RBRACE
998:
999: client-lease-declarations :==
1000: <nil> |
1001: client-lease-declaration |
1002: client-lease-declarations client-lease-declaration */
1003:
1004:
1005: void parse_client_lease_statement (cfile, is_static)
1006: struct parse *cfile;
1007: int is_static;
1008: {
1009: struct client_lease *lease, *lp, *pl, *next;
1010: struct interface_info *ip = (struct interface_info *)0;
1011: int token;
1012: const char *val;
1013: struct client_state *client = (struct client_state *)0;
1014:
1015: token = next_token (&val, (unsigned *)0, cfile);
1016: if (token != LBRACE) {
1017: parse_warn (cfile, "expecting left brace.");
1018: skip_to_semi (cfile);
1019: return;
1020: }
1021:
1022: lease = ((struct client_lease *)
1023: dmalloc (sizeof (struct client_lease), MDL));
1024: if (!lease)
1025: log_fatal ("no memory for lease.\n");
1026: memset (lease, 0, sizeof *lease);
1027: lease -> is_static = is_static;
1028: if (!option_state_allocate (&lease -> options, MDL))
1029: log_fatal ("no memory for lease options.\n");
1030:
1031: do {
1032: token = peek_token (&val, (unsigned *)0, cfile);
1033: if (token == END_OF_FILE) {
1034: parse_warn (cfile, "unterminated lease declaration.");
1035: return;
1036: }
1037: if (token == RBRACE)
1038: break;
1039: parse_client_lease_declaration (cfile, lease, &ip, &client);
1040: } while (1);
1041: token = next_token (&val, (unsigned *)0, cfile);
1042:
1043: /* If the lease declaration didn't include an interface
1044: declaration that we recognized, it's of no use to us. */
1045: if (!ip) {
1046: destroy_client_lease (lease);
1047: return;
1048: }
1049:
1050: /* Make sure there's a client state structure... */
1051: if (!ip -> client) {
1052: make_client_state (&ip -> client);
1053: ip -> client -> interface = ip;
1054: }
1055: if (!client)
1056: client = ip -> client;
1057:
1058: /* If this is an alias lease, it doesn't need to be sorted in. */
1059: if (is_static == 2) {
1060: ip -> client -> alias = lease;
1061: return;
1062: }
1063:
1064: /* The new lease may supersede a lease that's not the
1065: active lease but is still on the lease list, so scan the
1066: lease list looking for a lease with the same address, and
1067: if we find it, toss it. */
1068: pl = (struct client_lease *)0;
1069: for (lp = client -> leases; lp; lp = next) {
1070: next = lp -> next;
1071: if (lp -> address.len == lease -> address.len &&
1072: !memcmp (lp -> address.iabuf, lease -> address.iabuf,
1073: lease -> address.len)) {
1074: if (pl)
1075: pl -> next = next;
1076: else
1077: client -> leases = next;
1078: destroy_client_lease (lp);
1079: break;
1080: } else
1081: pl = lp;
1082: }
1083:
1084: /* If this is a preloaded lease, just put it on the list of recorded
1085: leases - don't make it the active lease. */
1086: if (is_static) {
1087: lease -> next = client -> leases;
1088: client -> leases = lease;
1089: return;
1090: }
1091:
1092: /* The last lease in the lease file on a particular interface is
1093: the active lease for that interface. Of course, we don't know
1094: what the last lease in the file is until we've parsed the whole
1095: file, so at this point, we assume that the lease we just parsed
1096: is the active lease for its interface. If there's already
1097: an active lease for the interface, and this lease is for the same
1098: ip address, then we just toss the old active lease and replace
1099: it with this one. If this lease is for a different address,
1100: then if the old active lease has expired, we dump it; if not,
1101: we put it on the list of leases for this interface which are
1102: still valid but no longer active. */
1103: if (client -> active) {
1104: if (client -> active -> expiry < cur_time)
1105: destroy_client_lease (client -> active);
1106: else if (client -> active -> address.len ==
1107: lease -> address.len &&
1108: !memcmp (client -> active -> address.iabuf,
1109: lease -> address.iabuf,
1110: lease -> address.len))
1111: destroy_client_lease (client -> active);
1112: else {
1113: client -> active -> next = client -> leases;
1114: client -> leases = client -> active;
1115: }
1116: }
1117: client -> active = lease;
1118:
1119: /* phew. */
1120: }
1121:
1122: /* client-lease-declaration :==
1123: BOOTP |
1124: INTERFACE string |
1125: FIXED_ADDR ip_address |
1126: FILENAME string |
1127: SERVER_NAME string |
1128: OPTION option-decl |
1129: RENEW time-decl |
1130: REBIND time-decl |
1131: EXPIRE time-decl |
1132: KEY id */
1133:
1134: void parse_client_lease_declaration (cfile, lease, ipp, clientp)
1135: struct parse *cfile;
1136: struct client_lease *lease;
1137: struct interface_info **ipp;
1138: struct client_state **clientp;
1139: {
1140: int token;
1141: const char *val;
1142: struct interface_info *ip;
1143: struct option_cache *oc;
1144: struct client_state *client = (struct client_state *)0;
1145:
1146: switch (next_token (&val, (unsigned *)0, cfile)) {
1147: case KEY:
1148: token = next_token (&val, (unsigned *)0, cfile);
1149: if (token != STRING && !is_identifier (token)) {
1150: parse_warn (cfile, "expecting key name.");
1151: skip_to_semi (cfile);
1152: break;
1153: }
1154: if (omapi_auth_key_lookup_name (&lease -> key, val) !=
1155: ISC_R_SUCCESS)
1156: parse_warn (cfile, "unknown key %s", val);
1157: parse_semi (cfile);
1158: break;
1159: case TOKEN_BOOTP:
1160: lease -> is_bootp = 1;
1161: break;
1162:
1163: case INTERFACE:
1164: token = next_token (&val, (unsigned *)0, cfile);
1165: if (token != STRING) {
1166: parse_warn (cfile,
1167: "expecting interface name (in quotes).");
1168: skip_to_semi (cfile);
1169: break;
1170: }
1171: if (!interface_or_dummy (ipp, val))
1172: log_fatal ("Can't allocate interface %s.", val);
1173: break;
1174:
1175: case NAME:
1176: token = next_token (&val, (unsigned *)0, cfile);
1177: ip = *ipp;
1178: if (!ip) {
1179: parse_warn (cfile, "state name precedes interface.");
1180: break;
1181: }
1182: for (client = ip -> client; client; client = client -> next)
1183: if (client -> name && !strcmp (client -> name, val))
1184: break;
1185: if (!client)
1186: parse_warn (cfile,
1187: "lease specified for unknown pseudo.");
1188: *clientp = client;
1189: break;
1190:
1191: case FIXED_ADDR:
1192: if (!parse_ip_addr (cfile, &lease -> address))
1193: return;
1194: break;
1195:
1196: case MEDIUM:
1197: parse_string_list (cfile, &lease -> medium, 0);
1198: return;
1199:
1200: case FILENAME:
1201: parse_string (cfile, &lease -> filename, (unsigned *)0);
1202: return;
1203:
1204: case SERVER_NAME:
1205: parse_string (cfile, &lease -> server_name, (unsigned *)0);
1206: return;
1207:
1208: case RENEW:
1209: lease -> renewal = parse_date (cfile);
1210: return;
1211:
1212: case REBIND:
1213: lease -> rebind = parse_date (cfile);
1214: return;
1215:
1216: case EXPIRE:
1217: lease -> expiry = parse_date (cfile);
1218: return;
1219:
1220: case OPTION:
1221: oc = (struct option_cache *)0;
1222: if (parse_option_decl (&oc, cfile)) {
1223: save_option(oc->option->universe, lease->options, oc);
1224: option_cache_dereference (&oc, MDL);
1225: }
1226: return;
1227:
1228: default:
1229: parse_warn (cfile, "expecting lease declaration.");
1230: skip_to_semi (cfile);
1231: break;
1232: }
1233: token = next_token (&val, (unsigned *)0, cfile);
1234: if (token != SEMI) {
1235: parse_warn (cfile, "expecting semicolon.");
1236: skip_to_semi (cfile);
1237: }
1238: }
1239:
1240: /* Parse a default-duid ""; statement.
1241: */
1242: static void
1243: parse_client_default_duid(struct parse *cfile)
1244: {
1245: struct data_string new_duid;
1246: const char *val = NULL;
1247: unsigned len;
1248: int token;
1249:
1250: memset(&new_duid, 0, sizeof(new_duid));
1251:
1252: token = next_token(&val, &len, cfile);
1253: if (token != STRING) {
1254: parse_warn(cfile, "Expected DUID string.");
1255: skip_to_semi(cfile);
1256: return;
1257: }
1258:
1259: if (len <= 2) {
1260: parse_warn(cfile, "Invalid DUID contents.");
1261: skip_to_semi(cfile);
1262: return;
1263: }
1264:
1265: if (!buffer_allocate(&new_duid.buffer, len, MDL)) {
1266: parse_warn(cfile, "Out of memory parsing default DUID.");
1267: skip_to_semi(cfile);
1268: return;
1269: }
1270: new_duid.data = new_duid.buffer->data;
1271: new_duid.len = len;
1272:
1273: memcpy(new_duid.buffer->data, val, len);
1274:
1275: /* Rotate the last entry into place. */
1276: if (default_duid.buffer != NULL)
1277: data_string_forget(&default_duid, MDL);
1278: data_string_copy(&default_duid, &new_duid, MDL);
1279: data_string_forget(&new_duid, MDL);
1280:
1281: parse_semi(cfile);
1282: }
1283:
1284: /* Parse a lease6 {} construct. The v6 client is a little different
1285: * than the v4 client today, in that it only retains one lease, the
1286: * active lease, and discards any less recent information. It may
1287: * be useful in the future to cache additional information, but it
1288: * is not worth the effort for the moment.
1289: */
1290: static void
1291: parse_client6_lease_statement(struct parse *cfile)
1292: {
1293: #if !defined(DHCPv6)
1294: parse_warn(cfile, "No DHCPv6 support.");
1295: skip_to_semi(cfile);
1296: #else /* defined(DHCPv6) */
1297: struct option_cache *oc = NULL;
1298: struct dhc6_lease *lease;
1299: struct dhc6_ia **ia;
1300: struct client_state *client = NULL;
1301: struct interface_info *iface = NULL;
1302: struct data_string ds;
1303: const char *val;
1304: unsigned len;
1305: int token, has_ia, no_semi, has_name;
1306:
1307: token = next_token(NULL, NULL, cfile);
1308: if (token != LBRACE) {
1309: parse_warn(cfile, "Expecting open curly brace.");
1310: skip_to_semi(cfile);
1311: return;
1312: }
1313:
1314: lease = dmalloc(sizeof(*lease), MDL);
1315: if (lease == NULL) {
1316: parse_warn(cfile, "Unable to allocate lease state.");
1317: skip_to_rbrace(cfile, 1);
1318: return;
1319: }
1320:
1321: option_state_allocate(&lease->options, MDL);
1322: if (lease->options == NULL) {
1323: parse_warn(cfile, "Unable to allocate option cache.");
1324: skip_to_rbrace(cfile, 1);
1325: dfree(lease, MDL);
1326: return;
1327: }
1328:
1329: has_ia = 0;
1330: has_name = 0;
1331: ia = &lease->bindings;
1332: token = next_token(&val, NULL, cfile);
1333: while (token != RBRACE) {
1334: no_semi = 0;
1335:
1336: switch(token) {
1337: case IA_NA:
1338: *ia = parse_client6_ia_na_statement(cfile);
1339: if (*ia != NULL) {
1340: ia = &(*ia)->next;
1341: has_ia = 1;
1342: }
1343:
1344: no_semi = 1;
1345:
1346: break;
1347:
1348: case IA_TA:
1349: *ia = parse_client6_ia_ta_statement(cfile);
1350: if (*ia != NULL) {
1351: ia = &(*ia)->next;
1352: has_ia = 1;
1353: }
1354:
1355: no_semi = 1;
1356:
1357: break;
1358:
1359: case IA_PD:
1360: *ia = parse_client6_ia_pd_statement(cfile);
1361: if (*ia != NULL) {
1362: ia = &(*ia)->next;
1363: has_ia = 1;
1364: }
1365:
1366: no_semi = 1;
1367:
1368: break;
1369:
1370: case INTERFACE:
1371: if (iface != NULL) {
1372: parse_warn(cfile, "Multiple interface names?");
1373: skip_to_semi(cfile);
1374: no_semi = 1;
1375: break;
1376: }
1377:
1378: token = next_token(&val, &len, cfile);
1379: if (token != STRING) {
1380: strerror:
1381: parse_warn(cfile, "Expecting a string.");
1382: skip_to_semi(cfile);
1383: no_semi = 1;
1384: break;
1385: }
1386:
1387: for (iface = interfaces ; iface != NULL ;
1388: iface = iface->next) {
1389: if (strcmp(iface->name, val) == 0)
1390: break;
1391: }
1392:
1393: if (iface == NULL) {
1394: parse_warn(cfile, "Unknown interface.");
1395: break;
1396: }
1397:
1398: break;
1399:
1400: case NAME:
1401: has_name = 1;
1402:
1403: if (client != NULL) {
1404: parse_warn(cfile, "Multiple state names?");
1405: skip_to_semi(cfile);
1406: no_semi = 1;
1407: break;
1408: }
1409:
1410: if (iface == NULL) {
1411: parse_warn(cfile, "Client name without "
1412: "interface.");
1413: skip_to_semi(cfile);
1414: no_semi = 1;
1415: break;
1416: }
1417:
1418: token = next_token(&val, &len, cfile);
1419: if (token != STRING)
1420: goto strerror;
1421:
1422: for (client = iface->client ; client != NULL ;
1423: client = client->next) {
1424: if ((client->name != NULL) &&
1425: (strcmp(client->name, val) == 0))
1426: break;
1427: }
1428:
1429: if (client == NULL) {
1430: parse_warn(cfile, "Unknown client state %s.",
1431: val);
1432: break;
1433: }
1434:
1435: break;
1436:
1437: case OPTION:
1438: if (parse_option_decl(&oc, cfile)) {
1439: save_option(oc->option->universe,
1440: lease->options, oc);
1441: option_cache_dereference(&oc, MDL);
1442: }
1443: no_semi = 1;
1444: break;
1445:
1446: case TOKEN_RELEASED:
1447: case TOKEN_ABANDONED:
1448: lease->released = ISC_TRUE;
1449: break;
1450:
1451: default:
1452: parse_warn(cfile, "Unexpected token, %s.", val);
1453: no_semi = 1;
1454: skip_to_semi(cfile);
1455: break;
1456: }
1457:
1458: if (!no_semi)
1459: parse_semi(cfile);
1460:
1461: token = next_token(&val, NULL, cfile);
1462:
1463: if (token == END_OF_FILE) {
1464: parse_warn(cfile, "Unexpected end of file.");
1465: break;
1466: }
1467: }
1468:
1469: if (!has_ia) {
1470: log_debug("Lease with no IA's discarded from lease db.");
1471: dhc6_lease_destroy(&lease, MDL);
1472: return;
1473: }
1474:
1475: if (iface == NULL)
1476: parse_warn(cfile, "Lease has no interface designation.");
1477: else if (!has_name && (client == NULL)) {
1478: for (client = iface->client ; client != NULL ;
1479: client = client->next) {
1480: if (client->name == NULL)
1481: break;
1482: }
1483: }
1484:
1485: if (client == NULL) {
1486: parse_warn(cfile, "No matching client state.");
1487: dhc6_lease_destroy(&lease, MDL);
1488: return;
1489: }
1490:
1491: /* Fetch Preference option from option cache. */
1492: memset(&ds, 0, sizeof(ds));
1493: oc = lookup_option(&dhcpv6_universe, lease->options, D6O_PREFERENCE);
1494: if ((oc != NULL) &&
1495: evaluate_option_cache(&ds, NULL, NULL, NULL, lease->options,
1496: NULL, &global_scope, oc, MDL)) {
1497: if (ds.len != 1) {
1498: log_error("Invalid length of DHCPv6 Preference option "
1499: "(%d != 1)", ds.len);
1500: data_string_forget(&ds, MDL);
1501: dhc6_lease_destroy(&lease, MDL);
1502: return;
1503: } else
1504: lease->pref = ds.data[0];
1505:
1506: data_string_forget(&ds, MDL);
1507: }
1508:
1509: /* Fetch server-id option from option cache. */
1510: oc = lookup_option(&dhcpv6_universe, lease->options, D6O_SERVERID);
1511: if ((oc == NULL) ||
1512: !evaluate_option_cache(&lease->server_id, NULL, NULL, NULL,
1513: lease->options, NULL, &global_scope, oc,
1514: MDL) ||
1515: (lease->server_id.len == 0)) {
1516: /* This should be impossible... */
1517: log_error("Invalid SERVERID option cache.");
1518: dhc6_lease_destroy(&lease, MDL);
1519: return;
1520: }
1521:
1522: if (client->active_lease != NULL)
1523: dhc6_lease_destroy(&client->active_lease, MDL);
1524:
1525: client->active_lease = lease;
1526: #endif /* defined(DHCPv6) */
1527: }
1528:
1529: /* Parse an ia_na object from the client lease.
1530: */
1531: #ifdef DHCPv6
1532: static struct dhc6_ia *
1533: parse_client6_ia_na_statement(struct parse *cfile)
1534: {
1535: struct option_cache *oc = NULL;
1536: struct dhc6_ia *ia;
1537: struct dhc6_addr **addr;
1538: const char *val;
1539: int token, no_semi, len;
1540: u_int8_t buf[5];
1541:
1542: ia = dmalloc(sizeof(*ia), MDL);
1543: if (ia == NULL) {
1544: parse_warn(cfile, "Out of memory allocating IA_NA state.");
1545: skip_to_semi(cfile);
1546: return NULL;
1547: }
1548: ia->ia_type = D6O_IA_NA;
1549:
1550: /* Get IAID. */
1551: len = parse_X(cfile, buf, 5);
1552: if (len == 4) {
1553: memcpy(ia->iaid, buf, 4);
1554: } else {
1555: parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
1556: skip_to_semi(cfile);
1557: dfree(ia, MDL);
1558: return NULL;
1559: }
1560:
1561: token = next_token(NULL, NULL, cfile);
1562: if (token != LBRACE) {
1563: parse_warn(cfile, "Expecting open curly brace.");
1564: skip_to_semi(cfile);
1565: dfree(ia, MDL);
1566: return NULL;
1567: }
1568:
1569: option_state_allocate(&ia->options, MDL);
1570: if (ia->options == NULL) {
1571: parse_warn(cfile, "Unable to allocate option state.");
1572: skip_to_rbrace(cfile, 1);
1573: dfree(ia, MDL);
1574: return NULL;
1575: }
1576:
1577: addr = &ia->addrs;
1578: token = next_token(&val, NULL, cfile);
1579: while (token != RBRACE) {
1580: no_semi = 0;
1581:
1582: switch (token) {
1583: case STARTS:
1584: token = next_token(&val, NULL, cfile);
1585: if (token == NUMBER) {
1586: ia->starts = atoi(val);
1587: } else {
1588: parse_warn(cfile, "Expecting a number.");
1589: skip_to_semi(cfile);
1590: no_semi = 1;
1591: }
1592: break;
1593:
1594: case RENEW:
1595: token = next_token(&val, NULL, cfile);
1596: if (token == NUMBER) {
1597: ia->renew = atoi(val);
1598: } else {
1599: parse_warn(cfile, "Expecting a number.");
1600: skip_to_semi(cfile);
1601: no_semi = 1;
1602: }
1603: break;
1604:
1605: case REBIND:
1606: token = next_token(&val, NULL, cfile);
1607: if (token == NUMBER) {
1608: ia->rebind = atoi(val);
1609: } else {
1610: parse_warn(cfile, "Expecting a number.");
1611: skip_to_semi(cfile);
1612: no_semi = 1;
1613: }
1614: break;
1615:
1616: case IAADDR:
1617: *addr = parse_client6_iaaddr_statement(cfile);
1618:
1619: if (*addr != NULL)
1620: addr = &(*addr)->next;
1621:
1622: no_semi = 1;
1623:
1624: break;
1625:
1626: case OPTION:
1627: if (parse_option_decl(&oc, cfile)) {
1628: save_option(oc->option->universe,
1629: ia->options, oc);
1630: option_cache_dereference(&oc, MDL);
1631: }
1632: no_semi = 1;
1633: break;
1634:
1635: default:
1636: parse_warn(cfile, "Unexpected token.");
1637: no_semi = 1;
1638: skip_to_semi(cfile);
1639: break;
1640: }
1641:
1642: if (!no_semi)
1643: parse_semi(cfile);
1644:
1645: token = next_token(&val, NULL, cfile);
1646:
1647: if (token == END_OF_FILE) {
1648: parse_warn(cfile, "Unexpected end of file.");
1649: break;
1650: }
1651: }
1652:
1653: return ia;
1654: }
1655: #endif /* DHCPv6 */
1656:
1657: /* Parse an ia_ta object from the client lease.
1658: */
1659: #ifdef DHCPv6
1660: static struct dhc6_ia *
1661: parse_client6_ia_ta_statement(struct parse *cfile)
1662: {
1663: struct option_cache *oc = NULL;
1664: struct dhc6_ia *ia;
1665: struct dhc6_addr **addr;
1666: const char *val;
1667: int token, no_semi, len;
1668: u_int8_t buf[5];
1669:
1670: ia = dmalloc(sizeof(*ia), MDL);
1671: if (ia == NULL) {
1672: parse_warn(cfile, "Out of memory allocating IA_TA state.");
1673: skip_to_semi(cfile);
1674: return NULL;
1675: }
1676: ia->ia_type = D6O_IA_TA;
1677:
1678: /* Get IAID. */
1679: len = parse_X(cfile, buf, 5);
1680: if (len == 4) {
1681: memcpy(ia->iaid, buf, 4);
1682: } else {
1683: parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
1684: skip_to_semi(cfile);
1685: dfree(ia, MDL);
1686: return NULL;
1687: }
1688:
1689: token = next_token(NULL, NULL, cfile);
1690: if (token != LBRACE) {
1691: parse_warn(cfile, "Expecting open curly brace.");
1692: skip_to_semi(cfile);
1693: dfree(ia, MDL);
1694: return NULL;
1695: }
1696:
1697: option_state_allocate(&ia->options, MDL);
1698: if (ia->options == NULL) {
1699: parse_warn(cfile, "Unable to allocate option state.");
1700: skip_to_rbrace(cfile, 1);
1701: dfree(ia, MDL);
1702: return NULL;
1703: }
1704:
1705: addr = &ia->addrs;
1706: token = next_token(&val, NULL, cfile);
1707: while (token != RBRACE) {
1708: no_semi = 0;
1709:
1710: switch (token) {
1711: case STARTS:
1712: token = next_token(&val, NULL, cfile);
1713: if (token == NUMBER) {
1714: ia->starts = atoi(val);
1715: } else {
1716: parse_warn(cfile, "Expecting a number.");
1717: skip_to_semi(cfile);
1718: no_semi = 1;
1719: }
1720: break;
1721:
1722: /* No RENEW or REBIND */
1723:
1724: case IAADDR:
1725: *addr = parse_client6_iaaddr_statement(cfile);
1726:
1727: if (*addr != NULL)
1728: addr = &(*addr)->next;
1729:
1730: no_semi = 1;
1731:
1732: break;
1733:
1734: case OPTION:
1735: if (parse_option_decl(&oc, cfile)) {
1736: save_option(oc->option->universe,
1737: ia->options, oc);
1738: option_cache_dereference(&oc, MDL);
1739: }
1740: no_semi = 1;
1741: break;
1742:
1743: default:
1744: parse_warn(cfile, "Unexpected token.");
1745: no_semi = 1;
1746: skip_to_semi(cfile);
1747: break;
1748: }
1749:
1750: if (!no_semi)
1751: parse_semi(cfile);
1752:
1753: token = next_token(&val, NULL, cfile);
1754:
1755: if (token == END_OF_FILE) {
1756: parse_warn(cfile, "Unexpected end of file.");
1757: break;
1758: }
1759: }
1760:
1761: return ia;
1762: }
1763: #endif /* DHCPv6 */
1764:
1765: /* Parse an ia_pd object from the client lease.
1766: */
1767: #ifdef DHCPv6
1768: static struct dhc6_ia *
1769: parse_client6_ia_pd_statement(struct parse *cfile)
1770: {
1771: struct option_cache *oc = NULL;
1772: struct dhc6_ia *ia;
1773: struct dhc6_addr **pref;
1774: const char *val;
1775: int token, no_semi, len;
1776: u_int8_t buf[5];
1777:
1778: ia = dmalloc(sizeof(*ia), MDL);
1779: if (ia == NULL) {
1780: parse_warn(cfile, "Out of memory allocating IA_PD state.");
1781: skip_to_semi(cfile);
1782: return NULL;
1783: }
1784: ia->ia_type = D6O_IA_PD;
1785:
1786: /* Get IAID. */
1787: len = parse_X(cfile, buf, 5);
1788: if (len == 4) {
1789: memcpy(ia->iaid, buf, 4);
1790: } else {
1791: parse_warn(cfile, "Expecting IAID of length 4, got %d.", len);
1792: skip_to_semi(cfile);
1793: dfree(ia, MDL);
1794: return NULL;
1795: }
1796:
1797: token = next_token(NULL, NULL, cfile);
1798: if (token != LBRACE) {
1799: parse_warn(cfile, "Expecting open curly brace.");
1800: skip_to_semi(cfile);
1801: dfree(ia, MDL);
1802: return NULL;
1803: }
1804:
1805: option_state_allocate(&ia->options, MDL);
1806: if (ia->options == NULL) {
1807: parse_warn(cfile, "Unable to allocate option state.");
1808: skip_to_rbrace(cfile, 1);
1809: dfree(ia, MDL);
1810: return NULL;
1811: }
1812:
1813: pref = &ia->addrs;
1814: token = next_token(&val, NULL, cfile);
1815: while (token != RBRACE) {
1816: no_semi = 0;
1817:
1818: switch (token) {
1819: case STARTS:
1820: token = next_token(&val, NULL, cfile);
1821: if (token == NUMBER) {
1822: ia->starts = atoi(val);
1823: } else {
1824: parse_warn(cfile, "Expecting a number.");
1825: skip_to_semi(cfile);
1826: no_semi = 1;
1827: }
1828: break;
1829:
1830: case RENEW:
1831: token = next_token(&val, NULL, cfile);
1832: if (token == NUMBER) {
1833: ia->renew = atoi(val);
1834: } else {
1835: parse_warn(cfile, "Expecting a number.");
1836: skip_to_semi(cfile);
1837: no_semi = 1;
1838: }
1839: break;
1840:
1841: case REBIND:
1842: token = next_token(&val, NULL, cfile);
1843: if (token == NUMBER) {
1844: ia->rebind = atoi(val);
1845: } else {
1846: parse_warn(cfile, "Expecting a number.");
1847: skip_to_semi(cfile);
1848: no_semi = 1;
1849: }
1850: break;
1851:
1852: case IAPREFIX:
1853: *pref = parse_client6_iaprefix_statement(cfile);
1854:
1855: if (*pref != NULL)
1856: pref = &(*pref)->next;
1857:
1858: no_semi = 1;
1859:
1860: break;
1861:
1862: case OPTION:
1863: if (parse_option_decl(&oc, cfile)) {
1864: save_option(oc->option->universe,
1865: ia->options, oc);
1866: option_cache_dereference(&oc, MDL);
1867: }
1868: no_semi = 1;
1869: break;
1870:
1871: default:
1872: parse_warn(cfile, "Unexpected token.");
1873: no_semi = 1;
1874: skip_to_semi(cfile);
1875: break;
1876: }
1877:
1878: if (!no_semi)
1879: parse_semi(cfile);
1880:
1881: token = next_token(&val, NULL, cfile);
1882:
1883: if (token == END_OF_FILE) {
1884: parse_warn(cfile, "Unexpected end of file.");
1885: break;
1886: }
1887: }
1888:
1889: return ia;
1890: }
1891: #endif /* DHCPv6 */
1892:
1893: /* Parse an iaaddr {} structure. */
1894: #ifdef DHCPv6
1895: static struct dhc6_addr *
1896: parse_client6_iaaddr_statement(struct parse *cfile)
1897: {
1898: struct option_cache *oc = NULL;
1899: struct dhc6_addr *addr;
1900: const char *val;
1901: int token, no_semi;
1902:
1903: addr = dmalloc(sizeof(*addr), MDL);
1904: if (addr == NULL) {
1905: parse_warn(cfile, "Unable to allocate IAADDR state.");
1906: skip_to_semi(cfile);
1907: return NULL;
1908: }
1909:
1910: /* Get IP address. */
1911: if (!parse_ip6_addr(cfile, &addr->address)) {
1912: skip_to_semi(cfile);
1913: dfree(addr, MDL);
1914: return NULL;
1915: }
1916:
1917: token = next_token(NULL, NULL, cfile);
1918: if (token != LBRACE) {
1919: parse_warn(cfile, "Expecting open curly bracket.");
1920: skip_to_semi(cfile);
1921: dfree(addr, MDL);
1922: return NULL;
1923: }
1924:
1925: option_state_allocate(&addr->options, MDL);
1926: if (addr->options == NULL) {
1927: parse_warn(cfile, "Unable to allocate option state.");
1928: skip_to_semi(cfile);
1929: dfree(addr, MDL);
1930: return NULL;
1931: }
1932:
1933: token = next_token(&val, NULL, cfile);
1934: while (token != RBRACE) {
1935: no_semi = 0;
1936:
1937: switch (token) {
1938: case STARTS:
1939: token = next_token(&val, NULL, cfile);
1940: if (token == NUMBER) {
1941: addr->starts = atoi(val);
1942: } else {
1943: parse_warn(cfile, "Expecting a number.");
1944: skip_to_semi(cfile);
1945: no_semi = 1;
1946: }
1947: break;
1948:
1949: case PREFERRED_LIFE:
1950: token = next_token(&val, NULL, cfile);
1951: if (token == NUMBER) {
1952: addr->preferred_life = atoi(val);
1953: } else {
1954: parse_warn(cfile, "Expecting a number.");
1955: skip_to_semi(cfile);
1956: no_semi = 1;
1957: }
1958: break;
1959:
1960: case MAX_LIFE:
1961: token = next_token(&val, NULL, cfile);
1962: if (token == NUMBER) {
1963: addr->max_life = atoi(val);
1964: } else {
1965: parse_warn(cfile, "Expecting a number.");
1966: skip_to_semi(cfile);
1967: no_semi = 1;
1968: }
1969: break;
1970:
1971: case OPTION:
1972: if (parse_option_decl(&oc, cfile)) {
1973: save_option(oc->option->universe,
1974: addr->options, oc);
1975: option_cache_dereference(&oc, MDL);
1976: }
1977: no_semi = 1;
1978: break;
1979:
1980: default:
1981: parse_warn(cfile, "Unexpected token.");
1982: skip_to_rbrace(cfile, 1);
1983: no_semi = 1;
1984: break;
1985: }
1986:
1987: if (!no_semi)
1988: parse_semi(cfile);
1989:
1990: token = next_token(&val, NULL, cfile);
1991: if (token == END_OF_FILE) {
1992: parse_warn(cfile, "Unexpected end of file.");
1993: break;
1994: }
1995: }
1996:
1997: return addr;
1998: }
1999: #endif /* DHCPv6 */
2000:
2001: /* Parse an iaprefix {} structure. */
2002: #ifdef DHCPv6
2003: static struct dhc6_addr *
2004: parse_client6_iaprefix_statement(struct parse *cfile)
2005: {
2006: struct option_cache *oc = NULL;
2007: struct dhc6_addr *pref;
2008: const char *val;
2009: int token, no_semi;
2010:
2011: pref = dmalloc(sizeof(*pref), MDL);
2012: if (pref == NULL) {
2013: parse_warn(cfile, "Unable to allocate IAPREFIX state.");
2014: skip_to_semi(cfile);
2015: return NULL;
2016: }
2017:
2018: /* Get IP prefix. */
2019: if (!parse_ip6_prefix(cfile, &pref->address, &pref->plen)) {
2020: skip_to_semi(cfile);
2021: dfree(pref, MDL);
2022: return NULL;
2023: }
2024:
2025: token = next_token(NULL, NULL, cfile);
2026: if (token != LBRACE) {
2027: parse_warn(cfile, "Expecting open curly bracket.");
2028: skip_to_semi(cfile);
2029: dfree(pref, MDL);
2030: return NULL;
2031: }
2032:
2033: option_state_allocate(&pref->options, MDL);
2034: if (pref->options == NULL) {
2035: parse_warn(cfile, "Unable to allocate option state.");
2036: skip_to_semi(cfile);
2037: dfree(pref, MDL);
2038: return NULL;
2039: }
2040:
2041: token = next_token(&val, NULL, cfile);
2042: while (token != RBRACE) {
2043: no_semi = 0;
2044:
2045: switch (token) {
2046: case STARTS:
2047: token = next_token(&val, NULL, cfile);
2048: if (token == NUMBER) {
2049: pref->starts = atoi(val);
2050: } else {
2051: parse_warn(cfile, "Expecting a number.");
2052: skip_to_semi(cfile);
2053: no_semi = 1;
2054: }
2055: break;
2056:
2057: case PREFERRED_LIFE:
2058: token = next_token(&val, NULL, cfile);
2059: if (token == NUMBER) {
2060: pref->preferred_life = atoi(val);
2061: } else {
2062: parse_warn(cfile, "Expecting a number.");
2063: skip_to_semi(cfile);
2064: no_semi = 1;
2065: }
2066: break;
2067:
2068: case MAX_LIFE:
2069: token = next_token(&val, NULL, cfile);
2070: if (token == NUMBER) {
2071: pref->max_life = atoi(val);
2072: } else {
2073: parse_warn(cfile, "Expecting a number.");
2074: skip_to_semi(cfile);
2075: no_semi = 1;
2076: }
2077: break;
2078:
2079: case OPTION:
2080: if (parse_option_decl(&oc, cfile)) {
2081: save_option(oc->option->universe,
2082: pref->options, oc);
2083: option_cache_dereference(&oc, MDL);
2084: }
2085: no_semi = 1;
2086: break;
2087:
2088: default:
2089: parse_warn(cfile, "Unexpected token.");
2090: skip_to_rbrace(cfile, 1);
2091: no_semi = 1;
2092: break;
2093: }
2094:
2095: if (!no_semi)
2096: parse_semi(cfile);
2097:
2098: token = next_token(&val, NULL, cfile);
2099: if (token == END_OF_FILE) {
2100: parse_warn(cfile, "Unexpected end of file.");
2101: break;
2102: }
2103: }
2104:
2105: return pref;
2106: }
2107: #endif /* DHCPv6 */
2108:
2109: void parse_string_list (cfile, lp, multiple)
2110: struct parse *cfile;
2111: struct string_list **lp;
2112: int multiple;
2113: {
2114: int token;
2115: const char *val;
2116: struct string_list *cur, *tmp;
2117:
2118: /* Find the last medium in the media list. */
2119: if (*lp) {
2120: for (cur = *lp; cur -> next; cur = cur -> next)
2121: ;
2122: } else {
2123: cur = (struct string_list *)0;
2124: }
2125:
2126: do {
2127: token = next_token (&val, (unsigned *)0, cfile);
2128: if (token != STRING) {
2129: parse_warn (cfile, "Expecting media options.");
2130: skip_to_semi (cfile);
2131: return;
2132: }
2133:
2134: tmp = ((struct string_list *)
2135: dmalloc (strlen (val) + sizeof (struct string_list),
2136: MDL));
2137: if (!tmp)
2138: log_fatal ("no memory for string list entry.");
2139:
2140: strcpy (tmp -> string, val);
2141: tmp -> next = (struct string_list *)0;
2142:
2143: /* Store this medium at the end of the media list. */
2144: if (cur)
2145: cur -> next = tmp;
2146: else
2147: *lp = tmp;
2148: cur = tmp;
2149:
2150: token = next_token (&val, (unsigned *)0, cfile);
2151: } while (multiple && token == COMMA);
2152:
2153: if (token != SEMI) {
2154: parse_warn (cfile, "expecting semicolon.");
2155: skip_to_semi (cfile);
2156: }
2157: }
2158:
2159: void parse_reject_statement (cfile, config)
2160: struct parse *cfile;
2161: struct client_config *config;
2162: {
2163: int token;
2164: const char *val;
2165: struct iaddrmatch match;
2166: struct iaddrmatchlist *list;
2167: int i;
2168:
2169: do {
2170: if (!parse_ip_addr_with_subnet (cfile, &match)) {
2171: /* no warn: parser will have reported what's wrong */
2172: skip_to_semi (cfile);
2173: return;
2174: }
2175:
2176: /* check mask is not all zeros (because that would
2177: * reject EVERY address). This check could be
2178: * simplified if we assume that the mask *always*
2179: * represents a prefix .. but perhaps it might be
2180: * useful to have a mask which is not a proper prefix
2181: * (perhaps for ipv6?). The following is almost as
2182: * efficient as inspection of match.mask.iabuf[0] when
2183: * it IS a true prefix, and is more general when it is
2184: * not.
2185: */
2186:
2187: for (i=0 ; i < match.mask.len ; i++) {
2188: if (match.mask.iabuf[i]) {
2189: break;
2190: }
2191: }
2192:
2193: if (i == match.mask.len) {
2194: /* oops we found all zeros */
2195: parse_warn(cfile, "zero-length prefix is not permitted "
2196: "for reject statement");
2197: skip_to_semi(cfile);
2198: return;
2199: }
2200:
2201: list = dmalloc(sizeof(struct iaddrmatchlist), MDL);
2202: if (!list)
2203: log_fatal ("no memory for reject list!");
2204:
2205: list->match = match;
2206: list->next = config->reject_list;
2207: config->reject_list = list;
2208:
2209: token = next_token (&val, (unsigned *)0, cfile);
2210: } while (token == COMMA);
2211:
2212: if (token != SEMI) {
2213: parse_warn (cfile, "expecting semicolon.");
2214: skip_to_semi (cfile);
2215: }
2216: }
2217:
2218: /* allow-deny-keyword :== BOOTP
2219: | BOOTING
2220: | DYNAMIC_BOOTP
2221: | UNKNOWN_CLIENTS */
2222:
2223: int parse_allow_deny (oc, cfile, flag)
2224: struct option_cache **oc;
2225: struct parse *cfile;
2226: int flag;
2227: {
2228: parse_warn (cfile, "allow/deny/ignore not permitted here.");
2229: skip_to_semi (cfile);
2230: return 0;
2231: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>