2 Unix SMB/CIFS implementation.
3 Main metadata server / Spotlight routines
5 Copyright (C) Ralph Boehme 2012-2014
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "marshalling.h"
26 #define DBGC_CLASS DBGC_RPC_SRV
29 * This is used to talloc an array that will hold the table of
30 * contents of a marshalled Spotlight RPC (S-RPC) reply. Each ToC
31 * entry is 8 bytes, so we allocate space for 1024 entries which
32 * should be sufficient for even the largest S-RPC replies.
34 * The total buffersize for S-RPC packets is typically limited to 64k,
35 * so we can only store so many elements there anyway.
37 #define MAX_SLQ_TOC 1024*64
38 #define MAX_SLQ_TOCIDX 1024*8
39 #define MAX_SLQ_COUNT 1024*64
40 #define MAX_SL_STRLEN 1024
42 /******************************************************************************
43 * RPC data marshalling and unmarshalling
44 ******************************************************************************/
46 /* Spotlight epoch is 1.1.2001 00:00 UTC */
47 #define SPOTLIGHT_TIME_DELTA 978307200 /* Diff from UNIX epoch to Spotlight epoch */
49 #define SQ_TYPE_NULL 0x0000
50 #define SQ_TYPE_COMPLEX 0x0200
51 #define SQ_TYPE_INT64 0x8400
52 #define SQ_TYPE_BOOL 0x0100
53 #define SQ_TYPE_FLOAT 0x8500
54 #define SQ_TYPE_DATA 0x0700
55 #define SQ_TYPE_CNIDS 0x8700
56 #define SQ_TYPE_UUID 0x0e00
57 #define SQ_TYPE_DATE 0x8600
58 #define SQ_TYPE_TOC 0x8800
60 #define SQ_CPX_TYPE_ARRAY 0x0a00
61 #define SQ_CPX_TYPE_STRING 0x0c00
62 #define SQ_CPX_TYPE_UTF16_STRING 0x1c00
63 #define SQ_CPX_TYPE_DICT 0x0d00
64 #define SQ_CPX_TYPE_CNIDS 0x1a00
65 #define SQ_CPX_TYPE_FILEMETA 0x1b00
74 static ssize_t
sl_pack_loop(DALLOC_CTX
*query
, char *buf
,
75 ssize_t offset
, size_t bufsize
,
76 char *toc_buf
, int *toc_idx
, int *count
);
77 static ssize_t
sl_unpack_loop(DALLOC_CTX
*query
, const char *buf
,
78 ssize_t offset
, size_t bufsize
,
79 int count
, ssize_t toc_offset
,
81 static ssize_t
sl_pack(DALLOC_CTX
*query
, char *buf
, size_t bufsize
);
83 /******************************************************************************
84 * Wrapper functions for the *VAL macros with bound checking
85 ******************************************************************************/
87 static ssize_t
sl_push_uint64_val(char *buf
,
92 if (offset
+ 8 > max_offset
) {
93 DEBUG(1, ("%s: offset: %zd, max_offset: %zu\n",
94 __func__
, offset
, max_offset
));
98 SBVAL(buf
, offset
, val
);
102 static ssize_t
sl_pull_uint64_val(const char *buf
,
110 if (offset
+ 8 > bufsize
) {
111 DEBUG(1,("%s: buffer overflow\n", __func__
));
115 if (encoding
== SL_ENC_LITTLE_ENDIAN
) {
116 val
= BVAL(buf
, offset
);
118 val
= RBVAL(buf
, offset
);
127 * Returns the UTF-16 string encoding, by checking the 2-byte byte order mark.
128 * If there is no byte order mark, -1 is returned.
130 static int spotlight_get_utf16_string_encoding(const char *buf
, ssize_t offset
,
131 size_t query_length
, int encoding
)
135 /* Assumed encoding in absence of a bom is little endian */
136 utf16_encoding
= SL_ENC_LITTLE_ENDIAN
;
138 if (query_length
>= 2) {
139 uint8_t le_bom
[] = {0xff, 0xfe};
140 uint8_t be_bom
[] = {0xfe, 0xff};
141 if (memcmp(le_bom
, buf
+ offset
, sizeof(uint16_t)) == 0) {
142 utf16_encoding
= SL_ENC_LITTLE_ENDIAN
| SL_ENC_UTF_16
;
143 } else if (memcmp(be_bom
, buf
+ offset
, sizeof(uint16_t)) == 0) {
144 utf16_encoding
= SL_ENC_BIG_ENDIAN
| SL_ENC_UTF_16
;
148 return utf16_encoding
;
151 /******************************************************************************
152 * marshalling functions
153 ******************************************************************************/
155 static inline uint64_t sl_pack_tag(uint16_t type
, uint16_t size_or_count
, uint32_t val
)
157 uint64_t tag
= ((uint64_t)val
<< 32) | ((uint64_t)type
<< 16) | size_or_count
;
161 static ssize_t
sl_pack_float(double d
, char *buf
, ssize_t offset
, size_t bufsize
)
170 offset
= sl_push_uint64_val(buf
, offset
, bufsize
, sl_pack_tag(SQ_TYPE_FLOAT
, 2, 1));
174 offset
= sl_push_uint64_val(buf
, offset
, bufsize
, ieee_fp_union
.w
);
182 static ssize_t
sl_pack_uint64(uint64_t u
, char *buf
, ssize_t offset
, size_t bufsize
)
186 tag
= sl_pack_tag(SQ_TYPE_INT64
, 2, 1);
187 offset
= sl_push_uint64_val(buf
, offset
, bufsize
, tag
);
191 offset
= sl_push_uint64_val(buf
, offset
, bufsize
, u
);
199 static ssize_t
sl_pack_uint64_array(uint64_t *u
, char *buf
, ssize_t offset
, size_t bufsize
, int *toc_count
)
204 count
= talloc_array_length(u
);
206 tag
= sl_pack_tag(SQ_TYPE_INT64
, count
+ 1, count
);
207 offset
= sl_push_uint64_val(buf
, offset
, bufsize
, tag
);
212 for (i
= 0; i
< count
; i
++) {
213 offset
= sl_push_uint64_val(buf
, offset
, bufsize
, u
[i
]);
220 *toc_count
+= (count
- 1);
226 static ssize_t
sl_pack_bool(sl_bool_t val
, char *buf
, ssize_t offset
, size_t bufsize
)
230 tag
= sl_pack_tag(SQ_TYPE_BOOL
, 1, val
? 1 : 0);
231 offset
= sl_push_uint64_val(buf
, offset
, bufsize
, tag
);
239 static ssize_t
sl_pack_nil(char *buf
, ssize_t offset
, size_t bufsize
)
243 tag
= sl_pack_tag(SQ_TYPE_NULL
, 1, 1);
244 offset
= sl_push_uint64_val(buf
, offset
, bufsize
, tag
);
252 static ssize_t
sl_pack_date(sl_time_t t
, char *buf
, ssize_t offset
, size_t bufsize
)
261 tag
= sl_pack_tag(SQ_TYPE_DATE
, 2, 1);
262 offset
= sl_push_uint64_val(buf
, offset
, bufsize
, tag
);
267 ieee_fp_union
.d
= (double)(t
.tv_sec
- SPOTLIGHT_TIME_DELTA
);
268 ieee_fp_union
.d
+= (double)t
.tv_usec
/ 1000000;
270 data
= ieee_fp_union
.w
;
271 offset
= sl_push_uint64_val(buf
, offset
, bufsize
, data
);
279 static ssize_t
sl_pack_uuid(sl_uuid_t
*uuid
, char *buf
, ssize_t offset
, size_t bufsize
)
283 tag
= sl_pack_tag(SQ_TYPE_UUID
, 3, 1);
284 offset
= sl_push_uint64_val(buf
, offset
, bufsize
, tag
);
289 if (offset
+ 16 > bufsize
) {
292 memcpy(buf
+ offset
, uuid
, 16);
297 static ssize_t
sl_pack_CNID(sl_cnids_t
*cnids
, char *buf
, ssize_t offset
,
298 size_t bufsize
, char *toc_buf
, int *toc_idx
)
302 int cnid_count
= dalloc_size(cnids
->ca_cnids
);
307 tag
= sl_pack_tag(SQ_CPX_TYPE_CNIDS
, offset
/ 8, 0);
308 result
= sl_push_uint64_val(toc_buf
, *toc_idx
* 8, MAX_SLQ_TOC
, tag
);
313 tag
= sl_pack_tag(SQ_TYPE_COMPLEX
, 1, *toc_idx
+ 1);
314 offset
= sl_push_uint64_val(buf
, offset
, bufsize
, tag
);
321 len
= cnid_count
+ 1;
322 if (cnid_count
> 0) {
326 /* unknown meaning, but always 8 */
327 tag
= sl_pack_tag(SQ_TYPE_CNIDS
, len
, 8 );
328 offset
= sl_push_uint64_val(buf
, offset
, bufsize
, tag
);
333 if (cnid_count
> 0) {
334 tag
= sl_pack_tag(cnids
->ca_unkn1
, cnid_count
, cnids
->ca_context
);
335 offset
= sl_push_uint64_val(buf
, offset
, bufsize
, tag
);
340 for (i
= 0; i
< cnid_count
; i
++) {
341 p
= dalloc_get_object(cnids
->ca_cnids
, i
);
345 memcpy(&id
, p
, sizeof(uint64_t));
346 offset
= sl_push_uint64_val(buf
, offset
, bufsize
, id
);
356 static ssize_t
sl_pack_array(sl_array_t
*array
, char *buf
, ssize_t offset
,
357 size_t bufsize
, char *toc_buf
, int *toc_idx
)
360 int count
= dalloc_size(array
);
361 int octets
= offset
/ 8;
363 int toc_idx_save
= *toc_idx
;
365 tag
= sl_pack_tag(SQ_TYPE_COMPLEX
, 1, *toc_idx
+ 1);
366 offset
= sl_push_uint64_val(buf
, offset
, bufsize
, tag
);
373 offset
= sl_pack_loop(array
, buf
, offset
, bufsize
- offset
, toc_buf
, toc_idx
, &count
);
375 tag
= sl_pack_tag(SQ_CPX_TYPE_ARRAY
, octets
, count
);
376 result
= sl_push_uint64_val(toc_buf
, toc_idx_save
* 8, MAX_SLQ_TOC
, tag
);
384 static ssize_t
sl_pack_dict(sl_array_t
*dict
, char *buf
, ssize_t offset
,
385 size_t bufsize
, char *toc_buf
, int *toc_idx
, int *count
)
390 tag
= sl_pack_tag(SQ_CPX_TYPE_DICT
, offset
/ 8,
392 result
= sl_push_uint64_val(toc_buf
, *toc_idx
* 8, MAX_SLQ_TOC
, tag
);
397 tag
= sl_pack_tag(SQ_TYPE_COMPLEX
, 1, *toc_idx
+ 1);
398 offset
= sl_push_uint64_val(buf
, offset
, bufsize
, tag
);
405 offset
= sl_pack_loop(dict
, buf
, offset
, bufsize
- offset
, toc_buf
, toc_idx
, count
);
410 static ssize_t
sl_pack_filemeta(sl_filemeta_t
*fm
, char *buf
, ssize_t offset
,
411 size_t bufsize
, char *toc_buf
, int *toc_idx
)
415 ssize_t saveoff
= offset
;
418 tag
= sl_pack_tag(SQ_TYPE_COMPLEX
, 1, *toc_idx
+ 1);
419 offset
= sl_push_uint64_val(buf
, offset
, bufsize
, tag
);
426 fmlen
= sl_pack(fm
, buf
+ offset
, bufsize
- offset
);
432 * Check for empty filemeta array, if it's only 40 bytes, it's
433 * only the header but no content
441 /* unknown meaning, but always 8 */
442 tag
= sl_pack_tag(SQ_TYPE_DATA
, (fmlen
/ 8) + 1, 8);
443 result
= sl_push_uint64_val(buf
, saveoff
+ 8, bufsize
, tag
);
448 tag
= sl_pack_tag(SQ_CPX_TYPE_FILEMETA
, saveoff
/ 8, fmlen
/ 8);
449 result
= sl_push_uint64_val(toc_buf
, *toc_idx
* 8, MAX_SLQ_TOC
, tag
);
459 static ssize_t
sl_pack_string(char *s
, char *buf
, ssize_t offset
, size_t bufsize
,
460 char *toc_buf
, int *toc_idx
)
463 size_t len
, octets
, used_in_last_octet
;
467 if (len
> MAX_SL_STRLEN
) {
470 octets
= (len
+ 7) / 8;
471 used_in_last_octet
= len
% 8;
472 if (used_in_last_octet
== 0) {
473 used_in_last_octet
= 8;
476 tag
= sl_pack_tag(SQ_CPX_TYPE_STRING
, offset
/ 8, used_in_last_octet
);
477 result
= sl_push_uint64_val(toc_buf
, *toc_idx
* 8, MAX_SLQ_TOC
, tag
);
482 tag
= sl_pack_tag(SQ_TYPE_COMPLEX
, 1, *toc_idx
+ 1);
483 offset
= sl_push_uint64_val(buf
, offset
, bufsize
, tag
);
490 tag
= sl_pack_tag(SQ_TYPE_DATA
, octets
+ 1, used_in_last_octet
);
491 offset
= sl_push_uint64_val(buf
, offset
, bufsize
, tag
);
496 if (offset
+ (octets
* 8) > bufsize
) {
500 memset(buf
+ offset
, 0, octets
* 8);
501 memcpy(buf
+ offset
, s
, len
);
502 offset
+= octets
* 8;
507 static ssize_t
sl_pack_string_as_utf16(char *s
, char *buf
, ssize_t offset
,
508 size_t bufsize
, char *toc_buf
, int *toc_idx
)
511 int utf16_plus_bom_len
, octets
, used_in_last_octet
;
512 char *utf16string
= NULL
;
513 char bom
[] = { 0xff, 0xfe };
514 size_t slen
, utf16len
;
519 if (slen
> MAX_SL_STRLEN
) {
523 ok
= convert_string_talloc(talloc_tos(),
534 utf16_plus_bom_len
= utf16len
+ 2;
535 octets
= (utf16_plus_bom_len
+ 7) / 8;
536 used_in_last_octet
= utf16_plus_bom_len
% 8;
537 if (used_in_last_octet
== 0) {
538 used_in_last_octet
= 8;
541 tag
= sl_pack_tag(SQ_CPX_TYPE_UTF16_STRING
, offset
/ 8, used_in_last_octet
);
542 result
= sl_push_uint64_val(toc_buf
, *toc_idx
* 8, MAX_SLQ_TOC
, tag
);
548 tag
= sl_pack_tag(SQ_TYPE_COMPLEX
, 1, *toc_idx
+ 1);
549 offset
= sl_push_uint64_val(buf
, offset
, bufsize
, tag
);
556 tag
= sl_pack_tag(SQ_TYPE_DATA
, octets
+ 1, used_in_last_octet
);
557 offset
= sl_push_uint64_val(buf
, offset
, bufsize
, tag
);
562 if (offset
+ (octets
* 8) > bufsize
) {
567 memset(buf
+ offset
, 0, octets
* 8);
568 memcpy(buf
+ offset
, &bom
, sizeof(bom
));
569 memcpy(buf
+ offset
+ 2, utf16string
, utf16len
);
570 offset
+= octets
* 8;
573 TALLOC_FREE(utf16string
);
577 static ssize_t
sl_pack_loop(DALLOC_CTX
*query
, char *buf
, ssize_t offset
,
578 size_t bufsize
, char *toc_buf
, int *toc_idx
, int *count
)
588 for (n
= 0; n
< dalloc_size(query
); n
++) {
590 type
= dalloc_get_name(query
, n
);
594 p
= dalloc_get_object(query
, n
);
599 if (strcmp(type
, "sl_array_t") == 0) {
600 offset
= sl_pack_array(p
, buf
, offset
, bufsize
,
602 } else if (strcmp(type
, "sl_dict_t") == 0) {
603 offset
= sl_pack_dict(p
, buf
, offset
, bufsize
,
604 toc_buf
, toc_idx
, count
);
605 } else if (strcmp(type
, "sl_filemeta_t") == 0) {
606 offset
= sl_pack_filemeta(p
, buf
, offset
, bufsize
,
608 } else if (strcmp(type
, "uint64_t") == 0) {
609 memcpy(&i
, p
, sizeof(uint64_t));
610 offset
= sl_pack_uint64(i
, buf
, offset
, bufsize
);
611 } else if (strcmp(type
, "uint64_t *") == 0) {
612 offset
= sl_pack_uint64_array(p
, buf
, offset
,
614 } else if (strcmp(type
, "char *") == 0) {
615 offset
= sl_pack_string(p
, buf
, offset
, bufsize
,
617 } else if (strcmp(type
, "smb_ucs2_t *") == 0) {
618 offset
= sl_pack_string_as_utf16(p
, buf
, offset
, bufsize
,
620 } else if (strcmp(type
, "sl_bool_t") == 0) {
621 memcpy(&bl
, p
, sizeof(sl_bool_t
));
622 offset
= sl_pack_bool(bl
, buf
, offset
, bufsize
);
623 } else if (strcmp(type
, "double") == 0) {
624 memcpy(&d
, p
, sizeof(double));
625 offset
= sl_pack_float(d
, buf
, offset
, bufsize
);
626 } else if (strcmp(type
, "sl_nil_t") == 0) {
627 offset
= sl_pack_nil(buf
, offset
, bufsize
);
628 } else if (strcmp(type
, "sl_time_t") == 0) {
629 memcpy(&t
, p
, sizeof(sl_time_t
));
630 offset
= sl_pack_date(t
, buf
, offset
, bufsize
);
631 } else if (strcmp(type
, "sl_uuid_t") == 0) {
632 offset
= sl_pack_uuid(p
, buf
, offset
, bufsize
);
633 } else if (strcmp(type
, "sl_cnids_t") == 0) {
634 offset
= sl_pack_CNID(p
, buf
, offset
,
635 bufsize
, toc_buf
, toc_idx
);
637 DEBUG(1, ("unknown type: %s\n", type
));
641 DEBUG(1, ("error packing type: %s\n", type
));
649 /******************************************************************************
650 * unmarshalling functions
651 ******************************************************************************/
653 static ssize_t
sl_unpack_tag(const char *buf
,
661 if (offset
+ 8 > bufsize
) {
662 DEBUG(1,("%s: buffer overflow\n", __func__
));
666 if (encoding
== SL_ENC_LITTLE_ENDIAN
) {
667 val
= BVAL(buf
, offset
);
669 val
= RBVAL(buf
, offset
);
672 tag
->size
= (val
& 0xffff) * 8;
673 tag
->type
= (val
& 0xffff0000) >> 16;
674 tag
->count
= val
>> 32;
675 tag
->length
= tag
->count
* 8;
677 if (tag
->size
> MAX_MDSCMD_SIZE
) {
678 DEBUG(1,("%s: size limit %zu\n", __func__
, tag
->size
));
682 if (tag
->length
> MAX_MDSCMD_SIZE
) {
683 DEBUG(1,("%s: length limit %zu\n", __func__
, tag
->length
));
687 if (tag
->count
> MAX_SLQ_COUNT
) {
688 DEBUG(1,("%s: count limit %d\n", __func__
, tag
->count
));
695 static int sl_unpack_ints(DALLOC_CTX
*query
,
703 uint64_t query_data64
;
705 offset
= sl_unpack_tag(buf
, offset
, bufsize
, encoding
, &tag
);
710 for (i
= 0; i
< tag
.count
; i
++) {
711 offset
= sl_pull_uint64_val(buf
, offset
, bufsize
, encoding
, &query_data64
);
715 result
= dalloc_add_copy(query
, &query_data64
, uint64_t);
724 static int sl_unpack_date(DALLOC_CTX
*query
,
732 uint64_t query_data64
;
740 offset
= sl_unpack_tag(buf
, offset
, bufsize
, encoding
, &tag
);
745 for (i
= 0; i
< tag
.count
; i
++) {
746 offset
= sl_pull_uint64_val(buf
, offset
, bufsize
, encoding
, &query_data64
);
750 ieee_fp_union
.w
= query_data64
;
751 fraction
= ieee_fp_union
.d
- (uint64_t)ieee_fp_union
.d
;
754 .tv_sec
= ieee_fp_union
.d
+ SPOTLIGHT_TIME_DELTA
,
755 .tv_usec
= fraction
* 1000000
758 result
= dalloc_add_copy(query
, &t
, sl_time_t
);
767 static int sl_unpack_uuid(DALLOC_CTX
*query
,
777 offset
= sl_unpack_tag(buf
, offset
, bufsize
, encoding
, &tag
);
782 for (i
= 0; i
< tag
.count
; i
++) {
783 if (offset
+ 16 > bufsize
) {
784 DEBUG(1,("%s: buffer overflow\n", __func__
));
787 memcpy(uuid
.sl_uuid
, buf
+ offset
, 16);
788 result
= dalloc_add_copy(query
, &uuid
, sl_uuid_t
);
798 static int sl_unpack_floats(DALLOC_CTX
*query
,
811 offset
= sl_unpack_tag(buf
, offset
, bufsize
, encoding
, &tag
);
816 for (i
= 0; i
< tag
.count
; i
++) {
817 if (offset
+ 8 > bufsize
) {
818 DEBUG(1,("%s: buffer overflow\n", __func__
));
821 if (encoding
== SL_ENC_LITTLE_ENDIAN
) {
822 #ifdef WORDS_BIGENDIAN
823 ieee_fp_union
.w
[0] = IVAL(buf
, offset
+ 4);
824 ieee_fp_union
.w
[1] = IVAL(buf
, offset
);
826 ieee_fp_union
.w
[0] = IVAL(buf
, offset
);
827 ieee_fp_union
.w
[1] = IVAL(buf
, offset
+ 4);
830 #ifdef WORDS_BIGENDIAN
831 ieee_fp_union
.w
[0] = RIVAL(buf
, offset
);
832 ieee_fp_union
.w
[1] = RIVAL(buf
, offset
+ 4);
834 ieee_fp_union
.w
[0] = RIVAL(buf
, offset
+ 4);
835 ieee_fp_union
.w
[1] = RIVAL(buf
, offset
);
838 result
= dalloc_add_copy(query
, &ieee_fp_union
.d
, double);
848 static int sl_unpack_CNID(DALLOC_CTX
*query
,
855 int i
, count
, result
;
856 uint64_t query_data64
;
859 cnids
= talloc_zero(query
, sl_cnids_t
);
863 cnids
->ca_cnids
= dalloc_new(cnids
);
864 if (cnids
->ca_cnids
== NULL
) {
873 * That's permitted, length=8 is an empty CNID array.
875 result
= dalloc_add(query
, cnids
, sl_cnids_t
);
882 offset
= sl_pull_uint64_val(buf
, offset
, bufsize
, encoding
, &query_data64
);
888 * Note: ca_unkn1 and ca_context could be taken from the tag
889 * type and count members, but the fields are packed
890 * differently in this context, so we can't use
893 count
= query_data64
& 0xffff;;
894 cnids
->ca_unkn1
= (query_data64
& 0xffff0000) >> 16;
895 cnids
->ca_context
= query_data64
>> 32;
897 for (i
= 0; i
< count
; i
++) {
898 offset
= sl_pull_uint64_val(buf
, offset
, bufsize
, encoding
, &query_data64
);
903 result
= dalloc_add_copy(cnids
->ca_cnids
, &query_data64
, uint64_t);
909 result
= dalloc_add(query
, cnids
, sl_cnids_t
);
917 static ssize_t
sl_unpack_cpx(DALLOC_CTX
*query
,
927 ssize_t roffset
= offset
;
928 int unicode_encoding
;
931 size_t slen
, tmp_len
;
932 sl_array_t
*sl_array
;
934 sl_filemeta_t
*sl_fm
;
938 switch (cpx_query_type
) {
939 case SQ_CPX_TYPE_ARRAY
:
940 sl_array
= dalloc_zero(query
, sl_array_t
);
941 if (sl_array
== NULL
) {
944 roffset
= sl_unpack_loop(sl_array
, buf
, offset
, bufsize
,
945 cpx_query_count
, toc_offset
, encoding
);
949 result
= dalloc_add(query
, sl_array
, sl_array_t
);
955 case SQ_CPX_TYPE_DICT
:
956 sl_dict
= dalloc_zero(query
, sl_dict_t
);
957 if (sl_dict
== NULL
) {
960 roffset
= sl_unpack_loop(sl_dict
, buf
, offset
, bufsize
,
961 cpx_query_count
, toc_offset
, encoding
);
965 result
= dalloc_add(query
, sl_dict
, sl_dict_t
);
971 case SQ_CPX_TYPE_STRING
:
972 case SQ_CPX_TYPE_UTF16_STRING
:
973 offset
= sl_unpack_tag(buf
, offset
, bufsize
, encoding
, &tag
);
979 DEBUG(1,("%s: string buffer too small\n", __func__
));
982 slen
= tag
.size
- 16 + tag
.count
;
983 if (slen
> MAX_MDSCMD_SIZE
) {
987 if (offset
+ slen
> bufsize
) {
988 DEBUG(1,("%s: buffer overflow\n", __func__
));
992 if (cpx_query_type
== SQ_CPX_TYPE_STRING
) {
993 p
= talloc_strndup(query
, buf
+ offset
, slen
);
998 unicode_encoding
= spotlight_get_utf16_string_encoding(
999 buf
, offset
, slen
, encoding
);
1000 mark_exists
= (unicode_encoding
& SL_ENC_UTF_16
) ? true : false;
1001 if (unicode_encoding
& SL_ENC_BIG_ENDIAN
) {
1002 DEBUG(1, ("Unsupported big endian UTF16 string\n"));
1005 slen
-= mark_exists
? 2 : 0;
1006 ok
= convert_string_talloc(
1010 buf
+ offset
+ (mark_exists
? 2 : 0),
1019 result
= dalloc_stradd(query
, p
);
1023 roffset
+= tag
.size
;
1026 case SQ_CPX_TYPE_FILEMETA
:
1027 offset
= sl_unpack_tag(buf
, offset
, bufsize
, encoding
, &tag
);
1032 DBG_WARNING("size too mall: %zu\n", tag
.size
);
1036 sl_fm
= dalloc_zero(query
, sl_filemeta_t
);
1037 if (sl_fm
== NULL
) {
1041 if (tag
.size
>= 16) {
1042 result
= sl_unpack(sl_fm
,
1049 result
= dalloc_add(query
, sl_fm
, sl_filemeta_t
);
1053 roffset
+= tag
.size
;
1056 case SQ_CPX_TYPE_CNIDS
:
1057 offset
= sl_unpack_tag(buf
, offset
, bufsize
, encoding
, &tag
);
1062 result
= sl_unpack_CNID(query
, buf
, offset
, bufsize
,
1063 tag
.size
, encoding
);
1067 roffset
+= tag
.size
;
1071 DEBUG(1, ("unknown complex query type: %u\n", cpx_query_type
));
1078 static ssize_t
sl_unpack_loop(DALLOC_CTX
*query
,
1086 int i
, toc_index
, subcount
;
1092 if (offset
>= toc_offset
) {
1096 result
= sl_unpack_tag(buf
, offset
, bufsize
, encoding
, &tag
);
1102 case SQ_TYPE_COMPLEX
: {
1103 struct sl_tag cpx_tag
;
1105 if (tag
.count
< 1) {
1106 DEBUG(1,("%s: invalid tag.count: %d\n",
1107 __func__
, tag
.count
));
1110 toc_index
= tag
.count
- 1;
1111 if (toc_index
> MAX_SLQ_TOCIDX
) {
1112 DEBUG(1,("%s: toc_index too large: %d\n",
1113 __func__
, toc_index
));
1116 result
= sl_unpack_tag(buf
, toc_offset
+ (toc_index
* 8),
1117 bufsize
, encoding
, &cpx_tag
);
1122 offset
= sl_unpack_cpx(query
, buf
, offset
+ 8, bufsize
, cpx_tag
.type
,
1123 cpx_tag
.count
, toc_offset
, encoding
);
1128 * tag.size is not the size here, so we need
1129 * to use the offset returned from sl_unpack_cpx()
1130 * instead of offset += tag.size;
1136 case SQ_TYPE_NULL
: {
1139 subcount
= tag
.count
;
1140 if (subcount
< 1 || subcount
> count
) {
1143 for (i
= 0; i
< subcount
; i
++) {
1144 result
= dalloc_add_copy(query
, &nil
, sl_nil_t
);
1154 case SQ_TYPE_BOOL
: {
1155 sl_bool_t b
= (tag
.count
!= 0);
1157 result
= dalloc_add_copy(query
, &b
, sl_bool_t
);
1167 subcount
= sl_unpack_ints(query
, buf
, offset
, bufsize
, encoding
);
1168 if (subcount
< 1 || subcount
> count
) {
1176 subcount
= sl_unpack_uuid(query
, buf
, offset
, bufsize
, encoding
);
1177 if (subcount
< 1 || subcount
> count
) {
1185 subcount
= sl_unpack_floats(query
, buf
, offset
, bufsize
, encoding
);
1186 if (subcount
< 1 || subcount
> count
) {
1194 subcount
= sl_unpack_date(query
, buf
, offset
, bufsize
, encoding
);
1195 if (subcount
< 1 || subcount
> count
) {
1203 DEBUG(1, ("unknown query type: %d\n", tag
.type
));
1211 static ssize_t
sl_pack(DALLOC_CTX
*query
, char *buf
, size_t bufsize
)
1217 ssize_t offset
, len
;
1219 uint32_t total_octets
;
1220 uint32_t data_octets
;
1223 memset(buf
, 0, bufsize
);
1225 toc_buf
= talloc_zero_size(query
, MAX_SLQ_TOC
+ 8);
1226 if (toc_buf
== NULL
) {
1230 offset
= sl_pack_loop(query
, buf
, 16, bufsize
, toc_buf
+ 8, &toc_index
, &toc_count
);
1231 if (offset
== -1 || offset
< 16) {
1232 DEBUG(10,("%s: sl_pack_loop error\n", __func__
));
1238 * Marshalling overview:
1240 * 16 bytes at the start of buf:
1242 * 8 bytes byte order mark
1243 * 4 bytes total octets
1244 * 4 bytes table of content octets
1246 * x bytes total octets * 8 from sl_pack_loop
1247 * x bytes ToC octets * 8 from toc_buf
1250 /* Byte-order mark - we are using little endian only for now */
1251 memcpy(buf
, "432130dm", strlen("432130dm"));
1254 * The data buffer and ToC buffer sizes are enocoded in number
1255 * of octets (size / 8), plus one, because the octet encoding
1256 * the sizes is included.
1258 data_octets
= (len
/ 8) + 1;
1259 total_octets
= data_octets
+ toc_index
+ 1;
1262 hdr
|= ((uint64_t)data_octets
<< 32);
1265 result
= sl_push_uint64_val(buf
, 8, bufsize
, hdr
);
1271 * ToC tag with number of ToC entries plus one, the ToC tag
1274 tag
= sl_pack_tag(SQ_TYPE_TOC
, toc_index
+ 1, 0);
1275 result
= sl_push_uint64_val(toc_buf
, 0, MAX_SLQ_TOC
, tag
);
1280 if ((16 + len
+ ((toc_index
+ 1 ) * 8)) > bufsize
) {
1281 DEBUG(1, ("%s: exceeding size limit %zu\n", __func__
, bufsize
));
1285 memcpy(buf
+ 16 + len
, toc_buf
, (toc_index
+ 1 ) * 8);
1286 len
+= 16 + (toc_index
+ 1 ) * 8;
1291 /******************************************************************************
1292 * Global functions for packing und unpacking
1293 ******************************************************************************/
1295 NTSTATUS
sl_pack_alloc(TALLOC_CTX
*mem_ctx
,
1297 struct mdssvc_blob
*b
,
1298 size_t max_fragment_size
)
1302 b
->spotlight_blob
= talloc_zero_array(mem_ctx
,
1305 if (b
->spotlight_blob
== NULL
) {
1306 return NT_STATUS_NO_MEMORY
;
1309 len
= sl_pack(d
, (char *)b
->spotlight_blob
, max_fragment_size
);
1311 return NT_STATUS_DATA_ERROR
;
1316 return NT_STATUS_OK
;
1319 bool sl_unpack(DALLOC_CTX
*query
, const char *buf
, size_t bufsize
)
1325 uint32_t total_octets
;
1326 uint64_t total_bytes
;
1327 uint32_t data_octets
;
1328 uint64_t data_bytes
;
1329 uint64_t toc_offset
;
1330 struct sl_tag toc_tag
;
1332 if (bufsize
> MAX_MDSCMD_SIZE
) {
1339 if (strncmp(buf
+ offset
, "md031234", 8) == 0) {
1340 encoding
= SL_ENC_BIG_ENDIAN
;
1342 encoding
= SL_ENC_LITTLE_ENDIAN
;
1346 offset
= sl_pull_uint64_val(buf
, offset
, bufsize
, encoding
, &hdr
);
1351 total_octets
= hdr
& UINT32_MAX
;
1352 data_octets
= hdr
>> 32;
1355 * Both fields contain the number of octets of the
1356 * corresponding buffer plus the tag octet. We adjust the
1357 * values to match just the number of octets in the buffers.
1359 if (total_octets
< 1) {
1362 if (data_octets
< 1) {
1367 data_bytes
= ((uint64_t)data_octets
) * 8;
1368 total_bytes
= ((uint64_t)total_octets
) * 8;
1370 if (data_bytes
>= total_bytes
) {
1371 DEBUG(1,("%s: data_bytes: %" PRIu64
", total_bytes: %" PRIu64
"\n",
1372 __func__
, data_bytes
, total_bytes
));
1376 if (total_bytes
> (bufsize
- offset
)) {
1380 toc_offset
= data_bytes
;
1382 toc_offset
= sl_unpack_tag(buf
+ offset
, toc_offset
,
1383 bufsize
- offset
, encoding
, &toc_tag
);
1384 if (toc_offset
== -1) {
1388 if (toc_tag
.type
!= SQ_TYPE_TOC
) {
1389 DEBUG(1,("%s: unknown tag type %d\n", __func__
, toc_tag
.type
));
1394 * Check toc_tag.size even though we don't use it when unmarshalling
1396 if (toc_tag
.size
> MAX_SLQ_TOC
) {
1397 DEBUG(1,("%s: bad size %zu\n", __func__
, toc_tag
.size
));
1400 if (toc_tag
.size
> (total_bytes
- data_bytes
)) {
1401 DEBUG(1,("%s: bad size %zu\n", __func__
, toc_tag
.size
));
1405 if (toc_tag
.count
!= 0) {
1406 DEBUG(1,("%s: bad count %u\n", __func__
, toc_tag
.count
));
1411 * We already consumed 16 bytes from the buffer (BOM and size
1412 * tag), so we start at buf + offset.
1414 result
= sl_unpack_loop(query
, buf
+ offset
, 0, bufsize
- offset
,
1415 1, toc_offset
, encoding
);
1417 DEBUG(1,("%s: sl_unpack_loop failed\n", __func__
));