Add dhcpcd_encode which encodes raw data back into a safe string.
authorRoy Marples <roy@marples.name>
Tue, 30 Sep 2014 07:27:37 +0000 (07:27 +0000)
committerRoy Marples <roy@marples.name>
Tue, 30 Sep 2014 07:27:37 +0000 (07:27 +0000)
This is used to convert wpa_supplicant safe strings into dhcpcd ones so the
display is consistent.
If a SSID has unsafe characters in and saving to wpa_supplicant.conf then
convert the SSID to a hex string.
A vis(3) shim has been added if libc does not provide one.

configure
src/libdhcpcd/Makefile
src/libdhcpcd/dhcpcd.c
src/libdhcpcd/dhcpcd.h
src/libdhcpcd/unvis.c
src/libdhcpcd/vis.c [new file with mode: 0644]
src/libdhcpcd/wpa.c

index 5bc9220216089777520af8a4a39beafe79016a95..73a761f4b4ba582c629ea27443aad3b404368ad2 100755 (executable)
--- a/configure
+++ b/configure
@@ -303,6 +303,32 @@ if [ "$STRLCPY" = no ]; then
            >>$CONFIG_H
 fi
 
+if [ -z "$VIS" ]; then
+       printf "Testing for vis ... "
+       cat <<EOF >_vis.c
+#include <vis.h>
+
+int main(void) {
+       char s[10];
+       xxvis(s, 0, 0, 0);
+       return 0;
+}
+EOF
+       if $XCC _vis.c -o _vis 2>&3; then
+               VIS=yes
+       else
+               VIS=no
+       fi
+       echo "$VIS"
+       rm -f _vis.c _vis
+fi
+if [ "$VIS" = no ]; then
+       echo "VIS_SRC=          vis.c" >>$CONFIG_MK
+       echo "#define vis       dhcpcd_vis" >>$CONFIG_H
+else
+       echo "#define HAVE_VIS_H" >>$CONFIG_H
+fi
+
 if [ -z "$STRNUNVIS" ]; then
        printf "Testing for strnunvis ... "
        cat <<EOF >_strnunvis.c
@@ -332,9 +358,9 @@ EOF
 fi
 if [ "$STRNUNVIS" = no ]; then
        echo "UNVIS_SRC=        unvis.c" >>$CONFIG_MK
-       echo "#define strnunvis dhcpcd_strnunvis" >>$CONFIG_H
+       echo "#define strnunvis dhcpcd_strnunvis" >>$CONFIG_H
 else
-       echo "#define HAVE_VIS_H" >>$CONFIG_H
+       echo "#define HAVE_STRNUNVIS" >>$CONFIG_H
 fi
 
 if [ -z "$STRVERSCMP" ]; then
index f0c0857ec80beaf75022b9653fc505191f72723d..eb910d222728444f7a204fdb2c1af46811b593b7 100644 (file)
@@ -1,6 +1,6 @@
 LIB=           dhcpcd
 SHLIB_MAJOR=   1
-SRCS=          dhcpcd.c config.c wpa.c ${UNVIS_SRC}
+SRCS=          dhcpcd.c config.c wpa.c ${VIS_SRC} ${UNVIS_SRC}
 INCS=          dhcpcd.h
 
 TOPDIR=                ../..
index a2295dc931ccbed704dec5a9063ea8b2c70080d3..153296c2cda813cc867e429b536665860ba37dd3 100644 (file)
@@ -298,10 +298,34 @@ dhcpcd_decode_hex(char *dst, size_t dlen, const char *src)
 }
 
 ssize_t
+dhcpcd_encode(char *dst, size_t dlen, const char *src, size_t slen)
+{
+       char *d, c, v[5], *ve, *vp;
+       const char *send;
+
+       d = dst;
+       send = src + slen;
+       while (src < send) {
+               c = *src++;
+               ve = vis(v, c, VIS_OCTAL | VIS_CSTYLE, src != send ? *src : 0);
+               if (dlen < (size_t)(ve - v) + 1) {
+                       errno = ENOSPC;
+                       return -1;
+               }
+               dlen -= (size_t)(ve - v);
+               vp = v;
+               while (vp != ve)
+                       *d++ = *vp++;
+       }
+       *d = '\0';
+
+       return d - dst;
+}
+
+ssize_t
 dhcpcd_decode_shell(char *dst, size_t dlen, const char *src)
 {
-       char *tmp, *p, *e, *d;
-       int c;
+       char *tmp;
        ssize_t l;
 
        assert(dst);
@@ -310,41 +334,11 @@ dhcpcd_decode_shell(char *dst, size_t dlen, const char *src)
        tmp = malloc(dlen);
        if (tmp == NULL)
                return -1;
-       if ((l = dhcpcd_decode(tmp, dlen, src)) == -1) {
-               free(tmp);
-               return -1;
-       }
-
-       p = tmp;
-       e = tmp + l;
-       d = dst;
-       while (p < e) {
-               c = *p++;
-
-               if (isascii(c) && (isgraph(c) || iswhite(c))) {
-                       if (dlen < 2) {
-                               errno = ENOSPC;
-                               return -1;
-                       }
-                       *d++ = (char)c;
-                       dlen--;
-                       continue;
-               }
+       if ((l = dhcpcd_decode(tmp, dlen, src)) != -1)
+               l = dhcpcd_encode(dst, dlen, tmp, (size_t)l);
 
-               if (dlen < 5) {
-                       errno = ENOSPC;
-                       return -1;
-               }
-               *d++ = '\\';
-               *d++ = (((unsigned char)c >> 6) & 03) + '0';
-               *d++ = (((unsigned char)c >> 3) & 07) + '0';
-               *d++ = ( (unsigned char)c       & 07) + '0';
-               dlen -= 4;
-       }
-       *d = '\0';
        free(tmp);
-
-       return d - dst;
+       return l;
 }
 
 const char *
index 604ac6a6fdf781c4884d0cc0aa19fc59cace4337..fd738fe593bd9305b1d195df86dd053486ed1d45 100644 (file)
@@ -200,13 +200,22 @@ DHCPCD_CONNECTION * dhcpcd_if_connection(DHCPCD_IF *);
 const char *dhcpcd_get_value(const DHCPCD_IF *, const char *);
 const char *dhcpcd_get_prefix_value(const DHCPCD_IF *, const char *,
     const char *);
+
 #ifdef IN_LIBDHCPCD
-/* This function only exists if libc does not provide a working version */
+#ifndef VIS_OCTAL
+#define VIS_OCTAL      0x0001
+#define VIS_CSTYLE     0x0002
+#endif
+/* These functions only exists if libc does not provide a working one */
+char *dhcpcd_svis(char *dst, int c, int flags, int nextc, const char *extra);
+char *dhcpcd_vis(char *dst, int c, int flags, int nextc);
 int dhcpcd_strnunvis(char *dst, size_t dlen, const char *src);
 #endif
+ssize_t dhcpcd_encode(char *dst, size_t dlen, const char *src, size_t slen);
 ssize_t dhcpcd_decode(char *dst, size_t dlen, const char *src);
 ssize_t dhcpcd_decode_shell(char *dst, size_t dlen, const char *src);
 ssize_t dhcpcd_decode_hex(char *dst, size_t dlen, const char *src);
+
 char * dhcpcd_if_message(DHCPCD_IF *i, bool *new_msg);
 
 ssize_t dhcpcd_command(DHCPCD_CONNECTION *, const char *, char **);
index e143e36b2531fcef9a5842ab747604011834cfac..4849b9de9eb887d9471ce64c89fe579ab0ddecc1 100644 (file)
  * SUCH DAMAGE.
  */
 
+/*
+ * HEAVILY trimmed down for use only in dhcpcd.
+ * Please use the source in NetBSD for a fuller working copy.
+ */
+
 #include <sys/types.h>
 
 #include <assert.h>
@@ -77,7 +82,7 @@
  * unvis - decode characters previously encoded by vis
  */
 static int
-unvis(char *cp, char c, int *astate, int flag)
+unvis(char *cp, int c, int *astate, int flag)
 {
        unsigned char uc = (unsigned char)c;
        unsigned char st;
@@ -114,18 +119,18 @@ unvis(char *cp, char c, int *astate, int flag)
                        *astate = SS(0, S_START);
                        return UNVIS_NOCHAR;
                }
-               *cp = c;
+               *cp = (char)c;
                return UNVIS_VALID;
 
        case S_START:
                switch(c) {
                case '\\':
-                       *cp = c;
+                       *cp = (char)c;
                        *astate = SS(0, S_GROUND);
                        return UNVIS_VALID;
                case '0': case '1': case '2': case '3':
                case '4': case '5': case '6': case '7':
-                       *cp = (c - '0');
+                       *cp = (char)(c - '0');
                        *astate = SS(0, S_OCTAL2);
                        return UNVIS_NOCHAR;
                case 'M':
@@ -188,7 +193,7 @@ unvis(char *cp, char c, int *astate, int flag)
                        return UNVIS_NOCHAR;
                default:
                        if (isgraph(c)) {
-                               *cp = c;
+                               *cp = (char)c;
                                *astate = SS(0, S_GROUND);
                                return UNVIS_VALID;
                        }
@@ -287,7 +292,7 @@ unvis(char *cp, char c, int *astate, int flag)
 int
 dhcpcd_strnunvis(char *dst, size_t dlen, const char *src)
 {
-       char c;
+       int c;
        char t = '\0', *start = dst;
        int state = 0;
 
diff --git a/src/libdhcpcd/vis.c b/src/libdhcpcd/vis.c
new file mode 100644 (file)
index 0000000..01206a2
--- /dev/null
@@ -0,0 +1,168 @@
+/*     $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>
+
+#define IN_LIBDHCPCD
+#include "dhcpcd.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 *
+dhcpcd_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 *
+dhcpcd_vis(char *dst, int c, int flag, int nextc)
+{
+
+       return dhcpcd_svis(dst, c, flag, nextc, "");
+}
index 4861c5c8fbc893d8bfe00eb3753ac92dddc0a3fc..0b03b2cafa0c61456ed63be4bd799bfaa177335e 100644 (file)
@@ -195,9 +195,10 @@ static DHCPCD_WI_SCAN *
 dhcpcd_wpa_scans_read(DHCPCD_WPA *wpa)
 {
        size_t i;
-       ssize_t bytes;
+       ssize_t bytes, dl;
        DHCPCD_WI_SCAN *wis, *w, *l;
        char *s, *p, buf[32];
+       char wssid[sizeof(w->ssid)], tssid[sizeof(w->ssid)];
 
        if (!dhcpcd_realloc(wpa->con, 2048))
                return NULL;
@@ -235,8 +236,14 @@ dhcpcd_wpa_scans_read(DHCPCD_WPA *wpa)
                                dhcpcd_strtoi(&w->level.value, s + 6);
                        else if (strncmp(s, "flags=", 6) == 0)
                                strlcpy(w->flags, s + 6, sizeof(w->flags));
-                       else if (strncmp(s, "ssid=", 5) == 0)
-                               strlcpy(w->ssid, s + 5, sizeof(w->ssid));
+                       else if (strncmp(s, "ssid=", 5) == 0) {
+                               /* Decode it from \xNN to \NNN
+                                * so we're consistent */
+                               strlcpy(wssid, s + 5, sizeof(wssid));
+                               dl = dhcpcd_decode(tssid, sizeof(tssid), wssid);
+                               dhcpcd_encode(w->ssid, sizeof(w->ssid),
+                                   tssid, (size_t)dl);
+                       }
                }
 
                w->strength.value = w->level.value;
@@ -409,8 +416,9 @@ dhcpcd_wpa_network_set(DHCPCD_WPA *wpa, int id,
 static int
 dhcpcd_wpa_network_find(DHCPCD_WPA *wpa, const char *fssid)
 {
-       ssize_t bytes;
+       ssize_t bytes, dl, tl;
        char *s, *t, *ssid, *bssid, *flags;
+       char dssid[IF_SSIDSIZE], tssid[IF_SSIDSIZE];
        long l;
 
        dhcpcd_realloc(wpa->con, 2048);
@@ -419,6 +427,9 @@ dhcpcd_wpa_network_find(DHCPCD_WPA *wpa, const char *fssid)
        if (bytes == 0 || bytes == -1)
                return -1;
 
+       if ((dl = dhcpcd_decode(dssid, sizeof(dssid), fssid)) == -1)
+               return -1;
+
        s = strchr(wpa->con->buf, '\n');
        if (s == NULL)
                return -1;
@@ -442,7 +453,10 @@ dhcpcd_wpa_network_find(DHCPCD_WPA *wpa, const char *fssid)
                        errno = ERANGE;
                        break;
                }
-               if (strcmp(ssid, fssid) == 0)
+
+               if ((tl = dhcpcd_decode(tssid, sizeof(tssid), ssid)) == -1)
+                       return -1;
+               if (tl == dl && memcmp(tssid, dssid, (size_t)tl) == 0)
                        return (int)l;
        }
        errno = ENOENT;
@@ -468,14 +482,44 @@ dhcpcd_wpa_network_new(DHCPCD_WPA *wpa)
        return (int)l;
 }
 
+static const char hexstr[] = "0123456789ABCDEF";
 int
 dhcpcd_wpa_network_find_new(DHCPCD_WPA *wpa, const char *ssid)
 {
        int id;
+       char dssid[IF_SSIDSIZE], essid[IF_SSIDSIZE], *ep;
+       ssize_t dl;
 
        id = dhcpcd_wpa_network_find(wpa, ssid);
-       if (id == -1)
-               id = dhcpcd_wpa_network_new(wpa);
+       if (id != -1)
+               return id;
+
+       dl = dhcpcd_decode(dssid, sizeof(dssid), ssid);
+       if (dl == -1)
+               return -1;
+
+       ep = essid;
+       if ((size_t)dl != strlen(ssid) || memcmp(dssid, ssid, (size_t)dl)) {
+               /* Non standard characters found! Encode as hex string */
+               char *dp;
+               unsigned char c;
+
+               dp = dssid;
+               for (; dl; dl--) {
+                       c = (unsigned char)*dp++;
+                       *ep++ = hexstr[c >> 4];
+                       *ep++ = hexstr[c & 0xf];
+               }
+       } else {
+               *ep++ = '\"';
+               ep = stpcpy(ep, ssid);
+               *ep++ = '\"';
+       }
+       *ep = '\0';
+
+       id = dhcpcd_wpa_network_new(wpa);
+       if (id != -1)
+               dhcpcd_wpa_network_set(wpa, id, "ssid", essid);
        return id;
 }