Properly check strtol() results when paring values as integers
[project/firewall3.git] / options.c
index 43025a8..7e62ca6 100644 (file)
--- a/options.c
+++ b/options.c
@@ -142,9 +142,10 @@ fw3_parse_bool(void *ptr, const char *val, bool is_list)
 bool
 fw3_parse_int(void *ptr, const char *val, bool is_list)
 {
-       int n = strtol(val, NULL, 0);
+       char *e;
+       int n = strtol(val, &e, 0);
 
-       if (errno == ERANGE || errno == EINVAL)
+       if (e == val || *e)
                return false;
 
        *((int *)ptr) = n;
@@ -518,6 +519,7 @@ fw3_parse_protocol(void *ptr, const char *val, bool is_list)
 {
        struct fw3_protocol proto = { };
        struct protoent *ent;
+       char *e;
 
        if (*val == '!')
        {
@@ -556,9 +558,9 @@ fw3_parse_protocol(void *ptr, const char *val, bool is_list)
                return true;
        }
 
-       proto.protocol = strtoul(val, NULL, 10);
+       proto.protocol = strtoul(val, &e, 10);
 
-       if (errno == ERANGE || errno == EINVAL)
+       if ((e == val) || (*e != 0))
                return false;
 
        put_value(ptr, &proto, sizeof(proto), is_list);
@@ -577,20 +579,22 @@ fw3_parse_ipset_datatype(void *ptr, const char *val, bool is_list)
 {
        struct fw3_ipset_datatype type = { };
 
+       type.dir = "src";
+
        if (!strncmp(val, "dest_", 5))
        {
                val += 5;
-               type.dest = true;
+               type.dir = "dst";
        }
        else if (!strncmp(val, "dst_", 4))
        {
                val += 4;
-               type.dest = true;
+               type.dir = "dst";
        }
        else if (!strncmp(val, "src_", 4))
        {
                val += 4;
-               type.dest = false;
+               type.dir = "src";
        }
 
        if (parse_enum(&type.type, val, &fw3_ipset_type_names[FW3_IPSET_TYPE_IP],
@@ -809,8 +813,48 @@ fw3_parse_mark(void *ptr, const char *val, bool is_list)
        return true;
 }
 
+bool
+fw3_parse_setmatch(void *ptr, const char *val, bool is_list)
+{
+       struct fw3_setmatch *m = ptr;
+       char *p, *s;
+       int i;
+
+       if (*val == '!')
+       {
+               m->invert = true;
+               while (isspace(*++val));
+       }
+
+       if (!(s = strdup(val)))
+               return false;
 
-void
+       if (!(p = strtok(s, " \t")))
+       {
+               free(s);
+               return false;
+       }
+
+       strncpy(m->name, p, sizeof(m->name));
+
+       for (i = 0, p = strtok(NULL, " \t,");
+            i < 3 && p != NULL;
+            i++, p = strtok(NULL, " \t,"))
+       {
+               if (!strncmp(p, "dest", 4) || !strncmp(p, "dst", 3))
+                       m->dir[i] = "dst";
+               else if (!strncmp(p, "src", 3))
+                       m->dir[i] = "src";
+       }
+
+       free(s);
+
+       m->set = true;
+       return true;
+}
+
+
+bool
 fw3_parse_options(void *s, const struct fw3_option *opts,
                   struct uci_section *section)
 {
@@ -820,6 +864,7 @@ fw3_parse_options(void *s, const struct fw3_option *opts,
        struct uci_option *o;
        const struct fw3_option *opt;
        struct list_head *dest;
+       bool valid = true;
 
        uci_foreach_element(&section->options, e)
        {
@@ -839,6 +884,7 @@ fw3_parse_options(void *s, const struct fw3_option *opts,
                                if (!opt->elem_size)
                                {
                                        warn_elem(e, "must not be a list");
+                                       valid = false;
                                }
                                else
                                {
@@ -852,6 +898,7 @@ fw3_parse_options(void *s, const struct fw3_option *opts,
                                                if (!opt->parse(dest, l->name, true))
                                                {
                                                        warn_elem(e, "has invalid value '%s'", l->name);
+                                                       valid = false;
                                                        continue;
                                                }
                                        }
@@ -867,7 +914,10 @@ fw3_parse_options(void *s, const struct fw3_option *opts,
                                if (!opt->elem_size)
                                {
                                        if (!opt->parse((char *)s + opt->offset, o->v.string, false))
+                                       {
                                                warn_elem(e, "has invalid value '%s'", o->v.string);
+                                               valid = false;
+                                       }
                                }
                                else
                                {
@@ -878,6 +928,7 @@ fw3_parse_options(void *s, const struct fw3_option *opts,
                                                if (!opt->parse(dest, p, true))
                                                {
                                                        warn_elem(e, "has invalid value '%s'", p);
+                                                       valid = false;
                                                        continue;
                                                }
                                        }
@@ -891,6 +942,8 @@ fw3_parse_options(void *s, const struct fw3_option *opts,
                if (!known)
                        warn_elem(e, "is unknown");
        }
+
+       return valid;
 }