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_bind(dh, DLPI_ANY_SAP, NULL) !=
511 DLPI_SUCCESS || dlpi_info(dh, &dlinfo, 0) !=
512 DLPI_SUCCESS) {
513 dlpi_close(dh);
514 goto failed;
515 }
516 maclen = dlinfo.di_physaddrlen;
517 (void) memcpy(outbuf, dlinfo.di_physaddr, maclen);
518 dlpi_close(dh);
519 if (hwtype == -1)
520 hwtype = dlpi_arptype(dlinfo.di_mactype);
521 }
522 }
523 if (hwtype == -1)
524 goto failed;
525 *hwret = htons(hwtype);
526 return (maclen);
527
528 failed:
529 *ierrnop = ITAB_BAD_NUMBER;
530 return (-1);
531 }
532
533 /*
534 * inittab_encode_e(): converts a string representation of a given datatype into
535 * binary; used for encoding ascii values into a form that
536 * can be put in DHCP packets to be sent on the wire.
537 *
538 * input: const dhcp_symbol_t *: the entry describing the value option
539 * const char *: the value to convert
540 * uint16_t *: set to the length of the binary data returned
541 * boolean_t: if false, return a full DHCP option
542 * int *: error return value
543 * output: uchar_t *: a dynamically allocated byte array with converted data
544 */
545
546 uchar_t *
inittab_encode_e(const dhcp_symbol_t * ie,const char * value,uint16_t * lengthp,boolean_t just_payload,int * ierrnop)547 inittab_encode_e(const dhcp_symbol_t *ie, const char *value, uint16_t *lengthp,
548 boolean_t just_payload, int *ierrnop)
549 {
550 int hlen = 0;
551 uint16_t length;
552 uchar_t n_entries = 0;
553 const char *valuep;
554 char *currp;
555 uchar_t *result = NULL;
556 uchar_t *optstart;
557 unsigned int i;
558 uint8_t type_size = inittab_type_to_size(ie);
559 boolean_t is_signed;
560 uint_t vallen, reslen;
561 dhcpv6_option_t *d6o;
562 int type;
563 char *cp2;
564
565 *ierrnop = 0;
566 if (type_size == 0) {
567 *ierrnop = ITAB_SYNTAX_ERROR;
568 return (NULL);
569 }
570
571 switch (ie->ds_type) {
572 case DSYM_ASCII:
573 n_entries = strlen(value); /* no NUL */
574 break;
575
576 case DSYM_OCTET:
577 vallen = strlen(value);
578 n_entries = vallen / 2;
579 n_entries += vallen % 2;
580 break;
581
582 case DSYM_DOMAIN:
583 /*
584 * Maximum (worst-case) encoded length is one byte more than
585 * the number of characters on input.
586 */
587 n_entries = strlen(value) + 1;
588 break;
589
590 case DSYM_DUID:
591 /* Worst case is ":::::" */
592 n_entries = strlen(value);
593 if (n_entries < DLPI_PHYSADDR_MAX)
594 n_entries = DLPI_PHYSADDR_MAX;
595 n_entries += sizeof (duid_llt_t);
596 break;
597
598 default:
599 /*
600 * figure out the number of entries by counting the spaces
601 * in the value string
602 */
603 for (valuep = value; valuep++ != NULL; n_entries++)
604 valuep = strchr(valuep, ' ');
605 break;
606 }
607
608 /*
609 * if we're gonna return a complete option, then include the
610 * option length and code in the size of the packet we allocate
611 */
612 if (!just_payload)
613 hlen = ie->ds_dhcpv6 ? sizeof (*d6o) : 2;
614
615 length = n_entries * type_size;
616 if (hlen + length > 0)
617 result = malloc(hlen + length);
618
619 if ((optstart = result) != NULL && !just_payload)
620 optstart += hlen;
621
622 switch (ie->ds_type) {
623
624 case DSYM_ASCII:
625
626 if (optstart == NULL) {
627 *ierrnop = ITAB_NOMEM;
628 return (NULL);
629 }
630
631 (void) memcpy(optstart, value, length);
632 break;
633
634 case DSYM_DOMAIN:
635 if (optstart == NULL) {
636 *ierrnop = ITAB_NOMEM;
637 return (NULL);
638 }
639
640 /*
641 * Note that this encoder always presents the trailing 0-octet
642 * when dealing with a list. This means that you can't have
643 * non-fully-qualified members anywhere but at the end of a
644 * list (or as the only member of the list).
645 */
646 valuep = value;
647 while (*valuep != '\0') {
648 int dig, val, inchr;
649 boolean_t escape;
650 uchar_t *flen;
651
652 /*
653 * Skip over whitespace that delimits list members.
654 */
655 if (isascii(*valuep) && isspace(*valuep)) {
656 valuep++;
657 continue;
658 }
659 dig = val = 0;
660 escape = B_FALSE;
661 flen = optstart++;
662 while ((inchr = *valuep) != '\0') {
663 valuep++;
664 /*
665 * Just copy non-ASCII text directly to the
666 * output string. This simplifies the use of
667 * other ctype macros below, as, unlike the
668 * special isascii function, they don't handle
669 * non-ASCII.
670 */
671 if (!isascii(inchr)) {
672 escape = B_FALSE;
673 *optstart++ = inchr;
674 continue;
675 }
676 if (escape) {
677 /*
678 * Handle any of \D, \DD, or \DDD for
679 * a digit escape.
680 */
681 if (isdigit(inchr)) {
682 val = val * 10 + inchr - '0';
683 if (++dig == 3) {
684 *optstart++ = val;
685 dig = val = 0;
686 escape = B_FALSE;
687 }
688 continue;
689 } else if (dig > 0) {
690 /*
691 * User terminated \D or \DD
692 * with non-digit. An error,
693 * but we can assume he means
694 * to treat as \00D or \0DD.
695 */
696 *optstart++ = val;
697 dig = val = 0;
698 }
699 /* Fall through and copy character */
700 escape = B_FALSE;
701 } else if (inchr == '\\') {
702 escape = B_TRUE;
703 continue;
704 } else if (inchr == '.') {
705 /*
706 * End of component. Write the length
707 * prefix. If the component is zero
708 * length (i.e., ".."), the just omit
709 * it.
710 */
711 *flen = (optstart - flen) - 1;
712 if (*flen > 0)
713 flen = optstart++;
714 continue;
715 } else if (isspace(inchr)) {
716 /*
717 * Unescaped space; end of domain name
718 * in list.
719 */
720 break;
721 }
722 *optstart++ = inchr;
723 }
724 /*
725 * Handle trailing escape sequence. If string ends
726 * with \, then assume user wants \ at end of encoded
727 * string. If it ends with \D or \DD, assume \00D or
728 * \0DD.
729 */
730 if (escape)
731 *optstart++ = dig > 0 ? val : '\\';
732 *flen = (optstart - flen) - 1;
733 /*
734 * If user specified FQDN with trailing '.', then above
735 * will result in zero for the last component length.
736 * We're done, and optstart already points to the start
737 * of the next in list. Otherwise, we need to write a
738 * single zero byte to end the entry, if there are more
739 * entries that will be decoded.
740 */
741 while (isascii(*valuep) && isspace(*valuep))
742 valuep++;
743 if (*flen > 0 && *valuep != '\0')
744 *optstart++ = '\0';
745 }
746 length = (optstart - result) - hlen;
747 break;
748
749 case DSYM_DUID:
750 if (optstart == NULL) {
751 *ierrnop = ITAB_NOMEM;
752 return (NULL);
753 }
754
755 errno = 0;
756 type = strtoul(value, &currp, 0);
757 if (errno != 0 || value == currp || type > 65535 ||
758 (*currp != ',' && *currp != '\0')) {
759 free(result);
760 *ierrnop = ITAB_BAD_NUMBER;
761 return (NULL);
762 }
763 switch (type) {
764 case DHCPV6_DUID_LLT: {
765 duid_llt_t dllt;
766 int hwtype;
767 ulong_t tstamp;
768 int maclen;
769
770 if ((hwtype = get_hw_type(&currp, ierrnop)) == -2) {
771 free(result);
772 return (NULL);
773 }
774 if (*currp++ != ',') {
775 free(result);
776 *ierrnop = ITAB_BAD_NUMBER;
777 return (NULL);
778 }
779 if (*currp == ',' || *currp == '\0') {
780 tstamp = time(NULL) - DUID_TIME_BASE;
781 } else {
782 tstamp = strtoul(currp, &cp2, 0);
783 if (errno != 0 || currp == cp2) {
784 free(result);
785 *ierrnop = ITAB_BAD_NUMBER;
786 return (NULL);
787 }
788 currp = cp2;
789 }
790 maclen = get_mac_addr(currp, ierrnop,
791 &dllt.dllt_hwtype, hwtype,
792 optstart + sizeof (dllt));
793 if (maclen == -1) {
794 free(result);
795 return (NULL);
796 }
797 dllt.dllt_dutype = htons(type);
798 dllt.dllt_time = htonl(tstamp);
799 (void) memcpy(optstart, &dllt, sizeof (dllt));
800 length = maclen + sizeof (dllt);
801 break;
802 }
803 case DHCPV6_DUID_EN: {
804 duid_en_t den;
805 ulong_t enterp;
806
807 if (*currp++ != ',') {
808 free(result);
809 *ierrnop = ITAB_BAD_NUMBER;
810 return (NULL);
811 }
812 enterp = strtoul(currp, &cp2, 0);
813 DHCPV6_SET_ENTNUM(&den, enterp);
814 if (errno != 0 || currp == cp2 ||
815 enterp != DHCPV6_GET_ENTNUM(&den) ||
816 (*cp2 != ',' && *cp2 != '\0')) {
817 free(result);
818 *ierrnop = ITAB_BAD_NUMBER;
819 return (NULL);
820 }
821 if (*cp2 == ',')
822 cp2++;
823 vallen = strlen(cp2);
824 reslen = (vallen + 1) / 2;
825 if (hexascii_to_octet(cp2, vallen,
826 optstart + sizeof (den), &reslen) != 0) {
827 free(result);
828 *ierrnop = ITAB_BAD_NUMBER;
829 return (NULL);
830 }
831 den.den_dutype = htons(type);
832 (void) memcpy(optstart, &den, sizeof (den));
833 length = reslen + sizeof (den);
834 break;
835 }
836 case DHCPV6_DUID_LL: {
837 duid_ll_t dll;
838 int hwtype;
839 int maclen;
840
841 if ((hwtype = get_hw_type(&currp, ierrnop)) == -2) {
842 free(result);
843 return (NULL);
844 }
845 maclen = get_mac_addr(currp, ierrnop, &dll.dll_hwtype,
846 hwtype, optstart + sizeof (dll));
847 if (maclen == -1) {
848 free(result);
849 return (NULL);
850 }
851 dll.dll_dutype = htons(type);
852 (void) memcpy(optstart, &dll, sizeof (dll));
853 length = maclen + sizeof (dll);
854 break;
855 }
856 default:
857 if (*currp == ',')
858 currp++;
859 vallen = strlen(currp);
860 reslen = (vallen + 1) / 2;
861 if (hexascii_to_octet(currp, vallen, optstart + 2,
862 &reslen) != 0) {
863 free(result);
864 *ierrnop = ITAB_BAD_NUMBER;
865 return (NULL);
866 }
867 optstart[0] = type >> 8;
868 optstart[1] = type;
869 length = reslen + 2;
870 break;
871 }
872 break;
873
874 case DSYM_OCTET:
875
876 if (optstart == NULL) {
877 *ierrnop = ITAB_BAD_OCTET;
878 return (NULL);
879 }
880
881 reslen = length;
882 /* Call libinetutil function to decode */
883 if (hexascii_to_octet(value, vallen, optstart, &reslen) != 0) {
884 free(result);
885 *ierrnop = ITAB_BAD_OCTET;
886 return (NULL);
887 }
888 break;
889
890 case DSYM_IP:
891 case DSYM_IPV6:
892
893 if (optstart == NULL) {
894 *ierrnop = ITAB_BAD_IPADDR;
895 return (NULL);
896 }
897 if (n_entries % ie->ds_gran != 0) {
898 *ierrnop = ITAB_BAD_GRAN;
899 inittab_msg("inittab_encode: number of entries "
900 "not compatible with option granularity");
901 free(result);
902 return (NULL);
903 }
904
905 for (valuep = value, i = 0; i < n_entries; i++, valuep++) {
906
907 currp = strchr(valuep, ' ');
908 if (currp != NULL)
909 *currp = '\0';
910 if (inet_pton(ie->ds_type == DSYM_IP ? AF_INET :
911 AF_INET6, valuep, optstart) != 1) {
912 *ierrnop = ITAB_BAD_IPADDR;
913 inittab_msg("inittab_encode: bogus ip address");
914 free(result);
915 return (NULL);
916 }
917
918 valuep = currp;
919 if (valuep == NULL) {
920 if (i < (n_entries - 1)) {
921 *ierrnop = ITAB_NOT_ENOUGH_IP;
922 inittab_msg("inittab_encode: too few "
923 "ip addresses");
924 free(result);
925 return (NULL);
926 }
927 break;
928 }
929 optstart += type_size;
930 }
931 break;
932
933 case DSYM_NUMBER: /* FALLTHRU */
934 case DSYM_UNUMBER8: /* FALLTHRU */
935 case DSYM_SNUMBER8: /* FALLTHRU */
936 case DSYM_UNUMBER16: /* FALLTHRU */
937 case DSYM_SNUMBER16: /* FALLTHRU */
938 case DSYM_UNUMBER24: /* FALLTHRU */
939 case DSYM_UNUMBER32: /* FALLTHRU */
940 case DSYM_SNUMBER32: /* FALLTHRU */
941 case DSYM_UNUMBER64: /* FALLTHRU */
942 case DSYM_SNUMBER64:
943
944 if (optstart == NULL) {
945 *ierrnop = ITAB_BAD_NUMBER;
946 return (NULL);
947 }
948
949 is_signed = (ie->ds_type == DSYM_SNUMBER64 ||
950 ie->ds_type == DSYM_SNUMBER32 ||
951 ie->ds_type == DSYM_SNUMBER16 ||
952 ie->ds_type == DSYM_SNUMBER8);
953
954 if (encode_number(n_entries, type_size, is_signed, 0, value,
955 optstart, ierrnop) == B_FALSE) {
956 free(result);
957 return (NULL);
958 }
959 break;
960
961 default:
962 if (ie->ds_type == DSYM_BOOL)
963 *ierrnop = ITAB_BAD_BOOLEAN;
964 else
965 *ierrnop = ITAB_SYNTAX_ERROR;
966
967 inittab_msg("inittab_encode: unsupported type `%d'",
968 ie->ds_type);
969
970 free(result);
971 return (NULL);
972 }
973
974 /*
975 * if just_payload is false, then we need to add the option
976 * code and length fields in.
977 */
978 if (!just_payload) {
979 if (ie->ds_dhcpv6) {
980 /* LINTED: alignment */
981 d6o = (dhcpv6_option_t *)result;
982 d6o->d6o_code = htons(ie->ds_code);
983 d6o->d6o_len = htons(length);
984 } else {
985 result[0] = ie->ds_code;
986 result[1] = length;
987 }
988 }
989
990 if (lengthp != NULL)
991 *lengthp = length + hlen;
992
993 return (result);
994 }
995
996 /*
997 * inittab_decode_e(): converts a binary representation of a given datatype into
998 * a string; used for decoding DHCP options in a packet off
999 * the wire into ascii
1000 *
1001 * input: dhcp_symbol_t *: the entry describing the payload option
1002 * uchar_t *: the payload to convert
1003 * uint16_t: the payload length (only used if just_payload is true)
1004 * boolean_t: if false, payload is assumed to be a DHCP option
1005 * int *: set to extended error code if error occurs.
1006 * output: char *: a dynamically allocated string containing the converted data
1007 */
1008
1009 char *
inittab_decode_e(const dhcp_symbol_t * ie,const uchar_t * payload,uint16_t length,boolean_t just_payload,int * ierrnop)1010 inittab_decode_e(const dhcp_symbol_t *ie, const uchar_t *payload,
1011 uint16_t length, boolean_t just_payload, int *ierrnop)
1012 {
1013 char *resultp, *result = NULL;
1014 uint_t n_entries;
1015 struct in_addr in_addr;
1016 in6_addr_t in6_addr;
1017 uint8_t type_size = inittab_type_to_size(ie);
1018 boolean_t is_signed;
1019 int type;
1020
1021 *ierrnop = 0;
1022 if (type_size == 0) {
1023 *ierrnop = ITAB_SYNTAX_ERROR;
1024 return (NULL);
1025 }
1026
1027 if (!just_payload) {
1028 if (ie->ds_dhcpv6) {
1029 dhcpv6_option_t d6o;
1030
1031 (void) memcpy(&d6o, payload, sizeof (d6o));
1032 length = ntohs(d6o.d6o_len);
1033 payload += sizeof (d6o);
1034 } else {
1035 length = payload[1];
1036 payload += 2;
1037 }
1038 }
1039
1040 /*
1041 * figure out the number of elements to convert. note that
1042 * for ds_type NUMBER, the granularity is really 1 since the
1043 * value of ds_gran is the number of bytes in the number.
1044 */
1045 if (ie->ds_type == DSYM_NUMBER)
1046 n_entries = MIN(ie->ds_max, length / type_size);
1047 else
1048 n_entries = MIN(ie->ds_max * ie->ds_gran, length / type_size);
1049
1050 if (n_entries == 0)
1051 n_entries = length / type_size;
1052
1053 if ((length % type_size) != 0) {
1054 inittab_msg("inittab_decode: length of string not compatible "
1055 "with option type `%i'", ie->ds_type);
1056 *ierrnop = ITAB_BAD_STRING;
1057 return (NULL);
1058 }
1059
1060 switch (ie->ds_type) {
1061
1062 case DSYM_ASCII:
1063
1064 result = malloc(n_entries + 1);
1065 if (result == NULL) {
1066 *ierrnop = ITAB_NOMEM;
1067 return (NULL);
1068 }
1069
1070 (void) memcpy(result, payload, n_entries);
1071 result[n_entries] = '\0';
1072 break;
1073
1074 case DSYM_DOMAIN:
1075
1076 /*
1077 * A valid, decoded RFC 1035 domain string or sequence of
1078 * strings is always the same size as the encoded form, but we
1079 * allow for RFC 1035 \DDD and \\ and \. escaping.
1080 *
1081 * Decoding stops at the end of the input or the first coding
1082 * violation. Coding violations result in discarding the
1083 * offending list entry entirely. Note that we ignore the 255
1084 * character overall limit on domain names.
1085 */
1086 if ((result = malloc(4 * length + 1)) == NULL) {
1087 *ierrnop = ITAB_NOMEM;
1088 return (NULL);
1089 }
1090 resultp = result;
1091 while (length > 0) {
1092 char *dstart;
1093 int slen;
1094
1095 dstart = resultp;
1096 while (length > 0) {
1097 slen = *payload++;
1098 length--;
1099 /* Upper two bits of length must be zero */
1100 if ((slen & 0xc0) != 0 || slen > length) {
1101 length = 0;
1102 resultp = dstart;
1103 break;
1104 }
1105 if (resultp != dstart)
1106 *resultp++ = '.';
1107 if (slen == 0)
1108 break;
1109 length -= slen;
1110 while (slen > 0) {
1111 if (!isascii(*payload) ||
1112 !isgraph(*payload)) {
1113 (void) snprintf(resultp, 5,
1114 "\\%03d",
1115 *(unsigned char *)payload);
1116 resultp += 4;
1117 payload++;
1118 } else {
1119 if (*payload == '.' ||
1120 *payload == '\\')
1121 *resultp++ = '\\';
1122 *resultp++ = *payload++;
1123 }
1124 slen--;
1125 }
1126 }
1127 if (resultp != dstart && length > 0)
1128 *resultp++ = ' ';
1129 }
1130 *resultp = '\0';
1131 break;
1132
1133 case DSYM_DUID:
1134
1135 /*
1136 * First, determine the type of DUID. We need at least two
1137 * octets worth of data to grab the type code. Once we have
1138 * that, the number of octets required for representation
1139 * depends on the type.
1140 */
1141
1142 if (length < 2) {
1143 *ierrnop = ITAB_BAD_GRAN;
1144 return (NULL);
1145 }
1146 type = (payload[0] << 8) + payload[1];
1147 switch (type) {
1148 case DHCPV6_DUID_LLT: {
1149 duid_llt_t dllt;
1150
1151 if (length < sizeof (dllt)) {
1152 *ierrnop = ITAB_BAD_GRAN;
1153 return (NULL);
1154 }
1155 (void) memcpy(&dllt, payload, sizeof (dllt));
1156 payload += sizeof (dllt);
1157 length -= sizeof (dllt);
1158 n_entries = sizeof ("1,65535,4294967295,") +
1159 length * 3;
1160 if ((result = malloc(n_entries)) == NULL) {
1161 *ierrnop = ITAB_NOMEM;
1162 return (NULL);
1163 }
1164 (void) snprintf(result, n_entries, "%d,%u,%u,", type,
1165 ntohs(dllt.dllt_hwtype), ntohl(dllt.dllt_time));
1166 break;
1167 }
1168 case DHCPV6_DUID_EN: {
1169 duid_en_t den;
1170
1171 if (length < sizeof (den)) {
1172 *ierrnop = ITAB_BAD_GRAN;
1173 return (NULL);
1174 }
1175 (void) memcpy(&den, payload, sizeof (den));
1176 payload += sizeof (den);
1177 length -= sizeof (den);
1178 n_entries = sizeof ("2,4294967295,") + length * 2;
1179 if ((result = malloc(n_entries)) == NULL) {
1180 *ierrnop = ITAB_NOMEM;
1181 return (NULL);
1182 }
1183 (void) snprintf(result, n_entries, "%d,%u,", type,
1184 DHCPV6_GET_ENTNUM(&den));
1185 break;
1186 }
1187 case DHCPV6_DUID_LL: {
1188 duid_ll_t dll;
1189
1190 if (length < sizeof (dll)) {
1191 *ierrnop = ITAB_BAD_GRAN;
1192 return (NULL);
1193 }
1194 (void) memcpy(&dll, payload, sizeof (dll));
1195 payload += sizeof (dll);
1196 length -= sizeof (dll);
1197 n_entries = sizeof ("3,65535,") + length * 3;
1198 if ((result = malloc(n_entries)) == NULL) {
1199 *ierrnop = ITAB_NOMEM;
1200 return (NULL);
1201 }
1202 (void) snprintf(result, n_entries, "%d,%u,", type,
1203 ntohs(dll.dll_hwtype));
1204 break;
1205 }
1206 default:
1207 n_entries = sizeof ("0,") + length * 2;
1208 if ((result = malloc(n_entries)) == NULL) {
1209 *ierrnop = ITAB_NOMEM;
1210 return (NULL);
1211 }
1212 (void) snprintf(result, n_entries, "%d,", type);
1213 break;
1214 }
1215 resultp = result + strlen(result);
1216 n_entries -= strlen(result);
1217 if (type == DHCPV6_DUID_LLT || type == DHCPV6_DUID_LL) {
1218 if (length > 0) {
1219 resultp += snprintf(resultp, 3, "%02X",
1220 *payload++);
1221 length--;
1222 }
1223 while (length-- > 0) {
1224 resultp += snprintf(resultp, 4, ":%02X",
1225 *payload++);
1226 }
1227 } else {
1228 while (length-- > 0) {
1229 resultp += snprintf(resultp, 3, "%02X",
1230 *payload++);
1231 }
1232 }
1233 break;
1234
1235 case DSYM_OCTET:
1236
1237 result = malloc(n_entries * (sizeof ("0xNN") + 1));
1238 if (result == NULL) {
1239 *ierrnop = ITAB_NOMEM;
1240 return (NULL);
1241 }
1242
1243 result[0] = '\0';
1244 resultp = result;
1245 if (n_entries > 0) {
1246 resultp += sprintf(resultp, "0x%02X", *payload++);
1247 n_entries--;
1248 }
1249 while (n_entries-- > 0)
1250 resultp += sprintf(resultp, " 0x%02X", *payload++);
1251
1252 break;
1253
1254 case DSYM_IP:
1255 case DSYM_IPV6:
1256 if ((length / type_size) % ie->ds_gran != 0) {
1257 *ierrnop = ITAB_BAD_GRAN;
1258 inittab_msg("inittab_decode: number of entries "
1259 "not compatible with option granularity");
1260 return (NULL);
1261 }
1262
1263 result = malloc(n_entries * (ie->ds_type == DSYM_IP ?
1264 INET_ADDRSTRLEN : INET6_ADDRSTRLEN));
1265 if (result == NULL) {
1266 *ierrnop = ITAB_NOMEM;
1267 return (NULL);
1268 }
1269
1270 for (resultp = result; n_entries != 0; n_entries--) {
1271 if (ie->ds_type == DSYM_IP) {
1272 (void) memcpy(&in_addr.s_addr, payload,
1273 sizeof (ipaddr_t));
1274 (void) strcpy(resultp, inet_ntoa(in_addr));
1275 } else {
1276 (void) memcpy(&in6_addr, payload,
1277 sizeof (in6_addr));
1278 (void) inet_ntop(AF_INET6, &in6_addr, resultp,
1279 INET6_ADDRSTRLEN);
1280 }
1281 resultp += strlen(resultp);
1282 if (n_entries > 1)
1283 *resultp++ = ' ';
1284 payload += type_size;
1285 }
1286 *resultp = '\0';
1287 break;
1288
1289 case DSYM_NUMBER: /* FALLTHRU */
1290 case DSYM_UNUMBER8: /* FALLTHRU */
1291 case DSYM_SNUMBER8: /* FALLTHRU */
1292 case DSYM_UNUMBER16: /* FALLTHRU */
1293 case DSYM_SNUMBER16: /* FALLTHRU */
1294 case DSYM_UNUMBER32: /* FALLTHRU */
1295 case DSYM_SNUMBER32: /* FALLTHRU */
1296 case DSYM_UNUMBER64: /* FALLTHRU */
1297 case DSYM_SNUMBER64:
1298
1299 is_signed = (ie->ds_type == DSYM_SNUMBER64 ||
1300 ie->ds_type == DSYM_SNUMBER32 ||
1301 ie->ds_type == DSYM_SNUMBER16 ||
1302 ie->ds_type == DSYM_SNUMBER8);
1303
1304 result = malloc(n_entries * ITAB_MAX_NUMBER_LEN);
1305 if (result == NULL) {
1306 *ierrnop = ITAB_NOMEM;
1307 return (NULL);
1308 }
1309
1310 if (decode_number(n_entries, type_size, is_signed, ie->ds_gran,
1311 payload, result, ierrnop) == B_FALSE) {
1312 free(result);
1313 return (NULL);
1314 }
1315 break;
1316
1317 default:
1318 inittab_msg("inittab_decode: unsupported type `%d'",
1319 ie->ds_type);
1320 break;
1321 }
1322
1323 return (result);
1324 }
1325
1326 /*
1327 * inittab_encode(): converts a string representation of a given datatype into
1328 * binary; used for encoding ascii values into a form that
1329 * can be put in DHCP packets to be sent on the wire.
1330 *
1331 * input: dhcp_symbol_t *: the entry describing the value option
1332 * const char *: the value to convert
1333 * uint16_t *: set to the length of the binary data returned
1334 * boolean_t: if false, return a full DHCP option
1335 * output: uchar_t *: a dynamically allocated byte array with converted data
1336 */
1337
1338 uchar_t *
inittab_encode(const dhcp_symbol_t * ie,const char * value,uint16_t * lengthp,boolean_t just_payload)1339 inittab_encode(const dhcp_symbol_t *ie, const char *value, uint16_t *lengthp,
1340 boolean_t just_payload)
1341 {
1342 int ierrno;
1343
1344 return (inittab_encode_e(ie, value, lengthp, just_payload, &ierrno));
1345 }
1346
1347 /*
1348 * inittab_decode(): converts a binary representation of a given datatype into
1349 * a string; used for decoding DHCP options in a packet off
1350 * the wire into ascii
1351 *
1352 * input: dhcp_symbol_t *: the entry describing the payload option
1353 * uchar_t *: the payload to convert
1354 * uint16_t: the payload length (only used if just_payload is true)
1355 * boolean_t: if false, payload is assumed to be a DHCP option
1356 * output: char *: a dynamically allocated string containing the converted data
1357 */
1358
1359 char *
inittab_decode(const dhcp_symbol_t * ie,const uchar_t * payload,uint16_t length,boolean_t just_payload)1360 inittab_decode(const dhcp_symbol_t *ie, const uchar_t *payload, uint16_t length,
1361 boolean_t just_payload)
1362 {
1363 int ierrno;
1364
1365 return (inittab_decode_e(ie, payload, length, just_payload, &ierrno));
1366 }
1367
1368 /*
1369 * inittab_msg(): prints diagnostic messages if INITTAB_DEBUG is set
1370 *
1371 * const char *: a printf-like format string
1372 * ...: arguments to the format string
1373 * output: void
1374 */
1375
1376 /*PRINTFLIKE1*/
1377 static void
inittab_msg(const char * fmt,...)1378 inittab_msg(const char *fmt, ...)
1379 {
1380 enum { INITTAB_MSG_CHECK, INITTAB_MSG_RETURN, INITTAB_MSG_OUTPUT };
1381
1382 va_list ap;
1383 char buf[512];
1384 static int action = INITTAB_MSG_CHECK;
1385
1386 /*
1387 * check DHCP_INITTAB_DEBUG the first time in; thereafter, use
1388 * the the cached result (stored in `action').
1389 */
1390 switch (action) {
1391
1392 case INITTAB_MSG_CHECK:
1393
1394 if (getenv("DHCP_INITTAB_DEBUG") == NULL) {
1395 action = INITTAB_MSG_RETURN;
1396 return;
1397 }
1398
1399 action = INITTAB_MSG_OUTPUT;
1400
1401 /* FALLTHRU into INITTAB_MSG_OUTPUT */
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