xref: /dragonfly/contrib/dhcpcd/src/dhcp-common.c (revision 7b1120e5)
1 /*
2  * dhcpcd - DHCP client daemon
3  * Copyright (c) 2006-2018 Roy Marples <roy@marples.name>
4  * All rights reserved
5 
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/stat.h>
29 #include <sys/utsname.h>
30 
31 #include <ctype.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <inttypes.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 
39 #include <arpa/nameser.h> /* after normal includes for sunos */
40 
41 #include "config.h"
42 
43 #include "common.h"
44 #include "dhcp-common.h"
45 #include "dhcp.h"
46 #include "if.h"
47 #include "ipv6.h"
48 #include "logerr.h"
49 
50 /* Support very old arpa/nameser.h as found in OpenBSD */
51 #ifndef NS_MAXDNAME
52 #define NS_MAXCDNAME MAXCDNAME
53 #define NS_MAXDNAME MAXDNAME
54 #define NS_MAXLABEL MAXLABEL
55 #endif
56 
57 const char *
58 dhcp_get_hostname(char *buf, size_t buf_len, const struct if_options *ifo)
59 {
60 
61 	if (ifo->hostname[0] == '\0') {
62 		if (gethostname(buf, buf_len) != 0)
63 			return NULL;
64 		buf[buf_len - 1] = '\0';
65 	} else
66 		strlcpy(buf, ifo->hostname, buf_len);
67 
68 	/* Deny sending of these local hostnames */
69 	if (buf[0] == '\0' || buf[0] == '.' ||
70 	    strcmp(buf, "(none)") == 0 ||
71 	    strcmp(buf, "localhost") == 0 ||
72 	    strncmp(buf, "localhost.", strlen("localhost.")) == 0)
73 		return NULL;
74 
75 	/* Shorten the hostname if required */
76 	if (ifo->options & DHCPCD_HOSTNAME_SHORT) {
77 		char *hp;
78 
79 		hp = strchr(buf, '.');
80 		if (hp != NULL)
81 			*hp = '\0';
82 	}
83 
84 	return buf;
85 }
86 
87 void
88 dhcp_print_option_encoding(const struct dhcp_opt *opt, int cols)
89 {
90 
91 	while (cols < 40) {
92 		putchar(' ');
93 		cols++;
94 	}
95 	putchar('\t');
96 	if (opt->type & OT_EMBED)
97 		printf(" embed");
98 	if (opt->type & OT_ENCAP)
99 		printf(" encap");
100 	if (opt->type & OT_INDEX)
101 		printf(" index");
102 	if (opt->type & OT_ARRAY)
103 		printf(" array");
104 	if (opt->type & OT_UINT8)
105 		printf(" uint8");
106 	else if (opt->type & OT_INT8)
107 		printf(" int8");
108 	else if (opt->type & OT_UINT16)
109 		printf(" uint16");
110 	else if (opt->type & OT_INT16)
111 		printf(" int16");
112 	else if (opt->type & OT_UINT32)
113 		printf(" uint32");
114 	else if (opt->type & OT_INT32)
115 		printf(" int32");
116 	else if (opt->type & OT_ADDRIPV4)
117 		printf(" ipaddress");
118 	else if (opt->type & OT_ADDRIPV6)
119 		printf(" ip6address");
120 	else if (opt->type & OT_FLAG)
121 		printf(" flag");
122 	else if (opt->type & OT_BITFLAG)
123 		printf(" bitflags");
124 	else if (opt->type & OT_RFC1035)
125 		printf(" domain");
126 	else if (opt->type & OT_DOMAIN)
127 		printf(" dname");
128 	else if (opt->type & OT_ASCII)
129 		printf(" ascii");
130 	else if (opt->type & OT_RAW)
131 		printf(" raw");
132 	else if (opt->type & OT_BINHEX)
133 		printf(" binhex");
134 	else if (opt->type & OT_STRING)
135 		printf(" string");
136 	if (opt->type & OT_RFC3361)
137 		printf(" rfc3361");
138 	if (opt->type & OT_RFC3442)
139 		printf(" rfc3442");
140 	if (opt->type & OT_REQUEST)
141 		printf(" request");
142 	if (opt->type & OT_NOREQ)
143 		printf(" norequest");
144 	putchar('\n');
145 }
146 
147 struct dhcp_opt *
148 vivso_find(uint32_t iana_en, const void *arg)
149 {
150 	const struct interface *ifp;
151 	size_t i;
152 	struct dhcp_opt *opt;
153 
154 	ifp = arg;
155 	for (i = 0, opt = ifp->options->vivso_override;
156 	    i < ifp->options->vivso_override_len;
157 	    i++, opt++)
158 		if (opt->option == iana_en)
159 			return opt;
160 	for (i = 0, opt = ifp->ctx->vivso;
161 	    i < ifp->ctx->vivso_len;
162 	    i++, opt++)
163 		if (opt->option == iana_en)
164 			return opt;
165 	return NULL;
166 }
167 
168 ssize_t
169 dhcp_vendor(char *str, size_t len)
170 {
171 	struct utsname utn;
172 	char *p;
173 	int l;
174 
175 	if (uname(&utn) == -1)
176 		return (ssize_t)snprintf(str, len, "%s-%s",
177 		    PACKAGE, VERSION);
178 	p = str;
179 	l = snprintf(p, len,
180 	    "%s-%s:%s-%s:%s", PACKAGE, VERSION,
181 	    utn.sysname, utn.release, utn.machine);
182 	if (l == -1 || (size_t)(l + 1) > len)
183 		return -1;
184 	p += l;
185 	len -= (size_t)l;
186 	l = if_machinearch(p, len);
187 	if (l == -1 || (size_t)(l + 1) > len)
188 		return -1;
189 	p += l;
190 	return p - str;
191 }
192 
193 int
194 make_option_mask(const struct dhcp_opt *dopts, size_t dopts_len,
195     const struct dhcp_opt *odopts, size_t odopts_len,
196     uint8_t *mask, const char *opts, int add)
197 {
198 	char *token, *o, *p;
199 	const struct dhcp_opt *opt;
200 	int match, e;
201 	unsigned int n;
202 	size_t i;
203 
204 	if (opts == NULL)
205 		return -1;
206 	o = p = strdup(opts);
207 	while ((token = strsep(&p, ", "))) {
208 		if (*token == '\0')
209 			continue;
210 		match = 0;
211 		for (i = 0, opt = odopts; i < odopts_len; i++, opt++) {
212 			if (opt->var == NULL || opt->option == 0)
213 				continue; /* buggy dhcpcd-definitions.conf */
214 			if (strcmp(opt->var, token) == 0)
215 				match = 1;
216 			else {
217 				n = (unsigned int)strtou(token, NULL, 0,
218 				    0, UINT_MAX, &e);
219 				if (e == 0 && opt->option == n)
220 					match = 1;
221 			}
222 			if (match)
223 				break;
224 		}
225 		if (match == 0) {
226 			for (i = 0, opt = dopts; i < dopts_len; i++, opt++) {
227 				if (strcmp(opt->var, token) == 0)
228 				        match = 1;
229 				else {
230 					n = (unsigned int)strtou(token, NULL, 0,
231 					    0, UINT_MAX, &e);
232 					if (e == 0 && opt->option == n)
233 						match = 1;
234 				}
235 				if (match)
236 					break;
237 			}
238 		}
239 		if (!match || !opt->option) {
240 			free(o);
241 			errno = ENOENT;
242 			return -1;
243 		}
244 		if (add == 2 && !(opt->type & OT_ADDRIPV4)) {
245 			free(o);
246 			errno = EINVAL;
247 			return -1;
248 		}
249 		if (add == 1 || add == 2)
250 			add_option_mask(mask, opt->option);
251 		else
252 			del_option_mask(mask, opt->option);
253 	}
254 	free(o);
255 	return 0;
256 }
257 
258 size_t
259 encode_rfc1035(const char *src, uint8_t *dst)
260 {
261 	uint8_t *p;
262 	uint8_t *lp;
263 	size_t len;
264 	uint8_t has_dot;
265 
266 	if (src == NULL || *src == '\0')
267 		return 0;
268 
269 	if (dst) {
270 		p = dst;
271 		lp = p++;
272 	}
273 	/* Silence bogus GCC warnings */
274 	else
275 		p = lp = NULL;
276 
277 	len = 1;
278 	has_dot = 0;
279 	for (; *src; src++) {
280 		if (*src == '\0')
281 			break;
282 		if (*src == '.') {
283 			/* Skip the trailing . */
284 			if (src[1] == '\0')
285 				break;
286 			has_dot = 1;
287 			if (dst) {
288 				*lp = (uint8_t)(p - lp - 1);
289 				if (*lp == '\0')
290 					return len;
291 				lp = p++;
292 			}
293 		} else if (dst)
294 			*p++ = (uint8_t)*src;
295 		len++;
296 	}
297 
298 	if (dst) {
299 		*lp = (uint8_t)(p - lp - 1);
300 		if (has_dot)
301 			*p++ = '\0';
302 	}
303 
304 	if (has_dot)
305 		len++;
306 
307 	return len;
308 }
309 
310 /* Decode an RFC1035 DNS search order option into a space
311  * separated string. Returns length of string (including
312  * terminating zero) or zero on error. out may be NULL
313  * to just determine output length. */
314 ssize_t
315 decode_rfc1035(char *out, size_t len, const uint8_t *p, size_t pl)
316 {
317 	const char *start;
318 	size_t start_len, l, d_len, o_len;
319 	const uint8_t *r, *q = p, *e;
320 	int hops;
321 	uint8_t ltype;
322 
323 	o_len = 0;
324 	start = out;
325 	start_len = len;
326 	q = p;
327 	e = p + pl;
328 	while (q < e) {
329 		r = NULL;
330 		d_len = 0;
331 		hops = 0;
332 		/* Check we are inside our length again in-case
333 		 * the name isn't fully qualified (ie, not terminated) */
334 		while (q < e && (l = (size_t)*q++)) {
335 			ltype = l & 0xc0;
336 			if (ltype == 0x80 || ltype == 0x40) {
337 				/* Currently reserved for future use as noted
338 				 * in RFC1035 4.1.4 as the 10 and 01
339 				 * combinations. */
340 				errno = ENOTSUP;
341 				return -1;
342 			}
343 			else if (ltype == 0xc0) { /* pointer */
344 				if (q == e) {
345 					errno = ERANGE;
346 					return -1;
347 				}
348 				l = (l & 0x3f) << 8;
349 				l |= *q++;
350 				/* save source of first jump. */
351 				if (!r)
352 					r = q;
353 				hops++;
354 				if (hops > 255) {
355 					errno = ERANGE;
356 					return -1;
357 				}
358 				q = p + l;
359 				if (q >= e) {
360 					errno = ERANGE;
361 					return -1;
362 				}
363 			} else {
364 				/* straightforward name segment, add with '.' */
365 				if (q + l > e) {
366 					errno = ERANGE;
367 					return -1;
368 				}
369 				if (l > NS_MAXLABEL) {
370 					errno = EINVAL;
371 					return -1;
372 				}
373 				d_len += l + 1;
374 				if (out) {
375 					if (l + 1 > len) {
376 						errno = ENOBUFS;
377 						return -1;
378 					}
379 					memcpy(out, q, l);
380 					out += l;
381 					*out++ = '.';
382 					len -= l;
383 					len--;
384 				}
385 				q += l;
386 			}
387 		}
388 
389 		/* Don't count the trailing NUL */
390 		if (d_len > NS_MAXDNAME + 1) {
391 			errno = E2BIG;
392 			return -1;
393 		}
394 		o_len += d_len;
395 
396 		/* change last dot to space */
397 		if (out && out != start)
398 			*(out - 1) = ' ';
399 		if (r)
400 			q = r;
401 	}
402 
403 	/* change last space to zero terminator */
404 	if (out) {
405 		if (out != start)
406 			*(out - 1) = '\0';
407 		else if (start_len > 0)
408 			*out = '\0';
409 	}
410 
411 	/* Remove the trailing NUL */
412 	if (o_len != 0)
413 		o_len--;
414 
415 	return (ssize_t)o_len;
416 }
417 
418 /* Check for a valid name as per RFC952 and RFC1123 section 2.1 */
419 static int
420 valid_domainname(char *lbl, int type)
421 {
422 	char *slbl, *lst;
423 	unsigned char c;
424 	int start, len, errset;
425 
426 	if (lbl == NULL || *lbl == '\0') {
427 		errno = EINVAL;
428 		return 0;
429 	}
430 
431 	slbl = lbl;
432 	lst = NULL;
433 	start = 1;
434 	len = errset = 0;
435 	for (;;) {
436 		c = (unsigned char)*lbl++;
437 		if (c == '\0')
438 			return 1;
439 		if (c == ' ') {
440 			if (lbl - 1 == slbl) /* No space at start */
441 				break;
442 			if (!(type & OT_ARRAY))
443 				break;
444 			/* Skip to the next label */
445 			if (!start) {
446 				start = 1;
447 				lst = lbl - 1;
448 			}
449 			if (len)
450 				len = 0;
451 			continue;
452 		}
453 		if (c == '.') {
454 			if (*lbl == '.')
455 				break;
456 			len = 0;
457 			continue;
458 		}
459 		if (((c == '-' || c == '_') &&
460 		    !start && *lbl != ' ' && *lbl != '\0') ||
461 		    isalnum(c))
462 		{
463 			if (++len > NS_MAXLABEL) {
464 				errno = ERANGE;
465 				errset = 1;
466 				break;
467 			}
468 		} else
469 			break;
470 		if (start)
471 			start = 0;
472 	}
473 
474 	if (!errset)
475 		errno = EINVAL;
476 	if (lst) {
477 		/* At least one valid domain, return it */
478 		*lst = '\0';
479 		return 1;
480 	}
481 	return 0;
482 }
483 
484 /*
485  * Prints a chunk of data to a string.
486  * PS_SHELL goes as it is these days, it's upto the target to validate it.
487  * PS_SAFE has all non ascii and non printables changes to escaped octal.
488  */
489 static const char hexchrs[] = "0123456789abcdef";
490 ssize_t
491 print_string(char *dst, size_t len, int type, const uint8_t *data, size_t dl)
492 {
493 	char *odst;
494 	uint8_t c;
495 	const uint8_t *e;
496 	size_t bytes;
497 
498 	odst = dst;
499 	bytes = 0;
500 	e = data + dl;
501 
502 	while (data < e) {
503 		c = *data++;
504 		if (type & OT_BINHEX) {
505 			if (dst) {
506 				if (len  == 0 || len == 1) {
507 					errno = ENOBUFS;
508 					return -1;
509 				}
510 				*dst++ = hexchrs[(c & 0xF0) >> 4];
511 				*dst++ = hexchrs[(c & 0x0F)];
512 				len -= 2;
513 			}
514 			bytes += 2;
515 			continue;
516 		}
517 		if (type & OT_ASCII && (!isascii(c))) {
518 			errno = EINVAL;
519 			break;
520 		}
521 		if (!(type & (OT_ASCII | OT_RAW | OT_ESCSTRING | OT_ESCFILE)) &&
522 		    (!isascii(c) && !isprint(c)))
523 		{
524 			errno = EINVAL;
525 			break;
526 		}
527 		if ((type & (OT_ESCSTRING | OT_ESCFILE) &&
528 		    (c == '\\' || !isascii(c) || !isprint(c))) ||
529 		    (type & OT_ESCFILE && (c == '/' || c == ' ')))
530 		{
531 			errno = EINVAL;
532 			if (c == '\\') {
533 				if (dst) {
534 					if (len  == 0 || len == 1) {
535 						errno = ENOBUFS;
536 						return -1;
537 					}
538 					*dst++ = '\\'; *dst++ = '\\';
539 					len -= 2;
540 				}
541 				bytes += 2;
542 				continue;
543 			}
544 			if (dst) {
545 				if (len < 5) {
546 					errno = ENOBUFS;
547 					return -1;
548 				}
549 				*dst++ = '\\';
550 		                *dst++ = (char)(((c >> 6) & 03) + '0');
551 		                *dst++ = (char)(((c >> 3) & 07) + '0');
552 		                *dst++ = (char)(( c       & 07) + '0');
553 				len -= 4;
554 			}
555 			bytes += 4;
556 		} else {
557 			if (dst) {
558 				if (len == 0) {
559 					errno = ENOBUFS;
560 					return -1;
561 				}
562 				*dst++ = (char)c;
563 				len--;
564 			}
565 			bytes++;
566 		}
567 	}
568 
569 	/* NULL */
570 	if (dst) {
571 		if (len == 0) {
572 			errno = ENOBUFS;
573 			return -1;
574 		}
575 		*dst = '\0';
576 
577 		/* Now we've printed it, validate the domain */
578 		if (type & OT_DOMAIN && !valid_domainname(odst, type)) {
579 			*odst = '\0';
580 			return 1;
581 		}
582 
583 	}
584 
585 	return (ssize_t)bytes;
586 }
587 
588 #define ADDR6SZ		16
589 static ssize_t
590 dhcp_optlen(const struct dhcp_opt *opt, size_t dl)
591 {
592 	size_t sz;
593 
594 	if (opt->type & OT_ADDRIPV6)
595 		sz = ADDR6SZ;
596 	else if (opt->type & (OT_INT32 | OT_UINT32 | OT_ADDRIPV4))
597 		sz = sizeof(uint32_t);
598 	else if (opt->type & (OT_INT16 | OT_UINT16))
599 		sz = sizeof(uint16_t);
600 	else if (opt->type & (OT_INT8 | OT_UINT8 | OT_BITFLAG))
601 		sz = sizeof(uint8_t);
602 	else if (opt->type & OT_FLAG)
603 		return 0;
604 	else {
605 		/* All other types are variable length */
606 		if (opt->len) {
607 			if ((size_t)opt->len > dl) {
608 				errno = EOVERFLOW;
609 				return -1;
610 			}
611 			return (ssize_t)opt->len;
612 		}
613 		return (ssize_t)dl;
614 	}
615 	if (dl < sz) {
616 		errno = EOVERFLOW;
617 		return -1;
618 	}
619 
620 	/* Trim any extra data.
621 	 * Maybe we need a settng to reject DHCP options with extra data? */
622 	if (opt->type & OT_ARRAY)
623 		return (ssize_t)(dl - (dl % sz));
624 	return (ssize_t)sz;
625 }
626 
627 /* It's possible for DHCPv4 to contain an IPv6 address */
628 static ssize_t
629 ipv6_printaddr(char *s, size_t sl, const uint8_t *d, const char *ifname)
630 {
631 	char buf[INET6_ADDRSTRLEN];
632 	const char *p;
633 	size_t l;
634 
635 	p = inet_ntop(AF_INET6, d, buf, sizeof(buf));
636 	if (p == NULL)
637 		return -1;
638 
639 	l = strlen(p);
640 	if (d[0] == 0xfe && (d[1] & 0xc0) == 0x80)
641 		l += 1 + strlen(ifname);
642 
643 	if (s == NULL)
644 		return (ssize_t)l;
645 
646 	if (sl < l) {
647 		errno = ENOMEM;
648 		return -1;
649 	}
650 
651 	s += strlcpy(s, p, sl);
652 	if (d[0] == 0xfe && (d[1] & 0xc0) == 0x80) {
653 		*s++ = '%';
654 		s += strlcpy(s, ifname, sl);
655 	}
656 	*s = '\0';
657 	return (ssize_t)l;
658 }
659 
660 static ssize_t
661 print_option(char *s, size_t len, const struct dhcp_opt *opt,
662     const uint8_t *data, size_t dl, const char *ifname)
663 {
664 	const uint8_t *e, *t;
665 	uint16_t u16;
666 	int16_t s16;
667 	uint32_t u32;
668 	int32_t s32;
669 	struct in_addr addr;
670 	ssize_t bytes = 0, sl;
671 	size_t l;
672 #ifdef INET
673 	char *tmp;
674 #endif
675 
676 	if (opt->type & OT_RFC1035) {
677 		sl = decode_rfc1035(s, len, data, dl);
678 		if (sl == 0 || sl == -1)
679 			return sl;
680 		if (s != NULL) {
681 			if (valid_domainname(s, opt->type) == -1)
682 				return -1;
683 		}
684 		return sl;
685 	}
686 
687 #ifdef INET
688 	if (opt->type & OT_RFC3361) {
689 		if ((tmp = decode_rfc3361(data, dl)) == NULL)
690 			return -1;
691 		l = strlen(tmp);
692 		sl = print_string(s, len, opt->type, (uint8_t *)tmp, l);
693 		free(tmp);
694 		return sl;
695 	}
696 
697 	if (opt->type & OT_RFC3442)
698 		return decode_rfc3442(s, len, data, dl);
699 #endif
700 
701 	if (opt->type & OT_STRING)
702 		return print_string(s, len, opt->type, data, dl);
703 
704 	if (opt->type & OT_FLAG) {
705 		if (s) {
706 			*s++ = '1';
707 			*s = '\0';
708 		}
709 		return 1;
710 	}
711 
712 	if (opt->type & OT_BITFLAG) {
713 		/* bitflags are a string, MSB first, such as ABCDEFGH
714 		 * where A is 10000000, B is 01000000, etc. */
715 		bytes = 0;
716 		for (l = 0, sl = sizeof(opt->bitflags) - 1;
717 		    l < sizeof(opt->bitflags);
718 		    l++, sl--)
719 		{
720 			/* Don't print NULL or 0 flags */
721 			if (opt->bitflags[l] != '\0' &&
722 			    opt->bitflags[l] != '0' &&
723 			    *data & (1 << sl))
724 			{
725 				if (s)
726 					*s++ = opt->bitflags[l];
727 				bytes++;
728 			}
729 		}
730 		if (s)
731 			*s = '\0';
732 		return bytes;
733 	}
734 
735 	if (!s) {
736 		if (opt->type & OT_UINT8)
737 			l = 3;
738 		else if (opt->type & OT_INT8)
739 			l = 4;
740 		else if (opt->type & OT_UINT16) {
741 			l = 5;
742 			dl /= 2;
743 		} else if (opt->type & OT_INT16) {
744 			l = 6;
745 			dl /= 2;
746 		} else if (opt->type & OT_UINT32) {
747 			l = 10;
748 			dl /= 4;
749 		} else if (opt->type & OT_INT32) {
750 			l = 11;
751 			dl /= 4;
752 		} else if (opt->type & OT_ADDRIPV4) {
753 			l = 16;
754 			dl /= 4;
755 		} else if (opt->type & OT_ADDRIPV6) {
756 			e = data + dl;
757 			l = 0;
758 			while (data < e) {
759 				if (l)
760 					l++; /* space */
761 				sl = ipv6_printaddr(NULL, 0, data, ifname);
762 				if (sl == -1)
763 					return l == 0 ? -1 : (ssize_t)l;
764 				l += (size_t)sl;
765 				data += 16;
766 			}
767 			return (ssize_t)l;
768 		} else {
769 			errno = EINVAL;
770 			return -1;
771 		}
772 		return (ssize_t)(l * dl);
773 	}
774 
775 	t = data;
776 	e = data + dl;
777 	while (data < e) {
778 		if (data != t) {
779 			*s++ = ' ';
780 			bytes++;
781 			len--;
782 		}
783 		if (opt->type & OT_UINT8) {
784 			sl = snprintf(s, len, "%u", *data);
785 			data++;
786 		} else if (opt->type & OT_INT8) {
787 			sl = snprintf(s, len, "%d", *data);
788 			data++;
789 		} else if (opt->type & OT_UINT16) {
790 			memcpy(&u16, data, sizeof(u16));
791 			u16 = ntohs(u16);
792 			sl = snprintf(s, len, "%u", u16);
793 			data += sizeof(u16);
794 		} else if (opt->type & OT_INT16) {
795 			memcpy(&u16, data, sizeof(u16));
796 			s16 = (int16_t)ntohs(u16);
797 			sl = snprintf(s, len, "%d", s16);
798 			data += sizeof(u16);
799 		} else if (opt->type & OT_UINT32) {
800 			memcpy(&u32, data, sizeof(u32));
801 			u32 = ntohl(u32);
802 			sl = snprintf(s, len, "%u", u32);
803 			data += sizeof(u32);
804 		} else if (opt->type & OT_INT32) {
805 			memcpy(&u32, data, sizeof(u32));
806 			s32 = (int32_t)ntohl(u32);
807 			sl = snprintf(s, len, "%d", s32);
808 			data += sizeof(u32);
809 		} else if (opt->type & OT_ADDRIPV4) {
810 			memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
811 			sl = snprintf(s, len, "%s", inet_ntoa(addr));
812 			data += sizeof(addr.s_addr);
813 		} else if (opt->type & OT_ADDRIPV6) {
814 			sl = ipv6_printaddr(s, len, data, ifname);
815 			data += 16;
816 		} else {
817 			errno = EINVAL;
818 			return -1;
819 		}
820 		if (sl == -1)
821 			return bytes == 0 ? -1 : bytes;
822 		len -= (size_t)sl;
823 		bytes += sl;
824 		s += sl;
825 	}
826 
827 	return bytes;
828 }
829 
830 int
831 dhcp_set_leasefile(char *leasefile, size_t len, int family,
832     const struct interface *ifp)
833 {
834 	char ssid[1 + (IF_SSIDLEN * 4) + 1]; /* - prefix and NUL terminated. */
835 
836 	if (ifp->name[0] == '\0') {
837 		strlcpy(leasefile, ifp->ctx->pidfile, len);
838 		return 0;
839 	}
840 
841 	switch (family) {
842 	case AF_INET:
843 	case AF_INET6:
844 		break;
845 	default:
846 		errno = EINVAL;
847 		return -1;
848 	}
849 
850 	if (ifp->wireless) {
851 		ssid[0] = '-';
852 		print_string(ssid + 1, sizeof(ssid) - 1,
853 		    OT_ESCFILE,
854 		    (const uint8_t *)ifp->ssid, ifp->ssid_len);
855 	} else
856 		ssid[0] = '\0';
857 	return snprintf(leasefile, len,
858 	    family == AF_INET ? LEASEFILE : LEASEFILE6,
859 	    ifp->name, ssid);
860 }
861 
862 static size_t
863 dhcp_envoption1(char **env, const char *prefix,
864     const struct dhcp_opt *opt, int vname, const uint8_t *od, size_t ol,
865     const char *ifname)
866 {
867 	ssize_t len;
868 	size_t e;
869 	char *v, *val;
870 	int r;
871 
872 	/* Ensure a valid length */
873 	ol = (size_t)dhcp_optlen(opt, ol);
874 	if ((ssize_t)ol == -1)
875 		return 0;
876 
877 	len = print_option(NULL, 0, opt, od, ol, ifname);
878 	if (len < 0)
879 		return 0;
880 	if (vname)
881 		e = strlen(opt->var) + 1;
882 	else
883 		e = 0;
884 	if (prefix)
885 		e += strlen(prefix);
886 	e += (size_t)len + 2;
887 	if (env == NULL)
888 		return e;
889 	v = val = *env = malloc(e);
890 	if (v == NULL)
891 		return 0;
892 	if (vname)
893 		r = snprintf(val, e, "%s_%s=", prefix, opt->var);
894 	else
895 		r = snprintf(val, e, "%s=", prefix);
896 	if (r != -1 && len != 0) {
897 		v += r;
898 		if (print_option(v, (size_t)len + 1, opt, od, ol, ifname) == -1)
899 			r = -1;
900 	}
901 	if (r == -1) {
902 		free(val);
903 		return 0;
904 	}
905 	return e;
906 }
907 
908 size_t
909 dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
910     const char *ifname, struct dhcp_opt *opt,
911     const uint8_t *(*dgetopt)(struct dhcpcd_ctx *,
912     size_t *, unsigned int *, size_t *,
913     const uint8_t *, size_t, struct dhcp_opt **),
914     const uint8_t *od, size_t ol)
915 {
916 	size_t e, i, n, eos, eol;
917 	ssize_t eo;
918 	unsigned int eoc;
919 	const uint8_t *eod;
920 	int ov;
921 	struct dhcp_opt *eopt, *oopt;
922 	char *pfx;
923 
924 	/* If no embedded or encapsulated options, it's easy */
925 	if (opt->embopts_len == 0 && opt->encopts_len == 0) {
926 		if (!(opt->type & OT_RESERVED)) {
927 			if (dhcp_envoption1(env == NULL ? NULL : &env[0],
928 			    prefix, opt, 1, od, ol, ifname))
929 				return 1;
930 			else
931 				logerr("%s: %s %d",
932 				    ifname, __func__, opt->option);
933 		}
934 		return 0;
935 	}
936 
937 	/* Create a new prefix based on the option */
938 	if (env) {
939 		if (opt->type & OT_INDEX) {
940 			if (opt->index > 999) {
941 				errno = ENOBUFS;
942 				logerr(__func__);
943 				return 0;
944 			}
945 		}
946 		e = strlen(prefix) + strlen(opt->var) + 2 +
947 		    (opt->type & OT_INDEX ? 3 : 0);
948 		pfx = malloc(e);
949 		if (pfx == NULL) {
950 			logerr(__func__);
951 			return 0;
952 		}
953 		if (opt->type & OT_INDEX)
954 			snprintf(pfx, e, "%s_%s%d", prefix,
955 			    opt->var, ++opt->index);
956 		else
957 			snprintf(pfx, e, "%s_%s", prefix, opt->var);
958 	} else
959 		pfx = NULL;
960 
961 	/* Embedded options are always processed first as that
962 	 * is a fixed layout */
963 	n = 0;
964 	for (i = 0, eopt = opt->embopts; i < opt->embopts_len; i++, eopt++) {
965 		eo = dhcp_optlen(eopt, ol);
966 		if (eo == -1) {
967 			if (env == NULL)
968 				logerrx("%s: %s %d.%d/%zu: "
969 				    "malformed embedded option",
970 				    ifname, __func__, opt->option,
971 				    eopt->option, i);
972 			goto out;
973 		}
974 		if (eo == 0) {
975 			/* An option was expected, but there is no data
976 			 * data for it.
977 			 * This may not be an error as some options like
978 			 * DHCP FQDN in RFC4702 have a string as the last
979 			 * option which is optional. */
980 			if (env == NULL &&
981 			    (ol != 0 || !(eopt->type & OT_OPTIONAL)))
982 				logerrx("%s: %s %d.%d/%zu: missing embedded option",
983 				    ifname, __func__, opt->option,
984 				    eopt->option, i);
985 			goto out;
986 		}
987 		/* Use the option prefix if the embedded option
988 		 * name is different.
989 		 * This avoids new_fqdn_fqdn which would be silly. */
990 		if (!(eopt->type & OT_RESERVED)) {
991 			ov = strcmp(opt->var, eopt->var);
992 			if (dhcp_envoption1(env == NULL ? NULL : &env[n],
993 			    pfx, eopt, ov, od, (size_t)eo, ifname))
994 				n++;
995 			else if (env == NULL)
996 				logerr("%s: %s %d.%d/%zu",
997 				    ifname, __func__,
998 				    opt->option, eopt->option, i);
999 		}
1000 		od += (size_t)eo;
1001 		ol -= (size_t)eo;
1002 	}
1003 
1004 	/* Enumerate our encapsulated options */
1005 	if (opt->encopts_len && ol > 0) {
1006 		/* Zero any option indexes
1007 		 * We assume that referenced encapsulated options are NEVER
1008 		 * recursive as the index order could break. */
1009 		for (i = 0, eopt = opt->encopts;
1010 		    i < opt->encopts_len;
1011 		    i++, eopt++)
1012 		{
1013 			eoc = opt->option;
1014 			if (eopt->type & OT_OPTION) {
1015 				dgetopt(ctx, NULL, &eoc, NULL, NULL, 0, &oopt);
1016 				if (oopt)
1017 					oopt->index = 0;
1018 			}
1019 		}
1020 
1021 		while ((eod = dgetopt(ctx, &eos, &eoc, &eol, od, ol, &oopt))) {
1022 			for (i = 0, eopt = opt->encopts;
1023 			    i < opt->encopts_len;
1024 			    i++, eopt++)
1025 			{
1026 				if (eopt->option == eoc) {
1027 					if (eopt->type & OT_OPTION) {
1028 						if (oopt == NULL)
1029 							/* Report error? */
1030 							continue;
1031 					}
1032 					n += dhcp_envoption(ctx,
1033 					    env == NULL ? NULL : &env[n], pfx,
1034 					    ifname,
1035 					    eopt->type & OT_OPTION ? oopt:eopt,
1036 					    dgetopt, eod, eol);
1037 					break;
1038 				}
1039 			}
1040 			od += eos + eol;
1041 			ol -= eos + eol;
1042 		}
1043 	}
1044 
1045 out:
1046 	if (env)
1047 		free(pfx);
1048 
1049 	/* Return number of options found */
1050 	return n;
1051 }
1052 
1053 void
1054 dhcp_zero_index(struct dhcp_opt *opt)
1055 {
1056 	size_t i;
1057 	struct dhcp_opt *o;
1058 
1059 	opt->index = 0;
1060 	for (i = 0, o = opt->embopts; i < opt->embopts_len; i++, o++)
1061 		dhcp_zero_index(o);
1062 	for (i = 0, o = opt->encopts; i < opt->encopts_len; i++, o++)
1063 		dhcp_zero_index(o);
1064 }
1065 
1066 size_t
1067 dhcp_read_lease_fd(int fd, void **lease)
1068 {
1069 	struct stat st;
1070 	size_t sz;
1071 	void *buf;
1072 	ssize_t len;
1073 
1074 	if (fstat(fd, &st) != 0)
1075 		goto out;
1076 	if (!S_ISREG(st.st_mode)) {
1077 		errno = EINVAL;
1078 		goto out;
1079 	}
1080 	if (st.st_size > UINT32_MAX) {
1081 		errno = E2BIG;
1082 		goto out;
1083 	}
1084 
1085 	sz = (size_t)st.st_size;
1086 	if ((buf = malloc(sz)) == NULL)
1087 		goto out;
1088 	if ((len = read(fd, buf, sz)) == -1) {
1089 		free(buf);
1090 		goto out;
1091 	}
1092 	*lease = buf;
1093 	return (size_t)len;
1094 
1095 out:
1096 	*lease = NULL;
1097 	return 0;
1098 }
1099