s3:net: add 'vfs' hierarchy with 'stream2adouble' command
authorRalph Boehme <slow@samba.org>
Wed, 10 Jul 2019 14:03:17 +0000 (16:03 +0200)
committerJeremy Allison <jra@samba.org>
Fri, 12 Jul 2019 21:31:29 +0000 (21:31 +0000)
This adds a new top-level command hierarchy 'vfs' that can be used to add
commands that access the smbd VFS stack.

The first command to be implemented is 'stream2adouble' which can be used to
convert stream metadata to AppleDouble files.

Signed-off-by: Ralph Boehme <slow@samba.org>
Reviewed-by: Jeremy Allison <jra@samba.org>
docs-xml/manpages/net.8.xml
source3/utils/net.c
source3/utils/net.h
source3/utils/net_proto.h
source3/utils/net_vfs.c [new file with mode: 0644]
source3/utils/wscript_build

index df423a3df06691ff37ad459aeb9f57bcbba124c8..d7fb1e15b0fe44338ca3a83e9d973c0134c5dd69 100644 (file)
                </para></listitem>
                </varlistentry>
 
+               <!-- Options for net vfs stream2abouble -->
+
+               <varlistentry>
+               <term>--recursive</term>
+               <listitem><para>Traverse a directory
+               hierarchy.</para></listitem>
+               </varlistentry>
+
+               <varlistentry>
+               <term>--continue</term>
+               <listitem><para>Continue traversing a directory hierarchy in
+               case conversion of one file fails.</para></listitem>
+               </varlistentry>
+
+               <varlistentry>
+               <term>--follow-symlinks</term>
+               <listitem><para>Follow symlinks encountered while traversing a
+               directory.</para></listitem>
+               </varlistentry>
+
                &stdarg.encrypt;
                &popt.common.samba.client;
 
@@ -2889,6 +2909,52 @@ Dump the locking table of a certain global lock.
        </refsect3>
 </refsect2>
 
+<refsect2>
+  <title>vfs</title>
+  <para>Access shared filesystem through the VFS.</para>
+
+  <refsect3>
+    <title>vfs stream2abouble [--recursive] [--verbose] [--continue] [--follow-symlinks] <replaceable>share</replaceable> <replaceable>path</replaceable></title>
+
+    <para>Convert file streams to AppleDouble files.</para>
+    <itemizedlist>
+      <listitem>
+       <para><replaceable>share</replaceable>
+       A Samba share.</para>
+      </listitem>
+    </itemizedlist>
+    <itemizedlist>
+      <listitem>
+       <para><replaceable>path</replaceable> A relative path of something in
+       the Samba share. "." can be used for the root directory of the
+       share.</para>
+      </listitem>
+    </itemizedlist>
+
+    <para>Options:</para>
+    <variablelist>
+      <varlistentry>
+       <term>--recursive</term>
+       <listitem><para>Traverse a directory hierarchy.</para></listitem>
+      </varlistentry>
+      <varlistentry>
+       <term>--verbose</term>
+       <listitem><para>Verbose output.</para></listitem>
+      </varlistentry>
+      <varlistentry>
+       <term>--continue</term>
+       <listitem><para>Continue traversing a directory hierarchy if a single
+       conversion fails.</para></listitem>
+      </varlistentry>
+      <varlistentry>
+       <term>--follow-symlinks</term>
+       <listitem><para>Follow symlinks encountered while traversing a
+       directory.</para></listitem>
+      </varlistentry>
+    </variablelist>
+  </refsect3>
+</refsect2>
+
 <refsect2>
 <title>HELP [COMMAND]</title>
 
index 7c5b6a05be74b228b814b13137c928f37b99548b..71b9b07d7d716b33fdc0952be8a89dcefc136dd0 100644 (file)
@@ -892,6 +892,14 @@ static struct functable net_func[] = {
                   "'net tdb' commands.")
        },
 
+       {       "vfs",
+               net_vfs,
+               NET_TRANSPORT_LOCAL,
+               N_("Filesystem operation through the VFS stack"),
+               N_("  Use 'net help vfs' to get more information about "
+                  "'net vfs' commands.")
+       },
+
 #ifdef WITH_FAKE_KASERVER
        {       "afs",
                net_afs,
@@ -1257,6 +1265,25 @@ static void get_credentials_file(struct net_context *c,
                        .argInfo    = POPT_ARG_NONE,
                        .arg        = &c->opt_json,
                },
+               /* Options for 'net vfs' */
+               {
+                       .longName   = "continue",
+                       .argInfo    = POPT_ARG_NONE,
+                       .arg        = &c->opt_continue_on_error,
+                       .descrip    = "Continue on errors",
+               },
+               {
+                       .longName   = "recursive",
+                       .argInfo    = POPT_ARG_NONE,
+                       .arg        = &c->opt_recursive,
+                       .descrip    = "Traverse directory hierarchy",
+               },
+               {
+                       .longName   = "follow-symlinks",
+                       .argInfo    = POPT_ARG_NONE,
+                       .arg        = &c->opt_follow_symlink,
+                       .descrip    = "follow symlinks",
+               },
                POPT_COMMON_SAMBA
                POPT_TABLEEND
        };
index 0d01ad450102e9be0d8f3d95013f6ab8977b9605..573b6e80d29061841a6f7c2590d0132438821eaf 100644 (file)
@@ -87,6 +87,9 @@ struct net_context {
        int opt_no_dns_updates;
        int opt_keep_account;
        int opt_json;
+       int opt_continue_on_error;
+       int opt_recursive;
+       int opt_follow_symlink;
 
        int opt_have_ip;
        struct sockaddr_storage opt_dest_ip;
index 22fe39e0f1c8e757a12db6de8d1469c1ad576bd0..13058be8b8b3b2317d90098a11a839ea9d4cf552 100644 (file)
@@ -457,4 +457,6 @@ int net_notify(struct net_context *c, int argc, const char **argv);
 
 int net_tdb(struct net_context *c, int argc, const char **argv);
 
+int net_vfs(struct net_context *c, int argc, const char **argv);
+
 #endif /*  _NET_PROTO_H_  */
diff --git a/source3/utils/net_vfs.c b/source3/utils/net_vfs.c
new file mode 100644 (file)
index 0000000..041f98f
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ * Samba Unix/Linux SMB client library
+ * Distributed SMB/CIFS Server Management Utility
+ * Copyright (C) 2019 Ralph Boehme <slow@samba.org>
+ *
+ * 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"
+#include <talloc.h>
+#include <tevent.h>
+#include <ftw.h>
+#include "system/filesys.h"
+#include "system/passwd.h"
+#include "popt_common.h"
+#include "lib/param/loadparm.h"
+#include "lib/param/param.h"
+#include "libcli/security/security.h"
+#include "smbd/proto.h"
+#include "locking/proto.h"
+#include "auth.h"
+#include "lib/adouble.h"
+#include "lib/string_replace.h"
+#include "utils/net.h"
+
+#define NET_VFS_CMD_STREAM_TO_ADOUBLE "stream2adouble"
+
+static struct net_vfs_state {
+       TALLOC_CTX *mem_ctx;
+       struct net_context *c;
+       struct auth_session_info *session_info;
+       struct conn_struct_tos *conn_tos;
+} state;
+
+static void net_vfs_usage(void)
+{
+       fprintf(stderr,
+               "Usage:\n"
+               "net vfs [OPTIONS] <share> ....\n");
+}
+
+static void net_vfs_stream_to_appledouble_usage(void)
+{
+       fprintf(stderr,
+               "Usage:\n"
+               "net vfs " NET_VFS_CMD_STREAM_TO_ADOUBLE
+               " [OPTIONS] <share> <path> [<path> ...]\n"
+               "Options:\n"
+               "  --verbose             verbose output\n"
+               "  --continue            continue on error\n"
+               "  --recursive           traverse directory hierarchy\n"
+               "  --follow-symlinks     follow symlinks\n");
+}
+
+static bool net_vfs_make_session_info(struct auth_session_info **session_info)
+{
+       NTSTATUS status;
+
+       if (non_root_mode()) {
+               struct passwd *p = NULL;
+
+               p = getpwuid(geteuid());
+               if (p == NULL) {
+                       fprintf(stderr, "getpwuid(%d) failed\n", geteuid());
+                       return false;
+               }
+
+               status = make_session_info_from_username(state.mem_ctx,
+                                                        p->pw_name,
+                                                        false,
+                                                        session_info);
+               if (!NT_STATUS_IS_OK(status)) {
+                       fprintf(stderr, "session_info from username failed\n");
+                       return false;
+               }
+
+               return true;
+       }
+
+       status = init_system_session_info(state.mem_ctx);
+       if (!NT_STATUS_IS_OK(status)) {
+               fprintf(stderr, "init_system_session_info failed\n");
+               return false;
+       }
+
+       status = make_session_info_system(state.mem_ctx, session_info);
+       if (!NT_STATUS_IS_OK(status)) {
+               fprintf(stderr, "make_session_info_system failed\n");
+               return false;
+       }
+
+       return true;
+}
+
+static int net_vfs_init(struct net_context *c, int argc, const char **argv)
+{
+       const char *service = NULL;
+       char *share_root = NULL;
+       int snum;
+       NTSTATUS status;
+       bool ok;
+       int rc = 1;
+
+       state = (struct net_vfs_state) {
+               .c = c,
+               .mem_ctx = c,
+       };
+
+       if (argc < 1) {
+               net_vfs_usage();
+               goto done;
+       }
+
+       if (geteuid() != 0 && !uid_wrapper_enabled()) {
+               fprintf(stderr, "'net vfs' must be run as root.\n");
+               goto done;
+       }
+
+       smb_init_locale();
+       umask(0);
+       sec_init();
+       setup_logging("net", DEBUG_STDOUT);
+       lp_set_cmdline("log level", "0");
+
+       ok = lp_load_with_shares(get_dyn_CONFIGFILE());
+       if (!ok) {
+               fprintf(stderr, "lp_load_with_shares failed\n");
+               goto done;
+       }
+
+       ok = locking_init();
+       if (!ok) {
+               fprintf(stderr, "locking init failed\n");
+               goto done;
+       }
+
+       ok = net_vfs_make_session_info(&state.session_info);
+       if (!ok) {
+               goto done;
+       }
+
+       service = argv[0];
+       snum = lp_servicenumber(service);
+       if (snum == -1) {
+               fprintf(stderr, "unknown service: %s\n", service);
+               goto done;
+       }
+
+       share_root = lp_path(state.mem_ctx, snum);
+       if (share_root == NULL) {
+               fprintf(stderr, "Failed to find share root for service: %s\n",
+                       service);
+               goto done;
+       }
+
+       status = create_conn_struct_tos_cwd(global_messaging_context(),
+                                           snum,
+                                           share_root,
+                                           state.session_info,
+                                           &state.conn_tos);
+       if (!NT_STATUS_IS_OK(status)) {
+               goto done;
+       }
+
+       state.conn_tos->conn->share_access = FILE_GENERIC_ALL;
+       state.conn_tos->conn->read_only = false;
+       file_init(state.conn_tos->conn->sconn);
+
+       ok = become_user_by_session(state.conn_tos->conn, state.session_info);
+       if (!ok) {
+               fprintf(stderr, "become_user_by_session failed\n");
+               goto done;
+       }
+
+       rc = 0;
+done:
+       return rc;
+}
+
+static bool do_unfruit(const char *path)
+{
+       struct smb_filename *smb_fname = NULL;
+       char *p = NULL;
+       bool converted;
+       int ret;
+       bool ok;
+
+       p = strrchr_m(path, '/');
+       if (p != NULL) {
+               if (p[1] == '.' && p[2] == '_') {
+                       return true;
+               }
+       }
+
+       smb_fname = synthetic_smb_fname(state.mem_ctx,
+                                       path,
+                                       NULL,
+                                       NULL,
+                                       0);
+       if (smb_fname == NULL) {
+               return false;
+       }
+
+       ret = SMB_VFS_STAT(state.conn_tos->conn, smb_fname);
+       if (ret != 0) {
+               fprintf(stderr, "%s: %s\n", path, strerror(errno));
+               if (state.c->opt_continue_on_error) {
+                       return true;
+               }
+               return false;
+       }
+
+       ok = ad_unconvert(state.mem_ctx,
+                         state.conn_tos->conn->vfs_handles,
+                         macos_string_replace_map,
+                         smb_fname,
+                         &converted);
+       if (!ok) {
+               fprintf(stderr, "Converting failed: %s\n", path);
+               if (state.c->opt_continue_on_error) {
+                       return true;
+               }
+               return false;
+       }
+
+       if (converted) {
+               fprintf(stdout, "Converted: %s\n", path);
+       } else if (state.c->opt_verbose) {
+               fprintf(stdout, "%s\n", path);
+       }
+       return true;
+}
+
+static int nftw_cb(const char *path,
+                  const struct stat *sb,
+                  int typeflag,
+                  struct FTW *ftwbuf)
+{
+       bool ok;
+
+       if (typeflag == FTW_SL) {
+               if (state.c->opt_verbose) {
+                       fprintf(stdout, "Ignoring symlink: %s\n", path);
+               }
+               return 0;
+       }
+
+       ok = do_unfruit(path);
+       if (!ok) {
+               return -1;
+       }
+
+       return 0;
+}
+
+static int net_vfs_stream_to_appledouble(struct net_context *net,
+                                        int argc,
+                                        const char **argv)
+{
+       int i;
+       int ret;
+       bool ok;
+       int rc = 1;
+
+       if (argc < 2 || net->display_usage) {
+               net_vfs_stream_to_appledouble_usage();
+               goto done;
+       }
+
+       ret = net_vfs_init(net, argc, argv);
+       if (ret != 0) {
+               goto done;
+       }
+
+       for (i = 1; i < argc; i++) {
+               const char *path = argv[i];
+
+               if (path[0] == '/') {
+                       fprintf(stderr, "ignoring absolute path: %s\n", path);
+                       if (state.c->opt_continue_on_error) {
+                               continue;
+                       }
+                       goto done;
+               }
+
+               if (!state.c->opt_recursive) {
+                       ok = do_unfruit(path);
+                       if (!ok) {
+                               if (!state.c->opt_continue_on_error) {
+                                       goto done;
+                               }
+                       }
+                       continue;
+               }
+
+               ret = nftw(path,
+                          nftw_cb,
+                          256,
+                          state.c->opt_follow_symlink ? 0 : FTW_PHYS);
+               if (ret != 0) {
+                       fprintf(stderr, "%s: %s\n", path, strerror(errno));
+                       if (!state.c->opt_continue_on_error) {
+                               goto done;
+                       }
+               }
+       }
+
+       rc = 0;
+
+done:
+       return rc;
+}
+
+static struct functable func[] = {
+       {
+               NET_VFS_CMD_STREAM_TO_ADOUBLE,
+               net_vfs_stream_to_appledouble,
+               NET_TRANSPORT_LOCAL,
+               N_("Convert streams to AppleDouble files"),
+               N_("net vfs " NET_VFS_CMD_STREAM_TO_ADOUBLE " [OPTIONS] <share> <path> [<path> ...]")
+       },
+       {NULL, NULL, 0, NULL, NULL}
+};
+
+int net_vfs(struct net_context *c, int argc, const char **argv)
+{
+       return net_run_function(c, argc, argv, "net vfs", func);
+}
index 9d9aa56bf3799960a78628fb079646bcfb952c2d..8393ab92b88f0267a594af034ef03a3650a3b906 100644 (file)
@@ -224,6 +224,7 @@ bld.SAMBA3_BINARY('net',
                  net_afs.c
                  net_notify.c
                  net_tdb.c
+                 net_vfs.c
                  ../registry/reg_parse.c
                  ../registry/reg_format.c
                  ../registry/reg_import.c
@@ -269,6 +270,7 @@ bld.SAMBA3_BINARY('net',
                  CONN_TDB
                  jansson
                  common_auth
+                 ADOUBLE
                  ''')
 
 bld.SAMBA3_BINARY('mvxattr',