diff options
-rw-r--r-- | source3/Makefile.in | 5 | ||||
-rw-r--r-- | source3/configure.in | 2 | ||||
-rw-r--r-- | source3/modules/vfs_linux_xfs_sgid.c | 105 |
3 files changed, 112 insertions, 0 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in index 5ce77dd851..c33bf27002 100644 --- a/source3/Makefile.in +++ b/source3/Makefile.in @@ -752,6 +752,7 @@ PERFCOUNT_TEST_OBJ = modules/perfcount_test.o VFS_DIRSORT_OBJ = modules/vfs_dirsort.o VFS_SCANNEDONLY_OBJ = modules/vfs_scannedonly.o VFS_CROSSRENAME_OBJ = modules/vfs_crossrename.o +VFS_LINUX_XFS_SGID_OBJ = modules/vfs_linux_xfs_sgid.o PLAINTEXT_AUTH_OBJ = auth/pampass.o auth/pass_check.o @@ -2833,6 +2834,10 @@ bin/crossrename.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_CROSSRENAME_OBJ) @echo "Building plugin $@" @$(SHLD_MODULE) $(VFS_CROSSRENAME_OBJ) +bin/linux_xfs_sgid.@SHLIBEXT@: $(BINARY_PREREQS) $(VFS_LINUX_XFS_SGID_OBJ) + @echo "Building plugin $@" + @$(SHLD_MODULE) $(VFS_LINUX_XFS_SGID_OBJ) + ######################################################### ## IdMap NSS plugins diff --git a/source3/configure.in b/source3/configure.in index 6f25be5a9c..146dc855cf 100644 --- a/source3/configure.in +++ b/source3/configure.in @@ -454,6 +454,7 @@ default_shared_modules="$default_shared_modules vfs_preopen" default_shared_modules="$default_shared_modules vfs_catia" default_shared_modules="$default_shared_modules vfs_scannedonly" default_shared_modules="$default_shared_modules vfs_crossrename" +default_shared_modules="$default_shared_modules vfs_linux_xfs_sgid" if test "x$developer" = xyes; then default_static_modules="$default_static_modules rpc_rpcecho pdb_ads" @@ -6576,6 +6577,7 @@ SMB_MODULE(vfs_onefs_shadow_copy, \$(VFS_ONEFS_SHADOW_COPY), "bin/onefs_shadow_c SMB_MODULE(vfs_dirsort, \$(VFS_DIRSORT_OBJ), "bin/dirsort.$SHLIBEXT", VFS) SMB_MODULE(vfs_scannedonly, \$(VFS_SCANNEDONLY_OBJ), "bin/scannedonly.$SHLIBEXT", VFS) SMB_MODULE(vfs_crossrename, \$(VFS_CROSSRENAME_OBJ), "bin/crossrename.$SHLIBEXT", VFS) +SMB_MODULE(vfs_linux_xfs_sgid, \$(VFS_LINUX_XFS_SGID_OBJ), "bin/linux_xfs_sgid.$SHLIBEXT", VFS) SMB_SUBSYSTEM(VFS,smbd/vfs.o) diff --git a/source3/modules/vfs_linux_xfs_sgid.c b/source3/modules/vfs_linux_xfs_sgid.c new file mode 100644 index 0000000000..e01b2d1157 --- /dev/null +++ b/source3/modules/vfs_linux_xfs_sgid.c @@ -0,0 +1,105 @@ +/* + * Module to work around a bug in Linux XFS: + * http://oss.sgi.com/bugzilla/show_bug.cgi?id=280 + * + * Copyright (c) Volker Lendecke 2010 + * + * 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" + +static int linux_xfs_sgid_mkdir(vfs_handle_struct *handle, const char *path, mode_t mode) +{ + struct smb_filename fname = { 0, }; + int mkdir_res; + int res; + + DEBUG(10, ("Calling linux_xfs_sgid_mkdir(%s)\n", path)); + + mkdir_res = SMB_VFS_NEXT_MKDIR(handle, path, mode); + if (mkdir_res == -1) { + DEBUG(10, ("SMB_VFS_NEXT_MKDIR returned error: %s\n", + strerror(errno))); + return mkdir_res; + } + + if (!parent_dirname(talloc_tos(), path, &fname.base_name, NULL)) { + DEBUG(1, ("parent_dirname failed\n")); + /* return success, we did the mkdir */ + return mkdir_res; + } + + res = SMB_VFS_NEXT_STAT(handle, &fname); + if (res == -1) { + DEBUG(10, ("NEXT_STAT(%s) failed: %s\n", fname.base_name, + strerror(errno))); + /* return success, we did the mkdir */ + return mkdir_res; + } + TALLOC_FREE(fname.base_name); + if ((fname.st.st_ex_mode & S_ISGID) == 0) { + /* No SGID to inherit */ + DEBUG(10, ("No SGID to inherit\n")); + return mkdir_res; + } + + fname.base_name = discard_const_p(char, path); + + res = SMB_VFS_NEXT_STAT(handle, &fname); + if (res == -1) { + DEBUG(2, ("Could not stat just created dir %s: %s\n", path, + strerror(errno))); + /* return success, we did the mkdir */ + return mkdir_res; + } + fname.st.st_ex_mode |= S_ISGID; + fname.st.st_ex_mode &= ~S_IFDIR; + + /* + * Yes, we have to do this as root. If you do it as + * non-privileged user, XFS on Linux will just ignore us and + * return success. What can you do... + */ + become_root(); + res = SMB_VFS_NEXT_CHMOD(handle, path, fname.st.st_ex_mode); + unbecome_root(); + + if (res == -1) { + DEBUG(2, ("CHMOD(%s, %o) failed: %s\n", path, + (int)fname.st.st_ex_mode, strerror(errno))); + /* return success, we did the mkdir */ + return mkdir_res; + } + return mkdir_res; +} + +static int linux_xfs_sgid_chmod_acl(vfs_handle_struct *handle, + const char *name, mode_t mode) +{ + errno = ENOSYS; + return -1; +} + +static struct vfs_fn_pointers linux_xfs_sgid_fns = { + .mkdir = linux_xfs_sgid_mkdir, + .chmod_acl = linux_xfs_sgid_chmod_acl, +}; + +NTSTATUS vfs_linux_xfs_sgid_init(void); +NTSTATUS vfs_linux_xfs_sgid_init(void) +{ + return smb_register_vfs(SMB_VFS_INTERFACE_VERSION, + "linux_xfs_sgid", &linux_xfs_sgid_fns); +} |