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