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