LCOV - code coverage report
Current view: top level - source3/rpc_server/mdssvc - mdssvc.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 503 908 55.4 %
Date: 2024-02-28 12:06:22 Functions: 21 26 80.8 %

          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 "smbd/proto.h"
      23             : #include "librpc/gen_ndr/auth.h"
      24             : #include "dbwrap/dbwrap.h"
      25             : #include "lib/util/dlinklist.h"
      26             : #include "lib/util/util_tdb.h"
      27             : #include "lib/util/time_basic.h"
      28             : #include "lib/dbwrap/dbwrap_rbt.h"
      29             : #include "libcli/security/dom_sid.h"
      30             : #include "libcli/security/security.h"
      31             : #include "mdssvc.h"
      32             : #include "mdssvc_noindex.h"
      33             : #ifdef HAVE_SPOTLIGHT_BACKEND_TRACKER
      34             : #include "mdssvc_tracker.h"
      35             : #endif
      36             : #ifdef HAVE_SPOTLIGHT_BACKEND_ES
      37             : #include "mdssvc_es.h"
      38             : #endif
      39             : #include "lib/global_contexts.h"
      40             : 
      41             : #undef DBGC_CLASS
      42             : #define DBGC_CLASS DBGC_RPC_SRV
      43             : 
      44             : struct slrpc_cmd {
      45             :         const char *name;
      46             :         bool (*function)(struct mds_ctx *mds_ctx,
      47             :                          const DALLOC_CTX *query,
      48             :                          DALLOC_CTX *reply);
      49             : };
      50             : 
      51             : struct slq_destroy_state {
      52             :         struct tevent_context *ev;
      53             :         struct sl_query *slq;
      54             : };
      55             : 
      56             : /*
      57             :  * This is a static global because we may be called multiple times and
      58             :  * we only want one mdssvc_ctx per connection to Tracker.
      59             :  *
      60             :  * The client will bind multiple times to the mdssvc RPC service, once
      61             :  * for every tree connect.
      62             :  */
      63             : static struct mdssvc_ctx *mdssvc_ctx = NULL;
      64             : 
      65             : /*
      66             :  * If these functions return an error, they hit something like a non
      67             :  * recoverable talloc error. Most errors are dealt with by returning
      68             :  * an error code in the Spotlight RPC reply.
      69             :  */
      70             : static bool slrpc_fetch_properties(struct mds_ctx *mds_ctx,
      71             :                                    const DALLOC_CTX *query, DALLOC_CTX *reply);
      72             : static bool slrpc_open_query(struct mds_ctx *mds_ctx,
      73             :                              const DALLOC_CTX *query, DALLOC_CTX *reply);
      74             : static bool slrpc_fetch_query_results(struct mds_ctx *mds_ctx,
      75             :                                       const DALLOC_CTX *query, DALLOC_CTX *reply);
      76             : static bool slrpc_store_attributes(struct mds_ctx *mds_ctx,
      77             :                                    const DALLOC_CTX *query, DALLOC_CTX *reply);
      78             : static bool slrpc_fetch_attributenames(struct mds_ctx *mds_ctx,
      79             :                                        const DALLOC_CTX *query, DALLOC_CTX *reply);
      80             : static bool slrpc_fetch_attributes(struct mds_ctx *mds_ctx,
      81             :                                    const DALLOC_CTX *query, DALLOC_CTX *reply);
      82             : static bool slrpc_close_query(struct mds_ctx *mds_ctx,
      83             :                               const DALLOC_CTX *query, DALLOC_CTX *reply);
      84             : 
      85             : /************************************************
      86             :  * Misc utility functions
      87             :  ************************************************/
      88             : 
      89             : /**
      90             :  * Add requested metadata for a query result element
      91             :  *
      92             :  * This could be rewritten to something more sophisticated like
      93             :  * querying metadata from Tracker.
      94             :  *
      95             :  * If path or sp is NULL, simply add nil values for all attributes.
      96             :  **/
      97          37 : static bool add_filemeta(struct mds_ctx *mds_ctx,
      98             :                          sl_array_t *reqinfo,
      99             :                          sl_array_t *fm_array,
     100             :                          const char *path,
     101             :                          const struct stat_ex *sp)
     102             : {
     103             :         sl_array_t *meta;
     104             :         sl_nil_t nil;
     105             :         int i, metacount, result;
     106             :         uint64_t uint64var;
     107             :         sl_time_t sl_time;
     108             :         char *p;
     109             :         const char *attribute;
     110             :         size_t nfc_len;
     111          37 :         const char *nfc_path = path;
     112             :         size_t nfd_buf_size;
     113          37 :         char *nfd_path = NULL;
     114          37 :         char *dest = NULL;
     115             :         size_t dest_remaining;
     116             :         size_t nconv;
     117             : 
     118          37 :         metacount = dalloc_size(reqinfo);
     119          37 :         if (metacount == 0 || path == NULL || sp == NULL) {
     120           3 :                 result = dalloc_add_copy(fm_array, &nil, sl_nil_t);
     121           3 :                 if (result != 0) {
     122           0 :                         return false;
     123             :                 }
     124           3 :                 return true;
     125             :         }
     126             : 
     127          34 :         meta = dalloc_zero(fm_array, sl_array_t);
     128          34 :         if (meta == NULL) {
     129           0 :                 return false;
     130             :         }
     131             : 
     132          34 :         nfc_len = strlen(nfc_path);
     133             :         /*
     134             :          * Simple heuristic, strlen by two should give enough room for NFC to
     135             :          * NFD conversion.
     136             :          */
     137          34 :         nfd_buf_size = nfc_len * 2;
     138          34 :         nfd_path = talloc_array(meta, char, nfd_buf_size);
     139          34 :         if (nfd_path == NULL) {
     140           0 :                 return false;
     141             :         }
     142          34 :         dest = nfd_path;
     143          34 :         dest_remaining = talloc_array_length(dest);
     144             : 
     145          34 :         nconv = smb_iconv(mds_ctx->ic_nfc_to_nfd,
     146             :                           &nfc_path,
     147             :                           &nfc_len,
     148             :                           &dest,
     149             :                           &dest_remaining);
     150          34 :         if (nconv == (size_t)-1) {
     151           0 :                 return false;
     152             :         }
     153             : 
     154          68 :         for (i = 0; i < metacount; i++) {
     155          34 :                 attribute = dalloc_get_object(reqinfo, i);
     156          34 :                 if (attribute == NULL) {
     157           0 :                         return false;
     158             :                 }
     159          34 :                 if (strcmp(attribute, "kMDItemDisplayName") == 0
     160          34 :                     || strcmp(attribute, "kMDItemFSName") == 0) {
     161          17 :                         p = strrchr(nfd_path, '/');
     162          17 :                         if (p) {
     163          17 :                                 result = dalloc_stradd(meta, p + 1);
     164          17 :                                 if (result != 0) {
     165           0 :                                         return false;
     166             :                                 }
     167             :                         }
     168          17 :                 } else if (strcmp(attribute, "kMDItemPath") == 0) {
     169          17 :                         result = dalloc_stradd(meta, nfd_path);
     170          17 :                         if (result != 0) {
     171           0 :                                 return false;
     172             :                         }
     173           0 :                 } else if (strcmp(attribute, "kMDItemFSSize") == 0) {
     174           0 :                         uint64var = sp->st_ex_size;
     175           0 :                         result = dalloc_add_copy(meta, &uint64var, uint64_t);
     176           0 :                         if (result != 0) {
     177           0 :                                 return false;
     178             :                         }
     179           0 :                 } else if (strcmp(attribute, "kMDItemFSOwnerUserID") == 0) {
     180           0 :                         uint64var = sp->st_ex_uid;
     181           0 :                         result = dalloc_add_copy(meta, &uint64var, uint64_t);
     182           0 :                         if (result != 0) {
     183           0 :                                 return false;
     184             :                         }
     185           0 :                 } else if (strcmp(attribute, "kMDItemFSOwnerGroupID") == 0) {
     186           0 :                         uint64var = sp->st_ex_gid;
     187           0 :                         result = dalloc_add_copy(meta, &uint64var, uint64_t);
     188           0 :                         if (result != 0) {
     189           0 :                                 return false;
     190             :                         }
     191           0 :                 } else if (strcmp(attribute, "kMDItemFSContentChangeDate") == 0 ||
     192           0 :                         strcmp(attribute, "kMDItemContentModificationDate") == 0)
     193             :                 {
     194           0 :                         sl_time = convert_timespec_to_timeval(sp->st_ex_mtime);
     195           0 :                         result = dalloc_add_copy(meta, &sl_time, sl_time_t);
     196           0 :                         if (result != 0) {
     197           0 :                                 return false;
     198             :                         }
     199             :                 } else {
     200           0 :                         result = dalloc_add_copy(meta, &nil, sl_nil_t);
     201           0 :                         if (result != 0) {
     202           0 :                                 return false;
     203             :                         }
     204             :                 }
     205             :         }
     206             : 
     207          34 :         result = dalloc_add(fm_array, meta, sl_array_t);
     208          34 :         if (result != 0) {
     209           0 :                 return false;
     210             :         }
     211          34 :         return true;
     212             : }
     213             : 
     214           0 : static int cnid_comp_fn(const void *p1, const void *p2)
     215             : {
     216           0 :         const uint64_t *cnid1 = p1, *cnid2 = p2;
     217           0 :         if (*cnid1 == *cnid2) {
     218           0 :                 return 0;
     219             :         }
     220           0 :         if (*cnid1 < *cnid2) {
     221           0 :                 return -1;
     222             :         }
     223           0 :         return 1;
     224             : }
     225             : 
     226             : /**
     227             :  * Create a sorted copy of a CNID array
     228             :  **/
     229           0 : static bool sort_cnids(struct sl_query *slq, const DALLOC_CTX *d)
     230             : {
     231           0 :         uint64_t *cnids = NULL;
     232             :         int i;
     233             :         const void *p;
     234             : 
     235           0 :         cnids = talloc_array(slq, uint64_t, dalloc_size(d));
     236           0 :         if (cnids == NULL) {
     237           0 :                 return false;
     238             :         }
     239             : 
     240           0 :         for (i = 0; i < dalloc_size(d); i++) {
     241           0 :                 p = dalloc_get_object(d, i);
     242           0 :                 if (p == NULL) {
     243           0 :                         return NULL;
     244             :                 }
     245           0 :                 memcpy(&cnids[i], p, sizeof(uint64_t));
     246             :         }
     247           0 :         qsort(cnids, dalloc_size(d), sizeof(uint64_t), cnid_comp_fn);
     248             : 
     249           0 :         slq->cnids = cnids;
     250           0 :         slq->cnids_num = dalloc_size(d);
     251             : 
     252           0 :         return true;
     253             : }
     254             : 
     255             : /**
     256             :  * Allocate result handle used in the async Tracker cursor result
     257             :  * handler for storing results
     258             :  **/
     259          13 : static bool create_result_handle(struct sl_query *slq)
     260             : {
     261          13 :         sl_nil_t nil = 0;
     262             :         struct sl_rslts *query_results;
     263             :         int result;
     264             : 
     265          13 :         if (slq->query_results) {
     266           0 :                 DEBUG(1, ("unexpected existing result handle\n"));
     267           0 :                 return false;
     268             :         }
     269             : 
     270          13 :         query_results = talloc_zero(slq, struct sl_rslts);
     271          13 :         if (query_results == NULL) {
     272           0 :                 return false;
     273             :         }
     274             : 
     275             :         /* CNIDs */
     276          13 :         query_results->cnids = talloc_zero(query_results, sl_cnids_t);
     277          13 :         if (query_results->cnids == NULL) {
     278           0 :                 return false;
     279             :         }
     280          13 :         query_results->cnids->ca_cnids = dalloc_new(query_results->cnids);
     281          13 :         if (query_results->cnids->ca_cnids == NULL) {
     282           0 :                 return false;
     283             :         }
     284             : 
     285          13 :         query_results->cnids->ca_unkn1 = 0xadd;
     286          13 :         if (slq->ctx2 > UINT32_MAX) {
     287           0 :                 DEBUG(1,("64bit ctx2 id too large: 0x%jx\n", (uintmax_t)slq->ctx2));
     288           0 :                 return false;
     289             :         }
     290          13 :         query_results->cnids->ca_context = (uint32_t)slq->ctx2;
     291             : 
     292             :         /* FileMeta */
     293          13 :         query_results->fm_array = dalloc_zero(query_results, sl_array_t);
     294          13 :         if (query_results->fm_array == NULL) {
     295           0 :                 return false;
     296             :         }
     297             : 
     298             :         /* For some reason the list of results always starts with a nil entry */
     299          13 :         result = dalloc_add_copy(query_results->fm_array, &nil, sl_nil_t);
     300          13 :         if (result != 0) {
     301           0 :                 return false;
     302             :         }
     303             : 
     304          13 :         slq->query_results = query_results;
     305          13 :         return true;
     306             : }
     307             : 
     308           8 : static bool add_results(sl_array_t *array, struct sl_query *slq)
     309             : {
     310             :         sl_filemeta_t *fm;
     311             :         uint64_t status;
     312             :         int result;
     313             :         bool ok;
     314             : 
     315             :         /*
     316             :          * Taken from network traces against a macOS SMB Spotlight server: if
     317             :          * the search is not finished yet in the backend macOS returns 0x23,
     318             :          * otherwise 0x0.
     319             :          */
     320           8 :         if (slq->state >= SLQ_STATE_DONE) {
     321           8 :                 status = 0;
     322             :         } else {
     323           0 :                 status = 0x23;
     324             :         }
     325             : 
     326             :         /* FileMeta */
     327           8 :         fm = dalloc_zero(array, sl_filemeta_t);
     328           8 :         if (fm == NULL) {
     329           0 :                 return false;
     330             :         }
     331             : 
     332           8 :         result = dalloc_add_copy(array, &status, uint64_t);
     333           8 :         if (result != 0) {
     334           0 :                 return false;
     335             :         }
     336           8 :         result = dalloc_add(array, slq->query_results->cnids, sl_cnids_t);
     337           8 :         if (result != 0) {
     338           0 :                 return false;
     339             :         }
     340           8 :         if (slq->query_results->num_results > 0) {
     341           5 :                 result = dalloc_add(fm, slq->query_results->fm_array, sl_array_t);
     342           5 :                 if (result != 0) {
     343           0 :                         return false;
     344             :                 }
     345             :         }
     346           8 :         result = dalloc_add(array, fm, sl_filemeta_t);
     347           8 :         if (result != 0) {
     348           0 :                 return false;
     349             :         }
     350             : 
     351             :         /* This ensure the results get clean up after been sent to the client */
     352           8 :         talloc_move(array, &slq->query_results);
     353             : 
     354           8 :         ok = create_result_handle(slq);
     355           8 :         if (!ok) {
     356           0 :                 DEBUG(1, ("couldn't add result handle\n"));
     357           0 :                 slq->state = SLQ_STATE_ERROR;
     358           0 :                 return false;
     359             :         }
     360             : 
     361           8 :         return true;
     362             : }
     363             : 
     364          48 : static const struct slrpc_cmd *slrpc_cmd_by_name(const char *rpccmd)
     365             : {
     366             :         size_t i;
     367             :         static const struct slrpc_cmd cmds[] = {
     368             :                 { "fetchPropertiesForContext:", slrpc_fetch_properties},
     369             :                 { "openQueryWithParams:forContext:", slrpc_open_query},
     370             :                 { "fetchQueryResultsForContext:", slrpc_fetch_query_results},
     371             :                 { "storeAttributes:forOIDArray:context:", slrpc_store_attributes},
     372             :                 { "fetchAttributeNamesForOIDArray:context:", slrpc_fetch_attributenames},
     373             :                 { "fetchAttributes:forOIDArray:context:", slrpc_fetch_attributes},
     374             :                 { "fetchAllAttributes:forOIDArray:context:", slrpc_fetch_attributes},
     375             :                 { "closeQueryForContext:", slrpc_close_query},
     376             :         };
     377             : 
     378         207 :         for (i = 0; i < ARRAY_SIZE(cmds); i++) {
     379             :                 int cmp;
     380             : 
     381         207 :                 cmp = strcmp(cmds[i].name, rpccmd);
     382         207 :                 if (cmp == 0) {
     383          48 :                         return &cmds[i];
     384             :                 }
     385             :         }
     386             : 
     387           0 :         return NULL;
     388             : }
     389             : 
     390             : /**
     391             :  * Search the list of active queries given their context ids
     392             :  **/
     393          13 : static struct sl_query *slq_for_ctx(struct mds_ctx *mds_ctx,
     394             :                                     uint64_t ctx1, uint64_t ctx2)
     395             : {
     396             :         struct sl_query *q;
     397             : 
     398          13 :         for (q = mds_ctx->query_list; q; q = q->next) {
     399          13 :                 if ((q->ctx1 == ctx1) && (q->ctx2 == ctx2)) {
     400          13 :                         return q;
     401             :                 }
     402             :         }
     403             : 
     404           0 :         return NULL;
     405             : }
     406             : 
     407           8 : static int slq_destructor_cb(struct sl_query *slq)
     408             : {
     409           8 :         SLQ_DEBUG(10, slq, "destroying");
     410             : 
     411             :         /* Free all entries before freeing the slq handle! */
     412           8 :         TALLOC_FREE(slq->entries_ctx);
     413           8 :         TALLOC_FREE(slq->te);
     414             : 
     415           8 :         if (slq->mds_ctx != NULL) {
     416           8 :                 DLIST_REMOVE(slq->mds_ctx->query_list, slq);
     417           8 :                 slq->mds_ctx = NULL;
     418             :         }
     419             : 
     420           8 :         TALLOC_FREE(slq->backend_private);
     421             : 
     422           8 :         return 0;
     423             : }
     424             : 
     425             : /**
     426             :  * Remove talloc_refcounted entry from mapping db
     427             :  *
     428             :  * Multiple queries (via the slq handle) may reference a
     429             :  * sl_inode_path_map entry, when the last reference goes away as the
     430             :  * queries are closed and this gets called to remove the entry from
     431             :  * the db.
     432             :  **/
     433          17 : static int ino_path_map_destr_cb(struct sl_inode_path_map *entry)
     434             : {
     435             :         NTSTATUS status;
     436             :         TDB_DATA key;
     437             : 
     438          17 :         key = make_tdb_data((uint8_t *)&entry->ino, sizeof(entry->ino));
     439             : 
     440          17 :         status = dbwrap_delete(entry->mds_ctx->ino_path_map, key);
     441          17 :         if (!NT_STATUS_IS_OK(status)) {
     442           0 :                 DEBUG(1, ("Failed to delete record: %s\n", nt_errstr(status)));
     443           0 :                 return -1;
     444             :         }
     445             : 
     446          17 :         DBG_DEBUG("deleted [0x%"PRIx64"] [%s]\n", entry->ino, entry->path);
     447          17 :         return 0;
     448             : }
     449             : 
     450             : /**
     451             :  * Add result to inode->path mapping dbwrap rbt db
     452             :  *
     453             :  * This is necessary as a CNID db substitute, ie we need a way to
     454             :  * simulate unique, constant numerical identifiers for paths with an
     455             :  * API that supports mapping from id to path.
     456             :  *
     457             :  * Entries are talloc'ed of the query, using talloc_reference() if
     458             :  * multiple queries returned the same result. That way we can cleanup
     459             :  * entries by calling talloc_free() on the query slq handles.
     460             :  **/
     461             : 
     462          17 : static bool inode_map_add(struct sl_query *slq,
     463             :                           uint64_t ino,
     464             :                           const char *path,
     465             :                           struct stat_ex *st)
     466             : {
     467             :         NTSTATUS status;
     468             :         struct sl_inode_path_map *entry;
     469             :         TDB_DATA key, value;
     470             :         void *p;
     471             : 
     472          17 :         key = make_tdb_data((uint8_t *)&ino, sizeof(ino));
     473          17 :         status = dbwrap_fetch(slq->mds_ctx->ino_path_map, slq, key, &value);
     474             : 
     475          17 :         if (NT_STATUS_IS_OK(status)) {
     476             :                 /*
     477             :                  * We have one db, so when different parallel queries
     478             :                  * return the same file, we have to refcount entries
     479             :                  * in the db.
     480             :                  */
     481             : 
     482           0 :                 if (value.dsize != sizeof(void *)) {
     483           0 :                         DEBUG(1, ("invalid dsize\n"));
     484           0 :                         return false;
     485             :                 }
     486           0 :                 memcpy(&p, value.dptr, sizeof(p));
     487           0 :                 entry = talloc_get_type_abort(p, struct sl_inode_path_map);
     488             : 
     489           0 :                 DEBUG(10, ("map: %s\n", entry->path));
     490             : 
     491           0 :                 entry = talloc_reference(slq->entries_ctx, entry);
     492           0 :                 if (entry == NULL) {
     493           0 :                         DEBUG(1, ("talloc_reference failed\n"));
     494           0 :                         return false;
     495             :                 }
     496           0 :                 return true;
     497             :         }
     498             : 
     499          17 :         if (!NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
     500           0 :                 DEBUG(1, ("dbwrap_fetch failed %s\n", nt_errstr(status)));
     501           0 :                 return false;
     502             :         }
     503             : 
     504          17 :         entry = talloc_zero(slq->entries_ctx, struct sl_inode_path_map);
     505          17 :         if (entry == NULL) {
     506           0 :                 DEBUG(1, ("talloc failed\n"));
     507           0 :                 return false;
     508             :         }
     509             : 
     510          17 :         entry->ino = ino;
     511          17 :         entry->mds_ctx = slq->mds_ctx;
     512          17 :         entry->st = *st;
     513          17 :         entry->path = talloc_strdup(entry, path);
     514          17 :         if (entry->path == NULL) {
     515           0 :                 DEBUG(1, ("talloc failed\n"));
     516           0 :                 TALLOC_FREE(entry);
     517           0 :                 return false;
     518             :         }
     519             : 
     520          17 :         status = dbwrap_store(slq->mds_ctx->ino_path_map, key,
     521             :                               make_tdb_data((void *)&entry, sizeof(void *)), 0);
     522          17 :         if (!NT_STATUS_IS_OK(status)) {
     523           0 :                 DEBUG(1, ("Failed to store record: %s\n", nt_errstr(status)));
     524           0 :                 TALLOC_FREE(entry);
     525           0 :                 return false;
     526             :         }
     527             : 
     528          17 :         talloc_set_destructor(entry, ino_path_map_destr_cb);
     529             : 
     530          17 :         return true;
     531             : }
     532             : 
     533          17 : bool mds_add_result(struct sl_query *slq, const char *path)
     534             : {
     535          17 :         struct smb_filename *smb_fname = NULL;
     536          17 :         const char *relative = NULL;
     537          17 :         char *fake_path = NULL;
     538             :         struct stat_ex sb;
     539             :         uint64_t ino64;
     540             :         int result;
     541             :         NTSTATUS status;
     542             :         bool sub;
     543             :         bool ok;
     544             : 
     545             :         /*
     546             :          * We're in a tevent callback which means in the case of
     547             :          * running as external RPC service we're running as root and
     548             :          * not as the user.
     549             :          */
     550          17 :         if (!become_authenticated_pipe_user(slq->mds_ctx->pipe_session_info)) {
     551           0 :                 DBG_ERR("can't become authenticated user: %d\n",
     552             :                         slq->mds_ctx->uid);
     553           0 :                 smb_panic("can't become authenticated user");
     554             :         }
     555             : 
     556          17 :         if (geteuid() != slq->mds_ctx->uid) {
     557           0 :                 DBG_ERR("uid mismatch: %d/%d\n", geteuid(), slq->mds_ctx->uid);
     558           0 :                 smb_panic("uid mismatch");
     559             :         }
     560             : 
     561             :         /*
     562             :          * We've changed identity to the authenticated pipe user, so
     563             :          * any function exit below must ensure we switch back
     564             :          */
     565             : 
     566          17 :         status = synthetic_pathref(talloc_tos(),
     567          17 :                                    slq->mds_ctx->conn->cwd_fsp,
     568             :                                    path,
     569             :                                    NULL,
     570             :                                    NULL,
     571             :                                    0,
     572             :                                    0,
     573             :                                    &smb_fname);
     574          17 :         if (!NT_STATUS_IS_OK(status)) {
     575           0 :                 DBG_DEBUG("synthetic_pathref [%s]: %s\n",
     576             :                           smb_fname_str_dbg(smb_fname),
     577             :                           nt_errstr(status));
     578           0 :                 unbecome_authenticated_pipe_user();
     579           0 :                 return true;
     580             :         }
     581             : 
     582          17 :         sb = smb_fname->st;
     583             : 
     584          17 :         status = smbd_check_access_rights_fsp(slq->mds_ctx->conn->cwd_fsp,
     585          17 :                                               smb_fname->fsp,
     586             :                                               false,
     587             :                                               FILE_READ_DATA);
     588          17 :         unbecome_authenticated_pipe_user();
     589          17 :         if (!NT_STATUS_IS_OK(status)) {
     590           0 :                 TALLOC_FREE(smb_fname);
     591           0 :                 return true;
     592             :         }
     593             : 
     594             :         /* Done with smb_fname now. */
     595          17 :         TALLOC_FREE(smb_fname);
     596             : 
     597          17 :         ino64 = SMB_VFS_FS_FILE_ID(slq->mds_ctx->conn, &sb);
     598             : 
     599          17 :         if (slq->cnids) {
     600             :                 bool found;
     601             : 
     602             :                 /*
     603             :                  * Check whether the found element is in the requested
     604             :                  * set of IDs. Note that we're faking CNIDs by using
     605             :                  * filesystem inode numbers here
     606             :                  */
     607           0 :                 found = bsearch(&ino64,
     608           0 :                                 slq->cnids,
     609             :                                 slq->cnids_num,
     610             :                                 sizeof(uint64_t),
     611             :                                 cnid_comp_fn);
     612           0 :                 if (!found) {
     613           0 :                         return true;
     614             :                 }
     615             :         }
     616             : 
     617          17 :         sub = subdir_of(slq->mds_ctx->spath,
     618          17 :                         slq->mds_ctx->spath_len,
     619             :                         path,
     620             :                         &relative);
     621          17 :         if (!sub) {
     622           0 :                 DBG_ERR("[%s] is not inside [%s]\n",
     623             :                         path, slq->mds_ctx->spath);
     624           0 :                 slq->state = SLQ_STATE_ERROR;
     625           0 :                 return false;
     626             :         }
     627             : 
     628             :         /*
     629             :          * Add inode number and filemeta to result set, this is what
     630             :          * we return as part of the result set of a query
     631             :          */
     632          17 :         result = dalloc_add_copy(slq->query_results->cnids->ca_cnids,
     633             :                                  &ino64,
     634             :                                  uint64_t);
     635          17 :         if (result != 0) {
     636           0 :                 DBG_ERR("dalloc error\n");
     637           0 :                 slq->state = SLQ_STATE_ERROR;
     638           0 :                 return false;
     639             :         }
     640             : 
     641          17 :         fake_path = talloc_asprintf(slq,
     642             :                                     "/%s/%s",
     643          17 :                                     slq->mds_ctx->sharename,
     644             :                                     relative);
     645          17 :         if (fake_path == NULL) {
     646           0 :                 slq->state = SLQ_STATE_ERROR;
     647           0 :                 return false;
     648             :         }
     649             : 
     650          17 :         ok = add_filemeta(slq->mds_ctx,
     651             :                           slq->reqinfo,
     652          17 :                           slq->query_results->fm_array,
     653             :                           fake_path,
     654             :                           &sb);
     655          17 :         if (!ok) {
     656           0 :                 DBG_ERR("add_filemeta error\n");
     657           0 :                 TALLOC_FREE(fake_path);
     658           0 :                 slq->state = SLQ_STATE_ERROR;
     659           0 :                 return false;
     660             :         }
     661             : 
     662          17 :         ok = inode_map_add(slq, ino64, fake_path, &sb);
     663          17 :         TALLOC_FREE(fake_path);
     664          17 :         if (!ok) {
     665           0 :                 DEBUG(1, ("inode_map_add error\n"));
     666           0 :                 slq->state = SLQ_STATE_ERROR;
     667           0 :                 return false;
     668             :         }
     669             : 
     670          17 :         slq->query_results->num_results++;
     671          17 :         return true;
     672             : }
     673             : 
     674             : /***********************************************************
     675             :  * Spotlight RPC functions
     676             :  ***********************************************************/
     677             : 
     678           7 : static bool slrpc_fetch_properties(struct mds_ctx *mds_ctx,
     679             :                                    const DALLOC_CTX *query, DALLOC_CTX *reply)
     680             : {
     681             :         sl_dict_t *dict;
     682             :         sl_array_t *array;
     683             :         char *s;
     684             :         uint64_t u;
     685             :         sl_bool_t b;
     686             :         sl_uuid_t uuid;
     687             :         int result;
     688             : 
     689           7 :         dict = dalloc_zero(reply, sl_dict_t);
     690           7 :         if (dict == NULL) {
     691           0 :                 return false;
     692             :         }
     693             : 
     694             :         /* kMDSStoreHasPersistentUUID = false */
     695           7 :         result = dalloc_stradd(dict, "kMDSStoreHasPersistentUUID");
     696           7 :         if (result != 0) {
     697           0 :                 return false;
     698             :         }
     699           7 :         b = false;
     700           7 :         result = dalloc_add_copy(dict, &b, sl_bool_t);
     701           7 :         if (result != 0) {
     702           0 :                 return false;
     703             :         }
     704             : 
     705             :         /* kMDSStoreIsBackup = false */
     706           7 :         result = dalloc_stradd(dict, "kMDSStoreIsBackup");
     707           7 :         if (result != 0) {
     708           0 :                 return false;
     709             :         }
     710           7 :         b = false;
     711           7 :         result = dalloc_add_copy(dict, &b, sl_bool_t);
     712           7 :         if (result != 0) {
     713           0 :                 return false;
     714             :         }
     715             : 
     716             :         /* kMDSStoreUUID = uuid */
     717           7 :         result = dalloc_stradd(dict, "kMDSStoreUUID");
     718           7 :         if (result != 0) {
     719           0 :                 return false;
     720             :         }
     721           7 :         memcpy(uuid.sl_uuid, "fakeuuidfakeuuid", sizeof(uuid.sl_uuid));
     722           7 :         result = dalloc_add_copy(dict, &uuid, sl_uuid_t);
     723           7 :         if (result != 0) {
     724           0 :                 return false;
     725             :         }
     726             : 
     727             :         /* kMDSStoreSupportsVolFS = true */
     728           7 :         result = dalloc_stradd(dict, "kMDSStoreSupportsVolFS");
     729           7 :         if (result != 0) {
     730           0 :                 return false;
     731             :         }
     732           7 :         b = true;
     733           7 :         result = dalloc_add_copy(dict, &b, sl_bool_t);
     734           7 :         if (result != 0) {
     735           0 :                 return false;
     736             :         }
     737             : 
     738             :         /* kMDSVolumeUUID = uuid */
     739           7 :         result = dalloc_stradd(dict, "kMDSVolumeUUID");
     740           7 :         if (result != 0) {
     741           0 :                 return false;
     742             :         }
     743           7 :         memcpy(uuid.sl_uuid, "fakeuuidfakeuuid", sizeof(uuid.sl_uuid));
     744           7 :         result = dalloc_add_copy(dict, &uuid, sl_uuid_t);
     745           7 :         if (result != 0) {
     746           0 :                 return false;
     747             :         }
     748             : 
     749             :         /* kMDSDiskStoreSpindleNumber = 1 (fake) */
     750           7 :         result = dalloc_stradd(dict, "kMDSDiskStoreSpindleNumber");
     751           7 :         if (result != 0) {
     752           0 :                 return false;
     753             :         }
     754           7 :         u = 1;
     755           7 :         result = dalloc_add_copy(dict, &u, uint64_t);
     756           7 :         if (result != 0) {
     757           0 :                 return false;
     758             :         }
     759             : 
     760             :         /* kMDSDiskStorePolicy = 3 (whatever that means, taken from OS X) */
     761           7 :         result = dalloc_stradd(dict, "kMDSDiskStorePolicy");
     762           7 :         if (result != 0) {
     763           0 :                 return false;
     764             :         }
     765           7 :         u = 3;
     766           7 :         result = dalloc_add_copy(dict, &u, uint64_t);
     767           7 :         if (result != 0) {
     768           0 :                 return false;
     769             :         }
     770             : 
     771             :         /* kMDSStoreMetaScopes array */
     772           7 :         result = dalloc_stradd(dict, "kMDSStoreMetaScopes");
     773           7 :         if (result != 0) {
     774           0 :                 return false;
     775             :         }
     776           7 :         array = dalloc_zero(dict, sl_array_t);
     777           7 :         if (array == NULL) {
     778           0 :                 return NULL;
     779             :         }
     780           7 :         result = dalloc_stradd(array, "kMDQueryScopeComputer");
     781           7 :         if (result != 0) {
     782           0 :                 return false;
     783             :         }
     784           7 :         result = dalloc_stradd(array, "kMDQueryScopeAllIndexed");
     785           7 :         if (result != 0) {
     786           0 :                 return false;
     787             :         }
     788           7 :         result = dalloc_stradd(array, "kMDQueryScopeComputerIndexed");
     789           7 :         if (result != 0) {
     790           0 :                 return false;
     791             :         }
     792           7 :         result = dalloc_add(dict, array, sl_array_t);
     793           7 :         if (result != 0) {
     794           0 :                 return false;
     795             :         }
     796             : 
     797             :         /* kMDSStoreDevice = 0x1000003 (whatever that means, taken from OS X) */
     798           7 :         result = dalloc_stradd(dict, "kMDSStoreDevice");
     799           7 :         if (result != 0) {
     800           0 :                 return false;
     801             :         }
     802           7 :         u = 0x1000003;
     803           7 :         result = dalloc_add_copy(dict, &u, uint64_t);
     804           7 :         if (result != 0) {
     805           0 :                 return false;
     806             :         }
     807             : 
     808             :         /* kMDSStoreSupportsTCC = true (whatever that means, taken from OS X) */
     809           7 :         result = dalloc_stradd(dict, "kMDSStoreSupportsTCC");
     810           7 :         if (result != 0) {
     811           0 :                 return false;
     812             :         }
     813           7 :         b = true;
     814           7 :         result = dalloc_add_copy(dict, &b, sl_bool_t);
     815           7 :         if (result != 0) {
     816           0 :                 return false;
     817             :         }
     818             : 
     819             :         /* kMDSStorePathScopes = ["/"] (whatever that means, taken from OS X) */
     820           7 :         result = dalloc_stradd(dict, "kMDSStorePathScopes");
     821           7 :         if (result != 0) {
     822           0 :                 return false;
     823             :         }
     824           7 :         array = dalloc_zero(dict, sl_array_t);
     825           7 :         if (array == NULL) {
     826           0 :                 return false;
     827             :         }
     828           7 :         s = talloc_strdup(dict, "/");
     829           7 :         if (s == NULL) {
     830           0 :                 return false;
     831             :         }
     832           7 :         talloc_set_name(s, "smb_ucs2_t *");
     833           7 :         result = dalloc_add(array, s, smb_ucs2_t *);
     834           7 :         if (result != 0) {
     835           0 :                 return false;
     836             :         }
     837           7 :         result = dalloc_add(dict, array, sl_array_t);
     838           7 :         if (result != 0) {
     839           0 :                 return false;
     840             :         }
     841             : 
     842           7 :         result = dalloc_add(reply, dict, sl_dict_t);
     843           7 :         if (result != 0) {
     844           0 :                 return false;
     845             :         }
     846             : 
     847           7 :         return true;
     848             : }
     849             : 
     850           0 : static void slq_close_timer(struct tevent_context *ev,
     851             :                             struct tevent_timer *te,
     852             :                             struct timeval current_time,
     853             :                             void *private_data)
     854             : {
     855           0 :         struct sl_query *slq = talloc_get_type_abort(
     856             :                 private_data, struct sl_query);
     857           0 :         struct mds_ctx *mds_ctx = slq->mds_ctx;
     858             : 
     859           0 :         SLQ_DEBUG(10, slq, "expired");
     860             : 
     861           0 :         TALLOC_FREE(slq);
     862             : 
     863           0 :         if (CHECK_DEBUGLVL(10)) {
     864           0 :                 for (slq = mds_ctx->query_list; slq != NULL; slq = slq->next) {
     865           0 :                         SLQ_DEBUG(10, slq, "pending");
     866             :                 }
     867             :         }
     868           0 : }
     869             : 
     870             : /**
     871             :  * Translate a fake scope from the client like /sharename/dir
     872             :  * to the real server-side path, replacing the "/sharename" part
     873             :  * with the absolute server-side path of the share.
     874             :  **/
     875           5 : static bool mdssvc_real_scope(struct sl_query *slq, const char *fake_scope)
     876             : {
     877           5 :         size_t sname_len = strlen(slq->mds_ctx->sharename);
     878           5 :         size_t fake_scope_len = strlen(fake_scope);
     879             : 
     880           5 :         if (fake_scope_len < sname_len + 1) {
     881           0 :                 DBG_ERR("Short scope [%s] for share [%s]\n",
     882             :                         fake_scope, slq->mds_ctx->sharename);
     883           0 :                 return false;
     884             :         }
     885             : 
     886          10 :         slq->path_scope = talloc_asprintf(slq,
     887             :                                           "%s%s",
     888           5 :                                           slq->mds_ctx->spath,
     889           5 :                                           fake_scope + sname_len + 1);
     890           5 :         if (slq->path_scope == NULL) {
     891           0 :                 return false;
     892             :         }
     893           5 :         return true;
     894             : }
     895             : 
     896             : /**
     897             :  * Begin a search query
     898             :  **/
     899           8 : static bool slrpc_open_query(struct mds_ctx *mds_ctx,
     900             :                              const DALLOC_CTX *query, DALLOC_CTX *reply)
     901             : {
     902             :         bool ok;
     903             :         uint64_t sl_result;
     904             :         uint64_t *uint64p;
     905             :         DALLOC_CTX *reqinfo;
     906             :         sl_array_t *array, *path_scope;
     907             :         sl_cnids_t *cnids;
     908           8 :         struct sl_query *slq = NULL;
     909             :         int result;
     910           8 :         const char *querystring = NULL;
     911             :         size_t querystring_len;
     912           8 :         char *dest = NULL;
     913             :         size_t dest_remaining;
     914             :         size_t nconv;
     915           8 :         char *scope = NULL;
     916             : 
     917           8 :         array = dalloc_zero(reply, sl_array_t);
     918           8 :         if (array == NULL) {
     919           0 :                 return false;
     920             :         }
     921             : 
     922             :         /* Allocate and initialize query object */
     923           8 :         slq = talloc_zero(mds_ctx, struct sl_query);
     924           8 :         if (slq == NULL) {
     925           0 :                 return false;
     926             :         }
     927           8 :         slq->entries_ctx = talloc_named_const(slq, 0, "struct sl_query.entries_ctx");
     928           8 :         if (slq->entries_ctx == NULL) {
     929           0 :                 TALLOC_FREE(slq);
     930           0 :                 return false;
     931             :         }
     932           8 :         talloc_set_destructor(slq, slq_destructor_cb);
     933           8 :         slq->state = SLQ_STATE_NEW;
     934           8 :         slq->mds_ctx = mds_ctx;
     935             : 
     936           8 :         slq->last_used = timeval_current();
     937           8 :         slq->start_time = slq->last_used;
     938           8 :         slq->expire_time = timeval_add(&slq->last_used, MAX_SL_RUNTIME, 0);
     939           8 :         slq->te = tevent_add_timer(global_event_context(), slq,
     940             :                                    slq->expire_time, slq_close_timer, slq);
     941           8 :         if (slq->te == NULL) {
     942           0 :                 DEBUG(1, ("tevent_add_timer failed\n"));
     943           0 :                 goto error;
     944             :         }
     945             : 
     946           8 :         querystring = dalloc_value_for_key(query, "DALLOC_CTX", 0,
     947             :                                            "DALLOC_CTX", 1,
     948             :                                            "kMDQueryString",
     949             :                                            "char *");
     950           8 :         if (querystring == NULL) {
     951           0 :                 DEBUG(1, ("missing kMDQueryString\n"));
     952           0 :                 goto error;
     953             :         }
     954             : 
     955           8 :         querystring_len = talloc_array_length(querystring);
     956             : 
     957           8 :         slq->query_string = talloc_array(slq, char, querystring_len);
     958           8 :         if (slq->query_string == NULL) {
     959           0 :                 DEBUG(1, ("out of memory\n"));
     960           0 :                 goto error;
     961             :         }
     962           8 :         dest = slq->query_string;
     963           8 :         dest_remaining = talloc_array_length(dest);
     964             : 
     965           8 :         nconv = smb_iconv(mds_ctx->ic_nfd_to_nfc,
     966             :                           &querystring,
     967             :                           &querystring_len,
     968             :                           &dest,
     969             :                           &dest_remaining);
     970           8 :         if (nconv == (size_t)-1) {
     971           0 :                 DBG_ERR("smb_iconv failed for: %s\n", querystring);
     972           0 :                 return false;
     973             :         }
     974             : 
     975           8 :         uint64p = dalloc_get(query, "DALLOC_CTX", 0, "DALLOC_CTX", 0,
     976             :                              "uint64_t", 1);
     977           8 :         if (uint64p == NULL) {
     978           0 :                 goto error;
     979             :         }
     980           8 :         slq->ctx1 = *uint64p;
     981           8 :         uint64p = dalloc_get(query, "DALLOC_CTX", 0, "DALLOC_CTX", 0,
     982             :                              "uint64_t", 2);
     983           8 :         if (uint64p == NULL) {
     984           0 :                 goto error;
     985             :         }
     986           8 :         slq->ctx2 = *uint64p;
     987             : 
     988           8 :         path_scope = dalloc_value_for_key(query, "DALLOC_CTX", 0,
     989             :                                           "DALLOC_CTX", 1,
     990             :                                           "kMDScopeArray",
     991             :                                           "sl_array_t");
     992           8 :         if (path_scope == NULL) {
     993           3 :                 DBG_ERR("missing kMDScopeArray\n");
     994           3 :                 goto error;
     995             :         }
     996             : 
     997           5 :         scope = dalloc_get(path_scope, "char *", 0);
     998           5 :         if (scope == NULL) {
     999           0 :                 scope = dalloc_get(path_scope,
    1000             :                                    "DALLOC_CTX", 0,
    1001             :                                    "char *", 0);
    1002             :         }
    1003           5 :         if (scope == NULL) {
    1004           0 :                 DBG_ERR("Failed to parse kMDScopeArray\n");
    1005           0 :                 goto error;
    1006             :         }
    1007             : 
    1008           5 :         ok = mdssvc_real_scope(slq, scope);
    1009           5 :         if (!ok) {
    1010           0 :                 goto error;
    1011             :         }
    1012             : 
    1013           5 :         reqinfo = dalloc_value_for_key(query, "DALLOC_CTX", 0,
    1014             :                                        "DALLOC_CTX", 1,
    1015             :                                        "kMDAttributeArray",
    1016             :                                        "sl_array_t");
    1017           5 :         if (reqinfo == NULL) {
    1018           0 :                 DBG_ERR("missing kMDAttributeArray\n");
    1019           0 :                 goto error;
    1020             :         }
    1021             : 
    1022           5 :         slq->reqinfo = talloc_steal(slq, reqinfo);
    1023           5 :         DEBUG(10, ("requested attributes: %s", dalloc_dump(reqinfo, 0)));
    1024             : 
    1025           5 :         cnids = dalloc_value_for_key(query, "DALLOC_CTX", 0,
    1026             :                                      "DALLOC_CTX", 1,
    1027             :                                      "kMDQueryItemArray",
    1028             :                                      "sl_array_t");
    1029           5 :         if (cnids) {
    1030           0 :                 ok = sort_cnids(slq, cnids->ca_cnids);
    1031           0 :                 if (!ok) {
    1032           0 :                         goto error;
    1033             :                 }
    1034             :         }
    1035             : 
    1036           5 :         ok = create_result_handle(slq);
    1037           5 :         if (!ok) {
    1038           0 :                 DEBUG(1, ("create_result_handle error\n"));
    1039           0 :                 slq->state = SLQ_STATE_ERROR;
    1040           0 :                 goto error;
    1041             :         }
    1042             : 
    1043           5 :         SLQ_DEBUG(10, slq, "new");
    1044             : 
    1045           5 :         DLIST_ADD(mds_ctx->query_list, slq);
    1046             : 
    1047           5 :         ok = mds_ctx->backend->search_start(slq);
    1048           5 :         if (!ok) {
    1049           0 :                 DBG_ERR("backend search_start failed\n");
    1050           0 :                 goto error;
    1051             :         }
    1052             : 
    1053           5 :         sl_result = 0;
    1054           5 :         result = dalloc_add_copy(array, &sl_result, uint64_t);
    1055           5 :         if (result != 0) {
    1056           0 :                 goto error;
    1057             :         }
    1058           5 :         result = dalloc_add(reply, array, sl_array_t);
    1059           5 :         if (result != 0) {
    1060           0 :                 goto error;
    1061             :         }
    1062           5 :         return true;
    1063             : 
    1064           3 : error:
    1065           3 :         sl_result = UINT64_MAX;
    1066           3 :         TALLOC_FREE(slq);
    1067           3 :         result = dalloc_add_copy(array, &sl_result, uint64_t);
    1068           3 :         if (result != 0) {
    1069           0 :                 return false;
    1070             :         }
    1071           3 :         result = dalloc_add(reply, array, sl_array_t);
    1072           3 :         if (result != 0) {
    1073           0 :                 return false;
    1074             :         }
    1075           3 :         return true;
    1076             : }
    1077             : 
    1078             : /**
    1079             :  * Fetch results of a query
    1080             :  **/
    1081           8 : static bool slrpc_fetch_query_results(struct mds_ctx *mds_ctx,
    1082             :                                       const DALLOC_CTX *query,
    1083             :                                       DALLOC_CTX *reply)
    1084             : {
    1085             :         bool ok;
    1086           8 :         struct sl_query *slq = NULL;
    1087             :         uint64_t *uint64p, ctx1, ctx2;
    1088             :         uint64_t status;
    1089             :         sl_array_t *array;
    1090             :         int result;
    1091             : 
    1092           8 :         array = dalloc_zero(reply, sl_array_t);
    1093           8 :         if (array == NULL) {
    1094           0 :                 return false;
    1095             :         }
    1096             : 
    1097             :         /* Get query for context */
    1098           8 :         uint64p = dalloc_get(query, "DALLOC_CTX", 0, "DALLOC_CTX", 0,
    1099             :                              "uint64_t", 1);
    1100           8 :         if (uint64p == NULL) {
    1101           0 :                 goto error;
    1102             :         }
    1103           8 :         ctx1 = *uint64p;
    1104             : 
    1105           8 :         uint64p = dalloc_get(query, "DALLOC_CTX", 0, "DALLOC_CTX", 0,
    1106             :                              "uint64_t", 2);
    1107           8 :         if (uint64p == NULL) {
    1108           0 :                 goto error;
    1109             :         }
    1110           8 :         ctx2 = *uint64p;
    1111             : 
    1112           8 :         slq = slq_for_ctx(mds_ctx, ctx1, ctx2);
    1113           8 :         if (slq == NULL) {
    1114           0 :                 DEBUG(1, ("bad context: [0x%jx,0x%jx]\n",
    1115             :                           (uintmax_t)ctx1, (uintmax_t)ctx2));
    1116           0 :                 goto error;
    1117             :         }
    1118             : 
    1119           8 :         TALLOC_FREE(slq->te);
    1120           8 :         slq->last_used = timeval_current();
    1121           8 :         slq->expire_time = timeval_add(&slq->last_used, MAX_SL_RUNTIME, 0);
    1122           8 :         slq->te = tevent_add_timer(global_event_context(), slq,
    1123             :                                    slq->expire_time, slq_close_timer, slq);
    1124           8 :         if (slq->te == NULL) {
    1125           0 :                 DEBUG(1, ("tevent_add_timer failed\n"));
    1126           0 :                 goto error;
    1127             :         }
    1128             : 
    1129           8 :         SLQ_DEBUG(10, slq, "fetch");
    1130             : 
    1131           8 :         switch (slq->state) {
    1132           8 :         case SLQ_STATE_RUNNING:
    1133             :         case SLQ_STATE_RESULTS:
    1134             :         case SLQ_STATE_FULL:
    1135             :         case SLQ_STATE_DONE:
    1136           8 :                 ok = add_results(array, slq);
    1137           8 :                 if (!ok) {
    1138           0 :                         DEBUG(1, ("error adding results\n"));
    1139           0 :                         goto error;
    1140             :                 }
    1141           8 :                 if (slq->state == SLQ_STATE_FULL) {
    1142           0 :                         slq->state = SLQ_STATE_RUNNING;
    1143           0 :                         slq->mds_ctx->backend->search_cont(slq);
    1144             :                 }
    1145           8 :                 break;
    1146             : 
    1147           0 :         case SLQ_STATE_ERROR:
    1148           0 :                 DEBUG(1, ("query in error state\n"));
    1149           0 :                 goto error;
    1150             : 
    1151           0 :         default:
    1152           0 :                 DEBUG(1, ("unexpected query state %d\n", slq->state));
    1153           0 :                 goto error;
    1154             :         }
    1155             : 
    1156           8 :         result = dalloc_add(reply, array, sl_array_t);
    1157           8 :         if (result != 0) {
    1158           0 :                 goto error;
    1159             :         }
    1160           8 :         return true;
    1161             : 
    1162           0 : error:
    1163           0 :         status = UINT64_MAX;
    1164           0 :         TALLOC_FREE(slq);
    1165           0 :         result = dalloc_add_copy(array, &status, uint64_t);
    1166           0 :         if (result != 0) {
    1167           0 :                 return false;
    1168             :         }
    1169           0 :         result = dalloc_add(reply, array, sl_array_t);
    1170           0 :         if (result != 0) {
    1171           0 :                 return false;
    1172             :         }
    1173           0 :         return true;
    1174             : }
    1175             : 
    1176             : /**
    1177             :  * Store metadata attributes for a CNID
    1178             :  **/
    1179           0 : static bool slrpc_store_attributes(struct mds_ctx *mds_ctx,
    1180             :                                    const DALLOC_CTX *query, DALLOC_CTX *reply)
    1181             : {
    1182             :         uint64_t sl_result;
    1183             :         sl_array_t *array;
    1184             :         int result;
    1185             : 
    1186           0 :         array = dalloc_zero(reply, sl_array_t);
    1187           0 :         if (array == NULL) {
    1188           0 :                 return false;
    1189             :         }
    1190             : 
    1191             :         /*
    1192             :          * FIXME: not implemented. Used by the client for eg setting
    1193             :          * the modification date of the shared directory which clients
    1194             :          * poll indicating changes on the share and cause the client
    1195             :          * to refresh view.
    1196             :          */
    1197             : 
    1198           0 :         sl_result = 0;
    1199           0 :         result = dalloc_add_copy(array, &sl_result, uint64_t);
    1200           0 :         if (result != 0) {
    1201           0 :                 return false;
    1202             :         }
    1203           0 :         result = dalloc_add(reply, array, sl_array_t);
    1204           0 :         if (result != 0) {
    1205           0 :                 return false;
    1206             :         }
    1207             : 
    1208           0 :         return true;
    1209             : }
    1210             : 
    1211             : /**
    1212             :  * Fetch supported metadata attributes for a CNID
    1213             :  **/
    1214           0 : static bool slrpc_fetch_attributenames(struct mds_ctx *mds_ctx,
    1215             :                                        const DALLOC_CTX *query,
    1216             :                                        DALLOC_CTX *reply)
    1217             : {
    1218             :         uint64_t id;
    1219             :         sl_cnids_t *cnids;
    1220             :         sl_array_t *array;
    1221             :         uint64_t sl_result;
    1222             :         sl_cnids_t *replycnids;
    1223             :         sl_array_t *mdattrs;
    1224             :         sl_filemeta_t *fmeta;
    1225             :         int result;
    1226             :         void *p;
    1227             : 
    1228           0 :         cnids = dalloc_get(query, "DALLOC_CTX", 0, "sl_cnids_t", 1);
    1229           0 :         if (cnids == NULL) {
    1230           0 :                 return false;
    1231             :         }
    1232             : 
    1233           0 :         p = dalloc_get_object(cnids->ca_cnids, 0);
    1234           0 :         if (p == NULL) {
    1235           0 :                 return NULL;
    1236             :         }
    1237           0 :         memcpy(&id, p, sizeof(uint64_t));
    1238             : 
    1239             :         /* Result array */
    1240           0 :         array = dalloc_zero(reply, sl_array_t);
    1241           0 :         if (array == NULL) {
    1242           0 :                 return false;
    1243             :         }
    1244             : 
    1245           0 :         result = dalloc_add(reply, array, sl_array_t);
    1246           0 :         if (result != 0) {
    1247           0 :                 return false;
    1248             :         }
    1249             : 
    1250             :         /* Return result value 0 */
    1251           0 :         sl_result = 0;
    1252           0 :         result = dalloc_add_copy(array, &sl_result, uint64_t);
    1253           0 :         if (result != 0) {
    1254           0 :                 return false;
    1255             :         }
    1256             : 
    1257             :         /* Return CNID array */
    1258           0 :         replycnids = talloc_zero(reply, sl_cnids_t);
    1259           0 :         if (replycnids == NULL) {
    1260           0 :                 return false;
    1261             :         }
    1262             : 
    1263           0 :         replycnids->ca_cnids = dalloc_new(cnids);
    1264           0 :         if (replycnids->ca_cnids == NULL) {
    1265           0 :                 return false;
    1266             :         }
    1267             : 
    1268           0 :         replycnids->ca_unkn1 = 0xfec;
    1269           0 :         replycnids->ca_context = cnids->ca_context;
    1270           0 :         result = dalloc_add_copy(replycnids->ca_cnids, &id, uint64_t);
    1271           0 :         if (result != 0) {
    1272           0 :                 return false;
    1273             :         }
    1274           0 :         result = dalloc_add(array, replycnids, sl_cnids_t);
    1275           0 :         if (result != 0) {
    1276           0 :                 return false;
    1277             :         }
    1278             : 
    1279             :         /*
    1280             :          * FIXME: this should return the real attributes from all
    1281             :          * known metadata sources (Tracker and filesystem)
    1282             :          */
    1283           0 :         mdattrs = dalloc_zero(reply, sl_array_t);
    1284           0 :         if (mdattrs == NULL) {
    1285           0 :                 return false;
    1286             :         }
    1287             : 
    1288           0 :         result = dalloc_stradd(mdattrs, "kMDItemFSName");
    1289           0 :         if (result != 0) {
    1290           0 :                 return false;
    1291             :         }
    1292           0 :         result = dalloc_stradd(mdattrs, "kMDItemDisplayName");
    1293           0 :         if (result != 0) {
    1294           0 :                 return false;
    1295             :         }
    1296           0 :         result = dalloc_stradd(mdattrs, "kMDItemFSSize");
    1297           0 :         if (result != 0) {
    1298           0 :                 return false;
    1299             :         }
    1300           0 :         result = dalloc_stradd(mdattrs, "kMDItemFSOwnerUserID");
    1301           0 :         if (result != 0) {
    1302           0 :                 return false;
    1303             :         }
    1304           0 :         result = dalloc_stradd(mdattrs, "kMDItemFSOwnerGroupID");
    1305           0 :         if (result != 0) {
    1306           0 :                 return false;
    1307             :         }
    1308           0 :         result = dalloc_stradd(mdattrs, "kMDItemFSContentChangeDate");
    1309           0 :         if (result != 0) {
    1310           0 :                 return false;
    1311             :         }
    1312             : 
    1313           0 :         fmeta = dalloc_zero(reply, sl_filemeta_t);
    1314           0 :         if (fmeta == NULL) {
    1315           0 :                 return false;
    1316             :         }
    1317           0 :         result = dalloc_add(fmeta, mdattrs, sl_array_t);
    1318           0 :         if (result != 0) {
    1319           0 :                 return false;
    1320             :         }
    1321           0 :         result = dalloc_add(array, fmeta, sl_filemeta_t);
    1322           0 :         if (result != 0) {
    1323           0 :                 return false;
    1324             :         }
    1325             : 
    1326           0 :         return true;
    1327             : }
    1328             : 
    1329             : /**
    1330             :  * Fetch metadata attribute values for a CNID
    1331             :  **/
    1332          20 : static bool slrpc_fetch_attributes(struct mds_ctx *mds_ctx,
    1333             :                                    const DALLOC_CTX *query, DALLOC_CTX *reply)
    1334             : {
    1335             :         int result;
    1336             :         bool ok;
    1337             :         sl_array_t *array;
    1338             :         sl_cnids_t *cnids;
    1339             :         sl_cnids_t *replycnids;
    1340             :         sl_array_t *reqinfo;
    1341             :         uint64_t ino;
    1342             :         uint64_t sl_result;
    1343             :         sl_filemeta_t *fm;
    1344             :         sl_array_t *fm_array;
    1345             :         sl_nil_t nil;
    1346          20 :         char *path = NULL;
    1347          20 :         struct smb_filename *smb_fname = NULL;
    1348          20 :         struct stat_ex *sp = NULL;
    1349          20 :         struct sl_inode_path_map *elem = NULL;
    1350             :         void *p;
    1351          20 :         TDB_DATA val = tdb_null;
    1352             :         NTSTATUS status;
    1353             : 
    1354          20 :         array = dalloc_zero(reply, sl_array_t);
    1355          20 :         if (array == NULL) {
    1356           0 :                 return false;
    1357             :         }
    1358          20 :         replycnids = talloc_zero(reply, sl_cnids_t);
    1359          20 :         if (replycnids == NULL) {
    1360           0 :                 goto error;
    1361             :         }
    1362          20 :         replycnids->ca_cnids = dalloc_new(replycnids);
    1363          20 :         if (replycnids->ca_cnids == NULL) {
    1364           0 :                 goto error;
    1365             :         }
    1366          20 :         fm = dalloc_zero(array, sl_filemeta_t);
    1367          20 :         if (fm == NULL) {
    1368           0 :                 goto error;
    1369             :         }
    1370          20 :         fm_array = dalloc_zero(fm, sl_array_t);
    1371          20 :         if (fm_array == NULL) {
    1372           0 :                 goto error;
    1373             :         }
    1374             :         /* For some reason the list of results always starts with a nil entry */
    1375          20 :         result = dalloc_add_copy(fm_array, &nil, sl_nil_t);
    1376          20 :         if (result == -1) {
    1377           0 :                 goto error;
    1378             :         }
    1379             : 
    1380          20 :         reqinfo = dalloc_get(query, "DALLOC_CTX", 0, "sl_array_t", 1);
    1381          20 :         if (reqinfo == NULL) {
    1382           0 :                 goto error;
    1383             :         }
    1384             : 
    1385          20 :         cnids = dalloc_get(query, "DALLOC_CTX", 0, "sl_cnids_t", 2);
    1386          20 :         if (cnids == NULL) {
    1387           0 :                 goto error;
    1388             :         }
    1389          20 :         p = dalloc_get_object(cnids->ca_cnids, 0);
    1390          20 :         if (p == NULL) {
    1391           0 :                 goto error;
    1392             :         }
    1393          20 :         memcpy(&ino, p, sizeof(uint64_t));
    1394             : 
    1395          20 :         replycnids->ca_unkn1 = 0xfec;
    1396          20 :         replycnids->ca_context = cnids->ca_context;
    1397          20 :         result = dalloc_add_copy(replycnids->ca_cnids, &ino, uint64_t);
    1398          20 :         if (result != 0) {
    1399           0 :                 goto error;
    1400             :         }
    1401             : 
    1402          20 :         status = dbwrap_fetch(mds_ctx->ino_path_map, reply,
    1403             :                               make_tdb_data((void*)&ino, sizeof(uint64_t)),
    1404             :                               &val);
    1405          20 :         if (NT_STATUS_IS_OK(status)) {
    1406          17 :                 if (val.dsize != sizeof(p)) {
    1407           0 :                         DBG_ERR("invalid record pointer size: %zd\n", val.dsize);
    1408           0 :                         TALLOC_FREE(val.dptr);
    1409           0 :                         goto error;
    1410             :                 }
    1411             : 
    1412          17 :                 memcpy(&p, val.dptr, sizeof(p));
    1413          17 :                 elem = talloc_get_type_abort(p, struct sl_inode_path_map);
    1414          17 :                 path = elem->path;
    1415             : 
    1416          17 :                 sp = &elem->st;
    1417             :         }
    1418             : 
    1419          20 :         ok = add_filemeta(mds_ctx, reqinfo, fm_array, path, sp);
    1420          20 :         if (!ok) {
    1421           0 :                 goto error;
    1422             :         }
    1423             : 
    1424          20 :         sl_result = 0;
    1425          20 :         result = dalloc_add_copy(array, &sl_result, uint64_t);
    1426          20 :         if (result != 0) {
    1427           0 :                 goto error;
    1428             :         }
    1429          20 :         result = dalloc_add(array, replycnids, sl_cnids_t);
    1430          20 :         if (result != 0) {
    1431           0 :                 goto error;
    1432             :         }
    1433          20 :         result = dalloc_add(fm, fm_array, sl_array_t);
    1434          20 :         if (result != 0) {
    1435           0 :                 goto error;
    1436             :         }
    1437          20 :         result = dalloc_add(array, fm, sl_filemeta_t);
    1438          20 :         if (result != 0) {
    1439           0 :                 goto error;
    1440             :         }
    1441          20 :         result = dalloc_add(reply, array, sl_array_t);
    1442          20 :         if (result != 0) {
    1443           0 :                 goto error;
    1444             :         }
    1445             : 
    1446          20 :         TALLOC_FREE(smb_fname);
    1447          20 :         return true;
    1448             : 
    1449           0 : error:
    1450             : 
    1451           0 :         TALLOC_FREE(smb_fname);
    1452           0 :         sl_result = UINT64_MAX;
    1453           0 :         result = dalloc_add_copy(array, &sl_result, uint64_t);
    1454           0 :         if (result != 0) {
    1455           0 :                 return false;
    1456             :         }
    1457           0 :         result = dalloc_add(reply, array, sl_array_t);
    1458           0 :         if (result != 0) {
    1459           0 :                 return false;
    1460             :         }
    1461             : 
    1462           0 :         return true;
    1463             : }
    1464             : 
    1465             : /**
    1466             :  * Close a query
    1467             :  **/
    1468           5 : static bool slrpc_close_query(struct mds_ctx *mds_ctx,
    1469             :                               const DALLOC_CTX *query, DALLOC_CTX *reply)
    1470             : {
    1471           5 :         struct sl_query *slq = NULL;
    1472             :         uint64_t *uint64p, ctx1, ctx2;
    1473             :         sl_array_t *array;
    1474             :         uint64_t sl_res;
    1475             :         int result;
    1476             : 
    1477           5 :         array = dalloc_zero(reply, sl_array_t);
    1478           5 :         if (array == NULL) {
    1479           0 :                 return false;
    1480             :         }
    1481             : 
    1482             :         /* Context */
    1483           5 :         uint64p = dalloc_get(query, "DALLOC_CTX", 0, "DALLOC_CTX", 0,
    1484             :                              "uint64_t", 1);
    1485           5 :         if (uint64p == NULL) {
    1486           0 :                 goto done;
    1487             :         }
    1488           5 :         ctx1 = *uint64p;
    1489             : 
    1490           5 :         uint64p = dalloc_get(query, "DALLOC_CTX", 0, "DALLOC_CTX", 0,
    1491             :                              "uint64_t", 2);
    1492           5 :         if (uint64p == NULL) {
    1493           0 :                 goto done;
    1494             :         }
    1495           5 :         ctx2 = *uint64p;
    1496             : 
    1497             :         /* Get query for context and free it */
    1498           5 :         slq = slq_for_ctx(mds_ctx, ctx1, ctx2);
    1499           5 :         if (slq == NULL) {
    1500           0 :                 DEBUG(1, ("bad context: [0x%jx,0x%jx]\n",
    1501             :                           (uintmax_t)ctx1, (uintmax_t)ctx2));
    1502           0 :                 goto done;
    1503             :         }
    1504             : 
    1505           5 :         SLQ_DEBUG(10, slq, "close");
    1506           5 :         TALLOC_FREE(slq);
    1507             : 
    1508           0 : done:
    1509           5 :         sl_res = UINT64_MAX;
    1510           5 :         result = dalloc_add_copy(array, &sl_res, uint64_t);
    1511           5 :         if (result != 0) {
    1512           0 :                 return false;
    1513             :         }
    1514           5 :         result = dalloc_add(reply, array, sl_array_t);
    1515           5 :         if (result != 0) {
    1516           0 :                 return false;
    1517             :         }
    1518           5 :         return true;
    1519             : }
    1520             : 
    1521          22 : static struct mdssvc_ctx *mdssvc_init(struct tevent_context *ev)
    1522             : {
    1523             :         bool ok;
    1524             : 
    1525          22 :         if (mdssvc_ctx != NULL) {
    1526          14 :                 return mdssvc_ctx;
    1527             :         }
    1528             : 
    1529           8 :         mdssvc_ctx = talloc_zero(ev, struct mdssvc_ctx);
    1530           8 :         if (mdssvc_ctx == NULL) {
    1531           0 :                 return NULL;
    1532             :         }
    1533             : 
    1534           8 :         mdssvc_ctx->ev_ctx = ev;
    1535             : 
    1536           8 :         ok = mdsscv_backend_noindex.init(mdssvc_ctx);
    1537           8 :         if (!ok) {
    1538           0 :                 DBG_ERR("backend init failed\n");
    1539           0 :                 TALLOC_FREE(mdssvc_ctx);
    1540           0 :                 return NULL;
    1541             :         }
    1542             : 
    1543             : #ifdef HAVE_SPOTLIGHT_BACKEND_ES
    1544           8 :         ok = mdsscv_backend_es.init(mdssvc_ctx);
    1545           8 :         if (!ok) {
    1546           0 :                 DBG_ERR("backend init failed\n");
    1547           0 :                 TALLOC_FREE(mdssvc_ctx);
    1548           0 :                 return NULL;
    1549             :         }
    1550             : #endif
    1551             : 
    1552             : #ifdef HAVE_SPOTLIGHT_BACKEND_TRACKER
    1553             :         ok = mdsscv_backend_tracker.init(mdssvc_ctx);
    1554             :         if (!ok) {
    1555             :                 DBG_ERR("backend init failed\n");
    1556             :                 TALLOC_FREE(mdssvc_ctx);
    1557             :                 return NULL;
    1558             :         }
    1559             : #endif
    1560             : 
    1561           8 :         return mdssvc_ctx;
    1562             : }
    1563             : 
    1564             : /**
    1565             :  * Init callbacks at startup
    1566             :  *
    1567             :  * This gets typically called in the main parent smbd which means we can't
    1568             :  * initialize our global state here.
    1569             :  **/
    1570          12 : bool mds_init(struct messaging_context *msg_ctx)
    1571             : {
    1572          12 :         return true;
    1573             : }
    1574             : 
    1575          12 : bool mds_shutdown(void)
    1576             : {
    1577             :         bool ok;
    1578             : 
    1579          12 :         if (mdssvc_ctx == NULL) {
    1580           4 :                 return false;
    1581             :         }
    1582             : 
    1583           8 :         ok = mdsscv_backend_noindex.shutdown(mdssvc_ctx);
    1584           8 :         if (!ok) {
    1585           0 :                 goto fail;
    1586             :         }
    1587             : 
    1588             : #ifdef HAVE_SPOTLIGHT_BACKEND_ES
    1589           8 :         ok = mdsscv_backend_es.shutdown(mdssvc_ctx);
    1590           8 :         if (!ok) {
    1591           0 :                 goto fail;
    1592             :         }
    1593             : #endif
    1594             : 
    1595             : #ifdef HAVE_SPOTLIGHT_BACKEND_TRACKER
    1596             :         ok = mdsscv_backend_tracker.shutdown(mdssvc_ctx);
    1597             :         if (!ok) {
    1598             :                 goto fail;
    1599             :         }
    1600             : #endif
    1601             : 
    1602           8 :         ok = true;
    1603           8 : fail:
    1604           8 :         TALLOC_FREE(mdssvc_ctx);
    1605           8 :         return ok;
    1606             : }
    1607             : 
    1608             : /**
    1609             :  * Tear down connections and free all resources
    1610             :  **/
    1611          22 : static int mds_ctx_destructor_cb(struct mds_ctx *mds_ctx)
    1612             : {
    1613             :         /*
    1614             :          * We need to free query_list before ino_path_map
    1615             :          */
    1616          22 :         while (mds_ctx->query_list != NULL) {
    1617             :                 /*
    1618             :                  * slq destructor removes element from list.
    1619             :                  * Don't use TALLOC_FREE()!
    1620             :                  */
    1621           0 :                 talloc_free(mds_ctx->query_list);
    1622             :         }
    1623          22 :         TALLOC_FREE(mds_ctx->ino_path_map);
    1624             : 
    1625          22 :         if (mds_ctx->conn != NULL) {
    1626          22 :                 SMB_VFS_DISCONNECT(mds_ctx->conn);
    1627          22 :                 conn_free(mds_ctx->conn);
    1628             :         }
    1629             : 
    1630          22 :         ZERO_STRUCTP(mds_ctx);
    1631             : 
    1632          22 :         return 0;
    1633             : }
    1634             : 
    1635             : /**
    1636             :  * Initialise a context per RPC bind
    1637             :  *
    1638             :  * This ends up being called for every tcon, because the client does a
    1639             :  * RPC bind for every tcon, so this is actually a per tcon context.
    1640             :  **/
    1641          25 : NTSTATUS mds_init_ctx(TALLOC_CTX *mem_ctx,
    1642             :                       struct tevent_context *ev,
    1643             :                       struct messaging_context *msg_ctx,
    1644             :                       struct auth_session_info *session_info,
    1645             :                       int snum,
    1646             :                       const char *sharename,
    1647             :                       const char *path,
    1648             :                       struct mds_ctx **_mds_ctx)
    1649             : {
    1650             :         const struct loadparm_substitution *lp_sub =
    1651          25 :                 loadparm_s3_global_substitution();
    1652             :         struct smb_filename conn_basedir;
    1653             :         struct mds_ctx *mds_ctx;
    1654             :         int backend;
    1655             :         int ret;
    1656             :         bool ok;
    1657          25 :         smb_iconv_t iconv_hnd = (smb_iconv_t)-1;
    1658             :         NTSTATUS status;
    1659             : 
    1660          25 :         if (!lp_spotlight(snum)) {
    1661           3 :                 return NT_STATUS_WRONG_VOLUME;
    1662             :         }
    1663             : 
    1664          22 :         mds_ctx = talloc_zero(mem_ctx, struct mds_ctx);
    1665          22 :         if (mds_ctx == NULL) {
    1666           0 :                 return NT_STATUS_NO_MEMORY;
    1667             :         }
    1668          22 :         talloc_set_destructor(mds_ctx, mds_ctx_destructor_cb);
    1669             : 
    1670          22 :         mds_ctx->mdssvc_ctx = mdssvc_init(ev);
    1671          22 :         if (mds_ctx->mdssvc_ctx == NULL) {
    1672           0 :                 return NT_STATUS_NO_MEMORY;
    1673             :         }
    1674             : 
    1675          22 :         backend = lp_spotlight_backend(snum);
    1676          22 :         switch (backend) {
    1677           0 :         case SPOTLIGHT_BACKEND_NOINDEX:
    1678           0 :                 mds_ctx->backend = &mdsscv_backend_noindex;
    1679           0 :                 break;
    1680             : 
    1681             : #ifdef HAVE_SPOTLIGHT_BACKEND_ES
    1682          22 :         case SPOTLIGHT_BACKEND_ES:
    1683          22 :                 mds_ctx->backend = &mdsscv_backend_es;
    1684          22 :                 break;
    1685             : #endif
    1686             : 
    1687             : #ifdef HAVE_SPOTLIGHT_BACKEND_TRACKER
    1688             :         case SPOTLIGHT_BACKEND_TRACKER:
    1689             :                 mds_ctx->backend = &mdsscv_backend_tracker;
    1690             :                 break;
    1691             : #endif
    1692           0 :         default:
    1693           0 :                 DBG_ERR("Unknown backend %d\n", backend);
    1694           0 :                 TALLOC_FREE(mdssvc_ctx);
    1695           0 :                 status = NT_STATUS_INTERNAL_ERROR;
    1696           0 :                 goto error;
    1697             :         }
    1698             : 
    1699          22 :         iconv_hnd = smb_iconv_open_ex(mds_ctx,
    1700             :                                       "UTF8-NFD",
    1701             :                                       "UTF8-NFC",
    1702             :                                       false);
    1703          22 :         if (iconv_hnd == (smb_iconv_t)-1) {
    1704           0 :                 status = NT_STATUS_INTERNAL_ERROR;
    1705           0 :                 goto error;
    1706             :         }
    1707          22 :         mds_ctx->ic_nfc_to_nfd = iconv_hnd;
    1708             : 
    1709          22 :         iconv_hnd = smb_iconv_open_ex(mds_ctx,
    1710             :                                       "UTF8-NFC",
    1711             :                                       "UTF8-NFD",
    1712             :                                       false);
    1713          22 :         if (iconv_hnd == (smb_iconv_t)-1) {
    1714           0 :                 status = NT_STATUS_INTERNAL_ERROR;
    1715           0 :                 goto error;
    1716             :         }
    1717          22 :         mds_ctx->ic_nfd_to_nfc = iconv_hnd;
    1718             : 
    1719          22 :         mds_ctx->sharename = talloc_strdup(mds_ctx, sharename);
    1720          22 :         if (mds_ctx->sharename == NULL) {
    1721           0 :                 status = NT_STATUS_NO_MEMORY;
    1722           0 :                 goto error;
    1723             :         }
    1724             : 
    1725          22 :         mds_ctx->spath = talloc_strdup(mds_ctx, path);
    1726          22 :         if (mds_ctx->spath == NULL) {
    1727           0 :                 status = NT_STATUS_NO_MEMORY;
    1728           0 :                 goto error;
    1729             :         }
    1730          22 :         mds_ctx->spath_len = strlen(path);
    1731             : 
    1732          22 :         mds_ctx->snum = snum;
    1733          22 :         mds_ctx->pipe_session_info = session_info;
    1734             : 
    1735          22 :         if (session_info->security_token->num_sids < 1) {
    1736           0 :                 status = NT_STATUS_BAD_LOGON_SESSION_STATE;
    1737           0 :                 goto error;
    1738             :         }
    1739          22 :         sid_copy(&mds_ctx->sid, &session_info->security_token->sids[0]);
    1740          22 :         mds_ctx->uid = session_info->unix_token->uid;
    1741             : 
    1742          22 :         mds_ctx->ino_path_map = db_open_rbt(mds_ctx);
    1743          22 :         if (mds_ctx->ino_path_map == NULL) {
    1744           0 :                 DEBUG(1,("open inode map db failed\n"));
    1745           0 :                 status = NT_STATUS_INTERNAL_ERROR;
    1746           0 :                 goto error;
    1747             :         }
    1748             : 
    1749          22 :         status = create_conn_struct_cwd(mds_ctx,
    1750             :                                         ev,
    1751             :                                         msg_ctx,
    1752             :                                         session_info,
    1753             :                                         snum,
    1754          22 :                                         lp_path(talloc_tos(), lp_sub, snum),
    1755             :                                         &mds_ctx->conn);
    1756          22 :         if (!NT_STATUS_IS_OK(status)) {
    1757           0 :                 DBG_ERR("failed to create conn for vfs: %s\n",
    1758             :                         nt_errstr(status));
    1759           0 :                 goto error;
    1760             :         }
    1761             : 
    1762          22 :         conn_basedir = (struct smb_filename) {
    1763          22 :                 .base_name = mds_ctx->conn->connectpath,
    1764             :         };
    1765             : 
    1766          22 :         ret = vfs_ChDir(mds_ctx->conn, &conn_basedir);
    1767          22 :         if (ret != 0) {
    1768           0 :                 DBG_ERR("vfs_ChDir [%s] failed: %s\n",
    1769             :                         conn_basedir.base_name, strerror(errno));
    1770           0 :                 status = map_nt_error_from_unix(errno);
    1771           0 :                 goto error;
    1772             :         }
    1773             : 
    1774          22 :         ok = mds_ctx->backend->connect(mds_ctx);
    1775          22 :         if (!ok) {
    1776           0 :                 DBG_ERR("backend connect failed\n");
    1777           0 :                 status = NT_STATUS_CONNECTION_RESET;
    1778           0 :                 goto error;
    1779             :         }
    1780             : 
    1781          22 :         *_mds_ctx = mds_ctx;
    1782          22 :         return NT_STATUS_OK;
    1783             : 
    1784           0 : error:
    1785           0 :         if (mds_ctx->ic_nfc_to_nfd != NULL) {
    1786           0 :                 smb_iconv_close(mds_ctx->ic_nfc_to_nfd);
    1787             :         }
    1788           0 :         if (mds_ctx->ic_nfd_to_nfc != NULL) {
    1789           0 :                 smb_iconv_close(mds_ctx->ic_nfd_to_nfc);
    1790             :         }
    1791             : 
    1792           0 :         TALLOC_FREE(mds_ctx);
    1793           0 :         return status;
    1794             : }
    1795             : 
    1796             : /**
    1797             :  * Dispatch a Spotlight RPC command
    1798             :  **/
    1799          51 : bool mds_dispatch(struct mds_ctx *mds_ctx,
    1800             :                   struct mdssvc_blob *request_blob,
    1801             :                   struct mdssvc_blob *response_blob,
    1802             :                   size_t max_fragment_size)
    1803             : {
    1804             :         bool ok;
    1805             :         int ret;
    1806          51 :         DALLOC_CTX *query = NULL;
    1807          51 :         DALLOC_CTX *reply = NULL;
    1808             :         char *rpccmd;
    1809             :         const struct slrpc_cmd *slcmd;
    1810          51 :         const struct smb_filename conn_basedir = {
    1811          51 :                 .base_name = mds_ctx->conn->connectpath,
    1812             :         };
    1813             :         NTSTATUS status;
    1814             : 
    1815          51 :         if (CHECK_DEBUGLVL(10)) {
    1816             :                 const struct sl_query *slq;
    1817             : 
    1818           0 :                 for (slq = mds_ctx->query_list; slq != NULL; slq = slq->next) {
    1819           0 :                         SLQ_DEBUG(10, slq, "pending");
    1820             :                 }
    1821             :         }
    1822             : 
    1823          51 :         response_blob->length = 0;
    1824             : 
    1825          51 :         DEBUG(10, ("share path: %s\n", mds_ctx->spath));
    1826             : 
    1827          51 :         query = dalloc_new(mds_ctx);
    1828          51 :         if (query == NULL) {
    1829           0 :                 ok = false;
    1830           0 :                 goto cleanup;
    1831             :         }
    1832          51 :         reply = dalloc_new(mds_ctx);
    1833          51 :         if (reply == NULL) {
    1834           0 :                 ok = false;
    1835           0 :                 goto cleanup;
    1836             :         }
    1837             : 
    1838          51 :         ok = sl_unpack(query, (char *)request_blob->spotlight_blob,
    1839          51 :                        request_blob->length);
    1840          51 :         if (!ok) {
    1841           3 :                 DEBUG(1, ("error unpacking Spotlight RPC blob\n"));
    1842           3 :                 goto cleanup;
    1843             :         }
    1844             : 
    1845          48 :         DEBUG(5, ("%s", dalloc_dump(query, 0)));
    1846             : 
    1847          48 :         rpccmd = dalloc_get(query, "DALLOC_CTX", 0, "DALLOC_CTX", 0,
    1848             :                             "char *", 0);
    1849          48 :         if (rpccmd == NULL) {
    1850           0 :                 DEBUG(1, ("missing primary Spotlight RPC command\n"));
    1851           0 :                 ok = false;
    1852           0 :                 goto cleanup;
    1853             :         }
    1854             : 
    1855          48 :         DEBUG(10, ("Spotlight RPC cmd: %s\n", rpccmd));
    1856             : 
    1857          48 :         slcmd = slrpc_cmd_by_name(rpccmd);
    1858          48 :         if (slcmd == NULL) {
    1859           0 :                 DEBUG(1, ("unsupported primary Spotlight RPC command %s\n",
    1860             :                           rpccmd));
    1861           0 :                 ok = false;
    1862           0 :                 goto cleanup;
    1863             :         }
    1864             : 
    1865          48 :         ret = vfs_ChDir(mds_ctx->conn, &conn_basedir);
    1866          48 :         if (ret != 0) {
    1867           0 :                 DBG_ERR("vfs_ChDir [%s] failed: %s\n",
    1868             :                         conn_basedir.base_name, strerror(errno));
    1869           0 :                 ok = false;
    1870           0 :                 goto cleanup;
    1871             :         }
    1872             : 
    1873          48 :         ok = slcmd->function(mds_ctx, query, reply);
    1874          48 :         if (!ok) {
    1875           0 :                 goto cleanup;
    1876             :         }
    1877             : 
    1878          48 :         DBG_DEBUG("%s", dalloc_dump(reply, 0));
    1879             : 
    1880          48 :         status = sl_pack_alloc(response_blob,
    1881             :                                reply,
    1882             :                                response_blob,
    1883             :                                max_fragment_size);
    1884          48 :         if (!NT_STATUS_IS_OK(status)) {
    1885           0 :                 DBG_ERR("sl_pack_alloc() failed\n");
    1886           0 :                 goto cleanup;
    1887             :         }
    1888             : 
    1889          48 : cleanup:
    1890          51 :         talloc_free(query);
    1891          51 :         talloc_free(reply);
    1892          51 :         return ok;
    1893             : }

Generated by: LCOV version 1.14