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