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