2014-07-23 09:58:45 +02:00
/*
Unix SMB / CIFS implementation .
Main metadata server / Spotlight routines
Copyright ( C ) Ralph Boehme 2012 - 2014
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 3 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program . If not , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
2021-05-10 12:10:08 +02:00
# include "smbd/proto.h"
2015-03-26 22:39:21 +01:00
# include "librpc/gen_ndr/auth.h"
# include "dbwrap/dbwrap.h"
# include "lib/util/dlinklist.h"
# include "lib/util/util_tdb.h"
# include "lib/util/time_basic.h"
# include "lib/dbwrap/dbwrap_rbt.h"
# include "libcli/security/dom_sid.h"
2021-05-10 12:34:32 +02:00
# include "libcli/security/security.h"
2014-07-23 09:58:45 +02:00
# include "mdssvc.h"
2019-04-17 11:00:52 +02:00
# include "mdssvc_noindex.h"
2019-05-06 15:03:02 +02:00
# ifdef HAVE_SPOTLIGHT_BACKEND_TRACKER
2019-03-14 07:38:20 +01:00
# include "mdssvc_tracker.h"
2019-05-06 15:03:02 +02:00
# endif
2019-08-05 16:25:01 +02:00
# ifdef HAVE_SPOTLIGHT_BACKEND_ES
# include "mdssvc_es.h"
# endif
2021-01-03 21:53:49 +01:00
# include "lib/global_contexts.h"
2014-07-23 09:58:45 +02:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_RPC_SRV
2015-03-26 22:39:21 +01:00
struct slrpc_cmd {
const char * name ;
bool ( * function ) ( struct mds_ctx * mds_ctx ,
const DALLOC_CTX * query ,
DALLOC_CTX * reply ) ;
} ;
struct slq_destroy_state {
struct tevent_context * ev ;
struct sl_query * slq ;
} ;
2016-01-27 13:23:51 +01:00
/*
* This is a static global because we may be called multiple times and
* we only want one mdssvc_ctx per connection to Tracker .
*
* The client will bind multiple times to the mdssvc RPC service , once
* for every tree connect .
*/
static struct mdssvc_ctx * mdssvc_ctx = NULL ;
2015-03-26 22:39:21 +01:00
/*
* If these functions return an error , they hit something like a non
* recoverable talloc error . Most errors are dealt with by returning
2017-02-18 08:52:09 +13:00
* an error code in the Spotlight RPC reply .
2015-03-26 22:39:21 +01:00
*/
static bool slrpc_fetch_properties ( struct mds_ctx * mds_ctx ,
const DALLOC_CTX * query , DALLOC_CTX * reply ) ;
static bool slrpc_open_query ( struct mds_ctx * mds_ctx ,
const DALLOC_CTX * query , DALLOC_CTX * reply ) ;
static bool slrpc_fetch_query_results ( struct mds_ctx * mds_ctx ,
const DALLOC_CTX * query , DALLOC_CTX * reply ) ;
static bool slrpc_store_attributes ( struct mds_ctx * mds_ctx ,
const DALLOC_CTX * query , DALLOC_CTX * reply ) ;
static bool slrpc_fetch_attributenames ( struct mds_ctx * mds_ctx ,
const DALLOC_CTX * query , DALLOC_CTX * reply ) ;
static bool slrpc_fetch_attributes ( struct mds_ctx * mds_ctx ,
const DALLOC_CTX * query , DALLOC_CTX * reply ) ;
static bool slrpc_close_query ( struct mds_ctx * mds_ctx ,
const DALLOC_CTX * query , DALLOC_CTX * reply ) ;
/************************************************
* Misc utility functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/**
* Add requested metadata for a query result element
*
* This could be rewritten to something more sophisticated like
* querying metadata from Tracker .
*
* If path or sp is NULL , simply add nil values for all attributes .
* */
2019-04-09 11:19:43 +02:00
static bool add_filemeta ( struct mds_ctx * mds_ctx ,
sl_array_t * reqinfo ,
2015-03-26 22:39:21 +01:00
sl_array_t * fm_array ,
const char * path ,
const struct stat_ex * sp )
{
sl_array_t * meta ;
sl_nil_t nil ;
int i , metacount , result ;
uint64_t uint64var ;
sl_time_t sl_time ;
char * p ;
const char * attribute ;
2019-04-09 11:19:43 +02:00
size_t nfc_len ;
const char * nfc_path = path ;
size_t nfd_buf_size ;
char * nfd_path = NULL ;
char * dest = NULL ;
size_t dest_remaining ;
size_t nconv ;
2015-03-26 22:39:21 +01:00
metacount = dalloc_size ( reqinfo ) ;
if ( metacount = = 0 | | path = = NULL | | sp = = NULL ) {
result = dalloc_add_copy ( fm_array , & nil , sl_nil_t ) ;
if ( result ! = 0 ) {
return false ;
}
return true ;
}
meta = dalloc_zero ( fm_array , sl_array_t ) ;
if ( meta = = NULL ) {
return false ;
}
2019-04-09 11:19:43 +02:00
nfc_len = strlen ( nfc_path ) ;
/*
* Simple heuristic , strlen by two should give enough room for NFC to
* NFD conversion .
*/
nfd_buf_size = nfc_len * 2 ;
nfd_path = talloc_array ( meta , char , nfd_buf_size ) ;
if ( nfd_path = = NULL ) {
return false ;
}
dest = nfd_path ;
dest_remaining = talloc_array_length ( dest ) ;
nconv = smb_iconv ( mds_ctx - > ic_nfc_to_nfd ,
& nfc_path ,
& nfc_len ,
& dest ,
& dest_remaining ) ;
if ( nconv = = ( size_t ) - 1 ) {
return false ;
}
2015-03-26 22:39:21 +01:00
for ( i = 0 ; i < metacount ; i + + ) {
attribute = dalloc_get_object ( reqinfo , i ) ;
2015-07-09 19:24:18 +02:00
if ( attribute = = NULL ) {
return false ;
}
2015-03-26 22:39:21 +01:00
if ( strcmp ( attribute , " kMDItemDisplayName " ) = = 0
| | strcmp ( attribute , " kMDItemFSName " ) = = 0 ) {
2019-04-09 11:19:43 +02:00
p = strrchr ( nfd_path , ' / ' ) ;
2015-03-26 22:39:21 +01:00
if ( p ) {
result = dalloc_stradd ( meta , p + 1 ) ;
if ( result ! = 0 ) {
return false ;
}
}
} else if ( strcmp ( attribute , " kMDItemPath " ) = = 0 ) {
2019-04-09 11:19:43 +02:00
result = dalloc_stradd ( meta , nfd_path ) ;
2015-03-26 22:39:21 +01:00
if ( result ! = 0 ) {
return false ;
}
} else if ( strcmp ( attribute , " kMDItemFSSize " ) = = 0 ) {
uint64var = sp - > st_ex_size ;
result = dalloc_add_copy ( meta , & uint64var , uint64_t ) ;
if ( result ! = 0 ) {
return false ;
}
} else if ( strcmp ( attribute , " kMDItemFSOwnerUserID " ) = = 0 ) {
uint64var = sp - > st_ex_uid ;
result = dalloc_add_copy ( meta , & uint64var , uint64_t ) ;
if ( result ! = 0 ) {
return false ;
}
} else if ( strcmp ( attribute , " kMDItemFSOwnerGroupID " ) = = 0 ) {
uint64var = sp - > st_ex_gid ;
result = dalloc_add_copy ( meta , & uint64var , uint64_t ) ;
if ( result ! = 0 ) {
return false ;
}
} else if ( strcmp ( attribute , " kMDItemFSContentChangeDate " ) = = 0 ) {
sl_time . tv_sec = sp - > st_ex_mtime . tv_sec ;
result = dalloc_add_copy ( meta , & sl_time , sl_time_t ) ;
if ( result ! = 0 ) {
return false ;
}
} else {
result = dalloc_add_copy ( meta , & nil , sl_nil_t ) ;
if ( result ! = 0 ) {
return false ;
}
}
}
result = dalloc_add ( fm_array , meta , sl_array_t ) ;
if ( result ! = 0 ) {
return false ;
}
return true ;
}
static int cnid_comp_fn ( const void * p1 , const void * p2 )
{
const uint64_t * cnid1 = p1 , * cnid2 = p2 ;
if ( * cnid1 = = * cnid2 ) {
return 0 ;
}
if ( * cnid1 < * cnid2 ) {
return - 1 ;
}
return 1 ;
}
/**
* Create a sorted copy of a CNID array
* */
static bool sort_cnids ( struct sl_query * slq , const DALLOC_CTX * d )
{
uint64_t * cnids = NULL ;
int i ;
const void * p ;
cnids = talloc_array ( slq , uint64_t , dalloc_size ( d ) ) ;
if ( cnids = = NULL ) {
return false ;
}
for ( i = 0 ; i < dalloc_size ( d ) ; i + + ) {
p = dalloc_get_object ( d , i ) ;
if ( p = = NULL ) {
return NULL ;
}
memcpy ( & cnids [ i ] , p , sizeof ( uint64_t ) ) ;
}
qsort ( cnids , dalloc_size ( d ) , sizeof ( uint64_t ) , cnid_comp_fn ) ;
slq - > cnids = cnids ;
slq - > cnids_num = dalloc_size ( d ) ;
return true ;
}
/**
* Allocate result handle used in the async Tracker cursor result
* handler for storing results
* */
static bool create_result_handle ( struct sl_query * slq )
{
sl_nil_t nil = 0 ;
struct sl_rslts * query_results ;
int result ;
if ( slq - > query_results ) {
DEBUG ( 1 , ( " unexpected existing result handle \n " ) ) ;
return false ;
}
query_results = talloc_zero ( slq , struct sl_rslts ) ;
if ( query_results = = NULL ) {
return false ;
}
/* CNIDs */
query_results - > cnids = talloc_zero ( query_results , sl_cnids_t ) ;
if ( query_results - > cnids = = NULL ) {
return false ;
}
query_results - > cnids - > ca_cnids = dalloc_new ( query_results - > cnids ) ;
if ( query_results - > cnids - > ca_cnids = = NULL ) {
return false ;
}
query_results - > cnids - > ca_unkn1 = 0xadd ;
if ( slq - > ctx2 > UINT32_MAX ) {
DEBUG ( 1 , ( " 64bit ctx2 id too large: 0x%jx " , ( uintmax_t ) slq - > ctx2 ) ) ;
return false ;
}
query_results - > cnids - > ca_context = ( uint32_t ) slq - > ctx2 ;
/* FileMeta */
query_results - > fm_array = dalloc_zero ( query_results , sl_array_t ) ;
if ( query_results - > fm_array = = NULL ) {
return false ;
}
/* For some reason the list of results always starts with a nil entry */
result = dalloc_add_copy ( query_results - > fm_array , & nil , sl_nil_t ) ;
if ( result ! = 0 ) {
return false ;
}
slq - > query_results = query_results ;
return true ;
}
static bool add_results ( sl_array_t * array , struct sl_query * slq )
{
sl_filemeta_t * fm ;
uint64_t status = 0 ;
int result ;
bool ok ;
/* FileMeta */
fm = dalloc_zero ( array , sl_filemeta_t ) ;
if ( fm = = NULL ) {
return false ;
}
result = dalloc_add_copy ( array , & status , uint64_t ) ;
if ( result ! = 0 ) {
return false ;
}
result = dalloc_add ( array , slq - > query_results - > cnids , sl_cnids_t ) ;
if ( result ! = 0 ) {
return false ;
}
if ( slq - > query_results - > num_results > 0 ) {
result = dalloc_add ( fm , slq - > query_results - > fm_array , sl_array_t ) ;
if ( result ! = 0 ) {
return false ;
}
}
result = dalloc_add ( array , fm , sl_filemeta_t ) ;
if ( result ! = 0 ) {
return false ;
}
/* This ensure the results get clean up after been sent to the client */
talloc_move ( array , & slq - > query_results ) ;
ok = create_result_handle ( slq ) ;
if ( ! ok ) {
DEBUG ( 1 , ( " couldn't add result handle \n " ) ) ;
slq - > state = SLQ_STATE_ERROR ;
return false ;
}
return true ;
}
static const struct slrpc_cmd * slrpc_cmd_by_name ( const char * rpccmd )
{
size_t i ;
static const struct slrpc_cmd cmds [ ] = {
{ " fetchPropertiesForContext: " , slrpc_fetch_properties } ,
{ " openQueryWithParams:forContext: " , slrpc_open_query } ,
{ " fetchQueryResultsForContext: " , slrpc_fetch_query_results } ,
{ " storeAttributes:forOIDArray:context: " , slrpc_store_attributes } ,
{ " fetchAttributeNamesForOIDArray:context: " , slrpc_fetch_attributenames } ,
{ " fetchAttributes:forOIDArray:context: " , slrpc_fetch_attributes } ,
{ " fetchAllAttributes:forOIDArray:context: " , slrpc_fetch_attributes } ,
{ " closeQueryForContext: " , slrpc_close_query } ,
} ;
for ( i = 0 ; i < ARRAY_SIZE ( cmds ) ; i + + ) {
int cmp ;
cmp = strcmp ( cmds [ i ] . name , rpccmd ) ;
if ( cmp = = 0 ) {
return & cmds [ i ] ;
}
}
return NULL ;
}
/**
* Search the list of active queries given their context ids
* */
static struct sl_query * slq_for_ctx ( struct mds_ctx * mds_ctx ,
uint64_t ctx1 , uint64_t ctx2 )
{
struct sl_query * q ;
for ( q = mds_ctx - > query_list ; q ; q = q - > next ) {
if ( ( q - > ctx1 = = ctx1 ) & & ( q - > ctx2 = = ctx2 ) ) {
return q ;
}
}
return NULL ;
}
static int slq_destructor_cb ( struct sl_query * slq )
{
SLQ_DEBUG ( 10 , slq , " destroying " ) ;
/* Free all entries before freeing the slq handle! */
TALLOC_FREE ( slq - > entries_ctx ) ;
TALLOC_FREE ( slq - > te ) ;
if ( slq - > mds_ctx ! = NULL ) {
DLIST_REMOVE ( slq - > mds_ctx - > query_list , slq ) ;
slq - > mds_ctx = NULL ;
}
2019-03-14 07:38:20 +01:00
TALLOC_FREE ( slq - > backend_private ) ;
2015-03-26 22:39:21 +01:00
return 0 ;
}
/**
* Remove talloc_refcounted entry from mapping db
*
* Multiple queries ( via the slq handle ) may reference a
* sl_inode_path_map entry , when the last reference goes away as the
* queries are closed and this gets called to remove the entry from
* the db .
* */
static int ino_path_map_destr_cb ( struct sl_inode_path_map * entry )
2014-07-23 09:58:45 +02:00
{
2015-03-26 22:39:21 +01:00
NTSTATUS status ;
TDB_DATA key ;
key = make_tdb_data ( ( uint8_t * ) & entry - > ino , sizeof ( entry - > ino ) ) ;
status = dbwrap_delete ( entry - > mds_ctx - > ino_path_map , key ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Failed to delete record: %s \n " , nt_errstr ( status ) ) ) ;
return - 1 ;
}
2019-04-16 11:24:02 +02:00
DBG_DEBUG ( " deleted [0x% " PRIx64 " ] [%s] \n " , entry - > ino , entry - > path ) ;
2014-07-23 09:58:45 +02:00
return 0 ;
}
2015-03-26 22:39:21 +01:00
/**
* Add result to inode - > path mapping dbwrap rbt db
*
* This is necessary as a CNID db substitute , ie we need a way to
* simulate unique , constant numerical identifiers for paths with an
* API that supports mapping from id to path .
*
* Entries are talloc ' ed of the query , using talloc_reference ( ) if
* multiple queries returned the same result . That way we can cleanup
* entries by calling talloc_free ( ) on the query slq handles .
* */
static bool inode_map_add ( struct sl_query * slq , uint64_t ino , const char * path )
{
NTSTATUS status ;
struct sl_inode_path_map * entry ;
TDB_DATA key , value ;
void * p ;
key = make_tdb_data ( ( uint8_t * ) & ino , sizeof ( ino ) ) ;
status = dbwrap_fetch ( slq - > mds_ctx - > ino_path_map , slq , key , & value ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
/*
* We have one db , so when different parallel queries
* return the same file , we have to refcount entries
* in the db .
*/
if ( value . dsize ! = sizeof ( void * ) ) {
2022-04-01 10:07:47 +03:00
DEBUG ( 1 , ( " invalid dsize \n " ) ) ;
2015-03-26 22:39:21 +01:00
return false ;
}
memcpy ( & p , value . dptr , sizeof ( p ) ) ;
entry = talloc_get_type_abort ( p , struct sl_inode_path_map ) ;
DEBUG ( 10 , ( " map: %s \n " , entry - > path ) ) ;
entry = talloc_reference ( slq - > entries_ctx , entry ) ;
if ( entry = = NULL ) {
DEBUG ( 1 , ( " talloc_reference failed \n " ) ) ;
return false ;
}
return true ;
}
if ( ! NT_STATUS_EQUAL ( status , NT_STATUS_NOT_FOUND ) ) {
DEBUG ( 1 , ( " dbwrap_fetch failed %s \n " , nt_errstr ( status ) ) ) ;
return false ;
}
entry = talloc_zero ( slq - > entries_ctx , struct sl_inode_path_map ) ;
if ( entry = = NULL ) {
DEBUG ( 1 , ( " talloc failed \n " ) ) ;
return false ;
}
entry - > ino = ino ;
entry - > mds_ctx = slq - > mds_ctx ;
entry - > path = talloc_strdup ( entry , path ) ;
if ( entry - > path = = NULL ) {
DEBUG ( 1 , ( " talloc failed \n " ) ) ;
TALLOC_FREE ( entry ) ;
return false ;
}
status = dbwrap_store ( slq - > mds_ctx - > ino_path_map , key ,
make_tdb_data ( ( void * ) & entry , sizeof ( void * ) ) , 0 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " Failed to store record: %s \n " , nt_errstr ( status ) ) ) ;
TALLOC_FREE ( entry ) ;
return false ;
}
talloc_set_destructor ( entry , ino_path_map_destr_cb ) ;
return true ;
}
2019-03-14 07:38:20 +01:00
bool mds_add_result ( struct sl_query * slq , const char * path )
2015-03-26 22:39:21 +01:00
{
2021-05-10 12:34:32 +02:00
struct smb_filename * smb_fname = NULL ;
2015-03-26 22:39:21 +01:00
struct stat_ex sb ;
uint64_t ino64 ;
2019-03-14 07:38:20 +01:00
int result ;
2021-05-10 12:34:32 +02:00
NTSTATUS status ;
2015-03-26 22:39:21 +01:00
bool ok ;
2019-03-11 18:11:04 +01:00
/*
* We ' re in a tevent callback which means in the case of
* running as external RPC service we ' re running as root and
* not as the user .
*/
if ( ! become_authenticated_pipe_user ( slq - > mds_ctx - > pipe_session_info ) ) {
2019-08-07 11:55:44 +02:00
DBG_ERR ( " can't become authenticated user: %d \n " ,
slq - > mds_ctx - > uid ) ;
2019-03-11 18:11:04 +01:00
smb_panic ( " can't become authenticated user " ) ;
}
2015-03-26 22:39:21 +01:00
if ( geteuid ( ) ! = slq - > mds_ctx - > uid ) {
2019-08-07 11:55:44 +02:00
DBG_ERR ( " uid mismatch: %d/%d \n " , geteuid ( ) , slq - > mds_ctx - > uid ) ;
2015-03-26 22:39:21 +01:00
smb_panic ( " uid mismatch " ) ;
}
2019-03-11 18:11:04 +01:00
/*
* We ' ve changed identity to the authenticated pipe user , so
* any function exit below must ensure we switch back
*/
2021-05-10 12:34:32 +02:00
status = synthetic_pathref ( talloc_tos ( ) ,
slq - > mds_ctx - > conn - > cwd_fsp ,
path ,
NULL ,
NULL ,
0 ,
0 ,
& smb_fname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_DEBUG ( " synthetic_pathref [%s]: %s \n " ,
smb_fname_str_dbg ( smb_fname ) ,
nt_errstr ( status ) ) ;
2019-03-11 18:11:04 +01:00
unbecome_authenticated_pipe_user ( ) ;
2019-03-14 07:38:20 +01:00
return true ;
2015-03-26 22:39:21 +01:00
}
2021-05-10 12:34:32 +02:00
2022-03-28 11:48:37 +02:00
sb = smb_fname - > st ;
2021-05-10 12:34:32 +02:00
status = smbd_check_access_rights_fsp ( slq - > mds_ctx - > conn - > cwd_fsp ,
smb_fname - > fsp ,
false ,
FILE_READ_DATA ) ;
2022-03-28 11:48:37 +02:00
unbecome_authenticated_pipe_user ( ) ;
2021-05-10 12:34:32 +02:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
TALLOC_FREE ( smb_fname ) ;
2019-03-14 07:38:20 +01:00
return true ;
2015-03-26 22:39:21 +01:00
}
2021-05-10 12:34:32 +02:00
/* Done with smb_fname now. */
TALLOC_FREE ( smb_fname ) ;
2022-03-28 11:48:37 +02:00
2021-05-10 12:34:32 +02:00
ino64 = SMB_VFS_FS_FILE_ID ( slq - > mds_ctx - > conn , & sb ) ;
2015-03-26 22:39:21 +01:00
if ( slq - > cnids ) {
2021-05-10 11:04:38 +02:00
bool found ;
2015-03-26 22:39:21 +01:00
/*
* Check whether the found element is in the requested
* set of IDs . Note that we ' re faking CNIDs by using
* filesystem inode numbers here
*/
2021-05-10 11:04:38 +02:00
found = bsearch ( & ino64 ,
slq - > cnids ,
slq - > cnids_num ,
sizeof ( uint64_t ) ,
cnid_comp_fn ) ;
if ( ! found ) {
2021-05-10 11:07:27 +02:00
return true ;
2015-03-26 22:39:21 +01:00
}
}
/*
* Add inode number and filemeta to result set , this is what
* we return as part of the result set of a query
*/
result = dalloc_add_copy ( slq - > query_results - > cnids - > ca_cnids ,
2019-08-07 11:55:44 +02:00
& ino64 ,
uint64_t ) ;
2015-03-26 22:39:21 +01:00
if ( result ! = 0 ) {
2019-08-07 11:55:44 +02:00
DBG_ERR ( " dalloc error \n " ) ;
2015-03-26 22:39:21 +01:00
slq - > state = SLQ_STATE_ERROR ;
2019-03-14 07:38:20 +01:00
return false ;
2015-03-26 22:39:21 +01:00
}
2019-04-09 11:19:43 +02:00
ok = add_filemeta ( slq - > mds_ctx ,
slq - > reqinfo ,
2019-08-07 11:55:44 +02:00
slq - > query_results - > fm_array ,
path ,
& sb ) ;
2015-03-26 22:39:21 +01:00
if ( ! ok ) {
2019-08-07 11:55:44 +02:00
DBG_ERR ( " add_filemeta error \n " ) ;
2015-03-26 22:39:21 +01:00
slq - > state = SLQ_STATE_ERROR ;
2019-03-14 07:38:20 +01:00
return false ;
2015-03-26 22:39:21 +01:00
}
ok = inode_map_add ( slq , ino64 , path ) ;
if ( ! ok ) {
DEBUG ( 1 , ( " inode_map_add error \n " ) ) ;
slq - > state = SLQ_STATE_ERROR ;
2019-03-14 07:38:20 +01:00
return false ;
2015-03-26 22:39:21 +01:00
}
slq - > query_results - > num_results + + ;
2019-03-14 07:38:20 +01:00
return true ;
2015-03-26 22:39:21 +01:00
}
/***********************************************************
* Spotlight RPC functions
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static bool slrpc_fetch_properties ( struct mds_ctx * mds_ctx ,
const DALLOC_CTX * query , DALLOC_CTX * reply )
{
sl_dict_t * dict ;
sl_array_t * array ;
char * s ;
uint64_t u ;
sl_bool_t b ;
sl_uuid_t uuid ;
int result ;
dict = dalloc_zero ( reply , sl_dict_t ) ;
if ( dict = = NULL ) {
return false ;
}
/* kMDSStoreHasPersistentUUID = false */
result = dalloc_stradd ( dict , " kMDSStoreHasPersistentUUID " ) ;
if ( result ! = 0 ) {
return false ;
}
b = false ;
result = dalloc_add_copy ( dict , & b , sl_bool_t ) ;
if ( result ! = 0 ) {
return false ;
}
/* kMDSStoreIsBackup = false */
result = dalloc_stradd ( dict , " kMDSStoreIsBackup " ) ;
if ( result ! = 0 ) {
return false ;
}
b = false ;
result = dalloc_add_copy ( dict , & b , sl_bool_t ) ;
if ( result ! = 0 ) {
return false ;
}
/* kMDSStoreUUID = uuid */
result = dalloc_stradd ( dict , " kMDSStoreUUID " ) ;
if ( result ! = 0 ) {
return false ;
}
memcpy ( uuid . sl_uuid , " fakeuuidfakeuuid " , sizeof ( uuid . sl_uuid ) ) ;
result = dalloc_add_copy ( dict , & uuid , sl_uuid_t ) ;
if ( result ! = 0 ) {
return false ;
}
/* kMDSStoreSupportsVolFS = true */
result = dalloc_stradd ( dict , " kMDSStoreSupportsVolFS " ) ;
if ( result ! = 0 ) {
return false ;
}
b = true ;
result = dalloc_add_copy ( dict , & b , sl_bool_t ) ;
if ( result ! = 0 ) {
return false ;
}
/* kMDSVolumeUUID = uuid */
result = dalloc_stradd ( dict , " kMDSVolumeUUID " ) ;
if ( result ! = 0 ) {
return false ;
}
memcpy ( uuid . sl_uuid , " fakeuuidfakeuuid " , sizeof ( uuid . sl_uuid ) ) ;
result = dalloc_add_copy ( dict , & uuid , sl_uuid_t ) ;
if ( result ! = 0 ) {
return false ;
}
/* kMDSDiskStoreSpindleNumber = 1 (fake) */
result = dalloc_stradd ( dict , " kMDSDiskStoreSpindleNumber " ) ;
if ( result ! = 0 ) {
return false ;
}
u = 1 ;
result = dalloc_add_copy ( dict , & u , uint64_t ) ;
if ( result ! = 0 ) {
return false ;
}
/* kMDSDiskStorePolicy = 3 (whatever that means, taken from OS X) */
result = dalloc_stradd ( dict , " kMDSDiskStorePolicy " ) ;
if ( result ! = 0 ) {
return false ;
}
u = 3 ;
result = dalloc_add_copy ( dict , & u , uint64_t ) ;
if ( result ! = 0 ) {
return false ;
}
/* kMDSStoreMetaScopes array */
array = dalloc_zero ( dict , sl_array_t ) ;
if ( array = = NULL ) {
return NULL ;
}
result = dalloc_stradd ( array , " kMDQueryScopeComputer " ) ;
if ( result ! = 0 ) {
return false ;
}
result = dalloc_stradd ( array , " kMDQueryScopeAllIndexed " ) ;
if ( result ! = 0 ) {
return false ;
}
result = dalloc_stradd ( array , " kMDQueryScopeComputerIndexed " ) ;
if ( result ! = 0 ) {
return false ;
}
result = dalloc_add ( dict , array , sl_array_t ) ;
if ( result ! = 0 ) {
return false ;
}
/* kMDSStoreDevice = 0x1000003 (whatever that means, taken from OS X) */
result = dalloc_stradd ( dict , " kMDSStoreDevice " ) ;
if ( result ! = 0 ) {
return false ;
}
u = 0x1000003 ;
result = dalloc_add_copy ( dict , & u , uint64_t ) ;
if ( result ! = 0 ) {
return false ;
}
/* kMDSStoreSupportsTCC = true (whatever that means, taken from OS X) */
result = dalloc_stradd ( dict , " kMDSStoreSupportsTCC " ) ;
if ( result ! = 0 ) {
return false ;
}
b = true ;
result = dalloc_add_copy ( dict , & b , sl_bool_t ) ;
if ( result ! = 0 ) {
return false ;
}
/* kMDSStorePathScopes = ["/"] (whatever that means, taken from OS X) */
result = dalloc_stradd ( dict , " kMDSStorePathScopes " ) ;
if ( result ! = 0 ) {
return false ;
}
array = dalloc_zero ( dict , sl_array_t ) ;
if ( array = = NULL ) {
return false ;
}
s = talloc_strdup ( dict , " / " ) ;
if ( s = = NULL ) {
return false ;
}
talloc_set_name ( s , " smb_ucs2_t * " ) ;
result = dalloc_add ( array , s , smb_ucs2_t * ) ;
if ( result ! = 0 ) {
return false ;
}
result = dalloc_add ( dict , array , sl_array_t ) ;
if ( result ! = 0 ) {
return false ;
}
result = dalloc_add ( reply , dict , sl_dict_t ) ;
if ( result ! = 0 ) {
return false ;
}
return true ;
}
static void slq_close_timer ( struct tevent_context * ev ,
struct tevent_timer * te ,
struct timeval current_time ,
void * private_data )
{
struct sl_query * slq = talloc_get_type_abort (
private_data , struct sl_query ) ;
struct mds_ctx * mds_ctx = slq - > mds_ctx ;
SLQ_DEBUG ( 10 , slq , " expired " ) ;
TALLOC_FREE ( slq ) ;
if ( CHECK_DEBUGLVL ( 10 ) ) {
for ( slq = mds_ctx - > query_list ; slq ! = NULL ; slq = slq - > next ) {
SLQ_DEBUG ( 10 , slq , " pending " ) ;
}
}
}
/**
* Begin a search query
* */
static bool slrpc_open_query ( struct mds_ctx * mds_ctx ,
const DALLOC_CTX * query , DALLOC_CTX * reply )
{
bool ok ;
uint64_t sl_result ;
uint64_t * uint64p ;
DALLOC_CTX * reqinfo ;
sl_array_t * array , * path_scope ;
sl_cnids_t * cnids ;
struct sl_query * slq = NULL ;
int result ;
2019-04-09 11:19:43 +02:00
const char * querystring = NULL ;
size_t querystring_len ;
char * dest = NULL ;
size_t dest_remaining ;
size_t nconv ;
2017-03-15 13:38:19 +01:00
char * scope = NULL ;
2015-03-26 22:39:21 +01:00
array = dalloc_zero ( reply , sl_array_t ) ;
if ( array = = NULL ) {
return false ;
}
/* Allocate and initialize query object */
slq = talloc_zero ( mds_ctx , struct sl_query ) ;
if ( slq = = NULL ) {
return false ;
}
slq - > entries_ctx = talloc_named_const ( slq , 0 , " struct sl_query.entries_ctx " ) ;
if ( slq - > entries_ctx = = NULL ) {
TALLOC_FREE ( slq ) ;
return false ;
}
talloc_set_destructor ( slq , slq_destructor_cb ) ;
slq - > state = SLQ_STATE_NEW ;
slq - > mds_ctx = mds_ctx ;
slq - > last_used = timeval_current ( ) ;
slq - > start_time = slq - > last_used ;
slq - > expire_time = timeval_add ( & slq - > last_used , MAX_SL_RUNTIME , 0 ) ;
2018-08-21 11:06:16 -07:00
slq - > te = tevent_add_timer ( global_event_context ( ) , slq ,
2015-03-26 22:39:21 +01:00
slq - > expire_time , slq_close_timer , slq ) ;
if ( slq - > te = = NULL ) {
DEBUG ( 1 , ( " tevent_add_timer failed \n " ) ) ;
goto error ;
}
querystring = dalloc_value_for_key ( query , " DALLOC_CTX " , 0 ,
" DALLOC_CTX " , 1 ,
" kMDQueryString " ) ;
if ( querystring = = NULL ) {
DEBUG ( 1 , ( " missing kMDQueryString \n " ) ) ;
goto error ;
}
2019-04-09 11:19:43 +02:00
querystring_len = talloc_array_length ( querystring ) ;
slq - > query_string = talloc_array ( slq , char , querystring_len ) ;
2015-03-26 22:39:21 +01:00
if ( slq - > query_string = = NULL ) {
DEBUG ( 1 , ( " out of memory \n " ) ) ;
goto error ;
}
2019-04-09 11:19:43 +02:00
dest = slq - > query_string ;
dest_remaining = talloc_array_length ( dest ) ;
2015-03-26 22:39:21 +01:00
2019-04-09 11:19:43 +02:00
nconv = smb_iconv ( mds_ctx - > ic_nfd_to_nfc ,
& querystring ,
& querystring_len ,
& dest ,
& dest_remaining ) ;
if ( nconv = = ( size_t ) - 1 ) {
DBG_ERR ( " smb_iconv failed for: %s \n " , querystring ) ;
return false ;
}
2015-03-26 22:39:21 +01:00
uint64p = dalloc_get ( query , " DALLOC_CTX " , 0 , " DALLOC_CTX " , 0 ,
" uint64_t " , 1 ) ;
if ( uint64p = = NULL ) {
goto error ;
}
slq - > ctx1 = * uint64p ;
uint64p = dalloc_get ( query , " DALLOC_CTX " , 0 , " DALLOC_CTX " , 0 ,
" uint64_t " , 2 ) ;
if ( uint64p = = NULL ) {
goto error ;
}
slq - > ctx2 = * uint64p ;
path_scope = dalloc_value_for_key ( query , " DALLOC_CTX " , 0 ,
" DALLOC_CTX " , 1 , " kMDScopeArray " ) ;
if ( path_scope = = NULL ) {
goto error ;
}
2017-03-15 13:38:19 +01:00
scope = dalloc_get ( path_scope , " char * " , 0 ) ;
if ( scope = = NULL ) {
2023-01-18 16:21:16 +01:00
scope = dalloc_get ( path_scope ,
" DALLOC_CTX " , 0 ,
" char * " , 0 ) ;
}
if ( scope = = NULL ) {
DBG_ERR ( " Failed to parse kMDScopeArray \n " ) ;
2017-03-15 13:38:19 +01:00
goto error ;
}
2019-03-14 07:38:20 +01:00
slq - > path_scope = talloc_strdup ( slq , scope ) ;
2015-03-26 22:39:21 +01:00
if ( slq - > path_scope = = NULL ) {
goto error ;
}
reqinfo = dalloc_value_for_key ( query , " DALLOC_CTX " , 0 ,
" DALLOC_CTX " , 1 , " kMDAttributeArray " ) ;
if ( reqinfo = = NULL ) {
goto error ;
}
slq - > reqinfo = talloc_steal ( slq , reqinfo ) ;
2018-11-16 14:24:35 +01:00
DEBUG ( 10 , ( " requested attributes: %s " , dalloc_dump ( reqinfo , 0 ) ) ) ;
2015-03-26 22:39:21 +01:00
cnids = dalloc_value_for_key ( query , " DALLOC_CTX " , 0 ,
" DALLOC_CTX " , 1 , " kMDQueryItemArray " ) ;
if ( cnids ) {
ok = sort_cnids ( slq , cnids - > ca_cnids ) ;
if ( ! ok ) {
goto error ;
}
}
ok = create_result_handle ( slq ) ;
if ( ! ok ) {
DEBUG ( 1 , ( " create_result_handle error \n " ) ) ;
slq - > state = SLQ_STATE_ERROR ;
goto error ;
}
SLQ_DEBUG ( 10 , slq , " new " ) ;
DLIST_ADD ( mds_ctx - > query_list , slq ) ;
2019-05-06 15:03:02 +02:00
ok = mds_ctx - > backend - > search_start ( slq ) ;
2014-07-31 18:01:34 +02:00
if ( ! ok ) {
2019-03-14 07:38:20 +01:00
DBG_ERR ( " backend search_start failed \n " ) ;
2014-07-31 18:01:34 +02:00
goto error ;
}
2015-03-26 22:39:21 +01:00
sl_result = 0 ;
result = dalloc_add_copy ( array , & sl_result , uint64_t ) ;
if ( result ! = 0 ) {
goto error ;
}
result = dalloc_add ( reply , array , sl_array_t ) ;
if ( result ! = 0 ) {
goto error ;
}
return true ;
error :
sl_result = UINT64_MAX ;
TALLOC_FREE ( slq ) ;
result = dalloc_add_copy ( array , & sl_result , uint64_t ) ;
if ( result ! = 0 ) {
return false ;
}
result = dalloc_add ( reply , array , sl_array_t ) ;
if ( result ! = 0 ) {
return false ;
}
return true ;
}
/**
* Fetch results of a query
* */
static bool slrpc_fetch_query_results ( struct mds_ctx * mds_ctx ,
const DALLOC_CTX * query ,
DALLOC_CTX * reply )
{
bool ok ;
struct sl_query * slq = NULL ;
uint64_t * uint64p , ctx1 , ctx2 ;
uint64_t status ;
sl_array_t * array ;
int result ;
array = dalloc_zero ( reply , sl_array_t ) ;
if ( array = = NULL ) {
return false ;
}
/* Get query for context */
uint64p = dalloc_get ( query , " DALLOC_CTX " , 0 , " DALLOC_CTX " , 0 ,
" uint64_t " , 1 ) ;
if ( uint64p = = NULL ) {
goto error ;
}
ctx1 = * uint64p ;
uint64p = dalloc_get ( query , " DALLOC_CTX " , 0 , " DALLOC_CTX " , 0 ,
" uint64_t " , 2 ) ;
if ( uint64p = = NULL ) {
goto error ;
}
ctx2 = * uint64p ;
slq = slq_for_ctx ( mds_ctx , ctx1 , ctx2 ) ;
if ( slq = = NULL ) {
DEBUG ( 1 , ( " bad context: [0x%jx,0x%jx] \n " ,
( uintmax_t ) ctx1 , ( uintmax_t ) ctx2 ) ) ;
goto error ;
}
TALLOC_FREE ( slq - > te ) ;
slq - > last_used = timeval_current ( ) ;
slq - > expire_time = timeval_add ( & slq - > last_used , MAX_SL_RUNTIME , 0 ) ;
2018-08-21 11:06:16 -07:00
slq - > te = tevent_add_timer ( global_event_context ( ) , slq ,
2015-03-26 22:39:21 +01:00
slq - > expire_time , slq_close_timer , slq ) ;
if ( slq - > te = = NULL ) {
DEBUG ( 1 , ( " tevent_add_timer failed \n " ) ) ;
goto error ;
}
SLQ_DEBUG ( 10 , slq , " fetch " ) ;
switch ( slq - > state ) {
case SLQ_STATE_RUNNING :
case SLQ_STATE_RESULTS :
case SLQ_STATE_FULL :
case SLQ_STATE_DONE :
ok = add_results ( array , slq ) ;
if ( ! ok ) {
DEBUG ( 1 , ( " error adding results \n " ) ) ;
goto error ;
}
if ( slq - > state = = SLQ_STATE_FULL ) {
slq - > state = SLQ_STATE_RESULTS ;
2019-05-06 15:03:02 +02:00
slq - > mds_ctx - > backend - > search_cont ( slq ) ;
2015-03-26 22:39:21 +01:00
}
break ;
case SLQ_STATE_ERROR :
DEBUG ( 1 , ( " query in error state \n " ) ) ;
goto error ;
default :
DEBUG ( 1 , ( " unexpected query state %d \n " , slq - > state ) ) ;
goto error ;
}
result = dalloc_add ( reply , array , sl_array_t ) ;
if ( result ! = 0 ) {
goto error ;
}
return true ;
error :
status = UINT64_MAX ;
TALLOC_FREE ( slq ) ;
result = dalloc_add_copy ( array , & status , uint64_t ) ;
if ( result ! = 0 ) {
return false ;
}
result = dalloc_add ( reply , array , sl_array_t ) ;
if ( result ! = 0 ) {
return false ;
}
return true ;
}
/**
* Store metadata attributes for a CNID
* */
static bool slrpc_store_attributes ( struct mds_ctx * mds_ctx ,
const DALLOC_CTX * query , DALLOC_CTX * reply )
{
uint64_t sl_result ;
sl_array_t * array ;
int result ;
array = dalloc_zero ( reply , sl_array_t ) ;
if ( array = = NULL ) {
return false ;
}
/*
* FIXME : not implemented . Used by the client for eg setting
* the modification date of the shared directory which clients
* poll indicating changes on the share and cause the client
* to refresh view .
*/
sl_result = 0 ;
result = dalloc_add_copy ( array , & sl_result , uint64_t ) ;
if ( result ! = 0 ) {
return false ;
}
result = dalloc_add ( reply , array , sl_array_t ) ;
if ( result ! = 0 ) {
return false ;
}
return true ;
}
/**
* Fetch supported metadata attributes for a CNID
* */
static bool slrpc_fetch_attributenames ( struct mds_ctx * mds_ctx ,
const DALLOC_CTX * query ,
DALLOC_CTX * reply )
{
uint64_t id ;
sl_cnids_t * cnids ;
sl_array_t * array ;
uint64_t sl_result ;
sl_cnids_t * replycnids ;
sl_array_t * mdattrs ;
sl_filemeta_t * fmeta ;
int result ;
void * p ;
cnids = dalloc_get ( query , " DALLOC_CTX " , 0 , " sl_cnids_t " , 1 ) ;
if ( cnids = = NULL ) {
return false ;
}
p = dalloc_get_object ( cnids - > ca_cnids , 0 ) ;
if ( p = = NULL ) {
return NULL ;
}
memcpy ( & id , p , sizeof ( uint64_t ) ) ;
/* Result array */
array = dalloc_zero ( reply , sl_array_t ) ;
if ( array = = NULL ) {
return false ;
}
result = dalloc_add ( reply , array , sl_array_t ) ;
if ( result ! = 0 ) {
return false ;
}
/* Return result value 0 */
sl_result = 0 ;
result = dalloc_add_copy ( array , & sl_result , uint64_t ) ;
if ( result ! = 0 ) {
return false ;
}
/* Return CNID array */
replycnids = talloc_zero ( reply , sl_cnids_t ) ;
if ( replycnids = = NULL ) {
return false ;
}
replycnids - > ca_cnids = dalloc_new ( cnids ) ;
if ( replycnids - > ca_cnids = = NULL ) {
return false ;
}
replycnids - > ca_unkn1 = 0xfec ;
replycnids - > ca_context = cnids - > ca_context ;
result = dalloc_add_copy ( replycnids - > ca_cnids , & id , uint64_t ) ;
if ( result ! = 0 ) {
return false ;
}
result = dalloc_add ( array , replycnids , sl_cnids_t ) ;
if ( result ! = 0 ) {
return false ;
}
/*
* FIXME : this should return the real attributes from all
* known metadata sources ( Tracker and filesystem )
*/
mdattrs = dalloc_zero ( reply , sl_array_t ) ;
if ( mdattrs = = NULL ) {
return false ;
}
result = dalloc_stradd ( mdattrs , " kMDItemFSName " ) ;
if ( result ! = 0 ) {
return false ;
}
result = dalloc_stradd ( mdattrs , " kMDItemDisplayName " ) ;
if ( result ! = 0 ) {
return false ;
}
result = dalloc_stradd ( mdattrs , " kMDItemFSSize " ) ;
if ( result ! = 0 ) {
return false ;
}
result = dalloc_stradd ( mdattrs , " kMDItemFSOwnerUserID " ) ;
if ( result ! = 0 ) {
return false ;
}
result = dalloc_stradd ( mdattrs , " kMDItemFSOwnerGroupID " ) ;
if ( result ! = 0 ) {
return false ;
}
result = dalloc_stradd ( mdattrs , " kMDItemFSContentChangeDate " ) ;
if ( result ! = 0 ) {
return false ;
}
fmeta = dalloc_zero ( reply , sl_filemeta_t ) ;
if ( fmeta = = NULL ) {
return false ;
}
result = dalloc_add ( fmeta , mdattrs , sl_array_t ) ;
if ( result ! = 0 ) {
return false ;
}
result = dalloc_add ( array , fmeta , sl_filemeta_t ) ;
if ( result ! = 0 ) {
return false ;
}
return true ;
}
/**
* Fetch metadata attribute values for a CNID
* */
static bool slrpc_fetch_attributes ( struct mds_ctx * mds_ctx ,
const DALLOC_CTX * query , DALLOC_CTX * reply )
{
int result ;
bool ok ;
sl_array_t * array ;
sl_cnids_t * cnids ;
sl_cnids_t * replycnids ;
sl_array_t * reqinfo ;
uint64_t ino ;
uint64_t sl_result ;
sl_filemeta_t * fm ;
sl_array_t * fm_array ;
sl_nil_t nil ;
2019-05-06 14:19:31 +02:00
char * path = NULL ;
2021-05-10 12:34:32 +02:00
struct smb_filename * smb_fname = NULL ;
2020-06-10 17:09:39 +02:00
struct stat_ex * sp = NULL ;
2015-03-26 22:39:21 +01:00
struct sl_inode_path_map * elem = NULL ;
void * p ;
TDB_DATA val = tdb_null ;
NTSTATUS status ;
array = dalloc_zero ( reply , sl_array_t ) ;
if ( array = = NULL ) {
return false ;
}
replycnids = talloc_zero ( reply , sl_cnids_t ) ;
if ( replycnids = = NULL ) {
goto error ;
}
replycnids - > ca_cnids = dalloc_new ( replycnids ) ;
if ( replycnids - > ca_cnids = = NULL ) {
goto error ;
}
fm = dalloc_zero ( array , sl_filemeta_t ) ;
if ( fm = = NULL ) {
goto error ;
}
fm_array = dalloc_zero ( fm , sl_array_t ) ;
if ( fm_array = = NULL ) {
goto error ;
}
/* For some reason the list of results always starts with a nil entry */
2015-07-09 19:22:59 +02:00
result = dalloc_add_copy ( fm_array , & nil , sl_nil_t ) ;
if ( result = = - 1 ) {
goto error ;
}
2015-03-26 22:39:21 +01:00
reqinfo = dalloc_get ( query , " DALLOC_CTX " , 0 , " sl_array_t " , 1 ) ;
if ( reqinfo = = NULL ) {
goto error ;
}
cnids = dalloc_get ( query , " DALLOC_CTX " , 0 , " sl_cnids_t " , 2 ) ;
if ( cnids = = NULL ) {
goto error ;
}
p = dalloc_get_object ( cnids - > ca_cnids , 0 ) ;
if ( p = = NULL ) {
goto error ;
}
memcpy ( & ino , p , sizeof ( uint64_t ) ) ;
replycnids - > ca_unkn1 = 0xfec ;
replycnids - > ca_context = cnids - > ca_context ;
result = dalloc_add_copy ( replycnids - > ca_cnids , & ino , uint64_t ) ;
if ( result ! = 0 ) {
goto error ;
}
status = dbwrap_fetch ( mds_ctx - > ino_path_map , reply ,
make_tdb_data ( ( void * ) & ino , sizeof ( uint64_t ) ) ,
& val ) ;
2019-05-06 14:19:31 +02:00
if ( NT_STATUS_IS_OK ( status ) ) {
if ( val . dsize ! = sizeof ( p ) ) {
DBG_ERR ( " invalid record pointer size: %zd \n " , val . dsize ) ;
TALLOC_FREE ( val . dptr ) ;
goto error ;
}
2015-03-26 22:39:21 +01:00
2019-05-06 14:19:31 +02:00
memcpy ( & p , val . dptr , sizeof ( p ) ) ;
elem = talloc_get_type_abort ( p , struct sl_inode_path_map ) ;
path = elem - > path ;
2015-03-26 22:39:21 +01:00
2021-05-10 12:34:32 +02:00
status = synthetic_pathref ( talloc_tos ( ) ,
mds_ctx - > conn - > cwd_fsp ,
path ,
NULL ,
NULL ,
0 ,
0 ,
& smb_fname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
/* This is not an error, the user may lack permissions */
DBG_DEBUG ( " synthetic_pathref [%s]: %s \n " ,
smb_fname_str_dbg ( smb_fname ) ,
nt_errstr ( status ) ) ;
return true ;
}
2022-03-18 11:56:53 -07:00
status = vfs_stat_fsp ( smb_fname - > fsp ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2021-05-10 12:34:32 +02:00
TALLOC_FREE ( smb_fname ) ;
return true ;
2019-05-06 14:19:31 +02:00
}
2021-05-10 12:34:32 +02:00
2022-03-18 11:56:53 -07:00
sp = & smb_fname - > fsp - > fsp_name - > st ;
2015-03-26 22:39:21 +01:00
}
2020-06-10 17:09:39 +02:00
ok = add_filemeta ( mds_ctx , reqinfo , fm_array , path , sp ) ;
2015-03-26 22:39:21 +01:00
if ( ! ok ) {
goto error ;
}
sl_result = 0 ;
result = dalloc_add_copy ( array , & sl_result , uint64_t ) ;
if ( result ! = 0 ) {
goto error ;
}
result = dalloc_add ( array , replycnids , sl_cnids_t ) ;
if ( result ! = 0 ) {
goto error ;
}
result = dalloc_add ( fm , fm_array , sl_array_t ) ;
if ( result ! = 0 ) {
goto error ;
}
result = dalloc_add ( array , fm , sl_filemeta_t ) ;
if ( result ! = 0 ) {
goto error ;
}
result = dalloc_add ( reply , array , sl_array_t ) ;
if ( result ! = 0 ) {
goto error ;
}
2021-05-10 12:34:32 +02:00
TALLOC_FREE ( smb_fname ) ;
2015-03-26 22:39:21 +01:00
return true ;
error :
2021-05-10 12:34:32 +02:00
TALLOC_FREE ( smb_fname ) ;
2015-03-26 22:39:21 +01:00
sl_result = UINT64_MAX ;
result = dalloc_add_copy ( array , & sl_result , uint64_t ) ;
if ( result ! = 0 ) {
return false ;
}
result = dalloc_add ( reply , array , sl_array_t ) ;
if ( result ! = 0 ) {
return false ;
}
return true ;
}
/**
* Close a query
* */
static bool slrpc_close_query ( struct mds_ctx * mds_ctx ,
const DALLOC_CTX * query , DALLOC_CTX * reply )
{
struct sl_query * slq = NULL ;
uint64_t * uint64p , ctx1 , ctx2 ;
sl_array_t * array ;
uint64_t sl_res ;
int result ;
array = dalloc_zero ( reply , sl_array_t ) ;
if ( array = = NULL ) {
return false ;
}
/* Context */
uint64p = dalloc_get ( query , " DALLOC_CTX " , 0 , " DALLOC_CTX " , 0 ,
" uint64_t " , 1 ) ;
if ( uint64p = = NULL ) {
goto done ;
}
ctx1 = * uint64p ;
uint64p = dalloc_get ( query , " DALLOC_CTX " , 0 , " DALLOC_CTX " , 0 ,
" uint64_t " , 2 ) ;
if ( uint64p = = NULL ) {
goto done ;
}
ctx2 = * uint64p ;
/* Get query for context and free it */
slq = slq_for_ctx ( mds_ctx , ctx1 , ctx2 ) ;
if ( slq = = NULL ) {
DEBUG ( 1 , ( " bad context: [0x%jx,0x%jx] \n " ,
( uintmax_t ) ctx1 , ( uintmax_t ) ctx2 ) ) ;
goto done ;
}
2019-03-14 07:38:20 +01:00
SLQ_DEBUG ( 10 , slq , " close " ) ;
TALLOC_FREE ( slq ) ;
2015-03-26 22:39:21 +01:00
done :
2019-04-16 19:14:39 +02:00
sl_res = UINT64_MAX ;
2015-03-26 22:39:21 +01:00
result = dalloc_add_copy ( array , & sl_res , uint64_t ) ;
if ( result ! = 0 ) {
return false ;
}
result = dalloc_add ( reply , array , sl_array_t ) ;
if ( result ! = 0 ) {
return false ;
}
return true ;
}
2016-01-27 13:23:51 +01:00
static struct mdssvc_ctx * mdssvc_init ( struct tevent_context * ev )
{
2019-03-14 07:38:20 +01:00
bool ok ;
2016-01-27 13:23:51 +01:00
if ( mdssvc_ctx ! = NULL ) {
return mdssvc_ctx ;
}
mdssvc_ctx = talloc_zero ( ev , struct mdssvc_ctx ) ;
if ( mdssvc_ctx = = NULL ) {
return NULL ;
}
mdssvc_ctx - > ev_ctx = ev ;
2019-04-17 11:00:52 +02:00
ok = mdsscv_backend_noindex . init ( mdssvc_ctx ) ;
if ( ! ok ) {
DBG_ERR ( " backend init failed \n " ) ;
TALLOC_FREE ( mdssvc_ctx ) ;
return NULL ;
}
2019-08-05 16:25:01 +02:00
# ifdef HAVE_SPOTLIGHT_BACKEND_ES
ok = mdsscv_backend_es . init ( mdssvc_ctx ) ;
if ( ! ok ) {
DBG_ERR ( " backend init failed \n " ) ;
TALLOC_FREE ( mdssvc_ctx ) ;
return NULL ;
}
# endif
2019-05-06 15:03:02 +02:00
# ifdef HAVE_SPOTLIGHT_BACKEND_TRACKER
2019-03-14 07:38:20 +01:00
ok = mdsscv_backend_tracker . init ( mdssvc_ctx ) ;
if ( ! ok ) {
DBG_ERR ( " backend init failed \n " ) ;
TALLOC_FREE ( mdssvc_ctx ) ;
2016-01-27 13:23:51 +01:00
return NULL ;
}
2019-05-06 15:03:02 +02:00
# endif
2016-01-27 13:23:51 +01:00
return mdssvc_ctx ;
}
2015-03-26 22:39:21 +01:00
/**
2016-03-17 14:05:58 +01:00
* Init callbacks at startup
2019-03-12 15:43:57 +01:00
*
* This gets typically called in the main parent smbd which means we can ' t
* initialize our global state here .
2015-03-26 22:39:21 +01:00
* */
bool mds_init ( struct messaging_context * msg_ctx )
{
return true ;
}
bool mds_shutdown ( void )
{
2019-03-14 07:38:20 +01:00
bool ok ;
2016-01-27 13:23:51 +01:00
if ( mdssvc_ctx = = NULL ) {
return false ;
}
2015-03-26 22:39:21 +01:00
2019-04-17 11:00:52 +02:00
ok = mdsscv_backend_noindex . shutdown ( mdssvc_ctx ) ;
if ( ! ok ) {
goto fail ;
}
2019-08-05 16:25:01 +02:00
# ifdef HAVE_SPOTLIGHT_BACKEND_ES
ok = mdsscv_backend_es . shutdown ( mdssvc_ctx ) ;
if ( ! ok ) {
goto fail ;
}
# endif
2019-05-06 15:03:02 +02:00
# ifdef HAVE_SPOTLIGHT_BACKEND_TRACKER
2019-03-14 07:38:20 +01:00
ok = mdsscv_backend_tracker . shutdown ( mdssvc_ctx ) ;
if ( ! ok ) {
goto fail ;
}
2019-05-06 15:03:02 +02:00
# endif
2015-03-26 22:39:21 +01:00
2019-03-14 07:38:20 +01:00
ok = true ;
fail :
2016-01-27 13:23:51 +01:00
TALLOC_FREE ( mdssvc_ctx ) ;
2019-03-14 07:38:20 +01:00
return ok ;
2015-03-26 22:39:21 +01:00
}
2019-03-12 15:29:48 +01:00
/**
* Tear down connections and free all resources
* */
static int mds_ctx_destructor_cb ( struct mds_ctx * mds_ctx )
{
/*
* We need to free query_list before ino_path_map
*/
while ( mds_ctx - > query_list ! = NULL ) {
/*
* slq destructor removes element from list .
* Don ' t use TALLOC_FREE ( ) !
*/
talloc_free ( mds_ctx - > query_list ) ;
}
TALLOC_FREE ( mds_ctx - > ino_path_map ) ;
2021-08-23 17:40:42 -07:00
if ( mds_ctx - > conn ! = NULL ) {
SMB_VFS_DISCONNECT ( mds_ctx - > conn ) ;
conn_free ( mds_ctx - > conn ) ;
}
2019-03-12 15:29:48 +01:00
ZERO_STRUCTP ( mds_ctx ) ;
return 0 ;
}
2015-03-26 22:39:21 +01:00
/**
2016-01-27 13:23:51 +01:00
* Initialise a context per RPC bind
*
* This ends up being called for every tcon , because the client does a
* RPC bind for every tcon , so this is acually a per tcon context .
2015-03-26 22:39:21 +01:00
* */
2022-05-25 17:26:29 +02:00
NTSTATUS mds_init_ctx ( TALLOC_CTX * mem_ctx ,
struct tevent_context * ev ,
struct messaging_context * msg_ctx ,
struct auth_session_info * session_info ,
int snum ,
const char * sharename ,
const char * path ,
struct mds_ctx * * _mds_ctx )
2015-03-26 22:39:21 +01:00
{
2021-05-10 12:10:08 +02:00
const struct loadparm_substitution * lp_sub =
loadparm_s3_global_substitution ( ) ;
struct smb_filename conn_basedir ;
2015-03-26 22:39:21 +01:00
struct mds_ctx * mds_ctx ;
2019-05-06 15:03:02 +02:00
int backend ;
2021-05-10 12:10:08 +02:00
int ret ;
2019-03-14 07:38:20 +01:00
bool ok ;
2020-05-06 12:36:00 -07:00
smb_iconv_t iconv_hnd = ( smb_iconv_t ) - 1 ;
2021-05-10 12:10:08 +02:00
NTSTATUS status ;
2015-03-26 22:39:21 +01:00
2022-05-25 17:37:22 +02:00
if ( ! lp_spotlight ( snum ) ) {
return NT_STATUS_WRONG_VOLUME ;
}
2015-03-26 22:39:21 +01:00
mds_ctx = talloc_zero ( mem_ctx , struct mds_ctx ) ;
if ( mds_ctx = = NULL ) {
2022-05-25 17:26:29 +02:00
return NT_STATUS_NO_MEMORY ;
2015-03-26 22:39:21 +01:00
}
talloc_set_destructor ( mds_ctx , mds_ctx_destructor_cb ) ;
2016-01-27 13:23:51 +01:00
mds_ctx - > mdssvc_ctx = mdssvc_init ( ev ) ;
if ( mds_ctx - > mdssvc_ctx = = NULL ) {
2022-05-25 17:26:29 +02:00
return NT_STATUS_NO_MEMORY ;
2016-01-27 13:23:51 +01:00
}
2019-05-06 15:03:02 +02:00
backend = lp_spotlight_backend ( snum ) ;
switch ( backend ) {
2019-04-17 11:00:52 +02:00
case SPOTLIGHT_BACKEND_NOINDEX :
mds_ctx - > backend = & mdsscv_backend_noindex ;
break ;
2019-08-05 16:25:01 +02:00
# ifdef HAVE_SPOTLIGHT_BACKEND_ES
case SPOTLIGHT_BACKEND_ES :
mds_ctx - > backend = & mdsscv_backend_es ;
break ;
# endif
2019-05-06 15:03:02 +02:00
# ifdef HAVE_SPOTLIGHT_BACKEND_TRACKER
case SPOTLIGHT_BACKEND_TRACKER :
mds_ctx - > backend = & mdsscv_backend_tracker ;
break ;
# endif
default :
DBG_ERR ( " Unknown backend %d \n " , backend ) ;
TALLOC_FREE ( mdssvc_ctx ) ;
2022-05-25 17:26:29 +02:00
status = NT_STATUS_INTERNAL_ERROR ;
2019-04-09 11:19:43 +02:00
goto error ;
}
2020-05-06 12:36:00 -07:00
iconv_hnd = smb_iconv_open_ex ( mds_ctx ,
2022-05-25 17:23:53 +02:00
" UTF8-NFD " ,
" UTF8-NFC " ,
false ) ;
2020-05-06 12:36:00 -07:00
if ( iconv_hnd = = ( smb_iconv_t ) - 1 ) {
2022-05-25 17:26:29 +02:00
status = NT_STATUS_INTERNAL_ERROR ;
2019-04-09 11:19:43 +02:00
goto error ;
}
2020-05-06 12:36:00 -07:00
mds_ctx - > ic_nfc_to_nfd = iconv_hnd ;
2019-04-09 11:19:43 +02:00
2020-05-06 12:36:00 -07:00
iconv_hnd = smb_iconv_open_ex ( mds_ctx ,
2022-05-25 17:23:53 +02:00
" UTF8-NFC " ,
" UTF8-NFD " ,
false ) ;
2020-05-06 12:36:00 -07:00
if ( iconv_hnd = = ( smb_iconv_t ) - 1 ) {
2022-05-25 17:26:29 +02:00
status = NT_STATUS_INTERNAL_ERROR ;
2019-04-09 11:19:43 +02:00
goto error ;
2019-05-06 15:03:02 +02:00
}
2020-05-06 12:36:00 -07:00
mds_ctx - > ic_nfd_to_nfc = iconv_hnd ;
2019-05-06 15:03:02 +02:00
2019-04-12 12:15:56 +02:00
mds_ctx - > sharename = talloc_strdup ( mds_ctx , sharename ) ;
if ( mds_ctx - > sharename = = NULL ) {
2022-05-25 17:26:29 +02:00
status = NT_STATUS_NO_MEMORY ;
2019-04-12 12:15:56 +02:00
goto error ;
}
2015-03-26 22:39:21 +01:00
mds_ctx - > spath = talloc_strdup ( mds_ctx , path ) ;
if ( mds_ctx - > spath = = NULL ) {
2022-05-25 17:26:29 +02:00
status = NT_STATUS_NO_MEMORY ;
2015-03-26 22:39:21 +01:00
goto error ;
}
2019-04-12 12:15:56 +02:00
mds_ctx - > snum = snum ;
2019-03-11 18:11:04 +01:00
mds_ctx - > pipe_session_info = session_info ;
2015-03-26 22:39:21 +01:00
if ( session_info - > security_token - > num_sids < 1 ) {
2022-05-25 17:26:29 +02:00
status = NT_STATUS_BAD_LOGON_SESSION_STATE ;
2015-03-26 22:39:21 +01:00
goto error ;
}
sid_copy ( & mds_ctx - > sid , & session_info - > security_token - > sids [ 0 ] ) ;
mds_ctx - > uid = session_info - > unix_token - > uid ;
mds_ctx - > ino_path_map = db_open_rbt ( mds_ctx ) ;
if ( mds_ctx - > ino_path_map = = NULL ) {
DEBUG ( 1 , ( " open inode map db failed \n " ) ) ;
2022-05-25 17:26:29 +02:00
status = NT_STATUS_INTERNAL_ERROR ;
2015-03-26 22:39:21 +01:00
goto error ;
}
2021-05-10 12:10:08 +02:00
status = create_conn_struct_cwd ( mds_ctx ,
ev ,
msg_ctx ,
session_info ,
snum ,
lp_path ( talloc_tos ( ) , lp_sub , snum ) ,
& mds_ctx - > conn ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_ERR ( " failed to create conn for vfs: %s \n " ,
nt_errstr ( status ) ) ;
goto error ;
}
conn_basedir = ( struct smb_filename ) {
. base_name = mds_ctx - > conn - > connectpath ,
} ;
ret = vfs_ChDir ( mds_ctx - > conn , & conn_basedir ) ;
if ( ret ! = 0 ) {
DBG_ERR ( " vfs_ChDir [%s] failed: %s \n " ,
conn_basedir . base_name , strerror ( errno ) ) ;
2022-05-25 17:26:29 +02:00
status = map_nt_error_from_unix ( errno ) ;
2021-05-10 12:10:08 +02:00
goto error ;
}
2019-05-06 15:03:02 +02:00
ok = mds_ctx - > backend - > connect ( mds_ctx ) ;
2019-03-14 07:38:20 +01:00
if ( ! ok ) {
DBG_ERR ( " backend connect failed \n " ) ;
2022-05-25 17:26:29 +02:00
status = NT_STATUS_CONNECTION_RESET ;
2019-03-12 15:27:25 +01:00
goto error ;
}
2022-05-25 17:26:29 +02:00
* _mds_ctx = mds_ctx ;
return NT_STATUS_OK ;
2015-03-26 22:39:21 +01:00
error :
2019-04-09 11:19:43 +02:00
if ( mds_ctx - > ic_nfc_to_nfd ! = NULL ) {
smb_iconv_close ( mds_ctx - > ic_nfc_to_nfd ) ;
}
if ( mds_ctx - > ic_nfd_to_nfc ! = NULL ) {
smb_iconv_close ( mds_ctx - > ic_nfd_to_nfc ) ;
}
2015-03-26 22:39:21 +01:00
TALLOC_FREE ( mds_ctx ) ;
2022-05-25 17:26:29 +02:00
return status ;
2015-03-26 22:39:21 +01:00
}
/**
* Dispatch a Spotlight RPC command
* */
bool mds_dispatch ( struct mds_ctx * mds_ctx ,
struct mdssvc_blob * request_blob ,
struct mdssvc_blob * response_blob )
{
bool ok ;
2021-06-15 14:14:52 +02:00
int ret ;
2015-03-26 22:39:21 +01:00
ssize_t len ;
DALLOC_CTX * query = NULL ;
DALLOC_CTX * reply = NULL ;
char * rpccmd ;
const struct slrpc_cmd * slcmd ;
2021-06-15 14:14:52 +02:00
const struct smb_filename conn_basedir = {
. base_name = mds_ctx - > conn - > connectpath ,
} ;
2015-03-26 22:39:21 +01:00
if ( CHECK_DEBUGLVL ( 10 ) ) {
const struct sl_query * slq ;
for ( slq = mds_ctx - > query_list ; slq ! = NULL ; slq = slq - > next ) {
SLQ_DEBUG ( 10 , slq , " pending " ) ;
}
}
response_blob - > length = 0 ;
DEBUG ( 10 , ( " share path: %s \n " , mds_ctx - > spath ) ) ;
query = dalloc_new ( mds_ctx ) ;
if ( query = = NULL ) {
ok = false ;
goto cleanup ;
}
reply = dalloc_new ( mds_ctx ) ;
if ( reply = = NULL ) {
ok = false ;
goto cleanup ;
}
ok = sl_unpack ( query , ( char * ) request_blob - > spotlight_blob ,
request_blob - > length ) ;
if ( ! ok ) {
DEBUG ( 1 , ( " error unpacking Spotlight RPC blob \n " ) ) ;
goto cleanup ;
}
2018-11-16 14:24:35 +01:00
DEBUG ( 5 , ( " %s " , dalloc_dump ( query , 0 ) ) ) ;
2015-03-26 22:39:21 +01:00
rpccmd = dalloc_get ( query , " DALLOC_CTX " , 0 , " DALLOC_CTX " , 0 ,
" char * " , 0 ) ;
if ( rpccmd = = NULL ) {
DEBUG ( 1 , ( " missing primary Spotlight RPC command \n " ) ) ;
ok = false ;
goto cleanup ;
}
DEBUG ( 10 , ( " Spotlight RPC cmd: %s \n " , rpccmd ) ) ;
slcmd = slrpc_cmd_by_name ( rpccmd ) ;
if ( slcmd = = NULL ) {
DEBUG ( 1 , ( " unsupported primary Spotlight RPC command %s \n " ,
rpccmd ) ) ;
ok = false ;
goto cleanup ;
}
2021-06-15 14:14:52 +02:00
ret = vfs_ChDir ( mds_ctx - > conn , & conn_basedir ) ;
if ( ret ! = 0 ) {
DBG_ERR ( " vfs_ChDir [%s] failed: %s \n " ,
conn_basedir . base_name , strerror ( errno ) ) ;
ok = false ;
goto cleanup ;
}
2015-03-26 22:39:21 +01:00
ok = slcmd - > function ( mds_ctx , query , reply ) ;
2019-04-16 14:17:11 +02:00
if ( ok ) {
DBG_DEBUG ( " %s " , dalloc_dump ( reply , 0 ) ) ;
len = sl_pack ( reply ,
( char * ) response_blob - > spotlight_blob ,
response_blob - > size ) ;
if ( len = = - 1 ) {
DBG_ERR ( " error packing Spotlight RPC reply \n " ) ;
ok = false ;
goto cleanup ;
}
response_blob - > length = len ;
2015-03-26 22:39:21 +01:00
}
cleanup :
talloc_free ( query ) ;
talloc_free ( reply ) ;
return ok ;
}