]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Remove vis based encoding - instead expand the DHCP option encoding to a
authorRoy Marples <roy@marples.name>
Wed, 1 Oct 2014 18:32:03 +0000 (18:32 +0000)
committerRoy Marples <roy@marples.name>
Wed, 1 Oct 2014 18:32:03 +0000 (18:32 +0000)
natural string based on content except as noted:
  *  domain (RFC3397)/dname (string) is strict domain name allowance
     (ie, [alnum] with _- (but not at the start or end))
  *  string is now printable ascii (1-127) until invalid
  *  ascii is all ascii (1-127) until invalid
  *  raw is all chars (1-255) until NUL
  *  binhex is a hex representation of the option including embedded NULs
  *  ssid is still escpaed octal because it's expected to be human readable
     AND can technically be all NUL
  *  everything else has strict option -> value encoding

This removes all shell escaped encoding - dhcpcd will assume that IF the
--script option is a shell, it will quote variables correctly.
The stock dhcpcd-run-hooks does.

dhcpcd -V now prints how the variables will be decoded.

Changed some options in dhcpcd-definitions.conf to more sensible defaults.

16 files changed:
compat/svis.c [deleted file]
compat/svis.h [deleted file]
configure
dhcp-common.c
dhcp-common.h
dhcp.c
dhcp6.c
dhcpcd-definitions.conf
dhcpcd-hooks/01-test
dhcpcd-run-hooks.8.in
dhcpcd.8.in
dhcpcd.c
dhcpcd.conf.5.in
if-options.c
ipv6nd.c
script.c

diff --git a/compat/svis.c b/compat/svis.c
deleted file mode 100644 (file)
index 37102d7..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-/*     $NetBSD: vis.c,v 1.44 2011/03/12 19:52:48 christos Exp $        */
-
-/*-
- * Copyright (c) 1989, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the University nor the names of its contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-/*-
- * Copyright (c) 1999, 2005 The NetBSD Foundation, Inc.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
- * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- * POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * HEAVILY trimmed down for use only in dhcpcd.
- * Please use the source in NetBSD for a fuller working copy.
- */
-
-#include <ctype.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "svis.h"
-
-#undef BELL
-#define BELL '\a'
-
-#define isoctal(c)     (((u_char)(c)) >= '0' && ((u_char)(c)) <= '7')
-#define iswhite(c)     (c == ' ' || c == '\t' || c == '\n')
-
-/*
- * This is do_vis, the central code of vis.
- * dst:              Pointer to the destination buffer
- * c:        Character to encode
- * flag:      Flag word
- * nextc:     The character following 'c'
- * extra:     Pointer to the list of extra characters to be
- *           backslash-protected.
- */
-char *
-svis(char *dst, int c, int flag, int nextc, const char *extra)
-{
-       int isextra;
-
-       isextra = strchr(extra, c) != NULL;
-       if (!isextra && isascii(c) && (isgraph(c) || iswhite(c))) {
-               *dst++ = (char)c;
-               return dst;
-       }
-       if (flag & VIS_CSTYLE) {
-               switch (c) {
-               case '\n':
-                       *dst++ = '\\'; *dst++ = 'n';
-                       return dst;
-               case '\r':
-                       *dst++ = '\\'; *dst++ = 'r';
-                       return dst;
-               case '\b':
-                       *dst++ = '\\'; *dst++ = 'b';
-                       return dst;
-               case BELL:
-                       *dst++ = '\\'; *dst++ = 'a';
-                       return dst;
-               case '\v':
-                       *dst++ = '\\'; *dst++ = 'v';
-                       return dst;
-               case '\t':
-                       *dst++ = '\\'; *dst++ = 't';
-                       return dst;
-               case '\f':
-                       *dst++ = '\\'; *dst++ = 'f';
-                       return dst;
-               case ' ':
-                       *dst++ = '\\'; *dst++ = 's';
-                       return dst;
-               case '\0':
-                       *dst++ = '\\'; *dst++ = '0';
-                       if (isoctal(nextc)) {
-                               *dst++ = '0';
-                               *dst++ = '0';
-                       }
-                       return dst;
-               case '$': /* vis(1) - l */
-                       break;
-               default:
-                       if (isgraph(c)) {
-                               *dst++ = '\\'; *dst++ = (char)c;
-                               return dst;
-                       }
-               }
-       }
-
-       *dst++ = '\\';
-       if (isextra || ((c & 0177) == ' ') || (flag & VIS_OCTAL)) {
-               *dst++ = (((unsigned char)c >> 6) & 03) + '0';
-               *dst++ = (((unsigned char)c >> 3) & 07) + '0';
-               *dst++ = ( (unsigned char)c       & 07) + '0';
-       } else {
-               if (c & 0200) {
-                       c &= 0177; *dst++ = 'M';
-               }
-
-               if (iscntrl(c)) {
-                       *dst++ = '^';
-                       if (c == 0177)
-                               *dst++ = '?';
-                       else
-                               *dst++ = (char)c + '@';
-               } else {
-                       *dst++ = '-'; *dst++ = (char)c;
-               }
-       }
-       return dst;
-}
-
-char *
-vis(char *dst, int c, int flag, int nextc)
-{
-
-       return svis(dst, c, flag, nextc, "");
-}
diff --git a/compat/svis.h b/compat/svis.h
deleted file mode 100644 (file)
index c56306c..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-#ifndef SVIS_H
-#define SVIS_H
-
-#define        VIS_OCTAL       0x0001  /* use octal \ddd format */
-#define        VIS_CSTYLE      0x0002  /* use \[nrft0..] where appropiate */
-
-char *vis(char *dst, int c, int flag, int nextc);
-char *svis(char *dst, int c, int flag, int nextc, const char *meta);
-
-#endif
index e18a19a5abfc4f84eba09ffe001ef2b759258a46..294f49a0edb80711eb530d79365803ff45d935d1 100755 (executable)
--- a/configure
+++ b/configure
@@ -71,7 +71,6 @@ for x do
        --without-md5) MD5=no;;
        --without-sha2) SHA2=no;;
        --without-sha256) SHA2=no;;
-       --without-svis) SVIS=no;;
        --without-dev) DEV=no;;
        --without-udev) UDEV=no;;
        --serviceexists) SERVICEEXISTS=$var;;
@@ -628,31 +627,6 @@ if [ "$STRLCPY" = no ]; then
        echo "#include          \"compat/strlcpy.h\"" >>$CONFIG_H
 fi
 
-if [ -z "$SVIS" ]; then
-       printf "Testing for svis ... "
-       cat <<EOF >_svis.c
-#include <vis.h>
-int main(void) {
-       char s[10];
-       svis(s, 1, 2, 3, s);
-       return 0;
-}
-EOF
-       if $XCC _svis.c -o _svis 2>&3; then
-               SVIS=yes
-       else
-               SVIS=no
-       fi
-       echo "$SVIS"
-       rm -f _svis.c _svis
-fi
-if [ "$SVIS" = no ]; then
-       echo "COMPAT_SRCS+=     compat/svis.c" >>$CONFIG_MK
-       echo "#include          \"compat/svis.h\"" >>$CONFIG_H
-else
-       echo "#define HAVE_VIS_H" >>$CONFIG_H
-fi
-
 if [ -z "$DPRINTF" ]; then
        printf "Testing for dprintf ... "
        cat <<EOF >_dprintf.c
index 915cad47da1bf8b3bb0746e213d481f6bbb6dfbd..1f2e6c27bb7938147d070257069b884e125f3c7f 100644 (file)
 
 #include "config.h"
 
-#ifdef HAVE_VIS_H
-#include <vis.h>
-#endif
-
 #include "common.h"
 #include "dhcp-common.h"
 #include "dhcp.h"
 #include "if.h"
 #include "ipv6.h"
 
+void
+dhcp_print_option_encoding(const struct dhcp_opt *opt, int cols)
+{
+
+       while (cols < 40) {
+               putchar(' ');
+               cols++;
+       }
+       putchar('\t');
+       if (opt->type & EMBED)
+               printf(" embed");
+       if (opt->type & ENCAP)
+               printf(" encap");
+       if (opt->type & INDEX)
+               printf(" index");
+       if (opt->type & ARRAY)
+               printf(" array");
+       if (opt->type & UINT8)
+               printf(" byte");
+       else if (opt->type & UINT16)
+               printf(" uint16");
+       else if (opt->type & SINT16)
+               printf(" sint16");
+       else if (opt->type & UINT32)
+               printf(" uint32");
+       else if (opt->type & SINT32)
+               printf(" sint32");
+       else if (opt->type & ADDRIPV4)
+               printf(" ipaddress");
+       else if (opt->type & ADDRIPV6)
+               printf(" ip6address");
+       else if (opt->type & FLAG)
+               printf(" flag");
+       else if (opt->type & RFC3397)
+               printf(" domain");
+       else if (opt->type & DOMAIN)
+               printf(" dname");
+       else if (opt->type & ASCII)
+               printf(" ascii");
+       else if (opt->type & RAW)
+               printf(" raw");
+       else if (opt->type & BINHEX)
+               printf(" binhex");
+       else if (opt->type & STRING)    
+               printf(" string");
+       if (opt->type & RFC3361)        
+               printf(" rfc3361");
+       if (opt->type & RFC3442)
+               printf(" rfc3442");
+       if (opt->type & RFC5969)
+               printf(" rfc5969");
+       if (opt->type & REQUEST)
+               printf(" request");
+       if (opt->type & NOREQ)
+               printf(" norequest");
+       putchar('\n');
+}
+
 struct dhcp_opt *
 vivso_find(uint32_t iana_en, const void *arg)
 {
@@ -296,62 +350,174 @@ decode_rfc3397(char *out, size_t len, const uint8_t *p, size_t pl)
        return (ssize_t)count;
 }
 
-/*
- * Escape these characters to avoid any nastiness passing to a POSIX shell.
- * See IEEE Std 1003.1, 2004 Shell Command Language, 2.2 Quoting
- * space is not escaped.
- */
-#define ESCAPE_CHARS   "|&;<>()$`\\\"'\t\n"
-#define ESCAPE_EXTRA   "*?[#~=%"
+/* Check for a valid domain name as per RFC1123 with the exception of
+ * allowing - and _ (but not at start or end) as they seem to be widely used. */
+static int
+valid_domainname(char *lbl, int type)
+{
+       char *slbl, *lst;
+       unsigned char c;
+       int start, len, errset;
+
+       if (lbl == NULL || *lbl == '\0') {
+               errno = EINVAL;
+               return 0;
+       }
+
+       slbl = lbl;
+       lst = NULL;
+       start = 1;
+       len = errset = 0;
+       for (;;) {
+               c = (unsigned char)*lbl++;
+               if (c == '\0')
+                       return 1;
+               if (c == ' ') {
+                       if (lbl - 1 == slbl) /* No space at start */
+                               break;
+                       if (!(type & ARRAY))
+                               break;
+                       /* Skip to the next label */
+                       if (!start) {
+                               start = 1;
+                               lst = lbl - 1;
+                       }
+                       if (len)
+                               len = 0;
+                       continue;
+               }
+               if (c == '.') {
+                       if (*lbl == '.')
+                               break;
+                       len = 0;
+                       continue;
+               }
+               if (((c == '-' || c == '_') &&
+                   !start && *lbl != ' ' && *lbl != '\0') ||
+                   isalnum(c))
+               {
+                       if (++len > 63) {
+                               errno = ERANGE;
+                               errset = 1;
+                               break;
+                       }
+               } else
+                       break;
+               if (start)
+                       start = 0;
+       }
+
+       if (!errset)
+               errno = EINVAL;
+       if (lst) {
+               /* At least one valid domain, return it */
+               *lst = '\0';
+               return 1;
+       }
+       return 0;
+}
 
 /*
  * Prints a chunk of data to a string.
- * Escapes some characters defnined above to try and avoid any loopholes
- * in the shell we're passing to.
- * Any non visible characters are escaped as an octal number.
+ * PS_SHELL goes as it is these days, it's upto the target to validate it.
+ * PS_SAFE has all non ascii and non printables changes to escaped octal.
  */
+static const char hexchrs[] = "0123456789abcdef";
 ssize_t
-print_string(char *s, size_t len, int flags, const uint8_t *data, size_t dl)
+print_string(char *dst, size_t len, int type, const uint8_t *data, size_t dl)
 {
+       char *odst;
        uint8_t c;
-       const uint8_t *e, *p;
+       const uint8_t *e;
        size_t bytes;
-       char v[5], *vp, *ve;
 
+       odst = dst;
        bytes = 0;
        e = data + dl;
+       
        while (data < e) {
                c = *data++;
-               if (c == '\0') {
-                       /* If rest is all NULL, skip it. */
-                       for (p = data; p < e; p++)
-                               if (*p != '\0')
-                                       break;
-                       if (p == e)
-                               break;
+               if (type & BINHEX) {
+                       if (dst) {
+                               if (len  == 0 || len == 1) {
+                                       errno = ENOSPC;
+                                       return -1;
+                               }
+                               *dst++ = hexchrs[(c & 0xF0) >> 4];
+                               *dst++ = hexchrs[(c & 0x0F)];
+                               len -= 2;
+                       }
+                       bytes += 2;
+                       continue;
                }
-               if (flags & PS_SHELL)
-                       ve = svis(v, c, VIS_CSTYLE | VIS_OCTAL,
-                           data <= e ? *data : 0, ESCAPE_CHARS ESCAPE_EXTRA);
-               else
-                       ve = vis(v, c, VIS_CSTYLE | VIS_OCTAL,
-                           data <= e ? *data : 0);
-               bytes += (size_t)(ve - v);
-               if (s && len < bytes + 1) {
-                       errno = ENOBUFS;
-                       return -1;
+               if (type & ASCII && (!isascii(c))) {
+                       errno = EINVAL;
+                       break;
                }
-               if (s) {
-                       vp = v;
-                       while (vp != ve)
-                               *s++ = *vp++;
+               if (!(type & (ASCII | RAW | ESCSTRING)) /*plain string */ &&
+                   (!isascii(c) && !isprint(c)))
+               {
+                       errno = EINVAL;
+                       break;
+               }
+               if (type & ESCSTRING &&
+                   (c == '\\' || !isascii(c) || !isprint(c)))
+               {
+                       errno = EINVAL;
+                       if (c == '\\') {
+                               if (len  == 0 || len == 1) {
+                                       errno = ENOSPC;
+                                       return -1;
+                               }
+                               if (dst) {
+                                       *dst++ = '\\'; *dst++ = '\\';
+                                       len -= 2;
+                               }
+                               bytes += 2;
+                               continue;
+                       }
+                       if (dst) {
+                               if (len < 5) {
+                                       errno = ENOSPC;
+                                       return -1;
+                               }
+                               *dst++ = '\\';
+                               *dst++ = (((unsigned char)c >> 6) & 03) + '0';
+                               *dst++ = (((unsigned char)c >> 3) & 07) + '0';
+                               *dst++ = ( (unsigned char)c       & 07) + '0';
+                               len -= 4;
+                       }
+                       bytes += 4;
+               } else {
+                       if (dst) {
+                               if (len == 0) {
+                                       errno = ENOSPC;
+                                       return -1;
+                               }
+                               *dst++ = (char)c;
+                               len--;
+                       }
+                       bytes++;
                }
        }
 
        /* NULL */
-       if (s)
-               *s = '\0';
+       if (dst) {
+               if (len == 0) {
+                       errno = ENOSPC;
+                       return -1;
+               }
+               *dst = '\0';
+
+               /* Now we've printed it, validate the domain */
+               if (type & DOMAIN && !valid_domainname(odst, type)) {
+                       *odst = '\0';
+                       return 1;
+               }
+
+       }
        bytes++;
+
        return (ssize_t)bytes;
 }
 
@@ -431,7 +597,7 @@ print_option(char *s, size_t len, int type, const uint8_t *data, size_t dl,
                if (tmp == NULL)
                        return -1;
                decode_rfc3397(tmp, l, data, dl);
-               sl = print_string(s, len, PS_SHELL, (uint8_t *)tmp, l - 1);
+               sl = print_string(s, len, type, (uint8_t *)tmp, l - 1);
                free(tmp);
                return sl;
        }
@@ -441,7 +607,7 @@ print_option(char *s, size_t len, int type, const uint8_t *data, size_t dl,
                if ((tmp = decode_rfc3361(data, dl)) == NULL)
                        return -1;
                l = strlen(tmp);
-               sl = print_string(s, len, PS_SHELL, (uint8_t *)tmp, l);
+               sl = print_string(s, len, type, (uint8_t *)tmp, l);
                free(tmp);
                return sl;
        }
@@ -453,12 +619,8 @@ print_option(char *s, size_t len, int type, const uint8_t *data, size_t dl,
                return decode_rfc5969(s, len, data, dl);
 #endif
 
-       if (type & STRING) {
-               /* Some DHCP servers return NULL strings */
-               if (*data == '\0')
-                       return 0;
-               return print_string(s, len, PS_SHELL, data, dl);
-       }
+       if (type & STRING)
+               return print_string(s, len, type, data, dl);
 
        if (type & FLAG) {
                if (s) {
@@ -502,9 +664,7 @@ print_option(char *s, size_t len, int type, const uint8_t *data, size_t dl,
                        return (ssize_t)(l + 1);
                }
 #endif
-               else if (type & BINHEX) {
-                       l = 2;
-               } else {
+               else {
                        errno = EINVAL;
                        return -1;
                }
@@ -514,7 +674,7 @@ print_option(char *s, size_t len, int type, const uint8_t *data, size_t dl,
        t = data;
        e = data + dl;
        while (data < e) {
-               if (data != t && type != BINHEX) {
+               if (data != t) {
                        *s++ = ' ';
                        bytes++;
                        len--;
@@ -559,10 +719,7 @@ print_option(char *s, size_t len, int type, const uint8_t *data, size_t dl,
                        data += 16;
                }
 #endif
-               else if (type & BINHEX) {
-                       sl = snprintf(s, len, "%.2x", data[0]);
-                       data++;
-               } else
+               else
                        sl = 0;
                len -= (size_t)sl;
                bytes += sl;
index a2ac7f0da0bb146b5a312272d14ccdd5ad29f54d..05294660c42ece18e9e31febcc4b9791da586dc4 100644 (file)
 #define ENCAP          (1 << 18)
 #define INDEX          (1 << 19)
 #define OPTION         (1 << 20)
-
-/* Print string flags */
-#define PS_SHELL       (1 << 0)
+#define DOMAIN         (1 << 21)
+#define ASCII          (1 << 22)
+#define RAW            (1 << 23)
+#define ESCSTRING      (1 << 24)
 
 struct dhcp_opt {
        uint32_t option; /* Also used for IANA Enterpise Number */
@@ -87,6 +88,7 @@ struct dhcp_opt *vivso_find(uint32_t, const void *);
 
 ssize_t dhcp_vendor(char *, size_t);
 
+void dhcp_print_option_encoding(const struct dhcp_opt *opt, int cols);
 #define add_option_mask(var, val) (var[val >> 3] |= 1 << (val & 7))
 #define del_option_mask(var, val) (var[val >> 3] &= ~(1 << (val & 7)))
 #define has_option_mask(var, val) (var[val >> 3] & (1 << (val & 7)))
diff --git a/dhcp.c b/dhcp.c
index 00fd2c3cb50d73d7e879e2eb83e356a9959d121c..066885980a45c6da2170a1b31fd10e99b3b2c1c4 100644 (file)
--- a/dhcp.c
+++ b/dhcp.c
@@ -132,6 +132,7 @@ dhcp_printoptions(const struct dhcpcd_ctx *ctx,
        const char * const *p;
        size_t i, j;
        const struct dhcp_opt *opt, *opt2;
+       int cols;
 
        for (p = dhcp_params; *p; p++)
                printf("    %s\n", *p);
@@ -140,11 +141,15 @@ dhcp_printoptions(const struct dhcpcd_ctx *ctx,
                for (j = 0, opt2 = opts; j < opts_len; j++, opt2++)
                        if (opt->option == opt2->option)
                                break;
-               if (j == opts_len)
-                       printf("%03d %s\n", opt->option, opt->var);
+               if (j == opts_len) {
+                       cols = printf("%03d %s", opt->option, opt->var);
+                       dhcp_print_option_encoding(opt, cols);
+               }
+       }
+       for (i = 0, opt = opts; i < opts_len; i++, opt++) {
+               cols = printf("%03d %s", opt->option, opt->var);
+               dhcp_print_option_encoding(opt, cols);
        }
-       for (i = 0, opt = opts; i < opts_len; i++, opt++)
-               printf("%03d %s\n", opt->option, opt->var);
 }
 
 #define get_option_raw(ctx, dhcp, opt) get_option(ctx, dhcp, opt, NULL)
@@ -1269,12 +1274,12 @@ dhcp_env(char **env, const char *prefix, const struct dhcp_message *dhcp,
        }
 
        if (*dhcp->bootfile && !(overl & 1)) {
-               print_string(safe, sizeof(safe), PS_SHELL,
+               print_string(safe, sizeof(safe), STRING,
                    dhcp->bootfile, sizeof(dhcp->bootfile));
                setvar(&ep, prefix, "filename", safe);
        }
        if (*dhcp->servername && !(overl & 2)) {
-               print_string(safe, sizeof(safe), PS_SHELL,
+               print_string(safe, sizeof(safe), STRING | DOMAIN,
                    dhcp->servername, sizeof(dhcp->servername));
                setvar(&ep, prefix, "server_name", safe);
        }
@@ -2204,7 +2209,7 @@ log_dhcp1(int lvl, const char *msg,
                                free(a);
                                return;
                        }
-                       print_string(tmp, tmpl, 0, (uint8_t *)a, al);
+                       print_string(tmp, tmpl, STRING, (uint8_t *)a, al);
                        free(a);
                        a = tmp;
                }
@@ -2221,7 +2226,7 @@ log_dhcp1(int lvl, const char *msg,
        tfrom = "from";
        r = get_option_addr(iface->ctx, &addr, dhcp, DHO_SERVERID);
        if (dhcp->servername[0] && r == 0) {
-               print_string(sname, sizeof(sname), 0,
+               print_string(sname, sizeof(sname), STRING,
                    dhcp->servername, strlen((const char *)dhcp->servername));
                if (a == NULL)
                        syslog(lvl, "%s: %s %s %s `%s'", iface->name, msg,
diff --git a/dhcp6.c b/dhcp6.c
index 4e80385ba9d6b18f6dcdd60d1fe42b18e00f8857..744318b588cca6968cb46c4b9ae1941bc61fcc72 100644 (file)
--- a/dhcp6.c
+++ b/dhcp6.c
@@ -134,6 +134,7 @@ dhcp6_printoptions(const struct dhcpcd_ctx *ctx,
 {
        size_t i, j;
        const struct dhcp_opt *opt, *opt2;
+       int cols;
 
        for (i = 0, opt = ctx->dhcp6_opts;
            i < ctx->dhcp6_opts_len; i++, opt++)
@@ -141,11 +142,15 @@ dhcp6_printoptions(const struct dhcpcd_ctx *ctx,
                for (j = 0, opt2 = opts; j < opts_len; j++, opt2++)
                        if (opt2->option == opt->option)
                                break;
-               if (j == opts_len)
-                       printf("%05d %s\n", opt->option, opt->var);
+               if (j == opts_len) {
+                       cols = printf("%05d %s", opt->option, opt->var);
+                       dhcp_print_option_encoding(opt, cols);
+               }
+       }
+       for (i = 0, opt = opts; i < opts_len; i++, opt++) {
+               cols = printf("%05d %s", opt->option, opt->var);
+               dhcp_print_option_encoding(opt, cols);
        }
-       for (i = 0, opt = opts; i < opts_len; i++, opt++)
-               printf("%05d %s\n", opt->option, opt->var);
 }
 
 static size_t
index 0be5ff7866248dcb85cc918b51d313b15e5c0f61..80e00964dde24d2f42a15a54b4552c848ffde77a 100644 (file)
@@ -26,10 +26,12 @@ define 8    array ipaddress         cookie_servers
 define 9       array ipaddress         lpr_servers
 define 10      array ipaddress         impress_servers
 define 11      array ipaddress         resource_location_servers
-define 12      string                  host_name
+define 12      dname                   host_name
 define 13      uint16                  boot_size
 define 14      string                  merit_dump
-define 15      string                  domain_name
+# Technically domain_name is not an array, but many servers expect clients
+# to treat it as one.
+define 15      array dname             domain_name
 define 16      ipaddress               swap_server
 define 17      string                  root_path
 define 18      string                  extensions_path
@@ -56,7 +58,7 @@ define 39     byte                    tcp_keepalive_garbage
 define 40      string                  nis_domain
 define 41      array ipaddress         nis_servers
 define 42      array ipaddress         ntp_servers
-define 43      string                  vendor_encapsulated_options
+define 43      binhex                  vendor_encapsulated_options
 define 44      array ipaddress         netbios_name_servers
 define 45      ipaddress               netbios_dd_server
 define 46      byte                    netbios_node_type
@@ -77,7 +79,7 @@ define 60     binhex                  vendor_class_identifier
 define 61      binhex                  dhcp_client_identifier
 define 64      string                  nisplus_domain
 define 65      array ipaddress         nisplus_servers
-define 66      string                  tftp_server_name
+define 66      dname                   tftp_server_name
 define 67      string                  bootfile_name
 define 68      array ipaddress         mobile_ip_home_agent
 define 69      array ipaddress         smtp_server
@@ -90,7 +92,7 @@ define 75     array ipaddress         streettalk_server
 define 76      array ipaddress         streettalk_directory_assistance_server
 
 # DHCP User Class, RFC3004
-define 77      string                  user_class
+define 77      binhex                  user_class
 
 # DHCP SLP Directory Agent, RFC2610
 define 78      embed                   slp_agent
@@ -98,7 +100,7 @@ embed                byte                    mandatory
 embed          array ipaddress         address
 define 79      embed                   slp_service
 embed          byte                    mandatory
-embed          string                  scope_list
+embed          ascii                   scope_list
 
 # DHCP Rapid Commit, RFC4039
 define 80      norequest flag          rapid_commit
@@ -116,11 +118,11 @@ embed             domain                  fqdn
 
 # DHCP Novell Directory Services, RFC2241
 define 85      array ipaddress         nds_servers
-define 86      string                  nds_tree_name
-define 87      string                  nds_context
+define 86      raw                     nds_tree_name
+define 87      raw                     nds_context
 
 # DHCP Broadcast and Multicast Control Server, RFC4280
-define 88      domain                  bcms_controller_names
+define 88      array domain            bcms_controller_names
 define 89      array ipaddress         bcms_controller_address
 
 # DHCP Authentication, RFC3118
@@ -166,7 +168,7 @@ define 117  array uint16            name_service_search
 define 118     ipaddress               subnet_selection
 
 # DHCP Domain Search, RFC3397
-define 119     domain                  domain_search
+define 119     array domain            domain_search
 
 # DHCP Session Initiated Protocol Servers, RFC3361
 define 120     rfc3361                 sip_server
@@ -227,7 +229,7 @@ encap 2             domain                  cs
 encap 3                domain                  es
 
 # DHCP SIP UA, RFC6011
-define 141     domain                  sip_ua_cs_list
+define 141     array domain            sip_ua_cs_list
 
 # DHCP ANDSF, RFC6153
 define 142     array ipaddress         andsf
@@ -245,7 +247,7 @@ define 146  embed                   rdnss_selection
 embed          byte                    prf
 embed          ipaddress               primary
 embed          ipaddress               secondary
-embed          domain                  domains
+embed          array domain            domains
 
 # Options 147, 148 and 149 are unused, RFC3942
 
@@ -342,12 +344,12 @@ define6 19        byte                    reconfigure_msg
 define6 20     flag                    reconfigure_accept
 
 # DHCPv6 Session Initiation Protocol Options, RFC3319
-define6 21     domain                  sip_servers_names
+define6 21     array domain            sip_servers_names
 define6 22     array ip6address        sip_servers_addresses
 
 # DHCPv6 DNS Configuration Options, RFC3646
 define6 23     array ip6address        name_servers
-define6 24     domain                  domain_search
+define6 24     array domain            domain_search
 
 # DHCPv6 Prefix Options, RFC6603
 define6 25     norequest index embed   ia_pd
@@ -366,8 +368,8 @@ encap 67    option
 # DHCPv6 Network Information Service Options, RFC3898
 define6 27     array ip6address        nis_servers
 define6 28     array ip6address        nisp_servers
-define6 29     domain                  nis_domain_name
-define6 30     domain                  nisp_domain_name
+define6 29     string                  nis_domain_name
+define6 30     string                  nisp_domain_name
 
 # DHCPv6 Simple Network Time Protocol Servers Option, RFC4075
 define6 31     array ip6address        sntp_servers
@@ -376,7 +378,7 @@ define6 31  array ip6address        sntp_servers
 define6 32     uint32                  info_refresh_time
 
 # DHCPv6 Broadcast and Multicast Control Server, RFC4280
-define6 33     domain                  bcms_server_d
+define6 33     array domain            bcms_server_d
 define6 34     array ip6address        bcms_server_a
 
 # DHCP Civic Addresses Configuration Information, RFC4776
@@ -446,7 +448,7 @@ encap 3             ip6address              fqdn
 define6 57     domain                  access_domain
 
 # DHCPv6 SIP UA, RFC6011
-define6 58     domain                  sip_ua_cs_list
+define6 58     array domain            sip_ua_cs_list
 
 # DHCPv6 Network Boot, RFC5970
 define6 59     string                  bootfile_url
@@ -489,18 +491,18 @@ define6 73        domain                  mip6_haf
 define6 74     embed                   rdnss_selection
 embed          ip6address              server
 embed          byte                    prf
-embed          domain                  domains
+embed          array domain            domains
 
 # DHCPv6 Kerberos, RFC6784
-define6 75     domain                  krb_principal_name
-define6 76     domain                  krb_realm_name
+define6 75     string                  krb_principal_name
+define6 76     string                  krb_realm_name
 define6 78     embed                   krb_kdc
 embed          uint16                  priority
 embed          uint16                  weight
 embed          byte                    transport_type
 embed          uint16                  port
 embed          ip6address              address
-embed          domain                  realm_name
+embed          string                  realm_name
 
 # DHCPv6 Client Link-Layer Address, RFC6939
 # Section 7 states that clients MUST ignore the option 79
index 6e662019d11e16bc24b4f85b8a378a326e5acdff..aac344e5843025490764d5d479d44e9d006ffbba 100644 (file)
@@ -2,7 +2,7 @@
 
 if [ "$reason" = "TEST" ]; then
        set | grep "^\(interface\|pid\|reason\|skip_hooks\)=" | sort
-       set | grep "^if\(carrier\|flags\|mtu\|wireless\)=" | sort
+       set | grep "^if\(carrier\|flags\|mtu\|wireless\|ssid\)=" | sort
        set | grep "^\(new_\|old_\|ra_count=\|ra[0-9]*_\)" | sort
        exit 0
 fi
index 6b22806a72b05e77dd82a3e5f7b0421b483d1dff..e287951c1c26262c787accac648b3d486057d0de 100644 (file)
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd September 26, 2014
+.Dd August 1, 2014
 .Dt DHCPCD-RUN-HOOKS 8
 .Os
 .Sh NAME
@@ -165,6 +165,10 @@ flags.
 .It Ev $ifmtu
 .Ev $interface
 MTU.
+.It Ev $ifssid
+the name of the SSID the
+.Ev interface
+is connected to.
 .It Ev $interface_order
 A list of interfaces, in order of preference.
 .It Ev $if_up
@@ -190,14 +194,6 @@ requirements specified in
 .It Ev $profile
 the name of the profile selected from
 .Xr dhcpcd.conf 5 .
-.It Ev $new_ssid
-the name of the SSID the
-.Ev interface
-is connected to.
-.It Ev $old_ssid
-the name of the SSID the
-.Ev interface
-was connected to.
 .It Ev $new_dhcp6_prefix
 space separated list of delegated prefixes.
 .El
@@ -218,10 +214,9 @@ in a lexical order and then finally
 Please report them to
 .Lk http://roy.marples.name/projects/dhcpcd
 .Sh SECURITY CONSIDERATIONS
-Little validation of DHCP options is done in dhcpcd itself.
-Instead, it is up to the hooks to handle any validation needed.
-To this end, some helper functions are provided, such as valid_domainname as
-used by the
-.Pa 20-resolv.conf
-hook to ensure that the hostname is not set to an invalid value.
-valid_path is also provided, but is currently unused by a stock hook script.
+.Nm dhcpcd
+will validate the content of each option against its encoding.
+For string, ascii, raw or binhex encoding it's up to the user to validate it
+for the intended purpose.
+.Pp
+When used in a shell script, each variable must be quoted correctly.
index 92582f4eab522358d066a241f05f3f73c19094dc..8635f197cbb1d23ea0bc960e378a7e5f6a14883a 100644 (file)
@@ -203,50 +203,6 @@ See
 for details on how these scripts work.
 .Nm
 currently ignores the exit code of the script.
-.Pp
-.Nm
-converts all binary variables passed from the DHCP/RA message by
-encoding them as hex strings of the format XX:XX.
-This be decoded back into the raw binary form using
-.Xr dhcpcd-decode 8
-like so:
-.D1 dhcpcd-decode -x \*q$variable_name\*q
-or
-.D1 printf \*q%s\*q \*q$variable_name\*q | \e
-.D1 sed -e 's/://g' -e 's/\e([0-9A-F]\e{2\e}\e)/\e\e\e\e\e\ex\e1/gI' | \e
-.D1 xargs printf
-.Pp
-.Nm
-sanitises each string variable passed from the DHCP/RA message by encoding non
-printable characters in C style where possible, or escaped octal when not.
-The following characters are also escaped in C style (except for $ in octal):
-.D1 | \*[Am] \&; \*[Lt] \*[Gt] \&( \&) $ ` \e \*q ' \
-\*[Lt]tab\*[Gt] \*[Lt]newline\*[Gt]
-.D1 * \&? \&[ # ~ = %
-.Pp
-It is possible to reverse this encoding by passing the variable to
-.Xr dhcpcd-decode 8 ,
-like so:
-.D1 dhcpcd-decode \*q$variable_name\*q
-or to
-.Xr unvis 1
-like so:
-.D1 printf \*q%s\*q \*q$variable_name\*q | unvis
-.Pp
-To remove the shell escaped character encoding but keep the non printable
-character octal escaped and C style encoding you can do this:
-.D1 dhcpcd-decode -s \*q$variable-name\*q
-or
-.D1 printf \*q%s\*q \*q$variable_name\*q | unvis | vis -c
-.Pp
-If you have neither
-.Xr dhcpcd-decode 8
-or a working
-.Xr unvis 1 ,
-then the shell builtin eval could be used:
-.D1 eval \*q$variable_name\*q
-but that does not work well with any non printable characters and the $
-character.
 .Ss Fine tuning
 You can fine-tune the behaviour of
 .Nm
@@ -728,7 +684,6 @@ Control socket to per interface daemon.
 .Xr if_nametoindex 3 ,
 .Xr dhcpcd.conf 5 ,
 .Xr resolv.conf 5 ,
-.Xr dhcpcd-decode 8 ,
 .Xr dhcpcd-run-hooks 8 ,
 .Xr resolvconf 8
 .Sh STANDARDS
index 2e45726ee6a145e3795f9838484ffde6923418a0..69af3e29ec949159b94d2f560ba4c8b9d5139459 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -491,7 +491,7 @@ dhcpcd_selectprofile(struct interface *ifp, const char *profile)
        if (ifp->ssid_len) {
                ssize_t r;
 
-               r = print_string(pssid, sizeof(pssid), 0,
+               r = print_string(pssid, sizeof(pssid), ESCSTRING,
                    ifp->ssid, ifp->ssid_len);
                if (r == -1) {
                        syslog(LOG_ERR, "%s: %s: %m", ifp->name, __func__);
index df63b4e8abf7bb82257cb6082bd5d87980bf9f4f..3d6af4cc1d72213640fca4c8075de9680f78eb50 100644 (file)
@@ -683,7 +683,7 @@ An IPv4 address, 4 bytes
 .It Ic ip6address
 An IPv6 address, 16 bytes
 .It Ic string Op : Ic length
-A shell escaped string (binary data escaped as octal)
+A NVT ASCII string of printable characters.
 .It Ic byte
 A byte
 .It Ic int16
@@ -698,6 +698,8 @@ An unsigned 32bit integer, 4 bytes
 A fixed value (1) to indicate that the option is present, 0 bytes
 .It Ic domain
 A RFC 3397 encoded string
+.It Ic dname
+A RFC 1035 validated string
 .It Ic binhex Op : Ic length
 Binary data expressed as hexadecimal
 .It Ic embed
index d8bb8beed3a885613d00496cff2629f92d72eea7..74c0916862e35bfa9ca5ba0d1c65c919ed546bc7 100644 (file)
@@ -1548,10 +1548,16 @@ err_sla:
                        t |= SINT32;
                else if (strcasecmp(arg, "flag") == 0)
                        t |= FLAG;
+               else if (strcasecmp(arg, "raw") == 0)
+                       t |= STRING | RAW;
+               else if (strcasecmp(arg, "ascii") == 0)
+                       t |= STRING | ASCII;
                else if (strcasecmp(arg, "domain") == 0)
-                       t |= STRING | RFC3397;
+                       t |= STRING | DOMAIN | RFC3397;
+               else if (strcasecmp(arg, "dname") == 0)
+                       t |= STRING | DOMAIN;
                else if (strcasecmp(arg, "binhex") == 0)
-                       t |= BINHEX;
+                       t |= STRING | BINHEX;
                else if (strcasecmp(arg, "embed") == 0)
                        t |= EMBED;
                else if (strcasecmp(arg, "encap") == 0)
@@ -1573,7 +1579,9 @@ err_sla:
                            "ignoring length for type `%s'", arg);
                        l = 0;
                }
-               if (t & ARRAY && t & (STRING | BINHEX)) {
+               if (t & ARRAY && t & (STRING | BINHEX) &&
+                   !(t & (RFC3397 | DOMAIN)))
+               {
                        syslog(LOG_WARNING, "ignoring array for strings");
                        t &= ~ARRAY;
                }
index 57f9b1d4786d1608367426a10b4e96ae25477c6f..640df971feb3fdd026c557d664759895c137f5db 100644 (file)
--- a/ipv6nd.c
+++ b/ipv6nd.c
@@ -1011,12 +1011,14 @@ ipv6nd_handlera(struct ipv6_ctx *ctx, struct interface *ifp,
                                        decode_rfc3397(tmp, l, op, n);
                                        l -= 1;
                                        n = (size_t)print_string(NULL, 0,
-                                           PS_SHELL, (const uint8_t *)tmp, l);
+                                           STRING | ARRAY | DOMAIN,
+                                           (const uint8_t *)tmp, l);
                                        opt = malloc(n);
-                                       if (opt)
-                                               print_string(opt, n, PS_SHELL,
+                                       if (opt) {
+                                               print_string(opt, n,
+                                                   STRING | ARRAY | DOMAIN,
                                                    (const uint8_t *)tmp, l);
-                                       else
+                                       else
                                                syslog(LOG_ERR, "%s: %m",
                                                    __func__);
                                        free(tmp);
index f5637e44e126deafb58a44a6a5110b9bc1dc3a1f..80f892c3eb64116ac54ccc6191cfe6fd0438a231 100644 (file)
--- a/script.c
+++ b/script.c
@@ -374,25 +374,18 @@ make_env(const struct interface *ifp, const char *reason, char ***argv)
                snprintf(env[elen++], e, "profile=%s", ifp->profile);
        }
        if (ifp->wireless) {
-               const char *pfx;
+               static const char *pfx = "ifssid=";
                size_t pfx_len;
                ssize_t psl;
 
-               if (strcmp(reason, "CARRIER") == 0)
-                       pfx = "new_ssid=";
-               else if (strcmp(reason, "NOCARRIER") == 0)
-                       pfx = "old_ssid=";
-               else
-                       pfx = "if_ssid=";
-
                pfx_len = strlen(pfx);
-               psl = print_string(NULL, 0, PS_SHELL,
+               psl = print_string(NULL, 0, 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,
-                           PS_SHELL,
+                           ESCSTRING,
                            (const uint8_t *)ifp->ssid, ifp->ssid_len);
                        elen++;
                }