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