Home | History | Annotate | Line # | Download | only in src
      1 /* SPDX-License-Identifier: BSD-2-Clause */
      2 /*
      3  * dhcpcd - DHCP client daemon
      4  * Copyright (c) 2006-2025 Roy Marples <roy (at) 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 	else if (opt->type & OT_URI)
    129 		printf(" uri");
    130 	if (opt->type & OT_RFC3361)
    131 		printf(" rfc3361");
    132 	if (opt->type & OT_RFC3442)
    133 		printf(" rfc3442");
    134 	if (opt->type & OT_REQUEST)
    135 		printf(" request");
    136 	if (opt->type & OT_NOREQ)
    137 		printf(" norequest");
    138 	if (opt->type & OT_TRUNCATED)
    139 		printf(" truncated");
    140 	putchar('\n');
    141 	fflush(stdout);
    142 }
    143 
    144 struct dhcp_opt *
    145 vivso_find(uint32_t iana_en, const void *arg)
    146 {
    147 	const struct interface *ifp;
    148 	size_t i;
    149 	struct dhcp_opt *opt;
    150 
    151 	ifp = arg;
    152 	for (i = 0, opt = ifp->options->vivso_override;
    153 	    i < ifp->options->vivso_override_len;
    154 	    i++, opt++)
    155 		if (opt->option == iana_en)
    156 			return opt;
    157 	for (i = 0, opt = ifp->ctx->vivso;
    158 	    i < ifp->ctx->vivso_len;
    159 	    i++, opt++)
    160 		if (opt->option == iana_en)
    161 			return opt;
    162 	return NULL;
    163 }
    164 
    165 ssize_t
    166 dhcp_vendor(char *str, size_t len)
    167 {
    168 	struct utsname utn;
    169 	char *p;
    170 	int l;
    171 
    172 	if (uname(&utn) == -1)
    173 		return (ssize_t)snprintf(str, len, "%s-%s",
    174 		    PACKAGE, VERSION);
    175 	p = str;
    176 	l = snprintf(p, len,
    177 	    "%s-%s:%s-%s:%s", PACKAGE, VERSION,
    178 	    utn.sysname, utn.release, utn.machine);
    179 	if (l == -1 || (size_t)(l + 1) > len)
    180 		return -1;
    181 	p += l;
    182 	len -= (size_t)l;
    183 	l = if_machinearch(p + 1, len - 1);
    184 	if (l == -1 || (size_t)(l + 1) > len)
    185 		return -1;
    186 	*p = ':';
    187 	p += l;
    188 	return p - str;
    189 }
    190 
    191 int
    192 make_option_mask(const struct dhcp_opt *dopts, size_t dopts_len,
    193     const struct dhcp_opt *odopts, size_t odopts_len,
    194     uint8_t *mask, const char *opts, int add)
    195 {
    196 	char *token, *o, *p;
    197 	const struct dhcp_opt *opt;
    198 	int match, e;
    199 	unsigned int n;
    200 	size_t i;
    201 
    202 	if (opts == NULL)
    203 		return -1;
    204 	o = p = strdup(opts);
    205 	while ((token = strsep(&p, ", "))) {
    206 		if (*token == '\0')
    207 			continue;
    208 		if (strncmp(token, "dhcp6_", 6) == 0)
    209 			token += 6;
    210 		if (strncmp(token, "nd_", 3) == 0)
    211 			token += 3;
    212 		match = 0;
    213 		for (i = 0, opt = odopts; i < odopts_len; i++, opt++) {
    214 			if (opt->var == NULL || opt->option == 0)
    215 				continue; /* buggy dhcpcd-definitions.conf */
    216 			if (strcmp(opt->var, token) == 0)
    217 				match = 1;
    218 			else {
    219 				n = (unsigned int)strtou(token, NULL, 0,
    220 				    0, UINT_MAX, &e);
    221 				if (e == 0 && opt->option == n)
    222 					match = 1;
    223 			}
    224 			if (match)
    225 				break;
    226 		}
    227 		if (match == 0) {
    228 			for (i = 0, opt = dopts; i < dopts_len; i++, opt++) {
    229 				if (strcmp(opt->var, token) == 0)
    230 				        match = 1;
    231 				else {
    232 					n = (unsigned int)strtou(token, NULL, 0,
    233 					    0, UINT_MAX, &e);
    234 					if (e == 0 && opt->option == n)
    235 						match = 1;
    236 				}
    237 				if (match)
    238 					break;
    239 			}
    240 		}
    241 		if (!match || !opt->option) {
    242 			free(o);
    243 			errno = ENOENT;
    244 			return -1;
    245 		}
    246 		if (add == 2 && !(opt->type & OT_ADDRIPV4)) {
    247 			free(o);
    248 			errno = EINVAL;
    249 			return -1;
    250 		}
    251 		if (add == 1 || add == 2)
    252 			add_option_mask(mask, opt->option);
    253 		else
    254 			del_option_mask(mask, opt->option);
    255 	}
    256 	free(o);
    257 	return 0;
    258 }
    259 
    260 size_t
    261 encode_rfc1035(const char *src, uint8_t *dst)
    262 {
    263 	uint8_t *p;
    264 	uint8_t *lp;
    265 	size_t len;
    266 	uint8_t has_dot;
    267 
    268 	if (src == NULL || *src == '\0')
    269 		return 0;
    270 
    271 	if (dst) {
    272 		p = dst;
    273 		lp = p++;
    274 	}
    275 	/* Silence bogus GCC warnings */
    276 	else
    277 		p = lp = NULL;
    278 
    279 	len = 1;
    280 	has_dot = 0;
    281 	for (; *src; src++) {
    282 		if (*src == '\0')
    283 			break;
    284 		if (*src == '.') {
    285 			/* Skip the trailing . */
    286 			if (src[1] == '\0')
    287 				break;
    288 			has_dot = 1;
    289 			if (dst) {
    290 				*lp = (uint8_t)(p - lp - 1);
    291 				if (*lp == '\0')
    292 					return len;
    293 				lp = p++;
    294 			}
    295 		} else if (dst)
    296 			*p++ = (uint8_t)*src;
    297 		len++;
    298 	}
    299 
    300 	if (dst) {
    301 		*lp = (uint8_t)(p - lp - 1);
    302 		if (has_dot)
    303 			*p++ = '\0';
    304 	}
    305 
    306 	if (has_dot)
    307 		len++;
    308 
    309 	return len;
    310 }
    311 
    312 /* Decode an RFC1035 DNS search order option into a space
    313  * separated string. Returns length of string (including
    314  * terminating zero) or zero on error. out may be NULL
    315  * to just determine output length. */
    316 ssize_t
    317 decode_rfc1035(char *out, size_t len, const uint8_t *p, size_t pl)
    318 {
    319 	const char *start;
    320 	size_t start_len, l, d_len, o_len;
    321 	const uint8_t *r, *q = p, *e;
    322 	int hops;
    323 	uint8_t ltype;
    324 
    325 	o_len = 0;
    326 	start = out;
    327 	start_len = len;
    328 	q = p;
    329 	e = p + pl;
    330 	while (q < e) {
    331 		r = NULL;
    332 		d_len = 0;
    333 		hops = 0;
    334 		/* Check we are inside our length again in-case
    335 		 * the name isn't fully qualified (ie, not terminated) */
    336 		while (q < e && (l = (size_t)*q++)) {
    337 			ltype = l & 0xc0;
    338 			if (ltype == 0x80 || ltype == 0x40) {
    339 				/* Currently reserved for future use as noted
    340 				 * in RFC1035 4.1.4 as the 10 and 01
    341 				 * combinations. */
    342 				errno = ENOTSUP;
    343 				return -1;
    344 			}
    345 			else if (ltype == 0xc0) { /* pointer */
    346 				if (q == e) {
    347 					errno = ERANGE;
    348 					return -1;
    349 				}
    350 				l = (l & 0x3f) << 8;
    351 				l |= *q++;
    352 				/* save source of first jump. */
    353 				if (!r)
    354 					r = q;
    355 				hops++;
    356 				if (hops > 255) {
    357 					errno = ERANGE;
    358 					return -1;
    359 				}
    360 				q = p + l;
    361 				if (q >= e) {
    362 					errno = ERANGE;
    363 					return -1;
    364 				}
    365 			} else {
    366 				/* straightforward name segment, add with '.' */
    367 				if (q + l > e) {
    368 					errno = ERANGE;
    369 					return -1;
    370 				}
    371 				if (l > NS_MAXLABEL) {
    372 					errno = EINVAL;
    373 					return -1;
    374 				}
    375 				d_len += l + 1;
    376 				if (out) {
    377 					if (l + 1 > len) {
    378 						errno = ENOBUFS;
    379 						return -1;
    380 					}
    381 					memcpy(out, q, l);
    382 					out += l;
    383 					*out++ = '.';
    384 					len -= l;
    385 					len--;
    386 				}
    387 				q += l;
    388 			}
    389 		}
    390 
    391 		/* Don't count the trailing NUL */
    392 		if (d_len > NS_MAXDNAME + 1) {
    393 			errno = E2BIG;
    394 			return -1;
    395 		}
    396 		o_len += d_len;
    397 
    398 		/* change last dot to space */
    399 		if (out && out != start)
    400 			*(out - 1) = ' ';
    401 		if (r)
    402 			q = r;
    403 	}
    404 
    405 	/* change last space to zero terminator */
    406 	if (out) {
    407 		if (out != start)
    408 			*(out - 1) = '\0';
    409 		else if (start_len > 0)
    410 			*out = '\0';
    411 	}
    412 
    413 	/* Remove the trailing NUL */
    414 	if (o_len != 0)
    415 		o_len--;
    416 
    417 	return (ssize_t)o_len;
    418 }
    419 
    420 /* Check for a valid name as per RFC952 and RFC1123 section 2.1 */
    421 static ssize_t
    422 valid_domainname(char *lbl, int type)
    423 {
    424 	char *slbl = lbl, *lst = NULL;
    425 	unsigned char c;
    426 	int len = 0;
    427 	bool start = true, errset = false;
    428 
    429 	if (lbl == NULL || *lbl == '\0') {
    430 		errno = EINVAL;
    431 		return 0;
    432 	}
    433 
    434 	for (;;) {
    435 		c = (unsigned char)*lbl++;
    436 		if (c == '\0')
    437 			return lbl - slbl - 1;
    438 		if (c == ' ') {
    439 			if (lbl - 1 == slbl) /* No space at start */
    440 				break;
    441 			if (!(type & OT_ARRAY))
    442 				break;
    443 			/* Skip to the next label */
    444 			if (!start) {
    445 				start = true;
    446 				lst = lbl - 1;
    447 			}
    448 			if (len)
    449 				len = 0;
    450 			continue;
    451 		}
    452 		if (c == '.') {
    453 			if (*lbl == '.')
    454 				break;
    455 			len = 0;
    456 			continue;
    457 		}
    458 		if (((c == '-' || c == '_') &&
    459 		    !start && *lbl != ' ' && *lbl != '\0') ||
    460 		    isalnum(c))
    461 		{
    462 			if (++len > NS_MAXLABEL) {
    463 				errno = ERANGE;
    464 				errset = true;
    465 				break;
    466 			}
    467 		} else
    468 			break;
    469 		if (start)
    470 			start = false;
    471 	}
    472 
    473 	if (!errset)
    474 		errno = EINVAL;
    475 	if (lst) {
    476 		/* At least one valid domain, return it */
    477 		*lst = '\0';
    478 		return lst - slbl;
    479 	}
    480 	return 0;
    481 }
    482 
    483 /*
    484  * Prints a chunk of data to a string.
    485  * PS_SHELL goes as it is these days, it's upto the target to validate it.
    486  * PS_SAFE has all non ascii and non printables changes to escaped octal.
    487  */
    488 static const char hexchrs[] = "0123456789abcdef";
    489 ssize_t
    490 print_string(char *dst, size_t len, int type, const uint8_t *data, size_t dl)
    491 {
    492 	char *odst;
    493 	uint8_t c;
    494 	const uint8_t *e;
    495 	size_t bytes;
    496 
    497 	odst = dst;
    498 	bytes = 0;
    499 	e = data + dl;
    500 
    501 	while (data < e) {
    502 		c = *data++;
    503 		if (type & OT_BINHEX) {
    504 			if (dst) {
    505 				if (len  == 0 || len == 1) {
    506 					errno = ENOBUFS;
    507 					return -1;
    508 				}
    509 				*dst++ = hexchrs[(c & 0xF0) >> 4];
    510 				*dst++ = hexchrs[(c & 0x0F)];
    511 				len -= 2;
    512 			}
    513 			bytes += 2;
    514 			continue;
    515 		}
    516 		if (type & OT_ASCII && (!isascii(c))) {
    517 			errno = EINVAL;
    518 			break;
    519 		}
    520 		if (!(type & (OT_ASCII | OT_RAW | OT_ESCSTRING | OT_ESCFILE)) &&
    521 		    (!isascii(c) && !isprint(c)))
    522 		{
    523 			errno = EINVAL;
    524 			break;
    525 		}
    526 		if (type & OT_URI && isspace(c)) {
    527 			errno = EINVAL;
    528 			break;
    529 		}
    530 		if ((type & (OT_ESCSTRING | OT_ESCFILE) &&
    531 		    (c == '\\' || !isascii(c) || !isprint(c))) ||
    532 		    (type & OT_ESCFILE && (c == '/' || c == ' ')))
    533 		{
    534 			errno = EINVAL;
    535 			if (c == '\\') {
    536 				if (dst) {
    537 					if (len  == 0 || len == 1) {
    538 						errno = ENOBUFS;
    539 						return -1;
    540 					}
    541 					*dst++ = '\\'; *dst++ = '\\';
    542 					len -= 2;
    543 				}
    544 				bytes += 2;
    545 				continue;
    546 			}
    547 			if (dst) {
    548 				if (len < 5) {
    549 					errno = ENOBUFS;
    550 					return -1;
    551 				}
    552 				*dst++ = '\\';
    553 		                *dst++ = (char)(((c >> 6) & 03) + '0');
    554 		                *dst++ = (char)(((c >> 3) & 07) + '0');
    555 		                *dst++ = (char)(( c       & 07) + '0');
    556 				len -= 4;
    557 			}
    558 			bytes += 4;
    559 		} else {
    560 			if (dst) {
    561 				if (len == 0) {
    562 					errno = ENOBUFS;
    563 					return -1;
    564 				}
    565 				*dst++ = (char)c;
    566 				len--;
    567 			}
    568 			bytes++;
    569 		}
    570 	}
    571 
    572 	/* NULL */
    573 	if (dst) {
    574 		if (len == 0) {
    575 			errno = ENOBUFS;
    576 			return -1;
    577 		}
    578 		*dst = '\0';
    579 
    580 		/* Now we've printed it, validate the domain */
    581 		if (type & OT_DOMAIN && !valid_domainname(odst, type)) {
    582 			*odst = '\0';
    583 			return 1;
    584 		}
    585 
    586 	}
    587 
    588 	return (ssize_t)bytes;
    589 }
    590 
    591 #define ADDR6SZ		16
    592 static ssize_t
    593 dhcp_optlen(const struct dhcp_opt *opt, size_t dl)
    594 {
    595 	size_t sz;
    596 
    597 	if (opt->type & OT_ADDRIPV6)
    598 		sz = ADDR6SZ;
    599 	else if (opt->type & (OT_INT32 | OT_UINT32 | OT_ADDRIPV4))
    600 		sz = sizeof(uint32_t);
    601 	else if (opt->type & (OT_INT16 | OT_UINT16))
    602 		sz = sizeof(uint16_t);
    603 	else if (opt->type & (OT_INT8 | OT_UINT8 | OT_BITFLAG))
    604 		sz = sizeof(uint8_t);
    605 	else if (opt->type & OT_FLAG)
    606 		return 0;
    607 	else {
    608 		/* All other types are variable length */
    609 		if (opt->len) {
    610 			if ((size_t)opt->len > dl) {
    611 				errno = EOVERFLOW;
    612 				return -1;
    613 			}
    614 			return (ssize_t)opt->len;
    615 		}
    616 		return (ssize_t)dl;
    617 	}
    618 	if (dl < sz) {
    619 		if (opt->type & OT_TRUNCATED)
    620 			return (ssize_t)dl;
    621 		errno = EOVERFLOW;
    622 		return -1;
    623 	}
    624 
    625 	/* Trim any extra data.
    626 	 * Maybe we need a setting to reject DHCP options with extra data? */
    627 	if (opt->type & OT_ARRAY)
    628 		return (ssize_t)(dl - (dl % sz));
    629 	return (ssize_t)sz;
    630 }
    631 
    632 static ssize_t
    633 print_option(FILE *fp, const char *prefix, const struct dhcp_opt *opt,
    634     int vname,
    635     const uint8_t *data, size_t dl, const char *ifname)
    636 {
    637 	fpos_t fp_pos;
    638 	const uint8_t *e, *t;
    639 	uint16_t u16;
    640 	int16_t s16;
    641 	uint32_t u32;
    642 	int32_t s32;
    643 	struct in_addr addr;
    644 	ssize_t sl;
    645 	size_t l;
    646 
    647 	/* Ensure a valid length */
    648 	dl = (size_t)dhcp_optlen(opt, dl);
    649 	if ((ssize_t)dl == -1)
    650 		return 0;
    651 
    652 	if (fgetpos(fp, &fp_pos) == -1)
    653 		return -1;
    654 	if (fprintf(fp, "%s", prefix) == -1)
    655 		goto err;
    656 
    657 	/* We printed something, so always goto err from now-on
    658 	 * to terminate the string. */
    659 	if (vname) {
    660 		if (fprintf(fp, "_%s", opt->var) == -1)
    661 			goto err;
    662 	}
    663 	if (fputc('=', fp) == EOF)
    664 		goto err;
    665 	if (dl == 0)
    666 		goto done;
    667 
    668 	if (opt->type & OT_RFC1035) {
    669 		char domain[NS_MAXDNAME];
    670 
    671 		sl = decode_rfc1035(domain, sizeof(domain), data, dl);
    672 		if (sl == -1)
    673 			goto err;
    674 		if (sl == 0)
    675 			goto done;
    676 		if (!valid_domainname(domain, opt->type))
    677 			goto err;
    678 		return efprintf(fp, "%s", domain);
    679 	}
    680 
    681 #ifdef INET
    682 	if (opt->type & OT_RFC3361)
    683 		return print_rfc3361(fp, data, dl);
    684 
    685 	if (opt->type & OT_RFC3442)
    686 		return print_rfc3442(fp, data, dl);
    687 #endif
    688 
    689 	/* Produces a space separated list of URIs.
    690 	 * This is valid as a URI cannot contain a space. */
    691 	if ((opt->type & (OT_ARRAY | OT_URI)) == (OT_ARRAY | OT_URI)) {
    692 #ifdef SMALL
    693 		errno = ENOTSUP;
    694 		return -1;
    695 #else
    696 		char buf[UINT16_MAX + 1];
    697 		uint16_t sz;
    698 		bool first = true;
    699 
    700 		while (dl) {
    701 			if (dl < 2) {
    702 				errno = EINVAL;
    703 				goto err;
    704 			}
    705 
    706 			memcpy(&u16, data, sizeof(u16));
    707 			sz = ntohs(u16);
    708 			data += sizeof(u16);
    709 			dl -= sizeof(u16);
    710 
    711 			if (sz == 0)
    712 				continue;
    713 			if (sz > dl) {
    714 				errno = EINVAL;
    715 				goto err;
    716 			}
    717 
    718 			if (print_string(buf, sizeof(buf),
    719 			    opt->type, data, sz) == -1)
    720 				goto err;
    721 
    722 			if (first)
    723 				first = false;
    724 			else if (fputc(' ', fp) == EOF)
    725 				goto err;
    726 
    727 			if (fprintf(fp, "%s", buf) == -1)
    728 				goto err;
    729 
    730 			data += sz;
    731 			dl -= sz;
    732 		}
    733 
    734 		if (fputc('\0', fp) == EOF)
    735 			goto err;
    736 		return 0;
    737 #endif
    738 	}
    739 
    740 	if (opt->type & (OT_STRING | OT_URI)) {
    741 		char buf[1024];
    742 
    743 		if (print_string(buf, sizeof(buf), opt->type, data, dl) == -1)
    744 			goto err;
    745 		return efprintf(fp, "%s", buf);
    746 	}
    747 
    748 	if (opt->type & OT_FLAG)
    749 		return efprintf(fp, "1");
    750 
    751 	if (opt->type & OT_BITFLAG) {
    752 		/* bitflags are a string, MSB first, such as ABCDEFGH
    753 		 * where A is 10000000, B is 01000000, etc. */
    754 		for (l = 0, sl = sizeof(opt->bitflags) - 1;
    755 		    l < sizeof(opt->bitflags);
    756 		    l++, sl--)
    757 		{
    758 			if (opt->bitflags[l] == '1') {
    759 				if (fprintf(fp, "%d", *data & (1 << sl)) == -1)
    760 					goto err;
    761 				continue;
    762 			}
    763 			/* Don't print NULL or 0 flags */
    764 			if (opt->bitflags[l] != '\0' &&
    765 			    opt->bitflags[l] != '0' &&
    766 			    *data & (1 << sl))
    767 			{
    768 				if (fputc(opt->bitflags[l], fp) == EOF)
    769 					goto err;
    770 			}
    771 		}
    772 		goto done;
    773 	}
    774 
    775 	t = data;
    776 	e = data + dl;
    777 	while (data < e) {
    778 		if (data != t) {
    779 			if (fputc(' ', fp) == EOF)
    780 				goto err;
    781 		}
    782 		if (opt->type & OT_UINT8) {
    783 			if (fprintf(fp, "%u", *data) == -1)
    784 				goto err;
    785 			data++;
    786 		} else if (opt->type & OT_INT8) {
    787 			if (fprintf(fp, "%d", *data) == -1)
    788 				goto err;
    789 			data++;
    790 		} else if (opt->type & OT_UINT16) {
    791 			memcpy(&u16, data, sizeof(u16));
    792 			u16 = ntohs(u16);
    793 			if (fprintf(fp, "%u", u16) == -1)
    794 				goto err;
    795 			data += sizeof(u16);
    796 		} else if (opt->type & OT_INT16) {
    797 			memcpy(&u16, data, sizeof(u16));
    798 			s16 = (int16_t)ntohs(u16);
    799 			if (fprintf(fp, "%d", s16) == -1)
    800 				goto err;
    801 			data += sizeof(u16);
    802 		} else if (opt->type & OT_UINT32) {
    803 			memcpy(&u32, data, sizeof(u32));
    804 			u32 = ntohl(u32);
    805 			if (fprintf(fp, "%u", u32) == -1)
    806 				goto err;
    807 			data += sizeof(u32);
    808 		} else if (opt->type & OT_INT32) {
    809 			memcpy(&u32, data, sizeof(u32));
    810 			s32 = (int32_t)ntohl(u32);
    811 			if (fprintf(fp, "%d", s32) == -1)
    812 				goto err;
    813 			data += sizeof(u32);
    814 		} else if (opt->type & OT_ADDRIPV4) {
    815 			memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
    816 			if (fprintf(fp, "%s", inet_ntoa(addr)) == -1)
    817 				goto err;
    818 			data += sizeof(addr.s_addr);
    819 		} else if (opt->type & OT_ADDRIPV6) {
    820 			uint8_t databuf[sizeof(struct in6_addr)] = { 0 };
    821 			size_t datalen = e - data >= 16 ? 16 : (size_t)(e - data);
    822 			char buf[INET6_ADDRSTRLEN];
    823 
    824 			/* avoid inet_ntop going beyond our option space by
    825 			 * copying out into a temporary buffer. */
    826 			memcpy(databuf, data, datalen);
    827 			if (inet_ntop(AF_INET6, databuf, buf, sizeof(buf)) == NULL)
    828 				goto err;
    829 			if (fprintf(fp, "%s", buf) == -1)
    830 				goto err;
    831 			if (data[0] == 0xfe && (data[1] & 0xc0) == 0x80) {
    832 				if (fprintf(fp,"%%%s", ifname) == -1)
    833 					goto err;
    834 			}
    835 			data += 16;
    836 		} else {
    837 			errno = EINVAL;
    838 			goto err;
    839 		}
    840 	}
    841 
    842 done:
    843 	if (fputc('\0', fp) == EOF)
    844 		return -1;
    845 	return 1;
    846 
    847 err:
    848 	(void)fsetpos(fp, &fp_pos);
    849 	return -1;
    850 }
    851 
    852 int
    853 dhcp_set_leasefile(char *leasefile, size_t len, int family,
    854     const struct interface *ifp)
    855 {
    856 	char ssid[1 + (IF_SSIDLEN * 4) + 1]; /* - prefix and NUL terminated. */
    857 
    858 	if (ifp->name[0] == '\0') {
    859 		strlcpy(leasefile, ifp->ctx->pidfile, len);
    860 		return 0;
    861 	}
    862 
    863 	switch (family) {
    864 	case AF_INET:
    865 	case AF_INET6:
    866 		break;
    867 	default:
    868 		errno = EINVAL;
    869 		return -1;
    870 	}
    871 
    872 	if (ifp->wireless) {
    873 		ssid[0] = '-';
    874 		print_string(ssid + 1, sizeof(ssid) - 1,
    875 		    OT_ESCFILE,
    876 		    (const uint8_t *)ifp->ssid, ifp->ssid_len);
    877 	} else
    878 		ssid[0] = '\0';
    879 	return snprintf(leasefile, len,
    880 	    family == AF_INET ? LEASEFILE : LEASEFILE6,
    881 	    ifp->name, ssid);
    882 }
    883 
    884 void
    885 dhcp_envoption(struct dhcpcd_ctx *ctx, FILE *fp, const char *prefix,
    886     const char *ifname, struct dhcp_opt *opt,
    887     const uint8_t *(*dgetopt)(struct dhcpcd_ctx *,
    888     size_t *, unsigned int *, size_t *,
    889     const uint8_t *, size_t, struct dhcp_opt **),
    890     const uint8_t *od, size_t ol)
    891 {
    892 	size_t i, eos, eol;
    893 	ssize_t eo;
    894 	unsigned int eoc;
    895 	const uint8_t *eod;
    896 	int ov;
    897 	struct dhcp_opt *eopt, *oopt;
    898 	char *pfx;
    899 
    900 	/* If no embedded or encapsulated options, it's easy */
    901 	if (opt->embopts_len == 0 && opt->encopts_len == 0) {
    902 		if (opt->type & OT_RESERVED)
    903 			return;
    904 		if (print_option(fp, prefix, opt, 1, od, ol, ifname) == -1)
    905 			logerr("%s: %s %d", ifname, __func__, opt->option);
    906 		return;
    907 	}
    908 
    909 	/* Create a new prefix based on the option */
    910 	if (opt->type & OT_INDEX) {
    911 		if (asprintf(&pfx, "%s_%s%d",
    912 		    prefix, opt->var, ++opt->index) == -1)
    913 			pfx = NULL;
    914 	} else {
    915 		if (asprintf(&pfx, "%s_%s", prefix, opt->var) == -1)
    916 			pfx = NULL;
    917 	}
    918 	if (pfx == NULL) {
    919 		logerr(__func__);
    920 		return;
    921 	}
    922 
    923 	/* Embedded options are always processed first as that
    924 	 * is a fixed layout */
    925 	for (i = 0, eopt = opt->embopts; i < opt->embopts_len; i++, eopt++) {
    926 		eo = dhcp_optlen(eopt, ol);
    927 		if (eo == -1) {
    928 			logerrx("%s: %s %d.%d/%zu: "
    929 			    "malformed embedded option",
    930 			    ifname, __func__, opt->option,
    931 			    eopt->option, i);
    932 			goto out;
    933 		}
    934 		if (eo == 0) {
    935 			/* An option was expected, but there is no data
    936 			 * data for it.
    937 			 * This may not be an error as some options like
    938 			 * DHCP FQDN in RFC4702 have a string as the last
    939 			 * option which is optional. */
    940 			if (ol != 0 || !(eopt->type & OT_OPTIONAL))
    941 				logerrx("%s: %s %d.%d/%zu: "
    942 				    "missing embedded option",
    943 				    ifname, __func__, opt->option,
    944 				    eopt->option, i);
    945 			goto out;
    946 		}
    947 		/* Use the option prefix if the embedded option
    948 		 * name is different.
    949 		 * This avoids new_fqdn_fqdn which would be silly. */
    950 		if (!(eopt->type & OT_RESERVED)) {
    951 			ov = strcmp(opt->var, eopt->var);
    952 			if (print_option(fp, pfx, eopt, ov, od, (size_t)eo,
    953 			    ifname) == -1)
    954 				logerr("%s: %s %d.%d/%zu",
    955 				    ifname, __func__,
    956 				    opt->option, eopt->option, i);
    957 		}
    958 		od += (size_t)eo;
    959 		ol -= (size_t)eo;
    960 	}
    961 
    962 	/* Enumerate our encapsulated options */
    963 	if (opt->encopts_len && ol > 0) {
    964 		/* Zero any option indexes
    965 		 * We assume that referenced encapsulated options are NEVER
    966 		 * recursive as the index order could break. */
    967 		for (i = 0, eopt = opt->encopts;
    968 		    i < opt->encopts_len;
    969 		    i++, eopt++)
    970 		{
    971 			eoc = opt->option;
    972 			if (eopt->type & OT_OPTION) {
    973 				dgetopt(ctx, NULL, &eoc, NULL, NULL, 0, &oopt);
    974 				if (oopt)
    975 					oopt->index = 0;
    976 			}
    977 		}
    978 
    979 		while ((eod = dgetopt(ctx, &eos, &eoc, &eol, od, ol, &oopt))) {
    980 			for (i = 0, eopt = opt->encopts;
    981 			    i < opt->encopts_len;
    982 			    i++, eopt++)
    983 			{
    984 				if (eopt->option != eoc)
    985 					continue;
    986 				if (eopt->type & OT_OPTION) {
    987 					if (oopt == NULL)
    988 						/* Report error? */
    989 						continue;
    990 				}
    991 				dhcp_envoption(ctx, fp, pfx, ifname,
    992 				    eopt->type & OT_OPTION ? oopt:eopt,
    993 				    dgetopt, eod, eol);
    994 			}
    995 			od += eos + eol;
    996 			ol -= eos + eol;
    997 		}
    998 	}
    999 
   1000 out:
   1001 	free(pfx);
   1002 }
   1003 
   1004 void
   1005 dhcp_zero_index(struct dhcp_opt *opt)
   1006 {
   1007 	size_t i;
   1008 	struct dhcp_opt *o;
   1009 
   1010 	opt->index = 0;
   1011 	for (i = 0, o = opt->embopts; i < opt->embopts_len; i++, o++)
   1012 		dhcp_zero_index(o);
   1013 	for (i = 0, o = opt->encopts; i < opt->encopts_len; i++, o++)
   1014 		dhcp_zero_index(o);
   1015 }
   1016 
   1017 ssize_t
   1018 dhcp_readfile(struct dhcpcd_ctx *ctx, const char *file, void *data, size_t len)
   1019 {
   1020 
   1021 #ifdef PRIVSEP
   1022 	if (ctx->options & DHCPCD_PRIVSEP &&
   1023 	    !(ctx->options & DHCPCD_PRIVSEPROOT))
   1024 		return ps_root_readfile(ctx, file, data, len);
   1025 #else
   1026 	UNUSED(ctx);
   1027 #endif
   1028 
   1029 	return readfile(file, data, len);
   1030 }
   1031 
   1032 ssize_t
   1033 dhcp_writefile(struct dhcpcd_ctx *ctx, const char *file, mode_t mode,
   1034     const void *data, size_t len)
   1035 {
   1036 
   1037 #ifdef PRIVSEP
   1038 	if (ctx->options & DHCPCD_PRIVSEP &&
   1039 	    !(ctx->options & DHCPCD_PRIVSEPROOT))
   1040 		return ps_root_writefile(ctx, file, mode, data, len);
   1041 #else
   1042 	UNUSED(ctx);
   1043 #endif
   1044 
   1045 	return writefile(file, mode, data, len);
   1046 }
   1047 
   1048 int
   1049 dhcp_filemtime(struct dhcpcd_ctx *ctx, const char *file, time_t *time)
   1050 {
   1051 
   1052 #ifdef PRIVSEP
   1053 	if (ctx->options & DHCPCD_PRIVSEP &&
   1054 	    !(ctx->options & DHCPCD_PRIVSEPROOT))
   1055 		return (int)ps_root_filemtime(ctx, file, time);
   1056 #else
   1057 	UNUSED(ctx);
   1058 #endif
   1059 
   1060 	return filemtime(file, time);
   1061 }
   1062 
   1063 int
   1064 dhcp_unlink(struct dhcpcd_ctx *ctx, const char *file)
   1065 {
   1066 
   1067 #ifdef PRIVSEP
   1068 	if (ctx->options & DHCPCD_PRIVSEP &&
   1069 	    !(ctx->options & DHCPCD_PRIVSEPROOT))
   1070 		return (int)ps_root_unlink(ctx, file);
   1071 #else
   1072 	UNUSED(ctx);
   1073 #endif
   1074 
   1075 	return unlink(file);
   1076 }
   1077 
   1078 size_t
   1079 dhcp_read_hwaddr_aton(struct dhcpcd_ctx *ctx, uint8_t **data, const char *file)
   1080 {
   1081 	char buf[BUFSIZ];
   1082 	ssize_t bytes;
   1083 	size_t len;
   1084 
   1085 	bytes = dhcp_readfile(ctx, file, buf, sizeof(buf));
   1086 	if (bytes == -1 || bytes == sizeof(buf))
   1087 		return 0;
   1088 
   1089 	bytes[buf] = '\0';
   1090 	len = hwaddr_aton(NULL, buf);
   1091 	if (len == 0)
   1092 		return 0;
   1093 	*data = malloc(len);
   1094 	if (*data == NULL)
   1095 		return 0;
   1096 	hwaddr_aton(*data, buf);
   1097 	return len;
   1098 }
   1099