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