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