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:
parent
da7dec0a50
commit
c85cd5c431
148
docs-xml/manpages/mdfind.1.xml
Normal file
148
docs-xml/manpages/mdfind.1.xml
Normal 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<$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>
|
@ -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
290
source3/utils/mdfind.c
Normal 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;
|
||||
}
|
@ -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
|
||||
''')
|
||||
|
Loading…
Reference in New Issue
Block a user