00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #define DHCP_OPTION_DATA
00030 #include "dhcpd.h"
00031 #include <omapip/omapip_p.h>
00032 #include <limits.h>
00033
00034 struct option *vendor_cfg_option;
00035
00036 static int pretty_text(char **, char *, const unsigned char **,
00037 const unsigned char *, int);
00038 static int pretty_domain(char **, char *, const unsigned char **,
00039 const unsigned char *);
00040 static int prepare_option_buffer(struct universe *universe, struct buffer *bp,
00041 unsigned char *buffer, unsigned length,
00042 unsigned code, int terminatep,
00043 struct option_cache **opp);
00044
00045
00046
00047 int parse_options (packet)
00048 struct packet *packet;
00049 {
00050 struct option_cache *op = (struct option_cache *)0;
00051
00052
00053 if (!option_state_allocate (&packet -> options, MDL)) {
00054 packet -> options_valid = 0;
00055 return 0;
00056 }
00057
00058
00059 if (memcmp (packet -> raw -> options, DHCP_OPTIONS_COOKIE, 4)) {
00060 packet -> options_valid = 0;
00061 return 1;
00062 }
00063
00064
00065
00066 if (!parse_option_buffer (packet -> options,
00067 &packet -> raw -> options [4],
00068 (packet -> packet_length -
00069 DHCP_FIXED_NON_UDP - 4),
00070 &dhcp_universe)) {
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084 if ((op = lookup_option (&dhcp_universe, packet -> options,
00085 DHO_DHCP_MESSAGE_TYPE))) {
00086 if (!op -> data.data ||
00087 (op -> data.data [0] != DHCPOFFER &&
00088 op -> data.data [0] != DHCPACK &&
00089 op -> data.data [0] != DHCPNAK))
00090 return 0;
00091 } else
00092 return 0;
00093 }
00094
00095
00096
00097 if ((op = lookup_option (&dhcp_universe, packet -> options,
00098 DHO_DHCP_OPTION_OVERLOAD))) {
00099 if (op -> data.data [0] & 1) {
00100 if (!parse_option_buffer
00101 (packet -> options,
00102 (unsigned char *)packet -> raw -> file,
00103 sizeof packet -> raw -> file,
00104 &dhcp_universe))
00105 return 0;
00106 }
00107 if (op -> data.data [0] & 2) {
00108 if (!parse_option_buffer
00109 (packet -> options,
00110 (unsigned char *)packet -> raw -> sname,
00111 sizeof packet -> raw -> sname,
00112 &dhcp_universe))
00113 return 0;
00114 }
00115 }
00116 packet -> options_valid = 1;
00117 return 1;
00118 }
00119
00120
00121
00122
00123 int parse_option_buffer (options, buffer, length, universe)
00124 struct option_state *options;
00125 const unsigned char *buffer;
00126 unsigned length;
00127 struct universe *universe;
00128 {
00129 unsigned len, offset;
00130 unsigned code;
00131 struct option_cache *op = NULL, *nop = NULL;
00132 struct buffer *bp = (struct buffer *)0;
00133 struct option *option = NULL;
00134 char *reason = "general failure";
00135
00136 if (!buffer_allocate (&bp, length, MDL)) {
00137 log_error ("no memory for option buffer.");
00138 return 0;
00139 }
00140 memcpy (bp -> data, buffer, length);
00141
00142 for (offset = 0;
00143 (offset + universe->tag_size) <= length &&
00144 (code = universe->get_tag(buffer + offset)) != universe->end; ) {
00145 offset += universe->tag_size;
00146
00147
00148 if (code == DHO_PAD)
00149 continue;
00150
00151
00152 if ((offset + universe->length_size) > length) {
00153 reason = "code tag at end of buffer - missing "
00154 "length field";
00155 goto bogus;
00156 }
00157
00158
00159
00160
00161
00162
00163
00164
00165 if (universe->get_length != NULL)
00166 len = universe->get_length(buffer + offset);
00167 else if (universe->length_size == 0)
00168 len = length - universe->tag_size;
00169 else {
00170 log_fatal("Improperly configured option space(%s): "
00171 "may not have a nonzero length size "
00172 "AND a NULL get_length function.",
00173 universe->name);
00174
00175
00176 return 0;
00177 }
00178
00179 offset += universe->length_size;
00180
00181 option_code_hash_lookup(&option, universe->code_hash, &code,
00182 0, MDL);
00183
00184
00185 if (offset + len > length) {
00186 reason = "option length exceeds option buffer length";
00187 bogus:
00188 log_error("parse_option_buffer: malformed option "
00189 "%s.%s (code %u): %s.", universe->name,
00190 option ? option->name : "<unknown>",
00191 code, reason);
00192 buffer_dereference (&bp, MDL);
00193 return 0;
00194 }
00195
00196
00197
00198
00199
00200 if (!(option &&
00201 (option->format[0] == 'e' ||
00202 option->format[0] == 'E') &&
00203 (parse_encapsulated_suboptions(options, option,
00204 bp->data + offset, len,
00205 universe, NULL)))) {
00206 op = lookup_option(universe, options, code);
00207
00208 if (op != NULL && universe->concat_duplicates) {
00209 struct data_string new;
00210 memset(&new, 0, sizeof new);
00211 if (!buffer_allocate(&new.buffer,
00212 op->data.len + len,
00213 MDL)) {
00214 log_error("parse_option_buffer: "
00215 "No memory.");
00216 buffer_dereference(&bp, MDL);
00217 return 0;
00218 }
00219
00220 memcpy(new.buffer->data, op->data.data,
00221 op->data.len);
00222
00223 memcpy(new.buffer->data + op->data.len,
00224 bp->data + offset, len);
00225 new.len = op->data.len + len;
00226 new.data = new.buffer->data;
00227
00228 data_string_forget(&op->data, MDL);
00229 data_string_copy(&op->data, &new, MDL);
00230 data_string_forget(&new, MDL);
00231 } else if (op != NULL) {
00232
00233
00234
00235 while (op->next != NULL)
00236 op = op->next;
00237
00238 if (!option_cache_allocate(&nop, MDL)) {
00239 log_error("parse_option_buffer: "
00240 "No memory.");
00241 buffer_dereference(&bp, MDL);
00242 return 0;
00243 }
00244
00245 option_reference(&nop->option, op->option, MDL);
00246
00247 nop->data.buffer = NULL;
00248 buffer_reference(&nop->data.buffer, bp, MDL);
00249 nop->data.data = bp->data + offset;
00250 nop->data.len = len;
00251
00252 option_cache_reference(&op->next, nop, MDL);
00253 option_cache_dereference(&nop, MDL);
00254 } else {
00255 if (save_option_buffer(universe, options, bp,
00256 bp->data + offset, len,
00257 code, 1) == 0) {
00258 log_error("parse_option_buffer: "
00259 "save_option_buffer failed");
00260 buffer_dereference(&bp, MDL);
00261 return 0;
00262 }
00263 }
00264 }
00265 option_dereference(&option, MDL);
00266 offset += len;
00267 }
00268 buffer_dereference (&bp, MDL);
00269 return 1;
00270 }
00271
00272
00273
00274
00275
00276
00277 struct universe *find_option_universe (struct option *eopt, const char *uname)
00278 {
00279 int i;
00280 char *s, *t;
00281 struct universe *universe = (struct universe *)0;
00282
00283
00284 s = strchr (eopt -> format, 'E');
00285 if (!s) {
00286 log_error ("internal encapsulation format error 1.");
00287 return 0;
00288 }
00289
00290 t = strchr (++s, '.');
00291
00292
00293 if (!t || t [1]) {
00294 log_error ("internal encapsulation format error 2.");
00295 return 0;
00296 }
00297 if (t == s && uname) {
00298 for (i = 0; i < universe_count; i++) {
00299 if (!strcmp (universes [i] -> name, uname)) {
00300 universe = universes [i];
00301 break;
00302 }
00303 }
00304 } else if (t != s) {
00305 for (i = 0; i < universe_count; i++) {
00306 if (strlen (universes [i] -> name) == t - s &&
00307 !memcmp (universes [i] -> name,
00308 s, (unsigned)(t - s))) {
00309 universe = universes [i];
00310 break;
00311 }
00312 }
00313 }
00314 return universe;
00315 }
00316
00317
00318
00319
00320
00321
00322 int parse_encapsulated_suboptions (struct option_state *options,
00323 struct option *eopt,
00324 const unsigned char *buffer,
00325 unsigned len, struct universe *eu,
00326 const char *uname)
00327 {
00328 int i;
00329 struct universe *universe = find_option_universe (eopt, uname);
00330
00331
00332
00333
00334 if (!universe)
00335 return 0;
00336
00337
00338
00339 if (!universe -> decode)
00340 return 0;
00341
00342 i = (*universe -> decode) (options, buffer, len, universe);
00343
00344
00345 if (eopt -> format [0] != 'E')
00346 return 0;
00347
00348 return i;
00349 }
00350
00351 int fqdn_universe_decode (struct option_state *options,
00352 const unsigned char *buffer,
00353 unsigned length, struct universe *u)
00354 {
00355 struct buffer *bp = (struct buffer *)0;
00356
00357
00358 if (length < 3)
00359 return 0;
00360
00361
00362 if (!buffer_allocate (&bp, length + 4, MDL)) {
00363 log_error ("no memory for option buffer.");
00364 return 0;
00365 }
00366 memcpy (&bp -> data [3], buffer + 1, length - 1);
00367
00368 if (buffer [0] & 4)
00369 bp -> data [0] = 1;
00370 else
00371 bp -> data [0] = 0;
00372 if (!save_option_buffer(&fqdn_universe, options, bp,
00373 bp->data, 1, FQDN_ENCODED, 0)) {
00374 bad:
00375 buffer_dereference (&bp, MDL);
00376 return 0;
00377 }
00378
00379 if (buffer [0] & 1)
00380 bp -> data [2] = 1;
00381 else
00382 bp -> data [2] = 0;
00383 if (buffer [0] & 2)
00384 bp -> data [1] = 1;
00385 else
00386 bp -> data [1] = 0;
00387
00388
00389
00390
00391
00392
00393
00394
00395 if (!bp -> data [0]) {
00396 unsigned i;
00397
00398
00399 if (buffer [length - 1] == 0) {
00400 --length;
00401 bp -> data [1] = 1;
00402 }
00403
00404
00405
00406
00407 for (i = 3; i < length && buffer [i] != '.'; i++);
00408 i -= 3;
00409
00410
00411
00412 if (i && (!save_option_buffer(&fqdn_universe, options, bp,
00413 &bp->data[5], i,
00414 FQDN_HOSTNAME, 0)))
00415 goto bad;
00416
00417
00418 if (length > 4 + i &&
00419 (!save_option_buffer(&fqdn_universe, options, bp,
00420 &bp -> data[6 + i], length - 4 - i,
00421 FQDN_DOMAINNAME, 1)))
00422 goto bad;
00423
00424 if (length > 3) {
00425 if (!save_option_buffer(&fqdn_universe, options, bp,
00426 &bp -> data [5], length - 3,
00427 FQDN_FQDN, 1))
00428 goto bad;
00429 }
00430 } else {
00431 unsigned len;
00432 unsigned total_len = 0;
00433 unsigned first_len = 0;
00434 int terminated = 0;
00435 unsigned char *s;
00436
00437 s = &bp -> data[5];
00438
00439 while (s < &bp -> data[0] + length + 2) {
00440 len = *s;
00441 if (len > 63) {
00442 log_info ("fancy bits in fqdn option");
00443 return 0;
00444 }
00445 if (len == 0) {
00446 terminated = 1;
00447 break;
00448 }
00449 if (s + len > &bp -> data [0] + length + 3) {
00450 log_info ("fqdn tag longer than buffer");
00451 return 0;
00452 }
00453
00454 if (first_len == 0) {
00455 first_len = len;
00456 }
00457
00458 *s = '.';
00459 s += len + 1;
00460 total_len += len + 1;
00461 }
00462
00463
00464
00465
00466
00467 if (total_len > 0)
00468 total_len--;
00469
00470 if (!terminated) {
00471 first_len = total_len;
00472 }
00473
00474 if (first_len > 0 &&
00475 !save_option_buffer(&fqdn_universe, options, bp,
00476 &bp -> data[6], first_len,
00477 FQDN_HOSTNAME, 0))
00478 goto bad;
00479 if (total_len > 0 && first_len != total_len) {
00480 if (!save_option_buffer(&fqdn_universe, options, bp,
00481 &bp->data[6 + first_len],
00482 total_len - first_len,
00483 FQDN_DOMAINNAME, 1))
00484 goto bad;
00485 }
00486 if (total_len > 0)
00487 if (!save_option_buffer (&fqdn_universe, options, bp,
00488 &bp -> data [6], total_len,
00489 FQDN_FQDN, 1))
00490 goto bad;
00491 }
00492
00493 if (!save_option_buffer (&fqdn_universe, options, bp,
00494 &bp -> data [1], 1,
00495 FQDN_NO_CLIENT_UPDATE, 0))
00496 goto bad;
00497 if (!save_option_buffer (&fqdn_universe, options, bp,
00498 &bp -> data [2], 1,
00499 FQDN_SERVER_UPDATE, 0))
00500 goto bad;
00501
00502 if (!save_option_buffer (&fqdn_universe, options, bp,
00503 &bp -> data [3], 1,
00504 FQDN_RCODE1, 0))
00505 goto bad;
00506 if (!save_option_buffer (&fqdn_universe, options, bp,
00507 &bp -> data [4], 1,
00508 FQDN_RCODE2, 0))
00509 goto bad;
00510
00511 buffer_dereference (&bp, MDL);
00512 return 1;
00513 }
00514
00515
00516
00517
00518
00519
00520
00521
00522 int
00523 cons_options(struct packet *inpacket, struct dhcp_packet *outpacket,
00524 struct lease *lease, struct client_state *client_state,
00525 int mms, struct option_state *in_options,
00526 struct option_state *cfg_options,
00527 struct binding_scope **scope,
00528 int overload_avail, int terminate, int bootpp,
00529 struct data_string *prl, const char *vuname)
00530 {
00531 #define PRIORITY_COUNT 300
00532 unsigned priority_list[PRIORITY_COUNT];
00533 int priority_len;
00534 unsigned char buffer[4096], agentopts[1024];
00535 unsigned index = 0;
00536 unsigned mb_size = 0, mb_max = 0;
00537 unsigned option_size = 0, agent_size = 0;
00538 unsigned length;
00539 int i;
00540 struct option_cache *op;
00541 struct data_string ds;
00542 pair pp, *hash;
00543 int overload_used = 0;
00544 int of1 = 0, of2 = 0;
00545
00546 memset(&ds, 0, sizeof ds);
00547
00548
00549
00550
00551
00552
00553
00554
00555 if (inpacket &&
00556 (op = lookup_option(&dhcp_universe, inpacket->options,
00557 DHO_DHCP_MAX_MESSAGE_SIZE)) &&
00558 (evaluate_option_cache(&ds, inpacket, lease,
00559 client_state, in_options,
00560 cfg_options, scope, op, MDL) != 0)) {
00561 if (ds.len >= sizeof (u_int16_t)) {
00562 i = getUShort(ds.data);
00563 if(!mms || (i < mms))
00564 mms = i;
00565 }
00566 data_string_forget(&ds, MDL);
00567 }
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578 if (mms) {
00579 if (mms < DHCP_MTU_MIN)
00580
00581 mb_size = DHCP_MIN_OPTION_LEN;
00582 else if (mms > DHCP_MTU_MAX)
00583
00584
00585
00586
00587
00588
00589
00590 mb_size = DHCP_MAX_OPTION_LEN;
00591 else
00592 mb_size = mms - DHCP_FIXED_LEN;
00593 } else if (bootpp) {
00594 mb_size = 64;
00595 if (inpacket != NULL &&
00596 (inpacket->packet_length >= 64 + DHCP_FIXED_NON_UDP))
00597 mb_size = inpacket->packet_length - DHCP_FIXED_NON_UDP;
00598 } else
00599 mb_size = DHCP_MIN_OPTION_LEN;
00600
00601
00602
00603
00604
00605
00606
00607 if (client_state == NULL) {
00608 priority_list[0] = DHO_DHCP_AGENT_OPTIONS;
00609 priority_len = 1;
00610 agent_size = store_options(NULL, agentopts, 0,
00611 sizeof(agentopts),
00612 inpacket, lease, client_state,
00613 in_options, cfg_options, scope,
00614 priority_list, priority_len,
00615 0, 0, 0, NULL);
00616
00617 mb_size += agent_size;
00618 if (mb_size > DHCP_MAX_OPTION_LEN)
00619 mb_size = DHCP_MAX_OPTION_LEN;
00620 }
00621
00622
00623
00624
00625
00626 mb_max = mb_size;
00627
00628 if (overload_avail & 1) {
00629 of1 = mb_max;
00630 mb_max += DHCP_FILE_LEN;
00631 }
00632
00633 if (overload_avail & 2) {
00634 of2 = mb_max;
00635 mb_max += DHCP_SNAME_LEN;
00636 }
00637
00638
00639
00640
00641
00642
00643
00644 priority_len = 0;
00645 priority_list[priority_len++] = DHO_DHCP_MESSAGE_TYPE;
00646 priority_list[priority_len++] = DHO_DHCP_SERVER_IDENTIFIER;
00647 priority_list[priority_len++] = DHO_DHCP_LEASE_TIME;
00648 priority_list[priority_len++] = DHO_DHCP_RENEWAL_TIME;
00649 priority_list[priority_len++] = DHO_DHCP_REBINDING_TIME;
00650 priority_list[priority_len++] = DHO_DHCP_MESSAGE;
00651 priority_list[priority_len++] = DHO_DHCP_REQUESTED_ADDRESS;
00652 priority_list[priority_len++] = DHO_ASSOCIATED_IP;
00653
00654 if (prl != NULL && prl->len > 0) {
00655 if ((op = lookup_option(&dhcp_universe, cfg_options,
00656 DHO_SUBNET_SELECTION))) {
00657 if (priority_len < PRIORITY_COUNT)
00658 priority_list[priority_len++] =
00659 DHO_SUBNET_SELECTION;
00660 }
00661
00662 data_string_truncate(prl, (PRIORITY_COUNT - priority_len));
00663
00664
00665
00666
00667
00668 for (i = 0; i < prl->len; i++) {
00669
00670
00671
00672
00673 if (prl->data[i] != DHO_DHCP_AGENT_OPTIONS)
00674 priority_list[priority_len++] = prl->data[i];
00675 }
00676
00677
00678
00679
00680
00681
00682
00683 if ((inpacket != NULL) && (priority_len < PRIORITY_COUNT) &&
00684 (lookup_option(&fqdn_universe, inpacket->options,
00685 FQDN_ENCODED) != NULL))
00686 priority_list[priority_len++] = DHO_FQDN;
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699 if ((inpacket != NULL) && (priority_len < PRIORITY_COUNT) &&
00700 ((inpacket->packet_type == DHCPDISCOVER) ||
00701 (inpacket->packet_type == DHCPREQUEST)))
00702 priority_list[priority_len++] = DHO_SUBNET_MASK;
00703 } else {
00704
00705
00706
00707
00708
00709 priority_list[priority_len++] = DHO_SUBNET_MASK;
00710 if (lookup_option(&dhcp_universe, cfg_options,
00711 DHO_CLASSLESS_STATIC_ROUTES))
00712 priority_list[priority_len++] = DHO_CLASSLESS_STATIC_ROUTES;
00713 else
00714 priority_list[priority_len++] = DHO_ROUTERS;
00715 priority_list[priority_len++] = DHO_DOMAIN_NAME_SERVERS;
00716 priority_list[priority_len++] = DHO_HOST_NAME;
00717 priority_list[priority_len++] = DHO_FQDN;
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728 if (cfg_options->site_code_min) {
00729 for (i = 0; i < OPTION_HASH_SIZE; i++) {
00730 hash = cfg_options->universes[dhcp_universe.index];
00731 if (hash) {
00732 for (pp = hash[i]; pp; pp = pp->cdr) {
00733 op = (struct option_cache *)(pp->car);
00734 if (op->option->code <
00735 cfg_options->site_code_min &&
00736 priority_len < PRIORITY_COUNT &&
00737 op->option->code != DHO_DHCP_AGENT_OPTIONS)
00738 priority_list[priority_len++] =
00739 op->option->code;
00740 }
00741 }
00742 }
00743 }
00744
00745
00746
00747
00748
00749
00750 for (i = 0; i < OPTION_HASH_SIZE; i++) {
00751 hash = cfg_options->universes[cfg_options->site_universe];
00752 if (hash != NULL)
00753 for (pp = hash[i]; pp; pp = pp->cdr) {
00754 op = (struct option_cache *)(pp->car);
00755 if (op->option->code >=
00756 cfg_options->site_code_min &&
00757 priority_len < PRIORITY_COUNT &&
00758 op->option->code != DHO_DHCP_AGENT_OPTIONS)
00759 priority_list[priority_len++] =
00760 op->option->code;
00761 }
00762 }
00763
00764
00765
00766
00767
00768 for (i = 0; i < cfg_options->universe_count; i++) {
00769 if (universes[i]->enc_opt &&
00770 priority_len < PRIORITY_COUNT &&
00771 universes[i]->enc_opt->universe == &dhcp_universe) {
00772 if (universes[i]->enc_opt->code !=
00773 DHO_DHCP_AGENT_OPTIONS)
00774 priority_list[priority_len++] =
00775 universes[i]->enc_opt->code;
00776 }
00777 }
00778
00779
00780
00781
00782
00783 if (priority_len < PRIORITY_COUNT)
00784 priority_list[priority_len++] =
00785 DHO_VENDOR_ENCAPSULATED_OPTIONS;
00786 }
00787
00788
00789 memcpy(buffer, DHCP_OPTIONS_COOKIE, 4);
00790 index += 4;
00791
00792
00793 option_size = store_options(&overload_used, buffer, index, mb_max,
00794 inpacket, lease, client_state,
00795 in_options, cfg_options, scope,
00796 priority_list, priority_len,
00797 of1, of2, terminate, vuname);
00798
00799
00800 if (option_size == 0)
00801 return 0;
00802
00803
00804 index += option_size;
00805
00806
00807
00808
00809
00810 if (overload_used) {
00811 if (mb_size - agent_size - index < 3)
00812 return 0;
00813
00814 buffer[index++] = DHO_DHCP_OPTION_OVERLOAD;
00815 buffer[index++] = 1;
00816 buffer[index++] = overload_used;
00817
00818 if (overload_used & 1)
00819 memcpy(outpacket->file, &buffer[of1], DHCP_FILE_LEN);
00820
00821 if (overload_used & 2)
00822 memcpy(outpacket->sname, &buffer[of2], DHCP_SNAME_LEN);
00823 }
00824
00825
00826 if (agent_size) {
00827 if (mb_size - index >= agent_size) {
00828 memcpy(&buffer[index], agentopts, agent_size);
00829 index += agent_size;
00830 } else
00831 log_error("Unable to store relay agent information "
00832 "in reply packet.");
00833 }
00834
00835
00836 if (index < mb_size)
00837 buffer[index++] = DHO_END;
00838
00839
00840 memcpy(outpacket->options, buffer, index);
00841
00842
00843 length = DHCP_FIXED_NON_UDP + index;
00844 return length;
00845 }
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856 struct vsio_state {
00857 char *buf;
00858 int buflen;
00859 int bufpos;
00860 };
00861
00862 static void
00863 vsio_options(struct option_cache *oc,
00864 struct packet *packet,
00865 struct lease *dummy_lease,
00866 struct client_state *dummy_client_state,
00867 struct option_state *dummy_opt_state,
00868 struct option_state *opt_state,
00869 struct binding_scope **dummy_binding_scope,
00870 struct universe *universe,
00871 void *void_vsio_state) {
00872 struct vsio_state *vs = (struct vsio_state *)void_vsio_state;
00873 struct data_string ds;
00874 int total_len;
00875
00876 memset(&ds, 0, sizeof(ds));
00877 if (evaluate_option_cache(&ds, packet, NULL,
00878 NULL, opt_state, NULL,
00879 &global_scope, oc, MDL)) {
00880 total_len = ds.len + universe->tag_size + universe->length_size;
00881 if (total_len <= (vs->buflen - vs->bufpos)) {
00882 if (universe->tag_size == 1) {
00883 vs->buf[vs->bufpos++] = oc->option->code;
00884 } else if (universe->tag_size == 2) {
00885 putUShort((unsigned char *)vs->buf+vs->bufpos,
00886 oc->option->code);
00887 vs->bufpos += 2;
00888 } else if (universe->tag_size == 4) {
00889 putULong((unsigned char *)vs->buf+vs->bufpos,
00890 oc->option->code);
00891 vs->bufpos += 4;
00892 }
00893 if (universe->length_size == 1) {
00894 vs->buf[vs->bufpos++] = ds.len;
00895 } else if (universe->length_size == 2) {
00896 putUShort((unsigned char *)vs->buf+vs->bufpos,
00897 ds.len);
00898 vs->bufpos += 2;
00899 } else if (universe->length_size == 4) {
00900 putULong((unsigned char *)vs->buf+vs->bufpos,
00901 ds.len);
00902 vs->bufpos += 4;
00903 }
00904 memcpy(vs->buf + vs->bufpos, ds.data, ds.len);
00905 vs->bufpos += ds.len;
00906 } else {
00907 log_debug("No space for option %d in VSIO space %s.",
00908 oc->option->code, universe->name);
00909 }
00910 data_string_forget(&ds, MDL);
00911 } else {
00912 log_error("Error evaluating option %d in VSIO space %s.",
00913 oc->option->code, universe->name);
00914 }
00915 }
00916
00917
00918
00919
00920
00921
00922
00923
00924 int
00925 store_options6(char *buf, int buflen,
00926 struct option_state *opt_state,
00927 struct packet *packet,
00928 const int *required_opts,
00929 struct data_string *oro) {
00930 int i, j;
00931 struct option_cache *oc;
00932 struct option *o;
00933 struct data_string ds;
00934 int bufpos;
00935 int oro_size;
00936 u_int16_t code;
00937 int in_required_opts;
00938 int vsio_option_code;
00939 int vsio_wanted;
00940 struct vsio_state vs;
00941 unsigned char *tmp;
00942
00943 bufpos = 0;
00944 vsio_wanted = 0;
00945
00946
00947
00948
00949 vsio_option_code = 0;
00950 o = vsio_universe.enc_opt;
00951 while (o != NULL) {
00952 if (o->universe == &dhcpv6_universe) {
00953 vsio_option_code = o->code;
00954 break;
00955 }
00956 o = o->universe->enc_opt;
00957 }
00958 if (vsio_option_code == 0) {
00959 log_fatal("No VSIO option code found.");
00960 }
00961
00962 if (required_opts != NULL) {
00963 for (i=0; required_opts[i] != 0; i++) {
00964 if (required_opts[i] == vsio_option_code) {
00965 vsio_wanted = 1;
00966 }
00967
00968 oc = lookup_option(&dhcpv6_universe,
00969 opt_state, required_opts[i]);
00970 if (oc == NULL) {
00971 continue;
00972 }
00973 memset(&ds, 0, sizeof(ds));
00974 for (; oc != NULL ; oc = oc->next) {
00975 if (evaluate_option_cache(&ds, packet, NULL,
00976 NULL, opt_state,
00977 NULL, &global_scope,
00978 oc, MDL)) {
00979 if ((ds.len + 4) <=
00980 (buflen - bufpos)) {
00981 tmp = (unsigned char *)buf;
00982 tmp += bufpos;
00983
00984 putUShort(tmp,
00985 required_opts[i]);
00986
00987 putUShort(tmp+2, ds.len);
00988
00989 memcpy(tmp+4, ds.data, ds.len);
00990
00991 bufpos += (4 + ds.len);
00992 } else {
00993 log_debug("No space for "
00994 "option %d",
00995 required_opts[i]);
00996 }
00997 data_string_forget(&ds, MDL);
00998 } else {
00999 log_error("Error evaluating option %d",
01000 required_opts[i]);
01001 }
01002 }
01003 }
01004 }
01005
01006 if (oro == NULL) {
01007 oro_size = 0;
01008 } else {
01009 oro_size = oro->len / 2;
01010 }
01011 for (i=0; i<oro_size; i++) {
01012 memcpy(&code, oro->data+(i*2), 2);
01013 code = ntohs(code);
01014
01015
01016
01017
01018
01019 in_required_opts = 0;
01020 if (required_opts != NULL) {
01021 for (j=0; required_opts[j] != 0; j++) {
01022 if (required_opts[j] == code) {
01023 in_required_opts = 1;
01024 break;
01025 }
01026 }
01027 }
01028 if (in_required_opts) {
01029 continue;
01030 }
01031
01032
01033
01034
01035 if (code == vsio_option_code) {
01036 vsio_wanted = 1;
01037 }
01038
01039
01040
01041
01042 oc = lookup_option(&dhcpv6_universe, opt_state, code);
01043 memset(&ds, 0, sizeof(ds));
01044 for (; oc != NULL ; oc = oc->next) {
01045 if (evaluate_option_cache(&ds, packet, NULL, NULL,
01046 opt_state, NULL,
01047 &global_scope, oc, MDL)) {
01048 if ((ds.len + 4) <= (buflen - bufpos)) {
01049 tmp = (unsigned char *)buf + bufpos;
01050
01051 putUShort(tmp, code);
01052
01053 putUShort(tmp+2, ds.len);
01054
01055 memcpy(tmp+4, ds.data, ds.len);
01056
01057 bufpos += (4 + ds.len);
01058 } else {
01059 log_debug("No space for option %d",
01060 code);
01061 }
01062 data_string_forget(&ds, MDL);
01063 } else {
01064 log_error("Error evaluating option %d", code);
01065 }
01066 }
01067 }
01068
01069 if (vsio_wanted) {
01070 for (i=0; i < opt_state->universe_count; i++) {
01071 if (opt_state->universes[i] != NULL) {
01072 o = universes[i]->enc_opt;
01073 if ((o != NULL) &&
01074 (o->universe == &vsio_universe)) {
01075
01076
01077
01078 vs.buf = buf;
01079 vs.buflen = buflen;
01080 vs.bufpos = bufpos+8;
01081 option_space_foreach(packet, NULL,
01082 NULL,
01083 NULL, opt_state,
01084 NULL,
01085 universes[i],
01086 (void *)&vs,
01087 vsio_options);
01088
01089
01090
01091
01092
01093 if (vs.bufpos > bufpos+8) {
01094 tmp = (unsigned char *)buf +
01095 bufpos;
01096 putUShort(tmp,
01097 vsio_option_code);
01098 putUShort(tmp+2,
01099 vs.bufpos-bufpos-4);
01100 putULong(tmp+4, o->code);
01101
01102 bufpos = vs.bufpos;
01103 }
01104 }
01105 }
01106 }
01107 }
01108
01109 return bufpos;
01110 }
01111
01112
01113
01114
01115
01116 int
01117 store_options(int *ocount,
01118 unsigned char *buffer, unsigned index, unsigned buflen,
01119 struct packet *packet, struct lease *lease,
01120 struct client_state *client_state,
01121 struct option_state *in_options,
01122 struct option_state *cfg_options,
01123 struct binding_scope **scope,
01124 unsigned *priority_list, int priority_len,
01125 unsigned first_cutoff, int second_cutoff, int terminate,
01126 const char *vuname)
01127 {
01128 int bufix = 0, six = 0, tix = 0;
01129 int i;
01130 int ix;
01131 int tto;
01132 int bufend, sbufend;
01133 struct data_string od;
01134 struct option_cache *oc;
01135 struct option *option = NULL;
01136 unsigned code;
01137
01138
01139
01140
01141
01142
01143 buffer = &buffer[index];
01144 buflen -= index;
01145 if (first_cutoff)
01146 first_cutoff -= index;
01147 if (second_cutoff)
01148 second_cutoff -= index;
01149
01150
01151 bufend = sbufend = buflen;
01152 if (first_cutoff) {
01153 if (first_cutoff >= buflen)
01154 log_fatal("%s:%d:store_options: Invalid first cutoff.", MDL);
01155 bufend = first_cutoff;
01156
01157 if (second_cutoff) {
01158 if (second_cutoff >= buflen)
01159 log_fatal("%s:%d:store_options: Invalid second cutoff.",
01160 MDL);
01161 sbufend = second_cutoff;
01162 }
01163 } else if (second_cutoff) {
01164 if (second_cutoff >= buflen)
01165 log_fatal("%s:%d:store_options: Invalid second cutoff.", MDL);
01166 bufend = second_cutoff;
01167 }
01168
01169 memset (&od, 0, sizeof od);
01170
01171
01172
01173
01174 for (i = 0; i < priority_len - 1; i++) {
01175
01176 tto = 0;
01177 for (ix = i + 1; ix < priority_len + tto; ix++) {
01178 if (tto)
01179 priority_list [ix - tto] =
01180 priority_list [ix];
01181 if (priority_list [i] == priority_list [ix]) {
01182 tto++;
01183 priority_len--;
01184 }
01185 }
01186
01187
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197
01198 if (priority_list[i] == DHO_SUBNET_MASK) {
01199 for (ix = i - 1 ; ix >= 0 ; ix--) {
01200 if (priority_list[ix] == DHO_ROUTERS) {
01201
01202 priority_list[ix] = DHO_SUBNET_MASK;
01203 priority_list[i] = DHO_ROUTERS;
01204 break;
01205 }
01206 }
01207 }
01208 }
01209
01210
01211
01212 for (i = 0; i < priority_len; i++) {
01213
01214
01215 unsigned length;
01216 int optstart, soptstart, toptstart;
01217 struct universe *u;
01218 int have_encapsulation = 0;
01219 struct data_string encapsulation;
01220 int splitup;
01221
01222 memset (&encapsulation, 0, sizeof encapsulation);
01223 have_encapsulation = 0;
01224
01225 if (option != NULL)
01226 option_dereference(&option, MDL);
01227
01228
01229 code = priority_list [i];
01230
01231
01232
01233 if (code >= cfg_options -> site_code_min)
01234 u = universes [cfg_options -> site_universe];
01235 else
01236 u = &dhcp_universe;
01237
01238 oc = lookup_option (u, cfg_options, code);
01239
01240 if (oc && oc->option)
01241 option_reference(&option, oc->option, MDL);
01242 else
01243 option_code_hash_lookup(&option, u->code_hash, &code, 0, MDL);
01244
01245
01246
01247
01248
01249
01250
01251
01252
01253 if ((option != NULL) &&
01254 (((oc == NULL) && (option->format[0] == 'E')) ||
01255 ((oc != NULL) && (option->format[0] == 'e')))) {
01256 static char *s, *t;
01257 struct option_cache *tmp;
01258 struct data_string name;
01259
01260 s = strchr (option->format, 'E');
01261 if (s)
01262 t = strchr (++s, '.');
01263 if (s && t) {
01264 memset (&name, 0, sizeof name);
01265
01266
01267
01268 if (t == s) {
01269 if (vendor_cfg_option) {
01270 tmp = lookup_option (vendor_cfg_option -> universe,
01271 cfg_options,
01272 vendor_cfg_option -> code);
01273 if (tmp)
01274
01275 (void) evaluate_option_cache (&name, packet, lease,
01276 client_state,
01277 in_options,
01278 cfg_options,
01279 scope, tmp, MDL);
01280 } else if (vuname) {
01281 name.data = (unsigned char *)s;
01282 name.len = strlen (s);
01283 }
01284 } else {
01285 name.data = (unsigned char *)s;
01286 name.len = t - s;
01287 }
01288
01289
01290
01291 if (name.len) {
01292 have_encapsulation =
01293 (option_space_encapsulate
01294 (&encapsulation, packet, lease, client_state,
01295 in_options, cfg_options, scope, &name));
01296 data_string_forget (&name, MDL);
01297 }
01298 }
01299 }
01300
01301
01302
01303
01304
01305
01306
01307
01308
01309
01310 if (!oc && !have_encapsulation) {
01311 continue;
01312 }
01313
01314
01315 od.len = 0;
01316 if (oc) {
01317
01318 (void) evaluate_option_cache (&od, packet,
01319 lease, client_state, in_options,
01320 cfg_options, scope, oc, MDL);
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330 if (!od.len) {
01331 data_string_forget (&encapsulation, MDL);
01332 data_string_forget (&od, MDL);
01333 continue;
01334 }
01335 }
01336
01337
01338 length = od.len;
01339 if (have_encapsulation) {
01340 length += encapsulation.len;
01341
01342
01343
01344
01345
01346 if (!od.len) {
01347 data_string_copy (&od, &encapsulation, MDL);
01348 data_string_forget (&encapsulation, MDL);
01349 } else {
01350 struct buffer *bp = (struct buffer *)0;
01351 if (!buffer_allocate (&bp, length, MDL)) {
01352 option_cache_dereference (&oc, MDL);
01353 data_string_forget (&od, MDL);
01354 data_string_forget (&encapsulation, MDL);
01355 continue;
01356 }
01357 memcpy (&bp -> data [0], od.data, od.len);
01358 memcpy (&bp -> data [od.len], encapsulation.data,
01359 encapsulation.len);
01360 data_string_forget (&od, MDL);
01361 data_string_forget (&encapsulation, MDL);
01362 od.data = &bp -> data [0];
01363 buffer_reference (&od.buffer, bp, MDL);
01364 buffer_dereference (&bp, MDL);
01365 od.len = length;
01366 od.terminated = 0;
01367 }
01368 }
01369
01370
01371 if (terminate && option && format_has_text(option->format)) {
01372 length++;
01373 tto = 1;
01374 } else {
01375 tto = 0;
01376 }
01377
01378
01379
01380
01381
01382
01383
01384
01385 if (length > 255)
01386 splitup = 1;
01387 else
01388 splitup = 0;
01389
01390 ix = 0;
01391 optstart = bufix;
01392 soptstart = six;
01393 toptstart = tix;
01394 while (length) {
01395 unsigned incr = length;
01396 int *pix;
01397 unsigned char *base;
01398
01399
01400 if (!splitup &&
01401 ((!six && !tix && (i == priority_len - 1) &&
01402 (bufix + 2 + length < bufend)) ||
01403 (bufix + 5 + length < bufend))) {
01404 base = buffer;
01405 pix = &bufix;
01406
01407 } else if (!splitup && first_cutoff &&
01408 (first_cutoff + six + 3 + length < sbufend)) {
01409 base = &buffer[first_cutoff];
01410 pix = &six;
01411
01412 } else if (!splitup && second_cutoff &&
01413 (second_cutoff + tix + 3 + length < buflen)) {
01414 base = &buffer[second_cutoff];
01415 pix = &tix;
01416
01417 } else {
01418 splitup = 1;
01419
01420
01421 if (bufix + 6 < bufend) {
01422 incr = bufend - bufix - 5;
01423 base = buffer;
01424 pix = &bufix;
01425
01426 } else if (first_cutoff &&
01427 (first_cutoff + six + 4 < sbufend)) {
01428 incr = sbufend - (first_cutoff + six) - 3;
01429 base = &buffer[first_cutoff];
01430 pix = &six;
01431
01432 } else if (second_cutoff &&
01433 (second_cutoff + tix + 4 < buflen)) {
01434 incr = buflen - (second_cutoff + tix) - 3;
01435 base = &buffer[second_cutoff];
01436 pix = &tix;
01437
01438 } else {
01439 bufix = optstart;
01440 six = soptstart;
01441 tix = toptstart;
01442 break;
01443 }
01444 }
01445
01446 if (incr > length)
01447 incr = length;
01448 if (incr > 255)
01449 incr = 255;
01450
01451
01452 base [*pix] = code;
01453 base [*pix + 1] = (unsigned char)incr;
01454 if (tto && incr == length) {
01455 if (incr > 1)
01456 memcpy (base + *pix + 2,
01457 od.data + ix, (unsigned)(incr - 1));
01458 base [*pix + 2 + incr - 1] = 0;
01459 } else {
01460 memcpy (base + *pix + 2,
01461 od.data + ix, (unsigned)incr);
01462 }
01463 length -= incr;
01464 ix += incr;
01465 *pix += 2 + incr;
01466 }
01467 data_string_forget (&od, MDL);
01468 }
01469
01470 if (option != NULL)
01471 option_dereference(&option, MDL);
01472
01473
01474 if (first_cutoff && six) {
01475 if ((first_cutoff + six + 1) < sbufend)
01476 memset (&buffer[first_cutoff + six + 1], DHO_PAD,
01477 sbufend - (first_cutoff + six + 1));
01478 else if (first_cutoff + six >= sbufend)
01479 log_fatal("Second buffer overflow in overloaded options.");
01480
01481 buffer[first_cutoff + six] = DHO_END;
01482 if (ocount != NULL)
01483 *ocount |= 1;
01484 }
01485
01486 if (second_cutoff && tix) {
01487 if (second_cutoff + tix + 1 < buflen) {
01488 memset (&buffer[second_cutoff + tix + 1], DHO_PAD,
01489 buflen - (second_cutoff + tix + 1));
01490 } else if (second_cutoff + tix >= buflen)
01491 log_fatal("Third buffer overflow in overloaded options.");
01492
01493 buffer[second_cutoff + tix] = DHO_END;
01494 if (ocount != NULL)
01495 *ocount |= 2;
01496 }
01497
01498 if ((six || tix) && (bufix + 3 > bufend))
01499 log_fatal("Not enough space for option overload option.");
01500
01501 return bufix;
01502 }
01503
01504
01505
01506
01507
01508 int
01509 format_has_text(format)
01510 const char *format;
01511 {
01512 const char *p;
01513
01514 p = format;
01515 while (*p != '\0') {
01516 switch (*p++) {
01517 case 'd':
01518 case 't':
01519 return 1;
01520
01521
01522
01523
01524
01525
01526 case 'A':
01527 case 'a':
01528 case 'X':
01529 case 'x':
01530 case 'D':
01531 return 0;
01532
01533 case 'c':
01534
01535
01536
01537
01538
01539 log_error("format_has_text(%s): 'c' atoms are illegal "
01540 "except after 'D' atoms.", format);
01541 break;
01542
01543
01544
01545
01546
01547
01548
01549 case 'E':
01550 case 'N':
01551
01552 while ((*p != '\0') && (*p++ != '.'))
01553 ;
01554 break;
01555
01556 default:
01557 break;
01558 }
01559 }
01560
01561 return 0;
01562 }
01563
01564
01565
01566
01567
01568
01569
01570 int
01571 format_min_length(format, oc)
01572 const char *format;
01573 struct option_cache *oc;
01574 {
01575 const char *p, *name;
01576 int min_len = 0;
01577 int last_size = 0;
01578 struct enumeration *espace;
01579
01580 p = format;
01581 while (*p != '\0') {
01582 switch (*p++) {
01583 case '6':
01584 min_len += 16;
01585 last_size = 16;
01586 break;
01587
01588 case 'I':
01589 case 'l':
01590 case 'L':
01591 case 'T':
01592 min_len += 4;
01593 last_size = 4;
01594 break;
01595
01596 case 's':
01597 case 'S':
01598 min_len += 2;
01599 last_size = 2;
01600 break;
01601
01602 case 'N':
01603
01604 name = p;
01605 p = strchr(p, '.');
01606 if (p == NULL)
01607 log_fatal("Corrupt format: %s", format);
01608
01609 espace = find_enumeration(name, p - name);
01610 if (espace == NULL) {
01611 log_error("Unknown enumeration: %s", format);
01612
01613 return INT_MAX;
01614 }
01615
01616 min_len += espace->width;
01617 last_size = espace->width;
01618 p++;
01619
01620 break;
01621
01622 case 'b':
01623 case 'B':
01624 case 'F':
01625 case 'f':
01626 min_len++;
01627 last_size = 1;
01628 break;
01629
01630 case 'o':
01631 min_len -= last_size;
01632
01633
01634
01635
01636
01637 case 'e':
01638 case 'E':
01639 return min_len;
01640
01641 case 'd':
01642 case 'D':
01643 case 't':
01644 case 'X':
01645 case 'x':
01646 case 'A':
01647 case 'a':
01648 case 'Z':
01649 return min_len;
01650
01651 case 'c':
01652 log_error("format_min_length(%s): 'c' atom is illegal "
01653 "except after 'D' atom.", format);
01654 return INT_MAX;
01655
01656 default:
01657
01658 log_error("format_min_length(%s): No safe value "
01659 "for unknown format symbols.", format);
01660 return INT_MAX;
01661 }
01662 }
01663
01664 return min_len;
01665 }
01666
01667
01668
01669
01670 const char *pretty_print_option (option, data, len, emit_commas, emit_quotes)
01671 struct option *option;
01672 const unsigned char *data;
01673 unsigned len;
01674 int emit_commas;
01675 int emit_quotes;
01676 {
01677 static char optbuf [32768];
01678 static char *endbuf = &optbuf[sizeof(optbuf)];
01679 int hunksize = 0;
01680 int opthunk = 0;
01681 int hunkinc = 0;
01682 int numhunk = -1;
01683 int numelem = 0;
01684 int count;
01685 int i, j, k, l;
01686 char fmtbuf[32] = "";
01687 struct iaddr iaddr;
01688 struct enumeration *enumbuf[32];
01689 char *op = optbuf;
01690 const unsigned char *dp = data;
01691 char comma;
01692 unsigned long tval;
01693 isc_boolean_t a_array = ISC_FALSE;
01694 int len_used;
01695 unsigned int octets = 0;
01696
01697 if (emit_commas)
01698 comma = ',';
01699 else
01700 comma = ' ';
01701
01702 memset (enumbuf, 0, sizeof enumbuf);
01703
01704 if (option->format[0] != 'R') {
01705
01706 for (l = i = 0; option -> format [i]; i++, l++) {
01707 if (l >= sizeof(fmtbuf) - 1)
01708 log_fatal("Bounds failure on internal buffer at "
01709 "%s:%d", MDL);
01710
01711 if (!numhunk) {
01712 log_error ("%s: Extra codes in format string: %s",
01713 option -> name,
01714 &(option -> format [i]));
01715 break;
01716 }
01717 numelem++;
01718 fmtbuf [l] = option -> format [i];
01719 switch (option -> format [i]) {
01720 case 'a':
01721 a_array = ISC_TRUE;
01722
01723 case 'A':
01724 --numelem;
01725 fmtbuf [l] = 0;
01726 numhunk = 0;
01727 break;
01728 case 'E':
01729
01730 while (option -> format [i] &&
01731 option -> format [i] != '.')
01732 i++;
01733
01734 case 'X':
01735 for (k = 0; k < len; k++) {
01736 if (!isascii (data [k]) ||
01737 !isprint (data [k]))
01738 break;
01739 }
01740
01741
01742
01743 if (k == len || (k + 1 == len && data [k] == 0)) {
01744 fmtbuf [l] = 't';
01745 numhunk = -2;
01746 } else {
01747 fmtbuf [l] = 'x';
01748 hunksize++;
01749 comma = ':';
01750 numhunk = 0;
01751 a_array = ISC_TRUE;
01752 hunkinc = 1;
01753 }
01754 fmtbuf [l + 1] = 0;
01755 break;
01756 case 'c':
01757
01758 log_error("'c' atom not following D atom in format "
01759 "string: %s", option->format);
01760 break;
01761 case 'D':
01762
01763
01764
01765
01766
01767 if (option->format[i+1] == 'c')
01768 i++;
01769 fmtbuf[l + 1] = 0;
01770 numhunk = -2;
01771 break;
01772 case 'd':
01773 fmtbuf[l] = 't';
01774
01775 case 't':
01776 fmtbuf[l + 1] = 0;
01777 numhunk = -2;
01778 break;
01779 case 'N':
01780 k = i;
01781 while (option -> format [i] &&
01782 option -> format [i] != '.')
01783 i++;
01784 enumbuf [l] =
01785 find_enumeration (&option -> format [k] + 1,
01786 i - k - 1);
01787 if (enumbuf[l] == NULL) {
01788 hunksize += 1;
01789 hunkinc = 1;
01790 } else {
01791 hunksize += enumbuf[l]->width;
01792 hunkinc = enumbuf[l]->width;
01793 }
01794 break;
01795 case '6':
01796 hunksize += 16;
01797 hunkinc = 16;
01798 break;
01799 case 'I':
01800 case 'l':
01801 case 'L':
01802 case 'T':
01803 hunksize += 4;
01804 hunkinc = 4;
01805 break;
01806 case 's':
01807 case 'S':
01808 hunksize += 2;
01809 hunkinc = 2;
01810 break;
01811 case 'b':
01812 case 'B':
01813 case 'f':
01814 case 'F':
01815 hunksize++;
01816 hunkinc = 1;
01817 break;
01818 case 'e':
01819 case 'Z':
01820 break;
01821 case 'o':
01822 opthunk += hunkinc;
01823 break;
01824 default:
01825 log_error ("%s: garbage in format string: %s",
01826 option -> name,
01827 &(option -> format [i]));
01828 break;
01829 }
01830 }
01831
01832
01833 if (hunksize - opthunk > len) {
01834 log_error ("%s: expecting at least %d bytes; got %d",
01835 option -> name,
01836 hunksize, len);
01837 return "<error>";
01838 }
01839
01840 if (numhunk == -1 && hunksize < len)
01841 log_error ("%s: %d extra bytes",
01842 option -> name,
01843 len - hunksize);
01844
01845
01846 if (numhunk == 0) {
01847 if (a_array == ISC_TRUE) {
01848
01849
01850
01851
01852
01853
01854
01855 numhunk = ((len - hunksize) / hunkinc) + 1;
01856 len_used = hunksize + ((numhunk - 1) * hunkinc);
01857 } else {
01858
01859
01860
01861
01862 numhunk = len / hunksize;
01863 len_used = numhunk * hunksize;
01864 }
01865
01866
01867 if (len_used < len) {
01868 log_error ("%s: %d extra bytes at end of array\n",
01869 option -> name,
01870 len - len_used);
01871 }
01872 }
01873
01874
01875
01876 if (numhunk < 0)
01877 numhunk = 1;
01878
01879 } else {
01880
01881
01882
01883
01884
01885
01886
01887
01888
01889 numhunk = 0;
01890 numelem = 2;
01891 fmtbuf[0]='R'; fmtbuf[1]='I'; fmtbuf[2]=0;
01892 for (i =0; i < len; i = i + octets + 5) {
01893 if (data[i] > 32) {
01894 log_error ("wrong subnet mask width in destination descriptor");
01895 break;
01896 }
01897 numhunk++;
01898 octets = ((data[i]+7) / 8);
01899 }
01900 if (i != len) {
01901 log_error ("classless static routes option has wrong size or "
01902 "there's some garbage in format");
01903 }
01904 }
01905
01906
01907 for (i = 0; i < numhunk; i++) {
01908 if ((a_array == ISC_TRUE) && (i != 0) && (numelem > 0)) {
01909
01910
01911
01912
01913
01914
01915 j = numelem - 1;
01916 } else {
01917
01918
01919
01920
01921
01922 j = 0;
01923 }
01924
01925 for (; j < numelem; j++) {
01926 switch (fmtbuf [j]) {
01927 case 't':
01928
01929 k = pretty_text(&op, endbuf - 1, &dp,
01930 data + len, emit_quotes);
01931 if (k == -1) {
01932 log_error("Error printing text.");
01933 break;
01934 }
01935 *op = 0;
01936 break;
01937 case 'D':
01938 for( ; dp < (data + len) ; dp += k) {
01939 unsigned char nbuff[NS_MAXCDNAME];
01940 const unsigned char *nbp, *nend;
01941
01942 nend = &nbuff[sizeof(nbuff)];
01943
01944
01945
01946
01947
01948
01949
01950
01951 if (dp != data) {
01952 if (op + 2 > endbuf)
01953 break;
01954
01955 if (emit_quotes)
01956 *op++ = ',';
01957 *op++ = ' ';
01958 }
01959
01960
01961
01962
01963
01964 k = MRns_name_unpack(data,
01965 data + len,
01966 dp, nbuff,
01967 sizeof(nbuff));
01968
01969 if (k == -1) {
01970 log_error("Invalid domain "
01971 "list.");
01972 break;
01973 }
01974
01975
01976
01977
01978
01979 if (emit_quotes) {
01980 nbp = nbuff;
01981 pretty_domain(&op, endbuf-1,
01982 &nbp, nend);
01983 } else {
01984
01985
01986
01987
01988 count = MRns_name_ntop(
01989 nbuff, op,
01990 (endbuf-op)-1);
01991
01992 if (count <= 0) {
01993 log_error("Invalid "
01994 "domain name.");
01995 break;
01996 }
01997
01998
01999
02000
02001 op += count - 1;
02002
02003
02004
02005
02006
02007
02008 *op++ = '.';
02009 }
02010 }
02011 *op = '\0';
02012 break;
02013
02014
02015 case 'N':
02016 if (!enumbuf [j]) {
02017 tval = *dp++;
02018 goto enum_as_num;
02019 }
02020
02021 switch (enumbuf[j]->width) {
02022 case 1:
02023 tval = getUChar(dp);
02024 break;
02025
02026 case 2:
02027 tval = getUShort(dp);
02028 break;
02029
02030 case 4:
02031 tval = getULong(dp);
02032 break;
02033
02034 default:
02035 log_fatal("Impossible case at %s:%d.",
02036 MDL);
02037 return "<double impossible condition>";
02038 }
02039
02040 for (i = 0; ;i++) {
02041 if (!enumbuf [j] -> values [i].name)
02042 goto enum_as_num;
02043 if (enumbuf [j] -> values [i].value ==
02044 tval)
02045 break;
02046 }
02047 strcpy (op, enumbuf [j] -> values [i].name);
02048 dp += enumbuf[j]->width;
02049 break;
02050
02051 enum_as_num:
02052 sprintf(op, "%lu", tval);
02053 break;
02054
02055 case 'I':
02056 iaddr.len = 4;
02057 memcpy(iaddr.iabuf, dp, 4);
02058 strcpy(op, piaddr(iaddr));
02059 dp += 4;
02060 break;
02061
02062 case 'R':
02063 if (dp[0] <= 32)
02064 iaddr.len = (((dp[0]+7)/8)+1);
02065 else {
02066 log_error ("wrong subnet mask width in destination descriptor");
02067 return "<error>";
02068 }
02069
02070 memcpy(iaddr.iabuf, dp, iaddr.len);
02071 strcpy(op, pdestdesc(iaddr));
02072 dp += iaddr.len;
02073 break;
02074
02075 case '6':
02076 iaddr.len = 16;
02077 memcpy(iaddr.iabuf, dp, 16);
02078 strcpy(op, piaddr(iaddr));
02079 dp += 16;
02080 break;
02081 case 'l':
02082 sprintf (op, "%ld", (long)getLong (dp));
02083 dp += 4;
02084 break;
02085 case 'T':
02086 tval = getULong (dp);
02087 if (tval == -1)
02088 sprintf (op, "%s", "infinite");
02089 else
02090 sprintf(op, "%lu", tval);
02091 break;
02092 case 'L':
02093 sprintf(op, "%lu",
02094 (unsigned long)getULong(dp));
02095 dp += 4;
02096 break;
02097 case 's':
02098 sprintf (op, "%d", (int)getShort (dp));
02099 dp += 2;
02100 break;
02101 case 'S':
02102 sprintf(op, "%u", (unsigned)getUShort(dp));
02103 dp += 2;
02104 break;
02105 case 'b':
02106 sprintf (op, "%d", *(const char *)dp++);
02107 break;
02108 case 'B':
02109 sprintf (op, "%d", *dp++);
02110 break;
02111 case 'X':
02112 case 'x':
02113 sprintf (op, "%x", *dp++);
02114 break;
02115 case 'f':
02116 strcpy (op, *dp++ ? "true" : "false");
02117 break;
02118 case 'F':
02119 strcpy (op, "true");
02120 break;
02121 case 'e':
02122 case 'Z':
02123 *op = '\0';
02124 break;
02125 default:
02126 log_error ("Unexpected format code %c",
02127 fmtbuf [j]);
02128 }
02129 op += strlen (op);
02130 if (dp == data + len)
02131 break;
02132 if (j + 1 < numelem && comma != ':')
02133 *op++ = ' ';
02134 }
02135 if (i + 1 < numhunk) {
02136 *op++ = comma;
02137 }
02138 if (dp == data + len)
02139 break;
02140 }
02141 return optbuf;
02142 }
02143
02144 int get_option (result, universe, packet, lease, client_state,
02145 in_options, cfg_options, options, scope, code, file, line)
02146 struct data_string *result;
02147 struct universe *universe;
02148 struct packet *packet;
02149 struct lease *lease;
02150 struct client_state *client_state;
02151 struct option_state *in_options;
02152 struct option_state *cfg_options;
02153 struct option_state *options;
02154 struct binding_scope **scope;
02155 unsigned code;
02156 const char *file;
02157 int line;
02158 {
02159 struct option_cache *oc;
02160
02161 if (!universe -> lookup_func)
02162 return 0;
02163 oc = ((*universe -> lookup_func) (universe, options, code));
02164 if (!oc)
02165 return 0;
02166 if (!evaluate_option_cache (result, packet, lease, client_state,
02167 in_options, cfg_options, scope, oc,
02168 file, line))
02169 return 0;
02170 return 1;
02171 }
02172
02173 void set_option (universe, options, option, op)
02174 struct universe *universe;
02175 struct option_state *options;
02176 struct option_cache *option;
02177 enum statement_op op;
02178 {
02179 struct option_cache *oc, *noc;
02180
02181 switch (op) {
02182 case if_statement:
02183 case add_statement:
02184 case eval_statement:
02185 case break_statement:
02186 default:
02187 log_error ("bogus statement type in set_option.");
02188 break;
02189
02190 case default_option_statement:
02191 oc = lookup_option (universe, options,
02192 option -> option -> code);
02193 if (oc)
02194 break;
02195 save_option (universe, options, option);
02196 break;
02197
02198 case supersede_option_statement:
02199 case send_option_statement:
02200
02201 save_option (universe, options, option);
02202 break;
02203
02204 case append_option_statement:
02205 case prepend_option_statement:
02206 oc = lookup_option (universe, options,
02207 option -> option -> code);
02208 if (!oc) {
02209 save_option (universe, options, option);
02210 break;
02211 }
02212
02213 if (!oc -> expression && oc -> data.len) {
02214 if (!expression_allocate (&oc -> expression, MDL)) {
02215 log_error ("Can't allocate const expression.");
02216 break;
02217 }
02218 oc -> expression -> op = expr_const_data;
02219 data_string_copy
02220 (&oc -> expression -> data.const_data,
02221 &oc -> data, MDL);
02222 data_string_forget (&oc -> data, MDL);
02223 }
02224 noc = (struct option_cache *)0;
02225 if (!option_cache_allocate (&noc, MDL))
02226 break;
02227 if (op == append_option_statement) {
02228 if (!make_concat (&noc -> expression,
02229 oc -> expression,
02230 option -> expression)) {
02231 option_cache_dereference (&noc, MDL);
02232 break;
02233 }
02234 } else {
02235 if (!make_concat (&noc -> expression,
02236 option -> expression,
02237 oc -> expression)) {
02238 option_cache_dereference (&noc, MDL);
02239 break;
02240 }
02241 }
02242 option_reference(&(noc->option), oc->option, MDL);
02243 save_option (universe, options, noc);
02244 option_cache_dereference (&noc, MDL);
02245 break;
02246 }
02247 }
02248
02249 struct option_cache *lookup_option (universe, options, code)
02250 struct universe *universe;
02251 struct option_state *options;
02252 unsigned code;
02253 {
02254 if (!options)
02255 return (struct option_cache *)0;
02256 if (universe -> lookup_func)
02257 return (*universe -> lookup_func) (universe, options, code);
02258 else
02259 log_error ("can't look up options in %s space.",
02260 universe -> name);
02261 return (struct option_cache *)0;
02262 }
02263
02264 struct option_cache *lookup_hashed_option (universe, options, code)
02265 struct universe *universe;
02266 struct option_state *options;
02267 unsigned code;
02268 {
02269 int hashix;
02270 pair bptr;
02271 pair *hash;
02272
02273
02274 if (universe -> index >= options -> universe_count ||
02275 !(options -> universes [universe -> index]))
02276 return (struct option_cache *)0;
02277
02278 hash = options -> universes [universe -> index];
02279
02280 hashix = compute_option_hash (code);
02281 for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
02282 if (((struct option_cache *)(bptr -> car)) -> option -> code ==
02283 code)
02284 return (struct option_cache *)(bptr -> car);
02285 }
02286 return (struct option_cache *)0;
02287 }
02288
02289
02290 int
02291 save_option_buffer(struct universe *universe, struct option_state *options,
02292 struct buffer *bp, unsigned char *buffer, unsigned length,
02293 unsigned code, int terminatep)
02294 {
02295 struct option_cache *op = NULL;
02296 int status = 1;
02297
02298 status = prepare_option_buffer(universe, bp, buffer, length, code,
02299 terminatep, &op);
02300
02301 if (status == 0)
02302 goto cleanup;
02303
02304 save_option(universe, options, op);
02305
02306 cleanup:
02307 if (op != NULL)
02308 option_cache_dereference(&op, MDL);
02309
02310 return status;
02311 }
02312
02313
02314 int
02315 append_option_buffer(struct universe *universe, struct option_state *options,
02316 struct buffer *bp, unsigned char *buffer, unsigned length,
02317 unsigned code, int terminatep)
02318 {
02319 struct option_cache *op = NULL;
02320 int status = 1;
02321
02322 status = prepare_option_buffer(universe, bp, buffer, length, code,
02323 terminatep, &op);
02324
02325 if (status == 0)
02326 goto cleanup;
02327
02328 also_save_option(universe, options, op);
02329
02330 cleanup:
02331 if (op != NULL)
02332 option_cache_dereference(&op, MDL);
02333
02334 return status;
02335 }
02336
02337
02338 static int
02339 prepare_option_buffer(struct universe *universe, struct buffer *bp,
02340 unsigned char *buffer, unsigned length, unsigned code,
02341 int terminatep, struct option_cache **opp)
02342 {
02343 struct buffer *lbp = NULL;
02344 struct option *option = NULL;
02345 struct option_cache *op;
02346 int status = 1;
02347
02348
02349 switch(universe->tag_size) {
02350 case 1:
02351 if (code > 0xff)
02352 return 0;
02353 break;
02354 case 2:
02355 if (code > 0xffff)
02356 return 0;
02357 break;
02358 case 4:
02359 if (code > 0xffffffff)
02360 return 0;
02361 break;
02362
02363 default:
02364 log_fatal("Inconsistent universe tag size at %s:%d.", MDL);
02365 }
02366
02367 option_code_hash_lookup(&option, universe->code_hash, &code, 0, MDL);
02368
02369
02370
02371
02372
02373
02374
02375
02376 if (!option) {
02377 char nbuf[sizeof("unknown-4294967295")];
02378
02379 sprintf(nbuf, "unknown-%u", code);
02380
02381 option = new_option(nbuf, MDL);
02382
02383 if (!option)
02384 return 0;
02385
02386 option->format = default_option_format;
02387 option->universe = universe;
02388 option->code = code;
02389
02390
02391 option->refcnt = 1;
02392 }
02393
02394 if (!option_cache_allocate (opp, MDL)) {
02395 log_error("No memory for option code %s.%s.",
02396 universe->name, option->name);
02397 status = 0;
02398 goto cleanup;
02399 }
02400
02401
02402 op = *opp;
02403
02404 option_reference(&op->option, option, MDL);
02405
02406
02407
02408 if (!bp) {
02409 if (!buffer_allocate (&lbp, length + terminatep, MDL)) {
02410 log_error ("no memory for option buffer.");
02411
02412 status = 0;
02413 goto cleanup;
02414 }
02415 memcpy (lbp -> data, buffer, length + terminatep);
02416 bp = lbp;
02417 buffer = &bp -> data [0];
02418 }
02419
02420
02421 op -> data.buffer = (struct buffer *)0;
02422 buffer_reference (&op -> data.buffer, bp, MDL);
02423
02424
02425 op -> data.data = buffer;
02426 op -> data.len = length;
02427
02428 if (terminatep) {
02429
02430
02431
02432
02433
02434 buffer [length] = 0;
02435 op -> data.terminated = 1;
02436 } else
02437 op -> data.terminated = 0;
02438
02439
02440
02441
02442
02443
02444 if (format_has_text(option->format)) {
02445 int min_len = format_min_length(option->format, op);
02446
02447 while ((op->data.len > min_len) &&
02448 (op->data.data[op->data.len-1] == '\0')) {
02449 op->data.len--;
02450 op->flags |= OPTION_HAD_NULLS;
02451 }
02452 }
02453
02454
02455 cleanup:
02456 if (lbp != NULL)
02457 buffer_dereference(&lbp, MDL);
02458 option_dereference(&option, MDL);
02459
02460 return status;
02461 }
02462
02463 static void
02464 count_options(struct option_cache *dummy_oc,
02465 struct packet *dummy_packet,
02466 struct lease *dummy_lease,
02467 struct client_state *dummy_client_state,
02468 struct option_state *dummy_opt_state,
02469 struct option_state *opt_state,
02470 struct binding_scope **dummy_binding_scope,
02471 struct universe *dummy_universe,
02472 void *void_accumulator) {
02473 int *accumulator = (int *)void_accumulator;
02474
02475 *accumulator += 1;
02476 }
02477
02478 static void
02479 collect_oro(struct option_cache *oc,
02480 struct packet *dummy_packet,
02481 struct lease *dummy_lease,
02482 struct client_state *dummy_client_state,
02483 struct option_state *dummy_opt_state,
02484 struct option_state *opt_state,
02485 struct binding_scope **dummy_binding_scope,
02486 struct universe *dummy_universe,
02487 void *void_oro) {
02488 struct data_string *oro = (struct data_string *)void_oro;
02489
02490 putUShort(oro->buffer->data + oro->len, oc->option->code);
02491 oro->len += 2;
02492 }
02493
02494
02495
02496
02497
02498 void
02499 build_server_oro(struct data_string *server_oro,
02500 struct option_state *options,
02501 const char *file, int line) {
02502 int num_opts;
02503 int i;
02504 struct option *o;
02505
02506
02507
02508
02509
02510 num_opts = 0;
02511 option_space_foreach(NULL, NULL, NULL, NULL, options,
02512 NULL, &dhcpv6_universe, (void *)&num_opts,
02513 count_options);
02514 for (i=0; i < options->universe_count; i++) {
02515 if (options->universes[i] != NULL) {
02516 o = universes[i]->enc_opt;
02517 while (o != NULL) {
02518 if (o->universe == &dhcpv6_universe) {
02519 num_opts++;
02520 break;
02521 }
02522 o = o->universe->enc_opt;
02523 }
02524 }
02525 }
02526
02527
02528
02529
02530 memset(server_oro, 0, sizeof(*server_oro));
02531 if (!buffer_allocate(&server_oro->buffer, num_opts * 2, MDL)) {
02532 log_fatal("no memory to build server ORO");
02533 }
02534 server_oro->data = server_oro->buffer->data;
02535
02536
02537
02538
02539
02540 server_oro->len = 0;
02541 option_space_foreach(NULL, NULL, NULL, NULL, options,
02542 NULL, &dhcpv6_universe, (void *)server_oro,
02543 collect_oro);
02544 for (i=0; i < options->universe_count; i++) {
02545 if (options->universes[i] != NULL) {
02546 o = universes[i]->enc_opt;
02547 while (o != NULL) {
02548 if (o->universe == &dhcpv6_universe) {
02549 unsigned char *tmp;
02550 tmp = server_oro->buffer->data;
02551 putUShort(tmp + server_oro->len,
02552 o->code);
02553 server_oro->len += 2;
02554 break;
02555 }
02556 o = o->universe->enc_opt;
02557 }
02558 }
02559 }
02560 }
02561
02562
02563 void
02564 save_option(struct universe *universe, struct option_state *options,
02565 struct option_cache *oc)
02566 {
02567 if (universe->save_func)
02568 (*universe->save_func)(universe, options, oc, ISC_FALSE);
02569 else
02570 log_error("can't store options in %s space.", universe->name);
02571 }
02572
02573
02574 void
02575 also_save_option(struct universe *universe, struct option_state *options,
02576 struct option_cache *oc)
02577 {
02578 if (universe->save_func)
02579 (*universe->save_func)(universe, options, oc, ISC_TRUE);
02580 else
02581 log_error("can't store options in %s space.", universe->name);
02582 }
02583
02584 void
02585 save_hashed_option(struct universe *universe, struct option_state *options,
02586 struct option_cache *oc, isc_boolean_t appendp)
02587 {
02588 int hashix;
02589 pair bptr;
02590 pair *hash = options -> universes [universe -> index];
02591 struct option_cache **ocloc;
02592
02593 if (oc -> refcnt == 0)
02594 abort ();
02595
02596
02597 hashix = compute_option_hash (oc -> option -> code);
02598
02599
02600 if (!hash) {
02601 hash = (pair *)dmalloc (OPTION_HASH_SIZE * sizeof *hash, MDL);
02602 if (!hash) {
02603 log_error ("no memory to store %s.%s",
02604 universe -> name, oc -> option -> name);
02605 return;
02606 }
02607 memset (hash, 0, OPTION_HASH_SIZE * sizeof *hash);
02608 options -> universes [universe -> index] = (void *)hash;
02609 } else {
02610
02611 for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
02612 if (((struct option_cache *)
02613 (bptr -> car)) -> option -> code ==
02614 oc -> option -> code)
02615 break;
02616 }
02617
02618
02619 if (bptr) {
02620 ocloc = (struct option_cache **)&bptr->car;
02621
02622
02623
02624
02625
02626
02627 if (appendp) {
02628 do {
02629 ocloc = &(*ocloc)->next;
02630 } while (*ocloc != NULL);
02631 } else {
02632 option_cache_dereference(ocloc, MDL);
02633 }
02634
02635 option_cache_reference(ocloc, oc, MDL);
02636 return;
02637 }
02638 }
02639
02640
02641 bptr = new_pair (MDL);
02642 if (!bptr) {
02643 log_error ("No memory for option_cache reference.");
02644 return;
02645 }
02646 bptr -> cdr = hash [hashix];
02647 bptr -> car = 0;
02648 option_cache_reference ((struct option_cache **)&bptr -> car, oc, MDL);
02649 hash [hashix] = bptr;
02650 }
02651
02652 void delete_option (universe, options, code)
02653 struct universe *universe;
02654 struct option_state *options;
02655 int code;
02656 {
02657 if (universe -> delete_func)
02658 (*universe -> delete_func) (universe, options, code);
02659 else
02660 log_error ("can't delete options from %s space.",
02661 universe -> name);
02662 }
02663
02664 void delete_hashed_option (universe, options, code)
02665 struct universe *universe;
02666 struct option_state *options;
02667 int code;
02668 {
02669 int hashix;
02670 pair bptr, prev = (pair)0;
02671 pair *hash = options -> universes [universe -> index];
02672
02673
02674 if (!hash)
02675 return;
02676
02677
02678 hashix = compute_option_hash (code);
02679 for (bptr = hash [hashix]; bptr; bptr = bptr -> cdr) {
02680 if (((struct option_cache *)(bptr -> car)) -> option -> code
02681 == code)
02682 break;
02683 prev = bptr;
02684 }
02685
02686 if (bptr) {
02687 if (prev)
02688 prev -> cdr = bptr -> cdr;
02689 else
02690 hash [hashix] = bptr -> cdr;
02691 option_cache_dereference
02692 ((struct option_cache **)(&bptr -> car), MDL);
02693 free_pair (bptr, MDL);
02694 }
02695 }
02696
02697 extern struct option_cache *free_option_caches;
02698
02699 int option_cache_dereference (ptr, file, line)
02700 struct option_cache **ptr;
02701 const char *file;
02702 int line;
02703 {
02704 if (!ptr || !*ptr) {
02705 log_error ("Null pointer in option_cache_dereference: %s(%d)",
02706 file, line);
02707 #if defined (POINTER_DEBUG)
02708 abort ();
02709 #else
02710 return 0;
02711 #endif
02712 }
02713
02714 (*ptr) -> refcnt--;
02715 rc_register (file, line, ptr, *ptr, (*ptr) -> refcnt, 1, RC_MISC);
02716 if (!(*ptr) -> refcnt) {
02717 if ((*ptr) -> data.buffer)
02718 data_string_forget (&(*ptr) -> data, file, line);
02719 if ((*ptr)->option)
02720 option_dereference(&(*ptr)->option, MDL);
02721 if ((*ptr) -> expression)
02722 expression_dereference (&(*ptr) -> expression,
02723 file, line);
02724 if ((*ptr) -> next)
02725 option_cache_dereference (&((*ptr) -> next),
02726 file, line);
02727
02728 (*ptr) -> expression = (struct expression *)free_option_caches;
02729 free_option_caches = *ptr;
02730 dmalloc_reuse (free_option_caches, (char *)0, 0, 0);
02731 }
02732 if ((*ptr) -> refcnt < 0) {
02733 log_error ("%s(%d): negative refcnt!", file, line);
02734 #if defined (DEBUG_RC_HISTORY)
02735 dump_rc_history (*ptr);
02736 #endif
02737 #if defined (POINTER_DEBUG)
02738 abort ();
02739 #else
02740 *ptr = (struct option_cache *)0;
02741 return 0;
02742 #endif
02743 }
02744 *ptr = (struct option_cache *)0;
02745 return 1;
02746
02747 }
02748
02749 int hashed_option_state_dereference (universe, state, file, line)
02750 struct universe *universe;
02751 struct option_state *state;
02752 const char *file;
02753 int line;
02754 {
02755 pair *heads;
02756 pair cp, next;
02757 int i;
02758
02759
02760 heads = (pair *)(state -> universes [universe -> index]);
02761 if (!heads)
02762 return 0;
02763
02764
02765
02766 for (i = 0; i < OPTION_HASH_SIZE; i++) {
02767 for (cp = heads [i]; cp; cp = next) {
02768 next = cp -> cdr;
02769 option_cache_dereference
02770 ((struct option_cache **)&cp -> car,
02771 file, line);
02772 free_pair (cp, file, line);
02773 }
02774 }
02775
02776 dfree (heads, file, line);
02777 state -> universes [universe -> index] = (void *)0;
02778 return 1;
02779 }
02780
02781
02782
02783
02784
02785
02786 int
02787 append_option(struct data_string *dst, struct universe *universe,
02788 struct option *option, struct data_string *src)
02789 {
02790 struct data_string tmp;
02791
02792 if (src->len == 0 && option->format[0] != 'Z')
02793 return 0;
02794
02795 memset(&tmp, 0, sizeof(tmp));
02796
02797
02798
02799
02800 if (!buffer_allocate(&tmp.buffer,
02801 (dst->len + universe->length_size +
02802 universe->tag_size + src->len), MDL)) {
02803
02804
02805
02806
02807
02808
02809 data_string_forget(dst, MDL);
02810 return 0;
02811 }
02812 tmp.data = tmp.buffer->data;
02813
02814
02815 if (dst->len != 0)
02816 memcpy(tmp.buffer->data, dst->data, dst->len);
02817 tmp.len = dst->len;
02818
02819
02820 (*universe->store_tag)(tmp.buffer->data + tmp.len, option->code);
02821 tmp.len += universe->tag_size;
02822 (*universe->store_length)(tmp.buffer->data + tmp.len, src->len);
02823 tmp.len += universe->length_size;
02824
02825
02826 memcpy(tmp.buffer->data + tmp.len, src->data, src->len);
02827 tmp.len += src->len;
02828
02829
02830 data_string_forget(dst, MDL);
02831 data_string_copy(dst, &tmp, MDL);
02832 data_string_forget(&tmp, MDL);
02833 return 1;
02834 }
02835
02836 int
02837 store_option(struct data_string *result, struct universe *universe,
02838 struct packet *packet, struct lease *lease,
02839 struct client_state *client_state,
02840 struct option_state *in_options, struct option_state *cfg_options,
02841 struct binding_scope **scope, struct option_cache *oc)
02842 {
02843 struct data_string tmp;
02844 struct universe *subu=NULL;
02845 int status;
02846 char *start, *end;
02847
02848 memset(&tmp, 0, sizeof(tmp));
02849
02850 if (evaluate_option_cache(&tmp, packet, lease, client_state,
02851 in_options, cfg_options, scope, oc, MDL)) {
02852
02853
02854
02855
02856 do {
02857 if (oc->option->format &&
02858 oc->option->format[0] == 'e') {
02859
02860 start = strchr(oc->option->format, 'E');
02861 if (start == NULL)
02862 break;
02863
02864
02865 end = strchr(++start, '.');
02866
02867
02868
02869
02870 if (end == NULL || start == end)
02871 break;
02872
02873 universe_hash_lookup(&subu, universe_hash,
02874 start, end - start, MDL);
02875
02876 if (subu == NULL) {
02877 log_error("store_option: option %d "
02878 "refers to unknown "
02879 "option space '%.*s'.",
02880 oc->option->code,
02881 (int)(end - start), start);
02882 break;
02883 }
02884
02885
02886
02887
02888
02889
02890
02891 subu->encapsulate(&tmp, packet, lease,
02892 client_state, in_options,
02893 cfg_options, scope, subu);
02894 subu = NULL;
02895 }
02896 } while (ISC_FALSE);
02897
02898 status = append_option(result, universe, oc->option, &tmp);
02899 data_string_forget(&tmp, MDL);
02900
02901 return status;
02902 }
02903
02904 return 0;
02905 }
02906
02907 int option_space_encapsulate (result, packet, lease, client_state,
02908 in_options, cfg_options, scope, name)
02909 struct data_string *result;
02910 struct packet *packet;
02911 struct lease *lease;
02912 struct client_state *client_state;
02913 struct option_state *in_options;
02914 struct option_state *cfg_options;
02915 struct binding_scope **scope;
02916 struct data_string *name;
02917 {
02918 struct universe *u = NULL;
02919 int status = 0;
02920
02921 universe_hash_lookup(&u, universe_hash,
02922 (const char *)name->data, name->len, MDL);
02923 if (u == NULL) {
02924 log_error("option_space_encapsulate: option space '%.*s' does "
02925 "not exist, but is configured.",
02926 (int)name->len, name->data);
02927 return status;
02928 }
02929
02930 if (u->encapsulate != NULL) {
02931 if (u->encapsulate(result, packet, lease, client_state,
02932 in_options, cfg_options, scope, u))
02933 status = 1;
02934 } else
02935 log_error("encapsulation requested for '%s' with no support.",
02936 name->data);
02937
02938 return status;
02939 }
02940
02941
02942
02943
02944
02945
02946
02947
02948
02949
02950
02951
02952
02953
02954
02955
02956 static int
02957 search_subencapsulation(struct data_string *result, struct packet *packet,
02958 struct lease *lease, struct client_state *client_state,
02959 struct option_state *in_options,
02960 struct option_state *cfg_options,
02961 struct binding_scope **scope,
02962 struct universe *universe)
02963 {
02964 struct data_string sub;
02965 struct universe *subu;
02966 int i, status = 0;
02967
02968 memset(&sub, 0, sizeof(sub));
02969 for (i = 0 ; i < cfg_options->universe_count ; i++) {
02970 subu = universes[i];
02971
02972 if (subu == NULL)
02973 log_fatal("Impossible condition at %s:%d.", MDL);
02974
02975 if (subu->enc_opt != NULL &&
02976 subu->enc_opt->universe == universe &&
02977 subu->enc_opt->format != NULL &&
02978 subu->enc_opt->format[0] == 'E' &&
02979 lookup_option(universe, cfg_options,
02980 subu->enc_opt->code) == NULL &&
02981 subu->encapsulate(&sub, packet, lease, client_state,
02982 in_options, cfg_options,
02983 scope, subu)) {
02984 if (append_option(result, universe,
02985 subu->enc_opt, &sub))
02986 status = 1;
02987
02988 data_string_forget(&sub, MDL);
02989 }
02990 }
02991
02992 return status;
02993 }
02994
02995 int hashed_option_space_encapsulate (result, packet, lease, client_state,
02996 in_options, cfg_options, scope, universe)
02997 struct data_string *result;
02998 struct packet *packet;
02999 struct lease *lease;
03000 struct client_state *client_state;
03001 struct option_state *in_options;
03002 struct option_state *cfg_options;
03003 struct binding_scope **scope;
03004 struct universe *universe;
03005 {
03006 pair p, *hash;
03007 int status;
03008 int i;
03009
03010 if (universe -> index >= cfg_options -> universe_count)
03011 return 0;
03012
03013 hash = cfg_options -> universes [universe -> index];
03014 if (!hash)
03015 return 0;
03016
03017
03018
03019
03020
03021 status = 0;
03022 for (i = 0; i < OPTION_HASH_SIZE; i++) {
03023 for (p = hash [i]; p; p = p -> cdr) {
03024 if (store_option(result, universe, packet, lease,
03025 client_state, in_options, cfg_options,
03026 scope, (struct option_cache *)p->car))
03027 status = 1;
03028 }
03029 }
03030
03031 if (search_subencapsulation(result, packet, lease, client_state,
03032 in_options, cfg_options, scope, universe))
03033 status = 1;
03034
03035 return status;
03036 }
03037
03038 int nwip_option_space_encapsulate (result, packet, lease, client_state,
03039 in_options, cfg_options, scope, universe)
03040 struct data_string *result;
03041 struct packet *packet;
03042 struct lease *lease;
03043 struct client_state *client_state;
03044 struct option_state *in_options;
03045 struct option_state *cfg_options;
03046 struct binding_scope **scope;
03047 struct universe *universe;
03048 {
03049 pair ocp;
03050 int status;
03051 static struct option_cache *no_nwip;
03052 struct data_string ds;
03053 struct option_chain_head *head;
03054
03055 if (universe -> index >= cfg_options -> universe_count)
03056 return 0;
03057 head = ((struct option_chain_head *)
03058 cfg_options -> universes [nwip_universe.index]);
03059 if (!head)
03060 return 0;
03061
03062 status = 0;
03063 for (ocp = head -> first; ocp; ocp = ocp -> cdr) {
03064 if (store_option (result, universe, packet,
03065 lease, client_state, in_options,
03066 cfg_options, scope,
03067 (struct option_cache *)ocp -> car))
03068 status = 1;
03069 }
03070
03071
03072
03073 if (!status) {
03074 if (!no_nwip) {
03075 unsigned one = 1;
03076 static unsigned char nni [] = { 1, 0 };
03077
03078 memset (&ds, 0, sizeof ds);
03079 ds.data = nni;
03080 ds.len = 2;
03081 if (option_cache_allocate (&no_nwip, MDL))
03082 data_string_copy (&no_nwip -> data, &ds, MDL);
03083 if (!option_code_hash_lookup(&no_nwip->option,
03084 nwip_universe.code_hash,
03085 &one, 0, MDL))
03086 log_fatal("Nwip option hash does not contain "
03087 "1 (%s:%d).", MDL);
03088 }
03089 if (no_nwip) {
03090 if (store_option (result, universe, packet, lease,
03091 client_state, in_options,
03092 cfg_options, scope, no_nwip))
03093 status = 1;
03094 }
03095 } else {
03096 memset (&ds, 0, sizeof ds);
03097
03098
03099
03100 if (!buffer_allocate (&ds.buffer, result -> len + 2, MDL)) {
03101 data_string_forget (result, MDL);
03102 return 0;
03103 }
03104 ds.data = &ds.buffer -> data [0];
03105 ds.buffer -> data [0] = 2;
03106 ds.buffer -> data [1] = 0;
03107 memcpy (&ds.buffer -> data [2], result -> data, result -> len);
03108 data_string_forget (result, MDL);
03109 data_string_copy (result, &ds, MDL);
03110 data_string_forget (&ds, MDL);
03111 }
03112
03113 return status;
03114 }
03115
03116
03117
03118
03119
03120
03121
03122 static int
03123 fqdn_encode(unsigned char *dst, int dstlen, const unsigned char *src,
03124 int srclen)
03125 {
03126 unsigned char *out;
03127 int i, j, len, outlen=0;
03128
03129 out = dst;
03130 for (i = 0, j = 0 ; i < srclen ; i = j) {
03131 while ((j < srclen) && (src[j] != '.') && (src[j] != '\0'))
03132 j++;
03133
03134 len = j - i;
03135 if ((outlen + 1 + len) > dstlen)
03136 return -1;
03137
03138 *out++ = len;
03139 outlen++;
03140
03141
03142 if (len == 0)
03143 return outlen;
03144
03145 memcpy(out, src + i, len);
03146 out += len;
03147 outlen += len;
03148
03149
03150 j++;
03151 }
03152
03153 if ((outlen + 1) > dstlen)
03154 return -1;
03155
03156
03157 *out++ = 0;
03158 outlen++;
03159
03160 return outlen;
03161 }
03162
03163 int fqdn_option_space_encapsulate (result, packet, lease, client_state,
03164 in_options, cfg_options, scope, universe)
03165 struct data_string *result;
03166 struct packet *packet;
03167 struct lease *lease;
03168 struct client_state *client_state;
03169 struct option_state *in_options;
03170 struct option_state *cfg_options;
03171 struct binding_scope **scope;
03172 struct universe *universe;
03173 {
03174 pair ocp;
03175 struct data_string results [FQDN_SUBOPTION_COUNT + 1];
03176 int status = 1;
03177 int i;
03178 unsigned len;
03179 struct buffer *bp = (struct buffer *)0;
03180 struct option_chain_head *head;
03181
03182
03183 if (fqdn_universe.index >= cfg_options -> universe_count)
03184 return 0;
03185 head = ((struct option_chain_head *)
03186 cfg_options -> universes [fqdn_universe.index]);
03187 if (!head)
03188 return 0;
03189
03190
03191 memset (results, 0, sizeof results);
03192 for (ocp = head -> first; ocp; ocp = ocp -> cdr) {
03193 struct option_cache *oc = (struct option_cache *)(ocp -> car);
03194 if (oc -> option -> code > FQDN_SUBOPTION_COUNT)
03195 continue;
03196
03197 (void) evaluate_option_cache (&results[oc->option->code],
03198 packet, lease, client_state,
03199 in_options, cfg_options, scope,
03200 oc, MDL);
03201 }
03202
03203
03204
03205
03206
03207
03208 len = 5 + results [FQDN_FQDN].len;
03209
03210 if (!buffer_allocate (&bp, len, MDL)) {
03211 log_error ("no memory for option buffer.");
03212 status = 0;
03213 goto exit;
03214 }
03215 buffer_reference (&result -> buffer, bp, MDL);
03216 result -> len = 3;
03217 result -> data = &bp -> data [0];
03218
03219 memset (&bp -> data [0], 0, len);
03220
03221
03222
03223
03224
03225
03226
03227
03228
03229
03230
03231 if (results [FQDN_NO_CLIENT_UPDATE].len &&
03232 results [FQDN_NO_CLIENT_UPDATE].data [0])
03233 bp -> data [0] |= 2;
03234 if (results [FQDN_SERVER_UPDATE].len &&
03235 results [FQDN_SERVER_UPDATE].data [0])
03236 bp -> data [0] |= 1;
03237 if (results [FQDN_RCODE1].len)
03238 bp -> data [1] = results [FQDN_RCODE1].data [0];
03239 if (results [FQDN_RCODE2].len)
03240 bp -> data [2] = results [FQDN_RCODE2].data [0];
03241
03242 if (results [FQDN_ENCODED].len &&
03243 results [FQDN_ENCODED].data [0]) {
03244 bp->data[0] |= 4;
03245 if (results [FQDN_FQDN].len) {
03246 i = fqdn_encode(&bp->data[3], len - 3,
03247 results[FQDN_FQDN].data,
03248 results[FQDN_FQDN].len);
03249
03250 if (i < 0) {
03251 status = 0;
03252 goto exit;
03253 }
03254
03255 result->len += i;
03256 result->terminated = 0;
03257 }
03258 } else {
03259 if (results [FQDN_FQDN].len) {
03260 memcpy (&bp -> data [3], results [FQDN_FQDN].data,
03261 results [FQDN_FQDN].len);
03262 result -> len += results [FQDN_FQDN].len;
03263 result -> terminated = 0;
03264 }
03265 }
03266 exit:
03267 for (i = 1; i <= FQDN_SUBOPTION_COUNT; i++) {
03268 if (results [i].len)
03269 data_string_forget (&results [i], MDL);
03270 }
03271 buffer_dereference (&bp, MDL);
03272 if (!status)
03273 data_string_forget(result, MDL);
03274 return status;
03275 }
03276
03277
03278
03279
03280 struct option_cache *
03281 lookup_fqdn6_option(struct universe *universe, struct option_state *options,
03282 unsigned code)
03283 {
03284 log_fatal("Impossible condition at %s:%d.", MDL);
03285 return NULL;
03286 }
03287
03288
03289
03290
03291 void
03292 save_fqdn6_option(struct universe *universe, struct option_state *options,
03293 struct option_cache *oc, isc_boolean_t appendp)
03294 {
03295 log_fatal("Impossible condition at %s:%d.", MDL);
03296 }
03297
03298
03299
03300
03301 void
03302 delete_fqdn6_option(struct universe *universe, struct option_state *options,
03303 int code)
03304 {
03305 log_fatal("Impossible condition at %s:%d.", MDL);
03306 }
03307
03308
03309
03310
03311
03312
03313
03314
03315 void
03316 fqdn6_option_space_foreach(struct packet *packet, struct lease *lease,
03317 struct client_state *client_state,
03318 struct option_state *in_options,
03319 struct option_state *cfg_options,
03320 struct binding_scope **scope,
03321 struct universe *u, void *stuff,
03322 void (*func)(struct option_cache *,
03323 struct packet *,
03324 struct lease *,
03325 struct client_state *,
03326 struct option_state *,
03327 struct option_state *,
03328 struct binding_scope **,
03329 struct universe *, void *))
03330 {
03331
03332 return;
03333 }
03334
03335
03336
03337 int
03338 fqdn6_option_space_encapsulate(struct data_string *result,
03339 struct packet *packet, struct lease *lease,
03340 struct client_state *client_state,
03341 struct option_state *in_options,
03342 struct option_state *cfg_options,
03343 struct binding_scope **scope,
03344 struct universe *universe)
03345 {
03346 pair ocp;
03347 struct option_chain_head *head;
03348 struct option_cache *oc;
03349 unsigned char *data;
03350 int i, len, rval = 0, count;
03351 struct data_string results[FQDN_SUBOPTION_COUNT + 1];
03352
03353 if (fqdn_universe.index >= cfg_options->universe_count)
03354 return 0;
03355 head = ((struct option_chain_head *)
03356 cfg_options->universes[fqdn_universe.index]);
03357 if (head == NULL)
03358 return 0;
03359
03360 memset(results, 0, sizeof(results));
03361 for (ocp = head->first ; ocp != NULL ; ocp = ocp->cdr) {
03362 oc = (struct option_cache *)(ocp->car);
03363 if (oc->option->code > FQDN_SUBOPTION_COUNT)
03364 log_fatal("Impossible condition at %s:%d.", MDL);
03365
03366 (void) evaluate_option_cache(&results[oc->option->code], packet,
03367 lease, client_state, in_options,
03368 cfg_options, scope, oc, MDL);
03369 }
03370
03371
03372
03373
03374
03375
03376 len = results[FQDN_FQDN].len + 3;
03377 if (!buffer_allocate(&result->buffer, len, MDL)) {
03378 log_error("No memory for virtual option buffer.");
03379 goto exit;
03380 }
03381 data = result->buffer->data;
03382 result->data = data;
03383
03384
03385 result->len = 1;
03386 data[0] = 0;
03387
03388
03389
03390
03391
03392
03393
03394
03395
03396
03397 if (results[FQDN_NO_CLIENT_UPDATE].len &&
03398 results[FQDN_NO_CLIENT_UPDATE].data[0])
03399 data[0] |= 2;
03400 if (results[FQDN_SERVER_UPDATE].len &&
03401 results[FQDN_SERVER_UPDATE].data[0])
03402 data[0] |= 1;
03403
03404
03405 if (results[FQDN_FQDN].len == 0) {
03406 rval = 1;
03407 goto exit;
03408 }
03409
03410
03411 count = fqdn_encode(data + 1, len - 1,
03412 results[FQDN_FQDN].data, results[FQDN_FQDN].len);
03413
03414 if (count < 0) {
03415 rval = 0;
03416 data_string_forget(result, MDL);
03417 goto exit;
03418 }
03419
03420 result->len += count;
03421 result->terminated = 0;
03422
03423
03424 rval = 1;
03425
03426 exit:
03427 for (i = 1 ; i <= FQDN_SUBOPTION_COUNT ; i++) {
03428 if (result[i].len)
03429 data_string_forget(&results[i], MDL);
03430 }
03431
03432 return rval;
03433 }
03434
03435
03436
03437 int
03438 fqdn6_universe_decode(struct option_state *options,
03439 const unsigned char *buffer, unsigned length,
03440 struct universe *u)
03441 {
03442 struct buffer *bp = NULL;
03443 unsigned char *first_dot;
03444 int len, hlen, dlen;
03445
03446
03447 if (length < 1)
03448 return 0;
03449
03450
03451
03452
03453
03454
03455
03456 if (!buffer_allocate(&bp, length + 2, MDL)) {
03457 log_error("No memory for dhcp6.fqdn option buffer.");
03458 return 0;
03459 }
03460
03461
03462 bp->data[0] = 1;
03463 if (!save_option_buffer(&fqdn_universe, options, bp,
03464 bp->data, 1, FQDN_ENCODED, 0))
03465 goto error;
03466
03467
03468
03469 if (buffer[0] & 1)
03470 bp->data[2] = 1;
03471 else
03472 bp->data[2] = 0;
03473
03474 if (!save_option_buffer(&fqdn_universe, options, bp, bp->data + 2, 1,
03475 FQDN_SERVER_UPDATE, 0))
03476 goto error;
03477
03478 if (buffer[0] & 2)
03479 bp->data[1] = 1;
03480 else
03481 bp->data[1] = 0;
03482
03483 if (!save_option_buffer(&fqdn_universe, options, bp, bp->data + 1, 1,
03484 FQDN_NO_CLIENT_UPDATE, 0))
03485 goto error;
03486
03487
03488 len = MRns_name_ntop(buffer + 1, (char *)bp->data + 3, length - 1);
03489 if (len == -1) {
03490 log_error("Unable to convert dhcp6.fqdn domain name to "
03491 "printable form.");
03492 goto error;
03493 }
03494
03495
03496 if (len > 0) {
03497 unsigned char *fqdn_start = bp->data + 3;
03498
03499 if (!save_option_buffer(&fqdn_universe, options, bp,
03500 fqdn_start, len, FQDN_FQDN, 1))
03501 goto error;
03502
03503 first_dot = (unsigned char *)strchr((char *)fqdn_start, '.');
03504
03505 if (first_dot != NULL) {
03506 hlen = first_dot - fqdn_start;
03507 dlen = len - hlen;
03508 } else {
03509 hlen = len;
03510 dlen = 0;
03511 }
03512
03513 if (!save_option_buffer(&fqdn_universe, options, bp,
03514 fqdn_start, len, FQDN_FQDN, 1) ||
03515 ((hlen > 0) &&
03516 !save_option_buffer(&fqdn_universe, options, bp,
03517 fqdn_start, hlen,
03518 FQDN_HOSTNAME, 0)) ||
03519 ((dlen > 0) &&
03520 !save_option_buffer(&fqdn_universe, options, bp,
03521 first_dot, dlen, FQDN_DOMAINNAME, 0)))
03522 goto error;
03523 }
03524
03525 buffer_dereference(&bp, MDL);
03526 return 1;
03527
03528 error:
03529 buffer_dereference(&bp, MDL);
03530 return 0;
03531 }
03532
03533 void option_space_foreach (struct packet *packet, struct lease *lease,
03534 struct client_state *client_state,
03535 struct option_state *in_options,
03536 struct option_state *cfg_options,
03537 struct binding_scope **scope,
03538 struct universe *u, void *stuff,
03539 void (*func) (struct option_cache *,
03540 struct packet *,
03541 struct lease *, struct client_state *,
03542 struct option_state *,
03543 struct option_state *,
03544 struct binding_scope **,
03545 struct universe *, void *))
03546 {
03547 if (u -> foreach)
03548 (*u -> foreach) (packet, lease, client_state, in_options,
03549 cfg_options, scope, u, stuff, func);
03550 }
03551
03552 void suboption_foreach (struct packet *packet, struct lease *lease,
03553 struct client_state *client_state,
03554 struct option_state *in_options,
03555 struct option_state *cfg_options,
03556 struct binding_scope **scope,
03557 struct universe *u, void *stuff,
03558 void (*func) (struct option_cache *,
03559 struct packet *,
03560 struct lease *, struct client_state *,
03561 struct option_state *,
03562 struct option_state *,
03563 struct binding_scope **,
03564 struct universe *, void *),
03565 struct option_cache *oc,
03566 const char *vsname)
03567 {
03568 struct universe *universe = find_option_universe (oc -> option,
03569 vsname);
03570 if (universe -> foreach)
03571 (*universe -> foreach) (packet, lease, client_state,
03572 in_options, cfg_options,
03573 scope, universe, stuff, func);
03574 }
03575
03576 void hashed_option_space_foreach (struct packet *packet, struct lease *lease,
03577 struct client_state *client_state,
03578 struct option_state *in_options,
03579 struct option_state *cfg_options,
03580 struct binding_scope **scope,
03581 struct universe *u, void *stuff,
03582 void (*func) (struct option_cache *,
03583 struct packet *,
03584 struct lease *,
03585 struct client_state *,
03586 struct option_state *,
03587 struct option_state *,
03588 struct binding_scope **,
03589 struct universe *, void *))
03590 {
03591 pair *hash;
03592 int i;
03593 struct option_cache *oc;
03594
03595 if (cfg_options -> universe_count <= u -> index)
03596 return;
03597
03598 hash = cfg_options -> universes [u -> index];
03599 if (!hash)
03600 return;
03601 for (i = 0; i < OPTION_HASH_SIZE; i++) {
03602 pair p;
03603
03604 for (p = hash [i]; p; p = p -> cdr) {
03605 oc = (struct option_cache *)p -> car;
03606 (*func) (oc, packet, lease, client_state,
03607 in_options, cfg_options, scope, u, stuff);
03608 }
03609 }
03610 }
03611
03612 void
03613 save_linked_option(struct universe *universe, struct option_state *options,
03614 struct option_cache *oc, isc_boolean_t appendp)
03615 {
03616 pair *tail;
03617 struct option_chain_head *head;
03618 struct option_cache **ocloc;
03619
03620 if (universe -> index >= options -> universe_count)
03621 return;
03622 head = ((struct option_chain_head *)
03623 options -> universes [universe -> index]);
03624 if (!head) {
03625 if (!option_chain_head_allocate (((struct option_chain_head **)
03626 &options -> universes
03627 [universe -> index]), MDL))
03628 return;
03629 head = ((struct option_chain_head *)
03630 options -> universes [universe -> index]);
03631 }
03632
03633
03634 for (tail = &head -> first; *tail; tail = &((*tail) -> cdr)) {
03635 ocloc = (struct option_cache **)&(*tail)->car;
03636
03637 if (oc->option->code == (*ocloc)->option->code) {
03638 if (appendp) {
03639 do {
03640 ocloc = &(*ocloc)->next;
03641 } while (*ocloc != NULL);
03642 } else {
03643 option_cache_dereference(ocloc, MDL);
03644 }
03645 option_cache_reference(ocloc, oc, MDL);
03646 return;
03647 }
03648 }
03649
03650 *tail = cons (0, 0);
03651 if (*tail) {
03652 option_cache_reference ((struct option_cache **)
03653 (&(*tail) -> car), oc, MDL);
03654 }
03655 }
03656
03657 int linked_option_space_encapsulate (result, packet, lease, client_state,
03658 in_options, cfg_options, scope, universe)
03659 struct data_string *result;
03660 struct packet *packet;
03661 struct lease *lease;
03662 struct client_state *client_state;
03663 struct option_state *in_options;
03664 struct option_state *cfg_options;
03665 struct binding_scope **scope;
03666 struct universe *universe;
03667 {
03668 int status = 0;
03669 pair oc;
03670 struct option_chain_head *head;
03671
03672 if (universe -> index >= cfg_options -> universe_count)
03673 return status;
03674 head = ((struct option_chain_head *)
03675 cfg_options -> universes [universe -> index]);
03676 if (!head)
03677 return status;
03678
03679 for (oc = head -> first; oc; oc = oc -> cdr) {
03680 if (store_option (result, universe, packet,
03681 lease, client_state, in_options, cfg_options,
03682 scope, (struct option_cache *)(oc -> car)))
03683 status = 1;
03684 }
03685
03686 if (search_subencapsulation(result, packet, lease, client_state,
03687 in_options, cfg_options, scope, universe))
03688 status = 1;
03689
03690 return status;
03691 }
03692
03693 void delete_linked_option (universe, options, code)
03694 struct universe *universe;
03695 struct option_state *options;
03696 int code;
03697 {
03698 pair *tail, tmp = (pair)0;
03699 struct option_chain_head *head;
03700
03701 if (universe -> index >= options -> universe_count)
03702 return;
03703 head = ((struct option_chain_head *)
03704 options -> universes [universe -> index]);
03705 if (!head)
03706 return;
03707
03708 for (tail = &head -> first; *tail; tail = &((*tail) -> cdr)) {
03709 if (code ==
03710 ((struct option_cache *)(*tail) -> car) -> option -> code)
03711 {
03712 tmp = (*tail) -> cdr;
03713 option_cache_dereference ((struct option_cache **)
03714 (&(*tail) -> car), MDL);
03715 dfree (*tail, MDL);
03716 (*tail) = tmp;
03717 break;
03718 }
03719 }
03720 }
03721
03722 struct option_cache *lookup_linked_option (universe, options, code)
03723 struct universe *universe;
03724 struct option_state *options;
03725 unsigned code;
03726 {
03727 pair oc;
03728 struct option_chain_head *head;
03729
03730 if (universe -> index >= options -> universe_count)
03731 return 0;
03732 head = ((struct option_chain_head *)
03733 options -> universes [universe -> index]);
03734 if (!head)
03735 return 0;
03736
03737 for (oc = head -> first; oc; oc = oc -> cdr) {
03738 if (code ==
03739 ((struct option_cache *)(oc -> car)) -> option -> code) {
03740 return (struct option_cache *)(oc -> car);
03741 }
03742 }
03743
03744 return (struct option_cache *)0;
03745 }
03746
03747 int linked_option_state_dereference (universe, state, file, line)
03748 struct universe *universe;
03749 struct option_state *state;
03750 const char *file;
03751 int line;
03752 {
03753 return (option_chain_head_dereference
03754 ((struct option_chain_head **)
03755 (&state -> universes [universe -> index]), MDL));
03756 }
03757
03758 void linked_option_space_foreach (struct packet *packet, struct lease *lease,
03759 struct client_state *client_state,
03760 struct option_state *in_options,
03761 struct option_state *cfg_options,
03762 struct binding_scope **scope,
03763 struct universe *u, void *stuff,
03764 void (*func) (struct option_cache *,
03765 struct packet *,
03766 struct lease *,
03767 struct client_state *,
03768 struct option_state *,
03769 struct option_state *,
03770 struct binding_scope **,
03771 struct universe *, void *))
03772 {
03773 pair car;
03774 struct option_chain_head *head;
03775
03776 if (u -> index >= cfg_options -> universe_count)
03777 return;
03778 head = ((struct option_chain_head *)
03779 cfg_options -> universes [u -> index]);
03780 if (!head)
03781 return;
03782 for (car = head -> first; car; car = car -> cdr) {
03783 (*func) ((struct option_cache *)(car -> car),
03784 packet, lease, client_state,
03785 in_options, cfg_options, scope, u, stuff);
03786 }
03787 }
03788
03789 void do_packet (interface, packet, len, from_port, from, hfrom)
03790 struct interface_info *interface;
03791 struct dhcp_packet *packet;
03792 unsigned len;
03793 unsigned int from_port;
03794 struct iaddr from;
03795 struct hardware *hfrom;
03796 {
03797 struct option_cache *op;
03798 struct packet *decoded_packet;
03799 #if defined (DEBUG_MEMORY_LEAKAGE)
03800 unsigned long previous_outstanding = dmalloc_outstanding;
03801 #endif
03802
03803 #if defined (TRACING)
03804 trace_inpacket_stash(interface, packet, len, from_port, from, hfrom);
03805 #endif
03806
03807 decoded_packet = NULL;
03808 if (!packet_allocate(&decoded_packet, MDL)) {
03809 log_error("do_packet: no memory for incoming packet!");
03810 return;
03811 }
03812 decoded_packet->raw = packet;
03813 decoded_packet->packet_length = len;
03814 decoded_packet->client_port = from_port;
03815 decoded_packet->client_addr = from;
03816 interface_reference(&decoded_packet->interface, interface, MDL);
03817 decoded_packet->haddr = hfrom;
03818
03819 if (packet->hlen > sizeof packet->chaddr) {
03820 packet_dereference(&decoded_packet, MDL);
03821 log_info("Discarding packet with bogus hlen.");
03822 return;
03823 }
03824
03825
03826 if (decoded_packet->packet_length >= DHCP_FIXED_NON_UDP + 4) {
03827 if (!parse_options(decoded_packet)) {
03828 if (decoded_packet->options)
03829 option_state_dereference
03830 (&decoded_packet->options, MDL);
03831 packet_dereference (&decoded_packet, MDL);
03832 return;
03833 }
03834
03835 if (decoded_packet->options_valid &&
03836 (op = lookup_option(&dhcp_universe,
03837 decoded_packet->options,
03838 DHO_DHCP_MESSAGE_TYPE))) {
03839 struct data_string dp;
03840 memset(&dp, 0, sizeof dp);
03841 evaluate_option_cache(&dp, decoded_packet, NULL, NULL,
03842 decoded_packet->options, NULL,
03843 NULL, op, MDL);
03844 if (dp.len > 0)
03845 decoded_packet->packet_type = dp.data[0];
03846 else
03847 decoded_packet->packet_type = 0;
03848 data_string_forget(&dp, MDL);
03849 }
03850 }
03851
03852 if (validate_packet(decoded_packet) != 0) {
03853 if (decoded_packet->packet_type)
03854 dhcp(decoded_packet);
03855 else
03856 bootp(decoded_packet);
03857 }
03858
03859
03860 packet_dereference(&decoded_packet, MDL);
03861
03862 #if defined (DEBUG_MEMORY_LEAKAGE)
03863 log_info("generation %ld: %ld new, %ld outstanding, %ld long-term",
03864 dmalloc_generation,
03865 dmalloc_outstanding - previous_outstanding,
03866 dmalloc_outstanding, dmalloc_longterm);
03867 dmalloc_dump_outstanding();
03868 #endif
03869 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
03870 dump_rc_history(0);
03871 #endif
03872 }
03873
03874 int
03875 packet6_len_okay(const char *packet, int len) {
03876 if (len < 1) {
03877 return 0;
03878 }
03879 if ((packet[0] == DHCPV6_RELAY_FORW) ||
03880 (packet[0] == DHCPV6_RELAY_REPL)) {
03881 if (len >= offsetof(struct dhcpv6_relay_packet, options)) {
03882 return 1;
03883 } else {
03884 return 0;
03885 }
03886 } else {
03887 if (len >= offsetof(struct dhcpv6_packet, options)) {
03888 return 1;
03889 } else {
03890 return 0;
03891 }
03892 }
03893 }
03894
03895 #ifdef DHCPv6
03896 void
03897 do_packet6(struct interface_info *interface, const char *packet,
03898 int len, int from_port, const struct iaddr *from,
03899 isc_boolean_t was_unicast) {
03900 unsigned char msg_type;
03901 const struct dhcpv6_packet *msg;
03902 const struct dhcpv6_relay_packet *relay;
03903 struct packet *decoded_packet;
03904 #if defined (DEBUG_MEMORY_LEAKAGE)
03905 unsigned long previous_outstanding = dmalloc_outstanding;
03906 #endif
03907
03908 if (!packet6_len_okay(packet, len)) {
03909 log_info("do_packet6: "
03910 "short packet from %s port %d, len %d, dropped",
03911 piaddr(*from), from_port, len);
03912 return;
03913 }
03914
03915 decoded_packet = NULL;
03916 if (!packet_allocate(&decoded_packet, MDL)) {
03917 log_error("do_packet6: no memory for incoming packet.");
03918 return;
03919 }
03920
03921 if (!option_state_allocate(&decoded_packet->options, MDL)) {
03922 log_error("do_packet6: no memory for options.");
03923 packet_dereference(&decoded_packet, MDL);
03924 return;
03925 }
03926
03927
03928
03929
03930
03931
03932
03933
03934 decoded_packet->raw = (struct dhcp_packet *)packet;
03935 decoded_packet->packet_length = (unsigned)len;
03936 decoded_packet->client_port = from_port;
03937 decoded_packet->client_addr = *from;
03938 interface_reference(&decoded_packet->interface, interface, MDL);
03939
03940 decoded_packet->unicast = was_unicast;
03941
03942 msg_type = packet[0];
03943 if ((msg_type == DHCPV6_RELAY_FORW) ||
03944 (msg_type == DHCPV6_RELAY_REPL)) {
03945 int relaylen = (int)(offsetof(struct dhcpv6_relay_packet, options));
03946 relay = (const struct dhcpv6_relay_packet *)packet;
03947 decoded_packet->dhcpv6_msg_type = relay->msg_type;
03948
03949
03950 decoded_packet->dhcpv6_hop_count = relay->hop_count;
03951 memcpy(&decoded_packet->dhcpv6_link_address,
03952 relay->link_address, sizeof(relay->link_address));
03953 memcpy(&decoded_packet->dhcpv6_peer_address,
03954 relay->peer_address, sizeof(relay->peer_address));
03955
03956 if (!parse_option_buffer(decoded_packet->options,
03957 relay->options, len - relaylen,
03958 &dhcpv6_universe)) {
03959
03960
03961 packet_dereference(&decoded_packet, MDL);
03962 return;
03963 }
03964 } else {
03965 int msglen = (int)(offsetof(struct dhcpv6_packet, options));
03966 msg = (const struct dhcpv6_packet *)packet;
03967 decoded_packet->dhcpv6_msg_type = msg->msg_type;
03968
03969
03970 memcpy(decoded_packet->dhcpv6_transaction_id,
03971 msg->transaction_id,
03972 sizeof(decoded_packet->dhcpv6_transaction_id));
03973
03974 if (!parse_option_buffer(decoded_packet->options,
03975 msg->options, len - msglen,
03976 &dhcpv6_universe)) {
03977
03978
03979 packet_dereference(&decoded_packet, MDL);
03980 return;
03981 }
03982 }
03983
03984 dhcpv6(decoded_packet);
03985
03986 packet_dereference(&decoded_packet, MDL);
03987
03988 #if defined (DEBUG_MEMORY_LEAKAGE)
03989 log_info("generation %ld: %ld new, %ld outstanding, %ld long-term",
03990 dmalloc_generation,
03991 dmalloc_outstanding - previous_outstanding,
03992 dmalloc_outstanding, dmalloc_longterm);
03993 dmalloc_dump_outstanding();
03994 #endif
03995 #if defined (DEBUG_RC_HISTORY_EXHAUSTIVELY)
03996 dump_rc_history(0);
03997 #endif
03998 }
03999 #endif
04000
04001 int
04002 pretty_escape(char **dst, char *dend, const unsigned char **src,
04003 const unsigned char *send)
04004 {
04005 int count = 0;
04006
04007
04008
04009
04010 if (dst == NULL || dend == NULL || src == NULL || send == NULL ||
04011 *dst == NULL || *src == NULL || (*dst >= dend) || (*src > send) ||
04012 ((send - *src) > (dend - *dst)))
04013 return -1;
04014
04015 for ( ; *src < send ; (*src)++) {
04016 if (!isascii (**src) || !isprint (**src)) {
04017
04018 if ((*src + 1) != send || **src != '\0') {
04019 if (*dst + 4 > dend)
04020 return -1;
04021
04022 sprintf(*dst, "\\%03o",
04023 **src);
04024 (*dst) += 4;
04025 count += 4;
04026 }
04027 } else if (**src == '"' || **src == '\'' || **src == '$' ||
04028 **src == '`' || **src == '\\' || **src == '|' ||
04029 **src == '&') {
04030 if (*dst + 2 > dend)
04031 return -1;
04032
04033 **dst = '\\';
04034 (*dst)++;
04035 **dst = **src;
04036 (*dst)++;
04037 count += 2;
04038 } else {
04039 if (*dst + 1 > dend)
04040 return -1;
04041
04042 **dst = **src;
04043 (*dst)++;
04044 count++;
04045 }
04046 }
04047
04048 return count;
04049 }
04050
04051 static int
04052 pretty_text(char **dst, char *dend, const unsigned char **src,
04053 const unsigned char *send, int emit_quotes)
04054 {
04055 int count;
04056
04057 if (dst == NULL || dend == NULL || src == NULL || send == NULL ||
04058 *dst == NULL || *src == NULL ||
04059 ((*dst + (emit_quotes ? 2 : 0)) > dend) || (*src > send))
04060 return -1;
04061
04062 if (emit_quotes) {
04063 **dst = '"';
04064 (*dst)++;
04065 }
04066
04067
04068 count = pretty_escape(dst, dend - (emit_quotes ? 1 : 0), src, send);
04069
04070 if (count == -1)
04071 return -1;
04072
04073 if (emit_quotes && (*dst < dend)) {
04074 **dst = '"';
04075 (*dst)++;
04076
04077
04078 count += 2;
04079 }
04080
04081 return count;
04082 }
04083
04084 static int
04085 pretty_domain(char **dst, char *dend, const unsigned char **src,
04086 const unsigned char *send)
04087 {
04088 const unsigned char *tend;
04089 int count = 2;
04090 int tsiz, status;
04091
04092 if (dst == NULL || dend == NULL || src == NULL || send == NULL ||
04093 *dst == NULL || *src == NULL ||
04094 ((*dst + 2) > dend) || (*src >= send))
04095 return -1;
04096
04097 **dst = '"';
04098 (*dst)++;
04099
04100 do {
04101
04102 if (*src >= send)
04103 break;
04104
04105
04106 tsiz = **src;
04107 (*src)++;
04108
04109
04110 if (tsiz == 0)
04111 break;
04112
04113 tend = (*src) + tsiz;
04114
04115
04116
04117
04118
04119 if (tend > send)
04120 return -1;
04121
04122
04123 status = pretty_escape(dst, dend-2, src, tend);
04124
04125 if ((status == -1) || ((*dst + 2) > dend))
04126 return -1;
04127
04128 **dst = '.';
04129 (*dst)++;
04130 count += status + 1;
04131 }
04132 while(1);
04133
04134 **dst = '"';
04135 (*dst)++;
04136
04137 return count;
04138 }
04139
04140
04141
04142
04143
04144 int
04145 add_option(struct option_state *options,
04146 unsigned int option_num,
04147 void *data,
04148 unsigned int data_len)
04149 {
04150 struct option_cache *oc;
04151 struct option *option;
04152
04153
04154
04155
04156 option = NULL;
04157 if (!option_code_hash_lookup(&option, dhcp_universe.code_hash,
04158 &option_num, 0, MDL)) {
04159 log_error("Attempting to add unknown option %d.", option_num);
04160 return 0;
04161 }
04162
04163 oc = NULL;
04164 if (!option_cache_allocate(&oc, MDL)) {
04165 log_error("No memory for option cache adding %s (option %d).",
04166 option->name, option_num);
04167 return 0;
04168 }
04169
04170 if (!make_const_data(&oc->expression,
04171 data,
04172 data_len,
04173 0,
04174 0,
04175 MDL)) {
04176 log_error("No memory for constant data adding %s (option %d).",
04177 option->name, option_num);
04178 option_cache_dereference(&oc, MDL);
04179 return 0;
04180 }
04181
04182 option_reference(&(oc->option), option, MDL);
04183 save_option(&dhcp_universe, options, oc);
04184 option_cache_dereference(&oc, MDL);
04185
04186 return 1;
04187 }
04188
04196 int validate_packet(struct packet *packet)
04197 {
04198 struct option_cache *oc = NULL;
04199
04200 oc = lookup_option (&dhcp_universe, packet->options,
04201 DHO_DHCP_CLIENT_IDENTIFIER);
04202 if (oc) {
04203
04204 if (oc->data.len == 0) {
04205 log_debug("Dropped DHCPv4 packet with zero-length client-id");
04206 return (0);
04207
04208 } else if (oc->data.len == 1) {
04209
04210
04211
04212
04213
04214
04215 log_debug("Accepted DHCPv4 packet with one-character client-id - "
04216 "a future version of ISC DHCP will reject this");
04217 }
04218 } else {
04219
04220
04221
04222
04223 if (packet->raw->hlen == 0) {
04224 log_debug("Received DHCPv4 packet without client-id"
04225 " option and empty hlen field.");
04226 }
04227 }
04228
04229
04230
04231 return (1);
04232 }