ldb:ldb_msg.c - make "ldb_msg_find_attr_as_*" more robust against invalid values
authorMatthias Dieter Wallnöfer <mdw@samba.org>
Wed, 6 Apr 2011 07:57:51 +0000 (09:57 +0200)
committerMatthias Dieter Wallnöfer <mdw@samba.org>
Thu, 7 Apr 2011 14:38:57 +0000 (16:38 +0200)
- Integer handling was modeled after validate code from "schema_syntax.c".
- Double handling was modeled similar, but with a dynamic buffer.
  I don't know if there is a maximum literal length for double values but an
  allocation shouldn't a problem here since doubles are rare.
- String handlind is enhanced with a terminating "0" test for safety.

Reviewed-by: abartlet + metze
Autobuild-User: Matthias Dieter Wallnöfer <mdw@samba.org>
Autobuild-Date: Thu Apr  7 16:38:57 CEST 2011 on sn-devel-104

source4/lib/ldb/common/ldb_msg.c

index 8060476d7d5b632e0d4b6a5517777fa387df21d5..9c5a279b8a7d503474218f217957d1d027b82c3b 100644 (file)
@@ -391,30 +391,63 @@ int ldb_msg_find_attr_as_int(const struct ldb_message *msg,
                             int default_value)
 {
        const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+       char buf[sizeof("-2147483648")];
+       char *end = NULL;
+       int ret;
+
        if (!v || !v->data) {
                return default_value;
        }
-       return strtol((const char *)v->data, NULL, 0);
+
+       ZERO_STRUCT(buf);
+       if (v->length >= sizeof(buf)) {
+               return default_value;
+       }
+
+       memcpy(buf, v->data, v->length);
+       errno = 0;
+       ret = (int) strtoll(buf, &end, 10);
+       if (errno != 0) {
+               return default_value;
+       }
+       if (end && end[0] != '\0') {
+               return default_value;
+       }
+       return ret;
 }
 
-unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg, 
+unsigned int ldb_msg_find_attr_as_uint(const struct ldb_message *msg,
                                       const char *attr_name,
                                       unsigned int default_value)
 {
-       unsigned int ret;
        const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+       char buf[sizeof("-2147483648")];
+       char *end = NULL;
+       unsigned int ret;
+
        if (!v || !v->data) {
                return default_value;
        }
 
-       /* in LDAP there're only int32_t values */
-       errno = 0;
-       ret = strtol((const char *)v->data, NULL, 0);
-       if (errno == 0) {
-               return ret;
+       ZERO_STRUCT(buf);
+       if (v->length >= sizeof(buf)) {
+               return default_value;
        }
 
-       return strtoul((const char *)v->data, NULL, 0);
+       memcpy(buf, v->data, v->length);
+       errno = 0;
+       ret = (unsigned int) strtoll(buf, &end, 10);
+       if (errno != 0) {
+               errno = 0;
+               ret = (unsigned int) strtoull(buf, &end, 10);
+               if (errno != 0) {
+                       return default_value;
+               }
+       }
+       if (end && end[0] != '\0') {
+               return default_value;
+       }
+       return ret;
 }
 
 int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg, 
@@ -422,30 +455,63 @@ int64_t ldb_msg_find_attr_as_int64(const struct ldb_message *msg,
                                   int64_t default_value)
 {
        const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+       char buf[sizeof("-9223372036854775808")];
+       char *end = NULL;
+       int64_t ret;
+
        if (!v || !v->data) {
                return default_value;
        }
-       return strtoll((const char *)v->data, NULL, 0);
+
+       ZERO_STRUCT(buf);
+       if (v->length >= sizeof(buf)) {
+               return default_value;
+       }
+
+       memcpy(buf, v->data, v->length);
+       errno = 0;
+       ret = (int64_t) strtoll(buf, &end, 10);
+       if (errno != 0) {
+               return default_value;
+       }
+       if (end && end[0] != '\0') {
+               return default_value;
+       }
+       return ret;
 }
 
-uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg, 
+uint64_t ldb_msg_find_attr_as_uint64(const struct ldb_message *msg,
                                     const char *attr_name,
                                     uint64_t default_value)
 {
-       uint64_t ret;
        const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+       char buf[sizeof("-9223372036854775808")];
+       char *end = NULL;
+       uint64_t ret;
+
        if (!v || !v->data) {
                return default_value;
        }
 
-       /* in LDAP there're only int64_t values */
-       errno = 0;
-       ret = strtoll((const char *)v->data, NULL, 0);
-       if (errno == 0) {
-               return ret;
+       ZERO_STRUCT(buf);
+       if (v->length >= sizeof(buf)) {
+               return default_value;
        }
 
-       return strtoull((const char *)v->data, NULL, 0);
+       memcpy(buf, v->data, v->length);
+       errno = 0;
+       ret = (uint64_t) strtoll(buf, &end, 10);
+       if (errno != 0) {
+               errno = 0;
+               ret = (uint64_t) strtoull(buf, &end, 10);
+               if (errno != 0) {
+                       return default_value;
+               }
+       }
+       if (end && end[0] != '\0') {
+               return default_value;
+       }
+       return ret;
 }
 
 double ldb_msg_find_attr_as_double(const struct ldb_message *msg, 
@@ -453,10 +519,28 @@ double ldb_msg_find_attr_as_double(const struct ldb_message *msg,
                                   double default_value)
 {
        const struct ldb_val *v = ldb_msg_find_ldb_val(msg, attr_name);
+       char *buf;
+       char *end = NULL;
+       double ret;
+
        if (!v || !v->data) {
                return default_value;
        }
-       return strtod((const char *)v->data, NULL);
+       buf = talloc_strndup(msg, (const char *)v->data, v->length);
+       if (buf == NULL) {
+               return default_value;
+       }
+
+       errno = 0;
+       ret = strtod(buf, &end);
+       talloc_free(buf);
+       if (errno != 0) {
+               return default_value;
+       }
+       if (end && end[0] != '\0') {
+               return default_value;
+       }
+       return ret;
 }
 
 int ldb_msg_find_attr_as_bool(const struct ldb_message *msg, 
@@ -484,6 +568,9 @@ const char *ldb_msg_find_attr_as_string(const struct ldb_message *msg,
        if (!v || !v->data) {
                return default_value;
        }
+       if (v->data[v->length] != '\0') {
+               return default_value;
+       }
        return (const char *)v->data;
 }