Remove vis/unvis encoding and dhcpcd-decode, this was a mistake.
[dhcpcd-ui] / src / libdhcpcd / dhcpcd.c
index 508137ce51b6c904505082b6a251590a5dbe92cd..9861dd172bc33dbaa1b9ca68a82cb2860d04809e 100644 (file)
@@ -34,6 +34,7 @@
 #include <arpa/inet.h>
 
 #include <assert.h>
+#include <ctype.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <libintl.h>
 #define _(a) (a)
 #endif
 
+#ifdef HAVE_VIS_H
+#include <vis.h>
+#endif
+
 #ifndef SUN_LEN
 #define SUN_LEN(su) \
        (sizeof(*(su)) - sizeof((su)->sun_path) + strlen((su)->sun_path))
 #endif
 
+#ifndef iswhite
+#define iswhite(c)     (c == ' ' || c == '\t' || c == '\n')
+#endif
+
 static const char * const dhcpcd_types[] =
     { "link", "ipv4", "ra", "dhcp6", NULL };
 
@@ -72,6 +81,9 @@ dhcpcd_command_fd(DHCPCD_CONNECTION *con,
        char buf[1024], *p;
        char *nbuf;
 
+       assert(con);
+       assert(cmd);
+
        /* Each command is \n terminated.
         * Each argument is NULL seperated.
         * We may need to send a space one day, so the API
@@ -128,6 +140,11 @@ ssize_t
 dhcpcd_command(DHCPCD_CONNECTION *con, const char *cmd, char **buffer)
 {
 
+       assert(con);
+       if (!con->privileged) {
+               errno = EACCES;
+               return -1;
+       }
        return dhcpcd_command_fd(con, con->command_fd, true, cmd, buffer);
 }
 
@@ -142,6 +159,7 @@ bool
 dhcpcd_realloc(DHCPCD_CONNECTION *con, size_t len)
 {
 
+       assert(con);
        if (con->buflen < len) {
                char *nbuf;
 
@@ -160,6 +178,9 @@ dhcpcd_command_arg(DHCPCD_CONNECTION *con, const char *cmd, const char *arg,
 {
        size_t cmdlen, len;
 
+       assert(con);
+       assert(cmd);
+
        cmdlen = strlen(cmd);
        if (arg)
                len = cmdlen + strlen(arg) + 2;
@@ -184,6 +205,7 @@ dhcpcd_connect(const char *path, int opts)
        socklen_t len;
        struct sockaddr_un sun;
 
+       assert(path);
        fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | opts, 0);
        if (fd == -1)
                return -1;
@@ -209,8 +231,13 @@ get_value(const char *data, size_t len, const char *var)
        vlen = strlen(var);
        p = NULL;
        while (data + vlen + 1 < end) {
-               if (strncmp(data, var, vlen) == 0) {
-                       p = data + vlen;
+               /* Skip past NUL padding */
+               if (*data == '\0') {
+                       data++;
+                       continue;
+               }
+               if (strncmp(data, var, vlen) == 0 && data[vlen] == '=') {
+                       p = data + vlen + 1;
                        break;
                }
                data += strlen(data) + 1;
@@ -225,15 +252,179 @@ dhcpcd_get_value(const DHCPCD_IF *i, const char *var)
 {
 
        assert(i);
+       assert(var);
        return get_value(i->data, i->data_len, var);
 }
 
+ssize_t
+dhcpcd_encode_string_escape(char *dst, size_t len, const char *src, size_t slen)
+{
+       const char *end;
+       size_t bytes;
+       char c;
+
+       end = src + slen;
+       bytes = 0;
+       while (src < end) {
+               c = *src++;
+               if ((c == '\\' || !isascii(c) || !isprint(c))) {
+                       if (c == '\\') {
+                               if (dst) {
+                                       if (len  == 0 || len == 1) {
+                                               errno = ENOSPC;
+                                               return -1;
+                                       }
+                                       *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++;
+               }
+       }
+
+       if (dst) {
+               if (len == 0) {
+                       errno = ENOSPC;
+                       return -1;
+               }
+               *dst = '\0';
+       }
+       bytes++;
+
+       return (ssize_t)bytes;
+}
+
+ssize_t
+dhcpcd_decode_string_escape(char *dst, size_t dlen, const char *src)
+{
+       char c, esc;
+       int oct;
+       ssize_t bytes;
+
+       bytes = 0;
+       for (;;) {
+               c = *src++;
+               if (c == '\0')
+                       break;
+               if (dst && --dlen == 0) {
+                       errno = ENOSPC;
+                       return 0;
+               }
+               switch (c) {
+               case '\\':
+                       if (*src == '\0') {
+                               errno = EINVAL;
+                               return -1;
+                       }
+                       esc = *src++;
+                       switch (esc) {
+                       case '\\':
+                       case '0':
+                       case '1':
+                       case '3':
+                       case '4':
+                       case '5':
+                       case '6':
+                       case '7':
+                               oct = esc - '0';
+                               if (*src >= '0' && *src <='7')
+                                       oct = oct * 8 + (*src++ - '0');
+                               else {
+                                       errno = EINVAL;
+                                       return -1;
+                               }
+                               if (*src >= '0' && *src <='7')
+                                       oct = oct * 8 + (*src++ - '0');
+                               else {
+                                       errno = EINVAL;
+                                       return -1;
+                               }
+                               if (dst)
+                                       *dst++ = (char)oct;
+                       default:
+                               errno = EINVAL;
+                               return -1;
+                       }
+                       break;
+               default:
+                       if (dst)
+                               *dst++ = c;
+               }
+               bytes++;
+       }
+       return bytes;
+}
+
+ssize_t
+dhcpcd_decode_hex(char *dst, size_t dlen, const char *src)
+{
+       size_t bytes, i;
+       char c;
+       int val, n;
+
+       bytes = 0;
+       while (*src) {
+               if (dlen == 0 || dlen == 1) {
+                       errno = ENOSPC;
+                       return -1;
+               }
+               val = 0;
+               for (i = 0; i < 2; i++) {
+                       c = *src++;
+                       if (c >= '0' && c <= '9')
+                               n = c - '0';
+                       else if (c >= 'a' && c <= 'f')
+                               n = 10 + c - 'a';
+                       else if (c >= 'A' && c <= 'F')
+                               n = 10 + c - 'A';
+                       else {
+                               errno = EINVAL;
+                               return -1;
+                       }
+                       val = val * 16 + n;
+               }
+               *dst++ = (char)val;
+               bytes += 2;
+               dlen -= 2;
+               if (*src == ':')
+                       src++;
+       }
+       return (ssize_t)bytes;
+}
+
 const char *
 dhcpcd_get_prefix_value(const DHCPCD_IF *i, const char *prefix, const char *var)
 {
        char pvar[128], *p;
        size_t plen, l;
 
+       assert(i);
+       assert(prefix);
+       assert(var);
+
        p = pvar;
        plen = sizeof(pvar);
        l = strlcpy(p, prefix, plen);
@@ -319,6 +510,9 @@ dhcpcd_get_if(DHCPCD_CONNECTION *con, const char *ifname, const char *type)
        DHCPCD_IF *i;
 
        assert(con);
+       assert(ifname);
+       assert(type);
+
        for (i = con->interfaces; i; i = i->next)
                if (strcmp(i->ifname, ifname) == 0 &&
                    strcmp(i->type, type) == 0)
@@ -335,17 +529,17 @@ dhcpcd_new_if(DHCPCD_CONNECTION *con, char *data, size_t len)
        int ti;
        bool addedi;
 
-       ifname = get_value(data, len, "interface=");
+       ifname = get_value(data, len, "interface");
        if (ifname == NULL || *ifname == '\0') {
                errno = ESRCH;
                return NULL;
        }
-       reason = get_value(data, len, "reason=");
+       reason = get_value(data, len, "reason");
        if (reason == NULL || *reason == '\0') {
                errno = ESRCH;
                return NULL;
        }
-       ifclass = get_value(data, len, "ifclass=");
+       ifclass = get_value(data, len, "ifclass");
        /* Skip pseudo interfaces */
        if (ifclass && *ifclass != '\0') {
                errno = ENOTSUP;
@@ -355,7 +549,7 @@ dhcpcd_new_if(DHCPCD_CONNECTION *con, char *data, size_t len)
                errno = ENOTSUP;
                return NULL;
        }
-       order = get_value(data, len, "interface_order=");
+       order = get_value(data, len, "interface_order");
        if (order == NULL || *order == '\0') {
                errno = ESRCH;
                return NULL;
@@ -443,7 +637,7 @@ dhcpcd_new_if(DHCPCD_CONNECTION *con, char *data, size_t len)
        i->ifname = ifname;
        i->type = type;
        i->reason = reason;
-       flags = dhcpcd_get_value(i, "ifflags=");
+       flags = dhcpcd_get_value(i, "ifflags");
        if (flags)
                i->flags = (unsigned int)strtoul(flags, NULL, 0);
        else
@@ -451,9 +645,9 @@ dhcpcd_new_if(DHCPCD_CONNECTION *con, char *data, size_t len)
        if (strcmp(reason, "CARRIER") == 0)
                i->up = true;
        else
-               i->up = strtobool(dhcpcd_get_value(i, "if_up="));
-       i->wireless = strtobool(dhcpcd_get_value(i, "ifwireless="));
-       i->ssid = dhcpcd_get_value(i, i->up ? "new_ssid=" : "old_ssid=");
+               i->up = strtobool(dhcpcd_get_value(i, "if_up"));
+       i->wireless = strtobool(dhcpcd_get_value(i, "ifwireless"));
+       i->ssid = dhcpcd_get_value(i, "ifssid");
 
        /* Sort! */
        n = nl = NULL;
@@ -588,7 +782,7 @@ dhcpcd_get_progname(const DHCPCD_CONNECTION *con)
        return con->progname;
 }
 
-#ifndef __GLIBC__
+#ifndef HAVE_STRVERSCMP
 /* Good enough for our needs */
 static int
 strverscmp(const char *s1, const char *s2)
@@ -821,7 +1015,7 @@ dhcpcd_if_message(DHCPCD_IF *i, bool *new_msg)
        assert(i);
        /* Don't report non SLAAC configurations */
        if (strcmp(i->type, "ra") == 0 && i->up &&
-           dhcpcd_get_value(i, "ra1_prefix=") == NULL)
+           dhcpcd_get_value(i, "ra1_prefix") == NULL)
                return NULL;
 
        showssid = false;
@@ -861,12 +1055,12 @@ dhcpcd_if_message(DHCPCD_IF *i, bool *new_msg)
        }
 
        pfx = i->up ? "new_" : "old_";
-       if ((ip = dhcpcd_get_prefix_value(i, pfx, "ip_address=")))
-               iplen = dhcpcd_get_prefix_value(i, pfx, "subnet_cidr=");
-       else if ((ip = dhcpcd_get_value(i, "ra1_prefix=")))
+       if ((ip = dhcpcd_get_prefix_value(i, pfx, "ip_address")))
+               iplen = dhcpcd_get_prefix_value(i, pfx, "subnet_cidr");
+       else if ((ip = dhcpcd_get_value(i, "ra1_prefix")))
                iplen = NULL;
        else if ((ip = dhcpcd_get_prefix_value(i, pfx,
-           "dhcp6_ia_na1_ia_addr1=")))
+           "dhcp6_ia_na1_ia_addr1")))
                iplen = "128";
        else {
                ip = NULL;