The branch, master has been updated
       via  9345d11c44e docs: add vfs_ceph_snapshots manpage
       via  76f3b194c25 vfs: add ceph_snapshots module
       via  76d7d05b1da vfs_ceph: drop fdopendir handler
      from  43958af1d50 CVE-2018-16860 Heimdal KDC: Reject PA-S4U2Self with 
unkeyed checksum

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 9345d11c44e55e9ad1eb6b55975d04561f5d2ba3
Author: David Disseldorp <dd...@samba.org>
Date:   Wed Mar 27 15:57:45 2019 +0100

    docs: add vfs_ceph_snapshots manpage
    
    Signed-off-by: David Disseldorp <dd...@samba.org>
    Reviewed-by: Jeremy Allison <j...@samba.org>
    
    Autobuild-User(master): David Disseldorp <dd...@samba.org>
    Autobuild-Date(master): Tue May 14 23:31:27 UTC 2019 on sn-devel-184

commit 76f3b194c25e8d388cde2da971d116479ac63d9d
Author: David Disseldorp <dd...@samba.org>
Date:   Tue Mar 26 16:35:18 2019 +0100

    vfs: add ceph_snapshots module
    
    vfs_ceph_snapshots is a module for accessing CephFS snapshots as
    Previous Versions. The module is separate from vfs_ceph, so that it can
    also be used atop a CephFS kernel backed share with vfs_default.
    
    Signed-off-by: David Disseldorp <dd...@samba.org>
    Reviewed-by: Jeremy Allison <j...@samba.org>

commit 76d7d05b1da6c0703b1c2bade0c4467c7cc1adec
Author: David Disseldorp <dd...@samba.org>
Date:   Wed Mar 27 13:10:04 2019 +0100

    vfs_ceph: drop fdopendir handler
    
    libcephfs doesn't currently offer an fdopendir equivalent, so the
    existing implementation peeks at fsp->fsp_name->base_name, which can
    break if vfs_ceph is used under a separate path-munging VFS module.
    
    Return ENOSYS instead and rely on existing OpenDir_fsp() fallback.
    
    Signed-off-by: David Disseldorp <dd...@samba.org>
    Reviewed-by: Jeremy Allison <j...@samba.org>

-----------------------------------------------------------------------

Summary of changes:
 docs-xml/manpages/vfs_ceph_snapshots.8.xml |  130 ++
 docs-xml/wscript_build                     |    1 +
 source3/modules/vfs_ceph.c                 |   15 +-
 source3/modules/vfs_ceph_snapshots.c       | 1835 ++++++++++++++++++++++++++++
 source3/modules/wscript_build              |    8 +
 source3/wscript                            |    5 +
 6 files changed, 1982 insertions(+), 12 deletions(-)
 create mode 100644 docs-xml/manpages/vfs_ceph_snapshots.8.xml
 create mode 100644 source3/modules/vfs_ceph_snapshots.c


Changeset truncated at 500 lines:

diff --git a/docs-xml/manpages/vfs_ceph_snapshots.8.xml 
b/docs-xml/manpages/vfs_ceph_snapshots.8.xml
new file mode 100644
index 00000000000..7fa2806fd95
--- /dev/null
+++ b/docs-xml/manpages/vfs_ceph_snapshots.8.xml
@@ -0,0 +1,130 @@
+<?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="vfs_ceph_snapshots.8">
+
+<refmeta>
+       <refentrytitle>vfs_ceph_snapshots</refentrytitle>
+       <manvolnum>8</manvolnum>
+       <refmiscinfo class="source">Samba</refmiscinfo>
+       <refmiscinfo class="manual">System Administration tools</refmiscinfo>
+       <refmiscinfo class="version">&doc.version;</refmiscinfo>
+</refmeta>
+
+
+<refnamediv>
+       <refname>vfs_ceph_snapshots</refname>
+       <refpurpose>
+               Expose CephFS snapshots as shadow-copies
+       </refpurpose>
+</refnamediv>
+
+<refsynopsisdiv>
+       <cmdsynopsis>
+               <command>vfs objects = ceph_snapshots</command>
+       </cmdsynopsis>
+</refsynopsisdiv>
+
+<refsect1>
+       <title>DESCRIPTION</title>
+
+       <para>This VFS module is part of the
+       <citerefentry><refentrytitle>samba</refentrytitle>
+       <manvolnum>8</manvolnum></citerefentry> suite.</para>
+
+       <para>
+               The <command>vfs_ceph_snapshots</command> VFS module exposes
+               CephFS snapshots for use by Samba. When enabled, SMB clients
+               such as Windows Explorer's Previous Versions dialog, can
+               enumerate snaphots and access them via "timewarp" tokens.
+       </para>
+
+       <para>
+               This module can be combined with <command>vfs_ceph</command>,
+               but <command>vfs_ceph_snapshots</command> must be listed first
+               in the <command>vfs objects</command> parameter list.
+       </para>
+
+       <para>
+               CephFS support for ceph.snap.btime virtual extended attributes
+               is required for this module to work properly. This support was
+               added via https://tracker.ceph.com/issues/38838.
+       </para>
+</refsect1>
+
+<refsect1>
+       <title>CONFIGURATION</title>
+
+       <para>
+               When used atop <command>vfs_ceph</command>,
+               <command>path</command> refers to an absolute path within the
+               Ceph filesystem and should not be mounted locally:
+       </para>
+
+       <programlisting>
+               <smbconfsection name="[share]"/>
+               <smbconfoption name="vfs objects">ceph_snapshots 
ceph</smbconfoption>
+               <smbconfoption 
name="path">/non-mounted/cephfs/path</smbconfoption>
+               <smbconfoption name="kernel share modes">no</smbconfoption>
+       </programlisting>
+
+       <para>
+               <command>vfs_ceph_snapshots</command> can also be used atop a
+               kernel CephFS mounted share path, without
+               <command>vfs_ceph</command>. In this case Samba's default VFS
+               backend <command>vfs_default</command> is used:
+       </para>
+
+       <programlisting>
+               <smbconfsection name="[share]"/>
+               <smbconfoption name="vfs objects">ceph_snapshots</smbconfoption>
+               <smbconfoption name="path">/mnt/cephfs/</smbconfoption>
+       </programlisting>
+</refsect1>
+
+<refsect1>
+       <title>OPTIONS</title>
+
+       <variablelist>
+               <varlistentry>
+               <term>ceph:snapdir = subdirectory</term>
+               <listitem>
+               <para>
+                       Allows for the configuration of the special CephFS
+                       snapshot subdirectory name. This parameter should only
+                       be changed from the ".snap" default if the ceph.conf
+                       <command>client snapdir</command> or
+                       <command>snapdirname</command> mount option settings
+                       are changed from their matching ".snap" defaults.
+               </para>
+               <para>
+                       Default:
+                       <smbconfoption name="ceph:snapdir">.snap</smbconfoption>
+               </para>
+               <para>
+                       Example:
+                       <smbconfoption 
name="ceph:snapdir">.snapshots</smbconfoption>
+               </para>
+               </listitem>
+               </varlistentry>
+       </variablelist>
+</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>
+
+</refsect1>
+
+</refentry>
diff --git a/docs-xml/wscript_build b/docs-xml/wscript_build
index 796b685c709..575fb702b46 100644
--- a/docs-xml/wscript_build
+++ b/docs-xml/wscript_build
@@ -72,6 +72,7 @@ vfs_module_manpages = ['vfs_acl_tdb',
                        'vfs_cap',
                        'vfs_catia',
                        'vfs_ceph',
+                       'vfs_ceph_snapshots',
                        'vfs_commit',
                        'vfs_crossrename',
                        'vfs_default_quota',
diff --git a/source3/modules/vfs_ceph.c b/source3/modules/vfs_ceph.c
index 6f29629566e..e1f3d757bf1 100644
--- a/source3/modules/vfs_ceph.c
+++ b/source3/modules/vfs_ceph.c
@@ -328,18 +328,9 @@ static DIR *cephwrap_fdopendir(struct vfs_handle_struct 
*handle,
                               const char *mask,
                               uint32_t attributes)
 {
-       int ret = 0;
-       struct ceph_dir_result *result;
-       DBG_DEBUG("[CEPH] fdopendir(%p, %p)\n", handle, fsp);
-
-       ret = ceph_opendir(handle->data, fsp->fsp_name->base_name, &result);
-       if (ret < 0) {
-               result = NULL;
-               errno = -ret; /* We return result which is NULL in this case */
-       }
-
-       DBG_DEBUG("[CEPH] fdopendir(...) = %d\n", ret);
-       return (DIR *) result;
+       /* OpenDir_fsp() falls back to regular open */
+       errno = ENOSYS;
+       return NULL;
 }
 
 static struct dirent *cephwrap_readdir(struct vfs_handle_struct *handle,
diff --git a/source3/modules/vfs_ceph_snapshots.c 
b/source3/modules/vfs_ceph_snapshots.c
new file mode 100644
index 00000000000..4183069a5c2
--- /dev/null
+++ b/source3/modules/vfs_ceph_snapshots.c
@@ -0,0 +1,1835 @@
+/*
+ * Module for accessing CephFS snapshots as Previous Versions. This module is
+ * separate to vfs_ceph, so that it can also be used atop a CephFS kernel 
backed
+ * share with vfs_default.
+ *
+ * Copyright (C) David Disseldorp 2019
+ *
+ * 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 <dirent.h>
+#include <libgen.h>
+#include "includes.h"
+#include "include/ntioctl.h"
+#include "include/smb.h"
+#include "system/filesys.h"
+#include "smbd/smbd.h"
+#include "lib/util/tevent_ntstatus.h"
+
+#undef DBGC_CLASS
+#define DBGC_CLASS DBGC_VFS
+
+/*
+ * CephFS has a magic snapshots subdirectory in all parts of the directory 
tree.
+ * This module automatically makes all snapshots in this subdir visible to SMB
+ * clients (if permitted by corresponding access control).
+ */
+#define CEPH_SNAP_SUBDIR_DEFAULT ".snap"
+/*
+ * The ceph.snap.btime (virtual) extended attribute carries the snapshot
+ * creation time in $secs.$nsecs format. It was added as part of
+ * https://tracker.ceph.com/issues/38838. Running Samba atop old Ceph versions
+ * which don't provide this xattr will not be able to enumerate or access
+ * snapshots using this module. As an alternative, vfs_shadow_copy2 could be
+ * used instead, alongside special shadow:format snapshot directory names.
+ */
+#define CEPH_SNAP_BTIME_XATTR "ceph.snap.btime"
+
+static int ceph_snap_get_btime(struct vfs_handle_struct *handle,
+                              struct smb_filename *smb_fname,
+                              time_t *_snap_secs)
+{
+       int ret;
+       char snap_btime[33];
+       char *s = NULL;
+       char *endptr = NULL;
+       struct timespec snap_timespec;
+       int err;
+
+       ret = SMB_VFS_NEXT_GETXATTR(handle, smb_fname, CEPH_SNAP_BTIME_XATTR,
+                                   snap_btime, sizeof(snap_btime));
+       if (ret < 0) {
+               DBG_ERR("failed to get %s xattr: %s\n",
+                       CEPH_SNAP_BTIME_XATTR, strerror(errno));
+               return -errno;
+       }
+
+       if (ret == 0 || ret >= sizeof(snap_btime) - 1) {
+               return -EINVAL;
+       }
+
+       /* ensure zero termination */
+       snap_btime[ret] = '\0';
+
+       /* format is sec.nsec */
+       s = strchr(snap_btime, '.');
+       if (s == NULL) {
+               DBG_ERR("invalid %s xattr value: %s\n",
+                       CEPH_SNAP_BTIME_XATTR, snap_btime);
+               return -EINVAL;
+       }
+
+       /* First component is seconds, extract it */
+       *s = '\0';
+       snap_timespec.tv_sec = strtoull_err(snap_btime, &endptr, 10, &err);
+       if (err != 0) {
+               return -err;
+       }
+       if ((endptr == snap_btime) || (*endptr != '\0')) {
+               DBG_ERR("couldn't process snap.tv_sec in %s\n", snap_btime);
+               return -EINVAL;
+       }
+
+       /* second component is nsecs */
+       s++;
+       snap_timespec.tv_nsec = strtoul_err(s, &endptr, 10, &err);
+       if (err != 0) {
+               return -err;
+       }
+       if ((endptr == s) || (*endptr != '\0')) {
+               DBG_ERR("couldn't process snap.tv_nsec in %s\n", s);
+               return -EINVAL;
+       }
+
+       /*
+        * >> 30 is a rough divide by ~10**9. No need to be exact, as @GMT
+        * tokens only offer 1-second resolution (while twrp is nsec).
+        */
+       *_snap_secs = snap_timespec.tv_sec + (snap_timespec.tv_nsec >> 30);
+
+       return 0;
+}
+
+/*
+ * XXX Ceph snapshots can be created with sub-second granularity, which means
+ * that multiple snapshots may be mapped to the same @GMT- label.
+ *
+ * @this_label is a pre-zeroed buffer to be filled with a @GMT label
+ * @return 0 if label successfully filled or -errno on error.
+ */
+static int ceph_snap_fill_label(struct vfs_handle_struct *handle,
+                               TALLOC_CTX *tmp_ctx,
+                               const char *parent_snapsdir,
+                               const char *subdir,
+                               SHADOW_COPY_LABEL this_label)
+{
+       struct smb_filename *smb_fname;
+       time_t snap_secs;
+       struct tm gmt_snap_time;
+       struct tm *tm_ret;
+       size_t str_sz;
+       char snap_path[PATH_MAX + 1];
+       int ret;
+
+       /*
+        * CephFS snapshot creation times are available via a special
+        * xattr - snapshot b/m/ctimes all match the snap source.
+        */
+       ret = snprintf(snap_path, sizeof(snap_path), "%s/%s",
+                       parent_snapsdir, subdir);
+       if (ret >= sizeof(snap_path)) {
+               return -EINVAL;
+       }
+
+       smb_fname = synthetic_smb_fname(tmp_ctx, snap_path,
+                                       NULL, NULL, 0);
+       if (smb_fname == NULL) {
+               return -ENOMEM;
+       }
+
+       ret = ceph_snap_get_btime(handle, smb_fname, &snap_secs);
+       if (ret < 0) {
+               return ret;
+       }
+
+       tm_ret = gmtime_r(&snap_secs, &gmt_snap_time);
+       if (tm_ret == NULL) {
+               return -EINVAL;
+       }
+       str_sz = strftime(this_label, sizeof(SHADOW_COPY_LABEL),
+                         "@GMT-%Y.%m.%d-%H.%M.%S", &gmt_snap_time);
+       if (str_sz == 0) {
+               DBG_ERR("failed to convert tm to @GMT token\n");
+               return -EINVAL;
+       }
+
+       DBG_DEBUG("mapped snapshot at %s to enum snaps label %s\n",
+                 snap_path, this_label);
+
+       return 0;
+}
+
+static int ceph_snap_enum_snapdir(struct vfs_handle_struct *handle,
+                                 struct smb_filename *snaps_dname,
+                                 bool labels,
+                                 struct shadow_copy_data *sc_data)
+{
+       NTSTATUS status;
+       int ret;
+       DIR *d = NULL;
+       struct dirent *e = NULL;
+       uint32_t slots;
+
+       status = smbd_check_access_rights(handle->conn,
+                                       snaps_dname,
+                                       false,
+                                       SEC_DIR_LIST);
+       if (!NT_STATUS_IS_OK(status)) {
+               DEBUG(0,("user does not have list permission "
+                       "on snapdir %s\n",
+                       snaps_dname->base_name));
+               ret = -map_errno_from_nt_status(status);
+               goto err_out;
+       }
+
+       DBG_DEBUG("enumerating shadow copy dir at %s\n",
+                 snaps_dname->base_name);
+
+       /*
+        * CephFS stat(dir).size *normally* returns the number of child entries
+        * for a given dir, but it unfortunately that's not the case for the one
+        * place we need it (dir=.snap), so we need to dynamically determine it
+        * via readdir.
+        */
+       d = SMB_VFS_NEXT_OPENDIR(handle, snaps_dname, NULL, 0);
+       if (d == NULL) {
+               ret = -errno;
+               goto err_out;
+       }
+
+       slots = 0;
+       sc_data->num_volumes = 0;
+       sc_data->labels = NULL;
+
+       for (e = SMB_VFS_NEXT_READDIR(handle, d, NULL);
+            e != NULL;
+            e = SMB_VFS_NEXT_READDIR(handle, d, NULL)) {
+               if (ISDOT(e->d_name) || ISDOTDOT(e->d_name)) {
+                       continue;
+               }
+               sc_data->num_volumes++;
+               if (!labels) {
+                       continue;
+               }
+               if (sc_data->num_volumes > slots) {
+                       uint32_t new_slot_count = slots + 10;
+                       SMB_ASSERT(new_slot_count > slots);
+                       sc_data->labels = talloc_realloc(sc_data,
+                                                        sc_data->labels,
+                                                        SHADOW_COPY_LABEL,
+                                                        new_slot_count);
+                       if (sc_data->labels == NULL) {
+                               ret = -ENOMEM;
+                               goto err_closedir;
+                       }
+                       memset(sc_data->labels[slots], 0,
+                              sizeof(SHADOW_COPY_LABEL) * 10);
+
+                       DBG_DEBUG("%d->%d slots for enum_snaps response\n",
+                                 slots, new_slot_count);
+                       slots = new_slot_count;
+               }
+               DBG_DEBUG("filling shadow copy label for %s/%s\n",
+                         snaps_dname->base_name, e->d_name);
+               ret = ceph_snap_fill_label(handle, snaps_dname,
+                               snaps_dname->base_name, e->d_name,
+                               sc_data->labels[sc_data->num_volumes - 1]);
+               if (ret < 0) {
+                       goto err_closedir;
+               }
+       }
+
+       ret = SMB_VFS_NEXT_CLOSEDIR(handle, d);
+       if (ret != 0) {
+               ret = -errno;
+               goto err_out;
+       }
+
+       DBG_DEBUG("%s shadow copy enumeration found %d labels \n",
+                 snaps_dname->base_name, sc_data->num_volumes);
+
+       return 0;
+
+err_closedir:
+       SMB_VFS_NEXT_CLOSEDIR(handle, d);
+err_out:
+       TALLOC_FREE(sc_data->labels);
+       return ret;
+}
+
+/*
+ * Prior reading: The Meaning of Path Names
+ *   https://wiki.samba.org/index.php/Writing_a_Samba_VFS_Module
+ *
+ * translate paths so that we can use the parent dir for .snap access:
+ *   myfile        -> parent=        trimmed=myfile
+ *   /a            -> parent=/       trimmed=a
+ *   dir/sub/file  -> parent=dir/sub trimmed=file
+ *   /dir/sub      -> parent=/dir/   trimmed=sub
+ */
+static int ceph_snap_get_parent_path(const char *connectpath,
+                                    const char *path,
+                                    char *_parent_buf,
+                                    size_t buflen,
+                                    const char **_trimmed)
+{
+       const char *p;
+       size_t len;
+       int ret;
+
+       if (!strcmp(path, "/")) {
+               DBG_ERR("can't go past root for %s .snap dir\n", path);
+               return -EINVAL;
+       }
+
+       p = strrchr_m(path, '/'); /* Find final '/', if any */
+       if (p == NULL) {
+               DBG_DEBUG("parent .snap dir for %s is cwd\n", path);
+               ret = strlcpy(_parent_buf, "", buflen);
+               if (ret >= buflen) {
+                       return -EINVAL;
+               }
+               if (_trimmed != NULL) {
+                       *_trimmed = path;
+               }
+               return 0;
+       }
+
+       SMB_ASSERT(p >= path);
+       len = p - path;
+
+       ret = snprintf(_parent_buf, buflen, "%.*s", (int)len, path);
+       if (ret >= buflen) {
+               return -EINVAL;
+       }
+
+       /* for absolute paths, check that we're not going outside the share */
+       if ((len > 0) && (_parent_buf[0] == '/')) {
+               bool connectpath_match = false;


-- 
Samba Shared Repository

Reply via email to