Remove building with NOCRYPTO option
[minix3.git] / external / bsd / dhcpcd / dist / dhcp-common.c
blob34f9b3f3187175290fc5cad07d0354c871ba4e0a
1 #include <sys/cdefs.h>
2 __RCSID("$NetBSD: dhcp-common.c,v 1.10 2015/07/09 10:15:34 roy Exp $");
4 /*
5 * dhcpcd - DHCP client daemon
6 * Copyright (c) 2006-2015 Roy Marples <roy@marples.name>
7 * All rights reserved
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 * SUCH DAMAGE.
31 #include <sys/utsname.h>
33 #include <arpa/nameser.h>
35 #include <ctype.h>
36 #include <errno.h>
37 #include <fcntl.h>
38 #include <inttypes.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <unistd.h>
43 #include "config.h"
45 #include "common.h"
46 #include "dhcp-common.h"
47 #include "dhcp.h"
48 #include "if.h"
49 #include "ipv6.h"
51 /* Support very old arpa/nameser.h as found in OpenBSD */
52 #ifndef NS_MAXDNAME
53 #define NS_MAXCDNAME MAXCDNAME
54 #define NS_MAXDNAME MAXDNAME
55 #define NS_MAXLABEL MAXLABEL
56 #endif
58 void
59 dhcp_print_option_encoding(const struct dhcp_opt *opt, int cols)
62 while (cols < 40) {
63 putchar(' ');
64 cols++;
66 putchar('\t');
67 if (opt->type & EMBED)
68 printf(" embed");
69 if (opt->type & ENCAP)
70 printf(" encap");
71 if (opt->type & INDEX)
72 printf(" index");
73 if (opt->type & ARRAY)
74 printf(" array");
75 if (opt->type & UINT8)
76 printf(" byte");
77 else if (opt->type & UINT16)
78 printf(" uint16");
79 else if (opt->type & SINT16)
80 printf(" sint16");
81 else if (opt->type & UINT32)
82 printf(" uint32");
83 else if (opt->type & SINT32)
84 printf(" sint32");
85 else if (opt->type & ADDRIPV4)
86 printf(" ipaddress");
87 else if (opt->type & ADDRIPV6)
88 printf(" ip6address");
89 else if (opt->type & FLAG)
90 printf(" flag");
91 else if (opt->type & BITFLAG)
92 printf(" bitflags");
93 else if (opt->type & RFC1035)
94 printf(" domain");
95 else if (opt->type & DOMAIN)
96 printf(" dname");
97 else if (opt->type & ASCII)
98 printf(" ascii");
99 else if (opt->type & RAW)
100 printf(" raw");
101 else if (opt->type & BINHEX)
102 printf(" binhex");
103 else if (opt->type & STRING)
104 printf(" string");
105 if (opt->type & RFC3361)
106 printf(" rfc3361");
107 if (opt->type & RFC3442)
108 printf(" rfc3442");
109 if (opt->type & RFC5969)
110 printf(" rfc5969");
111 if (opt->type & REQUEST)
112 printf(" request");
113 if (opt->type & NOREQ)
114 printf(" norequest");
115 putchar('\n');
118 struct dhcp_opt *
119 vivso_find(uint32_t iana_en, const void *arg)
121 const struct interface *ifp;
122 size_t i;
123 struct dhcp_opt *opt;
125 ifp = arg;
126 for (i = 0, opt = ifp->options->vivso_override;
127 i < ifp->options->vivso_override_len;
128 i++, opt++)
129 if (opt->option == iana_en)
130 return opt;
131 for (i = 0, opt = ifp->ctx->vivso;
132 i < ifp->ctx->vivso_len;
133 i++, opt++)
134 if (opt->option == iana_en)
135 return opt;
136 return NULL;
139 ssize_t
140 dhcp_vendor(char *str, size_t len)
142 struct utsname utn;
143 char *p;
144 int l;
146 if (uname(&utn) != 0)
147 return (ssize_t)snprintf(str, len, "%s-%s",
148 PACKAGE, VERSION);
149 p = str;
150 l = snprintf(p, len,
151 "%s-%s:%s-%s:%s", PACKAGE, VERSION,
152 utn.sysname, utn.release, utn.machine);
153 if (l == -1 || (size_t)(l + 1) > len)
154 return -1;
155 p += l;
156 len -= (size_t)l;
157 l = if_machinearch(p, len);
158 if (l == -1 || (size_t)(l + 1) > len)
159 return -1;
160 p += l;
161 return p - str;
165 make_option_mask(const struct dhcp_opt *dopts, size_t dopts_len,
166 const struct dhcp_opt *odopts, size_t odopts_len,
167 uint8_t *mask, const char *opts, int add)
169 char *token, *o, *p;
170 const struct dhcp_opt *opt;
171 int match, e;
172 unsigned int n;
173 size_t i;
175 if (opts == NULL)
176 return -1;
177 o = p = strdup(opts);
178 while ((token = strsep(&p, ", "))) {
179 if (*token == '\0')
180 continue;
181 match = 0;
182 for (i = 0, opt = odopts; i < odopts_len; i++, opt++) {
183 if (strcmp(opt->var, token) == 0)
184 match = 1;
185 else {
186 n = (unsigned int)strtou(token, NULL, 0,
187 0, UINT_MAX, &e);
188 if (e == 0 && opt->option == n)
189 match = 1;
191 if (match)
192 break;
194 if (match == 0) {
195 for (i = 0, opt = dopts; i < dopts_len; i++, opt++) {
196 if (strcmp(opt->var, token) == 0)
197 match = 1;
198 else {
199 n = (unsigned int)strtou(token, NULL, 0,
200 0, UINT_MAX, &e);
201 if (e == 0 && opt->option == n)
202 match = 1;
204 if (match)
205 break;
208 if (!match || !opt->option) {
209 free(o);
210 errno = ENOENT;
211 return -1;
213 if (add == 2 && !(opt->type & ADDRIPV4)) {
214 free(o);
215 errno = EINVAL;
216 return -1;
218 if (add == 1 || add == 2)
219 add_option_mask(mask, opt->option);
220 else
221 del_option_mask(mask, opt->option);
223 free(o);
224 return 0;
227 size_t
228 encode_rfc1035(const char *src, uint8_t *dst)
230 uint8_t *p;
231 uint8_t *lp;
232 size_t len;
233 uint8_t has_dot;
235 if (src == NULL || *src == '\0')
236 return 0;
238 if (dst) {
239 p = dst;
240 lp = p++;
242 /* Silence bogus GCC warnings */
243 else
244 p = lp = NULL;
246 len = 1;
247 has_dot = 0;
248 for (; *src; src++) {
249 if (*src == '\0')
250 break;
251 if (*src == '.') {
252 /* Skip the trailing . */
253 if (src[1] == '\0')
254 break;
255 has_dot = 1;
256 if (dst) {
257 *lp = (uint8_t)(p - lp - 1);
258 if (*lp == '\0')
259 return len;
260 lp = p++;
262 } else if (dst)
263 *p++ = (uint8_t)*src;
264 len++;
267 if (dst) {
268 *lp = (uint8_t)(p - lp - 1);
269 if (has_dot)
270 *p++ = '\0';
273 if (has_dot)
274 len++;
276 return len;
279 /* Decode an RFC1035 DNS search order option into a space
280 * separated string. Returns length of string (including
281 * terminating zero) or zero on error. out may be NULL
282 * to just determine output length. */
283 ssize_t
284 decode_rfc1035(char *out, size_t len, const uint8_t *p, size_t pl)
286 const char *start;
287 size_t start_len, l, count;
288 const uint8_t *r, *q = p, *e;
289 int hops;
290 uint8_t ltype;
292 if (pl > NS_MAXCDNAME) {
293 errno = E2BIG;
294 return -1;
297 count = 0;
298 start = out;
299 start_len = len;
300 q = p;
301 e = p + pl;
302 while (q < e) {
303 r = NULL;
304 hops = 0;
305 /* Check we are inside our length again in-case
306 * the name isn't fully qualified (ie, not terminated) */
307 while (q < e && (l = (size_t)*q++)) {
308 ltype = l & 0xc0;
309 if (ltype == 0x80 || ltype == 0x40) {
310 /* Currently reserved for future use as noted
311 * in RFC1035 4.1.4 as the 10 and 01
312 * combinations. */
313 errno = ENOTSUP;
314 return -1;
316 else if (ltype == 0xc0) { /* pointer */
317 if (q == e) {
318 errno = ERANGE;
319 return -1;
321 l = (l & 0x3f) << 8;
322 l |= *q++;
323 /* save source of first jump. */
324 if (!r)
325 r = q;
326 hops++;
327 if (hops > 255) {
328 errno = ERANGE;
329 return -1;
331 q = p + l;
332 if (q >= e) {
333 errno = ERANGE;
334 return -1;
336 } else {
337 /* straightforward name segment, add with '.' */
338 if (q + l > e) {
339 errno = ERANGE;
340 return -1;
342 count += l + 1;
343 if (out) {
344 if (l + 1 > len) {
345 errno = ENOBUFS;
346 return -1;
348 if (l + 1 > NS_MAXLABEL) {
349 errno = EINVAL;
350 return -1;
352 memcpy(out, q, l);
353 out += l;
354 *out++ = '.';
355 len -= l;
356 len--;
358 q += l;
361 /* change last dot to space */
362 if (out && out != start)
363 *(out - 1) = ' ';
364 if (r)
365 q = r;
368 /* change last space to zero terminator */
369 if (out) {
370 if (out != start)
371 *(out - 1) = '\0';
372 else if (start_len > 0)
373 *out = '\0';
376 if (count)
377 /* Don't count the trailing NUL */
378 count--;
379 if (count > NS_MAXDNAME) {
380 errno = E2BIG;
381 return -1;
383 return (ssize_t)count;
386 /* Check for a valid domain name as per RFC1123 with the exception of
387 * allowing - and _ (but not at start or end) as they seem to be widely used. */
388 static int
389 valid_domainname(char *lbl, int type)
391 char *slbl, *lst;
392 unsigned char c;
393 int start, len, errset;
395 if (lbl == NULL || *lbl == '\0') {
396 errno = EINVAL;
397 return 0;
400 slbl = lbl;
401 lst = NULL;
402 start = 1;
403 len = errset = 0;
404 for (;;) {
405 c = (unsigned char)*lbl++;
406 if (c == '\0')
407 return 1;
408 if (c == ' ') {
409 if (lbl - 1 == slbl) /* No space at start */
410 break;
411 if (!(type & ARRAY))
412 break;
413 /* Skip to the next label */
414 if (!start) {
415 start = 1;
416 lst = lbl - 1;
418 if (len)
419 len = 0;
420 continue;
422 if (c == '.') {
423 if (*lbl == '.')
424 break;
425 len = 0;
426 continue;
428 if (((c == '-' || c == '_') &&
429 !start && *lbl != ' ' && *lbl != '\0') ||
430 isalnum(c))
432 if (++len > NS_MAXLABEL) {
433 errno = ERANGE;
434 errset = 1;
435 break;
437 } else
438 break;
439 if (start)
440 start = 0;
443 if (!errset)
444 errno = EINVAL;
445 if (lst) {
446 /* At least one valid domain, return it */
447 *lst = '\0';
448 return 1;
450 return 0;
454 * Prints a chunk of data to a string.
455 * PS_SHELL goes as it is these days, it's upto the target to validate it.
456 * PS_SAFE has all non ascii and non printables changes to escaped octal.
458 static const char hexchrs[] = "0123456789abcdef";
459 ssize_t
460 print_string(char *dst, size_t len, int type, const uint8_t *data, size_t dl)
462 char *odst;
463 uint8_t c;
464 const uint8_t *e;
465 size_t bytes;
467 odst = dst;
468 bytes = 0;
469 e = data + dl;
471 while (data < e) {
472 c = *data++;
473 if (type & BINHEX) {
474 if (dst) {
475 if (len == 0 || len == 1) {
476 errno = ENOSPC;
477 return -1;
479 *dst++ = hexchrs[(c & 0xF0) >> 4];
480 *dst++ = hexchrs[(c & 0x0F)];
481 len -= 2;
483 bytes += 2;
484 continue;
486 if (type & ASCII && (!isascii(c))) {
487 errno = EINVAL;
488 break;
490 if (!(type & (ASCII | RAW | ESCSTRING | ESCFILE)) /* plain */ &&
491 (!isascii(c) && !isprint(c)))
493 errno = EINVAL;
494 break;
496 if ((type & (ESCSTRING | ESCFILE) &&
497 (c == '\\' || !isascii(c) || !isprint(c))) ||
498 (type & ESCFILE && (c == '/' || c == ' ')))
500 errno = EINVAL;
501 if (c == '\\') {
502 if (dst) {
503 if (len == 0 || len == 1) {
504 errno = ENOSPC;
505 return -1;
507 *dst++ = '\\'; *dst++ = '\\';
508 len -= 2;
510 bytes += 2;
511 continue;
513 if (dst) {
514 if (len < 5) {
515 errno = ENOSPC;
516 return -1;
518 *dst++ = '\\';
519 *dst++ = (char)(((c >> 6) & 03) + '0');
520 *dst++ = (char)(((c >> 3) & 07) + '0');
521 *dst++ = (char)(( c & 07) + '0');
522 len -= 4;
524 bytes += 4;
525 } else {
526 if (dst) {
527 if (len == 0) {
528 errno = ENOSPC;
529 return -1;
531 *dst++ = (char)c;
532 len--;
534 bytes++;
538 /* NULL */
539 if (dst) {
540 if (len == 0) {
541 errno = ENOSPC;
542 return -1;
544 *dst = '\0';
546 /* Now we've printed it, validate the domain */
547 if (type & DOMAIN && !valid_domainname(odst, type)) {
548 *odst = '\0';
549 return 1;
554 return (ssize_t)bytes;
557 #define ADDRSZ 4
558 #define ADDR6SZ 16
559 static ssize_t
560 dhcp_optlen(const struct dhcp_opt *opt, size_t dl)
562 size_t sz;
564 if (opt->type == 0 ||
565 opt->type & (STRING | BINHEX | RFC3442 | RFC5969))
567 if (opt->len) {
568 if ((size_t)opt->len > dl)
569 return -1;
570 return (ssize_t)opt->len;
572 return (ssize_t)dl;
575 if ((opt->type & (ADDRIPV4 | ARRAY)) == (ADDRIPV4 | ARRAY)) {
576 if (dl < ADDRSZ)
577 return -1;
578 return (ssize_t)(dl - (dl % ADDRSZ));
581 if ((opt->type & (ADDRIPV6 | ARRAY)) == (ADDRIPV6 | ARRAY)) {
582 if (dl < ADDR6SZ)
583 return -1;
584 return (ssize_t)(dl - (dl % ADDR6SZ));
587 if (opt->type & (UINT32 | ADDRIPV4))
588 sz = sizeof(uint32_t);
589 else if (opt->type & UINT16)
590 sz = sizeof(uint16_t);
591 else if (opt->type & (UINT8 | BITFLAG))
592 sz = sizeof(uint8_t);
593 else if (opt->type & ADDRIPV6)
594 sz = ADDR6SZ;
595 else
596 /* If we don't know the size, assume it's valid */
597 return (ssize_t)dl;
598 return dl < sz ? -1 : (ssize_t)sz;
601 static ssize_t
602 print_option(char *s, size_t len, const struct dhcp_opt *opt,
603 const uint8_t *data, size_t dl, const char *ifname)
605 const uint8_t *e, *t;
606 uint16_t u16;
607 int16_t s16;
608 uint32_t u32;
609 int32_t s32;
610 struct in_addr addr;
611 ssize_t bytes = 0, sl;
612 size_t l;
613 char *tmp;
615 #ifndef INET6
616 UNUSED(ifname);
617 #endif
619 if (opt->type & RFC1035) {
620 sl = decode_rfc1035(NULL, 0, data, dl);
621 if (sl == 0 || sl == -1)
622 return sl;
623 l = (size_t)sl + 1;
624 tmp = malloc(l);
625 if (tmp == NULL)
626 return -1;
627 decode_rfc1035(tmp, l, data, dl);
628 sl = print_string(s, len, opt->type, (uint8_t *)tmp, l - 1);
629 free(tmp);
630 return sl;
633 #ifdef INET
634 if (opt->type & RFC3361) {
635 if ((tmp = decode_rfc3361(data, dl)) == NULL)
636 return -1;
637 l = strlen(tmp);
638 sl = print_string(s, len, opt->type, (uint8_t *)tmp, l);
639 free(tmp);
640 return sl;
643 if (opt->type & RFC3442)
644 return decode_rfc3442(s, len, data, dl);
646 if (opt->type & RFC5969)
647 return decode_rfc5969(s, len, data, dl);
648 #endif
650 if (opt->type & STRING)
651 return print_string(s, len, opt->type, data, dl);
653 if (opt->type & FLAG) {
654 if (s) {
655 *s++ = '1';
656 *s = '\0';
658 return 1;
661 if (opt->type & BITFLAG) {
662 /* bitflags are a string, MSB first, such as ABCDEFGH
663 * where A is 10000000, B is 01000000, etc. */
664 bytes = 0;
665 for (l = 0, sl = sizeof(opt->bitflags) - 1;
666 l < sizeof(opt->bitflags);
667 l++, sl--)
669 /* Don't print NULL or 0 flags */
670 if (opt->bitflags[l] != '\0' &&
671 opt->bitflags[l] != '0' &&
672 *data & (1 << sl))
674 if (s)
675 *s++ = opt->bitflags[l];
676 bytes++;
679 if (s)
680 *s = '\0';
681 return bytes;
684 if (!s) {
685 if (opt->type & UINT8)
686 l = 3;
687 else if (opt->type & UINT16) {
688 l = 5;
689 dl /= 2;
690 } else if (opt->type & SINT16) {
691 l = 6;
692 dl /= 2;
693 } else if (opt->type & UINT32) {
694 l = 10;
695 dl /= 4;
696 } else if (opt->type & SINT32) {
697 l = 11;
698 dl /= 4;
699 } else if (opt->type & ADDRIPV4) {
700 l = 16;
701 dl /= 4;
703 #ifdef INET6
704 else if (opt->type & ADDRIPV6) {
705 e = data + dl;
706 l = 0;
707 while (data < e) {
708 if (l)
709 l++; /* space */
710 sl = ipv6_printaddr(NULL, 0, data, ifname);
711 if (sl != -1)
712 l += (size_t)sl;
713 data += 16;
715 return (ssize_t)l;
717 #endif
718 else {
719 errno = EINVAL;
720 return -1;
722 return (ssize_t)(l * dl);
725 t = data;
726 e = data + dl;
727 while (data < e) {
728 if (data != t) {
729 *s++ = ' ';
730 bytes++;
731 len--;
733 if (opt->type & UINT8) {
734 sl = snprintf(s, len, "%u", *data);
735 data++;
736 } else if (opt->type & UINT16) {
737 memcpy(&u16, data, sizeof(u16));
738 u16 = ntohs(u16);
739 sl = snprintf(s, len, "%u", u16);
740 data += sizeof(u16);
741 } else if (opt->type & SINT16) {
742 memcpy(&u16, data, sizeof(u16));
743 s16 = (int16_t)ntohs(u16);
744 sl = snprintf(s, len, "%d", s16);
745 data += sizeof(u16);
746 } else if (opt->type & UINT32) {
747 memcpy(&u32, data, sizeof(u32));
748 u32 = ntohl(u32);
749 sl = snprintf(s, len, "%u", u32);
750 data += sizeof(u32);
751 } else if (opt->type & SINT32) {
752 memcpy(&u32, data, sizeof(u32));
753 s32 = (int32_t)ntohl(u32);
754 sl = snprintf(s, len, "%d", s32);
755 data += sizeof(u32);
756 } else if (opt->type & ADDRIPV4) {
757 memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
758 sl = snprintf(s, len, "%s", inet_ntoa(addr));
759 data += sizeof(addr.s_addr);
761 #ifdef INET6
762 else if (opt->type & ADDRIPV6) {
763 ssize_t r;
765 r = ipv6_printaddr(s, len, data, ifname);
766 if (r != -1)
767 sl = r;
768 else
769 sl = 0;
770 data += 16;
772 #endif
773 else
774 sl = 0;
775 len -= (size_t)sl;
776 bytes += sl;
777 s += sl;
780 return bytes;
784 dhcp_set_leasefile(char *leasefile, size_t len, int family,
785 const struct interface *ifp)
787 char ssid[len];
789 if (ifp->name[0] == '\0') {
790 strlcpy(leasefile, ifp->ctx->pidfile, len);
791 return 0;
794 switch (family) {
795 case AF_INET:
796 case AF_INET6:
797 break;
798 default:
799 errno = EINVAL;
800 return -1;
803 if (ifp->wireless) {
804 ssid[0] = '-';
805 print_string(ssid + 1, sizeof(ssid) - 1,
806 ESCFILE,
807 (const uint8_t *)ifp->ssid, ifp->ssid_len);
808 } else
809 ssid[0] = '\0';
810 return snprintf(leasefile, len,
811 family == AF_INET ? LEASEFILE : LEASEFILE6,
812 ifp->name, ssid);
815 static size_t
816 dhcp_envoption1(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
817 const struct dhcp_opt *opt, int vname, const uint8_t *od, size_t ol,
818 const char *ifname)
820 ssize_t len;
821 size_t e;
822 char *v, *val;
824 if (opt->len && opt->len < ol)
825 ol = opt->len;
826 len = print_option(NULL, 0, opt, od, ol, ifname);
827 if (len < 0)
828 return 0;
829 if (vname)
830 e = strlen(opt->var) + 1;
831 else
832 e = 0;
833 if (prefix)
834 e += strlen(prefix);
835 e += (size_t)len + 2;
836 if (env == NULL)
837 return e;
838 v = val = *env = malloc(e);
839 if (v == NULL) {
840 logger(ctx, LOG_ERR, "%s: %m", __func__);
841 return 0;
843 if (vname)
844 v += snprintf(val, e, "%s_%s=", prefix, opt->var);
845 else
846 v += snprintf(val, e, "%s=", prefix);
847 if (len != 0)
848 print_option(v, (size_t)len + 1, opt, od, ol, ifname);
849 return e;
852 size_t
853 dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
854 const char *ifname, struct dhcp_opt *opt,
855 const uint8_t *(*dgetopt)(struct dhcpcd_ctx *,
856 size_t *, unsigned int *, size_t *,
857 const uint8_t *, size_t, struct dhcp_opt **),
858 const uint8_t *od, size_t ol)
860 size_t e, i, n, eos, eol;
861 ssize_t eo;
862 unsigned int eoc;
863 const uint8_t *eod;
864 int ov;
865 struct dhcp_opt *eopt, *oopt;
866 char *pfx;
868 /* If no embedded or encapsulated options, it's easy */
869 if (opt->embopts_len == 0 && opt->encopts_len == 0) {
870 if (!(opt->type & RESERVED) &&
871 dhcp_envoption1(ctx, env == NULL ? NULL : &env[0],
872 prefix, opt, 1, od, ol, ifname))
873 return 1;
874 return 0;
877 /* Create a new prefix based on the option */
878 if (env) {
879 if (opt->type & INDEX) {
880 if (opt->index > 999) {
881 errno = ENOBUFS;
882 logger(ctx, LOG_ERR, "%s: %m", __func__);
883 return 0;
886 e = strlen(prefix) + strlen(opt->var) + 2 +
887 (opt->type & INDEX ? 3 : 0);
888 pfx = malloc(e);
889 if (pfx == NULL) {
890 logger(ctx, LOG_ERR, "%s: %m", __func__);
891 return 0;
893 if (opt->type & INDEX)
894 snprintf(pfx, e, "%s_%s%d", prefix,
895 opt->var, ++opt->index);
896 else
897 snprintf(pfx, e, "%s_%s", prefix, opt->var);
898 } else
899 pfx = NULL;
901 /* Embedded options are always processed first as that
902 * is a fixed layout */
903 n = 0;
904 for (i = 0, eopt = opt->embopts; i < opt->embopts_len; i++, eopt++) {
905 eo = dhcp_optlen(eopt, ol);
906 if (eo == -1) {
907 if (env == NULL)
908 logger(ctx, LOG_ERR,
909 "%s: %s: malformed embedded option %d:%d",
910 ifname, __func__, opt->option,
911 eopt->option);
912 goto out;
914 if (eo == 0) {
915 /* An option was expected, but there is no data
916 * data for it.
917 * This may not be an error as some options like
918 * DHCP FQDN in RFC4702 have a string as the last
919 * option which is optional.
920 * FIXME: Add an flag to the options to indicate
921 * wether this is allowable or not. */
922 if (env == NULL &&
923 (ol != 0 || i + 1 < opt->embopts_len))
924 logger(ctx, LOG_ERR,
925 "%s: %s: malformed embedded option %d:%d",
926 ifname, __func__, opt->option,
927 eopt->option);
928 goto out;
930 /* Use the option prefix if the embedded option
931 * name is different.
932 * This avoids new_fqdn_fqdn which would be silly. */
933 if (!(eopt->type & RESERVED)) {
934 ov = strcmp(opt->var, eopt->var);
935 if (dhcp_envoption1(ctx, env == NULL ? NULL : &env[n],
936 pfx, eopt, ov, od, (size_t)eo, ifname))
937 n++;
939 od += (size_t)eo;
940 ol -= (size_t)eo;
943 /* Enumerate our encapsulated options */
944 if (opt->encopts_len && ol > 0) {
945 /* Zero any option indexes
946 * We assume that referenced encapsulated options are NEVER
947 * recursive as the index order could break. */
948 for (i = 0, eopt = opt->encopts;
949 i < opt->encopts_len;
950 i++, eopt++)
952 eoc = opt->option;
953 if (eopt->type & OPTION) {
954 dgetopt(ctx, NULL, &eoc, NULL, NULL, 0, &oopt);
955 if (oopt)
956 oopt->index = 0;
960 while ((eod = dgetopt(ctx, &eos, &eoc, &eol, od, ol, &oopt))) {
961 for (i = 0, eopt = opt->encopts;
962 i < opt->encopts_len;
963 i++, eopt++)
965 if (eopt->option == eoc) {
966 if (eopt->type & OPTION) {
967 if (oopt == NULL)
968 /* Report error? */
969 continue;
971 n += dhcp_envoption(ctx,
972 env == NULL ? NULL : &env[n], pfx,
973 ifname,
974 eopt->type & OPTION ? oopt : eopt,
975 dgetopt, eod, eol);
976 break;
979 od += eos + eol;
980 ol -= eos + eol;
984 out:
985 if (env)
986 free(pfx);
988 /* Return number of options found */
989 return n;
992 void
993 dhcp_zero_index(struct dhcp_opt *opt)
995 size_t i;
996 struct dhcp_opt *o;
998 opt->index = 0;
999 for (i = 0, o = opt->embopts; i < opt->embopts_len; i++, o++)
1000 dhcp_zero_index(o);
1001 for (i = 0, o = opt->encopts; i < opt->encopts_len; i++, o++)
1002 dhcp_zero_index(o);