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_bind(dh, DLPI_ANY_SAP, NULL) != 511 DLPI_SUCCESS || dlpi_info(dh, &dlinfo, 0) != 512 DLPI_SUCCESS) { 513 dlpi_close(dh); 514 goto failed; 515 } 516 maclen = dlinfo.di_physaddrlen; 517 (void) memcpy(outbuf, dlinfo.di_physaddr, maclen); 518 dlpi_close(dh); 519 if (hwtype == -1) 520 hwtype = dlpi_arptype(dlinfo.di_mactype); 521 } 522 } 523 if (hwtype == -1) 524 goto failed; 525 *hwret = htons(hwtype); 526 return (maclen); 527 528 failed: 529 *ierrnop = ITAB_BAD_NUMBER; 530 return (-1); 531 } 532 533 /* 534 * inittab_encode_e(): converts a string representation of a given datatype into 535 * binary; used for encoding ascii values into a form that 536 * can be put in DHCP packets to be sent on the wire. 537 * 538 * input: const dhcp_symbol_t *: the entry describing the value option 539 * const char *: the value to convert 540 * uint16_t *: set to the length of the binary data returned 541 * boolean_t: if false, return a full DHCP option 542 * int *: error return value 543 * output: uchar_t *: a dynamically allocated byte array with converted data 544 */ 545 546 uchar_t * 547 inittab_encode_e(const dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, 548 boolean_t just_payload, int *ierrnop) 549 { 550 int hlen = 0; 551 uint16_t length; 552 uchar_t n_entries = 0; 553 const char *valuep; 554 char *currp; 555 uchar_t *result = NULL; 556 uchar_t *optstart; 557 unsigned int i; 558 uint8_t type_size = inittab_type_to_size(ie); 559 boolean_t is_signed; 560 uint_t vallen, reslen; 561 dhcpv6_option_t *d6o; 562 int type; 563 char *cp2; 564 565 *ierrnop = 0; 566 if (type_size == 0) { 567 *ierrnop = ITAB_SYNTAX_ERROR; 568 return (NULL); 569 } 570 571 switch (ie->ds_type) { 572 case DSYM_ASCII: 573 n_entries = strlen(value); /* no NUL */ 574 break; 575 576 case DSYM_OCTET: 577 vallen = strlen(value); 578 n_entries = vallen / 2; 579 n_entries += vallen % 2; 580 break; 581 582 case DSYM_DOMAIN: 583 /* 584 * Maximum (worst-case) encoded length is one byte more than 585 * the number of characters on input. 586 */ 587 n_entries = strlen(value) + 1; 588 break; 589 590 case DSYM_DUID: 591 /* Worst case is ":::::" */ 592 n_entries = strlen(value); 593 if (n_entries < DLPI_PHYSADDR_MAX) 594 n_entries = DLPI_PHYSADDR_MAX; 595 n_entries += sizeof (duid_llt_t); 596 break; 597 598 default: 599 /* 600 * figure out the number of entries by counting the spaces 601 * in the value string 602 */ 603 for (valuep = value; valuep++ != NULL; n_entries++) 604 valuep = strchr(valuep, ' '); 605 break; 606 } 607 608 /* 609 * if we're gonna return a complete option, then include the 610 * option length and code in the size of the packet we allocate 611 */ 612 if (!just_payload) 613 hlen = ie->ds_dhcpv6 ? sizeof (*d6o) : 2; 614 615 length = n_entries * type_size; 616 if (hlen + length > 0) 617 result = malloc(hlen + length); 618 619 if ((optstart = result) != NULL && !just_payload) 620 optstart += hlen; 621 622 switch (ie->ds_type) { 623 624 case DSYM_ASCII: 625 626 if (optstart == NULL) { 627 *ierrnop = ITAB_NOMEM; 628 return (NULL); 629 } 630 631 (void) memcpy(optstart, value, length); 632 break; 633 634 case DSYM_DOMAIN: 635 if (optstart == NULL) { 636 *ierrnop = ITAB_NOMEM; 637 return (NULL); 638 } 639 640 /* 641 * Note that this encoder always presents the trailing 0-octet 642 * when dealing with a list. This means that you can't have 643 * non-fully-qualified members anywhere but at the end of a 644 * list (or as the only member of the list). 645 */ 646 valuep = value; 647 while (*valuep != '\0') { 648 int dig, val, inchr; 649 boolean_t escape; 650 uchar_t *flen; 651 652 /* 653 * Skip over whitespace that delimits list members. 654 */ 655 if (isascii(*valuep) && isspace(*valuep)) { 656 valuep++; 657 continue; 658 } 659 dig = val = 0; 660 escape = B_FALSE; 661 flen = optstart++; 662 while ((inchr = *valuep) != '\0') { 663 valuep++; 664 /* 665 * Just copy non-ASCII text directly to the 666 * output string. This simplifies the use of 667 * other ctype macros below, as, unlike the 668 * special isascii function, they don't handle 669 * non-ASCII. 670 */ 671 if (!isascii(inchr)) { 672 escape = B_FALSE; 673 *optstart++ = inchr; 674 continue; 675 } 676 if (escape) { 677 /* 678 * Handle any of \D, \DD, or \DDD for 679 * a digit escape. 680 */ 681 if (isdigit(inchr)) { 682 val = val * 10 + inchr - '0'; 683 if (++dig == 3) { 684 *optstart++ = val; 685 dig = val = 0; 686 escape = B_FALSE; 687 } 688 continue; 689 } else if (dig > 0) { 690 /* 691 * User terminated \D or \DD 692 * with non-digit. An error, 693 * but we can assume he means 694 * to treat as \00D or \0DD. 695 */ 696 *optstart++ = val; 697 dig = val = 0; 698 } 699 /* Fall through and copy character */ 700 escape = B_FALSE; 701 } else if (inchr == '\\') { 702 escape = B_TRUE; 703 continue; 704 } else if (inchr == '.') { 705 /* 706 * End of component. Write the length 707 * prefix. If the component is zero 708 * length (i.e., ".."), the just omit 709 * it. 710 */ 711 *flen = (optstart - flen) - 1; 712 if (*flen > 0) 713 flen = optstart++; 714 continue; 715 } else if (isspace(inchr)) { 716 /* 717 * Unescaped space; end of domain name 718 * in list. 719 */ 720 break; 721 } 722 *optstart++ = inchr; 723 } 724 /* 725 * Handle trailing escape sequence. If string ends 726 * with \, then assume user wants \ at end of encoded 727 * string. If it ends with \D or \DD, assume \00D or 728 * \0DD. 729 */ 730 if (escape) 731 *optstart++ = dig > 0 ? val : '\\'; 732 *flen = (optstart - flen) - 1; 733 /* 734 * If user specified FQDN with trailing '.', then above 735 * will result in zero for the last component length. 736 * We're done, and optstart already points to the start 737 * of the next in list. Otherwise, we need to write a 738 * single zero byte to end the entry, if there are more 739 * entries that will be decoded. 740 */ 741 while (isascii(*valuep) && isspace(*valuep)) 742 valuep++; 743 if (*flen > 0 && *valuep != '\0') 744 *optstart++ = '\0'; 745 } 746 length = (optstart - result) - hlen; 747 break; 748 749 case DSYM_DUID: 750 if (optstart == NULL) { 751 *ierrnop = ITAB_NOMEM; 752 return (NULL); 753 } 754 755 errno = 0; 756 type = strtoul(value, &currp, 0); 757 if (errno != 0 || value == currp || type > 65535 || 758 (*currp != ',' && *currp != '\0')) { 759 free(result); 760 *ierrnop = ITAB_BAD_NUMBER; 761 return (NULL); 762 } 763 switch (type) { 764 case DHCPV6_DUID_LLT: { 765 duid_llt_t dllt; 766 int hwtype; 767 ulong_t tstamp; 768 int maclen; 769 770 if ((hwtype = get_hw_type(&currp, ierrnop)) == -2) { 771 free(result); 772 return (NULL); 773 } 774 if (*currp++ != ',') { 775 free(result); 776 *ierrnop = ITAB_BAD_NUMBER; 777 return (NULL); 778 } 779 if (*currp == ',' || *currp == '\0') { 780 tstamp = time(NULL) - DUID_TIME_BASE; 781 } else { 782 tstamp = strtoul(currp, &cp2, 0); 783 if (errno != 0 || currp == cp2) { 784 free(result); 785 *ierrnop = ITAB_BAD_NUMBER; 786 return (NULL); 787 } 788 currp = cp2; 789 } 790 maclen = get_mac_addr(currp, ierrnop, 791 &dllt.dllt_hwtype, hwtype, 792 optstart + sizeof (dllt)); 793 if (maclen == -1) { 794 free(result); 795 return (NULL); 796 } 797 dllt.dllt_dutype = htons(type); 798 dllt.dllt_time = htonl(tstamp); 799 (void) memcpy(optstart, &dllt, sizeof (dllt)); 800 length = maclen + sizeof (dllt); 801 break; 802 } 803 case DHCPV6_DUID_EN: { 804 duid_en_t den; 805 ulong_t enterp; 806 807 if (*currp++ != ',') { 808 free(result); 809 *ierrnop = ITAB_BAD_NUMBER; 810 return (NULL); 811 } 812 enterp = strtoul(currp, &cp2, 0); 813 DHCPV6_SET_ENTNUM(&den, enterp); 814 if (errno != 0 || currp == cp2 || 815 enterp != DHCPV6_GET_ENTNUM(&den) || 816 (*cp2 != ',' && *cp2 != '\0')) { 817 free(result); 818 *ierrnop = ITAB_BAD_NUMBER; 819 return (NULL); 820 } 821 if (*cp2 == ',') 822 cp2++; 823 vallen = strlen(cp2); 824 reslen = (vallen + 1) / 2; 825 if (hexascii_to_octet(cp2, vallen, 826 optstart + sizeof (den), &reslen) != 0) { 827 free(result); 828 *ierrnop = ITAB_BAD_NUMBER; 829 return (NULL); 830 } 831 den.den_dutype = htons(type); 832 (void) memcpy(optstart, &den, sizeof (den)); 833 length = reslen + sizeof (den); 834 break; 835 } 836 case DHCPV6_DUID_LL: { 837 duid_ll_t dll; 838 int hwtype; 839 int maclen; 840 841 if ((hwtype = get_hw_type(&currp, ierrnop)) == -2) { 842 free(result); 843 return (NULL); 844 } 845 maclen = get_mac_addr(currp, ierrnop, &dll.dll_hwtype, 846 hwtype, optstart + sizeof (dll)); 847 if (maclen == -1) { 848 free(result); 849 return (NULL); 850 } 851 dll.dll_dutype = htons(type); 852 (void) memcpy(optstart, &dll, sizeof (dll)); 853 length = maclen + sizeof (dll); 854 break; 855 } 856 default: 857 if (*currp == ',') 858 currp++; 859 vallen = strlen(currp); 860 reslen = (vallen + 1) / 2; 861 if (hexascii_to_octet(currp, vallen, optstart + 2, 862 &reslen) != 0) { 863 free(result); 864 *ierrnop = ITAB_BAD_NUMBER; 865 return (NULL); 866 } 867 optstart[0] = type >> 8; 868 optstart[1] = type; 869 length = reslen + 2; 870 break; 871 } 872 break; 873 874 case DSYM_OCTET: 875 876 if (optstart == NULL) { 877 *ierrnop = ITAB_BAD_OCTET; 878 return (NULL); 879 } 880 881 reslen = length; 882 /* Call libinetutil function to decode */ 883 if (hexascii_to_octet(value, vallen, optstart, &reslen) != 0) { 884 free(result); 885 *ierrnop = ITAB_BAD_OCTET; 886 return (NULL); 887 } 888 break; 889 890 case DSYM_IP: 891 case DSYM_IPV6: 892 893 if (optstart == NULL) { 894 *ierrnop = ITAB_BAD_IPADDR; 895 return (NULL); 896 } 897 if (n_entries % ie->ds_gran != 0) { 898 *ierrnop = ITAB_BAD_GRAN; 899 inittab_msg("inittab_encode: number of entries " 900 "not compatible with option granularity"); 901 free(result); 902 return (NULL); 903 } 904 905 for (valuep = value, i = 0; i < n_entries; i++, valuep++) { 906 907 currp = strchr(valuep, ' '); 908 if (currp != NULL) 909 *currp = '\0'; 910 if (inet_pton(ie->ds_type == DSYM_IP ? AF_INET : 911 AF_INET6, valuep, optstart) != 1) { 912 *ierrnop = ITAB_BAD_IPADDR; 913 inittab_msg("inittab_encode: bogus ip address"); 914 free(result); 915 return (NULL); 916 } 917 918 valuep = currp; 919 if (valuep == NULL) { 920 if (i < (n_entries - 1)) { 921 *ierrnop = ITAB_NOT_ENOUGH_IP; 922 inittab_msg("inittab_encode: too few " 923 "ip addresses"); 924 free(result); 925 return (NULL); 926 } 927 break; 928 } 929 optstart += type_size; 930 } 931 break; 932 933 case DSYM_NUMBER: /* FALLTHRU */ 934 case DSYM_UNUMBER8: /* FALLTHRU */ 935 case DSYM_SNUMBER8: /* FALLTHRU */ 936 case DSYM_UNUMBER16: /* FALLTHRU */ 937 case DSYM_SNUMBER16: /* FALLTHRU */ 938 case DSYM_UNUMBER24: /* FALLTHRU */ 939 case DSYM_UNUMBER32: /* FALLTHRU */ 940 case DSYM_SNUMBER32: /* FALLTHRU */ 941 case DSYM_UNUMBER64: /* FALLTHRU */ 942 case DSYM_SNUMBER64: 943 944 if (optstart == NULL) { 945 *ierrnop = ITAB_BAD_NUMBER; 946 return (NULL); 947 } 948 949 is_signed = (ie->ds_type == DSYM_SNUMBER64 || 950 ie->ds_type == DSYM_SNUMBER32 || 951 ie->ds_type == DSYM_SNUMBER16 || 952 ie->ds_type == DSYM_SNUMBER8); 953 954 if (encode_number(n_entries, type_size, is_signed, 0, value, 955 optstart, ierrnop) == B_FALSE) { 956 free(result); 957 return (NULL); 958 } 959 break; 960 961 default: 962 if (ie->ds_type == DSYM_BOOL) 963 *ierrnop = ITAB_BAD_BOOLEAN; 964 else 965 *ierrnop = ITAB_SYNTAX_ERROR; 966 967 inittab_msg("inittab_encode: unsupported type `%d'", 968 ie->ds_type); 969 970 free(result); 971 return (NULL); 972 } 973 974 /* 975 * if just_payload is false, then we need to add the option 976 * code and length fields in. 977 */ 978 if (!just_payload) { 979 if (ie->ds_dhcpv6) { 980 /* LINTED: alignment */ 981 d6o = (dhcpv6_option_t *)result; 982 d6o->d6o_code = htons(ie->ds_code); 983 d6o->d6o_len = htons(length); 984 } else { 985 result[0] = ie->ds_code; 986 result[1] = length; 987 } 988 } 989 990 if (lengthp != NULL) 991 *lengthp = length + hlen; 992 993 return (result); 994 } 995 996 /* 997 * inittab_decode_e(): converts a binary representation of a given datatype into 998 * a string; used for decoding DHCP options in a packet off 999 * the wire into ascii 1000 * 1001 * input: dhcp_symbol_t *: the entry describing the payload option 1002 * uchar_t *: the payload to convert 1003 * uint16_t: the payload length (only used if just_payload is true) 1004 * boolean_t: if false, payload is assumed to be a DHCP option 1005 * int *: set to extended error code if error occurs. 1006 * output: char *: a dynamically allocated string containing the converted data 1007 */ 1008 1009 char * 1010 inittab_decode_e(const dhcp_symbol_t *ie, const uchar_t *payload, 1011 uint16_t length, boolean_t just_payload, int *ierrnop) 1012 { 1013 char *resultp, *result = NULL; 1014 uint_t n_entries; 1015 struct in_addr in_addr; 1016 in6_addr_t in6_addr; 1017 uint8_t type_size = inittab_type_to_size(ie); 1018 boolean_t is_signed; 1019 int type; 1020 1021 *ierrnop = 0; 1022 if (type_size == 0) { 1023 *ierrnop = ITAB_SYNTAX_ERROR; 1024 return (NULL); 1025 } 1026 1027 if (!just_payload) { 1028 if (ie->ds_dhcpv6) { 1029 dhcpv6_option_t d6o; 1030 1031 (void) memcpy(&d6o, payload, sizeof (d6o)); 1032 length = ntohs(d6o.d6o_len); 1033 payload += sizeof (d6o); 1034 } else { 1035 length = payload[1]; 1036 payload += 2; 1037 } 1038 } 1039 1040 /* 1041 * figure out the number of elements to convert. note that 1042 * for ds_type NUMBER, the granularity is really 1 since the 1043 * value of ds_gran is the number of bytes in the number. 1044 */ 1045 if (ie->ds_type == DSYM_NUMBER) 1046 n_entries = MIN(ie->ds_max, length / type_size); 1047 else 1048 n_entries = MIN(ie->ds_max * ie->ds_gran, length / type_size); 1049 1050 if (n_entries == 0) 1051 n_entries = length / type_size; 1052 1053 if ((length % type_size) != 0) { 1054 inittab_msg("inittab_decode: length of string not compatible " 1055 "with option type `%i'", ie->ds_type); 1056 *ierrnop = ITAB_BAD_STRING; 1057 return (NULL); 1058 } 1059 1060 switch (ie->ds_type) { 1061 1062 case DSYM_ASCII: 1063 1064 result = malloc(n_entries + 1); 1065 if (result == NULL) { 1066 *ierrnop = ITAB_NOMEM; 1067 return (NULL); 1068 } 1069 1070 (void) memcpy(result, payload, n_entries); 1071 result[n_entries] = '\0'; 1072 break; 1073 1074 case DSYM_DOMAIN: 1075 1076 /* 1077 * A valid, decoded RFC 1035 domain string or sequence of 1078 * strings is always the same size as the encoded form, but we 1079 * allow for RFC 1035 \DDD and \\ and \. escaping. 1080 * 1081 * Decoding stops at the end of the input or the first coding 1082 * violation. Coding violations result in discarding the 1083 * offending list entry entirely. Note that we ignore the 255 1084 * character overall limit on domain names. 1085 */ 1086 if ((result = malloc(4 * length + 1)) == NULL) { 1087 *ierrnop = ITAB_NOMEM; 1088 return (NULL); 1089 } 1090 resultp = result; 1091 while (length > 0) { 1092 char *dstart; 1093 int slen; 1094 1095 dstart = resultp; 1096 while (length > 0) { 1097 slen = *payload++; 1098 length--; 1099 /* Upper two bits of length must be zero */ 1100 if ((slen & 0xc0) != 0 || slen > length) { 1101 length = 0; 1102 resultp = dstart; 1103 break; 1104 } 1105 if (resultp != dstart) 1106 *resultp++ = '.'; 1107 if (slen == 0) 1108 break; 1109 length -= slen; 1110 while (slen > 0) { 1111 if (!isascii(*payload) || 1112 !isgraph(*payload)) { 1113 (void) snprintf(resultp, 5, 1114 "\\%03d", 1115 *(unsigned char *)payload); 1116 resultp += 4; 1117 payload++; 1118 } else { 1119 if (*payload == '.' || 1120 *payload == '\\') 1121 *resultp++ = '\\'; 1122 *resultp++ = *payload++; 1123 } 1124 slen--; 1125 } 1126 } 1127 if (resultp != dstart && length > 0) 1128 *resultp++ = ' '; 1129 } 1130 *resultp = '\0'; 1131 break; 1132 1133 case DSYM_DUID: 1134 1135 /* 1136 * First, determine the type of DUID. We need at least two 1137 * octets worth of data to grab the type code. Once we have 1138 * that, the number of octets required for representation 1139 * depends on the type. 1140 */ 1141 1142 if (length < 2) { 1143 *ierrnop = ITAB_BAD_GRAN; 1144 return (NULL); 1145 } 1146 type = (payload[0] << 8) + payload[1]; 1147 switch (type) { 1148 case DHCPV6_DUID_LLT: { 1149 duid_llt_t dllt; 1150 1151 if (length < sizeof (dllt)) { 1152 *ierrnop = ITAB_BAD_GRAN; 1153 return (NULL); 1154 } 1155 (void) memcpy(&dllt, payload, sizeof (dllt)); 1156 payload += sizeof (dllt); 1157 length -= sizeof (dllt); 1158 n_entries = sizeof ("1,65535,4294967295,") + 1159 length * 3; 1160 if ((result = malloc(n_entries)) == NULL) { 1161 *ierrnop = ITAB_NOMEM; 1162 return (NULL); 1163 } 1164 (void) snprintf(result, n_entries, "%d,%u,%u,", type, 1165 ntohs(dllt.dllt_hwtype), ntohl(dllt.dllt_time)); 1166 break; 1167 } 1168 case DHCPV6_DUID_EN: { 1169 duid_en_t den; 1170 1171 if (length < sizeof (den)) { 1172 *ierrnop = ITAB_BAD_GRAN; 1173 return (NULL); 1174 } 1175 (void) memcpy(&den, payload, sizeof (den)); 1176 payload += sizeof (den); 1177 length -= sizeof (den); 1178 n_entries = sizeof ("2,4294967295,") + length * 2; 1179 if ((result = malloc(n_entries)) == NULL) { 1180 *ierrnop = ITAB_NOMEM; 1181 return (NULL); 1182 } 1183 (void) snprintf(result, n_entries, "%d,%u,", type, 1184 DHCPV6_GET_ENTNUM(&den)); 1185 break; 1186 } 1187 case DHCPV6_DUID_LL: { 1188 duid_ll_t dll; 1189 1190 if (length < sizeof (dll)) { 1191 *ierrnop = ITAB_BAD_GRAN; 1192 return (NULL); 1193 } 1194 (void) memcpy(&dll, payload, sizeof (dll)); 1195 payload += sizeof (dll); 1196 length -= sizeof (dll); 1197 n_entries = sizeof ("3,65535,") + length * 3; 1198 if ((result = malloc(n_entries)) == NULL) { 1199 *ierrnop = ITAB_NOMEM; 1200 return (NULL); 1201 } 1202 (void) snprintf(result, n_entries, "%d,%u,", type, 1203 ntohs(dll.dll_hwtype)); 1204 break; 1205 } 1206 default: 1207 n_entries = sizeof ("0,") + length * 2; 1208 if ((result = malloc(n_entries)) == NULL) { 1209 *ierrnop = ITAB_NOMEM; 1210 return (NULL); 1211 } 1212 (void) snprintf(result, n_entries, "%d,", type); 1213 break; 1214 } 1215 resultp = result + strlen(result); 1216 n_entries -= strlen(result); 1217 if (type == DHCPV6_DUID_LLT || type == DHCPV6_DUID_LL) { 1218 if (length > 0) { 1219 resultp += snprintf(resultp, 3, "%02X", 1220 *payload++); 1221 length--; 1222 } 1223 while (length-- > 0) { 1224 resultp += snprintf(resultp, 4, ":%02X", 1225 *payload++); 1226 } 1227 } else { 1228 while (length-- > 0) { 1229 resultp += snprintf(resultp, 3, "%02X", 1230 *payload++); 1231 } 1232 } 1233 break; 1234 1235 case DSYM_OCTET: 1236 1237 result = malloc(n_entries * (sizeof ("0xNN") + 1)); 1238 if (result == NULL) { 1239 *ierrnop = ITAB_NOMEM; 1240 return (NULL); 1241 } 1242 1243 result[0] = '\0'; 1244 resultp = result; 1245 if (n_entries > 0) { 1246 resultp += sprintf(resultp, "0x%02X", *payload++); 1247 n_entries--; 1248 } 1249 while (n_entries-- > 0) 1250 resultp += sprintf(resultp, " 0x%02X", *payload++); 1251 1252 break; 1253 1254 case DSYM_IP: 1255 case DSYM_IPV6: 1256 if ((length / type_size) % ie->ds_gran != 0) { 1257 *ierrnop = ITAB_BAD_GRAN; 1258 inittab_msg("inittab_decode: number of entries " 1259 "not compatible with option granularity"); 1260 return (NULL); 1261 } 1262 1263 result = malloc(n_entries * (ie->ds_type == DSYM_IP ? 1264 INET_ADDRSTRLEN : INET6_ADDRSTRLEN)); 1265 if (result == NULL) { 1266 *ierrnop = ITAB_NOMEM; 1267 return (NULL); 1268 } 1269 1270 for (resultp = result; n_entries != 0; n_entries--) { 1271 if (ie->ds_type == DSYM_IP) { 1272 (void) memcpy(&in_addr.s_addr, payload, 1273 sizeof (ipaddr_t)); 1274 (void) strcpy(resultp, inet_ntoa(in_addr)); 1275 } else { 1276 (void) memcpy(&in6_addr, payload, 1277 sizeof (in6_addr)); 1278 (void) inet_ntop(AF_INET6, &in6_addr, resultp, 1279 INET6_ADDRSTRLEN); 1280 } 1281 resultp += strlen(resultp); 1282 if (n_entries > 1) 1283 *resultp++ = ' '; 1284 payload += type_size; 1285 } 1286 *resultp = '\0'; 1287 break; 1288 1289 case DSYM_NUMBER: /* FALLTHRU */ 1290 case DSYM_UNUMBER8: /* FALLTHRU */ 1291 case DSYM_SNUMBER8: /* FALLTHRU */ 1292 case DSYM_UNUMBER16: /* FALLTHRU */ 1293 case DSYM_SNUMBER16: /* FALLTHRU */ 1294 case DSYM_UNUMBER32: /* FALLTHRU */ 1295 case DSYM_SNUMBER32: /* FALLTHRU */ 1296 case DSYM_UNUMBER64: /* FALLTHRU */ 1297 case DSYM_SNUMBER64: 1298 1299 is_signed = (ie->ds_type == DSYM_SNUMBER64 || 1300 ie->ds_type == DSYM_SNUMBER32 || 1301 ie->ds_type == DSYM_SNUMBER16 || 1302 ie->ds_type == DSYM_SNUMBER8); 1303 1304 result = malloc(n_entries * ITAB_MAX_NUMBER_LEN); 1305 if (result == NULL) { 1306 *ierrnop = ITAB_NOMEM; 1307 return (NULL); 1308 } 1309 1310 if (decode_number(n_entries, type_size, is_signed, ie->ds_gran, 1311 payload, result, ierrnop) == B_FALSE) { 1312 free(result); 1313 return (NULL); 1314 } 1315 break; 1316 1317 default: 1318 inittab_msg("inittab_decode: unsupported type `%d'", 1319 ie->ds_type); 1320 break; 1321 } 1322 1323 return (result); 1324 } 1325 1326 /* 1327 * inittab_encode(): converts a string representation of a given datatype into 1328 * binary; used for encoding ascii values into a form that 1329 * can be put in DHCP packets to be sent on the wire. 1330 * 1331 * input: dhcp_symbol_t *: the entry describing the value option 1332 * const char *: the value to convert 1333 * uint16_t *: set to the length of the binary data returned 1334 * boolean_t: if false, return a full DHCP option 1335 * output: uchar_t *: a dynamically allocated byte array with converted data 1336 */ 1337 1338 uchar_t * 1339 inittab_encode(const dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, 1340 boolean_t just_payload) 1341 { 1342 int ierrno; 1343 1344 return (inittab_encode_e(ie, value, lengthp, just_payload, &ierrno)); 1345 } 1346 1347 /* 1348 * inittab_decode(): converts a binary representation of a given datatype into 1349 * a string; used for decoding DHCP options in a packet off 1350 * the wire into ascii 1351 * 1352 * input: dhcp_symbol_t *: the entry describing the payload option 1353 * uchar_t *: the payload to convert 1354 * uint16_t: the payload length (only used if just_payload is true) 1355 * boolean_t: if false, payload is assumed to be a DHCP option 1356 * output: char *: a dynamically allocated string containing the converted data 1357 */ 1358 1359 char * 1360 inittab_decode(const dhcp_symbol_t *ie, const uchar_t *payload, uint16_t length, 1361 boolean_t just_payload) 1362 { 1363 int ierrno; 1364 1365 return (inittab_decode_e(ie, payload, length, just_payload, &ierrno)); 1366 } 1367 1368 /* 1369 * inittab_msg(): prints diagnostic messages if INITTAB_DEBUG is set 1370 * 1371 * const char *: a printf-like format string 1372 * ...: arguments to the format string 1373 * output: void 1374 */ 1375 1376 /*PRINTFLIKE1*/ 1377 static void 1378 inittab_msg(const char *fmt, ...) 1379 { 1380 enum { INITTAB_MSG_CHECK, INITTAB_MSG_RETURN, INITTAB_MSG_OUTPUT }; 1381 1382 va_list ap; 1383 char buf[512]; 1384 static int action = INITTAB_MSG_CHECK; 1385 1386 /* 1387 * check DHCP_INITTAB_DEBUG the first time in; thereafter, use 1388 * the the cached result (stored in `action'). 1389 */ 1390 switch (action) { 1391 1392 case INITTAB_MSG_CHECK: 1393 1394 if (getenv("DHCP_INITTAB_DEBUG") == NULL) { 1395 action = INITTAB_MSG_RETURN; 1396 return; 1397 } 1398 1399 action = INITTAB_MSG_OUTPUT; 1400 1401 /* FALLTHRU into INITTAB_MSG_OUTPUT */ 1402 1403 case INITTAB_MSG_OUTPUT: 1404 1405 va_start(ap, fmt); 1406 1407 (void) snprintf(buf, sizeof (buf), "inittab: %s\n", fmt); 1408 (void) vfprintf(stderr, buf, ap); 1409 1410 va_end(ap); 1411 break; 1412 1413 case INITTAB_MSG_RETURN: 1414 1415 return; 1416 } 1417 } 1418 1419 /* 1420 * decode_number(): decodes a sequence of numbers from binary into ascii; 1421 * binary is coming off of the network, so it is in nbo 1422 * 1423 * input: uint8_t: the number of "granularity" numbers to decode 1424 * uint8_t: the length of each number 1425 * boolean_t: whether the numbers should be considered signed 1426 * uint8_t: the number of numbers per granularity 1427 * const uint8_t *: where to decode the numbers from 1428 * char *: where to decode the numbers to 1429 * output: boolean_t: true on successful conversion, false on failure 1430 */ 1431 1432 static boolean_t 1433 decode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed, 1434 uint8_t granularity, const uint8_t *from, char *to, int *ierrnop) 1435 { 1436 uint16_t uint16; 1437 uint32_t uint32; 1438 uint64_t uint64; 1439 1440 if (granularity != 0) { 1441 if ((granularity % n_entries) != 0) { 1442 inittab_msg("decode_number: number of entries " 1443 "not compatible with option granularity"); 1444 *ierrnop = ITAB_BAD_GRAN; 1445 return (B_FALSE); 1446 } 1447 } 1448 1449 for (; n_entries != 0; n_entries--, from += size) { 1450 1451 switch (size) { 1452 1453 case 1: 1454 to += sprintf(to, is_signed ? "%d" : "%u", *from); 1455 break; 1456 1457 case 2: 1458 (void) memcpy(&uint16, from, 2); 1459 to += sprintf(to, is_signed ? "%hd" : "%hu", 1460 ntohs(uint16)); 1461 break; 1462 1463 case 3: 1464 uint32 = 0; 1465 (void) memcpy((uchar_t *)&uint32 + 1, from, 3); 1466 to += sprintf(to, is_signed ? "%ld" : "%lu", 1467 ntohl(uint32)); 1468 break; 1469 1470 case 4: 1471 (void) memcpy(&uint32, from, 4); 1472 to += sprintf(to, is_signed ? "%ld" : "%lu", 1473 ntohl(uint32)); 1474 break; 1475 1476 case 8: 1477 (void) memcpy(&uint64, from, 8); 1478 to += sprintf(to, is_signed ? "%lld" : "%llu", 1479 ntohll(uint64)); 1480 break; 1481 1482 default: 1483 *ierrnop = ITAB_BAD_NUMBER; 1484 inittab_msg("decode_number: unknown integer size `%d'", 1485 size); 1486 return (B_FALSE); 1487 } 1488 if (n_entries > 0) 1489 *to++ = ' '; 1490 } 1491 1492 *to = '\0'; 1493 return (B_TRUE); 1494 } 1495 1496 /* 1497 * encode_number(): encodes a sequence of numbers from ascii into binary; 1498 * number will end up on the wire so it needs to be in nbo 1499 * 1500 * input: uint8_t: the number of "granularity" numbers to encode 1501 * uint8_t: the length of each number 1502 * boolean_t: whether the numbers should be considered signed 1503 * uint8_t: the number of numbers per granularity 1504 * const uint8_t *: where to encode the numbers from 1505 * char *: where to encode the numbers to 1506 * int *: set to extended error code if error occurs. 1507 * output: boolean_t: true on successful conversion, false on failure 1508 */ 1509 1510 static boolean_t /* ARGSUSED */ 1511 encode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed, 1512 uint8_t granularity, const char *from, uint8_t *to, int *ierrnop) 1513 { 1514 uint8_t i; 1515 uint16_t uint16; 1516 uint32_t uint32; 1517 uint64_t uint64; 1518 char *endptr; 1519 1520 if (granularity != 0) { 1521 if ((granularity % n_entries) != 0) { 1522 *ierrnop = ITAB_BAD_GRAN; 1523 inittab_msg("encode_number: number of entries " 1524 "not compatible with option granularity"); 1525 return (B_FALSE); 1526 } 1527 } 1528 1529 for (i = 0; i < n_entries; i++, from++, to += size) { 1530 1531 /* 1532 * totally obscure c factoid: it is legal to pass a 1533 * string representing a negative number to strtoul(). 1534 * in this case, strtoul() will return an unsigned 1535 * long that if cast to a long, would represent the 1536 * negative number. we take advantage of this to 1537 * cut down on code here. 1538 */ 1539 1540 errno = 0; 1541 switch (size) { 1542 1543 case 1: 1544 *to = strtoul(from, &endptr, 0); 1545 if (errno != 0 || from == endptr) { 1546 goto error; 1547 } 1548 break; 1549 1550 case 2: 1551 uint16 = htons(strtoul(from, &endptr, 0)); 1552 if (errno != 0 || from == endptr) { 1553 goto error; 1554 } 1555 (void) memcpy(to, &uint16, 2); 1556 break; 1557 1558 case 3: 1559 uint32 = htonl(strtoul(from, &endptr, 0)); 1560 if (errno != 0 || from == endptr) { 1561 goto error; 1562 } 1563 (void) memcpy(to, (uchar_t *)&uint32 + 1, 3); 1564 break; 1565 1566 case 4: 1567 uint32 = htonl(strtoul(from, &endptr, 0)); 1568 if (errno != 0 || from == endptr) { 1569 goto error; 1570 } 1571 (void) memcpy(to, &uint32, 4); 1572 break; 1573 1574 case 8: 1575 uint64 = htonll(strtoull(from, &endptr, 0)); 1576 if (errno != 0 || from == endptr) { 1577 goto error; 1578 } 1579 (void) memcpy(to, &uint64, 8); 1580 break; 1581 1582 default: 1583 inittab_msg("encode_number: unsupported integer " 1584 "size `%d'", size); 1585 return (B_FALSE); 1586 } 1587 1588 from = strchr(from, ' '); 1589 if (from == NULL) 1590 break; 1591 } 1592 1593 return (B_TRUE); 1594 1595 error: 1596 *ierrnop = ITAB_BAD_NUMBER; 1597 inittab_msg("encode_number: cannot convert to integer"); 1598 return (B_FALSE); 1599 } 1600 1601 /* 1602 * inittab_type_to_size(): given an inittab entry, returns size of one entry of 1603 * its type 1604 * 1605 * input: dhcp_symbol_t *: an entry of the given type 1606 * output: uint8_t: the size in bytes of an entry of that type 1607 */ 1608 1609 uint8_t 1610 inittab_type_to_size(const dhcp_symbol_t *ie) 1611 { 1612 switch (ie->ds_type) { 1613 1614 case DSYM_DUID: 1615 case DSYM_DOMAIN: 1616 case DSYM_ASCII: 1617 case DSYM_OCTET: 1618 case DSYM_SNUMBER8: 1619 case DSYM_UNUMBER8: 1620 1621 return (1); 1622 1623 case DSYM_SNUMBER16: 1624 case DSYM_UNUMBER16: 1625 1626 return (2); 1627 1628 case DSYM_UNUMBER24: 1629 1630 return (3); 1631 1632 case DSYM_SNUMBER32: 1633 case DSYM_UNUMBER32: 1634 case DSYM_IP: 1635 1636 return (4); 1637 1638 case DSYM_SNUMBER64: 1639 case DSYM_UNUMBER64: 1640 1641 return (8); 1642 1643 case DSYM_NUMBER: 1644 1645 return (ie->ds_gran); 1646 1647 case DSYM_IPV6: 1648 1649 return (sizeof (in6_addr_t)); 1650 } 1651 1652 return (0); 1653 } 1654 1655 /* 1656 * itabcode_to_dsymcode(): maps an inittab category code to its dsym 1657 * representation 1658 * 1659 * input: uchar_t: the inittab category code 1660 * output: dsym_category_t: the dsym category code 1661 */ 1662 1663 static dsym_category_t 1664 itabcode_to_dsymcode(uchar_t itabcode) 1665 { 1666 1667 unsigned int i; 1668 1669 for (i = 0; i < ITAB_CAT_COUNT; i++) 1670 if (category_map[i].cme_itabcode == itabcode) 1671 return (category_map[i].cme_dsymcode); 1672 1673 return (DSYM_BAD_CAT); 1674 } 1675 1676 /* 1677 * category_to_code(): maps a category name to its numeric representation 1678 * 1679 * input: const char *: the category name 1680 * output: uchar_t: its internal code (numeric representation) 1681 */ 1682 1683 static uchar_t 1684 category_to_code(const char *category) 1685 { 1686 unsigned int i; 1687 1688 for (i = 0; i < ITAB_CAT_COUNT; i++) 1689 if (strcasecmp(category_map[i].cme_name, category) == 0) 1690 return (category_map[i].cme_itabcode); 1691 1692 return (0); 1693 } 1694 1695 /* 1696 * our internal table of DHCP option values, used by inittab_verify() 1697 */ 1698 static dhcp_symbol_t inittab_table[] = 1699 { 1700 { DSYM_INTERNAL, 1024, "Hostname", DSYM_BOOL, 0, 0 }, 1701 { DSYM_INTERNAL, 1025, "LeaseNeg", DSYM_BOOL, 0, 0 }, 1702 { DSYM_INTERNAL, 1026, "EchoVC", DSYM_BOOL, 0, 0 }, 1703 { DSYM_INTERNAL, 1027, "BootPath", DSYM_ASCII, 1, 128 }, 1704 { DSYM_FIELD, 0, "Opcode", DSYM_UNUMBER8, 1, 1 }, 1705 { DSYM_FIELD, 1, "Htype", DSYM_UNUMBER8, 1, 1 }, 1706 { DSYM_FIELD, 2, "HLen", DSYM_UNUMBER8, 1, 1 }, 1707 { DSYM_FIELD, 3, "Hops", DSYM_UNUMBER8, 1, 1 }, 1708 { DSYM_FIELD, 4, "Xid", DSYM_UNUMBER32, 1, 1 }, 1709 { DSYM_FIELD, 8, "Secs", DSYM_UNUMBER16, 1, 1 }, 1710 { DSYM_FIELD, 10, "Flags", DSYM_OCTET, 1, 2 }, 1711 { DSYM_FIELD, 12, "Ciaddr", DSYM_IP, 1, 1 }, 1712 { DSYM_FIELD, 16, "Yiaddr", DSYM_IP, 1, 1 }, 1713 { DSYM_FIELD, 20, "BootSrvA", DSYM_IP, 1, 1 }, 1714 { DSYM_FIELD, 24, "Giaddr", DSYM_IP, 1, 1 }, 1715 { DSYM_FIELD, 28, "Chaddr", DSYM_OCTET, 1, 16 }, 1716 { DSYM_FIELD, 44, "BootSrvN", DSYM_ASCII, 1, 64 }, 1717 { DSYM_FIELD, 108, "BootFile", DSYM_ASCII, 1, 128 }, 1718 { DSYM_FIELD, 236, "Magic", DSYM_OCTET, 1, 4 }, 1719 { DSYM_FIELD, 240, "Options", DSYM_OCTET, 1, 60 }, 1720 { DSYM_STANDARD, 1, "Subnet", DSYM_IP, 1, 1 }, 1721 { DSYM_STANDARD, 2, "UTCoffst", DSYM_SNUMBER32, 1, 1 }, 1722 { DSYM_STANDARD, 3, "Router", DSYM_IP, 1, 0 }, 1723 { DSYM_STANDARD, 4, "Timeserv", DSYM_IP, 1, 0 }, 1724 { DSYM_STANDARD, 5, "IEN116ns", DSYM_IP, 1, 0 }, 1725 { DSYM_STANDARD, 6, "DNSserv", DSYM_IP, 1, 0 }, 1726 { DSYM_STANDARD, 7, "Logserv", DSYM_IP, 1, 0 }, 1727 { DSYM_STANDARD, 8, "Cookie", DSYM_IP, 1, 0 }, 1728 { DSYM_STANDARD, 9, "Lprserv", DSYM_IP, 1, 0 }, 1729 { DSYM_STANDARD, 10, "Impress", DSYM_IP, 1, 0 }, 1730 { DSYM_STANDARD, 11, "Resource", DSYM_IP, 1, 0 }, 1731 { DSYM_STANDARD, 12, "Hostname", DSYM_ASCII, 1, 0 }, 1732 { DSYM_STANDARD, 13, "Bootsize", DSYM_UNUMBER16, 1, 1 }, 1733 { DSYM_STANDARD, 14, "Dumpfile", DSYM_ASCII, 1, 0 }, 1734 { DSYM_STANDARD, 15, "DNSdmain", DSYM_ASCII, 1, 0 }, 1735 { DSYM_STANDARD, 16, "Swapserv", DSYM_IP, 1, 1 }, 1736 { DSYM_STANDARD, 17, "Rootpath", DSYM_ASCII, 1, 0 }, 1737 { DSYM_STANDARD, 18, "ExtendP", DSYM_ASCII, 1, 0 }, 1738 { DSYM_STANDARD, 19, "IpFwdF", DSYM_UNUMBER8, 1, 1 }, 1739 { DSYM_STANDARD, 20, "NLrouteF", DSYM_UNUMBER8, 1, 1 }, 1740 { DSYM_STANDARD, 21, "PFilter", DSYM_IP, 2, 0 }, 1741 { DSYM_STANDARD, 22, "MaxIpSiz", DSYM_UNUMBER16, 1, 1 }, 1742 { DSYM_STANDARD, 23, "IpTTL", DSYM_UNUMBER8, 1, 1 }, 1743 { DSYM_STANDARD, 24, "PathTO", DSYM_UNUMBER32, 1, 1 }, 1744 { DSYM_STANDARD, 25, "PathTbl", DSYM_UNUMBER16, 1, 0 }, 1745 { DSYM_STANDARD, 26, "MTU", DSYM_UNUMBER16, 1, 1 }, 1746 { DSYM_STANDARD, 27, "SameMtuF", DSYM_UNUMBER8, 1, 1 }, 1747 { DSYM_STANDARD, 28, "Broadcst", DSYM_IP, 1, 1 }, 1748 { DSYM_STANDARD, 29, "MaskDscF", DSYM_UNUMBER8, 1, 1 }, 1749 { DSYM_STANDARD, 30, "MaskSupF", DSYM_UNUMBER8, 1, 1 }, 1750 { DSYM_STANDARD, 31, "RDiscvyF", DSYM_UNUMBER8, 1, 1 }, 1751 { DSYM_STANDARD, 32, "RSolictS", DSYM_IP, 1, 1 }, 1752 { DSYM_STANDARD, 33, "StaticRt", DSYM_IP, 2, 0 }, 1753 { DSYM_STANDARD, 34, "TrailerF", DSYM_UNUMBER8, 1, 1 }, 1754 { DSYM_STANDARD, 35, "ArpTimeO", DSYM_UNUMBER32, 1, 1 }, 1755 { DSYM_STANDARD, 36, "EthEncap", DSYM_UNUMBER8, 1, 1 }, 1756 { DSYM_STANDARD, 37, "TcpTTL", DSYM_UNUMBER8, 1, 1 }, 1757 { DSYM_STANDARD, 38, "TcpKaInt", DSYM_UNUMBER32, 1, 1 }, 1758 { DSYM_STANDARD, 39, "TcpKaGbF", DSYM_UNUMBER8, 1, 1 }, 1759 { DSYM_STANDARD, 40, "NISdmain", DSYM_ASCII, 1, 0 }, 1760 { DSYM_STANDARD, 41, "NISservs", DSYM_IP, 1, 0 }, 1761 { DSYM_STANDARD, 42, "NTPservs", DSYM_IP, 1, 0 }, 1762 { DSYM_STANDARD, 43, "Vendor", DSYM_OCTET, 1, 0 }, 1763 { DSYM_STANDARD, 44, "NetBNms", DSYM_IP, 1, 0 }, 1764 { DSYM_STANDARD, 45, "NetBDsts", DSYM_IP, 1, 0 }, 1765 { DSYM_STANDARD, 46, "NetBNdT", DSYM_UNUMBER8, 1, 1 }, 1766 { DSYM_STANDARD, 47, "NetBScop", DSYM_ASCII, 1, 0 }, 1767 { DSYM_STANDARD, 48, "XFontSrv", DSYM_IP, 1, 0 }, 1768 { DSYM_STANDARD, 49, "XDispMgr", DSYM_IP, 1, 0 }, 1769 { DSYM_STANDARD, 50, "ReqIP", DSYM_IP, 1, 1 }, 1770 { DSYM_STANDARD, 51, "LeaseTim", DSYM_UNUMBER32, 1, 1 }, 1771 { DSYM_STANDARD, 52, "OptOvrld", DSYM_UNUMBER8, 1, 1 }, 1772 { DSYM_STANDARD, 53, "DHCPType", DSYM_UNUMBER8, 1, 1 }, 1773 { DSYM_STANDARD, 54, "ServerID", DSYM_IP, 1, 1 }, 1774 { DSYM_STANDARD, 55, "ReqList", DSYM_OCTET, 1, 0 }, 1775 { DSYM_STANDARD, 56, "Message", DSYM_ASCII, 1, 0 }, 1776 { DSYM_STANDARD, 57, "DHCP_MTU", DSYM_UNUMBER16, 1, 1 }, 1777 { DSYM_STANDARD, 58, "T1Time", DSYM_UNUMBER32, 1, 1 }, 1778 { DSYM_STANDARD, 59, "T2Time", DSYM_UNUMBER32, 1, 1 }, 1779 { DSYM_STANDARD, 60, "ClassID", DSYM_ASCII, 1, 0 }, 1780 { DSYM_STANDARD, 61, "ClientID", DSYM_OCTET, 1, 0 }, 1781 { DSYM_STANDARD, 62, "NW_dmain", DSYM_ASCII, 1, 0 }, 1782 { DSYM_STANDARD, 63, "NWIPOpts", DSYM_OCTET, 1, 128 }, 1783 { DSYM_STANDARD, 64, "NIS+dom", DSYM_ASCII, 1, 0 }, 1784 { DSYM_STANDARD, 65, "NIS+serv", DSYM_IP, 1, 0 }, 1785 { DSYM_STANDARD, 66, "TFTPsrvN", DSYM_ASCII, 1, 64 }, 1786 { DSYM_STANDARD, 67, "OptBootF", DSYM_ASCII, 1, 128 }, 1787 { DSYM_STANDARD, 68, "MblIPAgt", DSYM_IP, 1, 0 }, 1788 { DSYM_STANDARD, 69, "SMTPserv", DSYM_IP, 1, 0 }, 1789 { DSYM_STANDARD, 70, "POP3serv", DSYM_IP, 1, 0 }, 1790 { DSYM_STANDARD, 71, "NNTPserv", DSYM_IP, 1, 0 }, 1791 { DSYM_STANDARD, 72, "WWWservs", DSYM_IP, 1, 0 }, 1792 { DSYM_STANDARD, 73, "Fingersv", DSYM_IP, 1, 0 }, 1793 { DSYM_STANDARD, 74, "IRCservs", DSYM_IP, 1, 0 }, 1794 { DSYM_STANDARD, 75, "STservs", DSYM_IP, 1, 0 }, 1795 { DSYM_STANDARD, 76, "STDAservs", DSYM_IP, 1, 0 }, 1796 { DSYM_STANDARD, 77, "UserClas", DSYM_ASCII, 1, 0 }, 1797 { DSYM_STANDARD, 78, "SLP_DA", DSYM_OCTET, 1, 0 }, 1798 { DSYM_STANDARD, 79, "SLP_SS", DSYM_OCTET, 1, 0 }, 1799 { DSYM_STANDARD, 82, "AgentOpt", DSYM_OCTET, 1, 0 }, 1800 { DSYM_STANDARD, 89, "FQDN", DSYM_OCTET, 1, 0 }, 1801 { 0, 0, "", 0, 0, 0 } 1802 };