1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <sys/types.h> 29 #include <string.h> 30 #include <stdlib.h> 31 #include <stdio.h> 32 #include <errno.h> 33 #include <stdarg.h> 34 #include <limits.h> 35 #include <ctype.h> 36 #include <libgen.h> 37 #include <sys/isa_defs.h> 38 #include <sys/socket.h> 39 #include <net/if_arp.h> 40 #include <netinet/in.h> 41 #include <arpa/inet.h> 42 #include <sys/sysmacros.h> 43 #include <libinetutil.h> 44 #include <libdlpi.h> 45 #include <netinet/dhcp6.h> 46 47 #include "dhcp_symbol.h" 48 #include "dhcp_inittab.h" 49 50 static uint64_t dhcp_htonll(uint64_t); 51 static uint64_t dhcp_ntohll(uint64_t); 52 static void inittab_msg(const char *, ...); 53 static uchar_t category_to_code(const char *); 54 static boolean_t encode_number(uint8_t, uint8_t, boolean_t, uint8_t, 55 const char *, uint8_t *, int *); 56 static boolean_t decode_number(uint8_t, uint8_t, boolean_t, uint8_t, 57 const uint8_t *, char *, int *); 58 static dhcp_symbol_t *inittab_lookup(uchar_t, char, const char *, int32_t, 59 size_t *); 60 static dsym_category_t itabcode_to_dsymcode(uchar_t); 61 static boolean_t parse_entry(char *, char **); 62 63 /* 64 * forward declaration of our internal inittab_table[]. too bulky to put 65 * up front -- check the end of this file for its definition. 66 * 67 * Note: we have only an IPv4 version here. The inittab_verify() function is 68 * used by the DHCP server and manager. We'll need a new function if the 69 * server is extended to DHCPv6. 70 */ 71 static dhcp_symbol_t inittab_table[]; 72 73 /* 74 * the number of fields in the inittab and names for the fields. note that 75 * this order is meaningful to parse_entry(); other functions should just 76 * use them as indexes into the array returned from parse_entry(). 77 */ 78 #define ITAB_FIELDS 7 79 enum { ITAB_NAME, ITAB_CODE, ITAB_TYPE, ITAB_GRAN, ITAB_MAX, ITAB_CONS, 80 ITAB_CAT }; 81 82 /* 83 * the category_map_entry_t is used to map the inittab category codes to 84 * the dsym codes. the reason the codes are different is that the inittab 85 * needs to have the codes be ORable such that queries can retrieve more 86 * than one category at a time. this map is also used to map the inittab 87 * string representation of a category to its numerical code. 88 */ 89 typedef struct category_map_entry { 90 dsym_category_t cme_dsymcode; 91 char *cme_name; 92 uchar_t cme_itabcode; 93 } category_map_entry_t; 94 95 static category_map_entry_t category_map[] = { 96 { DSYM_STANDARD, "STANDARD", ITAB_CAT_STANDARD }, 97 { DSYM_FIELD, "FIELD", ITAB_CAT_FIELD }, 98 { DSYM_INTERNAL, "INTERNAL", ITAB_CAT_INTERNAL }, 99 { DSYM_VENDOR, "VENDOR", ITAB_CAT_VENDOR }, 100 { DSYM_SITE, "SITE", ITAB_CAT_SITE } 101 }; 102 103 /* 104 * inittab_load(): returns all inittab entries with the specified criteria 105 * 106 * input: uchar_t: the categories the consumer is interested in 107 * char: the consumer type of the caller 108 * size_t *: set to the number of entries returned 109 * output: dhcp_symbol_t *: an array of dynamically allocated entries 110 * on success, NULL upon failure 111 */ 112 113 dhcp_symbol_t * 114 inittab_load(uchar_t categories, char consumer, size_t *n_entries) 115 { 116 return (inittab_lookup(categories, consumer, NULL, -1, n_entries)); 117 } 118 119 /* 120 * inittab_getbyname(): returns an inittab entry with the specified criteria 121 * 122 * input: int: the categories the consumer is interested in 123 * char: the consumer type of the caller 124 * char *: the name of the inittab entry the consumer wants 125 * output: dhcp_symbol_t *: a dynamically allocated dhcp_symbol structure 126 * on success, NULL upon failure 127 */ 128 129 dhcp_symbol_t * 130 inittab_getbyname(uchar_t categories, char consumer, const char *name) 131 { 132 return (inittab_lookup(categories, consumer, name, -1, NULL)); 133 } 134 135 /* 136 * inittab_getbycode(): returns an inittab entry with the specified criteria 137 * 138 * input: uchar_t: the categories the consumer is interested in 139 * char: the consumer type of the caller 140 * uint16_t: the code of the inittab entry the consumer wants 141 * output: dhcp_symbol_t *: a dynamically allocated dhcp_symbol structure 142 * on success, NULL upon failure 143 */ 144 145 dhcp_symbol_t * 146 inittab_getbycode(uchar_t categories, char consumer, uint16_t code) 147 { 148 return (inittab_lookup(categories, consumer, NULL, code, NULL)); 149 } 150 151 /* 152 * inittab_lookup(): returns inittab entries with the specified criteria 153 * 154 * input: uchar_t: the categories the consumer is interested in 155 * char: the consumer type of the caller 156 * const char *: the name of the entry the caller is interested 157 * in, or NULL if the caller doesn't care 158 * int32_t: the code the caller is interested in, or -1 if the 159 * caller doesn't care 160 * size_t *: set to the number of entries returned 161 * output: dhcp_symbol_t *: dynamically allocated dhcp_symbol structures 162 * on success, NULL upon failure 163 */ 164 165 static dhcp_symbol_t * 166 inittab_lookup(uchar_t categories, char consumer, const char *name, 167 int32_t code, size_t *n_entriesp) 168 { 169 FILE *inittab_fp; 170 dhcp_symbol_t *new_entries, *entries = NULL; 171 dhcp_symbol_t entry; 172 char buffer[ITAB_MAX_LINE_LEN]; 173 char *fields[ITAB_FIELDS]; 174 unsigned long line = 0; 175 size_t i, n_entries = 0; 176 const char *inittab_path; 177 uchar_t category_code; 178 dsym_cdtype_t type; 179 180 if (categories & ITAB_CAT_V6) { 181 inittab_path = getenv("DHCP_INITTAB6_PATH"); 182 if (inittab_path == NULL) 183 inittab_path = ITAB_INITTAB6_PATH; 184 } else { 185 inittab_path = getenv("DHCP_INITTAB_PATH"); 186 if (inittab_path == NULL) 187 inittab_path = ITAB_INITTAB_PATH; 188 } 189 190 inittab_fp = fopen(inittab_path, "r"); 191 if (inittab_fp == NULL) { 192 inittab_msg("inittab_lookup: fopen: %s: %s", 193 inittab_path, strerror(errno)); 194 return (NULL); 195 } 196 197 (void) bufsplit(",\n", 0, NULL); 198 while (fgets(buffer, sizeof (buffer), inittab_fp) != NULL) { 199 200 line++; 201 202 /* 203 * make sure the string didn't overflow our buffer 204 */ 205 if (strchr(buffer, '\n') == NULL) { 206 inittab_msg("inittab_lookup: line %li: too long, " 207 "skipping", line); 208 continue; 209 } 210 211 /* 212 * skip `pure comment' lines 213 */ 214 for (i = 0; buffer[i] != '\0'; i++) 215 if (isspace(buffer[i]) == 0) 216 break; 217 218 if (buffer[i] == ITAB_COMMENT_CHAR || buffer[i] == '\0') 219 continue; 220 221 /* 222 * parse the entry out into fields. 223 */ 224 if (parse_entry(buffer, fields) == B_FALSE) { 225 inittab_msg("inittab_lookup: line %li: syntax error, " 226 "skipping", line); 227 continue; 228 } 229 230 /* 231 * validate the values in the entries; skip if invalid. 232 */ 233 if (atoi(fields[ITAB_GRAN]) > ITAB_GRAN_MAX) { 234 inittab_msg("inittab_lookup: line %li: granularity `%s'" 235 " out of range, skipping", line, fields[ITAB_GRAN]); 236 continue; 237 } 238 239 if (atoi(fields[ITAB_MAX]) > ITAB_MAX_MAX) { 240 inittab_msg("inittab_lookup: line %li: maximum `%s' " 241 "out of range, skipping", line, fields[ITAB_MAX]); 242 continue; 243 } 244 245 if (dsym_get_type_id(fields[ITAB_TYPE], &type, B_FALSE) != 246 DSYM_SUCCESS) { 247 inittab_msg("inittab_lookup: line %li: type `%s' " 248 "is invalid, skipping", line, fields[ITAB_TYPE]); 249 continue; 250 } 251 252 /* 253 * find out whether this entry of interest to our consumer, 254 * and if so, throw it onto the set of entries we'll return. 255 * check categories last since it's the most expensive check. 256 */ 257 if (strchr(fields[ITAB_CONS], consumer) == NULL) 258 continue; 259 260 if (code != -1 && atoi(fields[ITAB_CODE]) != code) 261 continue; 262 263 if (name != NULL && strcasecmp(fields[ITAB_NAME], name) != 0) 264 continue; 265 266 category_code = category_to_code(fields[ITAB_CAT]); 267 if ((category_code & categories) == 0) 268 continue; 269 270 /* 271 * looks like a match. allocate an entry and fill it in 272 */ 273 new_entries = realloc(entries, (n_entries + 1) * 274 sizeof (dhcp_symbol_t)); 275 276 /* 277 * if we run out of memory, might as well return what we can 278 */ 279 if (new_entries == NULL) { 280 inittab_msg("inittab_lookup: ran out of memory " 281 "allocating dhcp_symbol_t's"); 282 break; 283 } 284 285 entry.ds_max = atoi(fields[ITAB_MAX]); 286 entry.ds_code = atoi(fields[ITAB_CODE]); 287 entry.ds_type = type; 288 entry.ds_gran = atoi(fields[ITAB_GRAN]); 289 entry.ds_category = itabcode_to_dsymcode(category_code); 290 entry.ds_classes.dc_cnt = 0; 291 entry.ds_classes.dc_names = NULL; 292 (void) strlcpy(entry.ds_name, fields[ITAB_NAME], 293 sizeof (entry.ds_name)); 294 entry.ds_dhcpv6 = (categories & ITAB_CAT_V6) ? 1 : 0; 295 296 entries = new_entries; 297 entries[n_entries++] = entry; 298 } 299 300 if (ferror(inittab_fp) != 0) { 301 inittab_msg("inittab_lookup: error on inittab stream"); 302 clearerr(inittab_fp); 303 } 304 305 (void) fclose(inittab_fp); 306 307 if (n_entriesp != NULL) 308 *n_entriesp = n_entries; 309 310 return (entries); 311 } 312 313 /* 314 * parse_entry(): parses an entry out into its constituent fields 315 * 316 * input: char *: the entry 317 * char **: an array of ITAB_FIELDS length which contains 318 * pointers into the entry on upon return 319 * output: boolean_t: B_TRUE on success, B_FALSE on failure 320 */ 321 322 static boolean_t 323 parse_entry(char *entry, char **fields) 324 { 325 char *category, *spacep; 326 size_t n_fields, i; 327 328 /* 329 * due to a mistake made long ago, the first and second fields of 330 * each entry are not separated by a comma, but rather by 331 * whitespace -- have bufsplit() treat the two fields as one, then 332 * pull them apart afterwards. 333 */ 334 n_fields = bufsplit(entry, ITAB_FIELDS - 1, fields); 335 if (n_fields != (ITAB_FIELDS - 1)) 336 return (B_FALSE); 337 338 /* 339 * pull the first and second fields apart. this is complicated 340 * since the first field can contain embedded whitespace (so we 341 * must separate the two fields by the last span of whitespace). 342 * 343 * first, find the initial span of whitespace. if there isn't one, 344 * then the entry is malformed. 345 */ 346 category = strpbrk(fields[ITAB_NAME], " \t"); 347 if (category == NULL) 348 return (B_FALSE); 349 350 /* 351 * find the last span of whitespace. 352 */ 353 do { 354 while (isspace(*category)) 355 category++; 356 357 spacep = strpbrk(category, " \t"); 358 if (spacep != NULL) 359 category = spacep; 360 } while (spacep != NULL); 361 362 /* 363 * NUL-terminate the first byte of the last span of whitespace, so 364 * that the first field doesn't have any residual trailing 365 * whitespace. 366 */ 367 spacep = category - 1; 368 while (isspace(*spacep)) 369 spacep--; 370 371 if (spacep <= fields[0]) 372 return (B_FALSE); 373 374 *++spacep = '\0'; 375 376 /* 377 * remove any whitespace from the fields. 378 */ 379 for (i = 0; i < n_fields; i++) { 380 while (isspace(*fields[i])) 381 fields[i]++; 382 } 383 fields[ITAB_CAT] = category; 384 385 return (B_TRUE); 386 } 387 388 /* 389 * inittab_verify(): verifies that a given inittab entry matches an internal 390 * definition 391 * 392 * input: dhcp_symbol_t *: the inittab entry to verify 393 * dhcp_symbol_t *: if non-NULL, a place to store the internal 394 * inittab entry upon return 395 * output: int: ITAB_FAILURE, ITAB_SUCCESS, or ITAB_UNKNOWN 396 * 397 * notes: IPv4 only 398 */ 399 400 int 401 inittab_verify(const dhcp_symbol_t *inittab_ent, dhcp_symbol_t *internal_ent) 402 { 403 unsigned int i; 404 405 for (i = 0; inittab_table[i].ds_name[0] != '\0'; i++) { 406 407 if (inittab_ent->ds_category != inittab_table[i].ds_category) 408 continue; 409 410 if (inittab_ent->ds_code == inittab_table[i].ds_code) { 411 if (internal_ent != NULL) 412 *internal_ent = inittab_table[i]; 413 414 if (inittab_table[i].ds_type != inittab_ent->ds_type || 415 inittab_table[i].ds_gran != inittab_ent->ds_gran || 416 inittab_table[i].ds_max != inittab_ent->ds_max) 417 return (ITAB_FAILURE); 418 419 return (ITAB_SUCCESS); 420 } 421 } 422 423 return (ITAB_UNKNOWN); 424 } 425 426 /* 427 * get_hw_type(): interpret ",hwtype" in the input string, as part of a DUID. 428 * The hwtype string is optional, and must be 0-65535 if 429 * present. 430 * 431 * input: char **: pointer to string pointer 432 * int *: error return value 433 * output: int: hardware type, or -1 for empty, or -2 for error. 434 */ 435 436 static int 437 get_hw_type(char **strp, int *ierrnop) 438 { 439 char *str = *strp; 440 ulong_t hwtype; 441 442 if (*str++ != ',') { 443 *ierrnop = ITAB_BAD_NUMBER; 444 return (-2); 445 } 446 if (*str == ',' || *str == '\0') { 447 *strp = str; 448 return (-1); 449 } 450 hwtype = strtoul(str, strp, 0); 451 if (errno != 0 || *strp == str || hwtype > 65535) { 452 *ierrnop = ITAB_BAD_NUMBER; 453 return (-2); 454 } else { 455 return ((int)hwtype); 456 } 457 } 458 459 /* 460 * get_mac_addr(): interpret ",macaddr" in the input string, as part of a DUID. 461 * The 'macaddr' may be a hex string (in any standard format), 462 * or the name of a physical interface. If an interface name 463 * is given, then the interface type is extracted as well. 464 * 465 * input: const char *: input string 466 * int *: error return value 467 * uint16_t *: hardware type output (network byte order) 468 * int: hardware type input; -1 for empty 469 * uchar_t *: output buffer for MAC address 470 * output: int: length of MAC address, or -1 for error 471 */ 472 473 static int 474 get_mac_addr(const char *str, int *ierrnop, uint16_t *hwret, int hwtype, 475 uchar_t *outbuf) 476 { 477 int maclen; 478 int dig, val; 479 dlpi_handle_t dh; 480 dlpi_info_t dlinfo; 481 char chr; 482 483 if (*str != '\0') { 484 if (*str++ != ',') 485 goto failed; 486 if (dlpi_open(str, &dh, 0) != DLPI_SUCCESS) { 487 maclen = 0; 488 dig = val = 0; 489 /* 490 * Allow MAC addresses with separators matching regexp 491 * (:|-| *). 492 */ 493 while ((chr = *str++) != '\0') { 494 if (isdigit(chr)) { 495 val = (val << 4) + chr - '0'; 496 } else if (isxdigit(chr)) { 497 val = (val << 4) + chr - 498 (isupper(chr) ? 'A' : 'a') + 10; 499 } else if (isspace(chr) && dig == 0) { 500 continue; 501 } else if (chr == ':' || chr == '-' || 502 isspace(chr)) { 503 dig = 1; 504 } else { 505 goto failed; 506 } 507 if (++dig == 2) { 508 *outbuf++ = val; 509 maclen++; 510 dig = val = 0; 511 } 512 } 513 } else { 514 if (dlpi_info(dh, &dlinfo, 0) != DLPI_SUCCESS) { 515 dlpi_close(dh); 516 goto failed; 517 } 518 maclen = dlinfo.di_physaddrlen; 519 (void) memcpy(outbuf, dlinfo.di_physaddr, maclen); 520 dlpi_close(dh); 521 if (hwtype == -1) 522 hwtype = dlpi_arptype(dlinfo.di_mactype); 523 } 524 } 525 if (hwtype == -1) 526 goto failed; 527 *hwret = htons(hwtype); 528 return (maclen); 529 530 failed: 531 *ierrnop = ITAB_BAD_NUMBER; 532 return (-1); 533 } 534 535 /* 536 * inittab_encode_e(): converts a string representation of a given datatype into 537 * binary; used for encoding ascii values into a form that 538 * can be put in DHCP packets to be sent on the wire. 539 * 540 * input: const dhcp_symbol_t *: the entry describing the value option 541 * const char *: the value to convert 542 * uint16_t *: set to the length of the binary data returned 543 * boolean_t: if false, return a full DHCP option 544 * int *: error return value 545 * output: uchar_t *: a dynamically allocated byte array with converted data 546 */ 547 548 uchar_t * 549 inittab_encode_e(const dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, 550 boolean_t just_payload, int *ierrnop) 551 { 552 int hlen = 0; 553 uint16_t length; 554 uchar_t n_entries = 0; 555 const char *valuep; 556 char *currp; 557 uchar_t *result = NULL; 558 uchar_t *optstart; 559 unsigned int i; 560 uint8_t type_size = inittab_type_to_size(ie); 561 boolean_t is_signed; 562 uint_t vallen, reslen; 563 dhcpv6_option_t *d6o; 564 int type; 565 char *cp2; 566 567 *ierrnop = 0; 568 if (type_size == 0) { 569 *ierrnop = ITAB_SYNTAX_ERROR; 570 return (NULL); 571 } 572 573 switch (ie->ds_type) { 574 case DSYM_ASCII: 575 n_entries = strlen(value); /* no NUL */ 576 break; 577 578 case DSYM_OCTET: 579 vallen = strlen(value); 580 n_entries = vallen / 2; 581 n_entries += vallen % 2; 582 break; 583 584 case DSYM_DOMAIN: 585 /* 586 * Maximum (worst-case) encoded length is one byte more than 587 * the number of characters on input. 588 */ 589 n_entries = strlen(value) + 1; 590 break; 591 592 case DSYM_DUID: 593 /* Worst case is ":::::" */ 594 n_entries = strlen(value); 595 if (n_entries < DLPI_PHYSADDR_MAX) 596 n_entries = DLPI_PHYSADDR_MAX; 597 n_entries += sizeof (duid_llt_t); 598 break; 599 600 default: 601 /* 602 * figure out the number of entries by counting the spaces 603 * in the value string 604 */ 605 for (valuep = value; valuep++ != NULL; n_entries++) 606 valuep = strchr(valuep, ' '); 607 break; 608 } 609 610 /* 611 * if we're gonna return a complete option, then include the 612 * option length and code in the size of the packet we allocate 613 */ 614 if (!just_payload) 615 hlen = ie->ds_dhcpv6 ? sizeof (*d6o) : 2; 616 617 length = n_entries * type_size; 618 if (hlen + length > 0) 619 result = malloc(hlen + length); 620 621 if ((optstart = result) != NULL && !just_payload) 622 optstart += hlen; 623 624 switch (ie->ds_type) { 625 626 case DSYM_ASCII: 627 628 if (optstart == NULL) { 629 *ierrnop = ITAB_NOMEM; 630 return (NULL); 631 } 632 633 (void) memcpy(optstart, value, length); 634 break; 635 636 case DSYM_DOMAIN: 637 if (optstart == NULL) { 638 *ierrnop = ITAB_NOMEM; 639 return (NULL); 640 } 641 642 /* 643 * Note that this encoder always presents the trailing 0-octet 644 * when dealing with a list. This means that you can't have 645 * non-fully-qualified members anywhere but at the end of a 646 * list (or as the only member of the list). 647 */ 648 valuep = value; 649 while (*valuep != '\0') { 650 int dig, val, inchr; 651 boolean_t escape; 652 uchar_t *flen; 653 654 /* 655 * Skip over whitespace that delimits list members. 656 */ 657 if (isascii(*valuep) && isspace(*valuep)) { 658 valuep++; 659 continue; 660 } 661 dig = val = 0; 662 escape = B_FALSE; 663 flen = optstart++; 664 while ((inchr = *valuep) != '\0') { 665 valuep++; 666 /* 667 * Just copy non-ASCII text directly to the 668 * output string. This simplifies the use of 669 * other ctype macros below, as, unlike the 670 * special isascii function, they don't handle 671 * non-ASCII. 672 */ 673 if (!isascii(inchr)) { 674 escape = B_FALSE; 675 *optstart++ = inchr; 676 continue; 677 } 678 if (escape) { 679 /* 680 * Handle any of \D, \DD, or \DDD for 681 * a digit escape. 682 */ 683 if (isdigit(inchr)) { 684 val = val * 10 + inchr - '0'; 685 if (++dig == 3) { 686 *optstart++ = val; 687 dig = val = 0; 688 escape = B_FALSE; 689 } 690 continue; 691 } else if (dig > 0) { 692 /* 693 * User terminated \D or \DD 694 * with non-digit. An error, 695 * but we can assume he means 696 * to treat as \00D or \0DD. 697 */ 698 *optstart++ = val; 699 dig = val = 0; 700 } 701 /* Fall through and copy character */ 702 escape = B_FALSE; 703 } else if (inchr == '\\') { 704 escape = B_TRUE; 705 continue; 706 } else if (inchr == '.') { 707 /* 708 * End of component. Write the length 709 * prefix. If the component is zero 710 * length (i.e., ".."), the just omit 711 * it. 712 */ 713 *flen = (optstart - flen) - 1; 714 if (*flen > 0) 715 flen = optstart++; 716 continue; 717 } else if (isspace(inchr)) { 718 /* 719 * Unescaped space; end of domain name 720 * in list. 721 */ 722 break; 723 } 724 *optstart++ = inchr; 725 } 726 /* 727 * Handle trailing escape sequence. If string ends 728 * with \, then assume user wants \ at end of encoded 729 * string. If it ends with \D or \DD, assume \00D or 730 * \0DD. 731 */ 732 if (escape) 733 *optstart++ = dig > 0 ? val : '\\'; 734 *flen = (optstart - flen) - 1; 735 /* 736 * If user specified FQDN with trailing '.', then above 737 * will result in zero for the last component length. 738 * We're done, and optstart already points to the start 739 * of the next in list. Otherwise, we need to write a 740 * single zero byte to end the entry, if there are more 741 * entries that will be decoded. 742 */ 743 while (isascii(*valuep) && isspace(*valuep)) 744 valuep++; 745 if (*flen > 0 && *valuep != '\0') 746 *optstart++ = '\0'; 747 } 748 length = (optstart - result) - hlen; 749 break; 750 751 case DSYM_DUID: 752 if (optstart == NULL) { 753 *ierrnop = ITAB_NOMEM; 754 return (NULL); 755 } 756 757 errno = 0; 758 type = strtoul(value, &currp, 0); 759 if (errno != 0 || value == currp || type > 65535 || 760 (*currp != ',' && *currp != '\0')) { 761 free(result); 762 *ierrnop = ITAB_BAD_NUMBER; 763 return (NULL); 764 } 765 switch (type) { 766 case DHCPV6_DUID_LLT: { 767 duid_llt_t dllt; 768 int hwtype; 769 ulong_t tstamp; 770 int maclen; 771 772 if ((hwtype = get_hw_type(&currp, ierrnop)) == -2) { 773 free(result); 774 return (NULL); 775 } 776 if (*currp++ != ',') { 777 free(result); 778 *ierrnop = ITAB_BAD_NUMBER; 779 return (NULL); 780 } 781 if (*currp == ',' || *currp == '\0') { 782 tstamp = time(NULL) - DUID_TIME_BASE; 783 } else { 784 tstamp = strtoul(currp, &cp2, 0); 785 if (errno != 0 || currp == cp2) { 786 free(result); 787 *ierrnop = ITAB_BAD_NUMBER; 788 return (NULL); 789 } 790 currp = cp2; 791 } 792 maclen = get_mac_addr(currp, ierrnop, 793 &dllt.dllt_hwtype, hwtype, 794 optstart + sizeof (dllt)); 795 if (maclen == -1) { 796 free(result); 797 return (NULL); 798 } 799 dllt.dllt_dutype = htons(type); 800 dllt.dllt_time = htonl(tstamp); 801 (void) memcpy(optstart, &dllt, sizeof (dllt)); 802 length = maclen + sizeof (dllt); 803 break; 804 } 805 case DHCPV6_DUID_EN: { 806 duid_en_t den; 807 ulong_t enterp; 808 809 if (*currp++ != ',') { 810 free(result); 811 *ierrnop = ITAB_BAD_NUMBER; 812 return (NULL); 813 } 814 enterp = strtoul(currp, &cp2, 0); 815 DHCPV6_SET_ENTNUM(&den, enterp); 816 if (errno != 0 || currp == cp2 || 817 enterp != DHCPV6_GET_ENTNUM(&den) || 818 (*cp2 != ',' && *cp2 != '\0')) { 819 free(result); 820 *ierrnop = ITAB_BAD_NUMBER; 821 return (NULL); 822 } 823 if (*cp2 == ',') 824 cp2++; 825 vallen = strlen(cp2); 826 reslen = (vallen + 1) / 2; 827 if (hexascii_to_octet(cp2, vallen, 828 optstart + sizeof (den), &reslen) != 0) { 829 free(result); 830 *ierrnop = ITAB_BAD_NUMBER; 831 return (NULL); 832 } 833 den.den_dutype = htons(type); 834 (void) memcpy(optstart, &den, sizeof (den)); 835 length = reslen + sizeof (den); 836 break; 837 } 838 case DHCPV6_DUID_LL: { 839 duid_ll_t dll; 840 int hwtype; 841 int maclen; 842 843 if ((hwtype = get_hw_type(&currp, ierrnop)) == -2) { 844 free(result); 845 return (NULL); 846 } 847 maclen = get_mac_addr(currp, ierrnop, &dll.dll_hwtype, 848 hwtype, optstart + sizeof (dll)); 849 if (maclen == -1) { 850 free(result); 851 return (NULL); 852 } 853 dll.dll_dutype = htons(type); 854 (void) memcpy(optstart, &dll, sizeof (dll)); 855 length = maclen + sizeof (dll); 856 break; 857 } 858 default: 859 if (*currp == ',') 860 currp++; 861 vallen = strlen(currp); 862 reslen = (vallen + 1) / 2; 863 if (hexascii_to_octet(currp, vallen, optstart + 2, 864 &reslen) != 0) { 865 free(result); 866 *ierrnop = ITAB_BAD_NUMBER; 867 return (NULL); 868 } 869 optstart[0] = type >> 8; 870 optstart[1] = type; 871 length = reslen + 2; 872 break; 873 } 874 break; 875 876 case DSYM_OCTET: 877 878 if (optstart == NULL) { 879 *ierrnop = ITAB_BAD_OCTET; 880 return (NULL); 881 } 882 883 reslen = length; 884 /* Call libinetutil function to decode */ 885 if (hexascii_to_octet(value, vallen, optstart, &reslen) != 0) { 886 free(result); 887 *ierrnop = ITAB_BAD_OCTET; 888 return (NULL); 889 } 890 break; 891 892 case DSYM_IP: 893 case DSYM_IPV6: 894 895 if (optstart == NULL) { 896 *ierrnop = ITAB_BAD_IPADDR; 897 return (NULL); 898 } 899 if (n_entries % ie->ds_gran != 0) { 900 *ierrnop = ITAB_BAD_GRAN; 901 inittab_msg("inittab_encode: number of entries " 902 "not compatible with option granularity"); 903 free(result); 904 return (NULL); 905 } 906 907 for (valuep = value, i = 0; i < n_entries; i++, valuep++) { 908 909 currp = strchr(valuep, ' '); 910 if (currp != NULL) 911 *currp = '\0'; 912 if (inet_pton(ie->ds_type == DSYM_IP ? AF_INET : 913 AF_INET6, valuep, optstart) != 1) { 914 *ierrnop = ITAB_BAD_IPADDR; 915 inittab_msg("inittab_encode: bogus ip address"); 916 free(result); 917 return (NULL); 918 } 919 920 valuep = currp; 921 if (valuep == NULL) { 922 if (i < (n_entries - 1)) { 923 *ierrnop = ITAB_NOT_ENOUGH_IP; 924 inittab_msg("inittab_encode: too few " 925 "ip addresses"); 926 free(result); 927 return (NULL); 928 } 929 break; 930 } 931 optstart += type_size; 932 } 933 break; 934 935 case DSYM_NUMBER: /* FALLTHRU */ 936 case DSYM_UNUMBER8: /* FALLTHRU */ 937 case DSYM_SNUMBER8: /* FALLTHRU */ 938 case DSYM_UNUMBER16: /* FALLTHRU */ 939 case DSYM_SNUMBER16: /* FALLTHRU */ 940 case DSYM_UNUMBER24: /* FALLTHRU */ 941 case DSYM_UNUMBER32: /* FALLTHRU */ 942 case DSYM_SNUMBER32: /* FALLTHRU */ 943 case DSYM_UNUMBER64: /* FALLTHRU */ 944 case DSYM_SNUMBER64: 945 946 if (optstart == NULL) { 947 *ierrnop = ITAB_BAD_NUMBER; 948 return (NULL); 949 } 950 951 is_signed = (ie->ds_type == DSYM_SNUMBER64 || 952 ie->ds_type == DSYM_SNUMBER32 || 953 ie->ds_type == DSYM_SNUMBER16 || 954 ie->ds_type == DSYM_SNUMBER8); 955 956 if (encode_number(n_entries, type_size, is_signed, 0, value, 957 optstart, ierrnop) == B_FALSE) { 958 free(result); 959 return (NULL); 960 } 961 break; 962 963 default: 964 if (ie->ds_type == DSYM_BOOL) 965 *ierrnop = ITAB_BAD_BOOLEAN; 966 else 967 *ierrnop = ITAB_SYNTAX_ERROR; 968 969 inittab_msg("inittab_encode: unsupported type `%d'", 970 ie->ds_type); 971 972 free(result); 973 return (NULL); 974 } 975 976 /* 977 * if just_payload is false, then we need to add the option 978 * code and length fields in. 979 */ 980 if (!just_payload) { 981 if (ie->ds_dhcpv6) { 982 /* LINTED: alignment */ 983 d6o = (dhcpv6_option_t *)result; 984 d6o->d6o_code = htons(ie->ds_code); 985 d6o->d6o_len = htons(length); 986 } else { 987 result[0] = ie->ds_code; 988 result[1] = length; 989 } 990 } 991 992 if (lengthp != NULL) 993 *lengthp = length + hlen; 994 995 return (result); 996 } 997 998 /* 999 * inittab_decode_e(): converts a binary representation of a given datatype into 1000 * a string; used for decoding DHCP options in a packet off 1001 * the wire into ascii 1002 * 1003 * input: dhcp_symbol_t *: the entry describing the payload option 1004 * uchar_t *: the payload to convert 1005 * uint16_t: the payload length (only used if just_payload is true) 1006 * boolean_t: if false, payload is assumed to be a DHCP option 1007 * int *: set to extended error code if error occurs. 1008 * output: char *: a dynamically allocated string containing the converted data 1009 */ 1010 1011 char * 1012 inittab_decode_e(const dhcp_symbol_t *ie, const uchar_t *payload, 1013 uint16_t length, boolean_t just_payload, int *ierrnop) 1014 { 1015 char *resultp, *result = NULL; 1016 uint_t n_entries; 1017 struct in_addr in_addr; 1018 in6_addr_t in6_addr; 1019 uint8_t type_size = inittab_type_to_size(ie); 1020 boolean_t is_signed; 1021 int type; 1022 1023 *ierrnop = 0; 1024 if (type_size == 0) { 1025 *ierrnop = ITAB_SYNTAX_ERROR; 1026 return (NULL); 1027 } 1028 1029 if (!just_payload) { 1030 if (ie->ds_dhcpv6) { 1031 dhcpv6_option_t d6o; 1032 1033 (void) memcpy(&d6o, payload, sizeof (d6o)); 1034 length = ntohs(d6o.d6o_len); 1035 payload += sizeof (d6o); 1036 } else { 1037 length = payload[1]; 1038 payload += 2; 1039 } 1040 } 1041 1042 /* 1043 * figure out the number of elements to convert. note that 1044 * for ds_type NUMBER, the granularity is really 1 since the 1045 * value of ds_gran is the number of bytes in the number. 1046 */ 1047 if (ie->ds_type == DSYM_NUMBER) 1048 n_entries = MIN(ie->ds_max, length / type_size); 1049 else 1050 n_entries = MIN(ie->ds_max * ie->ds_gran, length / type_size); 1051 1052 if (n_entries == 0) 1053 n_entries = length / type_size; 1054 1055 if ((length % type_size) != 0) { 1056 inittab_msg("inittab_decode: length of string not compatible " 1057 "with option type `%i'", ie->ds_type); 1058 *ierrnop = ITAB_BAD_STRING; 1059 return (NULL); 1060 } 1061 1062 switch (ie->ds_type) { 1063 1064 case DSYM_ASCII: 1065 1066 result = malloc(n_entries + 1); 1067 if (result == NULL) { 1068 *ierrnop = ITAB_NOMEM; 1069 return (NULL); 1070 } 1071 1072 (void) memcpy(result, payload, n_entries); 1073 result[n_entries] = '\0'; 1074 break; 1075 1076 case DSYM_DOMAIN: 1077 1078 /* 1079 * A valid, decoded RFC 1035 domain string or sequence of 1080 * strings is always the same size as the encoded form, but we 1081 * allow for RFC 1035 \DDD and \\ and \. escaping. 1082 * 1083 * Decoding stops at the end of the input or the first coding 1084 * violation. Coding violations result in discarding the 1085 * offending list entry entirely. Note that we ignore the 255 1086 * character overall limit on domain names. 1087 */ 1088 if ((result = malloc(4 * length + 1)) == NULL) { 1089 *ierrnop = ITAB_NOMEM; 1090 return (NULL); 1091 } 1092 resultp = result; 1093 while (length > 0) { 1094 char *dstart; 1095 int slen; 1096 1097 dstart = resultp; 1098 while (length > 0) { 1099 slen = *payload++; 1100 length--; 1101 /* Upper two bits of length must be zero */ 1102 if ((slen & 0xc0) != 0 || slen > length) { 1103 length = 0; 1104 resultp = dstart; 1105 break; 1106 } 1107 if (resultp != dstart) 1108 *resultp++ = '.'; 1109 if (slen == 0) 1110 break; 1111 length -= slen; 1112 while (slen > 0) { 1113 if (!isascii(*payload) || 1114 !isgraph(*payload)) { 1115 (void) snprintf(resultp, 5, 1116 "\\%03d", 1117 *(unsigned char *)payload); 1118 resultp += 4; 1119 payload++; 1120 } else { 1121 if (*payload == '.' || 1122 *payload == '\\') 1123 *resultp++ = '\\'; 1124 *resultp++ = *payload++; 1125 } 1126 slen--; 1127 } 1128 } 1129 if (resultp != dstart && length > 0) 1130 *resultp++ = ' '; 1131 } 1132 *resultp = '\0'; 1133 break; 1134 1135 case DSYM_DUID: 1136 1137 /* 1138 * First, determine the type of DUID. We need at least two 1139 * octets worth of data to grab the type code. Once we have 1140 * that, the number of octets required for representation 1141 * depends on the type. 1142 */ 1143 1144 if (length < 2) { 1145 *ierrnop = ITAB_BAD_GRAN; 1146 return (NULL); 1147 } 1148 type = (payload[0] << 8) + payload[1]; 1149 switch (type) { 1150 case DHCPV6_DUID_LLT: { 1151 duid_llt_t dllt; 1152 1153 if (length < sizeof (dllt)) { 1154 *ierrnop = ITAB_BAD_GRAN; 1155 return (NULL); 1156 } 1157 (void) memcpy(&dllt, payload, sizeof (dllt)); 1158 payload += sizeof (dllt); 1159 length -= sizeof (dllt); 1160 n_entries = sizeof ("1,65535,4294967295,") + 1161 length * 3; 1162 if ((result = malloc(n_entries)) == NULL) { 1163 *ierrnop = ITAB_NOMEM; 1164 return (NULL); 1165 } 1166 (void) snprintf(result, n_entries, "%d,%u,%u,", type, 1167 ntohs(dllt.dllt_hwtype), ntohl(dllt.dllt_time)); 1168 break; 1169 } 1170 case DHCPV6_DUID_EN: { 1171 duid_en_t den; 1172 1173 if (length < sizeof (den)) { 1174 *ierrnop = ITAB_BAD_GRAN; 1175 return (NULL); 1176 } 1177 (void) memcpy(&den, payload, sizeof (den)); 1178 payload += sizeof (den); 1179 length -= sizeof (den); 1180 n_entries = sizeof ("2,4294967295,") + length * 2; 1181 if ((result = malloc(n_entries)) == NULL) { 1182 *ierrnop = ITAB_NOMEM; 1183 return (NULL); 1184 } 1185 (void) snprintf(result, n_entries, "%d,%u,", type, 1186 DHCPV6_GET_ENTNUM(&den)); 1187 break; 1188 } 1189 case DHCPV6_DUID_LL: { 1190 duid_ll_t dll; 1191 1192 if (length < sizeof (dll)) { 1193 *ierrnop = ITAB_BAD_GRAN; 1194 return (NULL); 1195 } 1196 (void) memcpy(&dll, payload, sizeof (dll)); 1197 payload += sizeof (dll); 1198 length -= sizeof (dll); 1199 n_entries = sizeof ("3,65535,") + length * 3; 1200 if ((result = malloc(n_entries)) == NULL) { 1201 *ierrnop = ITAB_NOMEM; 1202 return (NULL); 1203 } 1204 (void) snprintf(result, n_entries, "%d,%u,", type, 1205 ntohs(dll.dll_hwtype)); 1206 break; 1207 } 1208 default: 1209 n_entries = sizeof ("0,") + length * 2; 1210 if ((result = malloc(n_entries)) == NULL) { 1211 *ierrnop = ITAB_NOMEM; 1212 return (NULL); 1213 } 1214 (void) snprintf(result, n_entries, "%d,", type); 1215 break; 1216 } 1217 resultp = result + strlen(result); 1218 n_entries -= strlen(result); 1219 if (type == DHCPV6_DUID_LLT || type == DHCPV6_DUID_LL) { 1220 if (length > 0) { 1221 resultp += snprintf(resultp, 3, "%02X", 1222 *payload++); 1223 length--; 1224 } 1225 while (length-- > 0) { 1226 resultp += snprintf(resultp, 4, ":%02X", 1227 *payload++); 1228 } 1229 } else { 1230 while (length-- > 0) { 1231 resultp += snprintf(resultp, 3, "%02X", 1232 *payload++); 1233 } 1234 } 1235 break; 1236 1237 case DSYM_OCTET: 1238 1239 result = malloc(n_entries * (sizeof ("0xNN") + 1)); 1240 if (result == NULL) { 1241 *ierrnop = ITAB_NOMEM; 1242 return (NULL); 1243 } 1244 1245 result[0] = '\0'; 1246 resultp = result; 1247 if (n_entries > 0) { 1248 resultp += sprintf(resultp, "0x%02X", *payload++); 1249 n_entries--; 1250 } 1251 while (n_entries-- > 0) 1252 resultp += sprintf(resultp, " 0x%02X", *payload++); 1253 1254 break; 1255 1256 case DSYM_IP: 1257 case DSYM_IPV6: 1258 if ((length / type_size) % ie->ds_gran != 0) { 1259 *ierrnop = ITAB_BAD_GRAN; 1260 inittab_msg("inittab_decode: number of entries " 1261 "not compatible with option granularity"); 1262 return (NULL); 1263 } 1264 1265 result = malloc(n_entries * (ie->ds_type == DSYM_IP ? 1266 INET_ADDRSTRLEN : INET6_ADDRSTRLEN)); 1267 if (result == NULL) { 1268 *ierrnop = ITAB_NOMEM; 1269 return (NULL); 1270 } 1271 1272 for (resultp = result; n_entries != 0; n_entries--) { 1273 if (ie->ds_type == DSYM_IP) { 1274 (void) memcpy(&in_addr.s_addr, payload, 1275 sizeof (ipaddr_t)); 1276 (void) strcpy(resultp, inet_ntoa(in_addr)); 1277 } else { 1278 (void) memcpy(&in6_addr, payload, 1279 sizeof (in6_addr)); 1280 (void) inet_ntop(AF_INET6, &in6_addr, resultp, 1281 INET6_ADDRSTRLEN); 1282 } 1283 resultp += strlen(resultp); 1284 if (n_entries > 1) 1285 *resultp++ = ' '; 1286 payload += type_size; 1287 } 1288 *resultp = '\0'; 1289 break; 1290 1291 case DSYM_NUMBER: /* FALLTHRU */ 1292 case DSYM_UNUMBER8: /* FALLTHRU */ 1293 case DSYM_SNUMBER8: /* FALLTHRU */ 1294 case DSYM_UNUMBER16: /* FALLTHRU */ 1295 case DSYM_SNUMBER16: /* FALLTHRU */ 1296 case DSYM_UNUMBER32: /* FALLTHRU */ 1297 case DSYM_SNUMBER32: /* FALLTHRU */ 1298 case DSYM_UNUMBER64: /* FALLTHRU */ 1299 case DSYM_SNUMBER64: 1300 1301 is_signed = (ie->ds_type == DSYM_SNUMBER64 || 1302 ie->ds_type == DSYM_SNUMBER32 || 1303 ie->ds_type == DSYM_SNUMBER16 || 1304 ie->ds_type == DSYM_SNUMBER8); 1305 1306 result = malloc(n_entries * ITAB_MAX_NUMBER_LEN); 1307 if (result == NULL) { 1308 *ierrnop = ITAB_NOMEM; 1309 return (NULL); 1310 } 1311 1312 if (decode_number(n_entries, type_size, is_signed, ie->ds_gran, 1313 payload, result, ierrnop) == B_FALSE) { 1314 free(result); 1315 return (NULL); 1316 } 1317 break; 1318 1319 default: 1320 inittab_msg("inittab_decode: unsupported type `%d'", 1321 ie->ds_type); 1322 break; 1323 } 1324 1325 return (result); 1326 } 1327 1328 /* 1329 * inittab_encode(): converts a string representation of a given datatype into 1330 * binary; used for encoding ascii values into a form that 1331 * can be put in DHCP packets to be sent on the wire. 1332 * 1333 * input: dhcp_symbol_t *: the entry describing the value option 1334 * const char *: the value to convert 1335 * uint16_t *: set to the length of the binary data returned 1336 * boolean_t: if false, return a full DHCP option 1337 * output: uchar_t *: a dynamically allocated byte array with converted data 1338 */ 1339 1340 uchar_t * 1341 inittab_encode(const dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, 1342 boolean_t just_payload) 1343 { 1344 int ierrno; 1345 1346 return (inittab_encode_e(ie, value, lengthp, just_payload, &ierrno)); 1347 } 1348 1349 /* 1350 * inittab_decode(): converts a binary representation of a given datatype into 1351 * a string; used for decoding DHCP options in a packet off 1352 * the wire into ascii 1353 * 1354 * input: dhcp_symbol_t *: the entry describing the payload option 1355 * uchar_t *: the payload to convert 1356 * uint16_t: the payload length (only used if just_payload is true) 1357 * boolean_t: if false, payload is assumed to be a DHCP option 1358 * output: char *: a dynamically allocated string containing the converted data 1359 */ 1360 1361 char * 1362 inittab_decode(const dhcp_symbol_t *ie, const uchar_t *payload, uint16_t length, 1363 boolean_t just_payload) 1364 { 1365 int ierrno; 1366 1367 return (inittab_decode_e(ie, payload, length, just_payload, &ierrno)); 1368 } 1369 1370 /* 1371 * inittab_msg(): prints diagnostic messages if INITTAB_DEBUG is set 1372 * 1373 * const char *: a printf-like format string 1374 * ...: arguments to the format string 1375 * output: void 1376 */ 1377 1378 /*PRINTFLIKE1*/ 1379 static void 1380 inittab_msg(const char *fmt, ...) 1381 { 1382 enum { INITTAB_MSG_CHECK, INITTAB_MSG_RETURN, INITTAB_MSG_OUTPUT }; 1383 1384 va_list ap; 1385 char buf[512]; 1386 static int action = INITTAB_MSG_CHECK; 1387 1388 /* 1389 * check DHCP_INITTAB_DEBUG the first time in; thereafter, use 1390 * the the cached result (stored in `action'). 1391 */ 1392 switch (action) { 1393 1394 case INITTAB_MSG_CHECK: 1395 1396 if (getenv("DHCP_INITTAB_DEBUG") == NULL) { 1397 action = INITTAB_MSG_RETURN; 1398 return; 1399 } 1400 1401 action = INITTAB_MSG_OUTPUT; 1402 1403 /* FALLTHRU into INITTAB_MSG_OUTPUT */ 1404 1405 case INITTAB_MSG_OUTPUT: 1406 1407 va_start(ap, fmt); 1408 1409 (void) snprintf(buf, sizeof (buf), "inittab: %s\n", fmt); 1410 (void) vfprintf(stderr, buf, ap); 1411 1412 va_end(ap); 1413 break; 1414 1415 case INITTAB_MSG_RETURN: 1416 1417 return; 1418 } 1419 } 1420 1421 /* 1422 * decode_number(): decodes a sequence of numbers from binary into ascii; 1423 * binary is coming off of the network, so it is in nbo 1424 * 1425 * input: uint8_t: the number of "granularity" numbers to decode 1426 * uint8_t: the length of each number 1427 * boolean_t: whether the numbers should be considered signed 1428 * uint8_t: the number of numbers per granularity 1429 * const uint8_t *: where to decode the numbers from 1430 * char *: where to decode the numbers to 1431 * output: boolean_t: true on successful conversion, false on failure 1432 */ 1433 1434 static boolean_t 1435 decode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed, 1436 uint8_t granularity, const uint8_t *from, char *to, int *ierrnop) 1437 { 1438 uint16_t uint16; 1439 uint32_t uint32; 1440 uint64_t uint64; 1441 1442 if (granularity != 0) { 1443 if ((granularity % n_entries) != 0) { 1444 inittab_msg("decode_number: number of entries " 1445 "not compatible with option granularity"); 1446 *ierrnop = ITAB_BAD_GRAN; 1447 return (B_FALSE); 1448 } 1449 } 1450 1451 for (; n_entries != 0; n_entries--, from += size) { 1452 1453 switch (size) { 1454 1455 case 1: 1456 to += sprintf(to, is_signed ? "%d" : "%u", *from); 1457 break; 1458 1459 case 2: 1460 (void) memcpy(&uint16, from, 2); 1461 to += sprintf(to, is_signed ? "%hd" : "%hu", 1462 ntohs(uint16)); 1463 break; 1464 1465 case 3: 1466 uint32 = 0; 1467 (void) memcpy((uchar_t *)&uint32 + 1, from, 3); 1468 to += sprintf(to, is_signed ? "%ld" : "%lu", 1469 ntohl(uint32)); 1470 break; 1471 1472 case 4: 1473 (void) memcpy(&uint32, from, 4); 1474 to += sprintf(to, is_signed ? "%ld" : "%lu", 1475 ntohl(uint32)); 1476 break; 1477 1478 case 8: 1479 (void) memcpy(&uint64, from, 8); 1480 to += sprintf(to, is_signed ? "%lld" : "%llu", 1481 dhcp_ntohll(uint64)); 1482 break; 1483 1484 default: 1485 *ierrnop = ITAB_BAD_NUMBER; 1486 inittab_msg("decode_number: unknown integer size `%d'", 1487 size); 1488 return (B_FALSE); 1489 } 1490 if (n_entries > 0) 1491 *to++ = ' '; 1492 } 1493 1494 *to = '\0'; 1495 return (B_TRUE); 1496 } 1497 1498 /* 1499 * encode_number(): encodes a sequence of numbers from ascii into binary; 1500 * number will end up on the wire so it needs to be in nbo 1501 * 1502 * input: uint8_t: the number of "granularity" numbers to encode 1503 * uint8_t: the length of each number 1504 * boolean_t: whether the numbers should be considered signed 1505 * uint8_t: the number of numbers per granularity 1506 * const uint8_t *: where to encode the numbers from 1507 * char *: where to encode the numbers to 1508 * int *: set to extended error code if error occurs. 1509 * output: boolean_t: true on successful conversion, false on failure 1510 */ 1511 1512 static boolean_t /* ARGSUSED */ 1513 encode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed, 1514 uint8_t granularity, const char *from, uint8_t *to, int *ierrnop) 1515 { 1516 uint8_t i; 1517 uint16_t uint16; 1518 uint32_t uint32; 1519 uint64_t uint64; 1520 char *endptr; 1521 1522 if (granularity != 0) { 1523 if ((granularity % n_entries) != 0) { 1524 *ierrnop = ITAB_BAD_GRAN; 1525 inittab_msg("encode_number: number of entries " 1526 "not compatible with option granularity"); 1527 return (B_FALSE); 1528 } 1529 } 1530 1531 for (i = 0; i < n_entries; i++, from++, to += size) { 1532 1533 /* 1534 * totally obscure c factoid: it is legal to pass a 1535 * string representing a negative number to strtoul(). 1536 * in this case, strtoul() will return an unsigned 1537 * long that if cast to a long, would represent the 1538 * negative number. we take advantage of this to 1539 * cut down on code here. 1540 */ 1541 1542 errno = 0; 1543 switch (size) { 1544 1545 case 1: 1546 *to = strtoul(from, &endptr, 0); 1547 if (errno != 0 || from == endptr) { 1548 goto error; 1549 } 1550 break; 1551 1552 case 2: 1553 uint16 = htons(strtoul(from, &endptr, 0)); 1554 if (errno != 0 || from == endptr) { 1555 goto error; 1556 } 1557 (void) memcpy(to, &uint16, 2); 1558 break; 1559 1560 case 3: 1561 uint32 = htonl(strtoul(from, &endptr, 0)); 1562 if (errno != 0 || from == endptr) { 1563 goto error; 1564 } 1565 (void) memcpy(to, (uchar_t *)&uint32 + 1, 3); 1566 break; 1567 1568 case 4: 1569 uint32 = htonl(strtoul(from, &endptr, 0)); 1570 if (errno != 0 || from == endptr) { 1571 goto error; 1572 } 1573 (void) memcpy(to, &uint32, 4); 1574 break; 1575 1576 case 8: 1577 uint64 = dhcp_htonll(strtoull(from, &endptr, 0)); 1578 if (errno != 0 || from == endptr) { 1579 goto error; 1580 } 1581 (void) memcpy(to, &uint64, 8); 1582 break; 1583 1584 default: 1585 inittab_msg("encode_number: unsupported integer " 1586 "size `%d'", size); 1587 return (B_FALSE); 1588 } 1589 1590 from = strchr(from, ' '); 1591 if (from == NULL) 1592 break; 1593 } 1594 1595 return (B_TRUE); 1596 1597 error: 1598 *ierrnop = ITAB_BAD_NUMBER; 1599 inittab_msg("encode_number: cannot convert to integer"); 1600 return (B_FALSE); 1601 } 1602 1603 /* 1604 * inittab_type_to_size(): given an inittab entry, returns size of one entry of 1605 * its type 1606 * 1607 * input: dhcp_symbol_t *: an entry of the given type 1608 * output: uint8_t: the size in bytes of an entry of that type 1609 */ 1610 1611 uint8_t 1612 inittab_type_to_size(const dhcp_symbol_t *ie) 1613 { 1614 switch (ie->ds_type) { 1615 1616 case DSYM_DUID: 1617 case DSYM_DOMAIN: 1618 case DSYM_ASCII: 1619 case DSYM_OCTET: 1620 case DSYM_SNUMBER8: 1621 case DSYM_UNUMBER8: 1622 1623 return (1); 1624 1625 case DSYM_SNUMBER16: 1626 case DSYM_UNUMBER16: 1627 1628 return (2); 1629 1630 case DSYM_UNUMBER24: 1631 1632 return (3); 1633 1634 case DSYM_SNUMBER32: 1635 case DSYM_UNUMBER32: 1636 case DSYM_IP: 1637 1638 return (4); 1639 1640 case DSYM_SNUMBER64: 1641 case DSYM_UNUMBER64: 1642 1643 return (8); 1644 1645 case DSYM_NUMBER: 1646 1647 return (ie->ds_gran); 1648 1649 case DSYM_IPV6: 1650 1651 return (sizeof (in6_addr_t)); 1652 } 1653 1654 return (0); 1655 } 1656 1657 /* 1658 * itabcode_to_dsymcode(): maps an inittab category code to its dsym 1659 * representation 1660 * 1661 * input: uchar_t: the inittab category code 1662 * output: dsym_category_t: the dsym category code 1663 */ 1664 1665 static dsym_category_t 1666 itabcode_to_dsymcode(uchar_t itabcode) 1667 { 1668 1669 unsigned int i; 1670 1671 for (i = 0; i < ITAB_CAT_COUNT; i++) 1672 if (category_map[i].cme_itabcode == itabcode) 1673 return (category_map[i].cme_dsymcode); 1674 1675 return (DSYM_BAD_CAT); 1676 } 1677 1678 /* 1679 * category_to_code(): maps a category name to its numeric representation 1680 * 1681 * input: const char *: the category name 1682 * output: uchar_t: its internal code (numeric representation) 1683 */ 1684 1685 static uchar_t 1686 category_to_code(const char *category) 1687 { 1688 unsigned int i; 1689 1690 for (i = 0; i < ITAB_CAT_COUNT; i++) 1691 if (strcasecmp(category_map[i].cme_name, category) == 0) 1692 return (category_map[i].cme_itabcode); 1693 1694 return (0); 1695 } 1696 1697 /* 1698 * dhcp_htonll(): converts a 64-bit number from host to network byte order 1699 * 1700 * input: uint64_t: the number to convert 1701 * output: uint64_t: its value in network byte order 1702 */ 1703 1704 static uint64_t 1705 dhcp_htonll(uint64_t uint64_hbo) 1706 { 1707 return (dhcp_ntohll(uint64_hbo)); 1708 } 1709 1710 /* 1711 * dhcp_ntohll(): converts a 64-bit number from network to host byte order 1712 * 1713 * input: uint64_t: the number to convert 1714 * output: uint64_t: its value in host byte order 1715 */ 1716 1717 static uint64_t 1718 dhcp_ntohll(uint64_t uint64_nbo) 1719 { 1720 #ifdef _LITTLE_ENDIAN 1721 return ((uint64_t)ntohl(uint64_nbo & 0xffffffff) << 32 | 1722 ntohl(uint64_nbo >> 32)); 1723 #else 1724 return (uint64_nbo); 1725 #endif 1726 } 1727 1728 /* 1729 * our internal table of DHCP option values, used by inittab_verify() 1730 */ 1731 static dhcp_symbol_t inittab_table[] = 1732 { 1733 { DSYM_INTERNAL, 1024, "Hostname", DSYM_BOOL, 0, 0 }, 1734 { DSYM_INTERNAL, 1025, "LeaseNeg", DSYM_BOOL, 0, 0 }, 1735 { DSYM_INTERNAL, 1026, "EchoVC", DSYM_BOOL, 0, 0 }, 1736 { DSYM_INTERNAL, 1027, "BootPath", DSYM_ASCII, 1, 128 }, 1737 { DSYM_FIELD, 0, "Opcode", DSYM_UNUMBER8, 1, 1 }, 1738 { DSYM_FIELD, 1, "Htype", DSYM_UNUMBER8, 1, 1 }, 1739 { DSYM_FIELD, 2, "HLen", DSYM_UNUMBER8, 1, 1 }, 1740 { DSYM_FIELD, 3, "Hops", DSYM_UNUMBER8, 1, 1 }, 1741 { DSYM_FIELD, 4, "Xid", DSYM_UNUMBER32, 1, 1 }, 1742 { DSYM_FIELD, 8, "Secs", DSYM_UNUMBER16, 1, 1 }, 1743 { DSYM_FIELD, 10, "Flags", DSYM_OCTET, 1, 2 }, 1744 { DSYM_FIELD, 12, "Ciaddr", DSYM_IP, 1, 1 }, 1745 { DSYM_FIELD, 16, "Yiaddr", DSYM_IP, 1, 1 }, 1746 { DSYM_FIELD, 20, "BootSrvA", DSYM_IP, 1, 1 }, 1747 { DSYM_FIELD, 24, "Giaddr", DSYM_IP, 1, 1 }, 1748 { DSYM_FIELD, 28, "Chaddr", DSYM_OCTET, 1, 16 }, 1749 { DSYM_FIELD, 44, "BootSrvN", DSYM_ASCII, 1, 64 }, 1750 { DSYM_FIELD, 108, "BootFile", DSYM_ASCII, 1, 128 }, 1751 { DSYM_FIELD, 236, "Magic", DSYM_OCTET, 1, 4 }, 1752 { DSYM_FIELD, 240, "Options", DSYM_OCTET, 1, 60 }, 1753 { DSYM_STANDARD, 1, "Subnet", DSYM_IP, 1, 1 }, 1754 { DSYM_STANDARD, 2, "UTCoffst", DSYM_SNUMBER32, 1, 1 }, 1755 { DSYM_STANDARD, 3, "Router", DSYM_IP, 1, 0 }, 1756 { DSYM_STANDARD, 4, "Timeserv", DSYM_IP, 1, 0 }, 1757 { DSYM_STANDARD, 5, "IEN116ns", DSYM_IP, 1, 0 }, 1758 { DSYM_STANDARD, 6, "DNSserv", DSYM_IP, 1, 0 }, 1759 { DSYM_STANDARD, 7, "Logserv", DSYM_IP, 1, 0 }, 1760 { DSYM_STANDARD, 8, "Cookie", DSYM_IP, 1, 0 }, 1761 { DSYM_STANDARD, 9, "Lprserv", DSYM_IP, 1, 0 }, 1762 { DSYM_STANDARD, 10, "Impress", DSYM_IP, 1, 0 }, 1763 { DSYM_STANDARD, 11, "Resource", DSYM_IP, 1, 0 }, 1764 { DSYM_STANDARD, 12, "Hostname", DSYM_ASCII, 1, 0 }, 1765 { DSYM_STANDARD, 13, "Bootsize", DSYM_UNUMBER16, 1, 1 }, 1766 { DSYM_STANDARD, 14, "Dumpfile", DSYM_ASCII, 1, 0 }, 1767 { DSYM_STANDARD, 15, "DNSdmain", DSYM_ASCII, 1, 0 }, 1768 { DSYM_STANDARD, 16, "Swapserv", DSYM_IP, 1, 1 }, 1769 { DSYM_STANDARD, 17, "Rootpath", DSYM_ASCII, 1, 0 }, 1770 { DSYM_STANDARD, 18, "ExtendP", DSYM_ASCII, 1, 0 }, 1771 { DSYM_STANDARD, 19, "IpFwdF", DSYM_UNUMBER8, 1, 1 }, 1772 { DSYM_STANDARD, 20, "NLrouteF", DSYM_UNUMBER8, 1, 1 }, 1773 { DSYM_STANDARD, 21, "PFilter", DSYM_IP, 2, 0 }, 1774 { DSYM_STANDARD, 22, "MaxIpSiz", DSYM_UNUMBER16, 1, 1 }, 1775 { DSYM_STANDARD, 23, "IpTTL", DSYM_UNUMBER8, 1, 1 }, 1776 { DSYM_STANDARD, 24, "PathTO", DSYM_UNUMBER32, 1, 1 }, 1777 { DSYM_STANDARD, 25, "PathTbl", DSYM_UNUMBER16, 1, 0 }, 1778 { DSYM_STANDARD, 26, "MTU", DSYM_UNUMBER16, 1, 1 }, 1779 { DSYM_STANDARD, 27, "SameMtuF", DSYM_UNUMBER8, 1, 1 }, 1780 { DSYM_STANDARD, 28, "Broadcst", DSYM_IP, 1, 1 }, 1781 { DSYM_STANDARD, 29, "MaskDscF", DSYM_UNUMBER8, 1, 1 }, 1782 { DSYM_STANDARD, 30, "MaskSupF", DSYM_UNUMBER8, 1, 1 }, 1783 { DSYM_STANDARD, 31, "RDiscvyF", DSYM_UNUMBER8, 1, 1 }, 1784 { DSYM_STANDARD, 32, "RSolictS", DSYM_IP, 1, 1 }, 1785 { DSYM_STANDARD, 33, "StaticRt", DSYM_IP, 2, 0 }, 1786 { DSYM_STANDARD, 34, "TrailerF", DSYM_UNUMBER8, 1, 1 }, 1787 { DSYM_STANDARD, 35, "ArpTimeO", DSYM_UNUMBER32, 1, 1 }, 1788 { DSYM_STANDARD, 36, "EthEncap", DSYM_UNUMBER8, 1, 1 }, 1789 { DSYM_STANDARD, 37, "TcpTTL", DSYM_UNUMBER8, 1, 1 }, 1790 { DSYM_STANDARD, 38, "TcpKaInt", DSYM_UNUMBER32, 1, 1 }, 1791 { DSYM_STANDARD, 39, "TcpKaGbF", DSYM_UNUMBER8, 1, 1 }, 1792 { DSYM_STANDARD, 40, "NISdmain", DSYM_ASCII, 1, 0 }, 1793 { DSYM_STANDARD, 41, "NISservs", DSYM_IP, 1, 0 }, 1794 { DSYM_STANDARD, 42, "NTPservs", DSYM_IP, 1, 0 }, 1795 { DSYM_STANDARD, 43, "Vendor", DSYM_OCTET, 1, 0 }, 1796 { DSYM_STANDARD, 44, "NetBNms", DSYM_IP, 1, 0 }, 1797 { DSYM_STANDARD, 45, "NetBDsts", DSYM_IP, 1, 0 }, 1798 { DSYM_STANDARD, 46, "NetBNdT", DSYM_UNUMBER8, 1, 1 }, 1799 { DSYM_STANDARD, 47, "NetBScop", DSYM_ASCII, 1, 0 }, 1800 { DSYM_STANDARD, 48, "XFontSrv", DSYM_IP, 1, 0 }, 1801 { DSYM_STANDARD, 49, "XDispMgr", DSYM_IP, 1, 0 }, 1802 { DSYM_STANDARD, 50, "ReqIP", DSYM_IP, 1, 1 }, 1803 { DSYM_STANDARD, 51, "LeaseTim", DSYM_UNUMBER32, 1, 1 }, 1804 { DSYM_STANDARD, 52, "OptOvrld", DSYM_UNUMBER8, 1, 1 }, 1805 { DSYM_STANDARD, 53, "DHCPType", DSYM_UNUMBER8, 1, 1 }, 1806 { DSYM_STANDARD, 54, "ServerID", DSYM_IP, 1, 1 }, 1807 { DSYM_STANDARD, 55, "ReqList", DSYM_OCTET, 1, 0 }, 1808 { DSYM_STANDARD, 56, "Message", DSYM_ASCII, 1, 0 }, 1809 { DSYM_STANDARD, 57, "DHCP_MTU", DSYM_UNUMBER16, 1, 1 }, 1810 { DSYM_STANDARD, 58, "T1Time", DSYM_UNUMBER32, 1, 1 }, 1811 { DSYM_STANDARD, 59, "T2Time", DSYM_UNUMBER32, 1, 1 }, 1812 { DSYM_STANDARD, 60, "ClassID", DSYM_ASCII, 1, 0 }, 1813 { DSYM_STANDARD, 61, "ClientID", DSYM_OCTET, 1, 0 }, 1814 { DSYM_STANDARD, 62, "NW_dmain", DSYM_ASCII, 1, 0 }, 1815 { DSYM_STANDARD, 63, "NWIPOpts", DSYM_OCTET, 1, 128 }, 1816 { DSYM_STANDARD, 64, "NIS+dom", DSYM_ASCII, 1, 0 }, 1817 { DSYM_STANDARD, 65, "NIS+serv", DSYM_IP, 1, 0 }, 1818 { DSYM_STANDARD, 66, "TFTPsrvN", DSYM_ASCII, 1, 64 }, 1819 { DSYM_STANDARD, 67, "OptBootF", DSYM_ASCII, 1, 128 }, 1820 { DSYM_STANDARD, 68, "MblIPAgt", DSYM_IP, 1, 0 }, 1821 { DSYM_STANDARD, 69, "SMTPserv", DSYM_IP, 1, 0 }, 1822 { DSYM_STANDARD, 70, "POP3serv", DSYM_IP, 1, 0 }, 1823 { DSYM_STANDARD, 71, "NNTPserv", DSYM_IP, 1, 0 }, 1824 { DSYM_STANDARD, 72, "WWWservs", DSYM_IP, 1, 0 }, 1825 { DSYM_STANDARD, 73, "Fingersv", DSYM_IP, 1, 0 }, 1826 { DSYM_STANDARD, 74, "IRCservs", DSYM_IP, 1, 0 }, 1827 { DSYM_STANDARD, 75, "STservs", DSYM_IP, 1, 0 }, 1828 { DSYM_STANDARD, 76, "STDAservs", DSYM_IP, 1, 0 }, 1829 { DSYM_STANDARD, 77, "UserClas", DSYM_ASCII, 1, 0 }, 1830 { DSYM_STANDARD, 78, "SLP_DA", DSYM_OCTET, 1, 0 }, 1831 { DSYM_STANDARD, 79, "SLP_SS", DSYM_OCTET, 1, 0 }, 1832 { DSYM_STANDARD, 82, "AgentOpt", DSYM_OCTET, 1, 0 }, 1833 { DSYM_STANDARD, 89, "FQDN", DSYM_OCTET, 1, 0 }, 1834 { 0, 0, "", 0, 0, 0 } 1835 }; 1836