s3: RPC: Don't crash on trying to talloc_free(-1) if smb_iconv_open_ex() fails.
[Samba.git] / source3 / rpc_server / mdssvc / mdssvc.c
blobd6edc1c1686a79c856cc2be8f2307a8475b67363
1 /*
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/>.
21 #include "includes.h"
22 #include "librpc/gen_ndr/auth.h"
23 #include "dbwrap/dbwrap.h"
24 #include "lib/util/dlinklist.h"
25 #include "lib/util/util_tdb.h"
26 #include "lib/util/time_basic.h"
27 #include "lib/dbwrap/dbwrap_rbt.h"
28 #include "libcli/security/dom_sid.h"
29 #include "mdssvc.h"
30 #include "mdssvc_noindex.h"
31 #ifdef HAVE_SPOTLIGHT_BACKEND_TRACKER
32 #include "mdssvc_tracker.h"
33 #endif
34 #ifdef HAVE_SPOTLIGHT_BACKEND_ES
35 #include "mdssvc_es.h"
36 #endif
38 #undef DBGC_CLASS
39 #define DBGC_CLASS DBGC_RPC_SRV
41 struct slrpc_cmd {
42 const char *name;
43 bool (*function)(struct mds_ctx *mds_ctx,
44 const DALLOC_CTX *query,
45 DALLOC_CTX *reply);
48 struct slq_destroy_state {
49 struct tevent_context *ev;
50 struct sl_query *slq;
54 * This is a static global because we may be called multiple times and
55 * we only want one mdssvc_ctx per connection to Tracker.
57 * The client will bind multiple times to the mdssvc RPC service, once
58 * for every tree connect.
60 static struct mdssvc_ctx *mdssvc_ctx = NULL;
63 * If these functions return an error, they hit something like a non
64 * recoverable talloc error. Most errors are dealt with by returning
65 * an error code in the Spotlight RPC reply.
67 static bool slrpc_fetch_properties(struct mds_ctx *mds_ctx,
68 const DALLOC_CTX *query, DALLOC_CTX *reply);
69 static bool slrpc_open_query(struct mds_ctx *mds_ctx,
70 const DALLOC_CTX *query, DALLOC_CTX *reply);
71 static bool slrpc_fetch_query_results(struct mds_ctx *mds_ctx,
72 const DALLOC_CTX *query, DALLOC_CTX *reply);
73 static bool slrpc_store_attributes(struct mds_ctx *mds_ctx,
74 const DALLOC_CTX *query, DALLOC_CTX *reply);
75 static bool slrpc_fetch_attributenames(struct mds_ctx *mds_ctx,
76 const DALLOC_CTX *query, DALLOC_CTX *reply);
77 static bool slrpc_fetch_attributes(struct mds_ctx *mds_ctx,
78 const DALLOC_CTX *query, DALLOC_CTX *reply);
79 static bool slrpc_close_query(struct mds_ctx *mds_ctx,
80 const DALLOC_CTX *query, DALLOC_CTX *reply);
82 /************************************************
83 * Misc utility functions
84 ************************************************/
86 /**
87 * Add requested metadata for a query result element
89 * This could be rewritten to something more sophisticated like
90 * querying metadata from Tracker.
92 * If path or sp is NULL, simply add nil values for all attributes.
93 **/
94 static bool add_filemeta(struct mds_ctx *mds_ctx,
95 sl_array_t *reqinfo,
96 sl_array_t *fm_array,
97 const char *path,
98 const struct stat_ex *sp)
100 sl_array_t *meta;
101 sl_nil_t nil;
102 int i, metacount, result;
103 uint64_t uint64var;
104 sl_time_t sl_time;
105 char *p;
106 const char *attribute;
107 size_t nfc_len;
108 const char *nfc_path = path;
109 size_t nfd_buf_size;
110 char *nfd_path = NULL;
111 char *dest = NULL;
112 size_t dest_remaining;
113 size_t nconv;
115 metacount = dalloc_size(reqinfo);
116 if (metacount == 0 || path == NULL || sp == NULL) {
117 result = dalloc_add_copy(fm_array, &nil, sl_nil_t);
118 if (result != 0) {
119 return false;
121 return true;
124 meta = dalloc_zero(fm_array, sl_array_t);
125 if (meta == NULL) {
126 return false;
129 nfc_len = strlen(nfc_path);
131 * Simple heuristic, strlen by two should give enough room for NFC to
132 * NFD conversion.
134 nfd_buf_size = nfc_len * 2;
135 nfd_path = talloc_array(meta, char, nfd_buf_size);
136 if (nfd_path == NULL) {
137 return false;
139 dest = nfd_path;
140 dest_remaining = talloc_array_length(dest);
142 nconv = smb_iconv(mds_ctx->ic_nfc_to_nfd,
143 &nfc_path,
144 &nfc_len,
145 &dest,
146 &dest_remaining);
147 if (nconv == (size_t)-1) {
148 return false;
151 for (i = 0; i < metacount; i++) {
152 attribute = dalloc_get_object(reqinfo, i);
153 if (attribute == NULL) {
154 return false;
156 if (strcmp(attribute, "kMDItemDisplayName") == 0
157 || strcmp(attribute, "kMDItemFSName") == 0) {
158 p = strrchr(nfd_path, '/');
159 if (p) {
160 result = dalloc_stradd(meta, p + 1);
161 if (result != 0) {
162 return false;
165 } else if (strcmp(attribute, "kMDItemPath") == 0) {
166 result = dalloc_stradd(meta, nfd_path);
167 if (result != 0) {
168 return false;
170 } else if (strcmp(attribute, "kMDItemFSSize") == 0) {
171 uint64var = sp->st_ex_size;
172 result = dalloc_add_copy(meta, &uint64var, uint64_t);
173 if (result != 0) {
174 return false;
176 } else if (strcmp(attribute, "kMDItemFSOwnerUserID") == 0) {
177 uint64var = sp->st_ex_uid;
178 result = dalloc_add_copy(meta, &uint64var, uint64_t);
179 if (result != 0) {
180 return false;
182 } else if (strcmp(attribute, "kMDItemFSOwnerGroupID") == 0) {
183 uint64var = sp->st_ex_gid;
184 result = dalloc_add_copy(meta, &uint64var, uint64_t);
185 if (result != 0) {
186 return false;
188 } else if (strcmp(attribute, "kMDItemFSContentChangeDate") == 0) {
189 sl_time.tv_sec = sp->st_ex_mtime.tv_sec;
190 result = dalloc_add_copy(meta, &sl_time, sl_time_t);
191 if (result != 0) {
192 return false;
194 } else {
195 result = dalloc_add_copy(meta, &nil, sl_nil_t);
196 if (result != 0) {
197 return false;
202 result = dalloc_add(fm_array, meta, sl_array_t);
203 if (result != 0) {
204 return false;
206 return true;
209 static int cnid_comp_fn(const void *p1, const void *p2)
211 const uint64_t *cnid1 = p1, *cnid2 = p2;
212 if (*cnid1 == *cnid2) {
213 return 0;
215 if (*cnid1 < *cnid2) {
216 return -1;
218 return 1;
222 * Create a sorted copy of a CNID array
224 static bool sort_cnids(struct sl_query *slq, const DALLOC_CTX *d)
226 uint64_t *cnids = NULL;
227 int i;
228 const void *p;
230 cnids = talloc_array(slq, uint64_t, dalloc_size(d));
231 if (cnids == NULL) {
232 return false;
235 for (i = 0; i < dalloc_size(d); i++) {
236 p = dalloc_get_object(d, i);
237 if (p == NULL) {
238 return NULL;
240 memcpy(&cnids[i], p, sizeof(uint64_t));
242 qsort(cnids, dalloc_size(d), sizeof(uint64_t), cnid_comp_fn);
244 slq->cnids = cnids;
245 slq->cnids_num = dalloc_size(d);
247 return true;
251 * Allocate result handle used in the async Tracker cursor result
252 * handler for storing results
254 static bool create_result_handle(struct sl_query *slq)
256 sl_nil_t nil = 0;
257 struct sl_rslts *query_results;
258 int result;
260 if (slq->query_results) {
261 DEBUG(1, ("unexpected existing result handle\n"));
262 return false;
265 query_results = talloc_zero(slq, struct sl_rslts);
266 if (query_results == NULL) {
267 return false;
270 /* CNIDs */
271 query_results->cnids = talloc_zero(query_results, sl_cnids_t);
272 if (query_results->cnids == NULL) {
273 return false;
275 query_results->cnids->ca_cnids = dalloc_new(query_results->cnids);
276 if (query_results->cnids->ca_cnids == NULL) {
277 return false;
280 query_results->cnids->ca_unkn1 = 0xadd;
281 if (slq->ctx2 > UINT32_MAX) {
282 DEBUG(1,("64bit ctx2 id too large: 0x%jx", (uintmax_t)slq->ctx2));
283 return false;
285 query_results->cnids->ca_context = (uint32_t)slq->ctx2;
287 /* FileMeta */
288 query_results->fm_array = dalloc_zero(query_results, sl_array_t);
289 if (query_results->fm_array == NULL) {
290 return false;
293 /* For some reason the list of results always starts with a nil entry */
294 result = dalloc_add_copy(query_results->fm_array, &nil, sl_nil_t);
295 if (result != 0) {
296 return false;
299 slq->query_results = query_results;
300 return true;
303 static bool add_results(sl_array_t *array, struct sl_query *slq)
305 sl_filemeta_t *fm;
306 uint64_t status = 0;
307 int result;
308 bool ok;
310 /* FileMeta */
311 fm = dalloc_zero(array, sl_filemeta_t);
312 if (fm == NULL) {
313 return false;
316 result = dalloc_add_copy(array, &status, uint64_t);
317 if (result != 0) {
318 return false;
320 result = dalloc_add(array, slq->query_results->cnids, sl_cnids_t);
321 if (result != 0) {
322 return false;
324 if (slq->query_results->num_results > 0) {
325 result = dalloc_add(fm, slq->query_results->fm_array, sl_array_t);
326 if (result != 0) {
327 return false;
330 result = dalloc_add(array, fm, sl_filemeta_t);
331 if (result != 0) {
332 return false;
335 /* This ensure the results get clean up after been sent to the client */
336 talloc_move(array, &slq->query_results);
338 ok = create_result_handle(slq);
339 if (!ok) {
340 DEBUG(1, ("couldn't add result handle\n"));
341 slq->state = SLQ_STATE_ERROR;
342 return false;
345 return true;
348 static const struct slrpc_cmd *slrpc_cmd_by_name(const char *rpccmd)
350 size_t i;
351 static const struct slrpc_cmd cmds[] = {
352 { "fetchPropertiesForContext:", slrpc_fetch_properties},
353 { "openQueryWithParams:forContext:", slrpc_open_query},
354 { "fetchQueryResultsForContext:", slrpc_fetch_query_results},
355 { "storeAttributes:forOIDArray:context:", slrpc_store_attributes},
356 { "fetchAttributeNamesForOIDArray:context:", slrpc_fetch_attributenames},
357 { "fetchAttributes:forOIDArray:context:", slrpc_fetch_attributes},
358 { "fetchAllAttributes:forOIDArray:context:", slrpc_fetch_attributes},
359 { "closeQueryForContext:", slrpc_close_query},
362 for (i = 0; i < ARRAY_SIZE(cmds); i++) {
363 int cmp;
365 cmp = strcmp(cmds[i].name, rpccmd);
366 if (cmp == 0) {
367 return &cmds[i];
371 return NULL;
375 * Search the list of active queries given their context ids
377 static struct sl_query *slq_for_ctx(struct mds_ctx *mds_ctx,
378 uint64_t ctx1, uint64_t ctx2)
380 struct sl_query *q;
382 for (q = mds_ctx->query_list; q; q = q->next) {
383 if ((q->ctx1 == ctx1) && (q->ctx2 == ctx2)) {
384 return q;
388 return NULL;
391 static int slq_destructor_cb(struct sl_query *slq)
393 SLQ_DEBUG(10, slq, "destroying");
395 /* Free all entries before freeing the slq handle! */
396 TALLOC_FREE(slq->entries_ctx);
397 TALLOC_FREE(slq->te);
399 if (slq->mds_ctx != NULL) {
400 DLIST_REMOVE(slq->mds_ctx->query_list, slq);
401 slq->mds_ctx = NULL;
404 TALLOC_FREE(slq->backend_private);
406 return 0;
410 * Remove talloc_refcounted entry from mapping db
412 * Multiple queries (via the slq handle) may reference a
413 * sl_inode_path_map entry, when the last reference goes away as the
414 * queries are closed and this gets called to remove the entry from
415 * the db.
417 static int ino_path_map_destr_cb(struct sl_inode_path_map *entry)
419 NTSTATUS status;
420 TDB_DATA key;
422 key = make_tdb_data((uint8_t *)&entry->ino, sizeof(entry->ino));
424 status = dbwrap_delete(entry->mds_ctx->ino_path_map, key);
425 if (!NT_STATUS_IS_OK(status)) {
426 DEBUG(1, ("Failed to delete record: %s\n", nt_errstr(status)));
427 return -1;
430 DBG_DEBUG("deleted [0x%"PRIx64"] [%s]\n", entry->ino, entry->path);
431 return 0;
435 * Add result to inode->path mapping dbwrap rbt db
437 * This is necessary as a CNID db substitute, ie we need a way to
438 * simulate unique, constant numerical identifiers for paths with an
439 * API that supports mapping from id to path.
441 * Entries are talloc'ed of the query, using talloc_reference() if
442 * multiple queries returned the same result. That way we can cleanup
443 * entries by calling talloc_free() on the query slq handles.
446 static bool inode_map_add(struct sl_query *slq, uint64_t ino, const char *path)
448 NTSTATUS status;
449 struct sl_inode_path_map *entry;
450 TDB_DATA key, value;
451 void *p;
453 key = make_tdb_data((uint8_t *)&ino, sizeof(ino));
454 status = dbwrap_fetch(slq->mds_ctx->ino_path_map, slq, key, &value);
456 if (NT_STATUS_IS_OK(status)) {
458 * We have one db, so when different parallel queries
459 * return the same file, we have to refcount entries
460 * in the db.
463 if (value.dsize != sizeof(void *)) {
464 DEBUG(1, ("invalide dsize\n"));
465 return false;
467 memcpy(&p, value.dptr, sizeof(p));
468 entry = talloc_get_type_abort(p, struct sl_inode_path_map);
470 DEBUG(10, ("map: %s\n", entry->path));
472 entry = talloc_reference(slq->entries_ctx, entry);
473 if (entry == NULL) {
474 DEBUG(1, ("talloc_reference failed\n"));
475 return false;
477 return true;
480 if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
481 DEBUG(1, ("dbwrap_fetch failed %s\n", nt_errstr(status)));
482 return false;
485 entry = talloc_zero(slq->entries_ctx, struct sl_inode_path_map);
486 if (entry == NULL) {
487 DEBUG(1, ("talloc failed\n"));
488 return false;
491 entry->ino = ino;
492 entry->mds_ctx = slq->mds_ctx;
493 entry->path = talloc_strdup(entry, path);
494 if (entry->path == NULL) {
495 DEBUG(1, ("talloc failed\n"));
496 TALLOC_FREE(entry);
497 return false;
500 status = dbwrap_store(slq->mds_ctx->ino_path_map, key,
501 make_tdb_data((void *)&entry, sizeof(void *)), 0);
502 if (!NT_STATUS_IS_OK(status)) {
503 DEBUG(1, ("Failed to store record: %s\n", nt_errstr(status)));
504 TALLOC_FREE(entry);
505 return false;
508 talloc_set_destructor(entry, ino_path_map_destr_cb);
510 return true;
513 bool mds_add_result(struct sl_query *slq, const char *path)
515 struct stat_ex sb;
516 uint64_t ino64;
517 int result;
518 bool ok;
521 * We're in a tevent callback which means in the case of
522 * running as external RPC service we're running as root and
523 * not as the user.
525 if (!become_authenticated_pipe_user(slq->mds_ctx->pipe_session_info)) {
526 DBG_ERR("can't become authenticated user: %d\n",
527 slq->mds_ctx->uid);
528 smb_panic("can't become authenticated user");
531 if (geteuid() != slq->mds_ctx->uid) {
532 DBG_ERR("uid mismatch: %d/%d\n", geteuid(), slq->mds_ctx->uid);
533 smb_panic("uid mismatch");
537 * We've changed identity to the authenticated pipe user, so
538 * any function exit below must ensure we switch back
541 result = sys_stat(path, &sb, false);
542 if (result != 0) {
543 unbecome_authenticated_pipe_user();
544 return true;
546 result = access(path, R_OK);
547 if (result != 0) {
548 unbecome_authenticated_pipe_user();
549 return true;
552 unbecome_authenticated_pipe_user();
554 ino64 = sb.st_ex_ino;
555 if (slq->cnids) {
557 * Check whether the found element is in the requested
558 * set of IDs. Note that we're faking CNIDs by using
559 * filesystem inode numbers here
561 ok = bsearch(&ino64,
562 slq->cnids,
563 slq->cnids_num,
564 sizeof(uint64_t),
565 cnid_comp_fn);
566 if (!ok) {
567 return false;
572 * Add inode number and filemeta to result set, this is what
573 * we return as part of the result set of a query
575 result = dalloc_add_copy(slq->query_results->cnids->ca_cnids,
576 &ino64,
577 uint64_t);
578 if (result != 0) {
579 DBG_ERR("dalloc error\n");
580 slq->state = SLQ_STATE_ERROR;
581 return false;
583 ok = add_filemeta(slq->mds_ctx,
584 slq->reqinfo,
585 slq->query_results->fm_array,
586 path,
587 &sb);
588 if (!ok) {
589 DBG_ERR("add_filemeta error\n");
590 slq->state = SLQ_STATE_ERROR;
591 return false;
594 ok = inode_map_add(slq, ino64, path);
595 if (!ok) {
596 DEBUG(1, ("inode_map_add error\n"));
597 slq->state = SLQ_STATE_ERROR;
598 return false;
601 slq->query_results->num_results++;
602 return true;
605 /***********************************************************
606 * Spotlight RPC functions
607 ***********************************************************/
609 static bool slrpc_fetch_properties(struct mds_ctx *mds_ctx,
610 const DALLOC_CTX *query, DALLOC_CTX *reply)
612 sl_dict_t *dict;
613 sl_array_t *array;
614 char *s;
615 uint64_t u;
616 sl_bool_t b;
617 sl_uuid_t uuid;
618 int result;
620 dict = dalloc_zero(reply, sl_dict_t);
621 if (dict == NULL) {
622 return false;
625 /* kMDSStoreHasPersistentUUID = false */
626 result = dalloc_stradd(dict, "kMDSStoreHasPersistentUUID");
627 if (result != 0) {
628 return false;
630 b = false;
631 result = dalloc_add_copy(dict, &b, sl_bool_t);
632 if (result != 0) {
633 return false;
636 /* kMDSStoreIsBackup = false */
637 result = dalloc_stradd(dict, "kMDSStoreIsBackup");
638 if (result != 0) {
639 return false;
641 b = false;
642 result = dalloc_add_copy(dict, &b, sl_bool_t);
643 if (result != 0) {
644 return false;
647 /* kMDSStoreUUID = uuid */
648 result = dalloc_stradd(dict, "kMDSStoreUUID");
649 if (result != 0) {
650 return false;
652 memcpy(uuid.sl_uuid, "fakeuuidfakeuuid", sizeof(uuid.sl_uuid));
653 result = dalloc_add_copy(dict, &uuid, sl_uuid_t);
654 if (result != 0) {
655 return false;
658 /* kMDSStoreSupportsVolFS = true */
659 result = dalloc_stradd(dict, "kMDSStoreSupportsVolFS");
660 if (result != 0) {
661 return false;
663 b = true;
664 result = dalloc_add_copy(dict, &b, sl_bool_t);
665 if (result != 0) {
666 return false;
669 /* kMDSVolumeUUID = uuid */
670 result = dalloc_stradd(dict, "kMDSVolumeUUID");
671 if (result != 0) {
672 return false;
674 memcpy(uuid.sl_uuid, "fakeuuidfakeuuid", sizeof(uuid.sl_uuid));
675 result = dalloc_add_copy(dict, &uuid, sl_uuid_t);
676 if (result != 0) {
677 return false;
680 /* kMDSDiskStoreSpindleNumber = 1 (fake) */
681 result = dalloc_stradd(dict, "kMDSDiskStoreSpindleNumber");
682 if (result != 0) {
683 return false;
685 u = 1;
686 result = dalloc_add_copy(dict, &u, uint64_t);
687 if (result != 0) {
688 return false;
691 /* kMDSDiskStorePolicy = 3 (whatever that means, taken from OS X) */
692 result = dalloc_stradd(dict, "kMDSDiskStorePolicy");
693 if (result != 0) {
694 return false;
696 u = 3;
697 result = dalloc_add_copy(dict, &u, uint64_t);
698 if (result != 0) {
699 return false;
702 /* kMDSStoreMetaScopes array */
703 array = dalloc_zero(dict, sl_array_t);
704 if (array == NULL) {
705 return NULL;
707 result = dalloc_stradd(array, "kMDQueryScopeComputer");
708 if (result != 0) {
709 return false;
711 result = dalloc_stradd(array, "kMDQueryScopeAllIndexed");
712 if (result != 0) {
713 return false;
715 result = dalloc_stradd(array, "kMDQueryScopeComputerIndexed");
716 if (result != 0) {
717 return false;
719 result = dalloc_add(dict, array, sl_array_t);
720 if (result != 0) {
721 return false;
724 /* kMDSStoreDevice = 0x1000003 (whatever that means, taken from OS X) */
725 result = dalloc_stradd(dict, "kMDSStoreDevice");
726 if (result != 0) {
727 return false;
729 u = 0x1000003;
730 result = dalloc_add_copy(dict, &u, uint64_t);
731 if (result != 0) {
732 return false;
735 /* kMDSStoreSupportsTCC = true (whatever that means, taken from OS X) */
736 result = dalloc_stradd(dict, "kMDSStoreSupportsTCC");
737 if (result != 0) {
738 return false;
740 b = true;
741 result = dalloc_add_copy(dict, &b, sl_bool_t);
742 if (result != 0) {
743 return false;
746 /* kMDSStorePathScopes = ["/"] (whatever that means, taken from OS X) */
747 result = dalloc_stradd(dict, "kMDSStorePathScopes");
748 if (result != 0) {
749 return false;
751 array = dalloc_zero(dict, sl_array_t);
752 if (array == NULL) {
753 return false;
755 s = talloc_strdup(dict, "/");
756 if (s == NULL) {
757 return false;
759 talloc_set_name(s, "smb_ucs2_t *");
760 result = dalloc_add(array, s, smb_ucs2_t *);
761 if (result != 0) {
762 return false;
764 result = dalloc_add(dict, array, sl_array_t);
765 if (result != 0) {
766 return false;
769 result = dalloc_add(reply, dict, sl_dict_t);
770 if (result != 0) {
771 return false;
774 return true;
777 static void slq_close_timer(struct tevent_context *ev,
778 struct tevent_timer *te,
779 struct timeval current_time,
780 void *private_data)
782 struct sl_query *slq = talloc_get_type_abort(
783 private_data, struct sl_query);
784 struct mds_ctx *mds_ctx = slq->mds_ctx;
786 SLQ_DEBUG(10, slq, "expired");
788 TALLOC_FREE(slq);
790 if (CHECK_DEBUGLVL(10)) {
791 for (slq = mds_ctx->query_list; slq != NULL; slq = slq->next) {
792 SLQ_DEBUG(10, slq, "pending");
798 * Begin a search query
800 static bool slrpc_open_query(struct mds_ctx *mds_ctx,
801 const DALLOC_CTX *query, DALLOC_CTX *reply)
803 bool ok;
804 uint64_t sl_result;
805 uint64_t *uint64p;
806 DALLOC_CTX *reqinfo;
807 sl_array_t *array, *path_scope;
808 sl_cnids_t *cnids;
809 struct sl_query *slq = NULL;
810 int result;
811 const char *querystring = NULL;
812 size_t querystring_len;
813 char *dest = NULL;
814 size_t dest_remaining;
815 size_t nconv;
816 char *scope = NULL;
818 array = dalloc_zero(reply, sl_array_t);
819 if (array == NULL) {
820 return false;
823 /* Allocate and initialize query object */
824 slq = talloc_zero(mds_ctx, struct sl_query);
825 if (slq == NULL) {
826 return false;
828 slq->entries_ctx = talloc_named_const(slq, 0, "struct sl_query.entries_ctx");
829 if (slq->entries_ctx == NULL) {
830 TALLOC_FREE(slq);
831 return false;
833 talloc_set_destructor(slq, slq_destructor_cb);
834 slq->state = SLQ_STATE_NEW;
835 slq->mds_ctx = mds_ctx;
837 slq->last_used = timeval_current();
838 slq->start_time = slq->last_used;
839 slq->expire_time = timeval_add(&slq->last_used, MAX_SL_RUNTIME, 0);
840 slq->te = tevent_add_timer(global_event_context(), slq,
841 slq->expire_time, slq_close_timer, slq);
842 if (slq->te == NULL) {
843 DEBUG(1, ("tevent_add_timer failed\n"));
844 goto error;
847 querystring = dalloc_value_for_key(query, "DALLOC_CTX", 0,
848 "DALLOC_CTX", 1,
849 "kMDQueryString");
850 if (querystring == NULL) {
851 DEBUG(1, ("missing kMDQueryString\n"));
852 goto error;
855 querystring_len = talloc_array_length(querystring);
857 slq->query_string = talloc_array(slq, char, querystring_len);
858 if (slq->query_string == NULL) {
859 DEBUG(1, ("out of memory\n"));
860 goto error;
862 dest = slq->query_string;
863 dest_remaining = talloc_array_length(dest);
865 nconv = smb_iconv(mds_ctx->ic_nfd_to_nfc,
866 &querystring,
867 &querystring_len,
868 &dest,
869 &dest_remaining);
870 if (nconv == (size_t)-1) {
871 DBG_ERR("smb_iconv failed for: %s\n", querystring);
872 return false;
875 uint64p = dalloc_get(query, "DALLOC_CTX", 0, "DALLOC_CTX", 0,
876 "uint64_t", 1);
877 if (uint64p == NULL) {
878 goto error;
880 slq->ctx1 = *uint64p;
881 uint64p = dalloc_get(query, "DALLOC_CTX", 0, "DALLOC_CTX", 0,
882 "uint64_t", 2);
883 if (uint64p == NULL) {
884 goto error;
886 slq->ctx2 = *uint64p;
888 path_scope = dalloc_value_for_key(query, "DALLOC_CTX", 0,
889 "DALLOC_CTX", 1, "kMDScopeArray");
890 if (path_scope == NULL) {
891 goto error;
894 scope = dalloc_get(path_scope, "char *", 0);
895 if (scope == NULL) {
896 goto error;
899 slq->path_scope = talloc_strdup(slq, scope);
900 if (slq->path_scope == NULL) {
901 goto error;
904 reqinfo = dalloc_value_for_key(query, "DALLOC_CTX", 0,
905 "DALLOC_CTX", 1, "kMDAttributeArray");
906 if (reqinfo == NULL) {
907 goto error;
910 slq->reqinfo = talloc_steal(slq, reqinfo);
911 DEBUG(10, ("requested attributes: %s", dalloc_dump(reqinfo, 0)));
913 cnids = dalloc_value_for_key(query, "DALLOC_CTX", 0,
914 "DALLOC_CTX", 1, "kMDQueryItemArray");
915 if (cnids) {
916 ok = sort_cnids(slq, cnids->ca_cnids);
917 if (!ok) {
918 goto error;
922 ok = create_result_handle(slq);
923 if (!ok) {
924 DEBUG(1, ("create_result_handle error\n"));
925 slq->state = SLQ_STATE_ERROR;
926 goto error;
929 SLQ_DEBUG(10, slq, "new");
931 DLIST_ADD(mds_ctx->query_list, slq);
933 ok = mds_ctx->backend->search_start(slq);
934 if (!ok) {
935 DBG_ERR("backend search_start failed\n");
936 goto error;
939 sl_result = 0;
940 result = dalloc_add_copy(array, &sl_result, uint64_t);
941 if (result != 0) {
942 goto error;
944 result = dalloc_add(reply, array, sl_array_t);
945 if (result != 0) {
946 goto error;
948 return true;
950 error:
951 sl_result = UINT64_MAX;
952 TALLOC_FREE(slq);
953 result = dalloc_add_copy(array, &sl_result, uint64_t);
954 if (result != 0) {
955 return false;
957 result = dalloc_add(reply, array, sl_array_t);
958 if (result != 0) {
959 return false;
961 return true;
965 * Fetch results of a query
967 static bool slrpc_fetch_query_results(struct mds_ctx *mds_ctx,
968 const DALLOC_CTX *query,
969 DALLOC_CTX *reply)
971 bool ok;
972 struct sl_query *slq = NULL;
973 uint64_t *uint64p, ctx1, ctx2;
974 uint64_t status;
975 sl_array_t *array;
976 int result;
978 array = dalloc_zero(reply, sl_array_t);
979 if (array == NULL) {
980 return false;
983 /* Get query for context */
984 uint64p = dalloc_get(query, "DALLOC_CTX", 0, "DALLOC_CTX", 0,
985 "uint64_t", 1);
986 if (uint64p == NULL) {
987 goto error;
989 ctx1 = *uint64p;
991 uint64p = dalloc_get(query, "DALLOC_CTX", 0, "DALLOC_CTX", 0,
992 "uint64_t", 2);
993 if (uint64p == NULL) {
994 goto error;
996 ctx2 = *uint64p;
998 slq = slq_for_ctx(mds_ctx, ctx1, ctx2);
999 if (slq == NULL) {
1000 DEBUG(1, ("bad context: [0x%jx,0x%jx]\n",
1001 (uintmax_t)ctx1, (uintmax_t)ctx2));
1002 goto error;
1005 TALLOC_FREE(slq->te);
1006 slq->last_used = timeval_current();
1007 slq->expire_time = timeval_add(&slq->last_used, MAX_SL_RUNTIME, 0);
1008 slq->te = tevent_add_timer(global_event_context(), slq,
1009 slq->expire_time, slq_close_timer, slq);
1010 if (slq->te == NULL) {
1011 DEBUG(1, ("tevent_add_timer failed\n"));
1012 goto error;
1015 SLQ_DEBUG(10, slq, "fetch");
1017 switch (slq->state) {
1018 case SLQ_STATE_RUNNING:
1019 case SLQ_STATE_RESULTS:
1020 case SLQ_STATE_FULL:
1021 case SLQ_STATE_DONE:
1022 ok = add_results(array, slq);
1023 if (!ok) {
1024 DEBUG(1, ("error adding results\n"));
1025 goto error;
1027 if (slq->state == SLQ_STATE_FULL) {
1028 slq->state = SLQ_STATE_RESULTS;
1029 slq->mds_ctx->backend->search_cont(slq);
1031 break;
1033 case SLQ_STATE_ERROR:
1034 DEBUG(1, ("query in error state\n"));
1035 goto error;
1037 default:
1038 DEBUG(1, ("unexpected query state %d\n", slq->state));
1039 goto error;
1042 result = dalloc_add(reply, array, sl_array_t);
1043 if (result != 0) {
1044 goto error;
1046 return true;
1048 error:
1049 status = UINT64_MAX;
1050 TALLOC_FREE(slq);
1051 result = dalloc_add_copy(array, &status, uint64_t);
1052 if (result != 0) {
1053 return false;
1055 result = dalloc_add(reply, array, sl_array_t);
1056 if (result != 0) {
1057 return false;
1059 return true;
1063 * Store metadata attributes for a CNID
1065 static bool slrpc_store_attributes(struct mds_ctx *mds_ctx,
1066 const DALLOC_CTX *query, DALLOC_CTX *reply)
1068 uint64_t sl_result;
1069 sl_array_t *array;
1070 int result;
1072 array = dalloc_zero(reply, sl_array_t);
1073 if (array == NULL) {
1074 return false;
1078 * FIXME: not implemented. Used by the client for eg setting
1079 * the modification date of the shared directory which clients
1080 * poll indicating changes on the share and cause the client
1081 * to refresh view.
1084 sl_result = 0;
1085 result = dalloc_add_copy(array, &sl_result, uint64_t);
1086 if (result != 0) {
1087 return false;
1089 result = dalloc_add(reply, array, sl_array_t);
1090 if (result != 0) {
1091 return false;
1094 return true;
1098 * Fetch supported metadata attributes for a CNID
1100 static bool slrpc_fetch_attributenames(struct mds_ctx *mds_ctx,
1101 const DALLOC_CTX *query,
1102 DALLOC_CTX *reply)
1104 uint64_t id;
1105 sl_cnids_t *cnids;
1106 sl_array_t *array;
1107 uint64_t sl_result;
1108 sl_cnids_t *replycnids;
1109 sl_array_t *mdattrs;
1110 sl_filemeta_t *fmeta;
1111 int result;
1112 void *p;
1114 cnids = dalloc_get(query, "DALLOC_CTX", 0, "sl_cnids_t", 1);
1115 if (cnids == NULL) {
1116 return false;
1119 p = dalloc_get_object(cnids->ca_cnids, 0);
1120 if (p == NULL) {
1121 return NULL;
1123 memcpy(&id, p, sizeof(uint64_t));
1125 /* Result array */
1126 array = dalloc_zero(reply, sl_array_t);
1127 if (array == NULL) {
1128 return false;
1131 result = dalloc_add(reply, array, sl_array_t);
1132 if (result != 0) {
1133 return false;
1136 /* Return result value 0 */
1137 sl_result = 0;
1138 result = dalloc_add_copy(array, &sl_result, uint64_t);
1139 if (result != 0) {
1140 return false;
1143 /* Return CNID array */
1144 replycnids = talloc_zero(reply, sl_cnids_t);
1145 if (replycnids == NULL) {
1146 return false;
1149 replycnids->ca_cnids = dalloc_new(cnids);
1150 if (replycnids->ca_cnids == NULL) {
1151 return false;
1154 replycnids->ca_unkn1 = 0xfec;
1155 replycnids->ca_context = cnids->ca_context;
1156 result = dalloc_add_copy(replycnids->ca_cnids, &id, uint64_t);
1157 if (result != 0) {
1158 return false;
1160 result = dalloc_add(array, replycnids, sl_cnids_t);
1161 if (result != 0) {
1162 return false;
1166 * FIXME: this should return the real attributes from all
1167 * known metadata sources (Tracker and filesystem)
1169 mdattrs = dalloc_zero(reply, sl_array_t);
1170 if (mdattrs == NULL) {
1171 return false;
1174 result = dalloc_stradd(mdattrs, "kMDItemFSName");
1175 if (result != 0) {
1176 return false;
1178 result = dalloc_stradd(mdattrs, "kMDItemDisplayName");
1179 if (result != 0) {
1180 return false;
1182 result = dalloc_stradd(mdattrs, "kMDItemFSSize");
1183 if (result != 0) {
1184 return false;
1186 result = dalloc_stradd(mdattrs, "kMDItemFSOwnerUserID");
1187 if (result != 0) {
1188 return false;
1190 result = dalloc_stradd(mdattrs, "kMDItemFSOwnerGroupID");
1191 if (result != 0) {
1192 return false;
1194 result = dalloc_stradd(mdattrs, "kMDItemFSContentChangeDate");
1195 if (result != 0) {
1196 return false;
1199 fmeta = dalloc_zero(reply, sl_filemeta_t);
1200 if (fmeta == NULL) {
1201 return false;
1203 result = dalloc_add(fmeta, mdattrs, sl_array_t);
1204 if (result != 0) {
1205 return false;
1207 result = dalloc_add(array, fmeta, sl_filemeta_t);
1208 if (result != 0) {
1209 return false;
1212 return true;
1216 * Fetch metadata attribute values for a CNID
1218 static bool slrpc_fetch_attributes(struct mds_ctx *mds_ctx,
1219 const DALLOC_CTX *query, DALLOC_CTX *reply)
1221 int result;
1222 bool ok;
1223 sl_array_t *array;
1224 sl_cnids_t *cnids;
1225 sl_cnids_t *replycnids;
1226 sl_array_t *reqinfo;
1227 uint64_t ino;
1228 uint64_t sl_result;
1229 sl_filemeta_t *fm;
1230 sl_array_t *fm_array;
1231 sl_nil_t nil;
1232 char *path = NULL;
1233 struct stat_ex sb;
1234 struct sl_inode_path_map *elem = NULL;
1235 void *p;
1236 TDB_DATA val = tdb_null;
1237 NTSTATUS status;
1239 array = dalloc_zero(reply, sl_array_t);
1240 if (array == NULL) {
1241 return false;
1243 replycnids = talloc_zero(reply, sl_cnids_t);
1244 if (replycnids == NULL) {
1245 goto error;
1247 replycnids->ca_cnids = dalloc_new(replycnids);
1248 if (replycnids->ca_cnids == NULL) {
1249 goto error;
1251 fm = dalloc_zero(array, sl_filemeta_t);
1252 if (fm == NULL) {
1253 goto error;
1255 fm_array = dalloc_zero(fm, sl_array_t);
1256 if (fm_array == NULL) {
1257 goto error;
1259 /* For some reason the list of results always starts with a nil entry */
1260 result = dalloc_add_copy(fm_array, &nil, sl_nil_t);
1261 if (result == -1) {
1262 goto error;
1265 reqinfo = dalloc_get(query, "DALLOC_CTX", 0, "sl_array_t", 1);
1266 if (reqinfo == NULL) {
1267 goto error;
1270 cnids = dalloc_get(query, "DALLOC_CTX", 0, "sl_cnids_t", 2);
1271 if (cnids == NULL) {
1272 goto error;
1274 p = dalloc_get_object(cnids->ca_cnids, 0);
1275 if (p == NULL) {
1276 goto error;
1278 memcpy(&ino, p, sizeof(uint64_t));
1280 replycnids->ca_unkn1 = 0xfec;
1281 replycnids->ca_context = cnids->ca_context;
1282 result = dalloc_add_copy(replycnids->ca_cnids, &ino, uint64_t);
1283 if (result != 0) {
1284 goto error;
1287 status = dbwrap_fetch(mds_ctx->ino_path_map, reply,
1288 make_tdb_data((void*)&ino, sizeof(uint64_t)),
1289 &val);
1290 if (NT_STATUS_IS_OK(status)) {
1291 if (val.dsize != sizeof(p)) {
1292 DBG_ERR("invalid record pointer size: %zd\n", val.dsize);
1293 TALLOC_FREE(val.dptr);
1294 goto error;
1297 memcpy(&p, val.dptr, sizeof(p));
1298 elem = talloc_get_type_abort(p, struct sl_inode_path_map);
1299 path = elem->path;
1301 result = sys_stat(path, &sb, false);
1302 if (result != 0) {
1303 goto error;
1307 ok = add_filemeta(mds_ctx, reqinfo, fm_array, path, &sb);
1308 if (!ok) {
1309 goto error;
1312 sl_result = 0;
1313 result = dalloc_add_copy(array, &sl_result, uint64_t);
1314 if (result != 0) {
1315 goto error;
1317 result = dalloc_add(array, replycnids, sl_cnids_t);
1318 if (result != 0) {
1319 goto error;
1321 result = dalloc_add(fm, fm_array, sl_array_t);
1322 if (result != 0) {
1323 goto error;
1325 result = dalloc_add(array, fm, sl_filemeta_t);
1326 if (result != 0) {
1327 goto error;
1329 result = dalloc_add(reply, array, sl_array_t);
1330 if (result != 0) {
1331 goto error;
1334 return true;
1336 error:
1337 sl_result = UINT64_MAX;
1338 result = dalloc_add_copy(array, &sl_result, uint64_t);
1339 if (result != 0) {
1340 return false;
1342 result = dalloc_add(reply, array, sl_array_t);
1343 if (result != 0) {
1344 return false;
1347 return true;
1351 * Close a query
1353 static bool slrpc_close_query(struct mds_ctx *mds_ctx,
1354 const DALLOC_CTX *query, DALLOC_CTX *reply)
1356 struct sl_query *slq = NULL;
1357 uint64_t *uint64p, ctx1, ctx2;
1358 sl_array_t *array;
1359 uint64_t sl_res;
1360 int result;
1362 array = dalloc_zero(reply, sl_array_t);
1363 if (array == NULL) {
1364 return false;
1367 /* Context */
1368 uint64p = dalloc_get(query, "DALLOC_CTX", 0, "DALLOC_CTX", 0,
1369 "uint64_t", 1);
1370 if (uint64p == NULL) {
1371 goto done;
1373 ctx1 = *uint64p;
1375 uint64p = dalloc_get(query, "DALLOC_CTX", 0, "DALLOC_CTX", 0,
1376 "uint64_t", 2);
1377 if (uint64p == NULL) {
1378 goto done;
1380 ctx2 = *uint64p;
1382 /* Get query for context and free it */
1383 slq = slq_for_ctx(mds_ctx, ctx1, ctx2);
1384 if (slq == NULL) {
1385 DEBUG(1, ("bad context: [0x%jx,0x%jx]\n",
1386 (uintmax_t)ctx1, (uintmax_t)ctx2));
1387 goto done;
1390 SLQ_DEBUG(10, slq, "close");
1391 TALLOC_FREE(slq);
1393 done:
1394 sl_res = UINT64_MAX;
1395 result = dalloc_add_copy(array, &sl_res, uint64_t);
1396 if (result != 0) {
1397 return false;
1399 result = dalloc_add(reply, array, sl_array_t);
1400 if (result != 0) {
1401 return false;
1403 return true;
1406 static struct mdssvc_ctx *mdssvc_init(struct tevent_context *ev)
1408 bool ok;
1410 if (mdssvc_ctx != NULL) {
1411 return mdssvc_ctx;
1414 mdssvc_ctx = talloc_zero(ev, struct mdssvc_ctx);
1415 if (mdssvc_ctx == NULL) {
1416 return NULL;
1419 mdssvc_ctx->ev_ctx = ev;
1421 ok = mdsscv_backend_noindex.init(mdssvc_ctx);
1422 if (!ok) {
1423 DBG_ERR("backend init failed\n");
1424 TALLOC_FREE(mdssvc_ctx);
1425 return NULL;
1428 #ifdef HAVE_SPOTLIGHT_BACKEND_ES
1429 ok = mdsscv_backend_es.init(mdssvc_ctx);
1430 if (!ok) {
1431 DBG_ERR("backend init failed\n");
1432 TALLOC_FREE(mdssvc_ctx);
1433 return NULL;
1435 #endif
1437 #ifdef HAVE_SPOTLIGHT_BACKEND_TRACKER
1438 ok = mdsscv_backend_tracker.init(mdssvc_ctx);
1439 if (!ok) {
1440 DBG_ERR("backend init failed\n");
1441 TALLOC_FREE(mdssvc_ctx);
1442 return NULL;
1444 #endif
1446 return mdssvc_ctx;
1450 * Init callbacks at startup
1452 * This gets typically called in the main parent smbd which means we can't
1453 * initialize our global state here.
1455 bool mds_init(struct messaging_context *msg_ctx)
1457 return true;
1460 bool mds_shutdown(void)
1462 bool ok;
1464 if (mdssvc_ctx == NULL) {
1465 return false;
1468 ok = mdsscv_backend_noindex.shutdown(mdssvc_ctx);
1469 if (!ok) {
1470 goto fail;
1473 #ifdef HAVE_SPOTLIGHT_BACKEND_ES
1474 ok = mdsscv_backend_es.shutdown(mdssvc_ctx);
1475 if (!ok) {
1476 goto fail;
1478 #endif
1480 #ifdef HAVE_SPOTLIGHT_BACKEND_TRACKER
1481 ok = mdsscv_backend_tracker.shutdown(mdssvc_ctx);
1482 if (!ok) {
1483 goto fail;
1485 #endif
1487 ok = true;
1488 fail:
1489 TALLOC_FREE(mdssvc_ctx);
1490 return ok;
1494 * Tear down connections and free all resources
1496 static int mds_ctx_destructor_cb(struct mds_ctx *mds_ctx)
1499 * We need to free query_list before ino_path_map
1501 while (mds_ctx->query_list != NULL) {
1503 * slq destructor removes element from list.
1504 * Don't use TALLOC_FREE()!
1506 talloc_free(mds_ctx->query_list);
1508 TALLOC_FREE(mds_ctx->ino_path_map);
1510 ZERO_STRUCTP(mds_ctx);
1512 return 0;
1516 * Initialise a context per RPC bind
1518 * This ends up being called for every tcon, because the client does a
1519 * RPC bind for every tcon, so this is acually a per tcon context.
1521 struct mds_ctx *mds_init_ctx(TALLOC_CTX *mem_ctx,
1522 struct tevent_context *ev,
1523 struct auth_session_info *session_info,
1524 int snum,
1525 const char *sharename,
1526 const char *path)
1528 struct mds_ctx *mds_ctx;
1529 int backend;
1530 bool ok;
1531 smb_iconv_t iconv_hnd = (smb_iconv_t)-1;
1533 mds_ctx = talloc_zero(mem_ctx, struct mds_ctx);
1534 if (mds_ctx == NULL) {
1535 return NULL;
1537 talloc_set_destructor(mds_ctx, mds_ctx_destructor_cb);
1539 mds_ctx->mdssvc_ctx = mdssvc_init(ev);
1540 if (mds_ctx->mdssvc_ctx == NULL) {
1541 goto error;
1544 backend = lp_spotlight_backend(snum);
1545 if (!lp_spotlight(snum)) {
1546 backend = SPOTLIGHT_BACKEND_NOINDEX;
1548 switch (backend) {
1549 case SPOTLIGHT_BACKEND_NOINDEX:
1550 mds_ctx->backend = &mdsscv_backend_noindex;
1551 break;
1553 #ifdef HAVE_SPOTLIGHT_BACKEND_ES
1554 case SPOTLIGHT_BACKEND_ES:
1555 mds_ctx->backend = &mdsscv_backend_es;
1556 break;
1557 #endif
1559 #ifdef HAVE_SPOTLIGHT_BACKEND_TRACKER
1560 case SPOTLIGHT_BACKEND_TRACKER:
1561 mds_ctx->backend = &mdsscv_backend_tracker;
1562 break;
1563 #endif
1564 default:
1565 DBG_ERR("Unknown backend %d\n", backend);
1566 TALLOC_FREE(mdssvc_ctx);
1567 goto error;
1570 iconv_hnd = smb_iconv_open_ex(mds_ctx,
1571 "UTF8-NFD",
1572 "UTF8-NFC",
1573 false);
1574 if (iconv_hnd == (smb_iconv_t)-1) {
1575 goto error;
1577 mds_ctx->ic_nfc_to_nfd = iconv_hnd;
1579 iconv_hnd = smb_iconv_open_ex(mds_ctx,
1580 "UTF8-NFC",
1581 "UTF8-NFD",
1582 false);
1583 if (iconv_hnd == (smb_iconv_t)-1) {
1584 goto error;
1586 mds_ctx->ic_nfd_to_nfc = iconv_hnd;
1588 mds_ctx->sharename = talloc_strdup(mds_ctx, sharename);
1589 if (mds_ctx->sharename == NULL) {
1590 goto error;
1593 mds_ctx->spath = talloc_strdup(mds_ctx, path);
1594 if (mds_ctx->spath == NULL) {
1595 goto error;
1598 mds_ctx->snum = snum;
1599 mds_ctx->pipe_session_info = session_info;
1601 if (session_info->security_token->num_sids < 1) {
1602 goto error;
1604 sid_copy(&mds_ctx->sid, &session_info->security_token->sids[0]);
1605 mds_ctx->uid = session_info->unix_token->uid;
1607 mds_ctx->ino_path_map = db_open_rbt(mds_ctx);
1608 if (mds_ctx->ino_path_map == NULL) {
1609 DEBUG(1,("open inode map db failed\n"));
1610 goto error;
1613 ok = mds_ctx->backend->connect(mds_ctx);
1614 if (!ok) {
1615 DBG_ERR("backend connect failed\n");
1616 goto error;
1619 return mds_ctx;
1621 error:
1622 if (mds_ctx->ic_nfc_to_nfd != NULL) {
1623 smb_iconv_close(mds_ctx->ic_nfc_to_nfd);
1625 if (mds_ctx->ic_nfd_to_nfc != NULL) {
1626 smb_iconv_close(mds_ctx->ic_nfd_to_nfc);
1629 TALLOC_FREE(mds_ctx);
1630 return NULL;
1634 * Dispatch a Spotlight RPC command
1636 bool mds_dispatch(struct mds_ctx *mds_ctx,
1637 struct mdssvc_blob *request_blob,
1638 struct mdssvc_blob *response_blob)
1640 bool ok;
1641 ssize_t len;
1642 DALLOC_CTX *query = NULL;
1643 DALLOC_CTX *reply = NULL;
1644 char *rpccmd;
1645 const struct slrpc_cmd *slcmd;
1647 if (CHECK_DEBUGLVL(10)) {
1648 const struct sl_query *slq;
1650 for (slq = mds_ctx->query_list; slq != NULL; slq = slq->next) {
1651 SLQ_DEBUG(10, slq, "pending");
1655 response_blob->length = 0;
1657 DEBUG(10, ("share path: %s\n", mds_ctx->spath));
1659 query = dalloc_new(mds_ctx);
1660 if (query == NULL) {
1661 ok = false;
1662 goto cleanup;
1664 reply = dalloc_new(mds_ctx);
1665 if (reply == NULL) {
1666 ok = false;
1667 goto cleanup;
1670 ok = sl_unpack(query, (char *)request_blob->spotlight_blob,
1671 request_blob->length);
1672 if (!ok) {
1673 DEBUG(1, ("error unpacking Spotlight RPC blob\n"));
1674 goto cleanup;
1677 DEBUG(5, ("%s", dalloc_dump(query, 0)));
1679 rpccmd = dalloc_get(query, "DALLOC_CTX", 0, "DALLOC_CTX", 0,
1680 "char *", 0);
1681 if (rpccmd == NULL) {
1682 DEBUG(1, ("missing primary Spotlight RPC command\n"));
1683 ok = false;
1684 goto cleanup;
1687 DEBUG(10, ("Spotlight RPC cmd: %s\n", rpccmd));
1689 slcmd = slrpc_cmd_by_name(rpccmd);
1690 if (slcmd == NULL) {
1691 DEBUG(1, ("unsupported primary Spotlight RPC command %s\n",
1692 rpccmd));
1693 ok = false;
1694 goto cleanup;
1697 ok = slcmd->function(mds_ctx, query, reply);
1698 if (ok) {
1699 DBG_DEBUG("%s", dalloc_dump(reply, 0));
1701 len = sl_pack(reply,
1702 (char *)response_blob->spotlight_blob,
1703 response_blob->size);
1704 if (len == -1) {
1705 DBG_ERR("error packing Spotlight RPC reply\n");
1706 ok = false;
1707 goto cleanup;
1709 response_blob->length = len;
1712 cleanup:
1713 talloc_free(query);
1714 talloc_free(reply);
1715 return ok;