[daemon-fix] fixed querying about name information
[platform/upstream/dbus.git] / dbus / dbus-marshal-validate.c
index e63a463..9187a3e 100644 (file)
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
 
+#include <config.h>
 #include "dbus-internals.h"
 #include "dbus-marshal-validate.h"
 #include "dbus-marshal-recursive.h"
@@ -100,6 +101,7 @@ _dbus_validate_signature_with_reason (const DBusString *type_str,
         case DBUS_TYPE_UINT16:
         case DBUS_TYPE_INT32:
         case DBUS_TYPE_UINT32:
+        case DBUS_TYPE_UNIX_FD:
         case DBUS_TYPE_INT64:
         case DBUS_TYPE_UINT64:
         case DBUS_TYPE_DOUBLE:
@@ -246,13 +248,15 @@ _dbus_validate_signature_with_reason (const DBusString *type_str,
            }
         }
 
-      if (last == DBUS_DICT_ENTRY_BEGIN_CHAR &&
-          !dbus_type_is_basic (*p))
+      if (last == DBUS_DICT_ENTRY_BEGIN_CHAR)
         {
-          result = DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE;
-          goto out;
+          if (!(dbus_type_is_valid (*p) && dbus_type_is_basic (*p)))
+            {
+              result = DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE;
+              goto out;
+            }
         }
-        
+
       last = *p;
       ++p;
     }
@@ -287,16 +291,30 @@ out:
   return result;
 }
 
+/* note: this function is also used to validate the header's values,
+ * since the header is a valid body with a particular signature.
+ */
 static DBusValidity
 validate_body_helper (DBusTypeReader       *reader,
                       int                   byte_order,
                       dbus_bool_t           walk_reader_to_end,
+                      int                   total_depth,
                       const unsigned char  *p,
                       const unsigned char  *end,
                       const unsigned char **new_p)
 {
   int current_type;
 
+  /* The spec allows arrays and structs to each nest 32, for total
+   * nesting of 2*32. We want to impose the same limit on "dynamic"
+   * value nesting (not visible in the signature) which is introduced
+   * by DBUS_TYPE_VARIANT.
+   */
+  if (total_depth > (DBUS_MAXIMUM_TYPE_RECURSION_DEPTH * 2))
+    {
+      return DBUS_INVALID_NESTED_TOO_DEEPLY;
+    }
+
   while ((current_type = _dbus_type_reader_get_current_type (reader)) != DBUS_TYPE_INVALID)
     {
       const unsigned char *a;
@@ -317,12 +335,13 @@ validate_body_helper (DBusTypeReader       *reader,
         case DBUS_TYPE_BYTE:
           ++p;
           break;
-          
+
         case DBUS_TYPE_BOOLEAN:
         case DBUS_TYPE_INT16:
         case DBUS_TYPE_UINT16:
         case DBUS_TYPE_INT32:
         case DBUS_TYPE_UINT32:
+        case DBUS_TYPE_UNIX_FD:
         case DBUS_TYPE_INT64:
         case DBUS_TYPE_UINT64:
         case DBUS_TYPE_DOUBLE:
@@ -369,12 +388,30 @@ validate_body_helper (DBusTypeReader       *reader,
 
             /* p may now be == end */
             _dbus_assert (p <= end);
-            
+
             if (current_type == DBUS_TYPE_ARRAY)
               {
                 int array_elem_type = _dbus_type_reader_get_element_type (reader);
+
+                if (!dbus_type_is_valid (array_elem_type))
+                  {
+                    return DBUS_INVALID_UNKNOWN_TYPECODE;
+                  }
+
                 alignment = _dbus_type_get_alignment (array_elem_type);
-                p = _DBUS_ALIGN_ADDRESS (p, alignment);
+
+                a = _DBUS_ALIGN_ADDRESS (p, alignment);
+
+                /* a may now be == end */
+                if (a > end)
+                  return DBUS_INVALID_NOT_ENOUGH_DATA;
+
+                while (p != a)
+                  {
+                    if (*p != '\0')
+                      return DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
+                    ++p;
+                  }
               }
 
             if (claimed_len > (unsigned long) (end - p))
@@ -405,6 +442,7 @@ validate_body_helper (DBusTypeReader       *reader,
                 DBusTypeReader sub;
                 DBusValidity validity;
                 const unsigned char *array_end;
+                int array_elem_type;
 
                 if (claimed_len > DBUS_MAXIMUM_ARRAY_LENGTH)
                   return DBUS_INVALID_ARRAY_LENGTH_EXCEEDS_MAXIMUM;
@@ -417,16 +455,48 @@ validate_body_helper (DBusTypeReader       *reader,
 
                 array_end = p + claimed_len;
 
-                while (p < array_end)
+                array_elem_type = _dbus_type_reader_get_element_type (reader);
+
+                /* avoid recursive call to validate_body_helper if this is an array
+                 * of fixed-size elements
+                 */ 
+                if (dbus_type_is_fixed (array_elem_type))
+                  {
+                    /* bools need to be handled differently, because they can
+                     * have an invalid value
+                     */
+                    if (array_elem_type == DBUS_TYPE_BOOLEAN)
+                      {
+                        dbus_uint32_t v;
+                        alignment = _dbus_type_get_alignment (array_elem_type);
+
+                        while (p < array_end)
+                          {
+                            v = _dbus_unpack_uint32 (byte_order, p);
+
+                            if (!(v == 0 || v == 1))
+                              return DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE;
+
+                            p += alignment;
+                          }
+                      }
+
+                    else
+                      {
+                        p = array_end;
+                      }
+                  }
+
+                else
                   {
-                    /* FIXME we are calling a function per array element! very bad
-                     * need if (dbus_type_is_fixed(elem_type)) here to just skip
-                     * big blocks of ints/bytes/etc.
-                     */                     
-                    
-                    validity = validate_body_helper (&sub, byte_order, FALSE, p, end, &p);
-                    if (validity != DBUS_VALID)
-                      return validity;
+                    while (p < array_end)
+                      {
+                        validity = validate_body_helper (&sub, byte_order, FALSE,
+                                                         total_depth + 1,
+                                                         p, end, &p);
+                        if (validity != DBUS_VALID)
+                          return validity;
+                      }
                   }
 
                 if (p != array_end)
@@ -540,7 +610,9 @@ validate_body_helper (DBusTypeReader       *reader,
 
             _dbus_assert (_dbus_type_reader_get_current_type (&sub) != DBUS_TYPE_INVALID);
 
-            validity = validate_body_helper (&sub, byte_order, FALSE, p, end, &p);
+            validity = validate_body_helper (&sub, byte_order, FALSE,
+                                             total_depth + 1,
+                                             p, end, &p);
             if (validity != DBUS_VALID)
               return validity;
 
@@ -569,7 +641,9 @@ validate_body_helper (DBusTypeReader       *reader,
 
             _dbus_type_reader_recurse (reader, &sub);
 
-            validity = validate_body_helper (&sub, byte_order, TRUE, p, end, &p);
+            validity = validate_body_helper (&sub, byte_order, TRUE,
+                                             total_depth + 1,
+                                             p, end, &p);
             if (validity != DBUS_VALID)
               return validity;
           }
@@ -654,7 +728,7 @@ _dbus_validate_body_with_reason (const DBusString *expected_signature,
   p = _dbus_string_get_const_data_len (value_str, value_pos, len);
   end = p + len;
 
-  validity = validate_body_helper (&reader, byte_order, TRUE, p, end, &p);
+  validity = validate_body_helper (&reader, byte_order, TRUE, 0, p, end, &p);
   if (validity != DBUS_VALID)
     return validity;
   
@@ -759,6 +833,77 @@ _dbus_validate_path (const DBusString  *str,
   return TRUE;
 }
 
+const char *
+_dbus_validity_to_error_message (DBusValidity validity)
+{
+  switch (validity)
+    {
+    case DBUS_VALIDITY_UNKNOWN_OOM_ERROR:                          return "Out of memory";
+    case DBUS_INVALID_FOR_UNKNOWN_REASON:                          return "Unknown reason";
+    case DBUS_VALID_BUT_INCOMPLETE:                                return "Valid but incomplete";
+    case DBUS_VALIDITY_UNKNOWN:                                    return "Validity unknown";
+    case DBUS_VALID:                                               return "Valid";
+    case DBUS_INVALID_UNKNOWN_TYPECODE:                            return "Unknown typecode";
+    case DBUS_INVALID_MISSING_ARRAY_ELEMENT_TYPE:                  return "Missing array element type";
+    case DBUS_INVALID_SIGNATURE_TOO_LONG:                          return "Signature is too long";
+    case DBUS_INVALID_EXCEEDED_MAXIMUM_ARRAY_RECURSION:            return "Exceeded maximum array recursion";
+    case DBUS_INVALID_EXCEEDED_MAXIMUM_STRUCT_RECURSION:           return "Exceeded maximum struct recursion";
+    case DBUS_INVALID_STRUCT_ENDED_BUT_NOT_STARTED:                return "Struct ended but not started";
+    case DBUS_INVALID_STRUCT_STARTED_BUT_NOT_ENDED:                return "Struct started but not ended";
+    case DBUS_INVALID_STRUCT_HAS_NO_FIELDS:                        return "Struct has no fields";
+    case DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL:                   return "Alignment padding not null";
+    case DBUS_INVALID_BOOLEAN_NOT_ZERO_OR_ONE:                     return "Boolean is not zero or one";
+    case DBUS_INVALID_NOT_ENOUGH_DATA:                             return "Not enough data";
+    case DBUS_INVALID_TOO_MUCH_DATA:                               return "Too much data";
+    case DBUS_INVALID_BAD_BYTE_ORDER:                              return "Bad byte order";
+    case DBUS_INVALID_BAD_PROTOCOL_VERSION:                        return "Bad protocol version";
+    case DBUS_INVALID_BAD_MESSAGE_TYPE:                            return "Bad message type";
+    case DBUS_INVALID_BAD_SERIAL:                                  return "Bad serial";
+    case DBUS_INVALID_INSANE_FIELDS_ARRAY_LENGTH:                  return "Insane fields array length";
+    case DBUS_INVALID_INSANE_BODY_LENGTH:                          return "Insane body length";
+    case DBUS_INVALID_MESSAGE_TOO_LONG:                            return "Message too long";
+    case DBUS_INVALID_HEADER_FIELD_CODE:                           return "Header field code";
+    case DBUS_INVALID_HEADER_FIELD_HAS_WRONG_TYPE:                 return "Header field has wrong type";
+    case DBUS_INVALID_USES_LOCAL_INTERFACE:                        return "Uses local interface";
+    case DBUS_INVALID_USES_LOCAL_PATH:                             return "Uses local path";
+    case DBUS_INVALID_HEADER_FIELD_APPEARS_TWICE:                  return "Header field appears twice";
+    case DBUS_INVALID_BAD_DESTINATION:                             return "Bad destination";
+    case DBUS_INVALID_BAD_INTERFACE:                               return "Bad interface";
+    case DBUS_INVALID_BAD_MEMBER:                                  return "Bad member";
+    case DBUS_INVALID_BAD_ERROR_NAME:                              return "Bad error name";
+    case DBUS_INVALID_BAD_SENDER:                                  return "Bad sender";
+    case DBUS_INVALID_MISSING_PATH:                                return "Missing path";
+    case DBUS_INVALID_MISSING_INTERFACE:                           return "Missing interface";
+    case DBUS_INVALID_MISSING_MEMBER:                              return "Missing member";
+    case DBUS_INVALID_MISSING_ERROR_NAME:                          return "Missing error name";
+    case DBUS_INVALID_MISSING_REPLY_SERIAL:                        return "Missing reply serial";
+    case DBUS_INVALID_LENGTH_OUT_OF_BOUNDS:                        return "Length out of bounds";
+    case DBUS_INVALID_ARRAY_LENGTH_EXCEEDS_MAXIMUM:                return "Array length exceeds maximum";
+    case DBUS_INVALID_BAD_PATH:                                    return "Bad path";
+    case DBUS_INVALID_SIGNATURE_LENGTH_OUT_OF_BOUNDS:              return "Signature length out of bounds";
+    case DBUS_INVALID_BAD_UTF8_IN_STRING:                          return "Bad utf8 in string";
+    case DBUS_INVALID_ARRAY_LENGTH_INCORRECT:                      return "Array length incorrect";
+    case DBUS_INVALID_VARIANT_SIGNATURE_LENGTH_OUT_OF_BOUNDS:      return "Variant signature length out of bounds";
+    case DBUS_INVALID_VARIANT_SIGNATURE_BAD:                       return "Variant signature bad";
+    case DBUS_INVALID_VARIANT_SIGNATURE_EMPTY:                     return "Variant signature empty";
+    case DBUS_INVALID_VARIANT_SIGNATURE_SPECIFIES_MULTIPLE_VALUES: return "Variant signature specifies multiple values";
+    case DBUS_INVALID_VARIANT_SIGNATURE_MISSING_NUL:               return "Variant signature missing nul";
+    case DBUS_INVALID_STRING_MISSING_NUL:                          return "String missing nul";
+    case DBUS_INVALID_SIGNATURE_MISSING_NUL:                       return "Signature missing nul";
+    case DBUS_INVALID_EXCEEDED_MAXIMUM_DICT_ENTRY_RECURSION:       return "Exceeded maximum dict entry recursion";
+    case DBUS_INVALID_DICT_ENTRY_ENDED_BUT_NOT_STARTED:            return "Dict entry ended but not started";
+    case DBUS_INVALID_DICT_ENTRY_STARTED_BUT_NOT_ENDED:            return "Dict entry started but not ended";
+    case DBUS_INVALID_DICT_ENTRY_HAS_NO_FIELDS:                    return "Dict entry has no fields";
+    case DBUS_INVALID_DICT_ENTRY_HAS_ONLY_ONE_FIELD:               return "Dict entry has only one field";
+    case DBUS_INVALID_DICT_ENTRY_HAS_TOO_MANY_FIELDS:              return "Dict entry has too many fields";
+    case DBUS_INVALID_DICT_ENTRY_NOT_INSIDE_ARRAY:                 return "Dict entry not inside array";
+    case DBUS_INVALID_DICT_KEY_MUST_BE_BASIC_TYPE:                 return "Dict key must be basic type";
+    case DBUS_INVALID_NESTED_TOO_DEEPLY:                           return "Variants cannot be used to create a hugely recursive tree of values";
+    default:
+      return "Invalid";
+    }
+}
+
 /**
  * Checks that the given range of the string is a valid interface name
  * in the D-Bus protocol. This includes a length restriction and an
@@ -937,23 +1082,11 @@ _dbus_validate_error_name (const DBusString  *str,
     ((c) >= 'a' && (c) <= 'z') ||               \
     ((c) == '_') || ((c) == '-'))
 
-/**
- * Checks that the given range of the string is a valid bus name in
- * the D-Bus protocol. This includes a length restriction, etc., see
- * the specification.
- *
- * @todo this is inconsistent with most of DBusString in that
- * it allows a start,len range that extends past the string end.
- *
- * @param str the string
- * @param start first byte index to check
- * @param len number of bytes to check
- * @returns #TRUE if the byte range exists and is a valid name
- */
-dbus_bool_t
-_dbus_validate_bus_name (const DBusString  *str,
-                         int                start,
-                         int                len)
+static dbus_bool_t
+_dbus_validate_bus_name_full (const DBusString  *str,
+                              int                start,
+                              int                len,
+                              dbus_bool_t        is_namespace)
 {
   const unsigned char *s;
   const unsigned char *end;
@@ -1031,13 +1164,55 @@ _dbus_validate_bus_name (const DBusString  *str,
       ++s;
     }
 
-  if (_DBUS_UNLIKELY (last_dot == NULL))
+  if (!is_namespace && _DBUS_UNLIKELY (last_dot == NULL))
     return FALSE;
 
   return TRUE;
 }
 
 /**
+ * Checks that the given range of the string is a valid bus name in
+ * the D-Bus protocol. This includes a length restriction, etc., see
+ * the specification.
+ *
+ * @todo this is inconsistent with most of DBusString in that
+ * it allows a start,len range that extends past the string end.
+ *
+ * @param str the string
+ * @param start first byte index to check
+ * @param len number of bytes to check
+ * @returns #TRUE if the byte range exists and is a valid name
+ */
+dbus_bool_t
+_dbus_validate_bus_name (const DBusString  *str,
+                         int                start,
+                         int                len)
+{
+  return _dbus_validate_bus_name_full (str, start, len, FALSE);
+}
+
+/**
+ * Checks that the given range of the string is a prefix of a valid bus name in
+ * the D-Bus protocol. Unlike _dbus_validate_bus_name(), this accepts strings
+ * with only one period-separated component.
+ *
+ * @todo this is inconsistent with most of DBusString in that
+ * it allows a start,len range that extends past the string end.
+ *
+ * @param str the string
+ * @param start first byte index to check
+ * @param len number of bytes to check
+ * @returns #TRUE if the byte range exists and is a valid name
+ */
+dbus_bool_t
+_dbus_validate_bus_namespace (const DBusString  *str,
+                              int                start,
+                              int                len)
+{
+  return _dbus_validate_bus_name_full (str, start, len, TRUE);
+}
+
+/**
  * Checks that the given range of the string is a valid message type
  * signature in the D-Bus protocol.
  *
@@ -1076,6 +1251,8 @@ DEFINE_DBUS_NAME_CHECK(error_name)
 DEFINE_DBUS_NAME_CHECK(bus_name)
 /** define _dbus_check_is_valid_signature() */
 DEFINE_DBUS_NAME_CHECK(signature)
+/** define _dbus_check_is_valid_utf8() */
+DEFINE_DBUS_NAME_CHECK(utf8)
 
 /** @} */