]> arthur.barton.de Git - netatalk.git/commitdiff
Import Spotlight dissector code from Wireshark
authorFrank Lahm <franklahm@googlemail.com>
Sat, 9 Jun 2012 07:15:41 +0000 (09:15 +0200)
committerFrank Lahm <franklahm@googlemail.com>
Wed, 15 Aug 2012 18:14:21 +0000 (20:14 +0200)
etc/afpd/auth.c
etc/afpd/spotlight.c
etc/afpd/spotlight.h
include/atalk/byteorder.h

index 7569cfefa7be0dabb190dc5ef7774749e9f8746b..aa0fe873b572fd45d94c747c9cabf7ef3d13fc46 100644 (file)
@@ -46,6 +46,7 @@ extern void afp_get_cmdline( int *ac, char ***av );
 #include "status.h"
 #include "fork.h"
 #include "extattrs.h"
+#include "spotlight.h"
 #ifdef HAVE_ACLS
 #include "acls.h"
 #endif
@@ -183,7 +184,7 @@ static int set_auth_switch(const AFPObj *obj, int expired)
         case 31:
             uam_afpserver_action(AFP_SYNCDIR, UAM_AFPSERVER_POSTAUTH, afp_syncdir, NULL);
             uam_afpserver_action(AFP_SYNCFORK, UAM_AFPSERVER_POSTAUTH, afp_syncfork, NULL);
-            uam_afpserver_action(AFP_SPOTLIGHT_PRIVATE, UAM_AFPSERVER_POSTAUTH, afp_null_nolog, NULL);
+            uam_afpserver_action(AFP_SPOTLIGHT_PRIVATE, UAM_AFPSERVER_POSTAUTH, afp_spotlight_rpc, NULL);
             uam_afpserver_action(AFP_ENUMERATE_EXT2, UAM_AFPSERVER_POSTAUTH, afp_enumerate_ext2, NULL);
 
         case 30:
index d9a5ad9fc19b75ecdedaee5383284420b3d9bf4b..2b6fb6edbd0a6656e73139b97067fa330defe1cb 100644 (file)
 #include <atalk/util.h>
 #include <atalk/logger.h>
 #include <atalk/talloc.h>
-#include <atalk/bstrlib.h>
+#include <atalk/dalloc.h>
+#include <atalk/byteorder.h>
+#include <atalk/netatalk_conf.h>
+#include <atalk/volume.h>
 
 #include "spotlight.h"
 
+/**************************************************************************************************
+ * RPC data marshalling and unmarshalling
+ **************************************************************************************************/
+
+/* FPSpotlightRPC subcommand codes */
+#define SPOTLIGHT_CMD_FLAGS   2
+#define SPOTLIGHT_CMD_RPC     3
+#define SPOTLIGHT_CMD_VOLPATH 4
+
+/* Spotlight epoch is UNIX epoch minus SPOTLIGHT_TIME_DELTA */
+#define SPOTLIGHT_TIME_DELTA INT64_C(280878921600U)
+
+#define SQ_TYPE_NULL    0x0000
+#define SQ_TYPE_COMPLEX 0x0200
+#define SQ_TYPE_INT64   0x8400
+#define SQ_TYPE_BOOL    0x0100
+#define SQ_TYPE_FLOAT   0x8500
+#define SQ_TYPE_DATA    0x0700
+#define SQ_TYPE_CNIDS   0x8700
+#define SQ_TYPE_UUID    0x0e00
+#define SQ_TYPE_DATE    0x8600
+
+#define SQ_CPX_TYPE_ARRAY              0x0a00
+#define SQ_CPX_TYPE_STRING             0x0c00
+#define SQ_CPX_TYPE_UTF16_STRING       0x1c00
+#define SQ_CPX_TYPE_DICT               0x0d00
+#define SQ_CPX_TYPE_CNIDS              0x1a00
+#define SQ_CPX_TYPE_FILEMETA           0x1b00
+
+#define SUBQ_SAFETY_LIM 20
+
+/* Can be ored and used as flags */
+#define SL_ENC_LITTLE_ENDIAN 1
+#define SL_ENC_BIG_ENDIAN    2
+#define SL_ENC_UTF_16        4
+
+static uint64_t spotlight_ntoh64(const char *buf, int encoding)
+{
+       if (encoding == SL_ENC_LITTLE_ENDIAN)
+               return LVAL(buf, 0);
+       else
+        return ntoh64(LVAL(buf, 0));
+}
+
+#if 0
+static gdouble
+spotlight_ntohieee_double(tvbuff_t *tvb, gint offset, guint encoding)
+{
+       if (encoding == ENC_LITTLE_ENDIAN)
+               return tvb_get_letohieee_double(tvb, offset);
+       else
+               return tvb_get_ntohieee_double(tvb, offset);
+}
+
+/*
+* Returns the UTF-16 string encoding, by checking the 2-byte byte order mark.
+* If there is no byte order mark, -1 is returned.
+*/
+static guint
+spotlight_get_utf16_string_encoding(tvbuff_t *tvb, gint offset, gint query_length, guint encoding) {
+       guint utf16_encoding;
+
+       /* check for byte order mark */
+       utf16_encoding = ENC_BIG_ENDIAN;
+       if (query_length >= 2) {
+               guint16 byte_order_mark;
+               if (encoding == ENC_LITTLE_ENDIAN)
+                       byte_order_mark = tvb_get_letohs(tvb, offset);
+               else
+                       byte_order_mark = tvb_get_ntohs(tvb, offset);
+
+               if (byte_order_mark == 0xFFFE) {
+                       utf16_encoding = ENC_BIG_ENDIAN | ENC_UTF_16;
+               }
+               else if (byte_order_mark == 0xFEFF) {
+                       utf16_encoding = ENC_LITTLE_ENDIAN | ENC_UTF_16;
+               }
+       }
+
+       return utf16_encoding;
+}
+
+static gint
+spotlight_int64(tvbuff_t *tvb, proto_tree *tree, gint offset, guint encoding)
+{
+       gint count, i;
+       guint64 query_data64;
+
+       query_data64 = spotlight_ntoh64(tvb, offset, encoding);
+       count = query_data64 >> 32;
+       offset += 8;
+
+       i = 0;
+       while (i++ < count) {
+               query_data64 = spotlight_ntoh64(tvb, offset, encoding);
+               proto_tree_add_text(tree, tvb, offset, 8, "int64: 0x%016" G_GINT64_MODIFIER "x", query_data64);
+               offset += 8;
+       }
+
+       return count;
+}
+
+static gint
+spotlight_date(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset, guint encoding)
+{
+       gint count, i;
+       guint64 query_data64;
+       nstime_t t;
+
+       query_data64 = spotlight_ntoh64(tvb, offset, encoding);
+       count = query_data64 >> 32;
+       offset += 8;
+
+       if (count > SUBQ_SAFETY_LIM) {
+               expert_add_info_format(pinfo, tree, PI_MALFORMED, PI_ERROR,
+                                                          "Subquery count (%d) > safety limit (%d)", count, SUBQ_SAFETY_LIM);
+               return -1;
+       }
+
+       i = 0;
+       while (i++ < count) {
+               query_data64 = spotlight_ntoh64(tvb, offset, encoding) >> 24;
+               t.secs = query_data64 - SPOTLIGHT_TIME_DELTA;
+               t.nsecs = 0;
+               proto_tree_add_time(tree, hf_afp_spotlight_date, tvb, offset, 8, &t);
+               offset += 8;
+       }
+
+       return count;
+}
+
+static gint
+spotlight_uuid(tvbuff_t *tvb, proto_tree *tree, gint offset, guint encoding)
+{
+       gint count, i;
+       guint64 query_data64;
+
+       query_data64 = spotlight_ntoh64(tvb, offset, encoding);
+       count = query_data64 >> 32;
+       offset += 8;
+
+       i = 0;
+       while (i++ < count) {
+               proto_tree_add_item(tree, hf_afp_spotlight_uuid, tvb, offset, 16, ENC_BIG_ENDIAN);
+               offset += 16;
+       }
+
+       return count;
+}
+
+static gint
+spotlight_float(tvbuff_t *tvb, proto_tree *tree, gint offset, guint encoding)
+{
+       gint count, i;
+       guint64 query_data64;
+       gdouble fval;
+
+       query_data64 = spotlight_ntoh64(tvb, offset, encoding);
+       count = query_data64 >> 32;
+       offset += 8;
+
+       i = 0;
+       while (i++ < count) {
+               fval = spotlight_ntohieee_double(tvb, offset, encoding);
+               proto_tree_add_text(tree, tvb, offset, 8, "float: %f", fval);
+               offset += 8;
+       }
+
+       return count;
+}
+
+static gint
+spotlight_CNID_array(tvbuff_t *tvb, proto_tree *tree, gint offset, guint encoding)
+{
+       gint count;
+       guint64 query_data64;
+       guint16 unknown1;
+       guint32 unknown2;
+
+       query_data64 = spotlight_ntoh64(tvb, offset, encoding);
+       count = query_data64 & 0xffff;
+       unknown1 = (query_data64 & 0xffff0000) >> 16;
+       unknown2 = query_data64 >> 32;
+
+       proto_tree_add_text(tree, tvb, offset + 2, 2, "unknown1: 0x%04" G_GINT16_MODIFIER "x",
+               unknown1);
+       proto_tree_add_text(tree, tvb, offset + 4, 4, "unknown2: 0x%08" G_GINT32_MODIFIER "x",
+               unknown2);
+       offset += 8;
+
+
+       while (count --) {
+               query_data64 = spotlight_ntoh64(tvb, offset, encoding);
+               proto_tree_add_text(tree, tvb, offset, 8, "CNID: %" G_GINT64_MODIFIER "u",
+                       query_data64);
+               offset += 8;
+       }
+
+       return 0;
+}
+
+static const char *spotlight_get_qtype_string(guint64 query_type)
+{
+       switch (query_type) {
+       case SQ_TYPE_NULL:
+               return "null";
+       case SQ_TYPE_COMPLEX:
+               return "complex";
+       case SQ_TYPE_INT64:
+               return "int64";
+       case SQ_TYPE_BOOL:
+               return "bool";
+       case SQ_TYPE_FLOAT:
+               return "float";
+       case SQ_TYPE_DATA:
+               return "data";
+       case SQ_TYPE_CNIDS:
+               return "CNIDs";
+       default:
+               return "unknown";
+       }
+}
+
+static const char *spotlight_get_cpx_qtype_string(guint64 cpx_query_type)
+{
+       switch (cpx_query_type) {
+       case SQ_CPX_TYPE_ARRAY:
+               return "array";
+       case SQ_CPX_TYPE_STRING:
+               return "string";
+       case SQ_CPX_TYPE_UTF16_STRING:
+               return "utf-16 string";
+       case SQ_CPX_TYPE_DICT:
+               return "dictionary";
+       case SQ_CPX_TYPE_CNIDS:
+               return "CNIDs";
+       case SQ_CPX_TYPE_FILEMETA:
+               return "FileMeta";
+       default:
+               return "unknown";
+       }
+}
+
+static gint
+spotlight_dissect_query_loop(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset,
+                             guint64 cpx_query_type, gint count, gint toc_offset, guint encoding)
+{
+       gint i, j;
+       gint subquery_count;
+       gint toc_index;
+       guint64 query_data64;
+       gint query_length;
+       guint64 query_type;
+       guint64 complex_query_type;
+       guint unicode_encoding;
+       guint8 mark_exists;
+
+       proto_item *item_query;
+       proto_tree *sub_tree;
+
+       /*
+        * This loops through a possibly nested query data structure.
+        * The outermost one is always without count and called from
+        * dissect_spotlight() with count = INT_MAX thus the while (...)
+        * loop terminates if (offset >= toc_offset).
+        * If nested structures are found, these will have an encoded element
+        * count which is used in a recursive call to
+        * spotlight_dissect_query_loop as count parameter, thus in this case
+        * the while (...) loop will terminate when count reaches 0.
+        */
+       while ((offset < (toc_offset - 8)) && (count > 0)) {
+               query_data64 = spotlight_ntoh64(tvb, offset, encoding);
+               query_length = (query_data64 & 0xffff) * 8;
+               if (query_length == 0) {
+                       /* XXX - report this as an error */
+                       break;
+               }
+               query_type = (query_data64 & 0xffff0000) >> 16;
+
+               switch (query_type) {
+               case SQ_TYPE_COMPLEX:
+                       toc_index = (gint)((query_data64 >> 32) - 1);
+                       query_data64 = spotlight_ntoh64(tvb, toc_offset + toc_index * 8, encoding);
+                       complex_query_type = (query_data64 & 0xffff0000) >> 16;
+
+                       switch (complex_query_type) {
+                       case SQ_CPX_TYPE_ARRAY:
+                       case SQ_CPX_TYPE_DICT:
+                               subquery_count = (gint)(query_data64 >> 32);
+                               item_query = proto_tree_add_text(tree, tvb, offset, query_length,
+                                                                "%s, toc index: %u, children: %u",
+                                                                spotlight_get_cpx_qtype_string(complex_query_type),
+                                                                toc_index + 1,
+                                                                subquery_count);
+                               break;
+                       case SQ_CPX_TYPE_STRING:
+                               subquery_count = 1;
+                               query_data64 = spotlight_ntoh64(tvb, offset + 8, encoding);
+                               query_length = (query_data64 & 0xffff) * 8;
+                               item_query = proto_tree_add_text(tree, tvb, offset, query_length + 8,
+                                                                "%s, toc index: %u, string: '%s'",
+                                                                spotlight_get_cpx_qtype_string(complex_query_type),
+                                                                toc_index + 1,
+                                                                tvb_get_ephemeral_string(tvb, offset + 16, query_length - 8));
+                               break;
+                       case SQ_CPX_TYPE_UTF16_STRING:
+                               /*
+                               * This is an UTF-16 string.
+                               * Dissections show the typical byte order mark 0xFFFE or 0xFEFF, respectively.
+                               * However the existence of such a mark can not be assumed.
+                               * If the mark is missing, big endian encoding is assumed.
+                               */
+
+                               subquery_count = 1;
+                               query_data64 = spotlight_ntoh64(tvb, offset + 8, encoding);
+                               query_length = (query_data64 & 0xffff) * 8;
+
+                               unicode_encoding = spotlight_get_utf16_string_encoding(tvb, offset + 16, query_length - 8, encoding);
+                               mark_exists = (unicode_encoding & ENC_UTF_16);
+                               unicode_encoding &= ~ENC_UTF_16;
+
+                               item_query = proto_tree_add_text(tree, tvb, offset, query_length + 8,
+                                                                "%s, toc index: %u, utf-16 string: '%s'",
+                                                                spotlight_get_cpx_qtype_string(complex_query_type),
+                                                                toc_index + 1,
+                                                                tvb_get_ephemeral_unicode_string(tvb, offset + (mark_exists ? 18 : 16),
+                                                                query_length - (mark_exists? 10 : 8), unicode_encoding));
+                               break;
+                       default:
+                               subquery_count = 1;
+                               item_query = proto_tree_add_text(tree, tvb, offset, query_length,
+                                                                "type: %s (%s), toc index: %u, children: %u",
+                                                                spotlight_get_qtype_string(query_type),
+                                                                spotlight_get_cpx_qtype_string(complex_query_type),
+                                                                toc_index + 1,
+                                                                subquery_count);
+                               break;
+                       }
+
+                       sub_tree = proto_item_add_subtree(item_query, ett_afp_spotlight_query_line);
+                       offset += 8;
+                       offset = spotlight_dissect_query_loop(tvb, pinfo, sub_tree, offset, complex_query_type, subquery_count, toc_offset, encoding);
+                       count--;
+                       break;
+               case SQ_TYPE_NULL:
+                       subquery_count = (gint)(query_data64 >> 32);
+                       if (subquery_count > count) {
+                               item_query = proto_tree_add_text(tree, tvb, offset, query_length, "null");
+                               expert_add_info_format(pinfo, item_query, PI_MALFORMED, PI_ERROR,
+                                       "Subquery count (%d) > query count (%d)", subquery_count, count);
+                               count = 0;
+                       } else if (subquery_count > 20) {
+                               item_query = proto_tree_add_text(tree, tvb, offset, query_length, "null");
+                               expert_add_info_format(pinfo, item_query, PI_PROTOCOL, PI_WARN,
+                                       "Abnormal number of subqueries (%d)", subquery_count);
+                               count -= subquery_count;
+                       } else {
+                               for (i = 0; i < subquery_count; i++, count--)
+                                       proto_tree_add_text(tree, tvb, offset, query_length, "null");
+                       }
+                       offset += query_length;
+                       break;
+               case SQ_TYPE_BOOL:
+                       proto_tree_add_text(tree, tvb, offset, query_length, "bool: %s",
+                                                        (query_data64 >> 32) ? "true" : "false");
+                       count--;
+                       offset += query_length;
+                       break;
+               case SQ_TYPE_INT64:
+                       item_query = proto_tree_add_text(tree, tvb, offset, 8, "int64");
+                       sub_tree = proto_item_add_subtree(item_query, ett_afp_spotlight_query_line);
+                       j = spotlight_int64(tvb, sub_tree, offset, encoding);
+                       count -= j;
+                       offset += query_length;
+                       break;
+               case SQ_TYPE_UUID:
+                       item_query = proto_tree_add_text(tree, tvb, offset, 8, "UUID");
+                       sub_tree = proto_item_add_subtree(item_query, ett_afp_spotlight_query_line);
+                       j = spotlight_uuid(tvb, sub_tree, offset, encoding);
+                       count -= j;
+                       offset += query_length;
+                       break;
+               case SQ_TYPE_FLOAT:
+                       item_query = proto_tree_add_text(tree, tvb, offset, 8, "float");
+                       sub_tree = proto_item_add_subtree(item_query, ett_afp_spotlight_query_line);
+                       j = spotlight_float(tvb, sub_tree, offset, encoding);
+                       count -= j;
+                       offset += query_length;
+                       break;
+               case SQ_TYPE_DATA:
+                       switch (cpx_query_type) {
+                       case SQ_CPX_TYPE_STRING:
+                               proto_tree_add_text(tree, tvb, offset, query_length, "string: '%s'",
+                                                   tvb_get_ephemeral_string(tvb, offset + 8, query_length - 8));
+                               break;
+                       case SQ_CPX_TYPE_UTF16_STRING: {
+                               /* description see above */
+                               unicode_encoding = spotlight_get_utf16_string_encoding(tvb, offset + 8, query_length, encoding);
+                               mark_exists = (unicode_encoding & ENC_UTF_16);
+                               unicode_encoding &= ~ENC_UTF_16;
+
+                               proto_tree_add_text(tree, tvb, offset, query_length, "utf-16 string: '%s'",
+                                                   tvb_get_ephemeral_unicode_string(tvb, offset + (mark_exists ? 10 : 8),
+                                                               query_length - (mark_exists? 10 : 8), unicode_encoding));
+                               break;
+                       }
+                       case SQ_CPX_TYPE_FILEMETA:
+                               if (query_length <= 8) {
+                                       /* item_query = */ proto_tree_add_text(tree, tvb, offset, query_length, "filemeta (empty)");
+                               } else {
+                                       item_query = proto_tree_add_text(tree, tvb, offset, query_length, "filemeta");
+                                       sub_tree = proto_item_add_subtree(item_query, ett_afp_spotlight_query_line);
+                                       (void)dissect_spotlight(tvb, pinfo, sub_tree, offset + 8);
+                               }
+                               break;
+                       }
+                       count--;
+                       offset += query_length;
+                       break;
+               case SQ_TYPE_CNIDS:
+                       if (query_length <= 8) {
+                               /* item_query = */ proto_tree_add_text(tree, tvb, offset, query_length, "CNID Array (empty)");
+                       } else {
+                               item_query = proto_tree_add_text(tree, tvb, offset, query_length, "CNID Array");
+                               sub_tree = proto_item_add_subtree(item_query, ett_afp_spotlight_query_line);
+                               spotlight_CNID_array(tvb, sub_tree, offset + 8, encoding);
+                       }
+                       count--;
+                       offset += query_length;
+                       break;
+               case SQ_TYPE_DATE:
+                       if ((j = spotlight_date(tvb, pinfo, tree, offset, encoding)) == -1)
+                               return offset;
+                       count -= j;
+                       offset += query_length;
+                       break;
+               default:
+                       proto_tree_add_text(tree, tvb, offset, query_length, "type: %s",
+                                                        spotlight_get_qtype_string(query_type));
+                       count--;
+                       offset += query_length;
+                       break;
+               }
+       }
+
+       return offset;
+}
+
+static gint
+dissect_spotlight(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, gint offset)
+{
+       guint encoding;
+       gint i;
+       guint64 toc_offset;
+       guint64 querylen;
+       gint toc_entries;
+       guint64 toc_entry;
+
+       proto_item *item_queries_data;
+       proto_tree *sub_tree_queries;
+       proto_item *item_toc;
+       proto_tree *sub_tree_toc;
+
+       if (strncmp(tvb_get_ephemeral_string(tvb, offset, 8), "md031234", 8) == 0)
+               encoding = ENC_BIG_ENDIAN;
+       else
+               encoding = ENC_LITTLE_ENDIAN;
+       proto_tree_add_text(tree,
+                           tvb,
+                           offset,
+                           8,
+                           "Endianess: %s",
+                           encoding == ENC_BIG_ENDIAN ?
+                           "Big Endian" : "Litte Endian");
+       offset += 8;
+
+       toc_offset = (spotlight_ntoh64(tvb, offset, encoding) >> 32) * 8;
+       if (toc_offset < 8) {
+               proto_tree_add_text(tree,
+                                   tvb,
+                                   offset,
+                                   8,
+                                   "ToC Offset: %" G_GINT64_MODIFIER "u < 8 (bogus)",
+                                   toc_offset);
+               return -1;
+       }
+       toc_offset -= 8;
+       if (offset + toc_offset + 8 > G_MAXINT) {
+               proto_tree_add_text(tree,
+                                   tvb,
+                                   offset,
+                                   8,
+                                   "ToC Offset: %" G_GINT64_MODIFIER "u > %u (bogus)",
+                                   toc_offset,
+                                   G_MAXINT - 8 - offset);
+               return -1;
+       }
+       querylen = (spotlight_ntoh64(tvb, offset, encoding) & 0xffffffff) * 8;
+       if (querylen < 8) {
+               proto_tree_add_text(tree,
+                                   tvb,
+                                   offset,
+                                   8,
+                                   "ToC Offset: %" G_GINT64_MODIFIER "u Bytes, Query length: %" G_GINT64_MODIFIER "u < 8 (bogus)",
+                                   toc_offset,
+                                   querylen);
+               return -1;
+       }
+       querylen -= 8;
+       if (querylen > G_MAXINT) {
+               proto_tree_add_text(tree,
+                                   tvb,
+                                   offset,
+                                   8,
+                                   "ToC Offset: %" G_GINT64_MODIFIER "u Bytes, Query length: %" G_GINT64_MODIFIER "u > %u (bogus)",
+                                   toc_offset,
+                                   querylen,
+                                   G_MAXINT);
+               return -1;
+       }
+       proto_tree_add_text(tree,
+                           tvb,
+                           offset,
+                           8,
+                           "ToC Offset: %" G_GINT64_MODIFIER "u Bytes, Query length: %" G_GINT64_MODIFIER "u Bytes",
+                           toc_offset,
+                           querylen);
+       offset += 8;
+
+       toc_entries = (gint)(spotlight_ntoh64(tvb, offset + (gint)toc_offset, encoding) & 0xffff);
+
+       item_queries_data = proto_tree_add_text(tree,
+                                               tvb,
+                                               offset,
+                                               (gint)toc_offset,
+                                               "Spotlight RPC data");
+       sub_tree_queries = proto_item_add_subtree(item_queries_data, ett_afp_spotlight_queries);
+
+       /* Queries */
+       offset = spotlight_dissect_query_loop(tvb, pinfo, sub_tree_queries, offset, SQ_CPX_TYPE_ARRAY, INT_MAX, offset + (gint)toc_offset + 8, encoding);
+
+       /* ToC */
+       if (toc_entries < 1) {
+               proto_tree_add_text(tree,
+                                   tvb,
+                                   offset,
+                                   (gint)querylen - (gint)toc_offset,
+                                   "Complex types ToC (%u < 1 - bogus)",
+                                   toc_entries);
+               return -1;
+       }
+       toc_entries -= 1;
+       item_toc = proto_tree_add_text(tree,
+                                      tvb,
+                                      offset,
+                                      (gint)querylen - (gint)toc_offset,
+                                      "Complex types ToC (%u entries)",
+                                      toc_entries);
+       sub_tree_toc = proto_item_add_subtree(item_toc, ett_afp_spotlight_toc);
+       proto_tree_add_text(sub_tree_toc, tvb, offset, 2, "Number of entries (%u)", toc_entries);
+       proto_tree_add_text(sub_tree_toc, tvb, offset + 2, 2, "unknown");
+       proto_tree_add_text(sub_tree_toc, tvb, offset + 4, 4, "unknown");
+
+       offset += 8;
+       for (i = 0; i < toc_entries; i++, offset += 8) {
+               toc_entry = spotlight_ntoh64(tvb, offset, encoding);
+               if ((((toc_entry & 0xffff0000) >> 16) == SQ_CPX_TYPE_ARRAY)
+                   || (((toc_entry & 0xffff0000) >> 16) == SQ_CPX_TYPE_DICT)) {
+                       proto_tree_add_text(sub_tree_toc,
+                                           tvb,
+                                           offset,
+                                           8,
+                                           "%u: count: %" G_GINT64_MODIFIER "u, type: %s, offset: %" G_GINT64_MODIFIER "u",
+                                           i+1,
+                                           toc_entry >> 32,
+                                           spotlight_get_cpx_qtype_string((toc_entry & 0xffff0000) >> 16),
+                                           (toc_entry & 0xffff) * 8);
+               } else if ((((toc_entry & 0xffff0000) >> 16) == SQ_CPX_TYPE_STRING)
+                       || (((toc_entry & 0xffff0000) >> 16) == SQ_CPX_TYPE_UTF16_STRING)) {
+                       proto_tree_add_text(sub_tree_toc,
+                                           tvb,
+                                           offset,
+                                           8,
+                                           "%u: pad byte count: %" G_GINT64_MODIFIER "x, type: %s, offset: %" G_GINT64_MODIFIER "u",
+                                           i+1,
+                                           8 - (toc_entry >> 32),
+                                           spotlight_get_cpx_qtype_string((toc_entry & 0xffff0000) >> 16),
+                                           (toc_entry & 0xffff) * 8);
+               }
+               else {
+                       proto_tree_add_text(sub_tree_toc,
+                                           tvb,
+                                           offset,
+                                           8,
+                                           "%u: unknown: 0x%08" G_GINT64_MODIFIER "x, type: %s, offset: %" G_GINT64_MODIFIER "u",
+                                           i+1,
+                                           toc_entry >> 32,
+                                           spotlight_get_cpx_qtype_string((toc_entry & 0xffff0000) >> 16),
+                                           (toc_entry & 0xffff) * 8);
+               }
+
+
+       }
+
+       return offset;
+}
+#endif
+
+static DALLOC_CTX *unpack_spotlight(TALLOC_CTX *mem_ctx, char *ibuf, size_t ibuflen)
+{
+    EC_INIT;
+       int len;
+    DALLOC_CTX *query;
+
+    EC_NULL_LOG( query = talloc_zero(mem_ctx, DALLOC_CTX) );
+
+    ibuf++;
+    ibuflen--;
+
+
+EC_CLEANUP:
+    if (ret != 0) {
+        talloc_free(query);
+        query = NULL;
+    }
+       return query;
+}
+
+/**************************************************************************************************
+ * AFP functions
+ **************************************************************************************************/
+int afp_spotlight_rpc(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
+{
+    EC_INIT;
+    TALLOC_CTX *tmp_ctx = talloc_new(NULL);
+    uint16_t vid;
+    int cmd;
+    int endianess = SL_ENC_LITTLE_ENDIAN;
+    struct vol      *vol;
+
+    *rbuflen = 0;
+
+    ibuf += 2;
+    ibuflen -= 2;
+
+    vid = SVAL(ibuf, 0);
+    LOG(logtype_default, log_note, "afp_spotlight_rpc(vid: %" PRIu16 ")", vid);
+
+    if ((vol = getvolbyvid(vid)) == NULL) {
+        LOG(logtype_default, log_error, "afp_spotlight_rpc: bad volume id: %" PRIu16 ")", vid);
+        ret = AFPERR_ACCESS;
+        goto EC_CLEANUP;
+    }
+
+    /*    IVAL(ibuf, 2): unknown, always 0x00008004, some flags ? */
+
+    cmd = RIVAL(ibuf, 6);
+    LOG(logtype_default, log_note, "afp_spotlight_rpc(cmd: %d)", cmd);
+
+    /*    IVAL(ibuf, 10: unknown, always 0x00000000 */
+
+       switch (cmd) {
+
+       case SPOTLIGHT_CMD_VOLPATH: {
+        RSIVAL(rbuf, 0, ntohs(vid));
+        RSIVAL(rbuf, 4, 0);
+        int len = strlen(vol->v_path) + 1;
+        strncpy(rbuf + 8, vol->v_path, len);
+        *rbuflen += 8 + len;
+               break;
+    }
+       case SPOTLIGHT_CMD_FLAGS:
+               break;
+
+       case SPOTLIGHT_CMD_RPC:
+        /* IVAL(buf, 14): our reply in SPOTLIGHT_CMD_FLAGS */
+        /* IVAL(buf, 18): length */
+        /* IVAL(buf, 22): endianess, ignored, we assume little endian */
+               break;
+       }
+
+EC_CLEANUP:
+    talloc_free(tmp_ctx);
+    if (ret != AFP_OK) {
+        
+    }
+    EC_EXIT;
+}
+
+/**************************************************************************************************
+ * Testing
+ **************************************************************************************************/
+
 #ifdef SPOT_TEST_MAIN
 
 static const char *neststrings[] = {
index 671ac8d67cc251ec7045958482f70fa3e583102b..18d6bcdaed180f4ed4b83094f414ecbfba645766 100644 (file)
 #define SPOTLIGHT_H
 
 #include <atalk/dalloc.h>
+#include <atalk/globals.h>
 
+typedef DALLOC_CTX sl_array_t;    /* an array of elements                    */
+typedef DALLOC_CTX sl_dict_t;     /* an array of key/value elements          */
+typedef DALLOC_CTX sl_filemeta_t; /* an array of elements                    */
 typedef struct {
     uint16_t   ca_unkn1;
     uint32_t   ca_unkn2;
     DALLOC_CTX *ca_cnids;
-} cnid_array_t;
+} cnid_array_t;                   /* an array of CNID                        */
+
+extern int afp_spotlight_rpc(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen);
 
 #endif /* SPOTLIGHT_H */
index cc9a7f02a12bf580216e05fda91ec0c666b3c5f2..fccf9aa4c20adefc5545d5300bb4761c5a51114d 100644 (file)
@@ -74,6 +74,7 @@ reasoning behind them. byteorder.h defines the following macros:
 
 SVAL(buf,pos) - extract a 2 byte SMB value
 IVAL(buf,pos) - extract a 4 byte SMB value
+LVAL(buf,pos) - extract a 8 byte SMB value
 SVALS(buf,pos) signed version of SVAL()
 IVALS(buf,pos) signed version of IVAL()
 
@@ -118,6 +119,7 @@ it also defines lots of intermediate macros, just ignore those :-)
 
 #define SVAL(buf,pos) (PVAL(buf,(pos)+1)|PVAL(buf,pos)<<8)
 #define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
+#define LVAL(buf,pos) (IVAL(buf,pos)|IVAL(buf,(pos)+4)<<32)
 #define SSVALX(buf,pos,val) (CVAL_NC(buf,pos+1)=(unsigned char)((val)&0xFF),CVAL_NC(buf,pos)=(unsigned char)((val)>>8))
 #define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
 #define SVALS(buf,pos) ((int16)SVAL(buf,pos))
@@ -131,6 +133,7 @@ it also defines lots of intermediate macros, just ignore those :-)
 
 #define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
 #define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
+#define LVAL(buf,pos) (IVAL(buf,pos)|((uint64_t)IVAL(buf,(pos)+4))<<32)
 #define SSVALX(buf,pos,val) (CVAL_NC(buf,pos)=(unsigned char)((val)&0xFF),CVAL_NC(buf,pos+1)=(unsigned char)((val)>>8))
 #define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
 #define SVALS(buf,pos) ((int16)SVAL(buf,pos))
@@ -156,6 +159,7 @@ it also defines lots of intermediate macros, just ignore those :-)
 #define SVAL_NC(buf,pos) (*(uint16_t *)((char *)(buf) + (pos))) /* Non const version of above. */
 #define IVAL(buf,pos) (*(const uint32_t *)((const char *)(buf) + (pos)))
 #define IVAL_NC(buf,pos) (*(uint32_t *)((char *)(buf) + (pos))) /* Non const version of above. */
+#define LVAL(buf,pos) (*(const uint64_t *)((const char *)(buf) + (pos)))
 #define SVALS(buf,pos) (*(const int16_t *)((const char *)(buf) + (pos)))
 #define SVALS_NC(buf,pos) (*(int16 *)((char *)(buf) + (pos))) /* Non const version of above. */
 #define IVALS(buf,pos) (*(const int32_t *)((const char *)(buf) + (pos)))
@@ -172,11 +176,15 @@ it also defines lots of intermediate macros, just ignore those :-)
 /* now the reverse routines - these are used in nmb packets (mostly) */
 #define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
 #define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16)))
+#define LREV(x) ((IREV(x)<<32) | (IREV((x)>>32)))
 
 #define RSVAL(buf,pos) SREV(SVAL(buf,pos))
 #define RSVALS(buf,pos) SREV(SVALS(buf,pos))
 #define RIVAL(buf,pos) IREV(IVAL(buf,pos))
 #define RIVALS(buf,pos) IREV(IVALS(buf,pos))
+
+#define RLVAL(buf,pos) LREV(LVAL(buf,pos))
+
 #define RSSVAL(buf,pos,val) SSVAL(buf,pos,SREV(val))
 #define RSSVALS(buf,pos,val) SSVALS(buf,pos,SREV(val))
 #define RSIVAL(buf,pos,val) SIVAL(buf,pos,IREV(val))