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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <string.h> 31 #include <stdlib.h> 32 #include <stdio.h> 33 #include <errno.h> 34 #include <stdarg.h> 35 #include <limits.h> 36 #include <ctype.h> 37 #include <libgen.h> 38 #include <sys/isa_defs.h> 39 #include <sys/socket.h> 40 #include <netinet/in.h> 41 #include <arpa/inet.h> 42 #include <sys/sysmacros.h> 43 #include <libinetutil.h> 44 45 #include "dhcp_symbol.h" 46 #include "dhcp_inittab.h" 47 48 static uint64_t dhcp_htonll(uint64_t); 49 static uint64_t dhcp_ntohll(uint64_t); 50 static void inittab_msg(const char *, ...); 51 static uchar_t category_to_code(const char *); 52 static boolean_t encode_number(uint8_t, uint8_t, boolean_t, uint8_t, 53 const char *, uint8_t *, int *); 54 static boolean_t decode_number(uint8_t, uint8_t, boolean_t, uint8_t, 55 const uint8_t *, char *, int *); 56 static dhcp_symbol_t *inittab_lookup(uchar_t, char, const char *, int32_t, 57 size_t *); 58 static dsym_category_t itabcode_to_dsymcode(uchar_t); 59 static boolean_t parse_entry(char *, char **); 60 61 /* 62 * forward declaration of our internal inittab_table[]. too bulky to put 63 * up front -- check the end of this file for its definition. 64 */ 65 static dhcp_symbol_t inittab_table[]; 66 67 /* 68 * the number of fields in the inittab and names for the fields. note that 69 * this order is meaningful to parse_entry(); other functions should just 70 * use them as indexes into the array returned from parse_entry(). 71 */ 72 #define ITAB_FIELDS 7 73 enum { ITAB_NAME, ITAB_CODE, ITAB_TYPE, ITAB_GRAN, ITAB_MAX, ITAB_CONS, 74 ITAB_CAT }; 75 76 /* 77 * the category_map_entry_t is used to map the inittab category codes to 78 * the dsym codes. the reason the codes are different is that the inittab 79 * needs to have the codes be ORable such that queries can retrieve more 80 * than one category at a time. this map is also used to map the inittab 81 * string representation of a category to its numerical code. 82 */ 83 typedef struct category_map_entry { 84 dsym_category_t cme_dsymcode; 85 char *cme_name; 86 uchar_t cme_itabcode; 87 } category_map_entry_t; 88 89 static category_map_entry_t category_map[] = { 90 { DSYM_STANDARD, "STANDARD", ITAB_CAT_STANDARD }, 91 { DSYM_FIELD, "FIELD", ITAB_CAT_FIELD }, 92 { DSYM_INTERNAL, "INTERNAL", ITAB_CAT_INTERNAL }, 93 { DSYM_VENDOR, "VENDOR", ITAB_CAT_VENDOR }, 94 { DSYM_SITE, "SITE", ITAB_CAT_SITE } 95 }; 96 97 /* 98 * inittab_load(): returns all inittab entries with the specified criteria 99 * 100 * input: uchar_t: the categories the consumer is interested in 101 * char: the consumer type of the caller 102 * size_t *: set to the number of entries returned 103 * output: dhcp_symbol_t *: an array of dynamically allocated entries 104 * on success, NULL upon failure 105 */ 106 dhcp_symbol_t * 107 inittab_load(uchar_t categories, char consumer, size_t *n_entries) 108 { 109 return (inittab_lookup(categories, consumer, NULL, -1, n_entries)); 110 } 111 112 /* 113 * inittab_getbyname(): returns an inittab entry with the specified criteria 114 * 115 * input: int: the categories the consumer is interested in 116 * char: the consumer type of the caller 117 * char *: the name of the inittab entry the consumer wants 118 * output: dhcp_symbol_t *: a dynamically allocated dhcp_symbol structure 119 * on success, NULL upon failure 120 */ 121 dhcp_symbol_t * 122 inittab_getbyname(uchar_t categories, char consumer, const char *name) 123 { 124 return (inittab_lookup(categories, consumer, name, -1, NULL)); 125 } 126 127 /* 128 * inittab_getbycode(): returns an inittab entry with the specified criteria 129 * 130 * input: uchar_t: the categories the consumer is interested in 131 * char: the consumer type of the caller 132 * uint16_t: the code of the inittab entry the consumer wants 133 * output: dhcp_symbol_t *: a dynamically allocated dhcp_symbol structure 134 * on success, NULL upon failure 135 */ 136 dhcp_symbol_t * 137 inittab_getbycode(uchar_t categories, char consumer, uint16_t code) 138 { 139 return (inittab_lookup(categories, consumer, NULL, code, NULL)); 140 } 141 142 /* 143 * inittab_lookup(): returns inittab entries with the specified criteria 144 * 145 * input: uchar_t: the categories the consumer is interested in 146 * char: the consumer type of the caller 147 * const char *: the name of the entry the caller is interested 148 * in, or NULL if the caller doesn't care 149 * int32_t: the code the caller is interested in, or -1 if the 150 * caller doesn't care 151 * size_t *: set to the number of entries returned 152 * output: dhcp_symbol_t *: dynamically allocated dhcp_symbol structures 153 * on success, NULL upon failure 154 */ 155 static dhcp_symbol_t * 156 inittab_lookup(uchar_t categories, char consumer, const char *name, 157 int32_t code, size_t *n_entriesp) 158 { 159 FILE *inittab_fp; 160 dhcp_symbol_t *new_entries, *entries = NULL; 161 dhcp_symbol_t entry; 162 char buffer[ITAB_MAX_LINE_LEN]; 163 char *fields[ITAB_FIELDS]; 164 unsigned long line = 0; 165 size_t i, n_entries = 0; 166 char *inittab_path; 167 uchar_t category_code; 168 dsym_cdtype_t type; 169 170 inittab_path = getenv("DHCP_INITTAB_PATH"); 171 if (inittab_path == NULL) 172 inittab_path = ITAB_INITTAB_PATH; 173 174 inittab_fp = fopen(inittab_path, "r"); 175 if (inittab_fp == NULL) { 176 inittab_msg("inittab_lookup: fopen: %s: %s", 177 ITAB_INITTAB_PATH, strerror(errno)); 178 return (NULL); 179 } 180 181 (void) bufsplit(",\n", 0, NULL); 182 while (fgets(buffer, sizeof (buffer), inittab_fp) != NULL) { 183 184 line++; 185 186 /* 187 * make sure the string didn't overflow our buffer 188 */ 189 if (strchr(buffer, '\n') == NULL) { 190 inittab_msg("inittab_lookup: line %li: too long, " 191 "skipping", line); 192 continue; 193 } 194 195 /* 196 * skip `pure comment' lines 197 */ 198 for (i = 0; buffer[i] != '\0'; i++) 199 if (isspace(buffer[i]) == 0) 200 break; 201 202 if (buffer[i] == ITAB_COMMENT_CHAR || buffer[i] == '\0') 203 continue; 204 205 /* 206 * parse the entry out into fields. 207 */ 208 if (parse_entry(buffer, fields) == B_FALSE) { 209 inittab_msg("inittab_lookup: line %li: syntax error, " 210 "skipping", line); 211 continue; 212 } 213 214 /* 215 * validate the values in the entries; skip if invalid. 216 */ 217 if (atoi(fields[ITAB_GRAN]) > ITAB_GRAN_MAX) { 218 inittab_msg("inittab_lookup: line %li: granularity `%s'" 219 " out of range, skipping", line, fields[ITAB_GRAN]); 220 continue; 221 } 222 223 if (atoi(fields[ITAB_MAX]) > ITAB_MAX_MAX) { 224 inittab_msg("inittab_lookup: line %li: maximum `%s' " 225 "out of range, skipping", line, fields[ITAB_MAX]); 226 continue; 227 } 228 229 if (dsym_get_type_id(fields[ITAB_TYPE], &type, B_FALSE) != 230 DSYM_SUCCESS) { 231 inittab_msg("inittab_lookup: line %li: type `%s' " 232 "is invalid, skipping", line, fields[ITAB_TYPE]); 233 continue; 234 } 235 236 /* 237 * find out whether this entry of interest to our consumer, 238 * and if so, throw it onto the set of entries we'll return. 239 * check categories last since it's the most expensive check. 240 */ 241 if (strchr(fields[ITAB_CONS], consumer) == NULL) 242 continue; 243 244 if (code != -1 && atoi(fields[ITAB_CODE]) != code) 245 continue; 246 247 if (name != NULL && strcasecmp(fields[ITAB_NAME], name) != 0) 248 continue; 249 250 category_code = category_to_code(fields[ITAB_CAT]); 251 if ((category_code & categories) == 0) 252 continue; 253 254 /* 255 * looks like a match. allocate an entry and fill it in 256 */ 257 new_entries = realloc(entries, (n_entries + 1) * 258 sizeof (dhcp_symbol_t)); 259 260 /* 261 * if we run out of memory, might as well return what we can 262 */ 263 if (new_entries == NULL) { 264 inittab_msg("inittab_lookup: ran out of memory " 265 "allocating dhcp_symbol_t's"); 266 break; 267 } 268 269 entry.ds_max = atoi(fields[ITAB_MAX]); 270 entry.ds_code = atoi(fields[ITAB_CODE]); 271 entry.ds_type = type; 272 entry.ds_gran = atoi(fields[ITAB_GRAN]); 273 entry.ds_category = itabcode_to_dsymcode(category_code); 274 entry.ds_classes.dc_cnt = 0; 275 entry.ds_classes.dc_names = NULL; 276 (void) strlcpy(entry.ds_name, fields[ITAB_NAME], 277 sizeof (entry.ds_name)); 278 279 entries = new_entries; 280 entries[n_entries++] = entry; 281 } 282 283 if (ferror(inittab_fp) != 0) { 284 inittab_msg("inittab_lookup: error on inittab stream"); 285 clearerr(inittab_fp); 286 } 287 288 (void) fclose(inittab_fp); 289 290 if (n_entriesp != NULL) 291 *n_entriesp = n_entries; 292 293 return (entries); 294 } 295 296 /* 297 * parse_entry(): parses an entry out into its constituent fields 298 * 299 * input: char *: the entry 300 * char **: an array of ITAB_FIELDS length which contains 301 * pointers into the entry on upon return 302 * output: boolean_t: B_TRUE on success, B_FALSE on failure 303 */ 304 static boolean_t 305 parse_entry(char *entry, char **fields) 306 { 307 char *category, *spacep; 308 size_t n_fields, i; 309 310 /* 311 * due to a mistake made long ago, the first and second fields of 312 * each entry are not separated by a comma, but rather by 313 * whitespace -- have bufsplit() treat the two fields as one, then 314 * pull them apart afterwards. 315 */ 316 n_fields = bufsplit(entry, ITAB_FIELDS - 1, fields); 317 if (n_fields != (ITAB_FIELDS - 1)) 318 return (B_FALSE); 319 320 /* 321 * pull the first and second fields apart. this is complicated 322 * since the first field can contain embedded whitespace (so we 323 * must separate the two fields by the last span of whitespace). 324 * 325 * first, find the initial span of whitespace. if there isn't one, 326 * then the entry is malformed. 327 */ 328 category = strpbrk(fields[ITAB_NAME], " \t"); 329 if (category == NULL) 330 return (B_FALSE); 331 332 /* 333 * find the last span of whitespace. 334 */ 335 do { 336 while (isspace(*category)) 337 category++; 338 339 spacep = strpbrk(category, " \t"); 340 if (spacep != NULL) 341 category = spacep; 342 } while (spacep != NULL); 343 344 /* 345 * NUL-terminate the first byte of the last span of whitespace, so 346 * that the first field doesn't have any residual trailing 347 * whitespace. 348 */ 349 spacep = category - 1; 350 while (isspace(*spacep)) 351 spacep--; 352 353 if (spacep <= fields[0]) 354 return (B_FALSE); 355 356 *++spacep = '\0'; 357 358 /* 359 * remove any whitespace from the fields. 360 */ 361 for (i = 0; i < n_fields; i++) { 362 while (isspace(*fields[i])) 363 fields[i]++; 364 } 365 fields[ITAB_CAT] = category; 366 367 return (B_TRUE); 368 } 369 370 /* 371 * inittab_verify(): verifies that a given inittab entry matches an internal 372 * definition 373 * 374 * input: dhcp_symbol_t *: the inittab entry to verify 375 * dhcp_symbol_t *: if non-NULL, a place to store the internal 376 * inittab entry upon return 377 * output: int: ITAB_FAILURE, ITAB_SUCCESS, or ITAB_UNKNOWN 378 */ 379 int 380 inittab_verify(dhcp_symbol_t *inittab_ent, dhcp_symbol_t *internal_ent) 381 { 382 unsigned int i; 383 384 for (i = 0; inittab_table[i].ds_name[0] != '\0'; i++) { 385 386 if (inittab_ent->ds_category != inittab_table[i].ds_category) 387 continue; 388 389 if (inittab_ent->ds_code == inittab_table[i].ds_code) { 390 if (internal_ent != NULL) 391 *internal_ent = inittab_table[i]; 392 393 if (inittab_table[i].ds_type != inittab_ent->ds_type || 394 inittab_table[i].ds_gran != inittab_ent->ds_gran || 395 inittab_table[i].ds_max != inittab_ent->ds_max) 396 return (ITAB_FAILURE); 397 398 return (ITAB_SUCCESS); 399 } 400 } 401 402 return (ITAB_UNKNOWN); 403 } 404 405 /* 406 * inittab_encode_e(): converts a string representation of a given datatype into 407 * binary; used for encoding ascii values into a form that 408 * can be put in DHCP packets to be sent on the wire. 409 * 410 * input: dhcp_symbol_t *: the entry describing the value option 411 * const char *: the value to convert 412 * uint16_t *: set to the length of the binary data returned 413 * boolean_t: if false, return a full DHCP option 414 * output: uchar_t *: a dynamically allocated byte array with converted data 415 */ 416 uchar_t * 417 inittab_encode_e(dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, 418 boolean_t just_payload, int *ierrnop) 419 { 420 uint16_t length = 0; 421 uchar_t n_entries = 0; 422 const char *valuep; 423 char *currp; 424 uchar_t *result = NULL; 425 unsigned int i; 426 uint8_t type_size = inittab_type_to_size(ie); 427 boolean_t is_signed; 428 uint_t vallen, reslen; 429 430 *ierrnop = 0; 431 if (type_size == 0) { 432 *ierrnop = ITAB_SYNTAX_ERROR; 433 return (NULL); 434 } 435 436 if (ie->ds_type == DSYM_ASCII) 437 n_entries = strlen(value); /* no NUL */ 438 else if (ie->ds_type == DSYM_OCTET) { 439 vallen = strlen(value); 440 n_entries = vallen / 2; 441 n_entries += vallen % 2; 442 } else { 443 /* 444 * figure out the number of entries by counting the spaces 445 * in the value string 446 */ 447 for (valuep = value; valuep++ != NULL; n_entries++) 448 valuep = strchr(valuep, ' '); 449 } 450 451 /* 452 * if we're gonna return a complete option, then include the 453 * option length and code in the size of the packet we allocate 454 */ 455 if (just_payload == B_FALSE) 456 length += 2; 457 458 length += n_entries * type_size; 459 if (length > 0) 460 result = malloc(length); 461 462 switch (ie->ds_type) { 463 464 case DSYM_ASCII: 465 466 if (result == NULL) { 467 *ierrnop = ITAB_NOMEM; 468 return (NULL); 469 } 470 471 if (strlen(value) > length) { 472 free(result); 473 *ierrnop = ITAB_BAD_STRING; 474 return (NULL); 475 } 476 477 (void) memcpy(result, value, length); 478 break; 479 480 case DSYM_OCTET: 481 482 if (result == NULL) { 483 *ierrnop = ITAB_BAD_OCTET; 484 return (NULL); 485 } 486 487 reslen = length; 488 /* Call libinetutil function to decode */ 489 if (hexascii_to_octet(value, vallen, result, &reslen) != 0) { 490 free(result); 491 *ierrnop = ITAB_BAD_OCTET; 492 return (NULL); 493 } 494 break; 495 496 case DSYM_IP: 497 498 if (result == NULL) { 499 *ierrnop = ITAB_BAD_IPADDR; 500 return (NULL); 501 } 502 if (n_entries % ie->ds_gran != 0) { 503 *ierrnop = ITAB_BAD_GRAN; 504 inittab_msg("inittab_encode: number of entries " 505 "not compatible with option granularity"); 506 free(result); 507 return (NULL); 508 } 509 510 for (valuep = value, i = 0; i < n_entries; i++, valuep++) { 511 512 currp = strchr(valuep, ' '); 513 if (currp != NULL) 514 *currp = '\0'; 515 if (inet_pton(AF_INET, valuep, 516 &result[i * sizeof (ipaddr_t)]) != 1) { 517 *ierrnop = ITAB_BAD_IPADDR; 518 inittab_msg("inittab_encode: bogus ip address"); 519 free(result); 520 return (NULL); 521 } 522 523 valuep = currp; 524 if (valuep == NULL) { 525 if (i < (n_entries - 1)) { 526 *ierrnop = ITAB_NOT_ENOUGH_IP; 527 inittab_msg("inittab_encode: too few " 528 "ip addresses"); 529 free(result); 530 return (NULL); 531 } 532 break; 533 } 534 } 535 break; 536 537 case DSYM_NUMBER: /* FALLTHRU */ 538 case DSYM_UNUMBER8: /* FALLTHRU */ 539 case DSYM_SNUMBER8: /* FALLTHRU */ 540 case DSYM_UNUMBER16: /* FALLTHRU */ 541 case DSYM_SNUMBER16: /* FALLTHRU */ 542 case DSYM_UNUMBER32: /* FALLTHRU */ 543 case DSYM_SNUMBER32: /* FALLTHRU */ 544 case DSYM_UNUMBER64: /* FALLTHRU */ 545 case DSYM_SNUMBER64: 546 547 if (result == NULL) { 548 *ierrnop = ITAB_BAD_NUMBER; 549 return (NULL); 550 } 551 552 is_signed = (ie->ds_type == DSYM_SNUMBER64 || 553 ie->ds_type == DSYM_SNUMBER32 || 554 ie->ds_type == DSYM_SNUMBER16 || 555 ie->ds_type == DSYM_SNUMBER8); 556 557 if (encode_number(n_entries, type_size, is_signed, 0, value, 558 result, ierrnop) == B_FALSE) { 559 free(result); 560 return (NULL); 561 } 562 break; 563 564 default: 565 if (ie->ds_type == DSYM_BOOL) 566 *ierrnop = ITAB_BAD_BOOLEAN; 567 else 568 *ierrnop = ITAB_SYNTAX_ERROR; 569 570 inittab_msg("inittab_encode: unsupported type `%d'", 571 ie->ds_type); 572 573 free(result); 574 return (NULL); 575 } 576 577 /* 578 * if just_payload is false, then we need to slide the option 579 * code and length fields in. (length includes them in its 580 * count, so we have to subtract 2) 581 */ 582 if (just_payload == B_FALSE) { 583 (void) memmove(result + 2, result, length - 2); 584 result[0] = ie->ds_code; 585 result[1] = length - 2; 586 } 587 588 if (lengthp != NULL) 589 *lengthp = length; 590 591 return (result); 592 } 593 594 /* 595 * inittab_decode_e(): converts a binary representation of a given datatype into 596 * a string; used for decoding DHCP options in a packet off 597 * the wire into ascii 598 * 599 * input: dhcp_symbol_t *: the entry describing the payload option 600 * uchar_t *: the payload to convert 601 * uint16_t: the payload length (only used if just_payload is true) 602 * boolean_t: if false, payload is assumed to be a DHCP option 603 * int *: set to extended error code if error occurs. 604 * output: char *: a dynamically allocated string containing the converted data 605 */ 606 char * 607 inittab_decode_e(dhcp_symbol_t *ie, uchar_t *payload, uint16_t length, 608 boolean_t just_payload, int *ierrnop) 609 { 610 char *resultp, *end, *result = NULL; 611 char *currp; 612 uchar_t n_entries; 613 struct in_addr in_addr; 614 uint8_t type_size = inittab_type_to_size(ie); 615 boolean_t is_signed; 616 617 *ierrnop = 0; 618 if (type_size == 0) { 619 *ierrnop = ITAB_SYNTAX_ERROR; 620 return (NULL); 621 } 622 623 if (just_payload == B_FALSE) { 624 length = payload[1]; 625 payload += 2; 626 } 627 628 /* 629 * figure out the number of elements to convert. note that 630 * for ds_type NUMBER, the granularity is really 1 since the 631 * value of ds_gran is the number of bytes in the number. 632 */ 633 if (ie->ds_type == DSYM_NUMBER) 634 n_entries = MIN(ie->ds_max, length / type_size); 635 else 636 n_entries = MIN(ie->ds_max * ie->ds_gran, length / type_size); 637 638 if (n_entries == 0) 639 n_entries = length / type_size; 640 641 if ((length % type_size) != 0) { 642 inittab_msg("inittab_decode: length of string not compatible " 643 "with option type `%i'", ie->ds_type); 644 *ierrnop = ITAB_BAD_STRING; 645 return (NULL); 646 } 647 648 switch (ie->ds_type) { 649 650 case DSYM_ASCII: 651 652 result = malloc(n_entries + 1); 653 if (result == NULL) { 654 *ierrnop = ITAB_NOMEM; 655 return (NULL); 656 } 657 658 (void) memcpy(result, payload, n_entries); 659 result[n_entries] = '\0'; 660 break; 661 662 case DSYM_OCTET: 663 664 result = malloc(n_entries * (sizeof ("0xNN") + 1)); 665 if (result == NULL) { 666 *ierrnop = ITAB_NOMEM; 667 return (NULL); 668 } 669 670 for (resultp = result; n_entries != 0; n_entries--) { 671 currp = resultp; 672 resultp += sprintf(resultp, "0x%02X ", *payload++); 673 if (currp == resultp) { 674 free(result); 675 *ierrnop = ITAB_BAD_OCTET; 676 return (NULL); 677 } 678 } 679 680 resultp[-1] = '\0'; 681 break; 682 683 case DSYM_IP: 684 685 if ((length / sizeof (ipaddr_t)) % ie->ds_gran != 0) { 686 *ierrnop = ITAB_BAD_GRAN; 687 inittab_msg("inittab_decode: number of entries " 688 "not compatible with option granularity"); 689 return (NULL); 690 } 691 692 result = malloc(n_entries * (sizeof ("aaa.bbb.ccc.ddd") + 1)); 693 end = &result[n_entries * (sizeof ("aaa.bbb.ccc.ddd") + 1)]; 694 if (result == NULL) { 695 *ierrnop = ITAB_NOMEM; 696 return (NULL); 697 } 698 699 for (resultp = result; n_entries != 0; n_entries--) { 700 (void) memcpy(&in_addr.s_addr, payload, 701 sizeof (ipaddr_t)); 702 currp = resultp; 703 resultp += snprintf(resultp, end - resultp, "%s ", 704 inet_ntoa(in_addr)); 705 if (currp == resultp) { 706 free(result); 707 *ierrnop = ITAB_BAD_IPADDR; 708 return (NULL); 709 } 710 payload += sizeof (ipaddr_t); 711 } 712 713 resultp[-1] = '\0'; 714 break; 715 716 case DSYM_NUMBER: /* FALLTHRU */ 717 case DSYM_UNUMBER8: /* FALLTHRU */ 718 case DSYM_SNUMBER8: /* FALLTHRU */ 719 case DSYM_UNUMBER16: /* FALLTHRU */ 720 case DSYM_SNUMBER16: /* FALLTHRU */ 721 case DSYM_UNUMBER32: /* FALLTHRU */ 722 case DSYM_SNUMBER32: /* FALLTHRU */ 723 case DSYM_UNUMBER64: /* FALLTHRU */ 724 case DSYM_SNUMBER64: 725 726 is_signed = (ie->ds_type == DSYM_SNUMBER64 || 727 ie->ds_type == DSYM_SNUMBER32 || 728 ie->ds_type == DSYM_SNUMBER16 || 729 ie->ds_type == DSYM_SNUMBER8); 730 731 result = malloc(n_entries * ITAB_MAX_NUMBER_LEN); 732 if (result == NULL) { 733 *ierrnop = ITAB_NOMEM; 734 return (NULL); 735 } 736 737 if (decode_number(n_entries, type_size, is_signed, ie->ds_gran, 738 payload, result, ierrnop) == B_FALSE) { 739 free(result); 740 return (NULL); 741 } 742 break; 743 744 default: 745 inittab_msg("inittab_decode: unsupported type `%d'", 746 ie->ds_type); 747 break; 748 } 749 750 return (result); 751 } 752 753 /* 754 * inittab_encode(): converts a string representation of a given datatype into 755 * binary; used for encoding ascii values into a form that 756 * can be put in DHCP packets to be sent on the wire. 757 * 758 * input: dhcp_symbol_t *: the entry describing the value option 759 * const char *: the value to convert 760 * uint16_t *: set to the length of the binary data returned 761 * boolean_t: if false, return a full DHCP option 762 * output: uchar_t *: a dynamically allocated byte array with converted data 763 */ 764 uchar_t * 765 inittab_encode(dhcp_symbol_t *ie, const char *value, uint16_t *lengthp, 766 boolean_t just_payload) 767 { 768 int ierrno; 769 770 return (inittab_encode_e(ie, value, lengthp, just_payload, &ierrno)); 771 } 772 773 /* 774 * inittab_decode(): converts a binary representation of a given datatype into 775 * a string; used for decoding DHCP options in a packet off 776 * the wire into ascii 777 * 778 * input: dhcp_symbol_t *: the entry describing the payload option 779 * uchar_t *: the payload to convert 780 * uint16_t: the payload length (only used if just_payload is true) 781 * boolean_t: if false, payload is assumed to be a DHCP option 782 * output: char *: a dynamically allocated string containing the converted data 783 */ 784 char * 785 inittab_decode(dhcp_symbol_t *ie, uchar_t *payload, uint16_t length, 786 boolean_t just_payload) 787 { 788 int ierrno; 789 790 return (inittab_decode_e(ie, payload, length, just_payload, &ierrno)); 791 } 792 793 /* 794 * inittab_msg(): prints diagnostic messages if INITTAB_DEBUG is set 795 * 796 * const char *: a printf-like format string 797 * ...: arguments to the format string 798 * output: void 799 */ 800 /*PRINTFLIKE1*/ 801 static void 802 inittab_msg(const char *fmt, ...) 803 { 804 enum { INITTAB_MSG_CHECK, INITTAB_MSG_RETURN, INITTAB_MSG_OUTPUT }; 805 806 va_list ap; 807 char buf[512]; 808 static int action = INITTAB_MSG_CHECK; 809 810 /* 811 * check DHCP_INITTAB_DEBUG the first time in; thereafter, use 812 * the the cached result (stored in `action'). 813 */ 814 switch (action) { 815 816 case INITTAB_MSG_CHECK: 817 818 if (getenv("DHCP_INITTAB_DEBUG") == NULL) { 819 action = INITTAB_MSG_RETURN; 820 return; 821 } 822 823 action = INITTAB_MSG_OUTPUT; 824 825 /* FALLTHRU into INITTAB_MSG_OUTPUT */ 826 827 case INITTAB_MSG_OUTPUT: 828 829 va_start(ap, fmt); 830 831 (void) snprintf(buf, sizeof (buf), "inittab: %s\n", fmt); 832 (void) vfprintf(stderr, buf, ap); 833 834 va_end(ap); 835 break; 836 837 case INITTAB_MSG_RETURN: 838 839 return; 840 } 841 } 842 843 /* 844 * decode_number(): decodes a sequence of numbers from binary into ascii; 845 * binary is coming off of the network, so it is in nbo 846 * 847 * input: uint8_t: the number of "granularity" numbers to decode 848 * uint8_t: the length of each number 849 * boolean_t: whether the numbers should be considered signed 850 * uint8_t: the number of numbers per granularity 851 * const uint8_t *: where to decode the numbers from 852 * char *: where to decode the numbers to 853 * output: boolean_t: true on successful conversion, false on failure 854 */ 855 static boolean_t 856 decode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed, 857 uint8_t granularity, const uint8_t *from, char *to, int *ierrnop) 858 { 859 uint16_t uint16; 860 uint32_t uint32; 861 uint64_t uint64; 862 863 if (granularity != 0) { 864 if ((granularity % n_entries) != 0) { 865 inittab_msg("decode_number: number of entries " 866 "not compatible with option granularity"); 867 *ierrnop = ITAB_BAD_GRAN; 868 return (B_FALSE); 869 } 870 } 871 872 for (; n_entries != 0; n_entries--, from += size) { 873 874 switch (size) { 875 876 case 1: 877 to += sprintf(to, is_signed ? "%d " : "%u ", *from); 878 break; 879 880 case 2: 881 (void) memcpy(&uint16, from, 2); 882 to += sprintf(to, is_signed ? "%hd " : "%hu ", 883 ntohs(uint16)); 884 break; 885 886 case 4: 887 (void) memcpy(&uint32, from, 4); 888 to += sprintf(to, is_signed ? "%ld " : "%lu ", 889 ntohl(uint32)); 890 break; 891 892 case 8: 893 (void) memcpy(&uint64, from, 8); 894 to += sprintf(to, is_signed ? "%lld " : "%llu ", 895 dhcp_ntohll(uint64)); 896 break; 897 898 default: 899 *ierrnop = ITAB_BAD_NUMBER; 900 inittab_msg("decode_number: unknown integer size `%d'", 901 size); 902 return (B_FALSE); 903 } 904 } 905 906 to[-1] = '\0'; 907 return (B_TRUE); 908 } 909 910 /* 911 * encode_number(): encodes a sequence of numbers from ascii into binary; 912 * number will end up on the wire so it needs to be in nbo 913 * 914 * input: uint8_t: the number of "granularity" numbers to encode 915 * uint8_t: the length of each number 916 * boolean_t: whether the numbers should be considered signed 917 * uint8_t: the number of numbers per granularity 918 * const uint8_t *: where to encode the numbers from 919 * char *: where to encode the numbers to 920 * int *: set to extended error code if error occurs. 921 * output: boolean_t: true on successful conversion, false on failure 922 */ 923 static boolean_t /* ARGSUSED */ 924 encode_number(uint8_t n_entries, uint8_t size, boolean_t is_signed, 925 uint8_t granularity, const char *from, uint8_t *to, int *ierrnop) 926 { 927 uint8_t i; 928 uint16_t uint16; 929 uint32_t uint32; 930 uint64_t uint64; 931 char *endptr; 932 933 if (granularity != 0) { 934 if ((granularity % n_entries) != 0) { 935 *ierrnop = ITAB_BAD_GRAN; 936 inittab_msg("encode_number: number of entries " 937 "not compatible with option granularity"); 938 return (B_FALSE); 939 } 940 } 941 942 for (i = 0; i < n_entries; i++, from++) { 943 944 /* 945 * totally obscure c factoid: it is legal to pass a 946 * string representing a negative number to strtoul(). 947 * in this case, strtoul() will return an unsigned 948 * long that if cast to a long, would represent the 949 * negative number. we take advantage of this to 950 * cut down on code here. 951 */ 952 953 errno = 0; 954 switch (size) { 955 956 case 1: 957 to[i] = strtoul(from, &endptr, 0); 958 if (errno != 0 || from == endptr) { 959 goto error; 960 } 961 break; 962 963 case 2: 964 uint16 = htons(strtoul(from, &endptr, 0)); 965 if (errno != 0 || from == endptr) { 966 goto error; 967 } 968 (void) memcpy(to + (i * 2), &uint16, 2); 969 break; 970 971 case 4: 972 uint32 = htonl(strtoul(from, &endptr, 0)); 973 if (errno != 0 || from == endptr) { 974 goto error; 975 } 976 (void) memcpy(to + (i * 4), &uint32, 4); 977 break; 978 979 case 8: 980 uint64 = dhcp_htonll(strtoull(from, &endptr, 0)); 981 if (errno != 0 || from == endptr) { 982 goto error; 983 } 984 (void) memcpy(to + (i * 8), &uint64, 8); 985 break; 986 987 default: 988 inittab_msg("encode_number: unsupported integer " 989 "size `%d'", size); 990 return (B_FALSE); 991 } 992 993 from = strchr(from, ' '); 994 if (from == NULL) 995 break; 996 } 997 998 return (B_TRUE); 999 1000 error: 1001 *ierrnop = ITAB_BAD_NUMBER; 1002 inittab_msg("encode_number: cannot convert to integer"); 1003 return (B_FALSE); 1004 } 1005 1006 /* 1007 * inittab_type_to_size(): given an inittab entry, returns size of one entry of 1008 * its type 1009 * 1010 * input: dhcp_symbol_t *: an entry of the given type 1011 * output: uint8_t: the size in bytes of an entry of that type 1012 */ 1013 uint8_t 1014 inittab_type_to_size(dhcp_symbol_t *ie) 1015 { 1016 switch (ie->ds_type) { 1017 1018 case DSYM_ASCII: 1019 case DSYM_OCTET: 1020 case DSYM_SNUMBER8: 1021 case DSYM_UNUMBER8: 1022 1023 return (1); 1024 1025 case DSYM_SNUMBER16: 1026 case DSYM_UNUMBER16: 1027 1028 return (2); 1029 1030 case DSYM_SNUMBER32: 1031 case DSYM_UNUMBER32: 1032 case DSYM_IP: 1033 1034 return (4); 1035 1036 case DSYM_SNUMBER64: 1037 case DSYM_UNUMBER64: 1038 1039 return (8); 1040 1041 case DSYM_NUMBER: 1042 1043 return (ie->ds_gran); 1044 } 1045 1046 return (0); 1047 } 1048 1049 /* 1050 * itabcode_to_dsymcode(): maps an inittab category code to its dsym 1051 * representation 1052 * 1053 * input: uchar_t: the inittab category code 1054 * output: dsym_category_t: the dsym category code 1055 */ 1056 static dsym_category_t 1057 itabcode_to_dsymcode(uchar_t itabcode) 1058 { 1059 1060 unsigned int i; 1061 1062 for (i = 0; i < ITAB_CAT_COUNT; i++) 1063 if (category_map[i].cme_itabcode == itabcode) 1064 return (category_map[i].cme_dsymcode); 1065 1066 return (DSYM_BAD_CAT); 1067 } 1068 1069 /* 1070 * category_to_code(): maps a category name to its numeric representation 1071 * 1072 * input: const char *: the category name 1073 * output: uchar_t: its internal code (numeric representation) 1074 */ 1075 static uchar_t 1076 category_to_code(const char *category) 1077 { 1078 unsigned int i; 1079 1080 for (i = 0; i < ITAB_CAT_COUNT; i++) 1081 if (strcasecmp(category_map[i].cme_name, category) == 0) 1082 return (category_map[i].cme_itabcode); 1083 1084 return (0); 1085 } 1086 1087 /* 1088 * dhcp_htonll(): converts a 64-bit number from host to network byte order 1089 * 1090 * input: uint64_t: the number to convert 1091 * output: uint64_t: its value in network byte order 1092 */ 1093 static uint64_t 1094 dhcp_htonll(uint64_t uint64_hbo) 1095 { 1096 return (dhcp_ntohll(uint64_hbo)); 1097 } 1098 1099 /* 1100 * dhcp_ntohll(): converts a 64-bit number from network to host byte order 1101 * 1102 * input: uint64_t: the number to convert 1103 * output: uint64_t: its value in host byte order 1104 */ 1105 static uint64_t 1106 dhcp_ntohll(uint64_t uint64_nbo) 1107 { 1108 #ifdef _LITTLE_ENDIAN 1109 return ((uint64_t)ntohl(uint64_nbo & 0xffffffff) << 32 | 1110 ntohl(uint64_nbo >> 32)); 1111 #else 1112 return (uint64_nbo); 1113 #endif 1114 } 1115 1116 /* 1117 * our internal table of DHCP option values, used by inittab_verify() 1118 */ 1119 static dhcp_symbol_t inittab_table[] = 1120 { 1121 { DSYM_INTERNAL, 1024, "Hostname", DSYM_BOOL, 0, 0 }, 1122 { DSYM_INTERNAL, 1025, "LeaseNeg", DSYM_BOOL, 0, 0 }, 1123 { DSYM_INTERNAL, 1026, "EchoVC", DSYM_BOOL, 0, 0 }, 1124 { DSYM_INTERNAL, 1027, "BootPath", DSYM_ASCII, 1, 128 }, 1125 { DSYM_FIELD, 0, "Opcode", DSYM_UNUMBER8, 1, 1 }, 1126 { DSYM_FIELD, 1, "Htype", DSYM_UNUMBER8, 1, 1 }, 1127 { DSYM_FIELD, 2, "HLen", DSYM_UNUMBER8, 1, 1 }, 1128 { DSYM_FIELD, 3, "Hops", DSYM_UNUMBER8, 1, 1 }, 1129 { DSYM_FIELD, 4, "Xid", DSYM_UNUMBER32, 1, 1 }, 1130 { DSYM_FIELD, 8, "Secs", DSYM_UNUMBER16, 1, 1 }, 1131 { DSYM_FIELD, 10, "Flags", DSYM_OCTET, 1, 2 }, 1132 { DSYM_FIELD, 12, "Ciaddr", DSYM_IP, 1, 1 }, 1133 { DSYM_FIELD, 16, "Yiaddr", DSYM_IP, 1, 1 }, 1134 { DSYM_FIELD, 20, "BootSrvA", DSYM_IP, 1, 1 }, 1135 { DSYM_FIELD, 24, "Giaddr", DSYM_IP, 1, 1 }, 1136 { DSYM_FIELD, 28, "Chaddr", DSYM_OCTET, 1, 16 }, 1137 { DSYM_FIELD, 44, "BootSrvN", DSYM_ASCII, 1, 64 }, 1138 { DSYM_FIELD, 108, "BootFile", DSYM_ASCII, 1, 128 }, 1139 { DSYM_FIELD, 236, "Magic", DSYM_OCTET, 1, 4 }, 1140 { DSYM_FIELD, 240, "Options", DSYM_OCTET, 1, 60 }, 1141 { DSYM_STANDARD, 1, "Subnet", DSYM_IP, 1, 1 }, 1142 { DSYM_STANDARD, 2, "UTCoffst", DSYM_SNUMBER32, 1, 1 }, 1143 { DSYM_STANDARD, 3, "Router", DSYM_IP, 1, 0 }, 1144 { DSYM_STANDARD, 4, "Timeserv", DSYM_IP, 1, 0 }, 1145 { DSYM_STANDARD, 5, "IEN116ns", DSYM_IP, 1, 0 }, 1146 { DSYM_STANDARD, 6, "DNSserv", DSYM_IP, 1, 0 }, 1147 { DSYM_STANDARD, 7, "Logserv", DSYM_IP, 1, 0 }, 1148 { DSYM_STANDARD, 8, "Cookie", DSYM_IP, 1, 0 }, 1149 { DSYM_STANDARD, 9, "Lprserv", DSYM_IP, 1, 0 }, 1150 { DSYM_STANDARD, 10, "Impress", DSYM_IP, 1, 0 }, 1151 { DSYM_STANDARD, 11, "Resource", DSYM_IP, 1, 0 }, 1152 { DSYM_STANDARD, 12, "Hostname", DSYM_ASCII, 1, 0 }, 1153 { DSYM_STANDARD, 13, "Bootsize", DSYM_UNUMBER16, 1, 1 }, 1154 { DSYM_STANDARD, 14, "Dumpfile", DSYM_ASCII, 1, 0 }, 1155 { DSYM_STANDARD, 15, "DNSdmain", DSYM_ASCII, 1, 0 }, 1156 { DSYM_STANDARD, 16, "Swapserv", DSYM_IP, 1, 1 }, 1157 { DSYM_STANDARD, 17, "Rootpath", DSYM_ASCII, 1, 0 }, 1158 { DSYM_STANDARD, 18, "ExtendP", DSYM_ASCII, 1, 0 }, 1159 { DSYM_STANDARD, 19, "IpFwdF", DSYM_UNUMBER8, 1, 1 }, 1160 { DSYM_STANDARD, 20, "NLrouteF", DSYM_UNUMBER8, 1, 1 }, 1161 { DSYM_STANDARD, 21, "PFilter", DSYM_IP, 2, 0 }, 1162 { DSYM_STANDARD, 22, "MaxIpSiz", DSYM_UNUMBER16, 1, 1 }, 1163 { DSYM_STANDARD, 23, "IpTTL", DSYM_UNUMBER8, 1, 1 }, 1164 { DSYM_STANDARD, 24, "PathTO", DSYM_UNUMBER32, 1, 1 }, 1165 { DSYM_STANDARD, 25, "PathTbl", DSYM_UNUMBER16, 1, 0 }, 1166 { DSYM_STANDARD, 26, "MTU", DSYM_UNUMBER16, 1, 1 }, 1167 { DSYM_STANDARD, 27, "SameMtuF", DSYM_UNUMBER8, 1, 1 }, 1168 { DSYM_STANDARD, 28, "Broadcst", DSYM_IP, 1, 1 }, 1169 { DSYM_STANDARD, 29, "MaskDscF", DSYM_UNUMBER8, 1, 1 }, 1170 { DSYM_STANDARD, 30, "MaskSupF", DSYM_UNUMBER8, 1, 1 }, 1171 { DSYM_STANDARD, 31, "RDiscvyF", DSYM_UNUMBER8, 1, 1 }, 1172 { DSYM_STANDARD, 32, "RSolictS", DSYM_IP, 1, 1 }, 1173 { DSYM_STANDARD, 33, "StaticRt", DSYM_IP, 2, 0 }, 1174 { DSYM_STANDARD, 34, "TrailerF", DSYM_UNUMBER8, 1, 1 }, 1175 { DSYM_STANDARD, 35, "ArpTimeO", DSYM_UNUMBER32, 1, 1 }, 1176 { DSYM_STANDARD, 36, "EthEncap", DSYM_UNUMBER8, 1, 1 }, 1177 { DSYM_STANDARD, 37, "TcpTTL", DSYM_UNUMBER8, 1, 1 }, 1178 { DSYM_STANDARD, 38, "TcpKaInt", DSYM_UNUMBER32, 1, 1 }, 1179 { DSYM_STANDARD, 39, "TcpKaGbF", DSYM_UNUMBER8, 1, 1 }, 1180 { DSYM_STANDARD, 40, "NISdmain", DSYM_ASCII, 1, 0 }, 1181 { DSYM_STANDARD, 41, "NISservs", DSYM_IP, 1, 0 }, 1182 { DSYM_STANDARD, 42, "NTPservs", DSYM_IP, 1, 0 }, 1183 { DSYM_STANDARD, 43, "Vendor", DSYM_OCTET, 1, 0 }, 1184 { DSYM_STANDARD, 44, "NetBNms", DSYM_IP, 1, 0 }, 1185 { DSYM_STANDARD, 45, "NetBDsts", DSYM_IP, 1, 0 }, 1186 { DSYM_STANDARD, 46, "NetBNdT", DSYM_UNUMBER8, 1, 1 }, 1187 { DSYM_STANDARD, 47, "NetBScop", DSYM_ASCII, 1, 0 }, 1188 { DSYM_STANDARD, 48, "XFontSrv", DSYM_IP, 1, 0 }, 1189 { DSYM_STANDARD, 49, "XDispMgr", DSYM_IP, 1, 0 }, 1190 { DSYM_STANDARD, 50, "ReqIP", DSYM_IP, 1, 1 }, 1191 { DSYM_STANDARD, 51, "LeaseTim", DSYM_UNUMBER32, 1, 1 }, 1192 { DSYM_STANDARD, 52, "OptOvrld", DSYM_UNUMBER8, 1, 1 }, 1193 { DSYM_STANDARD, 53, "DHCPType", DSYM_UNUMBER8, 1, 1 }, 1194 { DSYM_STANDARD, 54, "ServerID", DSYM_IP, 1, 1 }, 1195 { DSYM_STANDARD, 55, "ReqList", DSYM_OCTET, 1, 0 }, 1196 { DSYM_STANDARD, 56, "Message", DSYM_ASCII, 1, 0 }, 1197 { DSYM_STANDARD, 57, "DHCP_MTU", DSYM_UNUMBER16, 1, 1 }, 1198 { DSYM_STANDARD, 58, "T1Time", DSYM_UNUMBER32, 1, 1 }, 1199 { DSYM_STANDARD, 59, "T2Time", DSYM_UNUMBER32, 1, 1 }, 1200 { DSYM_STANDARD, 60, "ClassID", DSYM_ASCII, 1, 0 }, 1201 { DSYM_STANDARD, 61, "ClientID", DSYM_OCTET, 1, 0 }, 1202 { DSYM_STANDARD, 62, "NW_dmain", DSYM_ASCII, 1, 0 }, 1203 { DSYM_STANDARD, 63, "NWIPOpts", DSYM_OCTET, 1, 128 }, 1204 { DSYM_STANDARD, 64, "NIS+dom", DSYM_ASCII, 1, 0 }, 1205 { DSYM_STANDARD, 65, "NIS+serv", DSYM_IP, 1, 0 }, 1206 { DSYM_STANDARD, 66, "TFTPsrvN", DSYM_ASCII, 1, 64 }, 1207 { DSYM_STANDARD, 67, "OptBootF", DSYM_ASCII, 1, 128 }, 1208 { DSYM_STANDARD, 68, "MblIPAgt", DSYM_IP, 1, 0 }, 1209 { DSYM_STANDARD, 69, "SMTPserv", DSYM_IP, 1, 0 }, 1210 { DSYM_STANDARD, 70, "POP3serv", DSYM_IP, 1, 0 }, 1211 { DSYM_STANDARD, 71, "NNTPserv", DSYM_IP, 1, 0 }, 1212 { DSYM_STANDARD, 72, "WWWservs", DSYM_IP, 1, 0 }, 1213 { DSYM_STANDARD, 73, "Fingersv", DSYM_IP, 1, 0 }, 1214 { DSYM_STANDARD, 74, "IRCservs", DSYM_IP, 1, 0 }, 1215 { DSYM_STANDARD, 75, "STservs", DSYM_IP, 1, 0 }, 1216 { DSYM_STANDARD, 76, "STDAservs", DSYM_IP, 1, 0 }, 1217 { DSYM_STANDARD, 77, "UserClas", DSYM_ASCII, 1, 0 }, 1218 { DSYM_STANDARD, 78, "SLP_DA", DSYM_OCTET, 1, 0 }, 1219 { DSYM_STANDARD, 79, "SLP_SS", DSYM_OCTET, 1, 0 }, 1220 { DSYM_STANDARD, 82, "AgentOpt", DSYM_OCTET, 1, 0 }, 1221 { DSYM_STANDARD, 89, "FQDN", DSYM_OCTET, 1, 0 }, 1222 { 0, 0, "", 0, 0, 0 } 1223 }; 1224