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