Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 : Main metadata server / Spotlight routines
4 :
5 : Copyright (C) Ralph Boehme 2012-2014
6 :
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.
11 :
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.
16 :
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/>.
19 : */
20 :
21 : #include "includes.h"
22 : #include "dalloc.h"
23 : #include "marshalling.h"
24 :
25 : #undef DBGC_CLASS
26 : #define DBGC_CLASS DBGC_RPC_SRV
27 :
28 : /*
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.
33 : *
34 : * The total buffersize for S-RPC packets is typically limited to 64k,
35 : * so we can only store so many elements there anyway.
36 : */
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
41 :
42 : /******************************************************************************
43 : * RPC data marshalling and unmarshalling
44 : ******************************************************************************/
45 :
46 : /* Spotlight epoch is 1.1.2001 00:00 UTC */
47 : #define SPOTLIGHT_TIME_DELTA 978307200 /* Diff from UNIX epoch to Spotlight epoch */
48 :
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
59 :
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
66 :
67 : struct sl_tag {
68 : int type;
69 : int count;
70 : size_t length;
71 : size_t size;
72 : };
73 :
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,
80 : int encoding);
81 : static ssize_t sl_pack(DALLOC_CTX *query, char *buf, size_t bufsize);
82 :
83 : /******************************************************************************
84 : * Wrapper functions for the *VAL macros with bound checking
85 : ******************************************************************************/
86 :
87 1684 : static ssize_t sl_push_uint64_val(char *buf,
88 : ssize_t offset,
89 : size_t max_offset,
90 : uint64_t val)
91 : {
92 1684 : if (offset + 8 > max_offset) {
93 0 : DEBUG(1, ("%s: offset: %zd, max_offset: %zu\n",
94 : __func__, offset, max_offset));
95 0 : return -1;
96 : }
97 :
98 1684 : SBVAL(buf, offset, val);
99 1684 : return offset + 8;
100 : }
101 :
102 326 : static ssize_t sl_pull_uint64_val(const char *buf,
103 : ssize_t offset,
104 : size_t bufsize,
105 : uint encoding,
106 : uint64_t *presult)
107 : {
108 2 : uint64_t val;
109 :
110 326 : if (offset + 8 > bufsize) {
111 0 : DEBUG(1,("%s: buffer overflow\n", __func__));
112 0 : return -1;
113 : }
114 :
115 326 : if (encoding == SL_ENC_LITTLE_ENDIAN) {
116 326 : val = BVAL(buf, offset);
117 : } else {
118 0 : val = RBVAL(buf, offset);
119 : }
120 :
121 326 : *presult = val;
122 :
123 326 : return offset + 8;
124 : }
125 :
126 : /*
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.
129 : */
130 10 : static int spotlight_get_utf16_string_encoding(const char *buf, ssize_t offset,
131 : size_t query_length, int encoding)
132 : {
133 0 : int utf16_encoding;
134 :
135 : /* Assumed encoding in absence of a bom is little endian */
136 10 : utf16_encoding = SL_ENC_LITTLE_ENDIAN;
137 :
138 10 : if (query_length >= 2) {
139 10 : uint8_t le_bom[] = {0xff, 0xfe};
140 10 : uint8_t be_bom[] = {0xfe, 0xff};
141 10 : if (memcmp(le_bom, buf + offset, sizeof(uint16_t)) == 0) {
142 10 : utf16_encoding = SL_ENC_LITTLE_ENDIAN | SL_ENC_UTF_16;
143 0 : } else if (memcmp(be_bom, buf + offset, sizeof(uint16_t)) == 0) {
144 0 : utf16_encoding = SL_ENC_BIG_ENDIAN | SL_ENC_UTF_16;
145 : }
146 : }
147 :
148 10 : return utf16_encoding;
149 : }
150 :
151 : /******************************************************************************
152 : * marshalling functions
153 : ******************************************************************************/
154 :
155 1392 : static inline uint64_t sl_pack_tag(uint16_t type, uint16_t size_or_count, uint32_t val)
156 : {
157 1392 : uint64_t tag = ((uint64_t)val << 32) | ((uint64_t)type << 16) | size_or_count;
158 1392 : return tag;
159 : }
160 :
161 6 : static ssize_t sl_pack_float(double d, char *buf, ssize_t offset, size_t bufsize)
162 : {
163 0 : union {
164 : double d;
165 : uint64_t w;
166 : } ieee_fp_union;
167 :
168 6 : ieee_fp_union.d = d;
169 :
170 6 : offset = sl_push_uint64_val(buf, offset, bufsize, sl_pack_tag(SQ_TYPE_FLOAT, 2, 1));
171 6 : if (offset == -1) {
172 0 : return -1;
173 : }
174 6 : offset = sl_push_uint64_val(buf, offset, bufsize, ieee_fp_union.w);
175 6 : if (offset == -1) {
176 0 : return -1;
177 : }
178 :
179 6 : return offset;
180 : }
181 :
182 44 : static ssize_t sl_pack_uint64(uint64_t u, char *buf, ssize_t offset, size_t bufsize)
183 : {
184 0 : uint64_t tag;
185 :
186 44 : tag = sl_pack_tag(SQ_TYPE_INT64, 2, 1);
187 44 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
188 44 : if (offset == -1) {
189 0 : return -1;
190 : }
191 44 : offset = sl_push_uint64_val(buf, offset, bufsize, u);
192 44 : if (offset == -1) {
193 0 : return -1;
194 : }
195 :
196 44 : return offset;
197 : }
198 :
199 58 : static ssize_t sl_pack_uint64_array(uint64_t *u, char *buf, ssize_t offset, size_t bufsize, int *toc_count)
200 : {
201 0 : int count, i;
202 0 : uint64_t tag;
203 :
204 58 : count = talloc_array_length(u);
205 :
206 58 : tag = sl_pack_tag(SQ_TYPE_INT64, count + 1, count);
207 58 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
208 58 : if (offset == -1) {
209 0 : return -1;
210 : }
211 :
212 174 : for (i = 0; i < count; i++) {
213 116 : offset = sl_push_uint64_val(buf, offset, bufsize, u[i]);
214 116 : if (offset == -1) {
215 0 : return -1;
216 : }
217 : }
218 :
219 58 : if (count > 1) {
220 58 : *toc_count += (count - 1);
221 : }
222 :
223 58 : return offset;
224 : }
225 :
226 8 : static ssize_t sl_pack_bool(sl_bool_t val, char *buf, ssize_t offset, size_t bufsize)
227 : {
228 0 : uint64_t tag;
229 :
230 8 : tag = sl_pack_tag(SQ_TYPE_BOOL, 1, val ? 1 : 0);
231 8 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
232 8 : if (offset == -1) {
233 0 : return -1;
234 : }
235 :
236 8 : return offset;
237 : }
238 :
239 10 : static ssize_t sl_pack_nil(char *buf, ssize_t offset, size_t bufsize)
240 : {
241 0 : uint64_t tag;
242 :
243 10 : tag = sl_pack_tag(SQ_TYPE_NULL, 1, 1);
244 10 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
245 10 : if (offset == -1) {
246 0 : return -1;
247 : }
248 :
249 10 : return offset;
250 : }
251 :
252 0 : static ssize_t sl_pack_date(sl_time_t t, char *buf, ssize_t offset, size_t bufsize)
253 : {
254 0 : uint64_t data;
255 0 : uint64_t tag;
256 0 : union {
257 : double d;
258 : uint64_t w;
259 : } ieee_fp_union;
260 :
261 0 : tag = sl_pack_tag(SQ_TYPE_DATE, 2, 1);
262 0 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
263 0 : if (offset == -1) {
264 0 : return -1;
265 : }
266 :
267 0 : ieee_fp_union.d = (double)(t.tv_sec - SPOTLIGHT_TIME_DELTA);
268 0 : ieee_fp_union.d += (double)t.tv_usec / 1000000;
269 :
270 0 : data = ieee_fp_union.w;
271 0 : offset = sl_push_uint64_val(buf, offset, bufsize, data);
272 0 : if (offset == -1) {
273 0 : return -1;
274 : }
275 :
276 0 : return offset;
277 : }
278 :
279 4 : static ssize_t sl_pack_uuid(sl_uuid_t *uuid, char *buf, ssize_t offset, size_t bufsize)
280 : {
281 0 : uint64_t tag;
282 :
283 4 : tag = sl_pack_tag(SQ_TYPE_UUID, 3, 1);
284 4 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
285 4 : if (offset == -1) {
286 0 : return -1;
287 : }
288 :
289 4 : if (offset + 16 > bufsize) {
290 0 : return -1;
291 : }
292 4 : memcpy(buf + offset, uuid, 16);
293 :
294 4 : return offset + 16;
295 : }
296 :
297 38 : 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)
299 : {
300 0 : ssize_t result;
301 0 : int len, i;
302 38 : int cnid_count = dalloc_size(cnids->ca_cnids);
303 0 : uint64_t tag;
304 0 : uint64_t id;
305 0 : void *p;
306 :
307 38 : tag = sl_pack_tag(SQ_CPX_TYPE_CNIDS, offset / 8, 0);
308 38 : result = sl_push_uint64_val(toc_buf, *toc_idx * 8, MAX_SLQ_TOC, tag);
309 38 : if (result == -1) {
310 0 : return -1;
311 : }
312 :
313 38 : tag = sl_pack_tag(SQ_TYPE_COMPLEX, 1, *toc_idx + 1);
314 38 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
315 38 : if (offset == -1) {
316 0 : return -1;
317 : }
318 :
319 38 : *toc_idx += 1;
320 :
321 38 : len = cnid_count + 1;
322 38 : if (cnid_count > 0) {
323 36 : len ++;
324 : }
325 :
326 : /* unknown meaning, but always 8 */
327 38 : tag = sl_pack_tag(SQ_TYPE_CNIDS, len, 8 );
328 38 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
329 38 : if (offset == -1) {
330 0 : return -1;
331 : }
332 :
333 38 : if (cnid_count > 0) {
334 36 : tag = sl_pack_tag(cnids->ca_unkn1, cnid_count, cnids->ca_context);
335 36 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
336 36 : if (offset == -1) {
337 0 : return -1;
338 : }
339 :
340 74 : for (i = 0; i < cnid_count; i++) {
341 38 : p = dalloc_get_object(cnids->ca_cnids, i);
342 38 : if (p == NULL) {
343 0 : return -1;
344 : }
345 38 : memcpy(&id, p, sizeof(uint64_t));
346 38 : offset = sl_push_uint64_val(buf, offset, bufsize, id);
347 38 : if (offset == -1) {
348 0 : return -1;
349 : }
350 : }
351 : }
352 :
353 38 : return offset;
354 : }
355 :
356 196 : 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)
358 : {
359 0 : ssize_t result;
360 196 : int count = dalloc_size(array);
361 196 : int octets = offset / 8;
362 0 : uint64_t tag;
363 196 : int toc_idx_save = *toc_idx;
364 :
365 196 : tag = sl_pack_tag(SQ_TYPE_COMPLEX, 1, *toc_idx + 1);
366 196 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
367 196 : if (offset == -1) {
368 0 : return -1;
369 : }
370 :
371 196 : *toc_idx += 1;
372 :
373 196 : offset = sl_pack_loop(array, buf, offset, bufsize - offset, toc_buf, toc_idx, &count);
374 :
375 196 : tag = sl_pack_tag(SQ_CPX_TYPE_ARRAY, octets, count);
376 196 : result = sl_push_uint64_val(toc_buf, toc_idx_save * 8, MAX_SLQ_TOC, tag);
377 196 : if (result == -1) {
378 0 : return -1;
379 : }
380 :
381 196 : return offset;
382 : }
383 :
384 10 : 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)
386 : {
387 0 : ssize_t result;
388 0 : uint64_t tag;
389 :
390 10 : tag = sl_pack_tag(SQ_CPX_TYPE_DICT, offset / 8,
391 10 : dalloc_size(dict));
392 10 : result = sl_push_uint64_val(toc_buf, *toc_idx * 8, MAX_SLQ_TOC, tag);
393 10 : if (result == -1) {
394 0 : return -1;
395 : }
396 :
397 10 : tag = sl_pack_tag(SQ_TYPE_COMPLEX, 1, *toc_idx + 1);
398 10 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
399 10 : if (offset == -1) {
400 0 : return -1;
401 : }
402 :
403 10 : *toc_idx += 1;
404 :
405 10 : offset = sl_pack_loop(dict, buf, offset, bufsize - offset, toc_buf, toc_idx, count);
406 :
407 10 : return offset;
408 : }
409 :
410 10 : 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)
412 : {
413 0 : ssize_t result;
414 0 : ssize_t fmlen;
415 10 : ssize_t saveoff = offset;
416 0 : uint64_t tag;
417 :
418 10 : tag = sl_pack_tag(SQ_TYPE_COMPLEX, 1, *toc_idx + 1);
419 10 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
420 10 : if (offset == -1) {
421 0 : return -1;
422 : }
423 :
424 10 : offset += 8;
425 :
426 10 : fmlen = sl_pack(fm, buf + offset, bufsize - offset);
427 10 : if (fmlen == -1) {
428 0 : return -1;
429 : }
430 :
431 : /*
432 : * Check for empty filemeta array, if it's only 40 bytes, it's
433 : * only the header but no content
434 : */
435 10 : if (fmlen > 40) {
436 8 : offset += fmlen;
437 : } else {
438 2 : fmlen = 0;
439 : }
440 :
441 : /* unknown meaning, but always 8 */
442 10 : tag = sl_pack_tag(SQ_TYPE_DATA, (fmlen / 8) + 1, 8);
443 10 : result = sl_push_uint64_val(buf, saveoff + 8, bufsize, tag);
444 10 : if (result == -1) {
445 0 : return -1;
446 : }
447 :
448 10 : tag = sl_pack_tag(SQ_CPX_TYPE_FILEMETA, saveoff / 8, fmlen / 8);
449 10 : result = sl_push_uint64_val(toc_buf, *toc_idx * 8, MAX_SLQ_TOC, tag);
450 10 : if (result == -1) {
451 0 : return -1;
452 : }
453 :
454 10 : *toc_idx += 1;
455 :
456 10 : return offset;
457 : }
458 :
459 192 : static ssize_t sl_pack_string(char *s, char *buf, ssize_t offset, size_t bufsize,
460 : char *toc_buf, int *toc_idx)
461 : {
462 0 : ssize_t result;
463 0 : size_t len, octets, used_in_last_octet;
464 0 : uint64_t tag;
465 :
466 192 : len = strlen(s);
467 192 : if (len > MAX_SL_STRLEN) {
468 0 : return -1;
469 : }
470 192 : octets = (len + 7) / 8;
471 192 : used_in_last_octet = len % 8;
472 192 : if (used_in_last_octet == 0) {
473 14 : used_in_last_octet = 8;
474 : }
475 :
476 192 : tag = sl_pack_tag(SQ_CPX_TYPE_STRING, offset / 8, used_in_last_octet);
477 192 : result = sl_push_uint64_val(toc_buf, *toc_idx * 8, MAX_SLQ_TOC, tag);
478 192 : if (result == -1) {
479 0 : return -1;
480 : }
481 :
482 192 : tag = sl_pack_tag(SQ_TYPE_COMPLEX, 1, *toc_idx + 1);
483 192 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
484 192 : if (offset == -1) {
485 0 : return -1;
486 : }
487 :
488 192 : *toc_idx += 1;
489 :
490 192 : tag = sl_pack_tag(SQ_TYPE_DATA, octets + 1, used_in_last_octet);
491 192 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
492 192 : if (offset == -1) {
493 0 : return -1;
494 : }
495 :
496 192 : if (offset + (octets * 8) > bufsize) {
497 0 : return -1;
498 : }
499 :
500 192 : memset(buf + offset, 0, octets * 8);
501 192 : memcpy(buf + offset, s, len);
502 192 : offset += octets * 8;
503 :
504 192 : return offset;
505 : }
506 :
507 2 : 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)
509 : {
510 0 : ssize_t result;
511 0 : int utf16_plus_bom_len, octets, used_in_last_octet;
512 2 : char *utf16string = NULL;
513 2 : char bom[] = { 0xff, 0xfe };
514 0 : size_t slen, utf16len;
515 0 : uint64_t tag;
516 0 : bool ok;
517 :
518 2 : slen = strlen(s);
519 2 : if (slen > MAX_SL_STRLEN) {
520 0 : return -1;
521 : }
522 :
523 2 : ok = convert_string_talloc(talloc_tos(),
524 : CH_UTF8,
525 : CH_UTF16LE,
526 : s,
527 : slen,
528 : &utf16string,
529 : &utf16len);
530 2 : if (!ok) {
531 0 : return -1;
532 : }
533 :
534 2 : utf16_plus_bom_len = utf16len + 2;
535 2 : octets = (utf16_plus_bom_len + 7) / 8;
536 2 : used_in_last_octet = utf16_plus_bom_len % 8;
537 2 : if (used_in_last_octet == 0) {
538 0 : used_in_last_octet = 8;
539 : }
540 :
541 2 : tag = sl_pack_tag(SQ_CPX_TYPE_UTF16_STRING, offset / 8, used_in_last_octet);
542 2 : result = sl_push_uint64_val(toc_buf, *toc_idx * 8, MAX_SLQ_TOC, tag);
543 2 : if (result == -1) {
544 0 : offset = -1;
545 0 : goto done;
546 : }
547 :
548 2 : tag = sl_pack_tag(SQ_TYPE_COMPLEX, 1, *toc_idx + 1);
549 2 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
550 2 : if (offset == -1) {
551 0 : goto done;
552 : }
553 :
554 2 : *toc_idx += 1;
555 :
556 2 : tag = sl_pack_tag(SQ_TYPE_DATA, octets + 1, used_in_last_octet);
557 2 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
558 2 : if (offset == -1) {
559 0 : goto done;
560 : }
561 :
562 2 : if (offset + (octets * 8) > bufsize) {
563 0 : offset = -1;
564 0 : goto done;
565 : }
566 :
567 2 : memset(buf + offset, 0, octets * 8);
568 2 : memcpy(buf + offset, &bom, sizeof(bom));
569 2 : memcpy(buf + offset + 2, utf16string, utf16len);
570 2 : offset += octets * 8;
571 :
572 2 : done:
573 2 : TALLOC_FREE(utf16string);
574 2 : return offset;
575 : }
576 :
577 294 : 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)
579 : {
580 0 : const char *type;
581 0 : int n;
582 0 : uint64_t i;
583 0 : sl_bool_t bl;
584 0 : double d;
585 0 : sl_time_t t;
586 0 : void *p;
587 :
588 872 : for (n = 0; n < dalloc_size(query); n++) {
589 :
590 578 : type = dalloc_get_name(query, n);
591 578 : if (type == NULL) {
592 0 : return -1;
593 : }
594 578 : p = dalloc_get_object(query, n);
595 578 : if (p == NULL) {
596 0 : return -1;
597 : }
598 :
599 578 : if (strcmp(type, "sl_array_t") == 0) {
600 196 : offset = sl_pack_array(p, buf, offset, bufsize,
601 : toc_buf, toc_idx);
602 382 : } else if (strcmp(type, "sl_dict_t") == 0) {
603 10 : offset = sl_pack_dict(p, buf, offset, bufsize,
604 : toc_buf, toc_idx, count);
605 372 : } else if (strcmp(type, "sl_filemeta_t") == 0) {
606 10 : offset = sl_pack_filemeta(p, buf, offset, bufsize,
607 : toc_buf, toc_idx);
608 362 : } else if (strcmp(type, "uint64_t") == 0) {
609 44 : memcpy(&i, p, sizeof(uint64_t));
610 44 : offset = sl_pack_uint64(i, buf, offset, bufsize);
611 318 : } else if (strcmp(type, "uint64_t *") == 0) {
612 58 : offset = sl_pack_uint64_array(p, buf, offset,
613 : bufsize, count);
614 260 : } else if (strcmp(type, "char *") == 0) {
615 192 : offset = sl_pack_string(p, buf, offset, bufsize,
616 : toc_buf, toc_idx);
617 68 : } else if (strcmp(type, "smb_ucs2_t *") == 0) {
618 2 : offset = sl_pack_string_as_utf16(p, buf, offset, bufsize,
619 : toc_buf, toc_idx);
620 66 : } else if (strcmp(type, "sl_bool_t") == 0) {
621 8 : memcpy(&bl, p, sizeof(sl_bool_t));
622 8 : offset = sl_pack_bool(bl, buf, offset, bufsize);
623 58 : } else if (strcmp(type, "double") == 0) {
624 6 : memcpy(&d, p, sizeof(double));
625 6 : offset = sl_pack_float(d, buf, offset, bufsize);
626 52 : } else if (strcmp(type, "sl_nil_t") == 0) {
627 10 : offset = sl_pack_nil(buf, offset, bufsize);
628 42 : } else if (strcmp(type, "sl_time_t") == 0) {
629 0 : memcpy(&t, p, sizeof(sl_time_t));
630 0 : offset = sl_pack_date(t, buf, offset, bufsize);
631 42 : } else if (strcmp(type, "sl_uuid_t") == 0) {
632 4 : offset = sl_pack_uuid(p, buf, offset, bufsize);
633 38 : } else if (strcmp(type, "sl_cnids_t") == 0) {
634 38 : offset = sl_pack_CNID(p, buf, offset,
635 : bufsize, toc_buf, toc_idx);
636 : } else {
637 0 : DEBUG(1, ("unknown type: %s\n", type));
638 0 : return -1;
639 : }
640 578 : if (offset == -1) {
641 0 : DEBUG(1, ("error packing type: %s\n", type));
642 0 : return -1;
643 : }
644 : }
645 :
646 294 : return offset;
647 : }
648 :
649 : /******************************************************************************
650 : * unmarshalling functions
651 : ******************************************************************************/
652 :
653 1865 : static ssize_t sl_unpack_tag(const char *buf,
654 : ssize_t offset,
655 : size_t bufsize,
656 : uint encoding,
657 : struct sl_tag *tag)
658 : {
659 11 : uint64_t val;
660 :
661 1865 : if (offset + 8 > bufsize) {
662 0 : DEBUG(1,("%s: buffer overflow\n", __func__));
663 0 : return -1;
664 : }
665 :
666 1865 : if (encoding == SL_ENC_LITTLE_ENDIAN) {
667 1865 : val = BVAL(buf, offset);
668 : } else {
669 0 : val = RBVAL(buf, offset);
670 : }
671 :
672 1865 : tag->size = (val & 0xffff) * 8;
673 1865 : tag->type = (val & 0xffff0000) >> 16;
674 1865 : tag->count = val >> 32;
675 1865 : tag->length = tag->count * 8;
676 :
677 1865 : if (tag->size > MAX_MDSCMD_SIZE) {
678 0 : DEBUG(1,("%s: size limit %zu\n", __func__, tag->size));
679 0 : return -1;
680 : }
681 :
682 1865 : if (tag->length > MAX_MDSCMD_SIZE) {
683 0 : DEBUG(1,("%s: length limit %zu\n", __func__, tag->length));
684 0 : return -1;
685 : }
686 :
687 1865 : if (tag->count > MAX_SLQ_COUNT) {
688 0 : DEBUG(1,("%s: count limit %d\n", __func__, tag->count));
689 0 : return -1;
690 : }
691 :
692 1854 : return offset + 8;
693 : }
694 :
695 101 : static int sl_unpack_ints(DALLOC_CTX *query,
696 : const char *buf,
697 : ssize_t offset,
698 : size_t bufsize,
699 : int encoding)
700 : {
701 1 : int i, result;
702 1 : struct sl_tag tag;
703 1 : uint64_t query_data64;
704 :
705 101 : offset = sl_unpack_tag(buf, offset, bufsize, encoding, &tag);
706 101 : if (offset == -1) {
707 0 : return -1;
708 : }
709 :
710 220 : for (i = 0; i < tag.count; i++) {
711 119 : offset = sl_pull_uint64_val(buf, offset, bufsize, encoding, &query_data64);
712 119 : if (offset == -1) {
713 0 : return -1;
714 : }
715 119 : result = dalloc_add_copy(query, &query_data64, uint64_t);
716 119 : if (result != 0) {
717 0 : return -1;
718 : }
719 : }
720 :
721 100 : return tag.count;
722 : }
723 :
724 0 : static int sl_unpack_date(DALLOC_CTX *query,
725 : const char *buf,
726 : ssize_t offset,
727 : size_t bufsize,
728 : int encoding)
729 : {
730 0 : int i, result;
731 0 : struct sl_tag tag;
732 0 : uint64_t query_data64;
733 0 : union {
734 : double d;
735 : uint64_t w;
736 : } ieee_fp_union;
737 0 : double fraction;
738 0 : sl_time_t t;
739 :
740 0 : offset = sl_unpack_tag(buf, offset, bufsize, encoding, &tag);
741 0 : if (offset == -1) {
742 0 : return -1;
743 : }
744 :
745 0 : for (i = 0; i < tag.count; i++) {
746 0 : offset = sl_pull_uint64_val(buf, offset, bufsize, encoding, &query_data64);
747 0 : if (offset == -1) {
748 0 : return -1;
749 : }
750 0 : ieee_fp_union.w = query_data64;
751 0 : fraction = ieee_fp_union.d - (uint64_t)ieee_fp_union.d;
752 :
753 0 : t = (sl_time_t) {
754 0 : .tv_sec = ieee_fp_union.d + SPOTLIGHT_TIME_DELTA,
755 0 : .tv_usec = fraction * 1000000
756 : };
757 :
758 0 : result = dalloc_add_copy(query, &t, sl_time_t);
759 0 : if (result != 0) {
760 0 : return -1;
761 : }
762 : }
763 :
764 0 : return tag.count;
765 : }
766 :
767 20 : static int sl_unpack_uuid(DALLOC_CTX *query,
768 : const char *buf,
769 : ssize_t offset,
770 : size_t bufsize,
771 : int encoding)
772 : {
773 0 : int i, result;
774 0 : sl_uuid_t uuid;
775 0 : struct sl_tag tag;
776 :
777 20 : offset = sl_unpack_tag(buf, offset, bufsize, encoding, &tag);
778 20 : if (offset == -1) {
779 0 : return -1;
780 : }
781 :
782 40 : for (i = 0; i < tag.count; i++) {
783 20 : if (offset + 16 > bufsize) {
784 0 : DEBUG(1,("%s: buffer overflow\n", __func__));
785 0 : return -1;
786 : }
787 20 : memcpy(uuid.sl_uuid, buf + offset, 16);
788 20 : result = dalloc_add_copy(query, &uuid, sl_uuid_t);
789 20 : if (result != 0) {
790 0 : return -1;
791 : }
792 20 : offset += 16;
793 : }
794 :
795 20 : return tag.count;
796 : }
797 :
798 2 : static int sl_unpack_floats(DALLOC_CTX *query,
799 : const char *buf,
800 : ssize_t offset,
801 : size_t bufsize,
802 : int encoding)
803 : {
804 0 : int i, result;
805 0 : union {
806 : double d;
807 : uint32_t w[2];
808 : } ieee_fp_union;
809 0 : struct sl_tag tag;
810 :
811 2 : offset = sl_unpack_tag(buf, offset, bufsize, encoding, &tag);
812 2 : if (offset == -1) {
813 0 : return -1;
814 : }
815 :
816 4 : for (i = 0; i < tag.count; i++) {
817 2 : if (offset + 8 > bufsize) {
818 0 : DEBUG(1,("%s: buffer overflow\n", __func__));
819 0 : return -1;
820 : }
821 2 : 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);
825 : #else
826 2 : ieee_fp_union.w[0] = IVAL(buf, offset);
827 2 : ieee_fp_union.w[1] = IVAL(buf, offset + 4);
828 : #endif
829 : } else {
830 : #ifdef WORDS_BIGENDIAN
831 : ieee_fp_union.w[0] = RIVAL(buf, offset);
832 : ieee_fp_union.w[1] = RIVAL(buf, offset + 4);
833 : #else
834 0 : ieee_fp_union.w[0] = RIVAL(buf, offset + 4);
835 0 : ieee_fp_union.w[1] = RIVAL(buf, offset);
836 : #endif
837 : }
838 2 : result = dalloc_add_copy(query, &ieee_fp_union.d, double);
839 2 : if (result != 0) {
840 0 : return -1;
841 : }
842 2 : offset += 8;
843 : }
844 :
845 2 : return tag.count;
846 : }
847 :
848 43 : static int sl_unpack_CNID(DALLOC_CTX *query,
849 : const char *buf,
850 : ssize_t offset,
851 : size_t bufsize,
852 : int length,
853 : int encoding)
854 : {
855 1 : int i, count, result;
856 1 : uint64_t query_data64;
857 1 : sl_cnids_t *cnids;
858 :
859 43 : cnids = talloc_zero(query, sl_cnids_t);
860 43 : if (cnids == NULL) {
861 0 : return -1;
862 : }
863 43 : cnids->ca_cnids = dalloc_new(cnids);
864 43 : if (cnids->ca_cnids == NULL) {
865 0 : return -1;
866 : }
867 :
868 43 : if (length < 8) {
869 0 : return -1;
870 : }
871 43 : if (length == 8) {
872 : /*
873 : * That's permitted, length=8 is an empty CNID array.
874 : */
875 3 : result = dalloc_add(query, cnids, sl_cnids_t);
876 3 : if (result != 0) {
877 0 : return -1;
878 : }
879 3 : return 0;
880 : }
881 :
882 40 : offset = sl_pull_uint64_val(buf, offset, bufsize, encoding, &query_data64);
883 40 : if (offset == -1) {
884 0 : return -1;
885 : }
886 :
887 : /*
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
891 : * sl_unpack_tag().
892 : */
893 40 : count = query_data64 & 0xffff;;
894 40 : cnids->ca_unkn1 = (query_data64 & 0xffff0000) >> 16;
895 40 : cnids->ca_context = query_data64 >> 32;
896 :
897 100 : for (i = 0; i < count; i++) {
898 60 : offset = sl_pull_uint64_val(buf, offset, bufsize, encoding, &query_data64);
899 60 : if (offset == -1) {
900 0 : return -1;
901 : }
902 :
903 60 : result = dalloc_add_copy(cnids->ca_cnids, &query_data64, uint64_t);
904 60 : if (result != 0) {
905 0 : return -1;
906 : }
907 : }
908 :
909 40 : result = dalloc_add(query, cnids, sl_cnids_t);
910 40 : if (result != 0) {
911 0 : return -1;
912 : }
913 :
914 40 : return 0;
915 : }
916 :
917 549 : static ssize_t sl_unpack_cpx(DALLOC_CTX *query,
918 : const char *buf,
919 : ssize_t offset,
920 : size_t bufsize,
921 : int cpx_query_type,
922 : int cpx_query_count,
923 : ssize_t toc_offset,
924 : int encoding)
925 : {
926 3 : int result;
927 549 : ssize_t roffset = offset;
928 3 : int unicode_encoding;
929 3 : bool mark_exists;
930 3 : char *p;
931 3 : size_t slen, tmp_len;
932 3 : sl_array_t *sl_array;
933 3 : sl_dict_t *sl_dict;
934 3 : sl_filemeta_t *sl_fm;
935 3 : bool ok;
936 3 : struct sl_tag tag;
937 :
938 549 : switch (cpx_query_type) {
939 199 : case SQ_CPX_TYPE_ARRAY:
940 199 : sl_array = dalloc_zero(query, sl_array_t);
941 199 : if (sl_array == NULL) {
942 0 : return -1;
943 : }
944 199 : roffset = sl_unpack_loop(sl_array, buf, offset, bufsize,
945 : cpx_query_count, toc_offset, encoding);
946 199 : if (roffset == -1) {
947 2 : return -1;
948 : }
949 197 : result = dalloc_add(query, sl_array, sl_array_t);
950 197 : if (result != 0) {
951 0 : return -1;
952 : }
953 196 : break;
954 :
955 14 : case SQ_CPX_TYPE_DICT:
956 14 : sl_dict = dalloc_zero(query, sl_dict_t);
957 14 : if (sl_dict == NULL) {
958 0 : return -1;
959 : }
960 14 : roffset = sl_unpack_loop(sl_dict, buf, offset, bufsize,
961 : cpx_query_count, toc_offset, encoding);
962 14 : if (roffset == -1) {
963 0 : return -1;
964 : }
965 14 : result = dalloc_add(query, sl_dict, sl_dict_t);
966 14 : if (result != 0) {
967 0 : return -1;
968 : }
969 14 : break;
970 :
971 256 : case SQ_CPX_TYPE_STRING:
972 : case SQ_CPX_TYPE_UTF16_STRING:
973 256 : offset = sl_unpack_tag(buf, offset, bufsize, encoding, &tag);
974 256 : if (offset == -1) {
975 0 : return -1;
976 : }
977 :
978 256 : if (tag.size < 16) {
979 0 : DEBUG(1,("%s: string buffer too small\n", __func__));
980 0 : return -1;
981 : }
982 256 : slen = tag.size - 16 + tag.count;
983 256 : if (slen > MAX_MDSCMD_SIZE) {
984 0 : return -1;
985 : }
986 :
987 256 : if (offset + slen > bufsize) {
988 0 : DEBUG(1,("%s: buffer overflow\n", __func__));
989 0 : return -1;
990 : }
991 :
992 256 : if (cpx_query_type == SQ_CPX_TYPE_STRING) {
993 246 : p = talloc_strndup(query, buf + offset, slen);
994 246 : if (p == NULL) {
995 0 : return -1;
996 : }
997 : } else {
998 10 : unicode_encoding = spotlight_get_utf16_string_encoding(
999 : buf, offset, slen, encoding);
1000 10 : mark_exists = (unicode_encoding & SL_ENC_UTF_16) ? true : false;
1001 10 : if (unicode_encoding & SL_ENC_BIG_ENDIAN) {
1002 0 : DEBUG(1, ("Unsupported big endian UTF16 string\n"));
1003 0 : return -1;
1004 : }
1005 10 : slen -= mark_exists ? 2 : 0;
1006 10 : ok = convert_string_talloc(
1007 : query,
1008 : CH_UTF16LE,
1009 : CH_UTF8,
1010 10 : buf + offset + (mark_exists ? 2 : 0),
1011 : slen,
1012 : &p,
1013 : &tmp_len);
1014 10 : if (!ok) {
1015 0 : return -1;
1016 : }
1017 : }
1018 :
1019 256 : result = dalloc_stradd(query, p);
1020 256 : if (result != 0) {
1021 0 : return -1;
1022 : }
1023 256 : roffset += tag.size;
1024 256 : break;
1025 :
1026 37 : case SQ_CPX_TYPE_FILEMETA:
1027 37 : offset = sl_unpack_tag(buf, offset, bufsize, encoding, &tag);
1028 37 : if (offset == -1) {
1029 0 : return -1;
1030 : }
1031 37 : if (tag.size < 8) {
1032 0 : DBG_WARNING("size too mall: %zu\n", tag.size);
1033 0 : return -1;
1034 : }
1035 :
1036 37 : sl_fm = dalloc_zero(query, sl_filemeta_t);
1037 37 : if (sl_fm == NULL) {
1038 0 : return -1;
1039 : }
1040 :
1041 37 : if (tag.size >= 16) {
1042 34 : result = sl_unpack(sl_fm,
1043 : buf + offset,
1044 : bufsize - offset );
1045 34 : if (result == -1) {
1046 0 : return -1;
1047 : }
1048 : }
1049 37 : result = dalloc_add(query, sl_fm, sl_filemeta_t);
1050 37 : if (result != 0) {
1051 0 : return -1;
1052 : }
1053 37 : roffset += tag.size;
1054 37 : break;
1055 :
1056 43 : case SQ_CPX_TYPE_CNIDS:
1057 43 : offset = sl_unpack_tag(buf, offset, bufsize, encoding, &tag);
1058 43 : if (offset == -1) {
1059 0 : return -1;
1060 : }
1061 :
1062 44 : result = sl_unpack_CNID(query, buf, offset, bufsize,
1063 43 : tag.size, encoding);
1064 43 : if (result == -1) {
1065 0 : return -1;
1066 : }
1067 43 : roffset += tag.size;
1068 43 : break;
1069 :
1070 0 : default:
1071 0 : DEBUG(1, ("unknown complex query type: %u\n", cpx_query_type));
1072 0 : return -1;
1073 : }
1074 :
1075 544 : return roffset;
1076 : }
1077 :
1078 320 : static ssize_t sl_unpack_loop(DALLOC_CTX *query,
1079 : const char *buf,
1080 : ssize_t offset,
1081 : size_t bufsize,
1082 : int count,
1083 : ssize_t toc_offset,
1084 : int encoding)
1085 : {
1086 2 : int i, toc_index, subcount;
1087 2 : uint64_t result;
1088 :
1089 1066 : while (count > 0) {
1090 4 : struct sl_tag tag;
1091 :
1092 750 : if (offset >= toc_offset) {
1093 4 : return -1;
1094 : }
1095 :
1096 750 : result = sl_unpack_tag(buf, offset, bufsize, encoding, &tag);
1097 750 : if (result == -1) {
1098 0 : return -1;
1099 : }
1100 :
1101 750 : switch (tag.type) {
1102 549 : case SQ_TYPE_COMPLEX: {
1103 3 : struct sl_tag cpx_tag;
1104 :
1105 549 : if (tag.count < 1) {
1106 0 : DEBUG(1,("%s: invalid tag.count: %d\n",
1107 : __func__, tag.count));
1108 2 : return -1;
1109 : }
1110 549 : toc_index = tag.count - 1;
1111 549 : if (toc_index > MAX_SLQ_TOCIDX) {
1112 0 : DEBUG(1,("%s: toc_index too large: %d\n",
1113 : __func__, toc_index));
1114 0 : return -1;
1115 : }
1116 549 : result = sl_unpack_tag(buf, toc_offset + (toc_index * 8),
1117 : bufsize, encoding, &cpx_tag);
1118 549 : if (result == -1) {
1119 0 : return -1;
1120 : }
1121 :
1122 549 : offset = sl_unpack_cpx(query, buf, offset + 8, bufsize, cpx_tag.type,
1123 : cpx_tag.count, toc_offset, encoding);
1124 549 : if (offset == -1) {
1125 2 : return -1;
1126 : }
1127 : /*
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;
1131 : */
1132 547 : count--;
1133 547 : break;
1134 : }
1135 :
1136 38 : case SQ_TYPE_NULL: {
1137 38 : sl_nil_t nil = 0;
1138 :
1139 38 : subcount = tag.count;
1140 38 : if (subcount < 1 || subcount > count) {
1141 2 : return -1;
1142 : }
1143 72 : for (i = 0; i < subcount; i++) {
1144 36 : result = dalloc_add_copy(query, &nil, sl_nil_t);
1145 36 : if (result != 0) {
1146 0 : return -1;
1147 : }
1148 : }
1149 36 : offset += tag.size;
1150 36 : count -= subcount;
1151 36 : break;
1152 : }
1153 :
1154 40 : case SQ_TYPE_BOOL: {
1155 40 : sl_bool_t b = (tag.count != 0);
1156 :
1157 40 : result = dalloc_add_copy(query, &b, sl_bool_t);
1158 40 : if (result != 0) {
1159 0 : return -1;
1160 : }
1161 40 : offset += tag.size;
1162 40 : count--;
1163 40 : break;
1164 : }
1165 :
1166 101 : case SQ_TYPE_INT64:
1167 101 : subcount = sl_unpack_ints(query, buf, offset, bufsize, encoding);
1168 101 : if (subcount < 1 || subcount > count) {
1169 0 : return -1;
1170 : }
1171 101 : offset += tag.size;
1172 101 : count -= subcount;
1173 101 : break;
1174 :
1175 20 : case SQ_TYPE_UUID:
1176 20 : subcount = sl_unpack_uuid(query, buf, offset, bufsize, encoding);
1177 20 : if (subcount < 1 || subcount > count) {
1178 0 : return -1;
1179 : }
1180 20 : offset += tag.size;
1181 20 : count -= subcount;
1182 20 : break;
1183 :
1184 2 : case SQ_TYPE_FLOAT:
1185 2 : subcount = sl_unpack_floats(query, buf, offset, bufsize, encoding);
1186 2 : if (subcount < 1 || subcount > count) {
1187 0 : return -1;
1188 : }
1189 2 : offset += tag.size;
1190 2 : count -= subcount;
1191 2 : break;
1192 :
1193 0 : case SQ_TYPE_DATE:
1194 0 : subcount = sl_unpack_date(query, buf, offset, bufsize, encoding);
1195 0 : if (subcount < 1 || subcount > count) {
1196 0 : return -1;
1197 : }
1198 0 : offset += tag.size;
1199 0 : count -= subcount;
1200 0 : break;
1201 :
1202 0 : default:
1203 0 : DEBUG(1, ("unknown query type: %d\n", tag.type));
1204 0 : return -1;
1205 : }
1206 : }
1207 :
1208 314 : return offset;
1209 : }
1210 :
1211 88 : static ssize_t sl_pack(DALLOC_CTX *query, char *buf, size_t bufsize)
1212 : {
1213 0 : ssize_t result;
1214 0 : char *toc_buf;
1215 88 : int toc_index = 0;
1216 88 : int toc_count = 0;
1217 0 : ssize_t offset, len;
1218 0 : uint64_t hdr;
1219 0 : uint32_t total_octets;
1220 0 : uint32_t data_octets;
1221 0 : uint64_t tag;
1222 :
1223 88 : memset(buf, 0, bufsize);
1224 :
1225 88 : toc_buf = talloc_zero_size(query, MAX_SLQ_TOC + 8);
1226 88 : if (toc_buf == NULL) {
1227 0 : return -1;
1228 : }
1229 :
1230 88 : offset = sl_pack_loop(query, buf, 16, bufsize, toc_buf + 8, &toc_index, &toc_count);
1231 88 : if (offset == -1 || offset < 16) {
1232 0 : DEBUG(10,("%s: sl_pack_loop error\n", __func__));
1233 0 : return -1;
1234 : }
1235 88 : len = offset - 16;
1236 :
1237 : /*
1238 : * Marshalling overview:
1239 : *
1240 : * 16 bytes at the start of buf:
1241 : *
1242 : * 8 bytes byte order mark
1243 : * 4 bytes total octets
1244 : * 4 bytes table of content octets
1245 : *
1246 : * x bytes total octets * 8 from sl_pack_loop
1247 : * x bytes ToC octets * 8 from toc_buf
1248 : */
1249 :
1250 : /* Byte-order mark - we are using little endian only for now */
1251 88 : memcpy(buf, "432130dm", strlen("432130dm"));
1252 :
1253 : /*
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.
1257 : */
1258 88 : data_octets = (len / 8) + 1;
1259 88 : total_octets = data_octets + toc_index + 1;
1260 :
1261 88 : hdr = total_octets;
1262 88 : hdr |= ((uint64_t)data_octets << 32);
1263 :
1264 : /* HDR */
1265 88 : result = sl_push_uint64_val(buf, 8, bufsize, hdr);
1266 88 : if (result == -1) {
1267 0 : return -1;
1268 : }
1269 :
1270 : /*
1271 : * ToC tag with number of ToC entries plus one, the ToC tag
1272 : * header.
1273 : */
1274 88 : tag = sl_pack_tag(SQ_TYPE_TOC, toc_index + 1, 0);
1275 88 : result = sl_push_uint64_val(toc_buf, 0, MAX_SLQ_TOC, tag);
1276 88 : if (result == -1) {
1277 0 : return -1;
1278 : }
1279 :
1280 88 : if ((16 + len + ((toc_index + 1 ) * 8)) > bufsize) {
1281 0 : DEBUG(1, ("%s: exceeding size limit %zu\n", __func__, bufsize));
1282 0 : return -1;
1283 : }
1284 :
1285 88 : memcpy(buf + 16 + len, toc_buf, (toc_index + 1 ) * 8);
1286 88 : len += 16 + (toc_index + 1 ) * 8;
1287 :
1288 88 : return len;
1289 : }
1290 :
1291 : /******************************************************************************
1292 : * Global functions for packing und unpacking
1293 : ******************************************************************************/
1294 :
1295 78 : NTSTATUS sl_pack_alloc(TALLOC_CTX *mem_ctx,
1296 : DALLOC_CTX *d,
1297 : struct mdssvc_blob *b,
1298 : size_t max_fragment_size)
1299 : {
1300 0 : ssize_t len;
1301 :
1302 78 : b->spotlight_blob = talloc_zero_array(mem_ctx,
1303 : uint8_t,
1304 : max_fragment_size);
1305 78 : if (b->spotlight_blob == NULL) {
1306 0 : return NT_STATUS_NO_MEMORY;
1307 : }
1308 :
1309 78 : len = sl_pack(d, (char *)b->spotlight_blob, max_fragment_size);
1310 78 : if (len == -1) {
1311 0 : return NT_STATUS_DATA_ERROR;
1312 : }
1313 :
1314 78 : b->length = len;
1315 78 : b->size = len;
1316 78 : return NT_STATUS_OK;
1317 : }
1318 :
1319 107 : bool sl_unpack(DALLOC_CTX *query, const char *buf, size_t bufsize)
1320 : {
1321 1 : ssize_t result;
1322 107 : ssize_t offset = 0;
1323 1 : int encoding;
1324 1 : uint64_t hdr;
1325 1 : uint32_t total_octets;
1326 1 : uint64_t total_bytes;
1327 1 : uint32_t data_octets;
1328 1 : uint64_t data_bytes;
1329 1 : uint64_t toc_offset;
1330 1 : struct sl_tag toc_tag;
1331 :
1332 107 : if (bufsize > MAX_MDSCMD_SIZE) {
1333 0 : return false;
1334 : }
1335 :
1336 107 : if (bufsize < 8) {
1337 0 : return false;
1338 : }
1339 107 : if (strncmp(buf + offset, "md031234", 8) == 0) {
1340 0 : encoding = SL_ENC_BIG_ENDIAN;
1341 : } else {
1342 107 : encoding = SL_ENC_LITTLE_ENDIAN;
1343 : }
1344 107 : offset += 8;
1345 :
1346 107 : offset = sl_pull_uint64_val(buf, offset, bufsize, encoding, &hdr);
1347 107 : if (offset == -1) {
1348 0 : return false;
1349 : }
1350 :
1351 107 : total_octets = hdr & UINT32_MAX;
1352 107 : data_octets = hdr >> 32;
1353 :
1354 : /*
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.
1358 : */
1359 107 : if (total_octets < 1) {
1360 0 : return false;
1361 : }
1362 107 : if (data_octets < 1) {
1363 0 : return false;
1364 : }
1365 107 : total_octets--;
1366 107 : data_octets--;
1367 107 : data_bytes = ((uint64_t)data_octets) * 8;
1368 107 : total_bytes = ((uint64_t)total_octets) * 8;
1369 :
1370 107 : if (data_bytes >= total_bytes) {
1371 0 : DEBUG(1,("%s: data_bytes: %" PRIu64 ", total_bytes: %" PRIu64 "\n",
1372 : __func__, data_bytes, total_bytes));
1373 0 : return false;
1374 : }
1375 :
1376 107 : if (total_bytes > (bufsize - offset)) {
1377 0 : return false;
1378 : }
1379 :
1380 107 : toc_offset = data_bytes;
1381 :
1382 107 : toc_offset = sl_unpack_tag(buf + offset, toc_offset,
1383 : bufsize - offset, encoding, &toc_tag);
1384 107 : if (toc_offset == -1) {
1385 0 : return false;
1386 : }
1387 :
1388 107 : if (toc_tag.type != SQ_TYPE_TOC) {
1389 0 : DEBUG(1,("%s: unknown tag type %d\n", __func__, toc_tag.type));
1390 0 : return false;
1391 : }
1392 :
1393 : /*
1394 : * Check toc_tag.size even though we don't use it when unmarshalling
1395 : */
1396 107 : if (toc_tag.size > MAX_SLQ_TOC) {
1397 0 : DEBUG(1,("%s: bad size %zu\n", __func__, toc_tag.size));
1398 0 : return false;
1399 : }
1400 107 : if (toc_tag.size > (total_bytes - data_bytes)) {
1401 0 : DEBUG(1,("%s: bad size %zu\n", __func__, toc_tag.size));
1402 0 : return false;
1403 : }
1404 :
1405 107 : if (toc_tag.count != 0) {
1406 0 : DEBUG(1,("%s: bad count %u\n", __func__, toc_tag.count));
1407 0 : return false;
1408 : }
1409 :
1410 : /*
1411 : * We already consumed 16 bytes from the buffer (BOM and size
1412 : * tag), so we start at buf + offset.
1413 : */
1414 107 : result = sl_unpack_loop(query, buf + offset, 0, bufsize - offset,
1415 : 1, toc_offset, encoding);
1416 107 : if (result == -1) {
1417 2 : DEBUG(1,("%s: sl_unpack_loop failed\n", __func__));
1418 2 : return false;
1419 : }
1420 :
1421 104 : return true;
1422 : }
|