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