From eae87634ffb0a6e9257db3958ed0811148b959eb Mon Sep 17 00:00:00 2001 From: Frank Lahm Date: Sat, 9 Jun 2012 09:15:41 +0200 Subject: [PATCH] Import Spotlight dissector code from Wireshark --- etc/afpd/auth.c | 3 +- etc/afpd/spotlight.c | 698 +++++++++++++++++++++++++++++++++++++- etc/afpd/spotlight.h | 8 +- include/atalk/byteorder.h | 8 + 4 files changed, 714 insertions(+), 3 deletions(-) diff --git a/etc/afpd/auth.c b/etc/afpd/auth.c index 7569cfef..aa0fe873 100644 --- a/etc/afpd/auth.c +++ b/etc/afpd/auth.c @@ -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: diff --git a/etc/afpd/spotlight.c b/etc/afpd/spotlight.c index d9a5ad9f..2b6fb6ed 100644 --- a/etc/afpd/spotlight.c +++ b/etc/afpd/spotlight.c @@ -28,10 +28,706 @@ #include #include #include -#include +#include +#include +#include +#include #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[] = { diff --git a/etc/afpd/spotlight.h b/etc/afpd/spotlight.h index 671ac8d6..18d6bcda 100644 --- a/etc/afpd/spotlight.h +++ b/etc/afpd/spotlight.h @@ -20,11 +20,17 @@ #define SPOTLIGHT_H #include +#include +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 */ diff --git a/include/atalk/byteorder.h b/include/atalk/byteorder.h index cc9a7f02..fccf9aa4 100644 --- a/include/atalk/byteorder.h +++ b/include/atalk/byteorder.h @@ -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)) -- 2.39.2