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