Home | History | Annotate | Download | only in dhcpcd-6.8.2
      1 /*
      2  * dhcpcd - DHCP client daemon
      3  * Copyright (c) 2006-2015 Roy Marples <roy (at) marples.name>
      4  * All rights reserved
      5 
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     25  * SUCH DAMAGE.
     26  */
     27 
     28 #include <sys/utsname.h>
     29 
     30 #include <ctype.h>
     31 #include <errno.h>
     32 #include <fcntl.h>
     33 #include <inttypes.h>
     34 #include <stdlib.h>
     35 #include <string.h>
     36 #include <unistd.h>
     37 
     38 #include "config.h"
     39 
     40 #include "common.h"
     41 #include "dhcp-common.h"
     42 #include "dhcp.h"
     43 #include "if.h"
     44 #include "ipv6.h"
     45 
     46 void
     47 dhcp_print_option_encoding(const struct dhcp_opt *opt, int cols)
     48 {
     49 
     50 	while (cols < 40) {
     51 		putchar(' ');
     52 		cols++;
     53 	}
     54 	putchar('\t');
     55 	if (opt->type & EMBED)
     56 		printf(" embed");
     57 	if (opt->type & ENCAP)
     58 		printf(" encap");
     59 	if (opt->type & INDEX)
     60 		printf(" index");
     61 	if (opt->type & ARRAY)
     62 		printf(" array");
     63 	if (opt->type & UINT8)
     64 		printf(" byte");
     65 	else if (opt->type & UINT16)
     66 		printf(" uint16");
     67 	else if (opt->type & SINT16)
     68 		printf(" sint16");
     69 	else if (opt->type & UINT32)
     70 		printf(" uint32");
     71 	else if (opt->type & SINT32)
     72 		printf(" sint32");
     73 	else if (opt->type & ADDRIPV4)
     74 		printf(" ipaddress");
     75 	else if (opt->type & ADDRIPV6)
     76 		printf(" ip6address");
     77 	else if (opt->type & FLAG)
     78 		printf(" flag");
     79 	else if (opt->type & RFC3397)
     80 		printf(" domain");
     81 	else if (opt->type & DOMAIN)
     82 		printf(" dname");
     83 	else if (opt->type & ASCII)
     84 		printf(" ascii");
     85 	else if (opt->type & RAW)
     86 		printf(" raw");
     87 	else if (opt->type & BINHEX)
     88 		printf(" binhex");
     89 	else if (opt->type & STRING)
     90 		printf(" string");
     91 	if (opt->type & RFC3361)
     92 		printf(" rfc3361");
     93 	if (opt->type & RFC3442)
     94 		printf(" rfc3442");
     95 	if (opt->type & RFC5969)
     96 		printf(" rfc5969");
     97 	if (opt->type & REQUEST)
     98 		printf(" request");
     99 	if (opt->type & NOREQ)
    100 		printf(" norequest");
    101 	putchar('\n');
    102 }
    103 
    104 struct dhcp_opt *
    105 vivso_find(uint32_t iana_en, const void *arg)
    106 {
    107 	const struct interface *ifp;
    108 	size_t i;
    109 	struct dhcp_opt *opt;
    110 
    111 	ifp = arg;
    112 	for (i = 0, opt = ifp->options->vivso_override;
    113 	    i < ifp->options->vivso_override_len;
    114 	    i++, opt++)
    115 		if (opt->option == iana_en)
    116 			return opt;
    117 	for (i = 0, opt = ifp->ctx->vivso;
    118 	    i < ifp->ctx->vivso_len;
    119 	    i++, opt++)
    120 		if (opt->option == iana_en)
    121 			return opt;
    122 	return NULL;
    123 }
    124 
    125 ssize_t
    126 dhcp_vendor(char *str, size_t len)
    127 {
    128 	struct utsname utn;
    129 	char *p;
    130 	int l;
    131 
    132 	if (uname(&utn) != 0)
    133 		return (ssize_t)snprintf(str, len, "%s-%s",
    134 		    PACKAGE, VERSION);
    135 	p = str;
    136 	l = snprintf(p, len,
    137 	    "%s-%s:%s-%s:%s", PACKAGE, VERSION,
    138 	    utn.sysname, utn.release, utn.machine);
    139 	if (l == -1 || (size_t)(l + 1) > len)
    140 		return -1;
    141 	p += l;
    142 	len -= (size_t)l;
    143 	l = if_machinearch(p, len);
    144 	if (l == -1 || (size_t)(l + 1) > len)
    145 		return -1;
    146 	p += l;
    147 	return p - str;
    148 }
    149 
    150 int
    151 make_option_mask(const struct dhcp_opt *dopts, size_t dopts_len,
    152     const struct dhcp_opt *odopts, size_t odopts_len,
    153     uint8_t *mask, const char *opts, int add)
    154 {
    155 	char *token, *o, *p;
    156 	const struct dhcp_opt *opt;
    157 	int match, e;
    158 	unsigned int n;
    159 	size_t i;
    160 
    161 	if (opts == NULL)
    162 		return -1;
    163 	o = p = strdup(opts);
    164 	while ((token = strsep(&p, ", "))) {
    165 		if (*token == '\0')
    166 			continue;
    167 		match = 0;
    168 		for (i = 0, opt = odopts; i < odopts_len; i++, opt++) {
    169 			if (strcmp(opt->var, token) == 0)
    170 				match = 1;
    171 			else {
    172 				n = (unsigned int)strtou(token, NULL, 0,
    173 				    0, UINT_MAX, &e);
    174 				if (e == 0 && opt->option == n)
    175 					match = 1;
    176 			}
    177 			if (match)
    178 				break;
    179 		}
    180 		if (match == 0) {
    181 			for (i = 0, opt = dopts; i < dopts_len; i++, opt++) {
    182 				if (strcmp(opt->var, token) == 0)
    183 				        match = 1;
    184 				else {
    185 					n = (unsigned int)strtou(token, NULL, 0,
    186 					    0, UINT_MAX, &e);
    187 					if (e == 0 && opt->option == n)
    188 						match = 1;
    189 				}
    190 				if (match)
    191 					break;
    192 			}
    193 		}
    194 		if (!match || !opt->option) {
    195 			free(o);
    196 			errno = ENOENT;
    197 			return -1;
    198 		}
    199 		if (add == 2 && !(opt->type & ADDRIPV4)) {
    200 			free(o);
    201 			errno = EINVAL;
    202 			return -1;
    203 		}
    204 		if (add == 1 || add == 2)
    205 			add_option_mask(mask, opt->option);
    206 		else
    207 			del_option_mask(mask, opt->option);
    208 	}
    209 	free(o);
    210 	return 0;
    211 }
    212 
    213 size_t
    214 encode_rfc1035(const char *src, uint8_t *dst)
    215 {
    216 	uint8_t *p;
    217 	uint8_t *lp;
    218 	size_t len;
    219 	uint8_t has_dot;
    220 
    221 	if (src == NULL || *src == '\0')
    222 		return 0;
    223 
    224 	if (dst) {
    225 		p = dst;
    226 		lp = p++;
    227 	}
    228 	/* Silence bogus GCC warnings */
    229 	else
    230 		p = lp = NULL;
    231 
    232 	len = 1;
    233 	has_dot = 0;
    234 	for (; *src; src++) {
    235 		if (*src == '\0')
    236 			break;
    237 		if (*src == '.') {
    238 			/* Skip the trailing . */
    239 			if (src[1] == '\0')
    240 				break;
    241 			has_dot = 1;
    242 			if (dst) {
    243 				*lp = (uint8_t)(p - lp - 1);
    244 				if (*lp == '\0')
    245 					return len;
    246 				lp = p++;
    247 			}
    248 		} else if (dst)
    249 			*p++ = (uint8_t)*src;
    250 		len++;
    251 	}
    252 
    253 	if (dst) {
    254 		*lp = (uint8_t)(p - lp - 1);
    255 		if (has_dot)
    256 			*p++ = '\0';
    257 	}
    258 
    259 	if (has_dot)
    260 		len++;
    261 
    262 	return len;
    263 }
    264 
    265 /* Decode an RFC3397 DNS search order option into a space
    266  * separated string. Returns length of string (including
    267  * terminating zero) or zero on error. out may be NULL
    268  * to just determine output length. */
    269 ssize_t
    270 decode_rfc3397(char *out, size_t len, const uint8_t *p, size_t pl)
    271 {
    272 	const char *start;
    273 	size_t start_len, l, count;
    274 	const uint8_t *r, *q = p, *e;
    275 	int hops;
    276 	uint8_t ltype;
    277 
    278 	count = 0;
    279 	start = out;
    280 	start_len = len;
    281 	q = p;
    282 	e = p + pl;
    283 	while (q < e) {
    284 		r = NULL;
    285 		hops = 0;
    286 		/* Check we are inside our length again in-case
    287 		 * the name isn't fully qualified (ie, not terminated) */
    288 		while (q < e && (l = (size_t)*q++)) {
    289 			ltype = l & 0xc0;
    290 			if (ltype == 0x80 || ltype == 0x40)
    291 				return -1;
    292 			else if (ltype == 0xc0) { /* pointer */
    293 				if (q == e) {
    294 					errno = ERANGE;
    295 					return -1;
    296 				}
    297 				l = (l & 0x3f) << 8;
    298 				l |= *q++;
    299 				/* save source of first jump. */
    300 				if (!r)
    301 					r = q;
    302 				hops++;
    303 				if (hops > 255) {
    304 					errno = ERANGE;
    305 					return -1;
    306 				}
    307 				q = p + l;
    308 				if (q >= e) {
    309 					errno = ERANGE;
    310 					return -1;
    311 				}
    312 			} else {
    313 				/* straightforward name segment, add with '.' */
    314 				if (q + l > e) {
    315 					errno = ERANGE;
    316 					return -1;
    317 				}
    318 				count += l + 1;
    319 				if (out) {
    320 					if (l + 1 > len) {
    321 						errno = ENOBUFS;
    322 						return -1;
    323 					}
    324 					memcpy(out, q, l);
    325 					out += l;
    326 					*out++ = '.';
    327 					len -= l;
    328 					len--;
    329 				}
    330 				q += l;
    331 			}
    332 		}
    333 		/* change last dot to space */
    334 		if (out && out != start)
    335 			*(out - 1) = ' ';
    336 		if (r)
    337 			q = r;
    338 	}
    339 
    340 	/* change last space to zero terminator */
    341 	if (out) {
    342 		if (out != start)
    343 			*(out - 1) = '\0';
    344 		else if (start_len > 0)
    345 			*out = '\0';
    346 	}
    347 
    348 	if (count)
    349 		/* Don't count the trailing NUL */
    350 		count--;
    351 	return (ssize_t)count;
    352 }
    353 
    354 /* Check for a valid domain name as per RFC1123 with the exception of
    355  * allowing - and _ (but not at start or end) as they seem to be widely used. */
    356 static int
    357 valid_domainname(char *lbl, int type)
    358 {
    359 	char *slbl, *lst;
    360 	unsigned char c;
    361 	int start, len, errset;
    362 
    363 	if (lbl == NULL || *lbl == '\0') {
    364 		errno = EINVAL;
    365 		return 0;
    366 	}
    367 
    368 	slbl = lbl;
    369 	lst = NULL;
    370 	start = 1;
    371 	len = errset = 0;
    372 	for (;;) {
    373 		c = (unsigned char)*lbl++;
    374 		if (c == '\0')
    375 			return 1;
    376 		if (c == ' ') {
    377 			if (lbl - 1 == slbl) /* No space at start */
    378 				break;
    379 			if (!(type & ARRAY))
    380 				break;
    381 			/* Skip to the next label */
    382 			if (!start) {
    383 				start = 1;
    384 				lst = lbl - 1;
    385 			}
    386 			if (len)
    387 				len = 0;
    388 			continue;
    389 		}
    390 		if (c == '.') {
    391 			if (*lbl == '.')
    392 				break;
    393 			len = 0;
    394 			continue;
    395 		}
    396 		if (((c == '-' || c == '_') &&
    397 		    !start && *lbl != ' ' && *lbl != '\0') ||
    398 		    isalnum(c))
    399 		{
    400 			if (++len > 63) {
    401 				errno = ERANGE;
    402 				errset = 1;
    403 				break;
    404 			}
    405 		} else
    406 			break;
    407 		if (start)
    408 			start = 0;
    409 	}
    410 
    411 	if (!errset)
    412 		errno = EINVAL;
    413 	if (lst) {
    414 		/* At least one valid domain, return it */
    415 		*lst = '\0';
    416 		return 1;
    417 	}
    418 	return 0;
    419 }
    420 
    421 /*
    422  * Prints a chunk of data to a string.
    423  * PS_SHELL goes as it is these days, it's upto the target to validate it.
    424  * PS_SAFE has all non ascii and non printables changes to escaped octal.
    425  */
    426 static const char hexchrs[] = "0123456789abcdef";
    427 ssize_t
    428 print_string(char *dst, size_t len, int type, const uint8_t *data, size_t dl)
    429 {
    430 	char *odst;
    431 	uint8_t c;
    432 	const uint8_t *e;
    433 	size_t bytes;
    434 
    435 	odst = dst;
    436 	bytes = 0;
    437 	e = data + dl;
    438 
    439 	while (data < e) {
    440 		c = *data++;
    441 		if (type & BINHEX) {
    442 			if (dst) {
    443 				if (len  == 0 || len == 1) {
    444 					errno = ENOSPC;
    445 					return -1;
    446 				}
    447 				*dst++ = hexchrs[(c & 0xF0) >> 4];
    448 				*dst++ = hexchrs[(c & 0x0F)];
    449 				len -= 2;
    450 			}
    451 			bytes += 2;
    452 			continue;
    453 		}
    454 		if (type & ASCII && (!isascii(c))) {
    455 			errno = EINVAL;
    456 			break;
    457 		}
    458 		if (!(type & (ASCII | RAW | ESCSTRING | ESCFILE)) /* plain */ &&
    459 		    (!isascii(c) && !isprint(c)))
    460 		{
    461 			errno = EINVAL;
    462 			break;
    463 		}
    464 		if ((type & (ESCSTRING | ESCFILE) &&
    465 		    (c == '\\' || !isascii(c) || !isprint(c))) ||
    466 		    (type & ESCFILE && (c == '/' || c == ' ')))
    467 		{
    468 			errno = EINVAL;
    469 			if (c == '\\') {
    470 				if (dst) {
    471 					if (len  == 0 || len == 1) {
    472 						errno = ENOSPC;
    473 						return -1;
    474 					}
    475 					*dst++ = '\\'; *dst++ = '\\';
    476 					len -= 2;
    477 				}
    478 				bytes += 2;
    479 				continue;
    480 			}
    481 			if (dst) {
    482 				if (len < 5) {
    483 					errno = ENOSPC;
    484 					return -1;
    485 				}
    486 				*dst++ = '\\';
    487 		                *dst++ = (char)(((c >> 6) & 03) + '0');
    488 		                *dst++ = (char)(((c >> 3) & 07) + '0');
    489 		                *dst++ = (char)(( c       & 07) + '0');
    490 				len -= 4;
    491 			}
    492 			bytes += 4;
    493 		} else {
    494 			if (dst) {
    495 				if (len == 0) {
    496 					errno = ENOSPC;
    497 					return -1;
    498 				}
    499 				*dst++ = (char)c;
    500 				len--;
    501 			}
    502 			bytes++;
    503 		}
    504 	}
    505 
    506 	/* NULL */
    507 	if (dst) {
    508 		if (len == 0) {
    509 			errno = ENOSPC;
    510 			return -1;
    511 		}
    512 		*dst = '\0';
    513 
    514 		/* Now we've printed it, validate the domain */
    515 		if (type & DOMAIN && !valid_domainname(odst, type)) {
    516 			*odst = '\0';
    517 			return 1;
    518 		}
    519 
    520 	}
    521 
    522 	return (ssize_t)bytes;
    523 }
    524 
    525 #define ADDR6SZ		16
    526 static size_t
    527 dhcp_optlen(const struct dhcp_opt *opt, size_t dl)
    528 {
    529 	size_t sz;
    530 
    531 	if (opt->type & ADDRIPV6)
    532 		sz = ADDR6SZ;
    533 	else if (opt->type & (UINT32 | ADDRIPV4))
    534 		sz = sizeof(uint32_t);
    535 	else if (opt->type & UINT16)
    536 		sz = sizeof(uint16_t);
    537 	else if (opt->type & (UINT8 | BITFLAG))
    538 		sz = sizeof(uint8_t);
    539 	else if (opt->type & FLAG)
    540 		return 0;
    541 	else {
    542 		/* All other types are variable length */
    543 		if (opt->len) {
    544 			if ((size_t)opt->len > dl) {
    545 				errno = ENODATA;
    546 				return -1;
    547 			}
    548 			return (ssize_t)opt->len;
    549 		}
    550 		return (ssize_t)dl;
    551 	}
    552 	if (dl < sz) {
    553 		errno = ENODATA;
    554 		return -1;
    555 	}
    556 
    557 	/* Trim any extra data.
    558 	 * Maybe we need a settng to reject DHCP options with extra data? */
    559 	if (opt->type & ARRAY)
    560 		return (ssize_t)(dl - (dl % sz));
    561 	return (ssize_t)sz;
    562 }
    563 
    564 #ifdef INET6
    565 #define PO_IFNAME
    566 #else
    567 #define PO_IFNAME __unused
    568 #endif
    569 
    570 ssize_t
    571 print_option(char *s, size_t len, int type, const uint8_t *data, size_t dl,
    572     PO_IFNAME const char *ifname)
    573 {
    574 	const uint8_t *e, *t;
    575 	uint16_t u16;
    576 	int16_t s16;
    577 	uint32_t u32;
    578 	int32_t s32;
    579 	struct in_addr addr;
    580 	ssize_t bytes = 0, sl;
    581 	size_t l;
    582 	char *tmp;
    583 
    584 	if (type & RFC3397) {
    585 		sl = decode_rfc3397(NULL, 0, data, dl);
    586 		if (sl == 0 || sl == -1)
    587 			return sl;
    588 		l = (size_t)sl + 1;
    589 		tmp = malloc(l);
    590 		if (tmp == NULL)
    591 			return -1;
    592 		decode_rfc3397(tmp, l, data, dl);
    593 		sl = print_string(s, len, type, (uint8_t *)tmp, l - 1);
    594 		free(tmp);
    595 		return sl;
    596 	}
    597 
    598 #ifdef INET
    599 	if (type & RFC3361) {
    600 		if ((tmp = decode_rfc3361(data, dl)) == NULL)
    601 			return -1;
    602 		l = strlen(tmp);
    603 		sl = print_string(s, len, type, (uint8_t *)tmp, l);
    604 		free(tmp);
    605 		return sl;
    606 	}
    607 
    608 	if (type & RFC3442)
    609 		return decode_rfc3442(s, len, data, dl);
    610 
    611 	if (type & RFC5969)
    612 		return decode_rfc5969(s, len, data, dl);
    613 #endif
    614 
    615 	if (type & STRING)
    616 		return print_string(s, len, type, data, dl);
    617 
    618 	if (type & FLAG) {
    619 		if (s) {
    620 			*s++ = '1';
    621 			*s = '\0';
    622 		}
    623 		return 1;
    624 	}
    625 
    626 	if (!s) {
    627 		if (type & UINT8)
    628 			l = 3;
    629 		else if (type & UINT16) {
    630 			l = 5;
    631 			dl /= 2;
    632 		} else if (type & SINT16) {
    633 			l = 6;
    634 			dl /= 2;
    635 		} else if (type & UINT32) {
    636 			l = 10;
    637 			dl /= 4;
    638 		} else if (type & SINT32) {
    639 			l = 11;
    640 			dl /= 4;
    641 		} else if (type & ADDRIPV4) {
    642 			l = 16;
    643 			dl /= 4;
    644 		}
    645 #ifdef INET6
    646 		else if (type & ADDRIPV6) {
    647 			e = data + dl;
    648 			l = 0;
    649 			while (data < e) {
    650 				if (l)
    651 					l++; /* space */
    652 				sl = ipv6_printaddr(NULL, 0, data, ifname);
    653 				if (sl != -1)
    654 					l += (size_t)sl;
    655 				data += 16;
    656 			}
    657 			return (ssize_t)l;
    658 		}
    659 #endif
    660 		else {
    661 			errno = EINVAL;
    662 			return -1;
    663 		}
    664 		return (ssize_t)(l * dl);
    665 	}
    666 
    667 	t = data;
    668 	e = data + dl;
    669 	while (data < e) {
    670 		if (data != t) {
    671 			*s++ = ' ';
    672 			bytes++;
    673 			len--;
    674 		}
    675 		if (type & UINT8) {
    676 			sl = snprintf(s, len, "%u", *data);
    677 			data++;
    678 		} else if (type & UINT16) {
    679 			memcpy(&u16, data, sizeof(u16));
    680 			u16 = ntohs(u16);
    681 			sl = snprintf(s, len, "%u", u16);
    682 			data += sizeof(u16);
    683 		} else if (type & SINT16) {
    684 			memcpy(&u16, data, sizeof(u16));
    685 			s16 = (int16_t)ntohs(u16);
    686 			sl = snprintf(s, len, "%d", s16);
    687 			data += sizeof(u16);
    688 		} else if (type & UINT32) {
    689 			memcpy(&u32, data, sizeof(u32));
    690 			u32 = ntohl(u32);
    691 			sl = snprintf(s, len, "%u", u32);
    692 			data += sizeof(u32);
    693 		} else if (type & SINT32) {
    694 			memcpy(&u32, data, sizeof(u32));
    695 			s32 = (int32_t)ntohl(u32);
    696 			sl = snprintf(s, len, "%d", s32);
    697 			data += sizeof(u32);
    698 		} else if (type & ADDRIPV4) {
    699 			memcpy(&addr.s_addr, data, sizeof(addr.s_addr));
    700 			sl = snprintf(s, len, "%s", inet_ntoa(addr));
    701 			data += sizeof(addr.s_addr);
    702 		}
    703 #ifdef INET6
    704 		else if (type & ADDRIPV6) {
    705 			ssize_t r;
    706 
    707 			r = ipv6_printaddr(s, len, data, ifname);
    708 			if (r != -1)
    709 				sl = r;
    710 			else
    711 				sl = 0;
    712 			data += 16;
    713 		}
    714 #endif
    715 		else
    716 			sl = 0;
    717 		if (len <= sl) {
    718 			bytes += len;
    719 			break;
    720 		}
    721 		len -= (size_t)sl;
    722 		bytes += sl;
    723 		s += sl;
    724 	}
    725 
    726 	return bytes;
    727 }
    728 
    729 /* Lease file name is formatted according to the expectation of the ChromiumOS's
    730  * connection manager (shill). */
    731 int
    732 dhcp_set_leasefile(char *leasefile, size_t len, int family,
    733     const struct interface *ifp, const char *extra)
    734 {
    735 	char ssid[len];
    736 
    737 	if (ifp->name[0] == '\0') {
    738 		strlcpy(leasefile, ifp->ctx->pidfile, len);
    739 		return 0;
    740 	}
    741 
    742 	if (strlen(ifp->lease_identifier) > 0) {
    743 		return snprintf(leasefile, len,
    744 				family == AF_INET ? LEASEFILE : LEASEFILE6,
    745 				ifp->lease_identifier, "", extra);
    746 	}
    747 	return snprintf(leasefile, len,
    748 			family == AF_INET ? LEASEFILE : LEASEFILE6,
    749 			ifp->name, "", extra);
    750 }
    751 
    752 static size_t
    753 dhcp_envoption1(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
    754     const struct dhcp_opt *opt, int vname, const uint8_t *od, size_t ol,
    755     const char *ifname)
    756 {
    757 	ssize_t len;
    758 	size_t e;
    759 	char *v, *val;
    760 
    761 	/* Ensure a valid length */
    762 	ol = (size_t)dhcp_optlen(opt, ol);
    763 	if ((ssize_t)ol == -1)
    764 		return 0;
    765 
    766 	len = print_option(NULL, 0, opt->type, od, ol, ifname);
    767 	if (len < 0)
    768 		return 0;
    769 	if (vname)
    770 		e = strlen(opt->var) + 1;
    771 	else
    772 		e = 0;
    773 	if (prefix)
    774 		e += strlen(prefix);
    775 	e += (size_t)len + 2;
    776 	if (env == NULL)
    777 		return e;
    778 	v = val = *env = malloc(e);
    779 	if (v == NULL) {
    780 		logger(ctx, LOG_ERR, "%s: %m", __func__);
    781 		return 0;
    782 	}
    783 	if (vname)
    784 		v += snprintf(val, e, "%s_%s=", prefix, opt->var);
    785 	else
    786 		v += snprintf(val, e, "%s=", prefix);
    787 	if (len != 0)
    788 		print_option(v, (size_t)len + 1, opt->type, od, ol, ifname);
    789 	return e;
    790 }
    791 
    792 size_t
    793 dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix,
    794     const char *ifname, struct dhcp_opt *opt,
    795     const uint8_t *(*dgetopt)(struct dhcpcd_ctx *,
    796     size_t *, unsigned int *, size_t *,
    797     const uint8_t *, size_t, struct dhcp_opt **),
    798     const uint8_t *od, size_t ol)
    799 {
    800 	size_t e, i, n, eos, eol;
    801 	unsigned int eoc;
    802 	const uint8_t *eod;
    803 	int ov;
    804 	struct dhcp_opt *eopt, *oopt;
    805 	char *pfx;
    806 
    807 	/* If no embedded or encapsulated options, it's easy */
    808 	if (opt->embopts_len == 0 && opt->encopts_len == 0) {
    809 		if (dhcp_envoption1(ctx, env == NULL ? NULL : &env[0],
    810 		    prefix, opt, 1, od, ol, ifname))
    811 			return 1;
    812 		return 0;
    813 	}
    814 
    815 	/* Create a new prefix based on the option */
    816 	if (env) {
    817 		if (opt->type & INDEX) {
    818 			if (opt->index > 999) {
    819 				errno = ENOBUFS;
    820 				logger(ctx, LOG_ERR, "%s: %m", __func__);
    821 				return 0;
    822 			}
    823 		}
    824 		e = strlen(prefix) + strlen(opt->var) + 2 +
    825 		    (opt->type & INDEX ? 3 : 0);
    826 		pfx = malloc(e);
    827 		if (pfx == NULL) {
    828 			logger(ctx, LOG_ERR, "%s: %m", __func__);
    829 			return 0;
    830 		}
    831 		if (opt->type & INDEX)
    832 			snprintf(pfx, e, "%s_%s%d", prefix,
    833 			    opt->var, ++opt->index);
    834 		else
    835 			snprintf(pfx, e, "%s_%s", prefix, opt->var);
    836 	} else
    837 		pfx = NULL;
    838 
    839 	/* Embedded options are always processed first as that
    840 	 * is a fixed layout */
    841 	n = 0;
    842 	for (i = 0, eopt = opt->embopts; i < opt->embopts_len; i++, eopt++) {
    843 		e = dhcp_optlen(eopt, ol);
    844 		if (e == 0) {
    845 			/* An option was expected, but there is not enough
    846 			 * data for it.
    847 			 * This may not be an error as some options like
    848 			 * DHCP FQDN in RFC4702 have a string as the last
    849 			 * option which is optional.
    850 			 * FIXME: Add an flag to the options to indicate
    851 			 * wether this is allowable or not. */
    852 			 if (ol != 0 || i + 1 < opt->embopts_len)
    853 				logger(ctx, LOG_WARNING,
    854 				    "%s: %s: malformed option %d",
    855 				    ifname, __func__, opt->option);
    856 			 goto out;
    857 		}
    858 		/* Use the option prefix if the embedded option
    859 		 * name is different.
    860 		 * This avoids new_fqdn_fqdn which would be silly. */
    861 		ov = strcmp(opt->var, eopt->var);
    862 		if (dhcp_envoption1(ctx, env == NULL ? NULL : &env[n],
    863 		    pfx, eopt, ov, od, e, ifname))
    864 			n++;
    865 		od += e;
    866 		ol -= e;
    867 	}
    868 
    869 	/* Enumerate our encapsulated options */
    870 	if (opt->encopts_len && ol > 0) {
    871 		/* Zero any option indexes
    872 		 * We assume that referenced encapsulated options are NEVER
    873 		 * recursive as the index order could break. */
    874 		for (i = 0, eopt = opt->encopts;
    875 		    i < opt->encopts_len;
    876 		    i++, eopt++)
    877 		{
    878 			eoc = opt->option;
    879 			if (eopt->type & OPTION) {
    880 				dgetopt(ctx, NULL, &eoc, NULL, NULL, 0, &oopt);
    881 				if (oopt)
    882 					oopt->index = 0;
    883 			}
    884 		}
    885 
    886 		while ((eod = dgetopt(ctx, &eos, &eoc, &eol, od, ol, &oopt))) {
    887 			for (i = 0, eopt = opt->encopts;
    888 			    i < opt->encopts_len;
    889 			    i++, eopt++)
    890 			{
    891 				if (eopt->option == eoc) {
    892 					if (eopt->type & OPTION) {
    893 						if (oopt == NULL)
    894 							/* Report error? */
    895 							continue;
    896 					}
    897 					n += dhcp_envoption(ctx,
    898 					    env == NULL ? NULL : &env[n], pfx,
    899 					    ifname,
    900 					    eopt->type & OPTION ? oopt : eopt,
    901 					    dgetopt, eod, eol);
    902 					break;
    903 				}
    904 			}
    905 			od += eos + eol;
    906 			ol -= eos + eol;
    907 		}
    908 	}
    909 
    910 out:
    911 	if (env)
    912 		free(pfx);
    913 
    914 	/* Return number of options found */
    915 	return n;
    916 }
    917 
    918 void
    919 dhcp_zero_index(struct dhcp_opt *opt)
    920 {
    921 	size_t i;
    922 	struct dhcp_opt *o;
    923 
    924 	opt->index = 0;
    925 	for (i = 0, o = opt->embopts; i < opt->embopts_len; i++, o++)
    926 		dhcp_zero_index(o);
    927 	for (i = 0, o = opt->encopts; i < opt->encopts_len; i++, o++)
    928 		dhcp_zero_index(o);
    929 }
    930