[rename] renamed kdbus related macros
[platform/upstream/dbus.git] / dbus / dbus-marshal-header.c
index 3494042..48151c6 100644 (file)
@@ -1,4 +1,4 @@
-/* -*- mode: C; c-file-style: "gnu" -*- */
+/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
 /* dbus-marshal-header.c  Managing marshaling/demarshaling of message headers
  *
  * Copyright (C) 2005  Red Hat, Inc.
  *
  * 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/dbus-shared.h"
 #include "dbus-marshal-header.h"
 #include "dbus-marshal-recursive.h"
+#include "dbus-marshal-byteswap.h"
 
 /**
  * @addtogroup DBusMarshal
 
 /* Not thread locked, but strictly const/read-only so should be OK
  */
+/** Static #DBusString containing the signature of a message header */
 _DBUS_STRING_DEFINE_STATIC(_dbus_header_signature_str, DBUS_HEADER_SIGNATURE);
-_DBUS_STRING_DEFINE_STATIC(_dbus_local_interface_str,  DBUS_INTERFACE_ORG_FREEDESKTOP_LOCAL);
-_DBUS_STRING_DEFINE_STATIC(_dbus_local_path_str,       DBUS_PATH_ORG_FREEDESKTOP_LOCAL);
+/** Static #DBusString containing the local interface */
+_DBUS_STRING_DEFINE_STATIC(_dbus_local_interface_str,  DBUS_INTERFACE_LOCAL);
+/** Static #DBusString containing the local path */
+_DBUS_STRING_DEFINE_STATIC(_dbus_local_path_str,       DBUS_PATH_LOCAL);
 
+/** Offset from start of _dbus_header_signature_str to the signature of the fields array */
 #define FIELDS_ARRAY_SIGNATURE_OFFSET 6
+/** Offset from start of _dbus_header_signature_str to the signature of an element of the fields array */
 #define FIELDS_ARRAY_ELEMENT_SIGNATURE_OFFSET 7
 
 
@@ -60,8 +68,8 @@ _DBUS_STRING_DEFINE_STATIC(_dbus_local_path_str,       DBUS_PATH_ORG_FREEDESKTOP
 
 typedef struct
 {
-  unsigned char code;
-  unsigned char type;
+  unsigned char code; /**< the field code */
+  unsigned char type; /**< the value type */
 } HeaderFieldType;
 
 static const HeaderFieldType
@@ -74,11 +82,14 @@ _dbus_header_field_types[DBUS_HEADER_FIELD_LAST+1] = {
   { DBUS_HEADER_FIELD_REPLY_SERIAL, DBUS_TYPE_UINT32 },
   { DBUS_HEADER_FIELD_DESTINATION, DBUS_TYPE_STRING },
   { DBUS_HEADER_FIELD_SENDER, DBUS_TYPE_STRING },
-  { DBUS_HEADER_FIELD_SIGNATURE, DBUS_TYPE_SIGNATURE }
+  { DBUS_HEADER_FIELD_SIGNATURE, DBUS_TYPE_SIGNATURE },
+  { DBUS_HEADER_FIELD_UNIX_FDS, DBUS_TYPE_UINT32 }
 };
 
+/** Macro to look up the correct type for a field */
 #define EXPECTED_TYPE_OF_FIELD(field) (_dbus_header_field_types[field].type)
 
+/** The most padding we could ever need for a header */
 #define MAX_POSSIBLE_HEADER_PADDING 7
 static dbus_bool_t
 reserve_header_padding (DBusHeader *header)
@@ -108,6 +119,7 @@ correct_header_padding (DBusHeader *header)
   header->padding = _dbus_string_get_length (&header->data) - unpadded_len;
 }
 
+/** Compute the end of the header, ignoring padding */
 #define HEADER_END_BEFORE_PADDING(header) \
   (_dbus_string_get_length (&(header)->data) - (header)->padding)
 
@@ -143,10 +155,6 @@ _dbus_header_cache_one (DBusHeader     *header,
                         int             field_code,
                         DBusTypeReader *variant_reader)
 {
-  int variant_type;
-
-  variant_type = _dbus_type_reader_get_current_type (variant_reader);
-
   header->fields[field_code].value_pos =
     _dbus_type_reader_get_value_pos (variant_reader);
 
@@ -157,6 +165,20 @@ _dbus_header_cache_one (DBusHeader     *header,
 }
 
 /**
+ * Returns the header's byte order.
+ *
+ * @param header the header
+ * @returns the byte order
+ */
+char
+_dbus_header_get_byte_order (const DBusHeader *header)
+{
+  _dbus_assert (_dbus_string_get_length (&header->data) > BYTE_ORDER_OFFSET);
+
+  return (char) _dbus_string_get_byte (&header->data, BYTE_ORDER_OFFSET);
+}
+
+/**
  * Revalidates the fields cache
  *
  * @param header the header
@@ -176,7 +198,7 @@ _dbus_header_cache_revalidate (DBusHeader *header)
     }
 
   _dbus_type_reader_init (&reader,
-                          header->byte_order,
+                          _dbus_header_get_byte_order (header),
                           &_dbus_header_signature_str,
                           FIELDS_ARRAY_SIGNATURE_OFFSET,
                           &header->data,
@@ -254,6 +276,7 @@ _dbus_header_cache_known_nonexistent (DBusHeader    *header,
  * Writes a struct of { byte, variant } with the given basic type.
  *
  * @param writer the writer (should be ready to write a struct)
+ * @param field the header field
  * @param type the type of the value
  * @param value the value as for _dbus_marshal_set_basic()
  * @returns #FALSE if no memory
@@ -314,6 +337,7 @@ write_basic_field (DBusTypeWriter *writer,
  * Sets a struct of { byte, variant } with the given basic type.
  *
  * @param reader the reader (should be iterating over the array pointing at the field to set)
+ * @param field the header field
  * @param type the type of the value
  * @param value the value as for _dbus_marshal_set_basic()
  * @param realign_root where to realign from
@@ -328,14 +352,16 @@ set_basic_field (DBusTypeReader       *reader,
 {
   DBusTypeReader sub;
   DBusTypeReader variant;
-  unsigned char v_BYTE;
 
   _dbus_type_reader_recurse (reader, &sub);
 
   _dbus_assert (_dbus_type_reader_get_current_type (&sub) == DBUS_TYPE_BYTE);
 #ifndef DBUS_DISABLE_ASSERT
-  _dbus_type_reader_read_basic (&sub, &v_BYTE);
-  _dbus_assert (((int) v_BYTE) == field);
+ {
+   unsigned char v_BYTE;
+   _dbus_type_reader_read_basic (&sub, &v_BYTE);
+   _dbus_assert (((int) v_BYTE) == field);
+ }
 #endif
 
   if (!_dbus_type_reader_next (&sub))
@@ -388,7 +414,7 @@ _dbus_header_set_serial (DBusHeader    *header,
   _dbus_marshal_set_uint32 (&header->data,
                             SERIAL_OFFSET,
                            serial,
-                            header->byte_order);
+                            _dbus_header_get_byte_order (header));
 }
 
 /**
@@ -402,7 +428,7 @@ _dbus_header_get_serial (DBusHeader *header)
 {
   return _dbus_marshal_read_uint32 (&header->data,
                                     SERIAL_OFFSET,
-                                    header->byte_order,
+                                    _dbus_header_get_byte_order (header),
                                     NULL);
 }
 
@@ -412,15 +438,12 @@ _dbus_header_get_serial (DBusHeader *header)
  * _dbus_header_create().
  *
  * @param header header to re-initialize
- * @param byte_order byte order of the header
  */
 void
-_dbus_header_reinit (DBusHeader *header,
-                     int         byte_order)
+_dbus_header_reinit (DBusHeader *header)
 {
   _dbus_string_set_length (&header->data, 0);
 
-  header->byte_order = byte_order;
   header->padding = 0;
 
   _dbus_header_cache_invalidate_all (header);
@@ -431,17 +454,15 @@ _dbus_header_reinit (DBusHeader *header,
  * to make the header valid, you have to call _dbus_header_create().
  *
  * @param header header to initialize
- * @param byte_order byte order of the header
  * @returns #FALSE if not enough memory
  */
 dbus_bool_t
-_dbus_header_init (DBusHeader *header,
-                   int         byte_order)
+_dbus_header_init (DBusHeader *header)
 {
   if (!_dbus_string_init_preallocated (&header->data, 32))
     return FALSE;
 
-  _dbus_header_reinit (header, byte_order);
+  _dbus_header_reinit (header);
 
   return TRUE;
 }
@@ -494,8 +515,9 @@ _dbus_header_copy (const DBusHeader *header,
  * sense, and passing them in will trigger an assertion failure.
  *
  * @param header the header
+ * @param byte_order byte order of the header
  * @param message_type the message type
- * @param destination service field or #NULL
+ * @param destination destination field or #NULL
  * @param path path field or #NULL
  * @param interface interface field or #NULL
  * @param member member field or #NULL
@@ -504,6 +526,7 @@ _dbus_header_copy (const DBusHeader *header,
  */
 dbus_bool_t
 _dbus_header_create (DBusHeader  *header,
+                     int          byte_order,
                      int          message_type,
                      const char  *destination,
                      const char  *path,
@@ -516,7 +539,9 @@ _dbus_header_create (DBusHeader  *header,
   DBusTypeWriter writer;
   DBusTypeWriter array;
 
-  _dbus_assert ((interface && member) ||
+  _dbus_assert (byte_order == DBUS_LITTLE_ENDIAN ||
+                byte_order == DBUS_BIG_ENDIAN);
+  _dbus_assert (((interface || message_type != DBUS_MESSAGE_TYPE_SIGNAL) && member) ||
                 (error_name) ||
                 !(interface || member || error_name));
   _dbus_assert (_dbus_string_get_length (&header->data) == 0);
@@ -524,12 +549,12 @@ _dbus_header_create (DBusHeader  *header,
   if (!reserve_header_padding (header))
     return FALSE;
 
-  _dbus_type_writer_init_values_only (&writer, header->byte_order,
+  _dbus_type_writer_init_values_only (&writer, byte_order,
                                       &_dbus_header_signature_str, 0,
                                       &header->data,
                                       HEADER_END_BEFORE_PADDING (header));
 
-  v_BYTE = header->byte_order;
+  v_BYTE = byte_order;
   if (!_dbus_type_writer_write_basic (&writer, DBUS_TYPE_BYTE,
                                       &v_BYTE))
     goto oom;
@@ -633,6 +658,7 @@ _dbus_header_create (DBusHeader  *header,
  * contain the entire message (assuming the claimed lengths are
  * accurate). Also checks that the lengths are in sanity parameters.
  *
+ * @param max_message_length maximum length of a valid message
  * @param validity return location for why the data is invalid if it is
  * @param byte_order return location for byte order
  * @param fields_array_len return location for claimed fields array length
@@ -660,7 +686,7 @@ _dbus_header_have_message_untrusted (int                max_message_length,
   dbus_uint32_t body_len_unsigned;
 
   _dbus_assert (start >= 0);
-  _dbus_assert (start < _DBUS_INT_MAX / 2);
+  _dbus_assert (start < _DBUS_INT32_MAX / 2);
   _dbus_assert (len >= 0);
 
   _dbus_assert (start == (int) _DBUS_ALIGN_VALUE (start, 8));
@@ -699,16 +725,16 @@ _dbus_header_have_message_untrusted (int                max_message_length,
   /* overflow should be impossible since the lengths aren't allowed to
    * be huge.
    */
-  _dbus_assert (max_message_length < _DBUS_INT_MAX / 2);
+  _dbus_assert (max_message_length < _DBUS_INT32_MAX / 2);
   if (body_len_unsigned + header_len_unsigned > (unsigned) max_message_length)
     {
       *validity = DBUS_INVALID_MESSAGE_TOO_LONG;
       return FALSE;
     }
 
-  _dbus_assert (body_len_unsigned < (unsigned) _DBUS_INT_MAX);
-  _dbus_assert (fields_array_len_unsigned < (unsigned) _DBUS_INT_MAX);
-  _dbus_assert (header_len_unsigned < (unsigned) _DBUS_INT_MAX);
+  _dbus_assert (body_len_unsigned < (unsigned) _DBUS_INT32_MAX);
+  _dbus_assert (fields_array_len_unsigned < (unsigned) _DBUS_INT32_MAX);
+  _dbus_assert (header_len_unsigned < (unsigned) _DBUS_INT32_MAX);
 
   *body_len = body_len_unsigned;
   *fields_array_len = fields_array_len_unsigned;
@@ -761,6 +787,7 @@ load_and_validate_field (DBusHeader     *header,
   int expected_type;
   const DBusString *value_str;
   int value_pos;
+  int str_data_pos;
   dbus_uint32_t v_UINT32;
   int bad_string_code;
   dbus_bool_t (* string_validation_func) (const DBusString *str,
@@ -800,6 +827,7 @@ load_and_validate_field (DBusHeader     *header,
   v_UINT32 = 0;
   value_str = NULL;
   value_pos = -1;
+  str_data_pos = -1;
   bad_string_code = DBUS_VALID;
 
   if (expected_type == DBUS_TYPE_UINT32)
@@ -813,6 +841,7 @@ load_and_validate_field (DBusHeader     *header,
     {
       _dbus_header_get_field_raw (header, field,
                                   &value_str, &value_pos);
+      str_data_pos = _DBUS_ALIGN_VALUE (value_pos, 4) + 4;
     }
   else
     {
@@ -822,7 +851,7 @@ load_and_validate_field (DBusHeader     *header,
   switch (field)
     {
     case DBUS_HEADER_FIELD_DESTINATION:
-      string_validation_func = _dbus_validate_service;
+      string_validation_func = _dbus_validate_bus_name;
       bad_string_code = DBUS_INVALID_BAD_DESTINATION;
       break;
     case DBUS_HEADER_FIELD_INTERFACE:
@@ -832,7 +861,7 @@ load_and_validate_field (DBusHeader     *header,
       if (_dbus_string_equal_substring (&_dbus_local_interface_str,
                                         0,
                                         _dbus_string_get_length (&_dbus_local_interface_str),
-                                        value_str, value_pos))
+                                        value_str, str_data_pos))
         {
           _dbus_verbose ("Message is on the local interface\n");
           return DBUS_INVALID_USES_LOCAL_INTERFACE;
@@ -850,7 +879,7 @@ load_and_validate_field (DBusHeader     *header,
       break;
 
     case DBUS_HEADER_FIELD_SENDER:
-      string_validation_func = _dbus_validate_service;
+      string_validation_func = _dbus_validate_bus_name;
       bad_string_code = DBUS_INVALID_BAD_SENDER;
       break;
 
@@ -858,13 +887,10 @@ load_and_validate_field (DBusHeader     *header,
       /* OBJECT_PATH was validated generically due to its type */
       string_validation_func = NULL;
 
-      _dbus_verbose ("value_str %p value_pos %d value_str_len %d\n",
-                     value_str, value_pos,
-                     _dbus_string_get_length (value_str));
       if (_dbus_string_equal_substring (&_dbus_local_path_str,
                                         0,
                                         _dbus_string_get_length (&_dbus_local_path_str),
-                                        value_str, value_pos))
+                                        value_str, str_data_pos))
         {
           _dbus_verbose ("Message is from the local path\n");
           return DBUS_INVALID_USES_LOCAL_PATH;
@@ -879,6 +905,10 @@ load_and_validate_field (DBusHeader     *header,
         }
       break;
 
+    case DBUS_HEADER_FIELD_UNIX_FDS:
+      /* Every value makes sense */
+      break;
+
     case DBUS_HEADER_FIELD_SIGNATURE:
       /* SIGNATURE validated generically due to its type */
       string_validation_func = NULL;
@@ -896,9 +926,14 @@ load_and_validate_field (DBusHeader     *header,
       _dbus_assert (bad_string_code != DBUS_VALID);
 
       len = _dbus_marshal_read_uint32 (value_str, value_pos,
-                                       header->byte_order, NULL);
+                                       _dbus_header_get_byte_order (header),
+                                       NULL);
 
-      if (!(*string_validation_func) (value_str, value_pos + 4, len))
+#if 0
+      _dbus_verbose ("Validating string header field; code %d if fails\n",
+                     bad_string_code);
+#endif
+      if (!(*string_validation_func) (value_str, str_data_pos, len))
         return bad_string_code;
     }
 
@@ -906,11 +941,12 @@ load_and_validate_field (DBusHeader     *header,
 }
 
 /**
- * Creates a message header from untrusted data. The return value
- * is #TRUE if there was enough memory and the data was valid. If it
- * returns #TRUE, the header will be created. If it returns #FALSE
- * and *validity == #DBUS_VALID, then there wasn't enough memory.  If
- * it returns #FALSE and *validity != #DBUS_VALID then the data was
+ * Creates a message header from potentially-untrusted data. The
+ * return value is #TRUE if there was enough memory and the data was
+ * valid. If it returns #TRUE, the header will be created. If it
+ * returns #FALSE and *validity == #DBUS_VALIDITY_UNKNOWN_OOM_ERROR, 
+ * then there wasn't enough memory.  If it returns #FALSE 
+ * and *validity != #DBUS_VALIDITY_UNKNOWN_OOM_ERROR then the data was 
  * invalid.
  *
  * The byte_order, fields_array_len, and body_len args should be from
@@ -919,6 +955,7 @@ load_and_validate_field (DBusHeader     *header,
  * already done.
  *
  * @param header the header (must be initialized)
+ * @param mode whether to do validation
  * @param validity return location for invalidity reason
  * @param byte_order byte order from header
  * @param fields_array_len claimed length of fields array
@@ -930,15 +967,16 @@ load_and_validate_field (DBusHeader     *header,
  * @returns #FALSE if no memory or data was invalid, #TRUE otherwise
  */
 dbus_bool_t
-_dbus_header_load_untrusted (DBusHeader       *header,
-                             DBusValidity     *validity,
-                             int               byte_order,
-                             int               fields_array_len,
-                             int               header_len,
-                             int               body_len,
-                             const DBusString *str,
-                             int               start,
-                             int               len)
+_dbus_header_load (DBusHeader        *header,
+                   DBusValidationMode mode,
+                   DBusValidity      *validity,
+                   int                byte_order,
+                   int                fields_array_len,
+                   int                header_len,
+                   int                body_len,
+                   const DBusString  *str,
+                   int                start,
+                   int                len)
 {
   int leftover;
   DBusValidity v;
@@ -958,19 +996,26 @@ _dbus_header_load_untrusted (DBusHeader       *header,
   if (!_dbus_string_copy_len (str, start, header_len, &header->data, 0))
     {
       _dbus_verbose ("Failed to copy buffer into new header\n");
-      *validity = DBUS_VALID;
+      *validity = DBUS_VALIDITY_UNKNOWN_OOM_ERROR;
       return FALSE;
     }
 
-  v = _dbus_validate_body_with_reason (&_dbus_header_signature_str, 0,
-                                       byte_order,
-                                       &leftover,
-                                       str, start, len);
-
-  if (v != DBUS_VALID)
+  if (mode == DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY)
     {
-      *validity = v;
-      goto invalid;
+      leftover = len - header_len - body_len - start;
+    }
+  else
+    {
+      v = _dbus_validate_body_with_reason (&_dbus_header_signature_str, 0,
+                                           byte_order,
+                                           &leftover,
+                                           str, start, len);
+      
+      if (v != DBUS_VALID)
+        {
+          *validity = v;
+          goto invalid;
+        }
     }
 
   _dbus_assert (leftover < len);
@@ -980,14 +1025,23 @@ _dbus_header_load_untrusted (DBusHeader       *header,
   _dbus_assert (start + header_len == (int) _DBUS_ALIGN_VALUE (padding_start, 8));
   _dbus_assert (start + header_len == padding_start + padding_len);
 
-  if (!_dbus_string_validate_nul (str, padding_start, padding_len))
+  if (mode != DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY)
     {
-      *validity = DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
-      goto invalid;
+      if (!_dbus_string_validate_nul (str, padding_start, padding_len))
+        {
+          *validity = DBUS_INVALID_ALIGNMENT_PADDING_NOT_NUL;
+          goto invalid;
+        }
     }
 
   header->padding = padding_len;
 
+  if (mode == DBUS_VALIDATION_MODE_WE_TRUST_THIS_DATA_ABSOLUTELY)
+    {
+      *validity = DBUS_VALID;
+      return TRUE;
+    }
+
   /* We now know the data is well-formed, but we have to check that
    * it's valid.
    */
@@ -1145,9 +1199,22 @@ _dbus_header_update_lengths (DBusHeader *header,
   _dbus_marshal_set_uint32 (&header->data,
                             BODY_LENGTH_OFFSET,
                             body_len,
-                            header->byte_order);
+                            _dbus_header_get_byte_order (header));
 }
 
+/**
+ * Try to find the given field.
+ *
+ * @param header the header
+ * @param field the field code
+ * @param reader a type reader; on success this is left pointing at the struct
+ *  (uv) for the field, while on failure it is left pointing into empty space
+ *  at the end of the header fields
+ * @param realign_root another type reader; on success or failure it is left
+ *  pointing to the beginning of the array of fields (i.e. the thing that might
+ *  need realigning)
+ * @returns #TRUE on success
+ */
 static dbus_bool_t
 find_field_for_modification (DBusHeader     *header,
                              int             field,
@@ -1159,7 +1226,7 @@ find_field_for_modification (DBusHeader     *header,
   retval = FALSE;
 
   _dbus_type_reader_init (realign_root,
-                          header->byte_order,
+                          _dbus_header_get_byte_order (header),
                           &_dbus_header_signature_str,
                           FIELDS_ARRAY_SIGNATURE_OFFSET,
                           &header->data,
@@ -1208,7 +1275,7 @@ _dbus_header_set_field_basic (DBusHeader       *header,
                               int               type,
                               const void       *value)
 {
-  _dbus_return_val_if_fail (field <= DBUS_HEADER_FIELD_LAST, FALSE);
+  _dbus_assert (field <= DBUS_HEADER_FIELD_LAST);
 
   if (!reserve_header_padding (header))
     return FALSE;
@@ -1232,7 +1299,7 @@ _dbus_header_set_field_basic (DBusHeader       *header,
       DBusTypeWriter array;
 
       _dbus_type_writer_init_values_only (&writer,
-                                          header->byte_order,
+                                          _dbus_header_get_byte_order (header),
                                           &_dbus_header_signature_str,
                                           FIELDS_ARRAY_SIGNATURE_OFFSET,
                                           &header->data,
@@ -1302,7 +1369,7 @@ _dbus_header_get_field_basic (DBusHeader    *header,
 
   _dbus_marshal_read_basic (&header->data,
                             header->fields[field].value_pos,
-                            type, value, header->byte_order,
+                            type, value, _dbus_header_get_byte_order (header),
                             NULL);
 
   return TRUE;
@@ -1419,17 +1486,29 @@ _dbus_header_get_flag (DBusHeader   *header,
   return (*flags_p & flag) != 0;
 }
 
-/** @} */
+/**
+ * Swaps the header into the given order if required.
+ *
+ * @param header the header
+ * @param new_order the new byte order
+ */
+void
+_dbus_header_byteswap (DBusHeader *header,
+                       int         new_order)
+{
+  char byte_order;
 
-#ifdef DBUS_BUILD_TESTS
-#include "dbus-test.h"
-#include <stdio.h>
+  byte_order = _dbus_header_get_byte_order (header);
 
-dbus_bool_t
-_dbus_marshal_header_test (void)
-{
+  if (byte_order == new_order)
+    return;
 
-  return TRUE;
+  _dbus_marshal_byteswap (&_dbus_header_signature_str,
+                          0, byte_order,
+                          new_order,
+                          &header->data, 0);
+
+  _dbus_string_set_byte (&header->data, BYTE_ORDER_OFFSET, new_order);
 }
 
-#endif /* DBUS_BUILD_TESTS */
+/** @} */