Mercurial > hg > dhcpcd
changeset 4549:dfe9f9f1c5f2 draft
Merge branch 'memstream'
| author | Roy Marples <roy@marples.name> |
|---|---|
| date | Thu, 04 Jul 2019 12:22:46 +0100 |
| parents | c7df03794de3 (current diff) 331b92976059 (diff) |
| children | 1b9e9a69b187 |
| files | configure src/arp.c src/auth.c src/common.c src/common.h src/dhcp-common.c src/dhcp-common.h src/dhcp.c src/dhcp.h src/dhcp6.c src/dhcp6.h src/dhcpcd.c src/dhcpcd.h src/ipv4.c src/ipv4ll.c src/ipv4ll.h src/ipv6.c src/ipv6.h src/ipv6nd.c src/ipv6nd.h src/script.c src/script.h |
| diffstat | 22 files changed, 556 insertions(+), 963 deletions(-) [+] |
line wrap: on
line diff
--- a/configure Thu Jul 04 12:18:28 2019 +0100 +++ b/configure Thu Jul 04 12:22:46 2019 +0100 @@ -15,6 +15,7 @@ CLOSEFROM= RBTREE= CONSTTIME_MEMEQUAL= +OPEN_MEMSTREAM= STRLCPY= UDEV= OS= @@ -741,29 +742,25 @@ echo "#include \"compat/arc4random_uniform.h\"" >>$CONFIG_H fi - -if [ -z "$STRLCPY" ]; then - printf "Testing for strlcpy ... " - cat <<EOF >_strlcpy.c -#include <string.h> +if [ -z "$OPEN_MEMSTREAM" ]; then + printf "Testing for open_memstream ... " + cat <<EOF >_open_memstream.c +#include <stdio.h> int main(void) { - const char s1[] = "foo"; - char s2[10]; - strlcpy(s2, s1, sizeof(s2)); + open_memstream(NULL, NULL); return 0; } EOF - if $XCC _strlcpy.c -o _strlcpy 2>&3; then - STRLCPY=yes + if $XCC _open_memstream.c -o _open_memstream 2>&3; then + OPEN_MEMSTREAM=yes else - STRLCPY=no + OPEN_MEMSTREAM=no fi - echo "$STRLCPY" - rm -f _strlcpy.c _strlcpy + echo "$OPEN_MEMSTREAM" + rm -f _open_memstream.c _open_memstream fi -if [ "$STRLCPY" = no ]; then - echo "COMPAT_SRCS+= compat/strlcpy.c" >>$CONFIG_MK - echo "#include \"compat/strlcpy.h\"" >>$CONFIG_H +if [ "$OPEN_MEMSTREAM" = yes ]; then + echo "#define HAVE_OPEN_MEMSTREAM" >>$CONFIG_H fi if [ -z "$PIDFILE_LOCK" ]; then @@ -824,6 +821,30 @@ echo "#define HAVE_SETPROCTITLE" >>$CONFIG_H fi +if [ -z "$STRLCPY" ]; then + printf "Testing for strlcpy ... " + cat <<EOF >_strlcpy.c +#include <string.h> +int main(void) { + const char s1[] = "foo"; + char s2[10]; + strlcpy(s2, s1, sizeof(s2)); + return 0; +} +EOF + if $XCC _strlcpy.c -o _strlcpy 2>&3; then + STRLCPY=yes + else + STRLCPY=no + fi + echo "$STRLCPY" + rm -f _strlcpy.c _strlcpy +fi +if [ "$STRLCPY" = no ]; then + echo "COMPAT_SRCS+= compat/strlcpy.c" >>$CONFIG_MK + echo "#include \"compat/strlcpy.h\"" >>$CONFIG_H +fi + if [ -z "$STRTOI" ]; then printf "Testing for strtoi ... " cat <<EOF >_strtoi.c
--- a/src/arp.c Thu Jul 04 12:18:28 2019 +0100 +++ b/src/arp.c Thu Jul 04 12:22:46 2019 +0100 @@ -37,6 +37,7 @@ #include <errno.h> #include <stdlib.h> +#include <stdio.h> #include <string.h> #include <unistd.h>
--- a/src/auth.c Thu Jul 04 12:18:28 2019 +0100 +++ b/src/auth.c Thu Jul 04 12:22:46 2019 +0100 @@ -31,6 +31,7 @@ #include <fcntl.h> #include <inttypes.h> #include <stddef.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h>
--- a/src/common.c Thu Jul 04 12:18:28 2019 +0100 +++ b/src/common.c Thu Jul 04 12:22:46 2019 +0100 @@ -57,54 +57,6 @@ /* Most route(4) messages are less than 256 bytes. */ #define IOVEC_BUFSIZ 256 -ssize_t -setvar(char **e, const char *prefix, const char *var, const char *value) -{ - size_t len = strlen(var) + strlen(value) + 3; - - if (prefix) - len += strlen(prefix) + 1; - if ((*e = malloc(len)) == NULL) { - logerr(__func__); - return -1; - } - if (prefix) - snprintf(*e, len, "%s_%s=%s", prefix, var, value); - else - snprintf(*e, len, "%s=%s", var, value); - return (ssize_t)len; -} - -ssize_t -setvard(char **e, const char *prefix, const char *var, size_t value) -{ - - char buffer[32]; - - snprintf(buffer, sizeof(buffer), "%zu", value); - return setvar(e, prefix, var, buffer); -} - -ssize_t -addvar(char ***e, const char *prefix, const char *var, const char *value) -{ - ssize_t len; - - len = setvar(*e, prefix, var, value); - if (len != -1) - (*e)++; - return (ssize_t)len; -} - -ssize_t -addvard(char ***e, const char *prefix, const char *var, size_t value) -{ - char buffer[32]; - - snprintf(buffer, sizeof(buffer), "%zu", value); - return addvar(e, prefix, var, buffer); -} - const char * hwaddr_ntoa(const void *hwaddr, size_t hwlen, char *buf, size_t buflen) {
--- a/src/common.h Thu Jul 04 12:18:28 2019 +0100 +++ b/src/common.h Thu Jul 04 12:22:46 2019 +0100 @@ -194,11 +194,6 @@ extern int clock_monotonic; int get_monotonic(struct timespec *); -ssize_t setvar(char **, const char *, const char *, const char *); -ssize_t setvard(char **, const char *, const char *, size_t); -ssize_t addvar(char ***, const char *, const char *, const char *); -ssize_t addvard(char ***, const char *, const char *, size_t); - const char *hwaddr_ntoa(const void *, size_t, char *, size_t); size_t hwaddr_aton(uint8_t *, const char *); size_t read_hwaddr_aton(uint8_t **, const char *);
--- a/src/dhcp-common.c Thu Jul 04 12:18:28 2019 +0100 +++ b/src/dhcp-common.c Thu Jul 04 12:22:46 2019 +0100 @@ -37,8 +37,6 @@ #include <string.h> #include <unistd.h> -#include <arpa/nameser.h> /* after normal includes for sunos */ - #include "config.h" #include "common.h" @@ -47,13 +45,7 @@ #include "if.h" #include "ipv6.h" #include "logerr.h" - -/* Support very old arpa/nameser.h as found in OpenBSD */ -#ifndef NS_MAXDNAME -#define NS_MAXCDNAME MAXCDNAME -#define NS_MAXDNAME MAXDNAME -#define NS_MAXLABEL MAXLABEL -#endif +#include "script.h" const char * dhcp_get_hostname(char *buf, size_t buf_len, const struct if_options *ifo) @@ -625,41 +617,9 @@ return (ssize_t)sz; } -/* It's possible for DHCPv4 to contain an IPv6 address */ static ssize_t -ipv6_printaddr(char *s, size_t sl, const uint8_t *d, const char *ifname) -{ - char buf[INET6_ADDRSTRLEN]; - const char *p; - size_t l; - - p = inet_ntop(AF_INET6, d, buf, sizeof(buf)); - if (p == NULL) - return -1; - - l = strlen(p); - if (d[0] == 0xfe && (d[1] & 0xc0) == 0x80) - l += 1 + strlen(ifname); - - if (s == NULL) - return (ssize_t)l; - - if (sl < l) { - errno = ENOMEM; - return -1; - } - - s += strlcpy(s, p, sl); - if (d[0] == 0xfe && (d[1] & 0xc0) == 0x80) { - *s++ = '%'; - s += strlcpy(s, ifname, sl); - } - *s = '\0'; - return (ssize_t)l; -} - -static ssize_t -print_option(char *s, size_t len, const struct dhcp_opt *opt, +print_option(FILE *fp, const char *prefix, const struct dhcp_opt *opt, + int vname, const uint8_t *data, size_t dl, const char *ifname) { const uint8_t *e, *t; @@ -668,52 +628,58 @@ uint32_t u32; int32_t s32; struct in_addr addr; - ssize_t bytes = 0, sl; + ssize_t sl; size_t l; -#ifdef INET - char *tmp; -#endif + + /* Ensure a valid length */ + dl = (size_t)dhcp_optlen(opt, dl); + if ((ssize_t)dl == -1) + return 0; + + if (fprintf(fp, "%s", prefix) == -1) + return -1; + if (vname) { + if (fprintf(fp, "_%s", opt->var) == -1) + return -1; + } + if (fputc('=', fp) == EOF) + return -1; + if (dl == 0) + return 1; if (opt->type & OT_RFC1035) { - sl = decode_rfc1035(s, len, data, dl); + char domain[NS_MAXDNAME]; + + sl = decode_rfc1035(domain, sizeof(domain), data, dl); if (sl == 0 || sl == -1) return sl; - if (s != NULL) { - if (valid_domainname(s, opt->type) == -1) - return -1; - } - return sl; + if (valid_domainname(domain, opt->type) == -1) + return -1; + return efprintf(fp, "%s", domain); } #ifdef INET - if (opt->type & OT_RFC3361) { - if ((tmp = decode_rfc3361(data, dl)) == NULL) - return -1; - l = strlen(tmp); - sl = print_string(s, len, opt->type, (uint8_t *)tmp, l); - free(tmp); - return sl; - } + if (opt->type & OT_RFC3361) + return print_rfc3361(fp, data, dl); if (opt->type & OT_RFC3442) - return decode_rfc3442(s, len, data, dl); + return print_rfc3442(fp, data, dl); #endif - if (opt->type & OT_STRING) - return print_string(s, len, opt->type, data, dl); + if (opt->type & OT_STRING) { + char buf[1024]; - if (opt->type & OT_FLAG) { - if (s) { - *s++ = '1'; - *s = '\0'; - } - return 1; + if (print_string(buf, sizeof(buf), opt->type, data, dl) == -1) + return -1; + return efprintf(fp, "%s", buf); } + if (opt->type & OT_FLAG) + return efprintf(fp, "1"); + if (opt->type & OT_BITFLAG) { /* bitflags are a string, MSB first, such as ABCDEFGH * where A is 10000000, B is 01000000, etc. */ - bytes = 0; for (l = 0, sl = sizeof(opt->bitflags) - 1; l < sizeof(opt->bitflags); l++, sl--) @@ -723,109 +689,80 @@ opt->bitflags[l] != '0' && *data & (1 << sl)) { - if (s) - *s++ = opt->bitflags[l]; - bytes++; + if (fputc(opt->bitflags[l], fp) == EOF) + return -1; } } - if (s) - *s = '\0'; - return bytes; - } - - if (!s) { - if (opt->type & OT_UINT8) - l = 3; - else if (opt->type & OT_INT8) - l = 4; - else if (opt->type & OT_UINT16) { - l = 5; - dl /= 2; - } else if (opt->type & OT_INT16) { - l = 6; - dl /= 2; - } else if (opt->type & OT_UINT32) { - l = 10; - dl /= 4; - } else if (opt->type & OT_INT32) { - l = 11; - dl /= 4; - } else if (opt->type & OT_ADDRIPV4) { - l = 16; - dl /= 4; - } else if (opt->type & OT_ADDRIPV6) { - e = data + dl; - l = 0; - while (data < e) { - if (l) - l++; /* space */ - sl = ipv6_printaddr(NULL, 0, data, ifname); - if (sl == -1) - return l == 0 ? -1 : (ssize_t)l; - l += (size_t)sl; - data += 16; - } - return (ssize_t)l; - } else { - errno = EINVAL; + if (fputc('\0', fp) == EOF) return -1; - } - return (ssize_t)(l * dl); + return 1; } t = data; e = data + dl; while (data < e) { if (data != t) { - *s++ = ' '; - bytes++; - len--; + if (fputc(' ', fp) == EOF) + return -1; } if (opt->type & OT_UINT8) { - sl = snprintf(s, len, "%u", *data); + if (fprintf(fp, "%u", *data) == -1) + return -1; data++; } else if (opt->type & OT_INT8) { - sl = snprintf(s, len, "%d", *data); + if (fprintf(fp, "%d", *data) == -1) + return -1; data++; } else if (opt->type & OT_UINT16) { memcpy(&u16, data, sizeof(u16)); u16 = ntohs(u16); - sl = snprintf(s, len, "%u", u16); + if (fprintf(fp, "%u", u16) == -1) + return -1; data += sizeof(u16); } else if (opt->type & OT_INT16) { memcpy(&u16, data, sizeof(u16)); s16 = (int16_t)ntohs(u16); - sl = snprintf(s, len, "%d", s16); + if (fprintf(fp, "%d", s16) == -1) + return -1; data += sizeof(u16); } else if (opt->type & OT_UINT32) { memcpy(&u32, data, sizeof(u32)); u32 = ntohl(u32); - sl = snprintf(s, len, "%u", u32); + if (fprintf(fp, "%u", u32) == -1) + return -1; data += sizeof(u32); } else if (opt->type & OT_INT32) { memcpy(&u32, data, sizeof(u32)); s32 = (int32_t)ntohl(u32); - sl = snprintf(s, len, "%d", s32); + if (fprintf(fp, "%d", s32) == -1) + return -1; data += sizeof(u32); } else if (opt->type & OT_ADDRIPV4) { memcpy(&addr.s_addr, data, sizeof(addr.s_addr)); - sl = snprintf(s, len, "%s", inet_ntoa(addr)); + if (fprintf(fp, "%s", inet_ntoa(addr)) == -1) + return -1; data += sizeof(addr.s_addr); } else if (opt->type & OT_ADDRIPV6) { - sl = ipv6_printaddr(s, len, data, ifname); + char buf[INET6_ADDRSTRLEN]; + + if (inet_ntop(AF_INET6, data, buf, sizeof(buf)) == NULL) + return -1; + if (fprintf(fp, "%s", buf) == -1) + return -1; + if (data[0] == 0xfe && (data[1] & 0xc0) == 0x80) { + if (fprintf(fp,"%%%s", ifname) == -1) + return -1; + } data += 16; } else { errno = EINVAL; return -1; } - if (sl == -1) - return bytes == 0 ? -1 : bytes; - len -= (size_t)sl; - bytes += sl; - s += sl; } - return bytes; + if (fputc('\0', fp) == EOF) + return -1; + return 1; } int @@ -860,61 +797,15 @@ ifp->name, ssid); } -static size_t -dhcp_envoption1(char **env, const char *prefix, - const struct dhcp_opt *opt, int vname, const uint8_t *od, size_t ol, - const char *ifname) -{ - ssize_t len; - size_t e; - char *v, *val; - int r; - - /* Ensure a valid length */ - ol = (size_t)dhcp_optlen(opt, ol); - if ((ssize_t)ol == -1) - return 0; - - len = print_option(NULL, 0, opt, od, ol, ifname); - if (len < 0) - return 0; - if (vname) - e = strlen(opt->var) + 1; - else - e = 0; - if (prefix) - e += strlen(prefix); - e += (size_t)len + 2; - if (env == NULL) - return e; - v = val = *env = malloc(e); - if (v == NULL) - return 0; - if (vname) - r = snprintf(val, e, "%s_%s=", prefix, opt->var); - else - r = snprintf(val, e, "%s=", prefix); - if (r != -1 && len != 0) { - v += r; - if (print_option(v, (size_t)len + 1, opt, od, ol, ifname) == -1) - r = -1; - } - if (r == -1) { - free(val); - return 0; - } - return e; -} - -size_t -dhcp_envoption(struct dhcpcd_ctx *ctx, char **env, const char *prefix, +void +dhcp_envoption(struct dhcpcd_ctx *ctx, FILE *fp, const char *prefix, const char *ifname, struct dhcp_opt *opt, const uint8_t *(*dgetopt)(struct dhcpcd_ctx *, size_t *, unsigned int *, size_t *, const uint8_t *, size_t, struct dhcp_opt **), const uint8_t *od, size_t ol) { - size_t e, i, n, eos, eol; + size_t i, eos, eol; ssize_t eo; unsigned int eoc; const uint8_t *eod; @@ -924,52 +815,36 @@ /* If no embedded or encapsulated options, it's easy */ if (opt->embopts_len == 0 && opt->encopts_len == 0) { - if (!(opt->type & OT_RESERVED)) { - if (dhcp_envoption1(env == NULL ? NULL : &env[0], - prefix, opt, 1, od, ol, ifname)) - return 1; - else - logerr("%s: %s %d", - ifname, __func__, opt->option); - } - return 0; + if (opt->type & OT_RESERVED) + return; + if (print_option(fp, prefix, opt, 1, od, ol, ifname) == -1) + logerr("%s: %s %d", ifname, __func__, opt->option); + return; } /* Create a new prefix based on the option */ - if (env) { - if (opt->type & OT_INDEX) { - if (opt->index > 999) { - errno = ENOBUFS; - logerr(__func__); - return 0; - } - } - e = strlen(prefix) + strlen(opt->var) + 2 + - (opt->type & OT_INDEX ? 3 : 0); - pfx = malloc(e); - if (pfx == NULL) { - logerr(__func__); - return 0; - } - if (opt->type & OT_INDEX) - snprintf(pfx, e, "%s_%s%d", prefix, - opt->var, ++opt->index); - else - snprintf(pfx, e, "%s_%s", prefix, opt->var); - } else - pfx = NULL; + if (opt->type & OT_INDEX) { + if (asprintf(&pfx, "%s_%s%d", + prefix, opt->var, ++opt->index) == -1) + pfx = NULL; + } else { + if (asprintf(&pfx, "%s_%s", prefix, opt->var) == -1) + pfx = NULL; + } + if (pfx == NULL) { + logerr(__func__); + return; + } /* Embedded options are always processed first as that * is a fixed layout */ - n = 0; for (i = 0, eopt = opt->embopts; i < opt->embopts_len; i++, eopt++) { eo = dhcp_optlen(eopt, ol); if (eo == -1) { - if (env == NULL) - logerrx("%s: %s %d.%d/%zu: " - "malformed embedded option", - ifname, __func__, opt->option, - eopt->option, i); + logerrx("%s: %s %d.%d/%zu: " + "malformed embedded option", + ifname, __func__, opt->option, + eopt->option, i); goto out; } if (eo == 0) { @@ -978,9 +853,9 @@ * This may not be an error as some options like * DHCP FQDN in RFC4702 have a string as the last * option which is optional. */ - if (env == NULL && - (ol != 0 || !(eopt->type & OT_OPTIONAL))) - logerrx("%s: %s %d.%d/%zu: missing embedded option", + if (ol != 0 || !(eopt->type & OT_OPTIONAL)) + logerrx("%s: %s %d.%d/%zu: " + "missing embedded option", ifname, __func__, opt->option, eopt->option, i); goto out; @@ -990,10 +865,8 @@ * This avoids new_fqdn_fqdn which would be silly. */ if (!(eopt->type & OT_RESERVED)) { ov = strcmp(opt->var, eopt->var); - if (dhcp_envoption1(env == NULL ? NULL : &env[n], - pfx, eopt, ov, od, (size_t)eo, ifname)) - n++; - else if (env == NULL) + if (print_option(fp, pfx, eopt, ov, od, (size_t)eo, + ifname) == -1) logerr("%s: %s %d.%d/%zu", ifname, __func__, opt->option, eopt->option, i); @@ -1024,19 +897,16 @@ i < opt->encopts_len; i++, eopt++) { - if (eopt->option == eoc) { - if (eopt->type & OT_OPTION) { - if (oopt == NULL) - /* Report error? */ - continue; - } - n += dhcp_envoption(ctx, - env == NULL ? NULL : &env[n], pfx, - ifname, - eopt->type & OT_OPTION ? oopt:eopt, - dgetopt, eod, eol); - break; + if (eopt->option != eoc) + continue; + if (eopt->type & OT_OPTION) { + if (oopt == NULL) + /* Report error? */ + continue; } + dhcp_envoption(ctx, fp, pfx, ifname, + eopt->type & OT_OPTION ? oopt:eopt, + dgetopt, eod, eol); } od += eos + eol; ol -= eos + eol; @@ -1044,11 +914,7 @@ } out: - if (env) - free(pfx); - - /* Return number of options found */ - return n; + free(pfx); } void @@ -1071,7 +937,7 @@ size_t sz; void *buf; ssize_t len; - + if (fstat(fd, &st) != 0) goto out; if (!S_ISREG(st.st_mode)) {
--- a/src/dhcp-common.h Thu Jul 04 12:18:28 2019 +0100 +++ b/src/dhcp-common.h Thu Jul 04 12:22:46 2019 +0100 @@ -34,9 +34,18 @@ #include <stdint.h> +#include <arpa/nameser.h> /* after normal includes for sunos */ + #include "common.h" #include "dhcpcd.h" +/* Support very old arpa/nameser.h as found in OpenBSD */ +#ifndef NS_MAXDNAME +#define NS_MAXCDNAME MAXCDNAME +#define NS_MAXDNAME MAXDNAME +#define NS_MAXLABEL MAXLABEL +#endif + /* Max MTU - defines dhcp option length */ #define IP_UDP_SIZE 28 #define MTU_MAX 1500 - IP_UDP_SIZE @@ -112,8 +121,8 @@ ssize_t print_string(char *, size_t, int, const uint8_t *, size_t); int dhcp_set_leasefile(char *, size_t, int, const struct interface *); -size_t dhcp_envoption(struct dhcpcd_ctx *, - char **, const char *, const char *, struct dhcp_opt *, +void dhcp_envoption(struct dhcpcd_ctx *, + FILE *, const char *, const char *, struct dhcp_opt *, const uint8_t *(*dgetopt)(struct dhcpcd_ctx *, size_t *, unsigned int *, size_t *, const uint8_t *, size_t, struct dhcp_opt **),
--- a/src/dhcp.c Thu Jul 04 12:18:28 2019 +0100 +++ b/src/dhcp.c Thu Jul 04 12:22:46 2019 +0100 @@ -48,6 +48,7 @@ #include <inttypes.h> #include <stdbool.h> #include <stddef.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> @@ -341,23 +342,25 @@ } ssize_t -decode_rfc3442(char *out, size_t len, const uint8_t *p, size_t pl) +print_rfc3442(FILE *fp, const uint8_t *data, size_t data_len) { - const uint8_t *e; - size_t bytes = 0, ocets; - int b; + const uint8_t *p = data, *e; + size_t ocets; uint8_t cidr; struct in_addr addr; - char *o = out; /* Minimum is 5 -first is CIDR and a router length of 4 */ - if (pl < 5) { + if (data_len < 5) { errno = EINVAL; return -1; } - e = p + pl; + e = p + data_len; while (p < e) { + if (p != data) { + if (fputc(' ', fp) == EOF) + return -1; + } cidr = *p++; if (cidr > 32) { errno = EINVAL; @@ -368,41 +371,25 @@ errno = ERANGE; return -1; } - if (!out) { - p += 4 + ocets; - bytes += ((4 * 4) * 2) + 4; - continue; - } - if ((((4 * 4) * 2) + 4) > len) { - errno = ENOBUFS; - return -1; + /* If we have ocets then we have a destination and netmask */ + addr.s_addr = 0; + if (ocets > 0) { + memcpy(&addr.s_addr, p, ocets); + p += ocets; } - if (o != out) { - *o++ = ' '; - len--; - } - /* If we have ocets then we have a destination and netmask */ - if (ocets > 0) { - addr.s_addr = 0; - memcpy(&addr.s_addr, p, ocets); - b = snprintf(o, len, "%s/%d", inet_ntoa(addr), cidr); - p += ocets; - } else - b = snprintf(o, len, "0.0.0.0/0"); - o += b; - len -= (size_t)b; + if (fprintf(fp, "%s/%d", inet_ntoa(addr), cidr) == -1) + return -1; /* Finally, snag the router */ memcpy(&addr.s_addr, p, 4); p += 4; - b = snprintf(o, len, " %s", inet_ntoa(addr)); - o += b; - len -= (size_t)b; + if (fprintf(fp, " %s", inet_ntoa(addr)) == -1) + return -1; } - if (out) - return o - out; - return (ssize_t)bytes; + if (fputc('\0', fp) == EOF) + return -1; + return 1; } static int @@ -475,15 +462,12 @@ return n; } -char * -decode_rfc3361(const uint8_t *data, size_t dl) +ssize_t +print_rfc3361(FILE *fp, const uint8_t *data, size_t dl) { uint8_t enc; - size_t l; - ssize_t r; - char *sip = NULL; + char sip[NS_MAXDNAME]; struct in_addr addr; - char *p; if (dl < 2) { errno = EINVAL; @@ -494,13 +478,10 @@ dl--; switch (enc) { case 0: - if ((r = decode_rfc1035(NULL, 0, data, dl)) > 0) { - l = (size_t)r + 1; - sip = malloc(l); - if (sip == NULL) - return 0; - decode_rfc1035(sip, l, data, dl); - } + if (decode_rfc1035(sip, sizeof(sip), data, dl) == -1) + return -1; + if (efprintf(fp, "%s", sip) == -1) + return -1; break; case 1: if (dl == 0 || dl % 4 != 0) { @@ -508,25 +489,27 @@ break; } addr.s_addr = INADDR_BROADCAST; - l = ((dl / sizeof(addr.s_addr)) * ((4 * 4) + 1)) + 1; - sip = p = malloc(l); - if (sip == NULL) - return 0; - while (dl != 0) { + for (; + dl != 0; + data += sizeof(addr.s_addr), dl -= sizeof(addr.s_addr)) + { memcpy(&addr.s_addr, data, sizeof(addr.s_addr)); - data += sizeof(addr.s_addr); - p += snprintf(p, l - (size_t)(p - sip), - "%s ", inet_ntoa(addr)); - dl -= sizeof(addr.s_addr); + if (fprintf(fp, "%s", inet_ntoa(addr)) == -1) + return -1; + if (dl != 0) { + if (fputc(' ', fp) == EOF) + return -1; + } } - *--p = '\0'; + if (fputc('\0', fp) == EOF) + return -1; break; default: errno = EINVAL; return 0; } - return sip; + return 1; } static char * @@ -1299,9 +1282,8 @@ } ssize_t -dhcp_env(char **env, const char *prefix, - const struct bootp *bootp, size_t bootp_len, - const struct interface *ifp) +dhcp_env(FILE *fenv, const char *prefix, const struct interface *ifp, + const struct bootp *bootp, size_t bootp_len) { const struct if_options *ifo; const uint8_t *p; @@ -1309,109 +1291,73 @@ struct in_addr net; struct in_addr brd; struct dhcp_opt *opt, *vo; - size_t e, i, pl; - char **ep; - char cidr[4], safe[(BOOTP_FILE_LEN * 4) + 1]; + size_t i, pl; + char safe[(BOOTP_FILE_LEN * 4) + 1]; uint8_t overl = 0; uint32_t en; - e = 0; ifo = ifp->options; if (get_option_uint8(ifp->ctx, &overl, bootp, bootp_len, DHO_OPTSOVERLOADED) == -1) overl = 0; - if (env == NULL) { - if (bootp->yiaddr || bootp->ciaddr) - e += 5; - if (*bootp->file && !(overl & 1)) - e++; - if (*bootp->sname && !(overl & 2)) - e++; - for (i = 0, opt = ifp->ctx->dhcp_opts; - i < ifp->ctx->dhcp_opts_len; - i++, opt++) - { - if (has_option_mask(ifo->nomask, opt->option)) - continue; - if (dhcp_getoverride(ifo, opt->option)) - continue; - p = get_option(ifp->ctx, bootp, bootp_len, - opt->option, &pl); - if (!p) - continue; - e += dhcp_envoption(ifp->ctx, NULL, NULL, ifp->name, - opt, dhcp_getoption, p, pl); - } - for (i = 0, opt = ifo->dhcp_override; - i < ifo->dhcp_override_len; - i++, opt++) - { - if (has_option_mask(ifo->nomask, opt->option)) - continue; - p = get_option(ifp->ctx, bootp, bootp_len, - opt->option, &pl); - if (!p) - continue; - e += dhcp_envoption(ifp->ctx, NULL, NULL, ifp->name, - opt, dhcp_getoption, p, pl); - } - return (ssize_t)e; - } - - ep = env; if (bootp->yiaddr || bootp->ciaddr) { /* Set some useful variables that we derive from the DHCP * message but are not necessarily in the options */ addr.s_addr = bootp->yiaddr ? bootp->yiaddr : bootp->ciaddr; - addvar(&ep, prefix, "ip_address", inet_ntoa(addr)); + if (efprintf(fenv, "%s_ip_address=%s", + prefix, inet_ntoa(addr)) == -1) + return -1; if (get_option_addr(ifp->ctx, &net, - bootp, bootp_len, DHO_SUBNETMASK) == -1) - { + bootp, bootp_len, DHO_SUBNETMASK) == -1) { net.s_addr = ipv4_getnetmask(addr.s_addr); - addvar(&ep, prefix, - "subnet_mask", inet_ntoa(net)); + if (efprintf(fenv, "%s_subnet_mask=%s", + prefix, inet_ntoa(net)) == -1) + return -1; } - snprintf(cidr, sizeof(cidr), "%d", inet_ntocidr(net)); - addvar(&ep, prefix, "subnet_cidr", cidr); + if (efprintf(fenv, "%s_subnet_cidr=%d", + prefix, inet_ntocidr(net))== -1) + return -1; if (get_option_addr(ifp->ctx, &brd, bootp, bootp_len, DHO_BROADCAST) == -1) { brd.s_addr = addr.s_addr | ~net.s_addr; - addvar(&ep, prefix, - "broadcast_address", inet_ntoa(brd)); + if (efprintf(fenv, "%s_broadcast_address=%s", + prefix, inet_ntoa(brd)) == -1) + return -1; } addr.s_addr = bootp->yiaddr & net.s_addr; - addvar(&ep, prefix, - "network_number", inet_ntoa(addr)); + if (efprintf(fenv, "%s_network_number=%s", + prefix, inet_ntoa(addr)) == -1) + return -1; } if (*bootp->file && !(overl & 1)) { print_string(safe, sizeof(safe), OT_STRING, bootp->file, sizeof(bootp->file)); - addvar(&ep, prefix, "filename", safe); + if (efprintf(fenv, "%s_filename=%s", prefix, safe) == -1) + return -1; } if (*bootp->sname && !(overl & 2)) { print_string(safe, sizeof(safe), OT_STRING | OT_DOMAIN, bootp->sname, sizeof(bootp->sname)); - addvar(&ep, prefix, "server_name", safe); + if (efprintf(fenv, "%s_server_name=%s", prefix, safe) == -1) + return -1; } /* Zero our indexes */ - if (env) { - for (i = 0, opt = ifp->ctx->dhcp_opts; - i < ifp->ctx->dhcp_opts_len; - i++, opt++) - dhcp_zero_index(opt); - for (i = 0, opt = ifp->options->dhcp_override; - i < ifp->options->dhcp_override_len; - i++, opt++) - dhcp_zero_index(opt); - for (i = 0, opt = ifp->ctx->vivso; - i < ifp->ctx->vivso_len; - i++, opt++) - dhcp_zero_index(opt); - } + for (i = 0, opt = ifp->ctx->dhcp_opts; + i < ifp->ctx->dhcp_opts_len; + i++, opt++) + dhcp_zero_index(opt); + for (i = 0, opt = ifp->options->dhcp_override; + i < ifp->options->dhcp_override_len; + i++, opt++) + dhcp_zero_index(opt); + for (i = 0, opt = ifp->ctx->vivso; + i < ifp->ctx->vivso_len; + i++, opt++) + dhcp_zero_index(opt); for (i = 0, opt = ifp->ctx->dhcp_opts; i < ifp->ctx->dhcp_opts_len; @@ -1424,7 +1370,7 @@ p = get_option(ifp->ctx, bootp, bootp_len, opt->option, &pl); if (p == NULL) continue; - ep += dhcp_envoption(ifp->ctx, ep, prefix, ifp->name, + dhcp_envoption(ifp->ctx, fenv, prefix, ifp->name, opt, dhcp_getoption, p, pl); if (opt->option != DHO_VIVSO || pl <= (int)sizeof(uint32_t)) @@ -1437,7 +1383,7 @@ /* Skip over en + total size */ p += sizeof(en) + 1; pl -= sizeof(en) + 1; - ep += dhcp_envoption(ifp->ctx, ep, prefix, ifp->name, + dhcp_envoption(ifp->ctx, fenv, prefix, ifp->name, vo, dhcp_getoption, p, pl); } @@ -1450,11 +1396,11 @@ p = get_option(ifp->ctx, bootp, bootp_len, opt->option, &pl); if (p == NULL) continue; - ep += dhcp_envoption(ifp->ctx, ep, prefix, ifp->name, + dhcp_envoption(ifp->ctx, fenv, prefix, ifp->name, opt, dhcp_getoption, p, pl); } - return ep - env; + return 1; } static void
--- a/src/dhcp.h Thu Jul 04 12:18:28 2019 +0100 +++ b/src/dhcp.h Thu Jul 04 12:22:46 2019 +0100 @@ -246,15 +246,15 @@ #include "dhcpcd.h" #include "if-options.h" -char *decode_rfc3361(const uint8_t *, size_t); -ssize_t decode_rfc3442(char *, size_t, const uint8_t *p, size_t); +ssize_t print_rfc3361(FILE *, const uint8_t *, size_t); +ssize_t print_rfc3442(FILE *, const uint8_t *, size_t); void dhcp_printoptions(const struct dhcpcd_ctx *, const struct dhcp_opt *, size_t); uint16_t dhcp_get_mtu(const struct interface *); int dhcp_get_routes(rb_tree_t *, struct interface *); -ssize_t dhcp_env(char **, const char *, const struct bootp *, size_t, - const struct interface *); +ssize_t dhcp_env(FILE *, const char *, const struct interface *, + const struct bootp *, size_t); void dhcp_handleifa(int, struct ipv4_addr *, pid_t pid); void dhcp_drop(struct interface *, const char *);
--- a/src/dhcp6.c Thu Jul 04 12:18:28 2019 +0100 +++ b/src/dhcp6.c Thu Jul 04 12:22:46 2019 +0100 @@ -3955,24 +3955,22 @@ } ssize_t -dhcp6_env(char **env, const char *prefix, const struct interface *ifp, +dhcp6_env(FILE *fp, const char *prefix, const struct interface *ifp, const struct dhcp6_message *m, size_t len) { const struct if_options *ifo; struct dhcp_opt *opt, *vo; const uint8_t *p; struct dhcp6_option o; - size_t i, n; + size_t i; char *pfx; uint32_t en; const struct dhcpcd_ctx *ctx; #ifndef SMALL const struct dhcp6_state *state; const struct ipv6_addr *ap; - char *v, *val; #endif - n = 0; if (m == NULL) goto delegated; @@ -3987,28 +3985,20 @@ ctx = ifp->ctx; /* Zero our indexes */ - if (env) { - for (i = 0, opt = ctx->dhcp6_opts; - i < ctx->dhcp6_opts_len; - i++, opt++) - dhcp_zero_index(opt); - for (i = 0, opt = ifp->options->dhcp6_override; - i < ifp->options->dhcp6_override_len; - i++, opt++) - dhcp_zero_index(opt); - for (i = 0, opt = ctx->vivso; - i < ctx->vivso_len; - i++, opt++) - dhcp_zero_index(opt); - i = strlen(prefix) + strlen("_dhcp6") + 1; - pfx = malloc(i); - if (pfx == NULL) { - logerr(__func__); - return -1; - } - snprintf(pfx, i, "%s_dhcp6", prefix); - } else - pfx = NULL; + for (i = 0, opt = ctx->dhcp6_opts; + i < ctx->dhcp6_opts_len; + i++, opt++) + dhcp_zero_index(opt); + for (i = 0, opt = ifp->options->dhcp6_override; + i < ifp->options->dhcp6_override_len; + i++, opt++) + dhcp_zero_index(opt); + for (i = 0, opt = ctx->vivso; + i < ctx->vivso_len; + i++, opt++) + dhcp_zero_index(opt); + if (asprintf(&pfx, "%s_dhcp6", prefix) == -1) + return -1; /* Unlike DHCP, DHCPv6 options *may* occur more than once. * There is also no provision for option concatenation unlike DHCP. */ @@ -4054,15 +4044,13 @@ opt = NULL; } if (opt) { - n += dhcp_envoption(ifp->ctx, - env == NULL ? NULL : &env[n], - pfx, ifp->name, + dhcp_envoption(ifp->ctx, + fp, pfx, ifp->name, opt, dhcp6_getoption, p, o.len); } if (vo) { - n += dhcp_envoption(ifp->ctx, - env == NULL ? NULL : &env[n], - pfx, ifp->name, + dhcp_envoption(ifp->ctx, + fp, pfx, ifp->name, vo, dhcp6_getoption, p + sizeof(en), o.len - sizeof(en)); @@ -4074,38 +4062,29 @@ #ifndef SMALL /* Needed for Delegated Prefixes */ state = D6_CSTATE(ifp); - i = 0; TAILQ_FOREACH(ap, &state->addrs, next) { - if (ap->delegating_prefix) { - i += strlen(ap->saddr) + 1; - } + if (ap->delegating_prefix) + break; } - if (env && i) { - i += strlen(prefix) + strlen("_delegated_dhcp6_prefix="); - v = val = env[n] = malloc(i); - if (v == NULL) { - logerr(__func__); - return -1; + if (ap == NULL) + return 1; + if (fprintf(fp, "%s_delegated_dhcp6_prefix=", prefix) == -1) + return -1; + TAILQ_FOREACH(ap, &state->addrs, next) { + if (ap->delegating_prefix == NULL) + continue; + if (ap != TAILQ_FIRST(&state->addrs)) { + if (fputc(' ', fp) == EOF) + return -1; } - v += snprintf(val, i, "%s_delegated_dhcp6_prefix=", prefix); - TAILQ_FOREACH(ap, &state->addrs, next) { - if (ap->delegating_prefix) { - /* Can't use stpcpy(3) due to "security" */ - const char *sap = ap->saddr; - - do - *v++ = *sap; - while (*++sap != '\0'); - *v++ = ' '; - } - } - *--v = '\0'; + if (fprintf(fp, "%s", ap->saddr) == -1) + return -1; } - if (i) - n++; + if (fputc('\0', fp) == EOF) + return -1; #endif - return (ssize_t)n; + return 1; } int
--- a/src/dhcp6.h Thu Jul 04 12:18:28 2019 +0100 +++ b/src/dhcp6.h Thu Jul 04 12:22:46 2019 +0100 @@ -229,7 +229,7 @@ int dhcp6_start(struct interface *, enum DH6S); void dhcp6_reboot(struct interface *); void dhcp6_renew(struct interface *); -ssize_t dhcp6_env(char **, const char *, const struct interface *, +ssize_t dhcp6_env(FILE *, const char *, const struct interface *, const struct dhcp6_message *, size_t); void dhcp6_free(struct interface *); void dhcp6_handleifa(int, struct ipv6_addr *, pid_t);
--- a/src/dhcpcd.c Thu Jul 04 12:18:28 2019 +0100 +++ b/src/dhcpcd.c Thu Jul 04 12:22:46 2019 +0100 @@ -2134,5 +2134,11 @@ if (ctx.options & DHCPCD_FORKED) _exit(i); /* so atexit won't remove our pidfile */ #endif +#ifdef HAVE_OPEN_MEMSTREAM + if (ctx.script_fp) + fclose(ctx.script_fp); +#endif + free(ctx.script_buf); + free(ctx.script_env); return i; }
--- a/src/dhcpcd.h Thu Jul 04 12:18:28 2019 +0100 +++ b/src/dhcpcd.h Thu Jul 04 12:22:46 2019 +0100 @@ -157,6 +157,14 @@ #endif struct eloop *eloop; +#ifdef HAVE_OPEN_MEMSTREAM + FILE *script_fp; +#endif + char *script_buf; + size_t script_buflen; + char **script_env; + size_t script_envlen; + int control_fd; int control_unpriv_fd; struct fd_list_head control_fds;
--- a/src/ipv4.c Thu Jul 04 12:18:28 2019 +0100 +++ b/src/ipv4.c Thu Jul 04 12:22:46 2019 +0100 @@ -39,6 +39,7 @@ #include <ctype.h> #include <errno.h> #include <stdbool.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h>
--- a/src/ipv4ll.c Thu Jul 04 12:18:28 2019 +0100 +++ b/src/ipv4ll.c Thu Jul 04 12:22:46 2019 +0100 @@ -31,6 +31,7 @@ #include <assert.h> #include <errno.h> #include <stdbool.h> +#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> @@ -138,7 +139,7 @@ } ssize_t -ipv4ll_env(char **env, const char *prefix, const struct interface *ifp) +ipv4ll_env(FILE *fp, const char *prefix, const struct interface *ifp) { const struct ipv4ll_state *state; const char *pf = prefix == NULL ? "" : "_"; @@ -148,24 +149,21 @@ if ((state = IPV4LL_CSTATE(ifp)) == NULL || state->addr == NULL) return 0; - if (env == NULL) - return 5; - /* Emulate a DHCP environment */ - if (asprintf(&env[0], "%s%sip_address=%s", + if (efprintf(fp, "%s%sip_address=%s", prefix, pf, inet_ntoa(state->addr->addr)) == -1) return -1; - if (asprintf(&env[1], "%s%ssubnet_mask=%s", + if (efprintf(fp, "%s%ssubnet_mask=%s", prefix, pf, inet_ntoa(state->addr->mask)) == -1) return -1; - if (asprintf(&env[2], "%s%ssubnet_cidr=%d", + if (efprintf(fp, "%s%ssubnet_cidr=%d", prefix, pf, inet_ntocidr(state->addr->mask)) == -1) return -1; - if (asprintf(&env[3], "%s%sbroadcast_address=%s", + if (efprintf(fp, "%s%sbroadcast_address=%s", prefix, pf, inet_ntoa(state->addr->brd)) == -1) return -1; netnum.s_addr = state->addr->addr.s_addr & state->addr->mask.s_addr; - if (asprintf(&env[4], "%s%snetwork_number=%s", + if (efprintf(fp, "%s%snetwork_number=%s", prefix, pf, inet_ntoa(netnum)) == -1) return -1; return 5;
--- a/src/ipv4ll.h Thu Jul 04 12:18:28 2019 +0100 +++ b/src/ipv4ll.h Thu Jul 04 12:22:46 2019 +0100 @@ -60,7 +60,7 @@ int ipv4ll_subnetroute(rb_tree_t *, struct interface *); int ipv4ll_defaultroute(rb_tree_t *,struct interface *); -ssize_t ipv4ll_env(char **, const char *, const struct interface *); +ssize_t ipv4ll_env(FILE *, const char *, const struct interface *); void ipv4ll_start(void *); void ipv4ll_claimed(void *); void ipv4ll_handle_failure(void *);
--- a/src/ipv6.c Thu Jul 04 12:18:28 2019 +0100 +++ b/src/ipv6.c Thu Jul 04 12:22:46 2019 +0100 @@ -1541,23 +1541,17 @@ } ssize_t -ipv6_env(char **env, const char *prefix, const struct interface *ifp) +ipv6_env(FILE *fp, const char *prefix, const struct interface *ifp) { - char **ep; - ssize_t n; struct ipv6_addr *ia; - ep = env; - n = 0; ia = ipv6_iffindaddr(UNCONST(ifp), &ifp->options->req_addr6, IN6_IFF_NOTUSEABLE); - if (ia) { - if (env) - addvar(&ep, prefix, "ip6_address", ia->saddr); - n++; - } - - return n; + if (ia == NULL) + return 0; + if (efprintf(fp, "%s_ip6_address=%s", prefix, ia->saddr) == -1) + return -1; + return 1; } int
--- a/src/ipv6.h Thu Jul 04 12:18:28 2019 +0100 +++ b/src/ipv6.h Thu Jul 04 12:22:46 2019 +0100 @@ -288,7 +288,7 @@ int ipv6_start(struct interface *); int ipv6_staticdadcompleted(const struct interface *); int ipv6_startstatic(struct interface *); -ssize_t ipv6_env(char **, const char *, const struct interface *); +ssize_t ipv6_env(FILE *, const char *, const struct interface *); void ipv6_ctxfree(struct dhcpcd_ctx *); bool inet6_getroutes(struct dhcpcd_ctx *, rb_tree_t *); #endif /* INET6 */
--- a/src/ipv6nd.c Thu Jul 04 12:18:28 2019 +0100 +++ b/src/ipv6nd.c Thu Jul 04 12:22:46 2019 +0100 @@ -1385,11 +1385,11 @@ } ssize_t -ipv6nd_env(char **env, const char *prefix, const struct interface *ifp) +ipv6nd_env(FILE *fp, const struct interface *ifp) { size_t i, j, n, len, olen; struct ra *rap; - char ndprefix[32], abuf[24]; + char ndprefix[32]; struct dhcp_opt *opt; uint8_t *p; struct nd_opt_hdr ndo; @@ -1402,34 +1402,24 @@ if (rap->iface != ifp) continue; i++; - if (prefix != NULL) - snprintf(ndprefix, sizeof(ndprefix), - "%s_nd%zu", prefix, i); - else - snprintf(ndprefix, sizeof(ndprefix), - "nd%zu", i); - if (env) - setvar(&env[n], ndprefix, "from", rap->sfrom); - n++; - if (env) - setvard(&env[n], ndprefix, "acquired", - (size_t)rap->acquired.tv_sec); - n++; - if (env) - setvard(&env[n], ndprefix, "now", (size_t)now.tv_sec); - n++; + snprintf(ndprefix, sizeof(ndprefix), "nd%zu", i); + if (efprintf(fp, "%s_from=%s", ndprefix, rap->sfrom) == -1) + return -1; + if (efprintf(fp, "%s_acquired=%ld", ndprefix, + rap->acquired.tv_sec) == -1) + return -1; + if (efprintf(fp, "%s_now=%ld", ndprefix, now.tv_sec) == -1) + return -1; /* Zero our indexes */ - if (env) { - for (j = 0, opt = rap->iface->ctx->nd_opts; - j < rap->iface->ctx->nd_opts_len; - j++, opt++) - dhcp_zero_index(opt); - for (j = 0, opt = rap->iface->options->nd_override; - j < rap->iface->options->nd_override_len; - j++, opt++) - dhcp_zero_index(opt); - } + for (j = 0, opt = rap->iface->ctx->nd_opts; + j < rap->iface->ctx->nd_opts_len; + j++, opt++) + dhcp_zero_index(opt); + for (j = 0, opt = rap->iface->options->nd_override; + j < rap->iface->options->nd_override_len; + j++, opt++) + dhcp_zero_index(opt); /* Unlike DHCP, ND6 options *may* occur more than once. * There is also no provision for option concatenation @@ -1462,13 +1452,12 @@ if (j == rap->iface->ctx->nd_opts_len) opt = NULL; } - if (opt) { - n += dhcp_envoption(rap->iface->ctx, - env == NULL ? NULL : &env[n], - ndprefix, rap->iface->name, - opt, ipv6nd_getoption, - p + sizeof(ndo), olen - sizeof(ndo)); - } + if (opt == NULL) + continue; + dhcp_envoption(rap->iface->ctx, fp, + ndprefix, rap->iface->name, + opt, ipv6nd_getoption, + p + sizeof(ndo), olen - sizeof(ndo)); } /* We need to output the addresses we actually made @@ -1482,15 +1471,12 @@ !(ia->flags & IPV6_AF_ADDED) || ia->prefix_vltime == 0) continue; - j++; - if (env) { - snprintf(abuf, sizeof(abuf), "addr%zu", j); - setvar(&env[n], ndprefix, abuf, ia->saddr); - } - n++; + if (efprintf(fp, "%s_addr%zu=%s", + ndprefix, j++, ia->saddr) == -1) + return -1; } } - return (ssize_t)n; + return 1; } void @@ -1622,13 +1608,13 @@ #endif case ND_OPT_DNSSL: if (len < sizeof(dnssl)) - break; + continue; memcpy(&dnssl, p, sizeof(dnssl)); ltime = dnssl.nd_opt_dnssl_lifetime; break; case ND_OPT_RDNSS: if (len < sizeof(rdnss)) - break; + continue; memcpy(&rdnss, p, sizeof(rdnss)); ltime = rdnss.nd_opt_rdnss_lifetime; break;
--- a/src/ipv6nd.h Thu Jul 04 12:18:28 2019 +0100 +++ b/src/ipv6nd.h Thu Jul 04 12:22:46 2019 +0100 @@ -96,7 +96,7 @@ void ipv6nd_printoptions(const struct dhcpcd_ctx *, const struct dhcp_opt *, size_t); void ipv6nd_startrs(struct interface *); -ssize_t ipv6nd_env(char **, const char *, const struct interface *); +ssize_t ipv6nd_env(FILE *, const struct interface *); const struct ipv6_addr *ipv6nd_iffindaddr(const struct interface *ifp, const struct in6_addr *addr, unsigned int flags); struct ipv6_addr *ipv6nd_findaddr(struct dhcpcd_ctx *,
--- a/src/script.c Thu Jul 04 12:18:28 2019 +0100 +++ b/src/script.c Thu Jul 04 12:22:46 2019 +0100 @@ -37,6 +37,7 @@ #include <errno.h> #include <signal.h> #include <spawn.h> +#include <stdarg.h> #include <stdlib.h> #include <string.h> #include <unistd.h> @@ -57,7 +58,7 @@ #define RC_SVCNAME "RC_SVCNAME" #endif -#define DEFAULT_PATH "PATH=/usr/bin:/usr/sbin:/bin:/sbin" +#define DEFAULT_PATH "/usr/bin:/usr/sbin:/bin:/sbin" static const char * const if_params[] = { "interface", @@ -121,103 +122,23 @@ } #ifdef INET -static char * -make_var(const char *prefix, const char *var) +static int +append_config(FILE *fp, const char *prefix, const char *const *config) { - size_t len; - char *v; - - len = strlen(prefix) + strlen(var) + 2; - if ((v = malloc(len)) == NULL) { - logerr(__func__); - return NULL; - } - snprintf(v, len, "%s_%s", prefix, var); - return v; -} - - -static int -append_config(char ***env, size_t *len, - const char *prefix, const char *const *config) -{ - size_t i, j, e1; - char **ne, *eq, **nep, *p; - int ret; + size_t i; if (config == NULL) return 0; - ne = *env; - ret = 0; + /* Do we need to replace existing config rather than append? */ for (i = 0; config[i] != NULL; i++) { - eq = strchr(config[i], '='); - e1 = (size_t)(eq - config[i] + 1); - for (j = 0; j < *len; j++) { - if (strncmp(ne[j], prefix, strlen(prefix)) == 0 && - ne[j][strlen(prefix)] == '_' && - strncmp(ne[j] + strlen(prefix) + 1, - config[i], e1) == 0) - { - p = make_var(prefix, config[i]); - if (p == NULL) { - ret = -1; - break; - } - free(ne[j]); - ne[j] = p; - break; - } - } - if (j == *len) { - j++; - p = make_var(prefix, config[i]); - if (p == NULL) { - ret = -1; - break; - } - nep = realloc(ne, sizeof(char *) * (j + 1)); - if (nep == NULL) { - logerr(__func__); - free(p); - ret = -1; - break; - } - ne = nep; - ne[j - 1] = p; - *len = j; - } + if (efprintf(fp, "%s_%s", prefix, config[i]) == -1) + return -1; } - *env = ne; - return ret; + return 1; } -#endif - -static ssize_t -arraytostr(const char *const *argv, char **s) -{ - const char *const *ap; - char *p; - size_t len, l; - if (*argv == NULL) - return 0; - len = 0; - ap = argv; - while (*ap) - len += strlen(*ap++) + 1; - *s = p = malloc(len); - if (p == NULL) - return -1; - ap = argv; - while (*ap) { - l = strlen(*ap) + 1; - memcpy(p, *ap, l); - p += l; - ap++; - } - return (ssize_t)len; -} +#endif #define PROTO_LINK 0 #define PROTO_DHCP 1 @@ -234,15 +155,32 @@ "static6" }; -static ssize_t -make_env(const struct interface *ifp, const char *reason, char ***argv) +int +efprintf(FILE *fp, const char *fmt, ...) { - int protocol, r; - char **env, **nenv, *p; - size_t e, elen, l; -#if defined(INET) || defined(INET6) - ssize_t n; -#endif + va_list args; + int r; + + va_start(args, fmt); + r = vfprintf(fp, fmt, args); + va_end(args); + if (r == -1) + return -1; + /* Write a trailing NULL so we can easily create env strings. */ + if (fputc('\0', fp) == EOF) + return -1; + return r; +} + +static ssize_t +make_env(const struct interface *ifp, const char *reason) +{ + struct dhcpcd_ctx *ctx = ifp->ctx; + FILE *fp; + char **env, **envp, *buf, *bufp, *endp, *path; + size_t nenv; + long buf_pos, i; + int protocol; const struct if_options *ifo = ifp->options; const struct interface *ifp2; int af; @@ -256,6 +194,31 @@ const struct dhcp6_state *d6_state; #endif +#ifdef HAVE_OPEN_MEMSTREAM + if (ctx->script_fp == NULL) { + fp = open_memstream(&ctx->script_buf, &ctx->script_buflen); + if (fp == NULL) + goto eexit; + ctx->script_fp = fp; + } else { + fp = ctx->script_fp; + rewind(fp); + } +#else + char tmpfile[] = "/tmp/dhcpcd-script-env-XXXXXX"; + int tmpfd; + + fp = NULL; + tmpfd = mkstemp(tmpfile); + if (tmpfd == -1) + goto eexit; + unlink(tmpfile); + fp = fopen(tmpfile, "w+"); + close(tmpfd); + if (fp == NULL) + goto eexit; +#endif + #ifdef INET state = D_STATE(ifp); #ifdef IPV4LL @@ -310,71 +273,60 @@ protocol = PROTO_DHCP; #endif - /* When dumping the lease, we only want to report interface and - reason - the other interface variables are meaningless */ - if (ifp->ctx->options & DHCPCD_DUMPLEASE) - elen = 2; - else - elen = 11; + /* Needed for scripts */ + path = getenv("PATH"); + if (efprintf(fp, "PATH=%s", path == NULL ? DEFAULT_PATH:path) == -1) + goto eexit; -#define EMALLOC(i, l) if ((env[(i)] = malloc((l))) == NULL) goto eexit; - /* Make our env + space for profile, wireless and debug */ - env = calloc(1, sizeof(char *) * (elen + 5 + 1)); - if (env == NULL) + if (efprintf(fp, "interface=%s", ifp->name) == -1) goto eexit; - e = strlen("interface") + strlen(ifp->name) + 2; - EMALLOC(0, e); - snprintf(env[0], e, "interface=%s", ifp->name); - e = strlen("reason") + strlen(reason) + 2; - EMALLOC(1, e); - snprintf(env[1], e, "reason=%s", reason); + if (efprintf(fp, "reason=%s", reason) == -1) + goto eexit; if (ifp->ctx->options & DHCPCD_DUMPLEASE) goto dumplease; - e = 20; - EMALLOC(2, e); - snprintf(env[2], e, "pid=%d", getpid()); - EMALLOC(3, e); - snprintf(env[3], e, "ifcarrier=%s", + if (efprintf(fp, "pid=%d", getpid()) == -1) + goto eexit; + if (efprintf(fp, "ifcarrier=%s", ifp->carrier == LINK_UNKNOWN ? "unknown" : - ifp->carrier == LINK_UP ? "up" : "down"); - EMALLOC(4, e); - snprintf(env[4], e, "ifmetric=%d", ifp->metric); - EMALLOC(5, e); - snprintf(env[5], e, "ifwireless=%d", ifp->wireless); - EMALLOC(6, e); - snprintf(env[6], e, "ifflags=%u", ifp->flags); - EMALLOC(7, e); - snprintf(env[7], e, "ifmtu=%d", if_getmtu(ifp)); - l = e = strlen("interface_order="); + ifp->carrier == LINK_UP ? "up" : "down") == -1) + goto eexit; + if (efprintf(fp, "ifmetric=%d", ifp->metric) == -1) + goto eexit; + if (efprintf(fp, "ifwireless=%d", ifp->wireless) == -1) + goto eexit; + if (efprintf(fp, "ifflags=%u", ifp->flags) == -1) + goto eexit; + if (efprintf(fp, "ifmtu=%d", if_getmtu(ifp)) == -1) + goto eexit; + + if (fprintf(fp, "interface_order=") == -1) + goto eexit; TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) { - e += strlen(ifp2->name) + 1; + if (ifp2 != TAILQ_FIRST(ifp->ctx->ifaces)) { + if (fputc(' ', fp) == EOF) + return -1; + } + if (fprintf(fp, "%s", ifp2->name) == -1) + return -1; } - EMALLOC(8, e); - p = env[8]; - strlcpy(p, "interface_order=", e); - e -= l; - p += l; - TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) { - l = strlcpy(p, ifp2->name, e); - p += l; - e -= l; - *p++ = ' '; - e--; - } - *--p = '\0'; + if (fputc('\0', fp) == EOF) + return -1; + if (strcmp(reason, "STOPPED") == 0) { - env[9] = strdup("if_up=false"); - if (ifo->options & DHCPCD_RELEASE) - env[10] = strdup("if_down=true"); - else - env[10] = strdup("if_down=false"); + if (efprintf(fp, "if_up=false") == -1) + goto eexit; + if (efprintf(fp, "if_down=%s", + ifo->options & DHCPCD_RELEASE ? "true" : "false") == -1) + goto eexit; } else if (strcmp(reason, "TEST") == 0 || strcmp(reason, "PREINIT") == 0 || strcmp(reason, "CARRIER") == 0 || strcmp(reason, "UNKNOWN") == 0) { - env[9] = strdup("if_up=false"); - env[10] = strdup("if_down=false"); + if (efprintf(fp, "if_up=false") == -1) + goto eexit; + if (efprintf(fp, "if_down=false") == -1) + goto eexit; } else if (1 == 2 /* appease ifdefs */ #ifdef INET || (protocol == PROTO_DHCP && state && state->new) @@ -391,24 +343,23 @@ #endif ) { - env[9] = strdup("if_up=true"); - env[10] = strdup("if_down=false"); + if (efprintf(fp, "if_up=true") == -1) + goto eexit; + if (efprintf(fp, "if_down=false") == -1) + goto eexit; } else { - env[9] = strdup("if_up=false"); - env[10] = strdup("if_down=true"); + if (efprintf(fp, "if_up=false") == -1) + goto eexit; + if (efprintf(fp, "if_down=true") == -1) + goto eexit; } - if (env[9] == NULL || env[10] == NULL) - goto eexit; if (protocols[protocol] != NULL) { - r = asprintf(&env[elen], "protocol=%s", protocols[protocol]); - if (r == -1) + if (efprintf(fp, "protocol=%s", protocols[protocol]) == -1) goto eexit; - elen++; } if ((af = dhcpcd_ifafwaiting(ifp)) != AF_MAX) { - e = 20; - EMALLOC(elen, e); - snprintf(env[elen++], e, "if_afwaiting=%d", af); + if (efprintf(fp, "if_afwaiting=%d", af) == -1) + goto eexit; } if ((af = dhcpcd_afwaiting(ifp->ctx)) != AF_MAX) { TAILQ_FOREACH(ifp2, ifp->ctx->ifaces, next) { @@ -417,75 +368,42 @@ } } if (af != AF_MAX) { - e = 20; - EMALLOC(elen, e); - snprintf(env[elen++], e, "af_waiting=%d", af); + if (efprintf(fp, "af_waiting=%d", af) == -1) + goto eexit; } if (ifo->options & DHCPCD_DEBUG) { - e = strlen("syslog_debug=true") + 1; - EMALLOC(elen, e); - snprintf(env[elen++], e, "syslog_debug=true"); + if (efprintf(fp, "syslog_debug=true") == -1) + goto eexit; } if (*ifp->profile) { - e = strlen("profile=") + strlen(ifp->profile) + 1; - EMALLOC(elen, e); - snprintf(env[elen++], e, "profile=%s", ifp->profile); + if (efprintf(fp, "profile=%s", ifp->profile) == -1) + goto eexit; } if (ifp->wireless) { - static const char *pfx = "ifssid="; - size_t pfx_len; - ssize_t psl; + char pssid[IF_SSIDLEN * 4]; - pfx_len = strlen(pfx); - psl = print_string(NULL, 0, OT_ESCSTRING, - (const uint8_t *)ifp->ssid, ifp->ssid_len); - if (psl != -1) { - EMALLOC(elen, pfx_len + (size_t)psl + 1); - memcpy(env[elen], pfx, pfx_len); - print_string(env[elen] + pfx_len, (size_t)psl + 1, - OT_ESCSTRING, - (const uint8_t *)ifp->ssid, ifp->ssid_len); - elen++; + if (print_string(pssid, sizeof(pssid), OT_ESCSTRING, + ifp->ssid, ifp->ssid_len) != -1) + { + if (efprintf(fp, "ifssid=%s", pssid) == -1) + goto eexit; } } #ifdef INET if (protocol == PROTO_DHCP && state && state->old) { - n = dhcp_env(NULL, NULL, state->old, state->old_len, ifp); - if (n == -1) + if (dhcp_env(fp, "old", ifp, + state->old, state->old_len) == -1) goto eexit; - if (n > 0) { - nenv = realloc(env, sizeof(char *) * - (elen + (size_t)n + 1)); - if (nenv == NULL) - goto eexit; - env = nenv; - n = dhcp_env(env + elen, "old", - state->old, state->old_len, ifp); - if (n == -1) - goto eexit; - elen += (size_t)n; - } - if (append_config(&env, &elen, "old", + if (append_config(fp, "old", (const char *const *)ifo->config) == -1) goto eexit; } #endif #ifdef DHCP6 if (protocol == PROTO_DHCP6 && d6_state && d6_state->old) { - n = dhcp6_env(NULL, NULL, ifp, - d6_state->old, d6_state->old_len); - if (n > 0) { - nenv = realloc(env, sizeof(char *) * - (elen + (size_t)n + 1)); - if (nenv == NULL) - goto eexit; - env = nenv; - n = dhcp6_env(env + elen, "old", ifp, - d6_state->old, d6_state->old_len); - if (n == -1) - goto eexit; - elen += (size_t)n; - } + if (dhcp6_env(fp, "old", ifp, + d6_state->old, d6_state->old_len) == -1) + goto eexit; } #endif @@ -493,144 +411,114 @@ #ifdef INET #ifdef IPV4LL if (protocol == PROTO_IPV4LL) { - n = ipv4ll_env(NULL, NULL, ifp); - if (n > 0) { - nenv = realloc(env, sizeof(char *) * - (elen + (size_t)n + 1)); - if (nenv == NULL) - goto eexit; - env = nenv; - if ((n = ipv4ll_env(env + elen, - istate->down ? "old" : "new", ifp)) == -1) - goto eexit; - elen += (size_t)n; - } + if (ipv4ll_env(fp, istate->down ? "old" : "new", ifp) == -1) + goto eexit; } #endif if (protocol == PROTO_DHCP && state && state->new) { - n = dhcp_env(NULL, NULL, state->new, state->new_len, ifp); - if (n > 0) { - nenv = realloc(env, sizeof(char *) * - (elen + (size_t)n + 1)); - if (nenv == NULL) - goto eexit; - env = nenv; - n = dhcp_env(env + elen, "new", - state->new, state->new_len, ifp); - if (n == -1) - goto eexit; - elen += (size_t)n; - } - if (append_config(&env, &elen, "new", + if (dhcp_env(fp, "new", ifp, + state->new, state->new_len) == -1) + goto eexit; + if (append_config(fp, "new", (const char *const *)ifo->config) == -1) goto eexit; } #endif #ifdef INET6 if (protocol == PROTO_STATIC6) { - n = ipv6_env(NULL, NULL, ifp); - if (n > 0) { - nenv = realloc(env, sizeof(char *) * - (elen + (size_t)n + 1)); - if (nenv == NULL) - goto eexit; - env = nenv; - n = ipv6_env(env + elen, "new", ifp); - if (n == -1) - goto eexit; - elen += (size_t)n; - } + if (ipv6_env(fp, "new", ifp) == -1) + goto eexit; } #ifdef DHCP6 if (protocol == PROTO_DHCP6 && D6_STATE_RUNNING(ifp)) { - n = dhcp6_env(NULL, NULL, ifp, - d6_state->new, d6_state->new_len); - if (n > 0) { - nenv = realloc(env, sizeof(char *) * - (elen + (size_t)n + 1)); - if (nenv == NULL) - goto eexit; - env = nenv; - n = dhcp6_env(env + elen, "new", ifp, - d6_state->new, d6_state->new_len); - if (n == -1) - goto eexit; - elen += (size_t)n; - } + if (dhcp6_env(fp, "new", ifp, + d6_state->new, d6_state->new_len) == -1) + goto eexit; } #endif if (protocol == PROTO_RA) { - n = ipv6nd_env(NULL, NULL, ifp); - if (n > 0) { - nenv = realloc(env, sizeof(char *) * - (elen + (size_t)n + 1)); - if (nenv == NULL) - goto eexit; - env = nenv; - n = ipv6nd_env(env + elen, NULL, ifp); - if (n == -1) - goto eexit; - elen += (size_t)n; - } + if (ipv6nd_env(fp, ifp) == -1) + goto eexit; } #endif /* Add our base environment */ if (ifo->environ) { - e = 0; - while (ifo->environ[e++]) - ; - nenv = realloc(env, sizeof(char *) * (elen + e + 1)); - if (nenv == NULL) + for (i = 0; ifo->environ[i] != NULL; i++) + if (efprintf(fp, "%s", ifo->environ[i]) == -1) + goto eexit; + } + + /* Convert buffer to argv */ + fflush(fp); + + buf_pos = ftell(fp); + if (buf_pos == -1) { + logerr(__func__); + goto eexit; + } +#ifdef HAVE_OPEN_MEMSTREAM + buf = ctx->script_buf; +#else + size_t buf_len = (size_t)buf_pos; + if (ctx->script_buflen < buf_len) { + buf = realloc(ctx->script_buf, buf_len); + if (buf == NULL) goto eexit; - env = nenv; - e = 0; - while (ifo->environ[e]) { - env[elen + e] = strdup(ifo->environ[e]); - if (env[elen + e] == NULL) - goto eexit; - e++; - } - elen += e; + ctx->script_buf = buf; + ctx->script_buflen = buf_len; + } + buf = ctx->script_buf; + rewind(fp); + if (fread(buf, sizeof(char), buf_len, fp) != buf_len) + goto eexit; + fclose(fp); + fp = NULL; +#endif + + nenv = 0; + endp = buf + buf_pos; + for (bufp = buf; bufp < endp; bufp++) { + if (*bufp == '\0') + nenv++; } - env[elen] = NULL; + if (ctx->script_envlen < nenv) { + env = reallocarray(ctx->script_env, nenv + 1, sizeof(*env)); + if (env == NULL) + goto eexit; + ctx->script_env = env; + ctx->script_envlen = nenv; + } + bufp = buf; + envp = ctx->script_env; + *envp++ = bufp++; + endp--; /* Avoid setting the last \0 to an invalid pointer */ + for (; bufp < endp; bufp++) { + if (*bufp == '\0') + *envp++ = bufp + 1; + } + *envp = NULL; - *argv = env; - return (ssize_t)elen; + return (ssize_t)nenv; eexit: logerr(__func__); - if (env) { - nenv = env; - while (*nenv) - free(*nenv++); - free(env); - } +#ifndef HAVE_OPEN_MEMSTREAM + if (fp != NULL) + fclose(fp); +#endif return -1; } static int -send_interface1(struct fd_list *fd, const struct interface *iface, +send_interface1(struct fd_list *fd, const struct interface *ifp, const char *reason) { - char **env, **ep, *s; - size_t elen; - int retval; + struct dhcpcd_ctx *ctx = ifp->ctx; - if (make_env(iface, reason, &env) == -1) + if (make_env(ifp, reason) == -1) return -1; - s = NULL; - elen = (size_t)arraytostr((const char *const *)env, &s); - if ((ssize_t)elen == -1) { - free(s); - retval = -1; - } else - retval = control_queue(fd, s, elen, 1); - ep = env; - while (*ep) - free(*ep++); - free(env); - return retval; + return control_queue(fd, ctx->script_buf, ctx->script_buflen, 1); } int @@ -697,10 +585,8 @@ int script_runreason(const struct interface *ifp, const char *reason) { + struct dhcpcd_ctx *ctx = ifp->ctx; char *argv[2]; - char **env = NULL, **ep; - char *svcname, *path, *bigenv; - size_t e, elen = 0; pid_t pid; int status = 0; struct fd_list *fd; @@ -710,8 +596,7 @@ return 0; /* Make our env */ - elen = (size_t)make_env(ifp, reason, &env); - if (elen == (size_t)-1) { + if (make_env(ifp, reason) == -1) { logerr(__func__); return -1; } @@ -723,43 +608,7 @@ argv[1] = NULL; logdebugx("%s: executing `%s' %s", ifp->name, argv[0], reason); - /* Resize for PATH and RC_SVCNAME */ - svcname = getenv(RC_SVCNAME); - ep = reallocarray(env, elen + 2 + (svcname ? 1 : 0), sizeof(char *)); - if (ep == NULL) { - elen = 0; - goto out; - } - env = ep; - /* Add path to it */ - path = getenv("PATH"); - if (path) { - e = strlen("PATH") + strlen(path) + 2; - env[elen] = malloc(e); - if (env[elen] == NULL) { - elen = 0; - goto out; - } - snprintf(env[elen], e, "PATH=%s", path); - } else { - env[elen] = strdup(DEFAULT_PATH); - if (env[elen] == NULL) { - elen = 0; - goto out; - } - } - if (svcname) { - e = strlen(RC_SVCNAME) + strlen(svcname) + 2; - env[++elen] = malloc(e); - if (env[elen] == NULL) { - elen = 0; - goto out; - } - snprintf(env[elen], e, "%s=%s", RC_SVCNAME, svcname); - } - env[++elen] = NULL; - - pid = exec_script(ifp->ctx, argv, env); + pid = exec_script(ctx, argv, ctx->script_env); if (pid == -1) logerr("%s: %s", __func__, argv[0]); else if (pid != 0) { @@ -782,36 +631,16 @@ send_listeners: /* Send to our listeners */ - bigenv = NULL; status = 0; - TAILQ_FOREACH(fd, &ifp->ctx->control_fds, next) { + TAILQ_FOREACH(fd, &ctx->control_fds, next) { if (!(fd->flags & FD_LISTEN)) continue; - if (bigenv == NULL) { - elen = (size_t)arraytostr((const char *const *)env, - &bigenv); - if ((ssize_t)elen == -1) { - logerr("%s: arraytostr", ifp->name); - break; - } - } - if (control_queue(fd, bigenv, elen, 1) == -1) + if (control_queue(fd, ctx->script_buf, ctx->script_buflen, 1) + == -1) logerr("%s: control_queue", __func__); else status = 1; } - if (!status) - free(bigenv); -out: - /* Cleanup */ - ep = env; - while (*ep) - free(*ep++); - free(env); - if (elen == 0) { - logerr(__func__); - return -1; - } return WEXITSTATUS(status); }
--- a/src/script.h Thu Jul 04 12:18:28 2019 +0100 +++ b/src/script.h Thu Jul 04 12:22:46 2019 +0100 @@ -31,6 +31,7 @@ #include "control.h" +__printflike(2, 3) int efprintf(FILE *, const char *, ...); void if_printoptions(void); int send_interface(struct fd_list *, const struct interface *); int script_runreason(const struct interface *, const char *);
