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*8
38 : #define MAX_SLQ_TOCIDX 1024
39 : #define MAX_SLQ_COUNT 4096
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 0 : static ssize_t sl_push_uint64_val(char *buf,
88 : ssize_t offset,
89 : size_t max_offset,
90 : uint64_t val)
91 : {
92 0 : if (offset + 8 > max_offset) {
93 0 : DEBUG(1, ("%s: offset: %zd, max_offset: %zu",
94 : __func__, offset, max_offset));
95 0 : return -1;
96 : }
97 :
98 0 : SBVAL(buf, offset, val);
99 0 : return offset + 8;
100 : }
101 :
102 0 : 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 : uint64_t val;
109 :
110 0 : if (offset + 8 > bufsize) {
111 0 : DEBUG(1,("%s: buffer overflow\n", __func__));
112 0 : return -1;
113 : }
114 :
115 0 : if (encoding == SL_ENC_LITTLE_ENDIAN) {
116 0 : val = BVAL(buf, offset);
117 : } else {
118 0 : val = RBVAL(buf, offset);
119 : }
120 :
121 0 : *presult = val;
122 :
123 0 : 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 0 : static int spotlight_get_utf16_string_encoding(const char *buf, ssize_t offset,
131 : size_t query_length, int encoding)
132 : {
133 : int utf16_encoding;
134 :
135 : /* Assumed encoding in absence of a bom is little endian */
136 0 : utf16_encoding = SL_ENC_LITTLE_ENDIAN;
137 :
138 0 : if (query_length >= 2) {
139 0 : uint8_t le_bom[] = {0xff, 0xfe};
140 0 : uint8_t be_bom[] = {0xfe, 0xff};
141 0 : if (memcmp(le_bom, buf + offset, sizeof(uint16_t)) == 0) {
142 0 : 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 0 : return utf16_encoding;
149 : }
150 :
151 : /******************************************************************************
152 : * marshalling functions
153 : ******************************************************************************/
154 :
155 0 : static inline uint64_t sl_pack_tag(uint16_t type, uint16_t size_or_count, uint32_t val)
156 : {
157 0 : uint64_t tag = ((uint64_t)val << 32) | ((uint64_t)type << 16) | size_or_count;
158 0 : return tag;
159 : }
160 :
161 0 : static ssize_t sl_pack_float(double d, char *buf, ssize_t offset, size_t bufsize)
162 : {
163 : union {
164 : double d;
165 : uint64_t w;
166 : } ieee_fp_union;
167 :
168 0 : ieee_fp_union.d = d;
169 :
170 0 : offset = sl_push_uint64_val(buf, offset, bufsize, sl_pack_tag(SQ_TYPE_FLOAT, 2, 1));
171 0 : if (offset == -1) {
172 0 : return -1;
173 : }
174 0 : offset = sl_push_uint64_val(buf, offset, bufsize, ieee_fp_union.w);
175 0 : if (offset == -1) {
176 0 : return -1;
177 : }
178 :
179 0 : return offset;
180 : }
181 :
182 0 : static ssize_t sl_pack_uint64(uint64_t u, char *buf, ssize_t offset, size_t bufsize)
183 : {
184 : uint64_t tag;
185 :
186 0 : tag = sl_pack_tag(SQ_TYPE_INT64, 2, 1);
187 0 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
188 0 : if (offset == -1) {
189 0 : return -1;
190 : }
191 0 : offset = sl_push_uint64_val(buf, offset, bufsize, u);
192 0 : if (offset == -1) {
193 0 : return -1;
194 : }
195 :
196 0 : return offset;
197 : }
198 :
199 0 : static ssize_t sl_pack_uint64_array(uint64_t *u, char *buf, ssize_t offset, size_t bufsize, int *toc_count)
200 : {
201 : int count, i;
202 : uint64_t tag;
203 :
204 0 : count = talloc_array_length(u);
205 :
206 0 : tag = sl_pack_tag(SQ_TYPE_INT64, count + 1, count);
207 0 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
208 0 : if (offset == -1) {
209 0 : return -1;
210 : }
211 :
212 0 : for (i = 0; i < count; i++) {
213 0 : offset = sl_push_uint64_val(buf, offset, bufsize, u[i]);
214 0 : if (offset == -1) {
215 0 : return -1;
216 : }
217 : }
218 :
219 0 : if (count > 1) {
220 0 : *toc_count += (count - 1);
221 : }
222 :
223 0 : return offset;
224 : }
225 :
226 0 : static ssize_t sl_pack_bool(sl_bool_t val, char *buf, ssize_t offset, size_t bufsize)
227 : {
228 : uint64_t tag;
229 :
230 0 : tag = sl_pack_tag(SQ_TYPE_BOOL, 1, val ? 1 : 0);
231 0 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
232 0 : if (offset == -1) {
233 0 : return -1;
234 : }
235 :
236 0 : return offset;
237 : }
238 :
239 0 : static ssize_t sl_pack_nil(char *buf, ssize_t offset, size_t bufsize)
240 : {
241 : uint64_t tag;
242 :
243 0 : tag = sl_pack_tag(SQ_TYPE_NULL, 1, 1);
244 0 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
245 0 : if (offset == -1) {
246 0 : return -1;
247 : }
248 :
249 0 : 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 : uint64_t data;
255 : uint64_t tag;
256 : 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 0 : static ssize_t sl_pack_uuid(sl_uuid_t *uuid, char *buf, ssize_t offset, size_t bufsize)
280 : {
281 : uint64_t tag;
282 :
283 0 : tag = sl_pack_tag(SQ_TYPE_UUID, 3, 1);
284 0 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
285 0 : if (offset == -1) {
286 0 : return -1;
287 : }
288 :
289 0 : if (offset + 16 > bufsize) {
290 0 : return -1;
291 : }
292 0 : memcpy(buf + offset, uuid, 16);
293 :
294 0 : return offset + 16;
295 : }
296 :
297 0 : 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 : ssize_t result;
301 : int len, i;
302 0 : int cnid_count = dalloc_size(cnids->ca_cnids);
303 : uint64_t tag;
304 : uint64_t id;
305 : void *p;
306 :
307 0 : tag = sl_pack_tag(SQ_CPX_TYPE_CNIDS, offset / 8, 0);
308 0 : result = sl_push_uint64_val(toc_buf, *toc_idx * 8, MAX_SLQ_TOC, tag);
309 0 : if (result == -1) {
310 0 : return -1;
311 : }
312 :
313 0 : tag = sl_pack_tag(SQ_TYPE_COMPLEX, 1, *toc_idx + 1);
314 0 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
315 0 : if (offset == -1) {
316 0 : return -1;
317 : }
318 :
319 0 : *toc_idx += 1;
320 :
321 0 : len = cnid_count + 1;
322 0 : if (cnid_count > 0) {
323 0 : len ++;
324 : }
325 :
326 : /* unknown meaning, but always 8 */
327 0 : tag = sl_pack_tag(SQ_TYPE_CNIDS, len, 8 );
328 0 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
329 0 : if (offset == -1) {
330 0 : return -1;
331 : }
332 :
333 0 : if (cnid_count > 0) {
334 0 : tag = sl_pack_tag(cnids->ca_unkn1, cnid_count, cnids->ca_context);
335 0 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
336 0 : if (offset == -1) {
337 0 : return -1;
338 : }
339 :
340 0 : for (i = 0; i < cnid_count; i++) {
341 0 : p = dalloc_get_object(cnids->ca_cnids, i);
342 0 : if (p == NULL) {
343 0 : return -1;
344 : }
345 0 : memcpy(&id, p, sizeof(uint64_t));
346 0 : offset = sl_push_uint64_val(buf, offset, bufsize, id);
347 0 : if (offset == -1) {
348 0 : return -1;
349 : }
350 : }
351 : }
352 :
353 0 : return offset;
354 : }
355 :
356 0 : 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 : ssize_t result;
360 0 : int count = dalloc_size(array);
361 0 : int octets = offset / 8;
362 : uint64_t tag;
363 0 : int toc_idx_save = *toc_idx;
364 :
365 0 : tag = sl_pack_tag(SQ_TYPE_COMPLEX, 1, *toc_idx + 1);
366 0 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
367 0 : if (offset == -1) {
368 0 : return -1;
369 : }
370 :
371 0 : *toc_idx += 1;
372 :
373 0 : offset = sl_pack_loop(array, buf, offset, bufsize - offset, toc_buf, toc_idx, &count);
374 :
375 0 : tag = sl_pack_tag(SQ_CPX_TYPE_ARRAY, octets, count);
376 0 : result = sl_push_uint64_val(toc_buf, toc_idx_save * 8, MAX_SLQ_TOC, tag);
377 0 : if (result == -1) {
378 0 : return -1;
379 : }
380 :
381 0 : return offset;
382 : }
383 :
384 0 : 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 : ssize_t result;
388 : uint64_t tag;
389 :
390 0 : tag = sl_pack_tag(SQ_CPX_TYPE_DICT, offset / 8,
391 0 : dalloc_size(dict));
392 0 : result = sl_push_uint64_val(toc_buf, *toc_idx * 8, MAX_SLQ_TOC, tag);
393 0 : if (result == -1) {
394 0 : return -1;
395 : }
396 :
397 0 : tag = sl_pack_tag(SQ_TYPE_COMPLEX, 1, *toc_idx + 1);
398 0 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
399 0 : if (offset == -1) {
400 0 : return -1;
401 : }
402 :
403 0 : *toc_idx += 1;
404 :
405 0 : offset = sl_pack_loop(dict, buf, offset, bufsize - offset, toc_buf, toc_idx, count);
406 :
407 0 : return offset;
408 : }
409 :
410 0 : 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 : ssize_t result;
414 : ssize_t fmlen;
415 0 : ssize_t saveoff = offset;
416 : uint64_t tag;
417 :
418 0 : tag = sl_pack_tag(SQ_TYPE_COMPLEX, 1, *toc_idx + 1);
419 0 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
420 0 : if (offset == -1) {
421 0 : return -1;
422 : }
423 :
424 0 : offset += 8;
425 :
426 0 : fmlen = sl_pack(fm, buf + offset, bufsize - offset);
427 0 : 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 0 : if (fmlen > 40) {
436 0 : offset += fmlen;
437 : } else {
438 0 : fmlen = 0;
439 : }
440 :
441 : /* unknown meaning, but always 8 */
442 0 : tag = sl_pack_tag(SQ_TYPE_DATA, (fmlen / 8) + 1, 8);
443 0 : result = sl_push_uint64_val(buf, saveoff + 8, bufsize, tag);
444 0 : if (result == -1) {
445 0 : return -1;
446 : }
447 :
448 0 : tag = sl_pack_tag(SQ_CPX_TYPE_FILEMETA, saveoff / 8, fmlen / 8);
449 0 : result = sl_push_uint64_val(toc_buf, *toc_idx * 8, MAX_SLQ_TOC, tag);
450 0 : if (result == -1) {
451 0 : return -1;
452 : }
453 :
454 0 : *toc_idx += 1;
455 :
456 0 : return offset;
457 : }
458 :
459 0 : 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 : ssize_t result;
463 : size_t len, octets, used_in_last_octet;
464 : uint64_t tag;
465 :
466 0 : len = strlen(s);
467 0 : if (len > MAX_SL_STRLEN) {
468 0 : return -1;
469 : }
470 0 : octets = (len + 7) / 8;
471 0 : used_in_last_octet = len % 8;
472 0 : if (used_in_last_octet == 0) {
473 0 : used_in_last_octet = 8;
474 : }
475 :
476 0 : tag = sl_pack_tag(SQ_CPX_TYPE_STRING, offset / 8, used_in_last_octet);
477 0 : result = sl_push_uint64_val(toc_buf, *toc_idx * 8, MAX_SLQ_TOC, tag);
478 0 : if (result == -1) {
479 0 : return -1;
480 : }
481 :
482 0 : tag = sl_pack_tag(SQ_TYPE_COMPLEX, 1, *toc_idx + 1);
483 0 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
484 0 : if (offset == -1) {
485 0 : return -1;
486 : }
487 :
488 0 : *toc_idx += 1;
489 :
490 0 : tag = sl_pack_tag(SQ_TYPE_DATA, octets + 1, used_in_last_octet);
491 0 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
492 0 : if (offset == -1) {
493 0 : return -1;
494 : }
495 :
496 0 : if (offset + (octets * 8) > bufsize) {
497 0 : return -1;
498 : }
499 :
500 0 : memset(buf + offset, 0, octets * 8);
501 0 : memcpy(buf + offset, s, len);
502 0 : offset += octets * 8;
503 :
504 0 : return offset;
505 : }
506 :
507 0 : 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 : ssize_t result;
511 : int utf16_plus_bom_len, octets, used_in_last_octet;
512 0 : char *utf16string = NULL;
513 0 : char bom[] = { 0xff, 0xfe };
514 : size_t slen, utf16len;
515 : uint64_t tag;
516 : bool ok;
517 :
518 0 : slen = strlen(s);
519 0 : if (slen > MAX_SL_STRLEN) {
520 0 : return -1;
521 : }
522 :
523 0 : ok = convert_string_talloc(talloc_tos(),
524 : CH_UTF8,
525 : CH_UTF16LE,
526 : s,
527 : slen,
528 : &utf16string,
529 : &utf16len);
530 0 : if (!ok) {
531 0 : return -1;
532 : }
533 :
534 0 : utf16_plus_bom_len = utf16len + 2;
535 0 : octets = (utf16_plus_bom_len + 7) / 8;
536 0 : used_in_last_octet = utf16_plus_bom_len % 8;
537 0 : if (used_in_last_octet == 0) {
538 0 : used_in_last_octet = 8;
539 : }
540 :
541 0 : tag = sl_pack_tag(SQ_CPX_TYPE_UTF16_STRING, offset / 8, used_in_last_octet);
542 0 : result = sl_push_uint64_val(toc_buf, *toc_idx * 8, MAX_SLQ_TOC, tag);
543 0 : if (result == -1) {
544 0 : offset = -1;
545 0 : goto done;
546 : }
547 :
548 0 : tag = sl_pack_tag(SQ_TYPE_COMPLEX, 1, *toc_idx + 1);
549 0 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
550 0 : if (offset == -1) {
551 0 : goto done;
552 : }
553 :
554 0 : *toc_idx += 1;
555 :
556 0 : tag = sl_pack_tag(SQ_TYPE_DATA, octets + 1, used_in_last_octet);
557 0 : offset = sl_push_uint64_val(buf, offset, bufsize, tag);
558 0 : if (offset == -1) {
559 0 : goto done;
560 : }
561 :
562 0 : if (offset + (octets * 8) > bufsize) {
563 0 : offset = -1;
564 0 : goto done;
565 : }
566 :
567 0 : memset(buf + offset, 0, octets * 8);
568 0 : memcpy(buf + offset, &bom, sizeof(bom));
569 0 : memcpy(buf + offset + 2, utf16string, utf16len);
570 0 : offset += octets * 8;
571 :
572 0 : done:
573 0 : TALLOC_FREE(utf16string);
574 0 : return offset;
575 : }
576 :
577 0 : 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 : const char *type;
581 : int n;
582 : uint64_t i;
583 : sl_bool_t bl;
584 : double d;
585 : sl_time_t t;
586 : void *p;
587 :
588 0 : for (n = 0; n < dalloc_size(query); n++) {
589 :
590 0 : type = dalloc_get_name(query, n);
591 0 : if (type == NULL) {
592 0 : return -1;
593 : }
594 0 : p = dalloc_get_object(query, n);
595 0 : if (p == NULL) {
596 0 : return -1;
597 : }
598 :
599 0 : if (strcmp(type, "sl_array_t") == 0) {
600 0 : offset = sl_pack_array(p, buf, offset, bufsize,
601 : toc_buf, toc_idx);
602 0 : } else if (strcmp(type, "sl_dict_t") == 0) {
603 0 : offset = sl_pack_dict(p, buf, offset, bufsize,
604 : toc_buf, toc_idx, count);
605 0 : } else if (strcmp(type, "sl_filemeta_t") == 0) {
606 0 : offset = sl_pack_filemeta(p, buf, offset, bufsize,
607 : toc_buf, toc_idx);
608 0 : } else if (strcmp(type, "uint64_t") == 0) {
609 0 : memcpy(&i, p, sizeof(uint64_t));
610 0 : offset = sl_pack_uint64(i, buf, offset, bufsize);
611 0 : } else if (strcmp(type, "uint64_t *") == 0) {
612 0 : offset = sl_pack_uint64_array(p, buf, offset,
613 : bufsize, count);
614 0 : } else if (strcmp(type, "char *") == 0) {
615 0 : offset = sl_pack_string(p, buf, offset, bufsize,
616 : toc_buf, toc_idx);
617 0 : } else if (strcmp(type, "smb_ucs2_t *") == 0) {
618 0 : offset = sl_pack_string_as_utf16(p, buf, offset, bufsize,
619 : toc_buf, toc_idx);
620 0 : } else if (strcmp(type, "sl_bool_t") == 0) {
621 0 : memcpy(&bl, p, sizeof(sl_bool_t));
622 0 : offset = sl_pack_bool(bl, buf, offset, bufsize);
623 0 : } else if (strcmp(type, "double") == 0) {
624 0 : memcpy(&d, p, sizeof(double));
625 0 : offset = sl_pack_float(d, buf, offset, bufsize);
626 0 : } else if (strcmp(type, "sl_nil_t") == 0) {
627 0 : offset = sl_pack_nil(buf, offset, bufsize);
628 0 : } 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 0 : } else if (strcmp(type, "sl_uuid_t") == 0) {
632 0 : offset = sl_pack_uuid(p, buf, offset, bufsize);
633 0 : } else if (strcmp(type, "sl_cnids_t") == 0) {
634 0 : offset = sl_pack_CNID(p, buf, offset,
635 : bufsize, toc_buf, toc_idx);
636 : } else {
637 0 : DEBUG(1, ("unknown type: %s", type));
638 0 : return -1;
639 : }
640 0 : if (offset == -1) {
641 0 : DEBUG(1, ("error packing type: %s\n", type));
642 0 : return -1;
643 : }
644 : }
645 :
646 0 : return offset;
647 : }
648 :
649 : /******************************************************************************
650 : * unmarshalling functions
651 : ******************************************************************************/
652 :
653 0 : 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 : uint64_t val;
660 :
661 0 : if (offset + 8 > bufsize) {
662 0 : DEBUG(1,("%s: buffer overflow\n", __func__));
663 0 : return -1;
664 : }
665 :
666 0 : if (encoding == SL_ENC_LITTLE_ENDIAN) {
667 0 : val = BVAL(buf, offset);
668 : } else {
669 0 : val = RBVAL(buf, offset);
670 : }
671 :
672 0 : tag->size = (val & 0xffff) * 8;
673 0 : tag->type = (val & 0xffff0000) >> 16;
674 0 : tag->count = val >> 32;
675 0 : tag->length = tag->count * 8;
676 :
677 0 : if (tag->size > MAX_SL_FRAGMENT_SIZE) {
678 0 : DEBUG(1,("%s: size limit %zu\n", __func__, tag->size));
679 0 : return -1;
680 : }
681 :
682 0 : if (tag->length > MAX_SL_FRAGMENT_SIZE) {
683 0 : DEBUG(1,("%s: length limit %zu\n", __func__, tag->length));
684 0 : return -1;
685 : }
686 :
687 0 : 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 0 : return offset + 8;
693 : }
694 :
695 0 : 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 : int i, result;
702 : struct sl_tag tag;
703 : uint64_t query_data64;
704 :
705 0 : offset = sl_unpack_tag(buf, offset, bufsize, encoding, &tag);
706 0 : if (offset == -1) {
707 0 : return -1;
708 : }
709 :
710 0 : for (i = 0; i < tag.count; i++) {
711 0 : offset = sl_pull_uint64_val(buf, offset, bufsize, encoding, &query_data64);
712 0 : if (offset == -1) {
713 0 : return -1;
714 : }
715 0 : result = dalloc_add_copy(query, &query_data64, uint64_t);
716 0 : if (result != 0) {
717 0 : return -1;
718 : }
719 : }
720 :
721 0 : 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 : int i, result;
731 : struct sl_tag tag;
732 : uint64_t query_data64;
733 : union {
734 : double d;
735 : uint64_t w;
736 : } ieee_fp_union;
737 : double fraction;
738 : 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 0 : 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 : int i, result;
774 : sl_uuid_t uuid;
775 : struct sl_tag tag;
776 :
777 0 : offset = sl_unpack_tag(buf, offset, bufsize, encoding, &tag);
778 0 : if (offset == -1) {
779 0 : return -1;
780 : }
781 :
782 0 : for (i = 0; i < tag.count; i++) {
783 0 : if (offset + 16 > bufsize) {
784 0 : DEBUG(1,("%s: buffer overflow\n", __func__));
785 0 : return -1;
786 : }
787 0 : memcpy(uuid.sl_uuid, buf + offset, 16);
788 0 : result = dalloc_add_copy(query, &uuid, sl_uuid_t);
789 0 : if (result != 0) {
790 0 : return -1;
791 : }
792 0 : offset += 16;
793 : }
794 :
795 0 : return tag.count;
796 : }
797 :
798 0 : 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 : int i, result;
805 : union {
806 : double d;
807 : uint32_t w[2];
808 : } ieee_fp_union;
809 : struct sl_tag tag;
810 :
811 0 : offset = sl_unpack_tag(buf, offset, bufsize, encoding, &tag);
812 0 : if (offset == -1) {
813 0 : return -1;
814 : }
815 :
816 0 : for (i = 0; i < tag.count; i++) {
817 0 : if (offset + 8 > bufsize) {
818 0 : DEBUG(1,("%s: buffer overflow\n", __func__));
819 0 : return -1;
820 : }
821 0 : 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 0 : ieee_fp_union.w[0] = IVAL(buf, offset);
827 0 : 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 0 : result = dalloc_add_copy(query, &ieee_fp_union.d, double);
839 0 : if (result != 0) {
840 0 : return -1;
841 : }
842 0 : offset += 8;
843 : }
844 :
845 0 : return tag.count;
846 : }
847 :
848 0 : 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 : int i, count, result;
856 : uint64_t query_data64;
857 : sl_cnids_t *cnids;
858 :
859 0 : cnids = talloc_zero(query, sl_cnids_t);
860 0 : if (cnids == NULL) {
861 0 : return -1;
862 : }
863 0 : cnids->ca_cnids = dalloc_new(cnids);
864 0 : if (cnids->ca_cnids == NULL) {
865 0 : return -1;
866 : }
867 :
868 0 : if (length < 8) {
869 0 : return -1;
870 : }
871 0 : if (length == 8) {
872 : /*
873 : * That's permitted, length=8 is an empty CNID array.
874 : */
875 0 : result = dalloc_add(query, cnids, sl_cnids_t);
876 0 : if (result != 0) {
877 0 : return -1;
878 : }
879 0 : return 0;
880 : }
881 :
882 0 : offset = sl_pull_uint64_val(buf, offset, bufsize, encoding, &query_data64);
883 0 : 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 0 : count = query_data64 & 0xffff;;
894 0 : cnids->ca_unkn1 = (query_data64 & 0xffff0000) >> 16;
895 0 : cnids->ca_context = query_data64 >> 32;
896 :
897 0 : for (i = 0; i < count; i++) {
898 0 : offset = sl_pull_uint64_val(buf, offset, bufsize, encoding, &query_data64);
899 0 : if (offset == -1) {
900 0 : return -1;
901 : }
902 :
903 0 : result = dalloc_add_copy(cnids->ca_cnids, &query_data64, uint64_t);
904 0 : if (result != 0) {
905 0 : return -1;
906 : }
907 : }
908 :
909 0 : result = dalloc_add(query, cnids, sl_cnids_t);
910 0 : if (result != 0) {
911 0 : return -1;
912 : }
913 :
914 0 : return 0;
915 : }
916 :
917 0 : 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 : int result;
927 0 : ssize_t roffset = offset;
928 : int unicode_encoding;
929 : bool mark_exists;
930 : char *p;
931 : size_t slen, tmp_len;
932 : sl_array_t *sl_array;
933 : sl_dict_t *sl_dict;
934 : sl_filemeta_t *sl_fm;
935 : bool ok;
936 : struct sl_tag tag;
937 :
938 0 : switch (cpx_query_type) {
939 0 : case SQ_CPX_TYPE_ARRAY:
940 0 : sl_array = dalloc_zero(query, sl_array_t);
941 0 : if (sl_array == NULL) {
942 0 : return -1;
943 : }
944 0 : roffset = sl_unpack_loop(sl_array, buf, offset, bufsize,
945 : cpx_query_count, toc_offset, encoding);
946 0 : if (roffset == -1) {
947 0 : return -1;
948 : }
949 0 : result = dalloc_add(query, sl_array, sl_array_t);
950 0 : if (result != 0) {
951 0 : return -1;
952 : }
953 0 : break;
954 :
955 0 : case SQ_CPX_TYPE_DICT:
956 0 : sl_dict = dalloc_zero(query, sl_dict_t);
957 0 : if (sl_dict == NULL) {
958 0 : return -1;
959 : }
960 0 : roffset = sl_unpack_loop(sl_dict, buf, offset, bufsize,
961 : cpx_query_count, toc_offset, encoding);
962 0 : if (roffset == -1) {
963 0 : return -1;
964 : }
965 0 : result = dalloc_add(query, sl_dict, sl_dict_t);
966 0 : if (result != 0) {
967 0 : return -1;
968 : }
969 0 : break;
970 :
971 0 : case SQ_CPX_TYPE_STRING:
972 : case SQ_CPX_TYPE_UTF16_STRING:
973 0 : offset = sl_unpack_tag(buf, offset, bufsize, encoding, &tag);
974 0 : if (offset == -1) {
975 0 : return -1;
976 : }
977 :
978 0 : if (tag.size < 16) {
979 0 : DEBUG(1,("%s: string buffer too small\n", __func__));
980 0 : return -1;
981 : }
982 0 : slen = tag.size - 16 + tag.count;
983 0 : if (slen > MAX_SL_FRAGMENT_SIZE) {
984 0 : return -1;
985 : }
986 :
987 0 : if (offset + slen > bufsize) {
988 0 : DEBUG(1,("%s: buffer overflow\n", __func__));
989 0 : return -1;
990 : }
991 :
992 0 : if (cpx_query_type == SQ_CPX_TYPE_STRING) {
993 0 : p = talloc_strndup(query, buf + offset, slen);
994 0 : if (p == NULL) {
995 0 : return -1;
996 : }
997 : } else {
998 0 : unicode_encoding = spotlight_get_utf16_string_encoding(
999 : buf, offset, slen, encoding);
1000 0 : mark_exists = (unicode_encoding & SL_ENC_UTF_16) ? true : false;
1001 0 : if (unicode_encoding & SL_ENC_BIG_ENDIAN) {
1002 0 : DEBUG(1, ("Unsupported big endian UTF16 string"));
1003 0 : return -1;
1004 : }
1005 0 : slen -= mark_exists ? 2 : 0;
1006 0 : ok = convert_string_talloc(
1007 : query,
1008 : CH_UTF16LE,
1009 : CH_UTF8,
1010 0 : buf + offset + (mark_exists ? 2 : 0),
1011 : slen,
1012 : &p,
1013 : &tmp_len);
1014 0 : if (!ok) {
1015 0 : return -1;
1016 : }
1017 : }
1018 :
1019 0 : result = dalloc_stradd(query, p);
1020 0 : if (result != 0) {
1021 0 : return -1;
1022 : }
1023 0 : roffset += tag.size;
1024 0 : break;
1025 :
1026 0 : case SQ_CPX_TYPE_FILEMETA:
1027 0 : offset = sl_unpack_tag(buf, offset, bufsize, encoding, &tag);
1028 0 : if (offset == -1) {
1029 0 : return -1;
1030 : }
1031 0 : if (tag.size < 8) {
1032 0 : DBG_WARNING("size too mall: %zu\n", tag.size);
1033 0 : return -1;
1034 : }
1035 :
1036 0 : sl_fm = dalloc_zero(query, sl_filemeta_t);
1037 0 : if (sl_fm == NULL) {
1038 0 : return -1;
1039 : }
1040 :
1041 0 : if (tag.size >= 16) {
1042 0 : result = sl_unpack(sl_fm,
1043 : buf + offset,
1044 : bufsize - offset );
1045 0 : if (result == -1) {
1046 0 : return -1;
1047 : }
1048 : }
1049 0 : result = dalloc_add(query, sl_fm, sl_filemeta_t);
1050 0 : if (result != 0) {
1051 0 : return -1;
1052 : }
1053 0 : roffset += tag.size;
1054 0 : break;
1055 :
1056 0 : case SQ_CPX_TYPE_CNIDS:
1057 0 : offset = sl_unpack_tag(buf, offset, bufsize, encoding, &tag);
1058 0 : if (offset == -1) {
1059 0 : return -1;
1060 : }
1061 :
1062 0 : result = sl_unpack_CNID(query, buf, offset, bufsize,
1063 0 : tag.size, encoding);
1064 0 : if (result == -1) {
1065 0 : return -1;
1066 : }
1067 0 : roffset += tag.size;
1068 0 : break;
1069 :
1070 0 : default:
1071 0 : DEBUG(1, ("unknown complex query type: %u", cpx_query_type));
1072 0 : return -1;
1073 : }
1074 :
1075 0 : return roffset;
1076 : }
1077 :
1078 0 : 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 : int i, toc_index, subcount;
1087 : uint64_t result;
1088 :
1089 0 : while (count > 0) {
1090 : struct sl_tag tag;
1091 :
1092 0 : if (offset >= toc_offset) {
1093 0 : return -1;
1094 : }
1095 :
1096 0 : result = sl_unpack_tag(buf, offset, bufsize, encoding, &tag);
1097 0 : if (result == -1) {
1098 0 : return -1;
1099 : }
1100 :
1101 0 : switch (tag.type) {
1102 0 : case SQ_TYPE_COMPLEX: {
1103 : struct sl_tag cpx_tag;
1104 :
1105 0 : if (tag.count < 1) {
1106 0 : DEBUG(1,("%s: invalid tag.count: %d\n",
1107 : __func__, tag.count));
1108 0 : return -1;
1109 : }
1110 0 : toc_index = tag.count - 1;
1111 0 : 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 0 : result = sl_unpack_tag(buf, toc_offset + (toc_index * 8),
1117 : bufsize, encoding, &cpx_tag);
1118 0 : if (result == -1) {
1119 0 : return -1;
1120 : }
1121 :
1122 0 : offset = sl_unpack_cpx(query, buf, offset + 8, bufsize, cpx_tag.type,
1123 : cpx_tag.count, toc_offset, encoding);
1124 0 : if (offset == -1) {
1125 0 : 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 0 : count--;
1133 0 : break;
1134 : }
1135 :
1136 0 : case SQ_TYPE_NULL: {
1137 0 : sl_nil_t nil = 0;
1138 :
1139 0 : subcount = tag.count;
1140 0 : if (subcount < 1 || subcount > count) {
1141 0 : return -1;
1142 : }
1143 0 : for (i = 0; i < subcount; i++) {
1144 0 : result = dalloc_add_copy(query, &nil, sl_nil_t);
1145 0 : if (result != 0) {
1146 0 : return -1;
1147 : }
1148 : }
1149 0 : offset += tag.size;
1150 0 : count -= subcount;
1151 0 : break;
1152 : }
1153 :
1154 0 : case SQ_TYPE_BOOL: {
1155 0 : sl_bool_t b = (tag.count != 0);
1156 :
1157 0 : result = dalloc_add_copy(query, &b, sl_bool_t);
1158 0 : if (result != 0) {
1159 0 : return -1;
1160 : }
1161 0 : offset += tag.size;
1162 0 : count--;
1163 0 : break;
1164 : }
1165 :
1166 0 : case SQ_TYPE_INT64:
1167 0 : subcount = sl_unpack_ints(query, buf, offset, bufsize, encoding);
1168 0 : if (subcount < 1 || subcount > count) {
1169 0 : return -1;
1170 : }
1171 0 : offset += tag.size;
1172 0 : count -= subcount;
1173 0 : break;
1174 :
1175 0 : case SQ_TYPE_UUID:
1176 0 : subcount = sl_unpack_uuid(query, buf, offset, bufsize, encoding);
1177 0 : if (subcount < 1 || subcount > count) {
1178 0 : return -1;
1179 : }
1180 0 : offset += tag.size;
1181 0 : count -= subcount;
1182 0 : break;
1183 :
1184 0 : case SQ_TYPE_FLOAT:
1185 0 : subcount = sl_unpack_floats(query, buf, offset, bufsize, encoding);
1186 0 : if (subcount < 1 || subcount > count) {
1187 0 : return -1;
1188 : }
1189 0 : offset += tag.size;
1190 0 : count -= subcount;
1191 0 : 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 0 : return offset;
1209 : }
1210 :
1211 0 : static ssize_t sl_pack(DALLOC_CTX *query, char *buf, size_t bufsize)
1212 : {
1213 : ssize_t result;
1214 : char *toc_buf;
1215 0 : int toc_index = 0;
1216 0 : int toc_count = 0;
1217 : ssize_t offset, len;
1218 : uint64_t hdr;
1219 : uint32_t total_octets;
1220 : uint32_t data_octets;
1221 : uint64_t tag;
1222 :
1223 0 : memset(buf, 0, bufsize);
1224 :
1225 0 : toc_buf = talloc_zero_size(query, MAX_SLQ_TOC + 8);
1226 0 : if (toc_buf == NULL) {
1227 0 : return -1;
1228 : }
1229 :
1230 0 : offset = sl_pack_loop(query, buf, 16, bufsize, toc_buf + 8, &toc_index, &toc_count);
1231 0 : if (offset == -1 || offset < 16) {
1232 0 : DEBUG(10,("%s: sl_pack_loop error\n", __func__));
1233 0 : return -1;
1234 : }
1235 0 : 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 0 : 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 0 : data_octets = (len / 8) + 1;
1259 0 : total_octets = data_octets + toc_index + 1;
1260 :
1261 0 : hdr = total_octets;
1262 0 : hdr |= ((uint64_t)data_octets << 32);
1263 :
1264 : /* HDR */
1265 0 : result = sl_push_uint64_val(buf, 8, bufsize, hdr);
1266 0 : 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 0 : tag = sl_pack_tag(SQ_TYPE_TOC, toc_index + 1, 0);
1275 0 : result = sl_push_uint64_val(toc_buf, 0, MAX_SLQ_TOC, tag);
1276 0 : if (result == -1) {
1277 0 : return -1;
1278 : }
1279 :
1280 0 : if ((16 + len + ((toc_index + 1 ) * 8)) > bufsize) {
1281 0 : DEBUG(1, ("%s: exceeding size limit %zu", __func__, bufsize));
1282 0 : return -1;
1283 : }
1284 :
1285 0 : memcpy(buf + 16 + len, toc_buf, (toc_index + 1 ) * 8);
1286 0 : len += 16 + (toc_index + 1 ) * 8;
1287 :
1288 0 : return len;
1289 : }
1290 :
1291 : /******************************************************************************
1292 : * Global functions for packing und unpacking
1293 : ******************************************************************************/
1294 :
1295 0 : 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 : ssize_t len;
1301 :
1302 0 : b->spotlight_blob = talloc_zero_array(mem_ctx,
1303 : uint8_t,
1304 : max_fragment_size);
1305 0 : if (b->spotlight_blob == NULL) {
1306 0 : return NT_STATUS_NO_MEMORY;
1307 : }
1308 :
1309 0 : len = sl_pack(d, (char *)b->spotlight_blob, max_fragment_size);
1310 0 : if (len == -1) {
1311 0 : return NT_STATUS_DATA_ERROR;
1312 : }
1313 :
1314 0 : b->length = len;
1315 0 : b->size = len;
1316 0 : return NT_STATUS_OK;
1317 : }
1318 :
1319 0 : bool sl_unpack(DALLOC_CTX *query, const char *buf, size_t bufsize)
1320 : {
1321 : ssize_t result;
1322 0 : ssize_t offset = 0;
1323 : int encoding;
1324 : uint64_t hdr;
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;
1331 :
1332 0 : if (bufsize > MAX_SL_FRAGMENT_SIZE) {
1333 0 : return false;
1334 : }
1335 :
1336 0 : if (bufsize < 8) {
1337 0 : return false;
1338 : }
1339 0 : if (strncmp(buf + offset, "md031234", 8) == 0) {
1340 0 : encoding = SL_ENC_BIG_ENDIAN;
1341 : } else {
1342 0 : encoding = SL_ENC_LITTLE_ENDIAN;
1343 : }
1344 0 : offset += 8;
1345 :
1346 0 : offset = sl_pull_uint64_val(buf, offset, bufsize, encoding, &hdr);
1347 0 : if (offset == -1) {
1348 0 : return false;
1349 : }
1350 :
1351 0 : total_octets = hdr & UINT32_MAX;
1352 0 : 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 0 : if (total_octets < 1) {
1360 0 : return false;
1361 : }
1362 0 : if (data_octets < 1) {
1363 0 : return false;
1364 : }
1365 0 : total_octets--;
1366 0 : data_octets--;
1367 0 : data_bytes = ((uint64_t)data_octets) * 8;
1368 0 : total_bytes = ((uint64_t)total_octets) * 8;
1369 :
1370 0 : 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 0 : if (total_bytes > (bufsize - offset)) {
1377 0 : return false;
1378 : }
1379 :
1380 0 : toc_offset = data_bytes;
1381 :
1382 0 : toc_offset = sl_unpack_tag(buf + offset, toc_offset,
1383 : bufsize - offset, encoding, &toc_tag);
1384 0 : if (toc_offset == -1) {
1385 0 : return false;
1386 : }
1387 :
1388 0 : 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 0 : 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 0 : 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 0 : 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 0 : result = sl_unpack_loop(query, buf + offset, 0, bufsize - offset,
1415 : 1, toc_offset, encoding);
1416 0 : if (result == -1) {
1417 0 : DEBUG(1,("%s: sl_unpack_loop failed\n", __func__));
1418 0 : return false;
1419 : }
1420 :
1421 0 : return true;
1422 : }
|