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