~ubuntu-branches/ubuntu/oneiric/isc-dhcp/oneiric-security

« back to all changes in this revision

Viewing changes to client/clparse.c

  • Committer: Bazaar Package Importer
  • Author(s): Andrew Pollock
  • Date: 2009-09-02 22:34:25 UTC
  • Revision ID: james.westby@ubuntu.com-20090902223425-nypo7bkftxffq41m
Tags: upstream-4.1.0
ImportĀ upstreamĀ versionĀ 4.1.0

Show diffs side-by-side

added added

removed removed

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