xref: /dragonfly/contrib/dhcpcd/src/dhcp-common.c (revision f0e61bb7)
1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3  * dhcpcd - DHCP client daemon
4  * Copyright (c) 2006-2023 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 ssize_t
417 valid_domainname(char *lbl, int type)
418 {
419 	char *slbl = lbl, *lst = NULL;
420 	unsigned char c;
421 	int len = 0;
422 	bool start = true, errset = false;
423 
424 	if (lbl == NULL || *lbl == '\0') {
425 		errno = EINVAL;
426 		return 0;
427 	}
428 
429 	for (;;) {
430 		c = (unsigned char)*lbl++;
431 		if (c == '\0')
432 			return lbl - slbl - 1;
433 		if (c == ' ') {
434 			if (lbl - 1 == slbl) /* No space at start */
435 				break;
436 			if (!(type & OT_ARRAY))
437 				break;
438 			/* Skip to the next label */
439 			if (!start) {
440 				start = true;
441 				lst = lbl - 1;
442 			}
443 			if (len)
444 				len = 0;
445 			continue;
446 		}
447 		if (c == '.') {
448 			if (*lbl == '.')
449 				break;
450 			len = 0;
451 			continue;
452 		}
453 		if (((c == '-' || c == '_') &&
454 		    !start && *lbl != ' ' && *lbl != '\0') ||
455 		    isalnum(c))
456 		{
457 			if (++len > NS_MAXLABEL) {
458 				errno = ERANGE;
459 				errset = true;
460 				break;
461 			}
462 		} else
463 			break;
464 		if (start)
465 			start = false;
466 	}
467 
468 	if (!errset)
469 		errno = EINVAL;
470 	if (lst) {
471 		/* At least one valid domain, return it */
472 		*lst = '\0';
473 		return lst - slbl;
474 	}
475 	return 0;
476 }
477 
478 /*
479  * Prints a chunk of data to a string.
480  * PS_SHELL goes as it is these days, it's upto the target to validate it.
481  * PS_SAFE has all non ascii and non printables changes to escaped octal.
482  */
483 static const char hexchrs[] = "0123456789abcdef";
484 ssize_t
485 print_string(char *dst, size_t len, int type, const uint8_t *data, size_t dl)
486 {
487 	char *odst;
488 	uint8_t c;
489 	const uint8_t *e;
490 	size_t bytes;
491 
492 	odst = dst;
493 	bytes = 0;
494 	e = data + dl;
495 
496 	while (data < e) {
497 		c = *data++;
498 		if (type & OT_BINHEX) {
499 			if (dst) {
500 				if (len  == 0 || len == 1) {
501 					errno = ENOBUFS;
502 					return -1;
503 				}
504 				*dst++ = hexchrs[(c & 0xF0) >> 4];
505 				*dst++ = hexchrs[(c & 0x0F)];
506 				len -= 2;
507 			}
508 			bytes += 2;
509 			continue;
510 		}
511 		if (type & OT_ASCII && (!isascii(c))) {
512 			errno = EINVAL;
513 			break;
514 		}
515 		if (!(type & (OT_ASCII | OT_RAW | OT_ESCSTRING | OT_ESCFILE)) &&
516 		    (!isascii(c) && !isprint(c)))
517 		{
518 			errno = EINVAL;
519 			break;
520 		}
521 		if ((type & (OT_ESCSTRING | OT_ESCFILE) &&
522 		    (c == '\\' || !isascii(c) || !isprint(c))) ||
523 		    (type & OT_ESCFILE && (c == '/' || c == ' ')))
524 		{
525 			errno = EINVAL;
526 			if (c == '\\') {
527 				if (dst) {
528 					if (len  == 0 || len == 1) {
529 						errno = ENOBUFS;
530 						return -1;
531 					}
532 					*dst++ = '\\'; *dst++ = '\\';
533 					len -= 2;
534 				}
535 				bytes += 2;
536 				continue;
537 			}
538 			if (dst) {
539 				if (len < 5) {
540 					errno = ENOBUFS;
541 					return -1;
542 				}
543 				*dst++ = '\\';
544 		                *dst++ = (char)(((c >> 6) & 03) + '0');
545 		                *dst++ = (char)(((c >> 3) & 07) + '0');
546 		                *dst++ = (char)(( c       & 07) + '0');
547 				len -= 4;
548 			}
549 			bytes += 4;
550 		} else {
551 			if (dst) {
552 				if (len == 0) {
553 					errno = ENOBUFS;
554 					return -1;
555 				}
556 				*dst++ = (char)c;
557 				len--;
558 			}
559 			bytes++;
560 		}
561 	}
562 
563 	/* NULL */
564 	if (dst) {
565 		if (len == 0) {
566 			errno = ENOBUFS;
567 			return -1;
568 		}
569 		*dst = '\0';
570 
571 		/* Now we've printed it, validate the domain */
572 		if (type & OT_DOMAIN && !valid_domainname(odst, type)) {
573 			*odst = '\0';
574 			return 1;
575 		}
576 
577 	}
578 
579 	return (ssize_t)bytes;
580 }
581 
582 #define ADDR6SZ		16
583 static ssize_t
584 dhcp_optlen(const struct dhcp_opt *opt, size_t dl)
585 {
586 	size_t sz;
587 
588 	if (opt->type & OT_ADDRIPV6)
589 		sz = ADDR6SZ;
590 	else if (opt->type & (OT_INT32 | OT_UINT32 | OT_ADDRIPV4))
591 		sz = sizeof(uint32_t);
592 	else if (opt->type & (OT_INT16 | OT_UINT16))
593 		sz = sizeof(uint16_t);
594 	else if (opt->type & (OT_INT8 | OT_UINT8 | OT_BITFLAG))
595 		sz = sizeof(uint8_t);
596 	else if (opt->type & OT_FLAG)
597 		return 0;
598 	else {
599 		/* All other types are variable length */
600 		if (opt->len) {
601 			if ((size_t)opt->len > dl) {
602 				errno = EOVERFLOW;
603 				return -1;
604 			}
605 			return (ssize_t)opt->len;
606 		}
607 		return (ssize_t)dl;
608 	}
609 	if (dl < sz) {
610 		errno = EOVERFLOW;
611 		return -1;
612 	}
613 
614 	/* Trim any extra data.
615 	 * Maybe we need a setting to reject DHCP options with extra data? */
616 	if (opt->type & OT_ARRAY)
617 		return (ssize_t)(dl - (dl % sz));
618 	return (ssize_t)sz;
619 }
620 
621 static ssize_t
622 print_option(FILE *fp, const char *prefix, const struct dhcp_opt *opt,
623     int vname,
624     const uint8_t *data, size_t dl, const char *ifname)
625 {
626 	fpos_t fp_pos;
627 	const uint8_t *e, *t;
628 	uint16_t u16;
629 	int16_t s16;
630 	uint32_t u32;
631 	int32_t s32;
632 	struct in_addr addr;
633 	ssize_t sl;
634 	size_t l;
635 
636 	/* Ensure a valid length */
637 	dl = (size_t)dhcp_optlen(opt, dl);
638 	if ((ssize_t)dl == -1)
639 		return 0;
640 
641 	if (fgetpos(fp, &fp_pos) == -1)
642 		return -1;
643 	if (fprintf(fp, "%s", prefix) == -1)
644 		goto err;
645 
646 	/* We printed something, so always goto err from now-on
647 	 * to terminate the string. */
648 	if (vname) {
649 		if (fprintf(fp, "_%s", opt->var) == -1)
650 			goto err;
651 	}
652 	if (fputc('=', fp) == EOF)
653 		goto err;
654 	if (dl == 0)
655 		goto done;
656 
657 	if (opt->type & OT_RFC1035) {
658 		char domain[NS_MAXDNAME];
659 
660 		sl = decode_rfc1035(domain, sizeof(domain), data, dl);
661 		if (sl == -1)
662 			goto err;
663 		if (sl == 0)
664 			goto done;
665 		if (!valid_domainname(domain, opt->type))
666 			goto err;
667 		return efprintf(fp, "%s", domain);
668 	}
669 
670 #ifdef INET
671 	if (opt->type & OT_RFC3361)
672 		return print_rfc3361(fp, data, dl);
673 
674 	if (opt->type & OT_RFC3442)
675 		return print_rfc3442(fp, data, dl);
676 #endif
677 
678 	if (opt->type & OT_STRING) {
679 		char buf[1024];
680 
681 		if (print_string(buf, sizeof(buf), opt->type, data, dl) == -1)
682 			goto err;
683 		return efprintf(fp, "%s", buf);
684 	}
685 
686 	if (opt->type & OT_FLAG)
687 		return efprintf(fp, "1");
688 
689 	if (opt->type & OT_BITFLAG) {
690 		/* bitflags are a string, MSB first, such as ABCDEFGH
691 		 * where A is 10000000, B is 01000000, etc. */
692 		for (l = 0, sl = sizeof(opt->bitflags) - 1;
693 		    l < sizeof(opt->bitflags);
694 		    l++, sl--)
695 		{
696 			/* Don't print NULL or 0 flags */
697 			if (opt->bitflags[l] != '\0' &&
698 			    opt->bitflags[l] != '0' &&
699 			    *data & (1 << sl))
700 			{
701 				if (fputc(opt->bitflags[l], fp) == EOF)
702 					goto err;
703 			}
704 		}
705 		goto done;
706 	}
707 
708 	t = data;
709 	e = data + dl;
710 	while (data < e) {
711 		if (data != t) {
712 			if (fputc(' ', fp) == EOF)
713 				goto err;
714 		}
715 		if (opt->type & OT_UINT8) {
716 			if (fprintf(fp, "%u", *data) == -1)
717 				goto err;
718 			data++;
719 		} else if (opt->type & OT_INT8) {
720 			if (fprintf(fp, "%d", *data) == -1)
721 				goto err;
722 			data++;
723 		} else if (opt->type & OT_UINT16) {
724 			memcpy(&u16, data, sizeof(u16));
725 			u16 = ntohs(u16);
726 			if (fprintf(fp, "%u", u16) == -1)
727 				goto err;
728 			data += sizeof(u16);
729 		} else if (opt->type & OT_INT16) {
730 			memcpy(&u16, data, sizeof(u16));
731 			s16 = (int16_t)ntohs(u16);
732 			if (fprintf(fp, "%d", s16) == -1)
733 				goto err;
734 			data += sizeof(u16);
735 		} else if (opt->type & OT_UINT32) {
736 			memcpy(&u32, data, sizeof(u32));
737 			u32 = ntohl(u32);
738 			if (fprintf(fp, "%u", u32) == -1)
739 				goto err;
740 			data += sizeof(u32);
741 		} else if (opt->type & OT_INT32) {
742 			memcpy(&u32, data, sizeof(u32));
743 			s32 = (int32_t)ntohl(u32);
744 			if (fprintf(fp, "%d", s32) == -1)
745 				goto err;
746 			data += sizeof(u32);
747 		} else if (opt->type & OT_ADDRIPV4) {
748 			memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
749 			if (fprintf(fp, "%s", inet_ntoa(addr)) == -1)
750 				goto err;
751 			data += sizeof(addr.s_addr);
752 		} else if (opt->type & OT_ADDRIPV6) {
753 			char buf[INET6_ADDRSTRLEN];
754 
755 			if (inet_ntop(AF_INET6, data, buf, sizeof(buf)) == NULL)
756 				goto err;
757 			if (fprintf(fp, "%s", buf) == -1)
758 				goto err;
759 			if (data[0] == 0xfe && (data[1] & 0xc0) == 0x80) {
760 				if (fprintf(fp,"%%%s", ifname) == -1)
761 					goto err;
762 			}
763 			data += 16;
764 		} else {
765 			errno = EINVAL;
766 			goto err;
767 		}
768 	}
769 
770 done:
771 	if (fputc('\0', fp) == EOF)
772 		return -1;
773 	return 1;
774 
775 err:
776 	(void)fsetpos(fp, &fp_pos);
777 	return -1;
778 }
779 
780 int
781 dhcp_set_leasefile(char *leasefile, size_t len, int family,
782     const struct interface *ifp)
783 {
784 	char ssid[1 + (IF_SSIDLEN * 4) + 1]; /* - prefix and NUL terminated. */
785 
786 	if (ifp->name[0] == '\0') {
787 		strlcpy(leasefile, ifp->ctx->pidfile, len);
788 		return 0;
789 	}
790 
791 	switch (family) {
792 	case AF_INET:
793 	case AF_INET6:
794 		break;
795 	default:
796 		errno = EINVAL;
797 		return -1;
798 	}
799 
800 	if (ifp->wireless) {
801 		ssid[0] = '-';
802 		print_string(ssid + 1, sizeof(ssid) - 1,
803 		    OT_ESCFILE,
804 		    (const uint8_t *)ifp->ssid, ifp->ssid_len);
805 	} else
806 		ssid[0] = '\0';
807 	return snprintf(leasefile, len,
808 	    family == AF_INET ? LEASEFILE : LEASEFILE6,
809 	    ifp->name, ssid);
810 }
811 
812 void
813 dhcp_envoption(struct dhcpcd_ctx *ctx, FILE *fp, const char *prefix,
814     const char *ifname, struct dhcp_opt *opt,
815     const uint8_t *(*dgetopt)(struct dhcpcd_ctx *,
816     size_t *, unsigned int *, size_t *,
817     const uint8_t *, size_t, struct dhcp_opt **),
818     const uint8_t *od, size_t ol)
819 {
820 	size_t i, eos, eol;
821 	ssize_t eo;
822 	unsigned int eoc;
823 	const uint8_t *eod;
824 	int ov;
825 	struct dhcp_opt *eopt, *oopt;
826 	char *pfx;
827 
828 	/* If no embedded or encapsulated options, it's easy */
829 	if (opt->embopts_len == 0 && opt->encopts_len == 0) {
830 		if (opt->type & OT_RESERVED)
831 			return;
832 		if (print_option(fp, prefix, opt, 1, od, ol, ifname) == -1)
833 			logerr("%s: %s %d", ifname, __func__, opt->option);
834 		return;
835 	}
836 
837 	/* Create a new prefix based on the option */
838 	if (opt->type & OT_INDEX) {
839 		if (asprintf(&pfx, "%s_%s%d",
840 		    prefix, opt->var, ++opt->index) == -1)
841 			pfx = NULL;
842 	} else {
843 		if (asprintf(&pfx, "%s_%s", prefix, opt->var) == -1)
844 			pfx = NULL;
845 	}
846 	if (pfx == NULL) {
847 		logerr(__func__);
848 		return;
849 	}
850 
851 	/* Embedded options are always processed first as that
852 	 * is a fixed layout */
853 	for (i = 0, eopt = opt->embopts; i < opt->embopts_len; i++, eopt++) {
854 		eo = dhcp_optlen(eopt, ol);
855 		if (eo == -1) {
856 			logerrx("%s: %s %d.%d/%zu: "
857 			    "malformed embedded option",
858 			    ifname, __func__, opt->option,
859 			    eopt->option, i);
860 			goto out;
861 		}
862 		if (eo == 0) {
863 			/* An option was expected, but there is no data
864 			 * data for it.
865 			 * This may not be an error as some options like
866 			 * DHCP FQDN in RFC4702 have a string as the last
867 			 * option which is optional. */
868 			if (ol != 0 || !(eopt->type & OT_OPTIONAL))
869 				logerrx("%s: %s %d.%d/%zu: "
870 				    "missing embedded option",
871 				    ifname, __func__, opt->option,
872 				    eopt->option, i);
873 			goto out;
874 		}
875 		/* Use the option prefix if the embedded option
876 		 * name is different.
877 		 * This avoids new_fqdn_fqdn which would be silly. */
878 		if (!(eopt->type & OT_RESERVED)) {
879 			ov = strcmp(opt->var, eopt->var);
880 			if (print_option(fp, pfx, eopt, ov, od, (size_t)eo,
881 			    ifname) == -1)
882 				logerr("%s: %s %d.%d/%zu",
883 				    ifname, __func__,
884 				    opt->option, eopt->option, i);
885 		}
886 		od += (size_t)eo;
887 		ol -= (size_t)eo;
888 	}
889 
890 	/* Enumerate our encapsulated options */
891 	if (opt->encopts_len && ol > 0) {
892 		/* Zero any option indexes
893 		 * We assume that referenced encapsulated options are NEVER
894 		 * recursive as the index order could break. */
895 		for (i = 0, eopt = opt->encopts;
896 		    i < opt->encopts_len;
897 		    i++, eopt++)
898 		{
899 			eoc = opt->option;
900 			if (eopt->type & OT_OPTION) {
901 				dgetopt(ctx, NULL, &eoc, NULL, NULL, 0, &oopt);
902 				if (oopt)
903 					oopt->index = 0;
904 			}
905 		}
906 
907 		while ((eod = dgetopt(ctx, &eos, &eoc, &eol, od, ol, &oopt))) {
908 			for (i = 0, eopt = opt->encopts;
909 			    i < opt->encopts_len;
910 			    i++, eopt++)
911 			{
912 				if (eopt->option != eoc)
913 					continue;
914 				if (eopt->type & OT_OPTION) {
915 					if (oopt == NULL)
916 						/* Report error? */
917 						continue;
918 				}
919 				dhcp_envoption(ctx, fp, pfx, ifname,
920 				    eopt->type & OT_OPTION ? oopt:eopt,
921 				    dgetopt, eod, eol);
922 			}
923 			od += eos + eol;
924 			ol -= eos + eol;
925 		}
926 	}
927 
928 out:
929 	free(pfx);
930 }
931 
932 void
933 dhcp_zero_index(struct dhcp_opt *opt)
934 {
935 	size_t i;
936 	struct dhcp_opt *o;
937 
938 	opt->index = 0;
939 	for (i = 0, o = opt->embopts; i < opt->embopts_len; i++, o++)
940 		dhcp_zero_index(o);
941 	for (i = 0, o = opt->encopts; i < opt->encopts_len; i++, o++)
942 		dhcp_zero_index(o);
943 }
944 
945 ssize_t
946 dhcp_readfile(struct dhcpcd_ctx *ctx, const char *file, void *data, size_t len)
947 {
948 
949 #ifdef PRIVSEP
950 	if (ctx->options & DHCPCD_PRIVSEP &&
951 	    !(ctx->options & DHCPCD_PRIVSEPROOT))
952 		return ps_root_readfile(ctx, file, data, len);
953 #else
954 	UNUSED(ctx);
955 #endif
956 
957 	return readfile(file, data, len);
958 }
959 
960 ssize_t
961 dhcp_writefile(struct dhcpcd_ctx *ctx, const char *file, mode_t mode,
962     const void *data, size_t len)
963 {
964 
965 #ifdef PRIVSEP
966 	if (ctx->options & DHCPCD_PRIVSEP &&
967 	    !(ctx->options & DHCPCD_PRIVSEPROOT))
968 		return ps_root_writefile(ctx, file, mode, data, len);
969 #else
970 	UNUSED(ctx);
971 #endif
972 
973 	return writefile(file, mode, data, len);
974 }
975 
976 int
977 dhcp_filemtime(struct dhcpcd_ctx *ctx, const char *file, time_t *time)
978 {
979 
980 #ifdef PRIVSEP
981 	if (ctx->options & DHCPCD_PRIVSEP &&
982 	    !(ctx->options & DHCPCD_PRIVSEPROOT))
983 		return (int)ps_root_filemtime(ctx, file, time);
984 #else
985 	UNUSED(ctx);
986 #endif
987 
988 	return filemtime(file, time);
989 }
990 
991 int
992 dhcp_unlink(struct dhcpcd_ctx *ctx, const char *file)
993 {
994 
995 #ifdef PRIVSEP
996 	if (ctx->options & DHCPCD_PRIVSEP &&
997 	    !(ctx->options & DHCPCD_PRIVSEPROOT))
998 		return (int)ps_root_unlink(ctx, file);
999 #else
1000 	UNUSED(ctx);
1001 #endif
1002 
1003 	return unlink(file);
1004 }
1005 
1006 size_t
1007 dhcp_read_hwaddr_aton(struct dhcpcd_ctx *ctx, uint8_t **data, const char *file)
1008 {
1009 	char buf[BUFSIZ];
1010 	ssize_t bytes;
1011 	size_t len;
1012 
1013 	bytes = dhcp_readfile(ctx, file, buf, sizeof(buf));
1014 	if (bytes == -1 || bytes == sizeof(buf))
1015 		return 0;
1016 
1017 	bytes[buf] = '\0';
1018 	len = hwaddr_aton(NULL, buf);
1019 	if (len == 0)
1020 		return 0;
1021 	*data = malloc(len);
1022 	if (*data == NULL)
1023 		return 0;
1024 	hwaddr_aton(*data, buf);
1025 	return len;
1026 }
1027