1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-08 21:18:16 +03:00

s3:utils: add mdfind

A small command line tool to run macOS Spotlight searches against an SMB server
that runs the Spotlight mdssvc RPC service, including macOS and Samba.

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Noel Power <noel.power@suse.com>
This commit is contained in:
Ralph Boehme 2019-05-02 21:33:46 +02:00
parent da7dec0a50
commit c85cd5c431
4 changed files with 453 additions and 0 deletions

View File

@ -0,0 +1,148 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE refentry PUBLIC "-//Samba-Team//DTD DocBook V4.2-Based Variant V1.0//EN" "http://www.samba.org/samba/DTD/samba-doc">
<refentry id="mdfind.1">
<refmeta>
<refentrytitle>mdfind</refentrytitle>
<manvolnum>1</manvolnum>
<refmiscinfo class="source">Samba</refmiscinfo>
<refmiscinfo class="manual">User Commands</refmiscinfo>
<refmiscinfo class="version">&doc.version;</refmiscinfo>
</refmeta>
<refnamediv>
<refname>mdfind</refname>
<refpurpose>Run Spotlight searches against an SMB server</refpurpose>
</refnamediv>
<refsynopsisdiv>
<cmdsynopsis>
<command>mvxattr</command>
<arg choice="req">server</arg>
<arg choice="req">sharename</arg>
<arg choice="req">query</arg>
<arg choice="opt">-p, --path</arg>
<arg choice="opt">-L, --live</arg>
</cmdsynopsis>
</refsynopsisdiv>
<refsect1>
<title>DESCRIPTION</title>
<para>This tool is part of the <citerefentry><refentrytitle>samba</refentrytitle>
<manvolnum>1</manvolnum></citerefentry> suite.</para>
<para>mdfind is a simple utility to run Spotlight searches against an SMB server
that runs the Spotlight <emphasis>mdssvc</emphasis> RPC service.</para>
</refsect1>
<refsect1>
<title>OPTIONS</title>
<variablelist>
<varlistentry>
<term>server</term>
<listitem>
<para>The SMB server name or IP address to connect to.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>sharename</term>
<listitem>
<para>The name of a share on the server.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>query</term>
<listitem>
<para>The query expression syntax is a simplified form of filename
globbing familiar to shell users. Queries have the following
format:</para>
<para>attribute=="value"</para>
<para>For queries against a Samba server with Spotlight enabled using
the Elasticsearch backend, the list of supported metadata attributes
is given by the JSON attribute mapping file, typically installed at
<filename>/usr/share/samba/mdssvc/elasticsearch_mappings.json</filename>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>-p PATH, --path=PATH</term>
<listitem>
<para>Server side path to search, defaults to
<emphasis>"/"</emphasis></para>
</listitem>
</varlistentry>
<varlistentry>
<term>-L, --live</term>
<listitem><para>Query remains running.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>EXAMPLES</title>
<para>Search all indexed metadata attributes, exact match:</para>
<programlisting>
'*=="Samba"'
</programlisting>
<para>Search all indexed metadata attributes, prefix match:</para>
<programlisting>
'*=="Samba*"'
</programlisting>
<para>Search by filename:</para>
<programlisting>
'kMDItemFSName=="Samba*"'
</programlisting>
<para>Search by date:</para>
<programlisting>
'kMDItemFSContentChangeDate&lt;$time.iso(2018-10-01T10:00:00Z)'
</programlisting>
<para>Search files's content:</para>
<programlisting>
'kMDItemTextContent=="Samba*"'
</programlisting>
<para>Expressions:</para>
<programlisting>
kMDItemFSName=="Samba*"||kMDItemTextContent=="Tango*"'
</programlisting>
</refsect1>
<refsect1>
<title>SEE ALSO</title>
<para>File Metadata Search Programming Guide
<ulink url="https://developer.apple.com/library/archive/documentation/Carbon/Conceptual/SpotlightQuery/Concepts/Introduction.html">
https://developer.apple.com/library/archive/documentation/Carbon/Conceptual/SpotlightQuery/Concepts/Introduction.html</ulink>
</para>
</refsect1>
<refsect1>
<title>VERSION</title>
<para>This man page is part of version &doc.version; of the Samba suite.</para>
</refsect1>
<refsect1>
<title>AUTHOR</title>
<para>The original Samba software and related utilities were created by
Andrew Tridgell. Samba is now developed by the Samba Team as an Open
Source project similar to the way the Linux kernel is developed.</para>
<para>The mdfind manpage was written by Ralph Boehme.</para>
</refsect1>
</refentry>

View File

@ -19,6 +19,7 @@ manpages='''
manpages/libsmbclient.7
manpages/lmhosts.5
manpages/log2pcap.1
manpages/mdfind.1
manpages/mvxattr.1
manpages/net.8
manpages/nmbd.8

290
source3/utils/mdfind.c Normal file
View File

@ -0,0 +1,290 @@
/*
* Copyright (C) 2019, Ralph Boehme <slow@samba.org.>
*
* This library 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 2 of the License, or (at your option) any later version.
*
* This library 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 library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "includes.h"
#include "lib/util/debug.h"
#include "popt_common.h"
#include "popt_common_cmdline.h"
#include "lib/cmdline_contexts.h"
#include "param.h"
#include "auth_info.h"
#include "client.h"
#include "libsmb/proto.h"
#include "librpc/rpc/rpc_common.h"
#include "rpc_client/cli_pipe.h"
#include "rpc_client/cli_mdssvc.h"
#include "librpc/gen_ndr/ndr_mdssvc_c.h"
static char *opt_path;
static int opt_live;
static struct poptOption long_options[] = {
POPT_AUTOHELP
{
.longName = "path",
.shortName = 'p',
.argInfo = POPT_ARG_STRING,
.arg = &opt_path,
.descrip = "Server-relative search path",
},
{
.longName = "live",
.shortName = 'L',
.argInfo = POPT_ARG_NONE,
.arg = &opt_live,
.descrip = "live query",
},
POPT_COMMON_SAMBA
POPT_COMMON_CREDENTIALS
POPT_TABLEEND
};
int main(int argc, char **argv)
{
const char **const_argv = discard_const_p(const char *, argv);
TALLOC_CTX *frame = talloc_stackframe();
struct tevent_context *ev = NULL;
struct user_auth_info *auth = NULL;
struct rpc_pipe_client *rpccli = NULL;
struct mdscli_ctx *mdscli_ctx = NULL;
struct mdscli_search_ctx *search = NULL;
const char *auth_username = NULL;
const char *auth_passwd = NULL;
const char *auth_domain = NULL;
const char *server = NULL;
const char *share = NULL;
const char *mds_query = NULL;
struct cli_state *cli = NULL;
char *basepath = NULL;
uint32_t flags = 0;
int signing_state = SMB_SIGNING_IPC_DEFAULT;
uint64_t *cnids = NULL;
size_t ncnids;
size_t i;
int opt;
poptContext pc;
NTSTATUS status;
bool ok;
setup_logging(argv[0], DEBUG_STDERR);
smb_init_locale();
lp_set_cmdline("log level", "1");
pc = poptGetContext(argv[0],
argc,
const_argv,
long_options,
POPT_CONTEXT_KEEP_FIRST);
poptSetOtherOptionHelp(pc, "mdfind [OPTIONS] <server> <share> <query>\n");
while ((opt = poptGetNextOpt(pc)) != -1) {
DBG_ERR("Invalid option %s: %s\n",
poptBadOption(pc, 0),
poptStrerror(opt));
poptPrintHelp(pc, stderr, 0);
goto fail;
}
poptGetArg(pc); /* Drop argv[0], the program name */
server = poptGetArg(pc);
share = poptGetArg(pc);
mds_query = poptGetArg(pc);
if (server == NULL || mds_query == NULL) {
poptPrintHelp(pc, stderr, 0);
goto fail;
}
popt_burn_cmdline_password(argc, argv);
if ((server[0] == '/' && server[1] == '/') ||
(server[0] == '\\' && server[1] == '\\'))
{
server += 2;
}
auth = popt_get_cmdline_auth_info();
auth_username = get_cmdline_auth_info_username(auth);
auth_passwd = get_cmdline_auth_info_password(auth);
auth_domain = get_cmdline_auth_info_domain(auth);
signing_state = get_cmdline_auth_info_signing_state(auth);
switch (signing_state) {
case SMB_SIGNING_OFF:
lp_set_cmdline("client ipc signing", "no");
break;
case SMB_SIGNING_REQUIRED:
lp_set_cmdline("client ipc signing", "required");
break;
}
if (get_cmdline_auth_info_use_kerberos(auth)) {
flags |= CLI_FULL_CONNECTION_USE_KERBEROS |
CLI_FULL_CONNECTION_FALLBACK_AFTER_KERBEROS;
}
if (get_cmdline_auth_info_use_ccache(auth)) {
flags |= CLI_FULL_CONNECTION_USE_CCACHE;
}
if (get_cmdline_auth_info_use_pw_nt_hash(auth)) {
flags |= CLI_FULL_CONNECTION_USE_NT_HASH;
}
ev = samba_tevent_context_init(frame);
if (ev == NULL) {
goto fail;
}
cmdline_messaging_context(get_dyn_CONFIGFILE());
ok = lp_load_client(get_dyn_CONFIGFILE());
if (!ok) {
fprintf(stderr, "ERROR: Can't load %s\n",
get_dyn_CONFIGFILE());
exit(1);
}
status = cli_full_connection(&cli,
lp_netbios_name(),
server,
NULL,
0,
"IPC$",
"IPC",
auth_username,
auth_domain,
auth_passwd,
flags,
SMB_SIGNING_IPC_DEFAULT);
if (!NT_STATUS_IS_OK(status)) {
DBG_ERR("Cannot connect to server: %s\n", nt_errstr(status));
goto fail;
}
if (get_cmdline_auth_info_smb_encrypt(auth)) {
status = cli_cm_force_encryption(cli,
auth_username,
auth_passwd,
auth_domain,
"IPC$");
if (!NT_STATUS_IS_OK(status)) {
goto fail;
}
}
status = cli_rpc_pipe_open_noauth_transport(cli,
NCACN_NP,
&ndr_table_mdssvc,
&rpccli);
if (!NT_STATUS_IS_OK(status)) {
goto fail;
}
status = mdscli_connect(frame,
rpccli->binding_handle,
share,
"/foo/bar",
&mdscli_ctx);
if (!NT_STATUS_IS_OK(status)) {
printf("Failed to connect mdssvc\n");
goto fail;
}
if (opt_path == NULL) {
basepath = mdscli_get_basepath(frame, mdscli_ctx);
} else {
basepath = talloc_strdup(frame, opt_path);
}
if (basepath == NULL) {
goto fail;
}
status = mdscli_search(frame,
mdscli_ctx,
mds_query,
basepath,
opt_live == 1 ? true : false,
&search);
if (!NT_STATUS_IS_OK(status)) {
printf("mdscli_search failed\n");
goto fail;
}
if (!opt_live) {
sleep(1);
}
while (true) {
status = mdscli_get_results(frame,
search,
&cnids);
if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MORE_MATCHES)) {
if (opt_live) {
sleep(1);
continue;
}
break;
}
if (!NT_STATUS_IS_OK(status)) {
printf("mdscli_get_results failed\n");
goto fail;
}
ncnids = talloc_array_length(cnids);
if (ncnids == 0) {
break;
}
for (i = 0; i < ncnids; i++) {
char *path = NULL;
status = mdscli_get_path(frame,
mdscli_ctx,
cnids[i],
&path);
if (!NT_STATUS_IS_OK(status)) {
printf("Get path for CNID 0x%"PRIx64" failed\n",
cnids[i]);
goto fail;
}
printf("%s\n", path);
TALLOC_FREE(path);
}
}
status = mdscli_close_search(&search);
if (!NT_STATUS_IS_OK(status)) {
printf("mdscli_close_search failed\n");
goto fail;
}
status = mdscli_disconnect(mdscli_ctx);
if (!NT_STATUS_IS_OK(status)) {
printf("mdscli_disconnect failed\n");
goto fail;
}
TALLOC_FREE(frame);
poptFreeContext(pc);
return 0;
fail:
TALLOC_FREE(frame);
return 1;
}

View File

@ -310,3 +310,17 @@ bld.SAMBA3_BINARY('smbstatus',
PROFILE
CONN_TDB
''')
bld.SAMBA3_BINARY('mdfind',
source='mdfind.c',
deps='''
talloc
tevent
smbconf
popt_samba3
popt_samba3_cmdline
libsmb
msrpc3
RPCCLI_MDSSVC
mdssvc
''')