1*3fc7bd6dSkrw /* $OpenBSD: confpars.c,v 1.36 2020/04/23 15:00:27 krw Exp $ */
2e853bc5dShenning
3e853bc5dShenning /*
4e853bc5dShenning * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium.
5e853bc5dShenning * All rights reserved.
6e853bc5dShenning *
7e853bc5dShenning * Redistribution and use in source and binary forms, with or without
8e853bc5dShenning * modification, are permitted provided that the following conditions
9e853bc5dShenning * are met:
10e853bc5dShenning *
11e853bc5dShenning * 1. Redistributions of source code must retain the above copyright
12e853bc5dShenning * notice, this list of conditions and the following disclaimer.
13e853bc5dShenning * 2. Redistributions in binary form must reproduce the above copyright
14e853bc5dShenning * notice, this list of conditions and the following disclaimer in the
15e853bc5dShenning * documentation and/or other materials provided with the distribution.
16e853bc5dShenning * 3. Neither the name of The Internet Software Consortium nor the names
17e853bc5dShenning * of its contributors may be used to endorse or promote products derived
18e853bc5dShenning * from this software without specific prior written permission.
19e853bc5dShenning *
20e853bc5dShenning * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
21e853bc5dShenning * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
22e853bc5dShenning * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23e853bc5dShenning * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24e853bc5dShenning * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
25e853bc5dShenning * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26e853bc5dShenning * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27e853bc5dShenning * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
28e853bc5dShenning * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29e853bc5dShenning * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30e853bc5dShenning * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31e853bc5dShenning * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32e853bc5dShenning * SUCH DAMAGE.
33e853bc5dShenning *
34e853bc5dShenning * This software has been written for the Internet Software Consortium
35e853bc5dShenning * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
36e853bc5dShenning * Enterprises. To learn more about the Internet Software Consortium,
37e853bc5dShenning * see ``http://www.vix.com/isc''. To learn more about Vixie
38e853bc5dShenning * Enterprises, see ``http://www.vix.com''.
39e853bc5dShenning */
40e853bc5dShenning
41837cddffSkrw #include <sys/types.h>
42837cddffSkrw #include <sys/socket.h>
43837cddffSkrw
44837cddffSkrw #include <net/if.h>
45837cddffSkrw
461fef8917Skrw #include <limits.h>
47837cddffSkrw #include <netdb.h>
481fef8917Skrw #include <resolv.h>
49837cddffSkrw #include <stdio.h>
50*3fc7bd6dSkrw #include <stdint.h>
51837cddffSkrw #include <stdlib.h>
52837cddffSkrw #include <string.h>
53837cddffSkrw
54837cddffSkrw #include "dhcp.h"
55837cddffSkrw #include "tree.h"
56e853bc5dShenning #include "dhcpd.h"
57e853bc5dShenning #include "dhctoken.h"
58c525a185Skrw #include "log.h"
59e853bc5dShenning
603b0fbcd4Skrw int parse_cidr(FILE *, unsigned char *, unsigned char *);
613b0fbcd4Skrw
629335a048Skrw /*
639335a048Skrw * conf-file :== parameters declarations EOF
649335a048Skrw * parameters :== <nil> | parameter | parameters parameter
659335a048Skrw * declarations :== <nil> | declaration | declarations declaration
669335a048Skrw */
676a467ce1Sderaadt int
readconf(void)686a467ce1Sderaadt readconf(void)
69e853bc5dShenning {
70e853bc5dShenning FILE *cfile;
71e853bc5dShenning char *val;
72e853bc5dShenning int token;
73e853bc5dShenning int declaration = 0;
74e853bc5dShenning
75e853bc5dShenning new_parse(path_dhcpd_conf);
76e853bc5dShenning
77e853bc5dShenning /* Set up the initial dhcp option universe. */
78e853bc5dShenning initialize_universes();
79e853bc5dShenning
809335a048Skrw /* Set up the global defaults. */
81e853bc5dShenning root_group.default_lease_time = 43200; /* 12 hours. */
82e853bc5dShenning root_group.max_lease_time = 86400; /* 24 hours. */
83e853bc5dShenning root_group.bootp_lease_cutoff = MAX_TIME;
84e853bc5dShenning root_group.boot_unknown_clients = 1;
85e853bc5dShenning root_group.allow_bootp = 1;
86e853bc5dShenning root_group.allow_booting = 1;
87e853bc5dShenning root_group.authoritative = 1;
88a51e9872Skrw root_group.echo_client_id = 1;
89e853bc5dShenning
906a467ce1Sderaadt if ((cfile = fopen(path_dhcpd_conf, "r")) == NULL)
910438cf0aSkrw fatal("Can't open %s", path_dhcpd_conf);
92e853bc5dShenning
93e853bc5dShenning do {
94e853bc5dShenning token = peek_token(&val, cfile);
95e853bc5dShenning if (token == EOF)
96e853bc5dShenning break;
97e853bc5dShenning declaration = parse_statement(cfile, &root_group,
98e853bc5dShenning ROOT_GROUP,
996a467ce1Sderaadt NULL,
100e853bc5dShenning declaration);
101e853bc5dShenning } while (1);
102e853bc5dShenning token = next_token(&val, cfile); /* Clear the peek buffer */
103e853bc5dShenning fclose(cfile);
104e853bc5dShenning
105e853bc5dShenning return !warnings_occurred;
106e853bc5dShenning }
107e853bc5dShenning
1089335a048Skrw /*
1099335a048Skrw * lease-file :== lease-declarations EOF
1109335a048Skrw * lease-statments :== <nil>
1119335a048Skrw * | lease-declaration
1129335a048Skrw * | lease-declarations lease-declaration
1136a467ce1Sderaadt */
1146a467ce1Sderaadt void
read_leases(void)1156a467ce1Sderaadt read_leases(void)
116e853bc5dShenning {
117e853bc5dShenning FILE *cfile;
118e853bc5dShenning char *val;
119e853bc5dShenning int token;
120e853bc5dShenning
121e853bc5dShenning new_parse(path_dhcpd_db);
122e853bc5dShenning
1239335a048Skrw /*
1249335a048Skrw * Open the lease file. If we can't open it, fail. The reason
1259335a048Skrw * for this is that although on initial startup, the absence of
1269335a048Skrw * a lease file is perfectly benign, if dhcpd has been running
1279335a048Skrw * and this file is absent, it means that dhcpd tried and failed
1289335a048Skrw * to rewrite the lease database. If we proceed and the
1299335a048Skrw * problem which caused the rewrite to fail has been fixed, but no
1309335a048Skrw * human has corrected the database problem, then we are left
1319335a048Skrw * thinking that no leases have been assigned to anybody, which
1329335a048Skrw * could create severe network chaos.
1339335a048Skrw */
134e853bc5dShenning if ((cfile = fopen(path_dhcpd_db, "r")) == NULL) {
1350438cf0aSkrw log_warn("Can't open lease database (%s)", path_dhcpd_db);
1360438cf0aSkrw log_warnx("check for failed database rewrite attempt!");
137c525a185Skrw log_warnx("Please read the dhcpd.leases manual page if you");
138c525a185Skrw fatalx("don't know what to do about this.");
139e23465bcShenning }
140e853bc5dShenning
141e853bc5dShenning do {
142e853bc5dShenning token = next_token(&val, cfile);
143e853bc5dShenning if (token == EOF)
144e853bc5dShenning break;
145f3ec5800Sderaadt if (token != TOK_LEASE) {
146c525a185Skrw log_warnx("Corrupt lease file - possible data loss!");
147e853bc5dShenning skip_to_semi(cfile);
148e853bc5dShenning } else {
149e853bc5dShenning struct lease *lease;
150e853bc5dShenning lease = parse_lease_declaration(cfile);
151e853bc5dShenning if (lease)
152e853bc5dShenning enter_lease(lease);
153e853bc5dShenning else
154e853bc5dShenning parse_warn("possibly corrupt lease file");
155e853bc5dShenning }
156e853bc5dShenning
157e853bc5dShenning } while (1);
158e853bc5dShenning fclose(cfile);
159e853bc5dShenning }
160e853bc5dShenning
1619335a048Skrw /*
1629335a048Skrw * statement :== parameter | declaration
1639335a048Skrw *
1649335a048Skrw * parameter :== timestamp
1659335a048Skrw * | DEFAULT_LEASE_TIME lease_time
1669335a048Skrw * | MAX_LEASE_TIME lease_time
1679335a048Skrw * | DYNAMIC_BOOTP_LEASE_CUTOFF date
1689335a048Skrw * | DYNAMIC_BOOTP_LEASE_LENGTH lease_time
1699335a048Skrw * | BOOT_UNKNOWN_CLIENTS boolean
1709335a048Skrw * | GET_LEASE_HOSTNAMES boolean
1719335a048Skrw * | USE_HOST_DECL_NAME boolean
1729335a048Skrw * | NEXT_SERVER ip-addr-or-hostname SEMI
1739335a048Skrw * | option_parameter
1749335a048Skrw * | SERVER-IDENTIFIER ip-addr-or-hostname SEMI
1759335a048Skrw * | FILENAME string-parameter
1769335a048Skrw * | SERVER_NAME string-parameter
1779335a048Skrw * | hardware-parameter
1789335a048Skrw * | fixed-address-parameter
1799335a048Skrw * | ALLOW allow-deny-keyword
1809335a048Skrw * | DENY allow-deny-keyword
1819335a048Skrw * | USE_LEASE_ADDR_FOR_DEFAULT_ROUTE boolean
1829335a048Skrw *
1839335a048Skrw * declaration :== host-declaration
1849335a048Skrw * | group-declaration
1859335a048Skrw * | shared-network-declaration
1869335a048Skrw * | subnet-declaration
1879335a048Skrw * | VENDOR_CLASS class-declaration
1889335a048Skrw * | USER_CLASS class-declaration
1899335a048Skrw * | RANGE address-range-declaration
1909335a048Skrw */
191370f92d9Skrw int
parse_statement(FILE * cfile,struct group * group,int type,struct host_decl * host_decl,int declaration)192370f92d9Skrw parse_statement(FILE *cfile, struct group *group, int type,
193370f92d9Skrw struct host_decl *host_decl, int declaration)
194e853bc5dShenning {
195e853bc5dShenning int token;
196e853bc5dShenning char *val;
197e853bc5dShenning struct shared_network *share;
1987a904ddaSkrw char *n;
199e853bc5dShenning struct tree *tree;
200e853bc5dShenning struct tree_cache *cache;
201e853bc5dShenning struct hardware hardware;
202e853bc5dShenning
203e853bc5dShenning switch (next_token(&val, cfile)) {
204f3ec5800Sderaadt case TOK_HOST:
205e853bc5dShenning if (type != HOST_DECL)
206e853bc5dShenning parse_host_declaration(cfile, group);
207e853bc5dShenning else {
208e853bc5dShenning parse_warn("host declarations not allowed here.");
209e853bc5dShenning skip_to_semi(cfile);
210e853bc5dShenning }
211e853bc5dShenning return 1;
212e853bc5dShenning
213f3ec5800Sderaadt case TOK_GROUP:
214e853bc5dShenning if (type != HOST_DECL)
215e853bc5dShenning parse_group_declaration(cfile, group);
216e853bc5dShenning else {
217e853bc5dShenning parse_warn("host declarations not allowed here.");
218e853bc5dShenning skip_to_semi(cfile);
219e853bc5dShenning }
220e853bc5dShenning return 1;
221e853bc5dShenning
222f3ec5800Sderaadt case TOK_TIMESTAMP:
223e853bc5dShenning break;
224e853bc5dShenning
225f3ec5800Sderaadt case TOK_SHARED_NETWORK:
226e853bc5dShenning if (type == SHARED_NET_DECL ||
227e853bc5dShenning type == HOST_DECL ||
228e853bc5dShenning type == SUBNET_DECL) {
229e853bc5dShenning parse_warn("shared-network parameters not %s.",
230e853bc5dShenning "allowed here");
231e853bc5dShenning skip_to_semi(cfile);
232e853bc5dShenning break;
233e853bc5dShenning }
234e853bc5dShenning
235e853bc5dShenning parse_shared_net_declaration(cfile, group);
236e853bc5dShenning return 1;
237e853bc5dShenning
238f3ec5800Sderaadt case TOK_SUBNET:
239e853bc5dShenning if (type == HOST_DECL || type == SUBNET_DECL) {
240e853bc5dShenning parse_warn("subnet declarations not allowed here.");
241e853bc5dShenning skip_to_semi(cfile);
242e853bc5dShenning return 1;
243e853bc5dShenning }
244e853bc5dShenning
245e853bc5dShenning /* If we're in a subnet declaration, just do the parse. */
246e853bc5dShenning if (group->shared_network) {
247e853bc5dShenning parse_subnet_declaration(cfile,
248e853bc5dShenning group->shared_network);
249e853bc5dShenning break;
250e853bc5dShenning }
251e853bc5dShenning
2529335a048Skrw /*
2539335a048Skrw * Otherwise, cons up a fake shared network structure
2549335a048Skrw * and populate it with the lone subnet.
2559335a048Skrw */
256e853bc5dShenning
2570372438bSkrw share = calloc(1, sizeof(struct shared_network));
258e853bc5dShenning if (!share)
259c525a185Skrw fatalx("No memory for shared subnet");
260e853bc5dShenning share->group = clone_group(group, "parse_statement:subnet");
261e853bc5dShenning share->group->shared_network = share;
262e853bc5dShenning
263e853bc5dShenning parse_subnet_declaration(cfile, share);
264e853bc5dShenning
265e853bc5dShenning /* share->subnets is the subnet we just parsed. */
266e853bc5dShenning if (share->subnets) {
267e853bc5dShenning share->interface =
268e853bc5dShenning share->subnets->interface;
269e853bc5dShenning
270e853bc5dShenning /* Make the shared network name from network number. */
271e853bc5dShenning n = piaddr(share->subnets->net);
2727a904ddaSkrw share->name = strdup(n);
2737a904ddaSkrw if (share->name == NULL)
274c525a185Skrw fatalx("no memory for subnet name");
275e853bc5dShenning
2769335a048Skrw /*
2779335a048Skrw * Copy the authoritative parameter from the subnet,
2789335a048Skrw * since there is no opportunity to declare it here.
2799335a048Skrw */
280e853bc5dShenning share->group->authoritative =
281e853bc5dShenning share->subnets->group->authoritative;
282e853bc5dShenning enter_shared_network(share);
283e853bc5dShenning }
284e853bc5dShenning return 1;
285e853bc5dShenning
286f3ec5800Sderaadt case TOK_VENDOR_CLASS:
287e853bc5dShenning parse_class_declaration(cfile, group, 0);
288e853bc5dShenning return 1;
289e853bc5dShenning
290f3ec5800Sderaadt case TOK_USER_CLASS:
291e853bc5dShenning parse_class_declaration(cfile, group, 1);
292e853bc5dShenning return 1;
293e853bc5dShenning
294f3ec5800Sderaadt case TOK_DEFAULT_LEASE_TIME:
295e853bc5dShenning parse_lease_time(cfile, &group->default_lease_time);
296e853bc5dShenning break;
297e853bc5dShenning
298f3ec5800Sderaadt case TOK_MAX_LEASE_TIME:
299e853bc5dShenning parse_lease_time(cfile, &group->max_lease_time);
300e853bc5dShenning break;
301e853bc5dShenning
302f3ec5800Sderaadt case TOK_DYNAMIC_BOOTP_LEASE_CUTOFF:
303e853bc5dShenning group->bootp_lease_cutoff = parse_date(cfile);
304e853bc5dShenning break;
305e853bc5dShenning
306f3ec5800Sderaadt case TOK_DYNAMIC_BOOTP_LEASE_LENGTH:
307e853bc5dShenning parse_lease_time(cfile, &group->bootp_lease_length);
308e853bc5dShenning break;
309e853bc5dShenning
310f3ec5800Sderaadt case TOK_BOOT_UNKNOWN_CLIENTS:
311e853bc5dShenning if (type == HOST_DECL)
312e853bc5dShenning parse_warn("boot-unknown-clients not allowed here.");
313e853bc5dShenning group->boot_unknown_clients = parse_boolean(cfile);
314e853bc5dShenning break;
315e853bc5dShenning
316f3ec5800Sderaadt case TOK_GET_LEASE_HOSTNAMES:
317e853bc5dShenning if (type == HOST_DECL)
318e853bc5dShenning parse_warn("get-lease-hostnames not allowed here.");
319e853bc5dShenning group->get_lease_hostnames = parse_boolean(cfile);
320e853bc5dShenning break;
321e853bc5dShenning
322f3ec5800Sderaadt case TOK_ALWAYS_REPLY_RFC1048:
323e853bc5dShenning group->always_reply_rfc1048 = parse_boolean(cfile);
324e853bc5dShenning break;
325e853bc5dShenning
326a51e9872Skrw case TOK_ECHO_CLIENT_ID:
327a51e9872Skrw group->echo_client_id = parse_boolean(cfile);
328a51e9872Skrw break;
329a51e9872Skrw
330f3ec5800Sderaadt case TOK_USE_HOST_DECL_NAMES:
331e853bc5dShenning if (type == HOST_DECL)
332e853bc5dShenning parse_warn("use-host-decl-names not allowed here.");
333e853bc5dShenning group->use_host_decl_names = parse_boolean(cfile);
334e853bc5dShenning break;
335e853bc5dShenning
336f3ec5800Sderaadt case TOK_USE_LEASE_ADDR_FOR_DEFAULT_ROUTE:
337e853bc5dShenning group->use_lease_addr_for_default_route =
338e853bc5dShenning parse_boolean(cfile);
339e853bc5dShenning break;
340e853bc5dShenning
341f3ec5800Sderaadt case TOK_TOKEN_NOT:
342e853bc5dShenning token = next_token(&val, cfile);
343e853bc5dShenning switch (token) {
344f3ec5800Sderaadt case TOK_AUTHORITATIVE:
345e853bc5dShenning if (type == HOST_DECL)
346e853bc5dShenning parse_warn("authority makes no sense here.");
347e853bc5dShenning group->authoritative = 0;
348e853bc5dShenning parse_semi(cfile);
349e853bc5dShenning break;
350e853bc5dShenning default:
351e853bc5dShenning parse_warn("expecting assertion");
352e853bc5dShenning skip_to_semi(cfile);
353e853bc5dShenning break;
354e853bc5dShenning }
355e853bc5dShenning break;
356e853bc5dShenning
357f3ec5800Sderaadt case TOK_AUTHORITATIVE:
358e853bc5dShenning if (type == HOST_DECL)
359e853bc5dShenning parse_warn("authority makes no sense here.");
360e853bc5dShenning group->authoritative = 1;
361e853bc5dShenning parse_semi(cfile);
362e853bc5dShenning break;
363e853bc5dShenning
364f3ec5800Sderaadt case TOK_NEXT_SERVER:
365e853bc5dShenning tree = parse_ip_addr_or_hostname(cfile, 0);
366e853bc5dShenning if (!tree)
367e853bc5dShenning break;
368e853bc5dShenning cache = tree_cache(tree);
369e853bc5dShenning if (!tree_evaluate (cache))
370c525a185Skrw fatalx("next-server is not known");
371e853bc5dShenning group->next_server.len = 4;
372e853bc5dShenning memcpy(group->next_server.iabuf,
373e853bc5dShenning cache->value, group->next_server.len);
374e853bc5dShenning parse_semi(cfile);
375e853bc5dShenning break;
376e853bc5dShenning
377f3ec5800Sderaadt case TOK_OPTION:
378e853bc5dShenning parse_option_param(cfile, group);
379e853bc5dShenning break;
380e853bc5dShenning
381f3ec5800Sderaadt case TOK_SERVER_IDENTIFIER:
382e853bc5dShenning tree = parse_ip_addr_or_hostname(cfile, 0);
383e853bc5dShenning if (!tree)
384e853bc5dShenning return declaration;
385cca1f910Shenning group->options[DHO_DHCP_SERVER_IDENTIFIER] = tree_cache(tree);
386e853bc5dShenning token = next_token(&val, cfile);
387e853bc5dShenning break;
388e853bc5dShenning
389f3ec5800Sderaadt case TOK_FILENAME:
390e853bc5dShenning group->filename = parse_string(cfile);
391e853bc5dShenning break;
392e853bc5dShenning
393f3ec5800Sderaadt case TOK_SERVER_NAME:
394e853bc5dShenning group->server_name = parse_string(cfile);
395e853bc5dShenning break;
396e853bc5dShenning
397f3ec5800Sderaadt case TOK_HARDWARE:
398e853bc5dShenning parse_hardware_param(cfile, &hardware);
399e853bc5dShenning if (host_decl)
400e853bc5dShenning host_decl->interface = hardware;
401e853bc5dShenning else
402e853bc5dShenning parse_warn("hardware address parameter %s",
403e853bc5dShenning "not allowed here.");
404e853bc5dShenning break;
405e853bc5dShenning
406f3ec5800Sderaadt case TOK_FIXED_ADDR:
407e853bc5dShenning cache = parse_fixed_addr_param(cfile);
408e853bc5dShenning if (host_decl)
409e853bc5dShenning host_decl->fixed_addr = cache;
410e853bc5dShenning else
411e853bc5dShenning parse_warn("fixed-address parameter not %s",
412e853bc5dShenning "allowed here.");
413e853bc5dShenning break;
414e853bc5dShenning
415f3ec5800Sderaadt case TOK_RANGE:
416e853bc5dShenning if (type != SUBNET_DECL || !group->subnet) {
417e853bc5dShenning parse_warn("range declaration not allowed here.");
418e853bc5dShenning skip_to_semi(cfile);
419e853bc5dShenning return declaration;
420e853bc5dShenning }
421e853bc5dShenning parse_address_range(cfile, group->subnet);
422e853bc5dShenning return declaration;
423e853bc5dShenning
424f3ec5800Sderaadt case TOK_ALLOW:
425e853bc5dShenning parse_allow_deny(cfile, group, 1);
426e853bc5dShenning break;
427e853bc5dShenning
428f3ec5800Sderaadt case TOK_DENY:
429e853bc5dShenning parse_allow_deny(cfile, group, 0);
430e853bc5dShenning break;
431e853bc5dShenning
432e853bc5dShenning default:
433e853bc5dShenning if (declaration)
434e853bc5dShenning parse_warn("expecting a declaration.");
435e853bc5dShenning else
436e853bc5dShenning parse_warn("expecting a parameter or declaration.");
437e853bc5dShenning skip_to_semi(cfile);
438e853bc5dShenning return declaration;
439e853bc5dShenning }
440e853bc5dShenning
441e853bc5dShenning if (declaration) {
442e853bc5dShenning parse_warn("parameters not allowed after first declaration.");
443e853bc5dShenning return 1;
444e853bc5dShenning }
445e853bc5dShenning
446e853bc5dShenning return 0;
447e853bc5dShenning }
448e853bc5dShenning
4499335a048Skrw /*
4509335a048Skrw * allow-deny-keyword :== BOOTP
4519335a048Skrw * | BOOTING
4529335a048Skrw * | DYNAMIC_BOOTP
4539335a048Skrw * | UNKNOWN_CLIENTS
4549335a048Skrw */
455370f92d9Skrw void
parse_allow_deny(FILE * cfile,struct group * group,int flag)456370f92d9Skrw parse_allow_deny(FILE *cfile, struct group *group, int flag)
457e853bc5dShenning {
458e853bc5dShenning int token;
459e853bc5dShenning char *val;
460e853bc5dShenning
461e853bc5dShenning token = next_token(&val, cfile);
462e853bc5dShenning switch (token) {
463f3ec5800Sderaadt case TOK_BOOTP:
464e853bc5dShenning group->allow_bootp = flag;
465e853bc5dShenning break;
466e853bc5dShenning
467f3ec5800Sderaadt case TOK_BOOTING:
468e853bc5dShenning group->allow_booting = flag;
469e853bc5dShenning break;
470e853bc5dShenning
471f3ec5800Sderaadt case TOK_DYNAMIC_BOOTP:
472e853bc5dShenning group->dynamic_bootp = flag;
473e853bc5dShenning break;
474e853bc5dShenning
475f3ec5800Sderaadt case TOK_UNKNOWN_CLIENTS:
476e853bc5dShenning group->boot_unknown_clients = flag;
477e853bc5dShenning break;
478e853bc5dShenning
479e853bc5dShenning default:
480e853bc5dShenning parse_warn("expecting allow/deny key");
481e853bc5dShenning skip_to_semi(cfile);
482e853bc5dShenning return;
483e853bc5dShenning }
484e853bc5dShenning parse_semi(cfile);
485e853bc5dShenning }
486e853bc5dShenning
4879335a048Skrw /*
4889335a048Skrw * boolean :== ON SEMI | OFF SEMI | TRUE SEMI | FALSE SEMI
4899335a048Skrw */
4900795b389Sderaadt int
parse_boolean(FILE * cfile)4910795b389Sderaadt parse_boolean(FILE *cfile)
492e853bc5dShenning {
493e853bc5dShenning char *val;
494e853bc5dShenning int rv;
495e853bc5dShenning
4960795b389Sderaadt next_token(&val, cfile);
4970795b389Sderaadt if (!strcasecmp (val, "true") || !strcasecmp (val, "on"))
498e853bc5dShenning rv = 1;
4990795b389Sderaadt else if (!strcasecmp (val, "false") || !strcasecmp (val, "off"))
500e853bc5dShenning rv = 0;
501e853bc5dShenning else {
502e853bc5dShenning parse_warn("boolean value (true/false/on/off) expected");
503e853bc5dShenning skip_to_semi(cfile);
504e853bc5dShenning return 0;
505e853bc5dShenning }
506e853bc5dShenning parse_semi(cfile);
507e853bc5dShenning return rv;
508e853bc5dShenning }
509e853bc5dShenning
5109335a048Skrw /*
5119335a048Skrw * Expect a left brace; if there isn't one, skip over the rest of the
5129335a048Skrw * statement and return zero; otherwise, return 1.
5139335a048Skrw */
5146a467ce1Sderaadt int
parse_lbrace(FILE * cfile)5156a467ce1Sderaadt parse_lbrace(FILE *cfile)
516e853bc5dShenning {
517e853bc5dShenning int token;
518e853bc5dShenning char *val;
519e853bc5dShenning
520e853bc5dShenning token = next_token(&val, cfile);
521f3ec5800Sderaadt if (token != '{') {
522e853bc5dShenning parse_warn("expecting left brace.");
523e853bc5dShenning skip_to_semi(cfile);
524e853bc5dShenning return 0;
525e853bc5dShenning }
526e853bc5dShenning return 1;
527e853bc5dShenning }
528e853bc5dShenning
529e853bc5dShenning
5309335a048Skrw /*
5319335a048Skrw * host-declaration :== hostname '{' parameters declarations '}'
5329335a048Skrw */
533370f92d9Skrw void
parse_host_declaration(FILE * cfile,struct group * group)534370f92d9Skrw parse_host_declaration(FILE *cfile, struct group *group)
535e853bc5dShenning {
536e853bc5dShenning char *val;
537e853bc5dShenning int token;
538e853bc5dShenning struct host_decl *host;
539e853bc5dShenning char *name = parse_host_name(cfile);
540e853bc5dShenning int declaration = 0;
541e853bc5dShenning
542e853bc5dShenning if (!name)
543e853bc5dShenning return;
544e853bc5dShenning
545d60fc4a4Skrw host = calloc(1, sizeof (struct host_decl));
546e853bc5dShenning if (!host)
547c525a185Skrw fatalx("can't allocate host decl struct %s.", name);
548e853bc5dShenning
549e853bc5dShenning host->name = name;
550e853bc5dShenning host->group = clone_group(group, "parse_host_declaration");
551e853bc5dShenning
5528645615cSzinovik if (!parse_lbrace(cfile)) {
5538645615cSzinovik free(host->name);
5548645615cSzinovik free(host->group);
5558645615cSzinovik free(host);
556e853bc5dShenning return;
5578645615cSzinovik }
558e853bc5dShenning
559e853bc5dShenning do {
560e853bc5dShenning token = peek_token(&val, cfile);
561f3ec5800Sderaadt if (token == '}') {
562e853bc5dShenning token = next_token(&val, cfile);
563e853bc5dShenning break;
564e853bc5dShenning }
565e853bc5dShenning if (token == EOF) {
566e853bc5dShenning token = next_token(&val, cfile);
567e853bc5dShenning parse_warn("unexpected end of file");
568e853bc5dShenning break;
569e853bc5dShenning }
570e853bc5dShenning declaration = parse_statement(cfile, host->group,
5716a467ce1Sderaadt HOST_DECL, host, declaration);
572e853bc5dShenning } while (1);
573e853bc5dShenning
574e853bc5dShenning if (!host->group->options[DHO_HOST_NAME] &&
575e853bc5dShenning host->group->use_host_decl_names) {
576e853bc5dShenning host->group->options[DHO_HOST_NAME] =
577e853bc5dShenning new_tree_cache("parse_host_declaration");
578e853bc5dShenning if (!host->group->options[DHO_HOST_NAME])
579c525a185Skrw fatalx("can't allocate a tree cache for hostname.");
580e853bc5dShenning host->group->options[DHO_HOST_NAME]->len =
581e853bc5dShenning strlen(name);
582e853bc5dShenning host->group->options[DHO_HOST_NAME]->value =
583e853bc5dShenning (unsigned char *)name;
584e853bc5dShenning host->group->options[DHO_HOST_NAME]->buf_size =
585e853bc5dShenning host->group->options[DHO_HOST_NAME]->len;
5865dee4edfSotto host->group->options[DHO_HOST_NAME]->timeout = -1;
587e853bc5dShenning host->group->options[DHO_HOST_NAME]->tree =
5886a467ce1Sderaadt NULL;
589e853bc5dShenning }
590e853bc5dShenning
591e853bc5dShenning enter_host(host);
592e853bc5dShenning }
593e853bc5dShenning
5949335a048Skrw /*
5959335a048Skrw * class-declaration :== STRING '{' parameters declarations '}'
596e853bc5dShenning */
597370f92d9Skrw void
parse_class_declaration(FILE * cfile,struct group * group,int type)598370f92d9Skrw parse_class_declaration(FILE *cfile, struct group *group, int type)
599e853bc5dShenning {
600e853bc5dShenning char *val;
601e853bc5dShenning int token;
602e853bc5dShenning struct class *class;
603e853bc5dShenning int declaration = 0;
604e853bc5dShenning
605e853bc5dShenning token = next_token(&val, cfile);
606f3ec5800Sderaadt if (token != TOK_STRING) {
607e853bc5dShenning parse_warn("Expecting class name");
608e853bc5dShenning skip_to_semi(cfile);
609e853bc5dShenning return;
610e853bc5dShenning }
611e853bc5dShenning
612e853bc5dShenning class = add_class (type, val);
613e853bc5dShenning if (!class)
614c525a185Skrw fatalx("No memory for class %s.", val);
615e853bc5dShenning class->group = clone_group(group, "parse_class_declaration");
616e853bc5dShenning
6178645615cSzinovik if (!parse_lbrace(cfile)) {
6188645615cSzinovik free(class->name);
6198645615cSzinovik free(class->group);
6208645615cSzinovik free(class);
621e853bc5dShenning return;
6228645615cSzinovik }
623e853bc5dShenning
624e853bc5dShenning do {
625e853bc5dShenning token = peek_token(&val, cfile);
626f3ec5800Sderaadt if (token == '}') {
627e853bc5dShenning token = next_token(&val, cfile);
628e853bc5dShenning break;
629e853bc5dShenning } else if (token == EOF) {
630e853bc5dShenning token = next_token(&val, cfile);
631e853bc5dShenning parse_warn("unexpected end of file");
632e853bc5dShenning break;
633e853bc5dShenning } else {
634e853bc5dShenning declaration = parse_statement(cfile, class->group,
6356a467ce1Sderaadt CLASS_DECL, NULL, declaration);
636e853bc5dShenning }
637e853bc5dShenning } while (1);
638e853bc5dShenning }
639e853bc5dShenning
6409335a048Skrw /*
6419335a048Skrw * shared-network-declaration :==
6429335a048Skrw * hostname LBRACE declarations parameters RBRACE
6439335a048Skrw */
644370f92d9Skrw void
parse_shared_net_declaration(FILE * cfile,struct group * group)645370f92d9Skrw parse_shared_net_declaration(FILE *cfile, struct group *group)
646e853bc5dShenning {
647e853bc5dShenning char *val;
648e853bc5dShenning int token;
649e853bc5dShenning struct shared_network *share;
650e853bc5dShenning char *name;
651e853bc5dShenning int declaration = 0;
652e853bc5dShenning
6530372438bSkrw share = calloc(1, sizeof(struct shared_network));
654e853bc5dShenning if (!share)
655c525a185Skrw fatalx("No memory for shared subnet");
6566a467ce1Sderaadt share->leases = NULL;
6576a467ce1Sderaadt share->last_lease = NULL;
6586a467ce1Sderaadt share->insertion_point = NULL;
6596a467ce1Sderaadt share->next = NULL;
6606a467ce1Sderaadt share->interface = NULL;
661e853bc5dShenning share->group = clone_group(group, "parse_shared_net_declaration");
662e853bc5dShenning share->group->shared_network = share;
663e853bc5dShenning
6649335a048Skrw /* Get the name of the shared network. */
665e853bc5dShenning token = peek_token(&val, cfile);
666f3ec5800Sderaadt if (token == TOK_STRING) {
667e853bc5dShenning token = next_token(&val, cfile);
668e853bc5dShenning
669e853bc5dShenning if (val[0] == 0) {
670e853bc5dShenning parse_warn("zero-length shared network name");
671e853bc5dShenning val = "<no-name-given>";
672e853bc5dShenning }
6737a904ddaSkrw name = strdup(val);
6747a904ddaSkrw if (name == NULL)
675c525a185Skrw fatalx("no memory for shared network name");
676e853bc5dShenning } else {
677e853bc5dShenning name = parse_host_name(cfile);
6788645615cSzinovik if (!name) {
6798645615cSzinovik free(share->group);
6808645615cSzinovik free(share);
681e853bc5dShenning return;
682e853bc5dShenning }
6838645615cSzinovik }
684e853bc5dShenning share->name = name;
685e853bc5dShenning
6868645615cSzinovik if (!parse_lbrace(cfile)) {
6878645615cSzinovik free(share->group);
6888645615cSzinovik free(share->name);
6898645615cSzinovik free(share);
690e853bc5dShenning return;
6918645615cSzinovik }
692e853bc5dShenning
693e853bc5dShenning do {
694e853bc5dShenning token = peek_token(&val, cfile);
695f3ec5800Sderaadt if (token == '}') {
696e853bc5dShenning token = next_token(&val, cfile);
697e853bc5dShenning if (!share->subnets) {
6988645615cSzinovik free(share->group);
6998645615cSzinovik free(share->name);
7008645615cSzinovik free(share);
701e853bc5dShenning parse_warn("empty shared-network decl");
702e853bc5dShenning return;
703e853bc5dShenning }
704e853bc5dShenning enter_shared_network(share);
705e853bc5dShenning return;
706e853bc5dShenning } else if (token == EOF) {
707e853bc5dShenning token = next_token(&val, cfile);
708e853bc5dShenning parse_warn("unexpected end of file");
709e853bc5dShenning break;
710e853bc5dShenning }
711e853bc5dShenning
712e853bc5dShenning declaration = parse_statement(cfile, share->group,
7136a467ce1Sderaadt SHARED_NET_DECL, NULL, declaration);
714e853bc5dShenning } while (1);
715e853bc5dShenning }
716e853bc5dShenning
7179335a048Skrw /*
7189335a048Skrw * subnet-declaration :==
7199335a048Skrw * net NETMASK netmask RBRACE parameters declarations LBRACE
7209335a048Skrw */
721370f92d9Skrw void
parse_subnet_declaration(FILE * cfile,struct shared_network * share)722370f92d9Skrw parse_subnet_declaration(FILE *cfile, struct shared_network *share)
723e853bc5dShenning {
724e853bc5dShenning char *val;
725e853bc5dShenning int token;
726e853bc5dShenning struct subnet *subnet, *t, *u;
727e853bc5dShenning struct iaddr iaddr;
728e853bc5dShenning unsigned char addr[4];
729e853bc5dShenning int len = sizeof addr;
730e853bc5dShenning int declaration = 0;
731e853bc5dShenning
7320372438bSkrw subnet = calloc(1, sizeof(struct subnet));
733e853bc5dShenning if (!subnet)
734c525a185Skrw fatalx("No memory for new subnet");
735e853bc5dShenning subnet->shared_network = share;
7366a467ce1Sderaadt subnet->group = clone_group(share->group, "parse_subnet_declaration");
737e853bc5dShenning subnet->group->subnet = subnet;
738e853bc5dShenning
7399335a048Skrw /* Get the network number. */
7408645615cSzinovik if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8)) {
7418645615cSzinovik free(subnet->group);
7428645615cSzinovik free(subnet);
743e853bc5dShenning return;
7448645615cSzinovik }
745e853bc5dShenning memcpy(iaddr.iabuf, addr, len);
746e853bc5dShenning iaddr.len = len;
747e853bc5dShenning subnet->net = iaddr;
748e853bc5dShenning
749e853bc5dShenning token = next_token(&val, cfile);
750f3ec5800Sderaadt if (token != TOK_NETMASK) {
7518645615cSzinovik free(subnet->group);
7528645615cSzinovik free(subnet);
753e853bc5dShenning parse_warn("Expecting netmask");
754e853bc5dShenning skip_to_semi(cfile);
755e853bc5dShenning return;
756e853bc5dShenning }
757e853bc5dShenning
7589335a048Skrw /* Get the netmask. */
7598645615cSzinovik if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8)) {
7608645615cSzinovik free(subnet->group);
7618645615cSzinovik free(subnet);
762e853bc5dShenning return;
7638645615cSzinovik }
764e853bc5dShenning memcpy(iaddr.iabuf, addr, len);
765e853bc5dShenning iaddr.len = len;
766e853bc5dShenning subnet->netmask = iaddr;
767e853bc5dShenning
768fe672a5aSkrw /* Save only the subnet number. */
769fe672a5aSkrw subnet->net = subnet_number(subnet->net, subnet->netmask);
770fe672a5aSkrw
771e853bc5dShenning enter_subnet(subnet);
772e853bc5dShenning
773e853bc5dShenning if (!parse_lbrace(cfile))
774e853bc5dShenning return;
775e853bc5dShenning
776e853bc5dShenning do {
777e853bc5dShenning token = peek_token(&val, cfile);
778f3ec5800Sderaadt if (token == '}') {
779e853bc5dShenning token = next_token(&val, cfile);
780e853bc5dShenning break;
781e853bc5dShenning } else if (token == EOF) {
782e853bc5dShenning token = next_token(&val, cfile);
783e853bc5dShenning parse_warn("unexpected end of file");
784e853bc5dShenning break;
785e853bc5dShenning }
786e853bc5dShenning declaration = parse_statement(cfile, subnet->group,
7876a467ce1Sderaadt SUBNET_DECL, NULL, declaration);
788e853bc5dShenning } while (1);
789e853bc5dShenning
7909335a048Skrw /*
7919335a048Skrw * If this subnet supports dynamic bootp, flag it so in the
7929335a048Skrw * shared_network containing it.
7939335a048Skrw */
794e853bc5dShenning if (subnet->group->dynamic_bootp)
795e853bc5dShenning share->group->dynamic_bootp = 1;
796e853bc5dShenning
797e853bc5dShenning /* Add the subnet to the list of subnets in this shared net. */
798e853bc5dShenning if (!share->subnets)
799e853bc5dShenning share->subnets = subnet;
800e853bc5dShenning else {
8016a467ce1Sderaadt u = NULL;
802e853bc5dShenning for (t = share->subnets; t; t = t->next_sibling) {
803e853bc5dShenning if (subnet_inner_than(subnet, t, 0)) {
804e853bc5dShenning if (u)
805e853bc5dShenning u->next_sibling = subnet;
806e853bc5dShenning else
807e853bc5dShenning share->subnets = subnet;
808e853bc5dShenning subnet->next_sibling = t;
809e853bc5dShenning return;
810e853bc5dShenning }
811e853bc5dShenning u = t;
812e853bc5dShenning }
813e853bc5dShenning u->next_sibling = subnet;
814e853bc5dShenning }
815e853bc5dShenning }
816e853bc5dShenning
8179335a048Skrw /*
8189335a048Skrw * group-declaration :== RBRACE parameters declarations LBRACE
8199335a048Skrw */
820370f92d9Skrw void
parse_group_declaration(FILE * cfile,struct group * group)821370f92d9Skrw parse_group_declaration(FILE *cfile, struct group *group)
822e853bc5dShenning {
823e853bc5dShenning char *val;
824e853bc5dShenning int token;
825e853bc5dShenning struct group *g;
826e853bc5dShenning int declaration = 0;
827e853bc5dShenning
828e853bc5dShenning g = clone_group(group, "parse_group_declaration");
829e853bc5dShenning
8308645615cSzinovik if (!parse_lbrace(cfile)) {
8318645615cSzinovik free(g);
832e853bc5dShenning return;
8338645615cSzinovik }
834e853bc5dShenning
835e853bc5dShenning do {
836e853bc5dShenning token = peek_token(&val, cfile);
837f3ec5800Sderaadt if (token == '}') {
838e853bc5dShenning token = next_token(&val, cfile);
839e853bc5dShenning break;
840e853bc5dShenning } else if (token == EOF) {
841e853bc5dShenning token = next_token(&val, cfile);
842e853bc5dShenning parse_warn("unexpected end of file");
843e853bc5dShenning break;
844e853bc5dShenning }
8456a467ce1Sderaadt declaration = parse_statement(cfile, g, GROUP_DECL, NULL,
846e853bc5dShenning declaration);
847e853bc5dShenning } while (1);
848e853bc5dShenning }
849e853bc5dShenning
8509335a048Skrw /*
8519335a048Skrw * cidr :== ip-address "/" bit-count
852171f404eSkrw * ip-address :== NUMBER [ DOT NUMBER [ DOT NUMBER [ DOT NUMBER ] ] ]
853171f404eSkrw * bit-count :== 0..32
854171f404eSkrw */
855171f404eSkrw int
parse_cidr(FILE * cfile,unsigned char * subnet,unsigned char * subnetlen)856*3fc7bd6dSkrw parse_cidr(FILE *cfile, unsigned char *subnet, unsigned char *subnetlen)
857171f404eSkrw {
858*3fc7bd6dSkrw uint8_t cidr[5];
85911b1f78aSkrw const char *errstr;
860171f404eSkrw char *val;
861*3fc7bd6dSkrw long long numval;
862*3fc7bd6dSkrw unsigned int i;
863171f404eSkrw int token;
864171f404eSkrw
865*3fc7bd6dSkrw memset(cidr, 0, sizeof(cidr));
866*3fc7bd6dSkrw i = 1; /* Last four octets hold subnet, first octet the # of bits. */
867*3fc7bd6dSkrw do {
868171f404eSkrw token = next_token(&val, cfile);
869*3fc7bd6dSkrw if (i == 0)
870*3fc7bd6dSkrw numval = strtonum(val, 0, 32, &errstr);
871*3fc7bd6dSkrw else
872*3fc7bd6dSkrw numval = strtonum(val, 0, UINT8_MAX, &errstr);
873*3fc7bd6dSkrw if (errstr != NULL)
874*3fc7bd6dSkrw break;
875*3fc7bd6dSkrw cidr[i++] = numval;
876*3fc7bd6dSkrw if (i == 1) {
877*3fc7bd6dSkrw memcpy(subnet, &cidr[1], 4); /* XXX Need cidr_t */
878*3fc7bd6dSkrw *subnetlen = cidr[0];
879171f404eSkrw return 1;
880*3fc7bd6dSkrw }
881*3fc7bd6dSkrw token = next_token(NULL, cfile);
882*3fc7bd6dSkrw if (token == '/')
883*3fc7bd6dSkrw i = 0;
884*3fc7bd6dSkrw if (i == sizeof(cidr))
885*3fc7bd6dSkrw break;
886*3fc7bd6dSkrw } while (token == '.' || token == '/');
887171f404eSkrw
888*3fc7bd6dSkrw parse_warn("expecting IPv4 CIDR block.");
889*3fc7bd6dSkrw
890171f404eSkrw if (token != ';')
891171f404eSkrw skip_to_semi(cfile);
892171f404eSkrw return 0;
893171f404eSkrw }
894171f404eSkrw
8959335a048Skrw /*
8969335a048Skrw * ip-addr-or-hostname :== ip-address | hostname
8979335a048Skrw * ip-address :== NUMBER DOT NUMBER DOT NUMBER DOT NUMBER
8989335a048Skrw *
8999335a048Skrw * Parse an ip address or a hostname. If uniform is zero, put in
9009335a048Skrw * a TREE_LIMIT node to catch hostnames that evaluate to more than
9019335a048Skrw * one IP address.
9029335a048Skrw */
903370f92d9Skrw struct tree *
parse_ip_addr_or_hostname(FILE * cfile,int uniform)904370f92d9Skrw parse_ip_addr_or_hostname(FILE *cfile, int uniform)
905e853bc5dShenning {
906e853bc5dShenning char *val;
907e853bc5dShenning int token;
908e853bc5dShenning unsigned char addr[4];
909e853bc5dShenning int len = sizeof addr;
910e853bc5dShenning char *name;
911e853bc5dShenning struct tree *rv;
9128952c965Shenning struct hostent *h;
913e853bc5dShenning
91411b1f78aSkrw name = NULL;
91511b1f78aSkrw h = NULL;
91611b1f78aSkrw
917e853bc5dShenning token = peek_token(&val, cfile);
918e853bc5dShenning if (is_identifier(token)) {
919e853bc5dShenning name = parse_host_name(cfile);
92011b1f78aSkrw if (name)
9218952c965Shenning h = gethostbyname(name);
92211b1f78aSkrw if (name && h) {
9238952c965Shenning rv = tree_const(h->h_addr_list[0], h->h_length);
924e853bc5dShenning if (!uniform)
925e853bc5dShenning rv = tree_limit(rv, 4);
92611b1f78aSkrw return rv;
92711b1f78aSkrw }
92811b1f78aSkrw }
92911b1f78aSkrw
93011b1f78aSkrw if (token == TOK_NUMBER_OR_NAME) {
93111b1f78aSkrw if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8)) {
93211b1f78aSkrw parse_warn("%s (%d): expecting IP address or hostname",
93311b1f78aSkrw val, token);
9346a467ce1Sderaadt return NULL;
93511b1f78aSkrw }
936e853bc5dShenning rv = tree_const(addr, len);
937e853bc5dShenning } else {
938f3ec5800Sderaadt if (token != '{' && token != '}')
939e853bc5dShenning token = next_token(&val, cfile);
940e853bc5dShenning parse_warn("%s (%d): expecting IP address or hostname",
941e853bc5dShenning val, token);
942f3ec5800Sderaadt if (token != ';')
943e853bc5dShenning skip_to_semi(cfile);
9446a467ce1Sderaadt return NULL;
945e853bc5dShenning }
946e853bc5dShenning
947e853bc5dShenning return rv;
948e853bc5dShenning }
949e853bc5dShenning
950e853bc5dShenning
9519335a048Skrw /*
9529335a048Skrw * fixed-addr-parameter :== ip-addrs-or-hostnames SEMI
9539335a048Skrw * ip-addrs-or-hostnames :== ip-addr-or-hostname
9549335a048Skrw * | ip-addrs-or-hostnames ip-addr-or-hostname
9559335a048Skrw */
956370f92d9Skrw struct tree_cache *
parse_fixed_addr_param(FILE * cfile)957370f92d9Skrw parse_fixed_addr_param(FILE *cfile)
958e853bc5dShenning {
959e853bc5dShenning char *val;
960e853bc5dShenning int token;
9616a467ce1Sderaadt struct tree *tree = NULL;
962e853bc5dShenning struct tree *tmp;
963e853bc5dShenning
964e853bc5dShenning do {
965e853bc5dShenning tmp = parse_ip_addr_or_hostname(cfile, 0);
966e853bc5dShenning if (tree)
967e853bc5dShenning tree = tree_concat(tree, tmp);
968e853bc5dShenning else
969e853bc5dShenning tree = tmp;
970e853bc5dShenning token = peek_token(&val, cfile);
971f3ec5800Sderaadt if (token == ',')
972e853bc5dShenning token = next_token(&val, cfile);
973f3ec5800Sderaadt } while (token == ',');
974e853bc5dShenning
975e853bc5dShenning if (!parse_semi(cfile))
9766a467ce1Sderaadt return NULL;
977e853bc5dShenning return tree_cache(tree);
978e853bc5dShenning }
979e853bc5dShenning
9809335a048Skrw /*
9819335a048Skrw * option_parameter :== identifier DOT identifier <syntax> SEMI
9829335a048Skrw * | identifier <syntax> SEMI
9839335a048Skrw *
9849335a048Skrw * Option syntax is handled specially through format strings, so it
9859335a048Skrw * would be painful to come up with BNF for it. However, it always
9869335a048Skrw * starts as above and ends in a SEMI.
9879335a048Skrw */
988370f92d9Skrw void
parse_option_param(FILE * cfile,struct group * group)989370f92d9Skrw parse_option_param(FILE *cfile, struct group *group)
990e853bc5dShenning {
991e853bc5dShenning char *val;
992e853bc5dShenning int token;
993e853bc5dShenning unsigned char buf[4];
994171f404eSkrw unsigned char cprefix;
995e853bc5dShenning char *vendor;
996e853bc5dShenning char *fmt;
997e853bc5dShenning struct universe *universe;
998e853bc5dShenning struct option *option;
9996a467ce1Sderaadt struct tree *tree = NULL;
1000e853bc5dShenning struct tree *t;
1001e853bc5dShenning
1002e853bc5dShenning token = next_token(&val, cfile);
1003e853bc5dShenning if (!is_identifier(token)) {
1004e853bc5dShenning parse_warn("expecting identifier after option keyword.");
1005f3ec5800Sderaadt if (token != ';')
1006e853bc5dShenning skip_to_semi(cfile);
1007e853bc5dShenning return;
1008e853bc5dShenning }
10097a904ddaSkrw vendor = strdup(val);
10107a904ddaSkrw if (vendor == NULL)
1011c525a185Skrw fatalx("no memory for vendor token.");
1012e853bc5dShenning token = peek_token(&val, cfile);
1013f3ec5800Sderaadt if (token == '.') {
10149335a048Skrw /* Go ahead and take the DOT token. */
1015e853bc5dShenning token = next_token(&val, cfile);
1016e853bc5dShenning
10179335a048Skrw /* The next token should be an identifier. */
1018e853bc5dShenning token = next_token(&val, cfile);
1019e853bc5dShenning if (!is_identifier(token)) {
1020e853bc5dShenning parse_warn("expecting identifier after '.'");
1021f3ec5800Sderaadt if (token != ';')
1022e853bc5dShenning skip_to_semi(cfile);
10238645615cSzinovik free(vendor);
1024e853bc5dShenning return;
1025e853bc5dShenning }
1026e853bc5dShenning
10279335a048Skrw /*
10289335a048Skrw * Look up the option name hash table for the specified
10299335a048Skrw * vendor.
10309335a048Skrw */
1031cca1f910Shenning universe = ((struct universe *)hash_lookup(&universe_hash,
1032e853bc5dShenning (unsigned char *)vendor, 0));
10339335a048Skrw /*
10349335a048Skrw * If it's not there, we can't parse the rest of the
10359335a048Skrw * declaration.
10369335a048Skrw */
1037e853bc5dShenning if (!universe) {
1038e853bc5dShenning parse_warn("no vendor named %s.", vendor);
1039e853bc5dShenning skip_to_semi(cfile);
10408645615cSzinovik free(vendor);
1041e853bc5dShenning return;
1042e853bc5dShenning }
1043e853bc5dShenning } else {
10449335a048Skrw /*
10459335a048Skrw * Use the default hash table, which contains all the
10469335a048Skrw * standard dhcp option names.
10479335a048Skrw */
1048e853bc5dShenning val = vendor;
1049e853bc5dShenning universe = &dhcp_universe;
1050e853bc5dShenning }
1051e853bc5dShenning
10529335a048Skrw /* Look up the actual option info. */
1053e853bc5dShenning option = (struct option *)hash_lookup(universe->hash,
1054e853bc5dShenning (unsigned char *)val, 0);
1055e853bc5dShenning
1056e853bc5dShenning /* If we didn't get an option structure, it's an undefined option. */
1057e853bc5dShenning if (!option) {
1058e853bc5dShenning if (val == vendor)
1059e853bc5dShenning parse_warn("no option named %s", val);
1060e853bc5dShenning else
1061e853bc5dShenning parse_warn("no option named %s for vendor %s",
1062e853bc5dShenning val, vendor);
1063e853bc5dShenning skip_to_semi(cfile);
10648645615cSzinovik free(vendor);
1065e853bc5dShenning return;
1066e853bc5dShenning }
1067e853bc5dShenning
1068e853bc5dShenning /* Free the initial identifier token. */
1069e853bc5dShenning free(vendor);
1070e853bc5dShenning
10719335a048Skrw /* Parse the option data. */
1072e853bc5dShenning do {
10739335a048Skrw /*
10749335a048Skrw * Set a flag if this is an array of a simple type (i.e.,
10759335a048Skrw * not an array of pairs of IP addresses, or something
10769335a048Skrw * like that.
10779335a048Skrw */
1078e853bc5dShenning int uniform = option->format[1] == 'A';
1079e853bc5dShenning
1080e853bc5dShenning for (fmt = option->format; *fmt; fmt++) {
1081e853bc5dShenning if (*fmt == 'A')
1082e853bc5dShenning break;
1083e853bc5dShenning switch (*fmt) {
1084e853bc5dShenning case 'X':
1085e853bc5dShenning token = peek_token(&val, cfile);
108611b1f78aSkrw if (token == TOK_NUMBER_OR_NAME) {
1087e853bc5dShenning do {
1088e853bc5dShenning token = next_token
1089e853bc5dShenning (&val, cfile);
109035318e8fSkrw if (token !=
109135318e8fSkrw TOK_NUMBER_OR_NAME) {
1092cca1f910Shenning parse_warn("expecting "
109311b1f78aSkrw "hex number.");
1094f3ec5800Sderaadt if (token != ';')
1095cca1f910Shenning skip_to_semi(
1096cca1f910Shenning cfile);
1097cca1f910Shenning return;
1098cca1f910Shenning }
1099e853bc5dShenning convert_num(buf, val, 16, 8);
1100cca1f910Shenning tree = tree_concat(tree,
1101e853bc5dShenning tree_const(buf, 1));
110235318e8fSkrw token = peek_token(&val,
110335318e8fSkrw cfile);
1104f3ec5800Sderaadt if (token == ':')
110535318e8fSkrw token =
110635318e8fSkrw next_token(&val,
1107cca1f910Shenning cfile);
1108f3ec5800Sderaadt } while (token == ':');
1109f3ec5800Sderaadt } else if (token == TOK_STRING) {
1110e853bc5dShenning token = next_token(&val, cfile);
1111cca1f910Shenning tree = tree_concat(tree,
1112cca1f910Shenning tree_const((unsigned char *)val,
1113e853bc5dShenning strlen(val)));
1114e853bc5dShenning } else {
1115e853bc5dShenning parse_warn("expecting string %s.",
1116e853bc5dShenning "or hexadecimal data");
1117e853bc5dShenning skip_to_semi(cfile);
1118e853bc5dShenning return;
1119e853bc5dShenning }
1120e853bc5dShenning break;
1121e853bc5dShenning
11229335a048Skrw case 't': /* Text string. */
1123e853bc5dShenning token = next_token(&val, cfile);
1124f3ec5800Sderaadt if (token != TOK_STRING
1125e853bc5dShenning && !is_identifier(token)) {
1126e853bc5dShenning parse_warn("expecting string.");
1127f3ec5800Sderaadt if (token != ';')
1128e853bc5dShenning skip_to_semi(cfile);
1129e853bc5dShenning return;
1130e853bc5dShenning }
1131cca1f910Shenning tree = tree_concat(tree,
1132e853bc5dShenning tree_const((unsigned char *)val,
1133e853bc5dShenning strlen(val)));
1134e853bc5dShenning break;
1135e853bc5dShenning
1136e853bc5dShenning case 'I': /* IP address or hostname. */
1137e853bc5dShenning t = parse_ip_addr_or_hostname(cfile, uniform);
1138e853bc5dShenning if (!t)
1139e853bc5dShenning return;
1140e853bc5dShenning tree = tree_concat(tree, t);
1141e853bc5dShenning break;
1142e853bc5dShenning
11439335a048Skrw case 'L': /* Unsigned 32-bit integer. */
11449335a048Skrw case 'l': /* Signed 32-bit integer. */
1145e853bc5dShenning token = next_token(&val, cfile);
114611b1f78aSkrw if (token != TOK_NUMBER && token !=
114711b1f78aSkrw TOK_NUMBER_OR_NAME) {
1148e853bc5dShenning parse_warn("expecting number.");
1149f3ec5800Sderaadt if (token != ';')
1150e853bc5dShenning skip_to_semi(cfile);
1151e853bc5dShenning return;
1152e853bc5dShenning }
1153e853bc5dShenning convert_num(buf, val, 0, 32);
1154e853bc5dShenning tree = tree_concat(tree, tree_const(buf, 4));
1155e853bc5dShenning break;
1156e853bc5dShenning case 's': /* Signed 16-bit integer. */
1157e853bc5dShenning case 'S': /* Unsigned 16-bit integer. */
1158e853bc5dShenning token = next_token(&val, cfile);
115911b1f78aSkrw if (token != TOK_NUMBER && token !=
116011b1f78aSkrw TOK_NUMBER_OR_NAME) {
1161cca1f910Shenning parse_warn("expecting number.");
1162f3ec5800Sderaadt if (token != ';')
1163cca1f910Shenning skip_to_semi(cfile);
1164cca1f910Shenning return;
1165cca1f910Shenning }
1166e853bc5dShenning convert_num(buf, val, 0, 16);
1167e853bc5dShenning tree = tree_concat(tree, tree_const(buf, 2));
1168e853bc5dShenning break;
1169e853bc5dShenning case 'b': /* Signed 8-bit integer. */
1170e853bc5dShenning case 'B': /* Unsigned 8-bit integer. */
1171e853bc5dShenning token = next_token(&val, cfile);
117211b1f78aSkrw if (token != TOK_NUMBER && token !=
117311b1f78aSkrw TOK_NUMBER_OR_NAME) {
1174cca1f910Shenning parse_warn("expecting number.");
1175f3ec5800Sderaadt if (token != ';')
1176cca1f910Shenning skip_to_semi(cfile);
1177cca1f910Shenning return;
1178cca1f910Shenning }
1179e853bc5dShenning convert_num(buf, val, 0, 8);
1180e853bc5dShenning tree = tree_concat(tree, tree_const(buf, 1));
1181e853bc5dShenning break;
1182e853bc5dShenning case 'f': /* Boolean flag. */
1183e853bc5dShenning token = next_token(&val, cfile);
1184e853bc5dShenning if (!is_identifier(token)) {
1185e853bc5dShenning parse_warn("expecting identifier.");
1186f3ec5800Sderaadt if (token != ';')
1187e853bc5dShenning skip_to_semi(cfile);
1188e853bc5dShenning return;
1189e853bc5dShenning }
1190e853bc5dShenning if (!strcasecmp(val, "true")
1191e853bc5dShenning || !strcasecmp(val, "on"))
1192e853bc5dShenning buf[0] = 1;
1193e853bc5dShenning else if (!strcasecmp(val, "false")
1194e853bc5dShenning || !strcasecmp(val, "off"))
1195e853bc5dShenning buf[0] = 0;
1196e853bc5dShenning else {
1197e853bc5dShenning parse_warn("expecting boolean.");
1198f3ec5800Sderaadt if (token != ';')
1199cca1f910Shenning skip_to_semi(cfile);
1200cca1f910Shenning return;
1201e853bc5dShenning }
1202e853bc5dShenning tree = tree_concat(tree, tree_const(buf, 1));
1203e853bc5dShenning break;
1204171f404eSkrw case 'C':
1205171f404eSkrw if (!parse_cidr(cfile, buf, &cprefix))
1206171f404eSkrw return;
1207171f404eSkrw tree = tree_concat(tree, tree_const(&cprefix,
1208171f404eSkrw sizeof(cprefix)));
12090d532c33Syasuoka if (cprefix > 0)
121035318e8fSkrw tree = tree_concat(tree, tree_const(
121135318e8fSkrw buf, (cprefix + 7) / 8));
1212171f404eSkrw break;
12131fef8917Skrw case 'D':
12141fef8917Skrw t = parse_domain_and_comp(cfile);
12151fef8917Skrw if (!t)
12161fef8917Skrw return;
12171fef8917Skrw tree = tree_concat(tree, t);
12181fef8917Skrw break;
1219e853bc5dShenning default:
122035318e8fSkrw log_warnx("Bad format %c in "
122135318e8fSkrw "parse_option_param.", *fmt);
1222e853bc5dShenning skip_to_semi(cfile);
1223e853bc5dShenning return;
1224e853bc5dShenning }
1225e853bc5dShenning }
1226e853bc5dShenning if (*fmt == 'A') {
1227e853bc5dShenning token = peek_token(&val, cfile);
1228f3ec5800Sderaadt if (token == ',') {
1229e853bc5dShenning token = next_token(&val, cfile);
1230e853bc5dShenning continue;
1231e853bc5dShenning }
1232e853bc5dShenning break;
1233e853bc5dShenning }
1234e853bc5dShenning } while (*fmt == 'A');
1235e853bc5dShenning
1236e853bc5dShenning token = next_token(&val, cfile);
1237f3ec5800Sderaadt if (token != ';') {
1238e853bc5dShenning parse_warn("semicolon expected.");
1239e853bc5dShenning skip_to_semi(cfile);
1240e853bc5dShenning return;
1241e853bc5dShenning }
1242e853bc5dShenning group->options[option->code] = tree_cache(tree);
1243e853bc5dShenning }
1244e853bc5dShenning
12459335a048Skrw /*
12469335a048Skrw * lease_declaration :== LEASE ip_address LBRACE lease_parameters RBRACE
12479335a048Skrw *
12489335a048Skrw * lease_parameters :== <nil>
12499335a048Skrw * | lease_parameter
12509335a048Skrw * | lease_parameters lease_parameter
12519335a048Skrw *
12529335a048Skrw * lease_parameter :== STARTS date
12539335a048Skrw * | ENDS date
12549335a048Skrw * | TIMESTAMP date
12559335a048Skrw * | HARDWARE hardware-parameter
12569335a048Skrw * | UID hex_numbers SEMI
12579335a048Skrw * | HOSTNAME hostname SEMI
12589335a048Skrw * | CLIENT_HOSTNAME hostname SEMI
12599335a048Skrw * | CLASS identifier SEMI
12609335a048Skrw * | DYNAMIC_BOOTP SEMI
12619335a048Skrw */
12620795b389Sderaadt struct lease *
parse_lease_declaration(FILE * cfile)12630795b389Sderaadt parse_lease_declaration(FILE *cfile)
1264e853bc5dShenning {
1265e853bc5dShenning char *val;
1266e853bc5dShenning int token;
1267e853bc5dShenning unsigned char addr[4];
1268e853bc5dShenning int len = sizeof addr;
1269e853bc5dShenning int seenmask = 0;
1270e853bc5dShenning int seenbit;
1271e853bc5dShenning char tbuf[32];
1272e853bc5dShenning static struct lease lease;
1273e853bc5dShenning
12749335a048Skrw /* Zap the lease structure. */
1275e853bc5dShenning memset(&lease, 0, sizeof lease);
1276e853bc5dShenning
1277e853bc5dShenning /* Get the address for which the lease has been issued. */
1278f3ec5800Sderaadt if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8))
12796a467ce1Sderaadt return NULL;
1280e853bc5dShenning memcpy(lease.ip_addr.iabuf, addr, len);
1281e853bc5dShenning lease.ip_addr.len = len;
1282e853bc5dShenning
1283e853bc5dShenning if (!parse_lbrace(cfile))
12846a467ce1Sderaadt return NULL;
1285e853bc5dShenning
1286e853bc5dShenning do {
1287e853bc5dShenning token = next_token(&val, cfile);
1288f3ec5800Sderaadt if (token == '}')
1289e853bc5dShenning break;
1290e853bc5dShenning else if (token == EOF) {
1291e853bc5dShenning parse_warn("unexpected end of file");
1292e853bc5dShenning break;
1293e853bc5dShenning }
1294e853bc5dShenning strlcpy(tbuf, val, sizeof tbuf);
1295e853bc5dShenning
1296e853bc5dShenning /* Parse any of the times associated with the lease. */
129735318e8fSkrw if (token == TOK_STARTS || token == TOK_ENDS || token ==
129835318e8fSkrw TOK_TIMESTAMP) {
1299fbc5e94dShenning time_t t;
1300e853bc5dShenning t = parse_date(cfile);
1301e853bc5dShenning switch (token) {
1302f3ec5800Sderaadt case TOK_STARTS:
1303e853bc5dShenning seenbit = 1;
1304e853bc5dShenning lease.starts = t;
1305e853bc5dShenning break;
1306e853bc5dShenning
1307f3ec5800Sderaadt case TOK_ENDS:
1308e853bc5dShenning seenbit = 2;
1309e853bc5dShenning lease.ends = t;
1310e853bc5dShenning break;
1311e853bc5dShenning
1312f3ec5800Sderaadt case TOK_TIMESTAMP:
1313e853bc5dShenning seenbit = 4;
1314e853bc5dShenning lease.timestamp = t;
1315e853bc5dShenning break;
1316e853bc5dShenning
1317e853bc5dShenning default:
1318e853bc5dShenning /*NOTREACHED*/
1319e853bc5dShenning seenbit = 0;
1320e853bc5dShenning break;
1321e853bc5dShenning }
1322e853bc5dShenning } else {
1323e853bc5dShenning switch (token) {
13249335a048Skrw /* Colon-separated hexadecimal octets. */
1325f3ec5800Sderaadt case TOK_UID:
1326e853bc5dShenning seenbit = 8;
1327e853bc5dShenning token = peek_token(&val, cfile);
1328f3ec5800Sderaadt if (token == TOK_STRING) {
1329e853bc5dShenning token = next_token(&val, cfile);
1330e853bc5dShenning lease.uid_len = strlen(val);
133135de856eSderaadt lease.uid = malloc(lease.uid_len);
1332e853bc5dShenning if (!lease.uid) {
1333c525a185Skrw log_warnx("no space for uid");
13346a467ce1Sderaadt return NULL;
1335e853bc5dShenning }
1336e853bc5dShenning memcpy(lease.uid, val, lease.uid_len);
1337e853bc5dShenning parse_semi(cfile);
1338e853bc5dShenning } else {
1339e853bc5dShenning lease.uid_len = 0;
1340cca1f910Shenning lease.uid =
1341cca1f910Shenning parse_numeric_aggregate(cfile,
13426a467ce1Sderaadt NULL, &lease.uid_len, ':', 16, 8);
1343e853bc5dShenning if (!lease.uid) {
1344c525a185Skrw log_warnx("no space for uid");
13456a467ce1Sderaadt return NULL;
1346e853bc5dShenning }
1347e853bc5dShenning if (lease.uid_len == 0) {
13486a467ce1Sderaadt lease.uid = NULL;
1349e853bc5dShenning parse_warn("zero-length uid");
1350e853bc5dShenning seenbit = 0;
1351e853bc5dShenning break;
1352e853bc5dShenning }
1353e853bc5dShenning }
13546a467ce1Sderaadt if (!lease.uid)
1355c525a185Skrw fatalx("No memory for lease uid");
1356e853bc5dShenning break;
1357e853bc5dShenning
1358f3ec5800Sderaadt case TOK_CLASS:
1359e853bc5dShenning seenbit = 32;
1360e853bc5dShenning token = next_token(&val, cfile);
1361e853bc5dShenning if (!is_identifier(token)) {
1362f3ec5800Sderaadt if (token != ';')
1363e853bc5dShenning skip_to_semi(cfile);
13646a467ce1Sderaadt return NULL;
1365e853bc5dShenning }
1366e853bc5dShenning /* for now, we aren't using this. */
1367e853bc5dShenning break;
1368e853bc5dShenning
1369f3ec5800Sderaadt case TOK_HARDWARE:
1370e853bc5dShenning seenbit = 64;
1371e853bc5dShenning parse_hardware_param(cfile,
1372e853bc5dShenning &lease.hardware_addr);
1373e853bc5dShenning break;
1374e853bc5dShenning
1375f3ec5800Sderaadt case TOK_DYNAMIC_BOOTP:
1376e853bc5dShenning seenbit = 128;
1377e853bc5dShenning lease.flags |= BOOTP_LEASE;
1378e853bc5dShenning break;
1379e853bc5dShenning
1380f3ec5800Sderaadt case TOK_ABANDONED:
1381e853bc5dShenning seenbit = 256;
1382e853bc5dShenning lease.flags |= ABANDONED_LEASE;
1383e853bc5dShenning break;
1384e853bc5dShenning
1385f3ec5800Sderaadt case TOK_HOSTNAME:
1386e853bc5dShenning seenbit = 512;
1387e853bc5dShenning token = peek_token(&val, cfile);
1388f3ec5800Sderaadt if (token == TOK_STRING)
1389e853bc5dShenning lease.hostname = parse_string(cfile);
1390e853bc5dShenning else
1391e853bc5dShenning lease.hostname =
1392e853bc5dShenning parse_host_name(cfile);
1393e853bc5dShenning if (!lease.hostname) {
1394e853bc5dShenning seenbit = 0;
13956a467ce1Sderaadt return NULL;
1396e853bc5dShenning }
1397e853bc5dShenning break;
1398e853bc5dShenning
1399f3ec5800Sderaadt case TOK_CLIENT_HOSTNAME:
1400e853bc5dShenning seenbit = 1024;
1401e853bc5dShenning token = peek_token(&val, cfile);
1402f3ec5800Sderaadt if (token == TOK_STRING)
1403e853bc5dShenning lease.client_hostname =
1404e853bc5dShenning parse_string(cfile);
1405e853bc5dShenning else
1406e853bc5dShenning lease.client_hostname =
1407e853bc5dShenning parse_host_name(cfile);
1408e853bc5dShenning break;
1409e853bc5dShenning
1410e853bc5dShenning default:
1411e853bc5dShenning skip_to_semi(cfile);
1412e853bc5dShenning seenbit = 0;
14136a467ce1Sderaadt return NULL;
1414e853bc5dShenning }
1415e853bc5dShenning
1416f3ec5800Sderaadt if (token != TOK_HARDWARE && token != TOK_STRING) {
1417e853bc5dShenning token = next_token(&val, cfile);
1418f3ec5800Sderaadt if (token != ';') {
1419e853bc5dShenning parse_warn("semicolon expected.");
1420e853bc5dShenning skip_to_semi(cfile);
14216a467ce1Sderaadt return NULL;
1422e853bc5dShenning }
1423e853bc5dShenning }
1424e853bc5dShenning }
1425e853bc5dShenning if (seenmask & seenbit) {
1426e853bc5dShenning parse_warn("Too many %s parameters in lease %s\n",
1427e853bc5dShenning tbuf, piaddr(lease.ip_addr));
1428e853bc5dShenning } else
1429e853bc5dShenning seenmask |= seenbit;
1430e853bc5dShenning
1431e853bc5dShenning } while (1);
1432e853bc5dShenning return &lease;
1433e853bc5dShenning }
1434e853bc5dShenning
14356a467ce1Sderaadt /*
14366a467ce1Sderaadt * address-range-declaration :== ip-address ip-address SEMI
14376a467ce1Sderaadt * | DYNAMIC_BOOTP ip-address ip-address SEMI
14386a467ce1Sderaadt */
14396a467ce1Sderaadt void
parse_address_range(FILE * cfile,struct subnet * subnet)14406a467ce1Sderaadt parse_address_range(FILE *cfile, struct subnet *subnet)
1441e853bc5dShenning {
1442e853bc5dShenning struct iaddr low, high;
1443e853bc5dShenning unsigned char addr[4];
14446a467ce1Sderaadt int len = sizeof addr, token, dynamic = 0;
1445e853bc5dShenning char *val;
1446e853bc5dShenning
1447f3ec5800Sderaadt if ((token = peek_token(&val, cfile)) == TOK_DYNAMIC_BOOTP) {
1448e853bc5dShenning token = next_token(&val, cfile);
1449e853bc5dShenning subnet->group->dynamic_bootp = dynamic = 1;
1450e853bc5dShenning }
1451e853bc5dShenning
14529335a048Skrw /* Get the bottom address in the range. */
1453f3ec5800Sderaadt if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8))
1454e853bc5dShenning return;
1455e853bc5dShenning memcpy(low.iabuf, addr, len);
1456e853bc5dShenning low.len = len;
1457e853bc5dShenning
1458e853bc5dShenning /* Only one address? */
1459e853bc5dShenning token = peek_token(&val, cfile);
1460f3ec5800Sderaadt if (token == ';')
1461e853bc5dShenning high = low;
1462e853bc5dShenning else {
14639335a048Skrw /* Get the top address in the range. */
1464f3ec5800Sderaadt if (!parse_numeric_aggregate(cfile, addr, &len, '.', 10, 8))
1465e853bc5dShenning return;
1466e853bc5dShenning memcpy(high.iabuf, addr, len);
1467e853bc5dShenning high.len = len;
1468e853bc5dShenning }
1469e853bc5dShenning
1470e853bc5dShenning token = next_token(&val, cfile);
1471f3ec5800Sderaadt if (token != ';') {
1472e853bc5dShenning parse_warn("semicolon expected.");
1473e853bc5dShenning skip_to_semi(cfile);
1474e853bc5dShenning return;
1475e853bc5dShenning }
1476e853bc5dShenning
14779335a048Skrw /* Create the new address range. */
1478e853bc5dShenning new_address_range(low, high, subnet, dynamic);
1479e853bc5dShenning }
14801fef8917Skrw
14811fef8917Skrw static void
push_domain_list(char *** domains,size_t * count,char * domain)14821fef8917Skrw push_domain_list(char ***domains, size_t *count, char *domain)
14831fef8917Skrw {
14841fef8917Skrw *domains = reallocarray(*domains, *count + 1, sizeof **domains);
14851fef8917Skrw if (!*domains)
14861fef8917Skrw fatalx("Can't allocate domain list");
14871fef8917Skrw
14881fef8917Skrw (*domains)[*count] = domain;
14891fef8917Skrw ++*count;
14901fef8917Skrw }
14911fef8917Skrw
14921fef8917Skrw static void
free_domain_list(char ** domains,size_t count)14931fef8917Skrw free_domain_list(char **domains, size_t count)
14941fef8917Skrw {
149534bf9f2aSvisa size_t i;
149634bf9f2aSvisa
149734bf9f2aSvisa for (i = 0; i < count; i++)
14981fef8917Skrw free(domains[i]);
14991fef8917Skrw free(domains);
15001fef8917Skrw }
15011fef8917Skrw
15021fef8917Skrw struct tree *
parse_domain_and_comp(FILE * cfile)15031fef8917Skrw parse_domain_and_comp(FILE *cfile)
15041fef8917Skrw {
15051fef8917Skrw struct tree *rv = NULL;
15061fef8917Skrw char **domains = NULL;
15071fef8917Skrw char *val, *domain;
15081fef8917Skrw unsigned char *buf = NULL;
15091fef8917Skrw unsigned char **bufptrs = NULL;
151034bf9f2aSvisa size_t bufsiz = 0, bufn = 0, count = 0, i;
15111fef8917Skrw int token = ';';
15121fef8917Skrw
15131fef8917Skrw do {
15141fef8917Skrw if (token == ',')
15151fef8917Skrw token = next_token(&val, cfile);
15161fef8917Skrw
15171fef8917Skrw token = next_token(&val, cfile);
15181fef8917Skrw if (token != TOK_STRING) {
15191fef8917Skrw parse_warn("string expected");
15201fef8917Skrw goto error;
15211fef8917Skrw }
15221fef8917Skrw domain = strdup(val);
15231fef8917Skrw if (domain == NULL)
15241fef8917Skrw fatalx("Can't allocate domain to compress");
15251fef8917Skrw push_domain_list(&domains, &count, domain);
15261fef8917Skrw
15271fef8917Skrw /*
15281fef8917Skrw * openbsd.org normally compresses to [7]openbsd[3]org[0].
15291fef8917Skrw * +2 to string length provides space for leading and
15301fef8917Skrw * trailing (root) prefix lengths not already accounted for
15311fef8917Skrw * by dots, and also provides sufficient space for pointer
15321fef8917Skrw * compression.
15331fef8917Skrw */
15341fef8917Skrw bufsiz = bufsiz + 2 + strlen(domain);
15351fef8917Skrw token = peek_token(NULL, cfile);
15361fef8917Skrw } while (token == ',');
15371fef8917Skrw
15381fef8917Skrw buf = malloc(bufsiz);
15391fef8917Skrw if (!buf)
15401fef8917Skrw fatalx("Can't allocate compressed domain buffer");
15411fef8917Skrw bufptrs = calloc(count + 1, sizeof *bufptrs);
15421fef8917Skrw if (!bufptrs)
15431fef8917Skrw fatalx("Can't allocate compressed pointer list");
15441fef8917Skrw bufptrs[0] = buf;
15451fef8917Skrw
15461fef8917Skrw /* dn_comp takes an int for the output buffer size */
15471fef8917Skrw if (!(bufsiz <= INT_MAX))
15481fef8917Skrw fatalx("Size of compressed domain buffer too large");
154934bf9f2aSvisa for (i = 0; i < count; i++) {
15501fef8917Skrw int n;
15511fef8917Skrw
15521fef8917Skrw /* see bufsiz <= INT_MAX assertion, above */
15531fef8917Skrw n = dn_comp(domains[i], &buf[bufn], bufsiz - bufn, bufptrs,
15541fef8917Skrw &bufptrs[count + 1]);
15551fef8917Skrw if (n == -1)
15561fef8917Skrw fatalx("Can't compress domain");
15571fef8917Skrw bufn += (size_t)n;
15581fef8917Skrw }
15591fef8917Skrw
15601fef8917Skrw rv = tree_const(buf, bufn);
15611fef8917Skrw error:
15621fef8917Skrw free_domain_list(domains, count);
15631fef8917Skrw free(buf);
15641fef8917Skrw free(bufptrs);
15651fef8917Skrw return rv;
15661fef8917Skrw }
1567