From 2664c997587416a2c8c911a75158485a5c98b70b Mon Sep 17 00:00:00 2001 From: John Hixon Date: Sat, 20 May 2017 04:39:37 +0200 Subject: [PATCH] Zfs provision (#1) Cherry-pick ZFS provisioning code by iXsystems Inc. * Check if sysvol is on filesystem with NFSv4 ACL's (cherry picked from commit ca86f52b78a7b6e7537454a69cf93e7b96210cba) * Only check targetdir if it is defined (I had assumed it was) (cherry picked from commit a29050cb2978ce23e3c04a859340dc2664c77a8a) * Kick samba a little bit into understanding NFSv4 ACL's (cherry picked from commit 1c7542ff4904b729e311e17464ee76582760c219) Signed-off-by: Timur I. Bakeyev --- python/samba/provision/__init__.py | 25 ++++-- source3/lib/sysacls.c | 10 +++ source3/param/loadparm.c | 7 ++ source3/smbd/pysmbd.c | 156 ++++++++++++++++++++++++++++++++++++- 4 files changed, 191 insertions(+), 7 deletions(-) diff --git a/python/samba/provision/__init__.py b/python/samba/provision/__init__.py index 5de986463a5..cd3b91f41b9 100644 --- a/python/samba/provision/__init__.py +++ b/python/samba/provision/__init__.py @@ -1695,19 +1695,25 @@ def setsysvolacl(samdb, netlogon, sysvol, uid, gid, do s3conf = s3param.get_context() s3conf.load(lp.configfile) - file = tempfile.NamedTemporaryFile(dir=os.path.abspath(sysvol)) + sysvol_dir = os.path.abspath(sysvol) + + set_simple_acl = smbd.set_simple_acl + if smbd.has_nfsv4_acls(sysvol_dir): + set_simple_acl = smbd.set_simple_nfsv4_acl + + file = tempfile.NamedTemporaryFile(dir=sysvol_dir) try: try: - smbd.set_simple_acl(file.name, 0o755, system_session_unix(), gid) + set_simple_acl(file.name, 0o755, system_session_unix(), gid) except OSError: - if not smbd.have_posix_acls(): + if not smbd.have_posix_acls() and not smbd.have_nfsv4_acls(): # This clue is only strictly correct for RPM and # Debian-like Linux systems, but hopefully other users # will get enough clue from it. - raise ProvisioningError("Samba was compiled without the posix ACL support that s3fs requires. " + raise ProvisioningError("Samba was compiled without the ACL support that s3fs requires. " "Try installing libacl1-dev or libacl-devel, then re-run configure and make.") - raise ProvisioningError("Your filesystem or build does not support posix ACLs, which s3fs requires. " + raise ProvisioningError("Your filesystem or build does not support ACLs, which s3fs requires. " "Try the mounting the filesystem with the 'acl' option.") try: smbd.chown(file.name, uid, gid, system_session_unix()) @@ -1984,6 +1990,9 @@ def provision_fill(samdb, secrets_ldb, logger, names, samdb.transaction_commit() if serverrole == "active directory domain controller": + if targetdir and smbd.have_nfsv4_acls() and smbd.has_nfsv4_acls(targetdir): + smbd.set_nfsv4_defaults() + # Continue setting up sysvol for GPO. This appears to require being # outside a transaction. if not skip_sysvolacl: @@ -2340,6 +2349,9 @@ def provision(logger, session_info, smbconf=None, if not os.path.isdir(paths.netlogon): os.makedirs(paths.netlogon, 0o755) + + if smbd.have_nfsv4_acls() and smbd.has_nfsv4_acls(paths.sysvol): + smbd.set_nfsv4_defaults() if adminpass is None: adminpass = samba.generate_random_password(12, 32) diff --git a/source3/lib/sysacls.c b/source3/lib/sysacls.c index 0bf3c37edfa..786cd39b5bc 100644 --- a/source3/lib/sysacls.c +++ b/source3/lib/sysacls.c @@ -38,6 +38,16 @@ #include "modules/vfs_hpuxacl.h" #endif +/* + * NFSv4 ACL's should be understood and a first class citizen. Work + * needs to be done in librpc/idl/smb_acl.idl for this to occur. + */ +#if defined(HAVE_LIBSUNACL) && defined(FREEBSD) +#if 0 +#include "modules/nfs4_acls.h" +#endif +#endif + #undef DBGC_CLASS #define DBGC_CLASS DBGC_ACLS diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index a2fcc4246c9..4b676897fc1 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -2801,9 +2801,29 @@ static void init_locals(void) } else { if (lp_parm_const_string(-1, "xattr_tdb", "file", NULL)) { lp_do_parameter(-1, "vfs objects", "dfs_samba4 acl_xattr xattr_tdb"); + /* + * By default, the samba sysvol is located in the statedir. Provisioning will fail in setntacl + * unless we have zfacl enabled. Unfortunately, at this point the smb.conf has not been generated. + * This workaround is freebsd-specific. + */ +#if defined(_PC_ACL_EXTENDED) + } else if (pathconf(lp_state_directory(), _PC_ACL_EXTENDED) == 1) { + lp_do_parameter(-1, "vfs objects", "dfs_samba4 freebsd"); +#endif +#if defined(_PC_ACL_NFS4) + } else if (pathconf(lp_state_directory(), _PC_ACL_NFS4) == 1) { + lp_do_parameter(-1, "vfs objects", "dfs_samba4 zfsacl"); +#endif } else if (lp_parm_const_string(-1, "posix", "eadb", NULL)) { lp_do_parameter(-1, "vfs objects", "dfs_samba4 acl_xattr posix_eadb"); } else { + /* + * This should only set dfs_samba4 and leave acl_xattr + * to be set later (or zfsacl). The only reason the decision + * can't be made here to load acl_xattr or zfsacl is + * that we don't have access to what the target + * directory is. + */ lp_do_parameter(-1, "vfs objects", "dfs_samba4 acl_xattr"); } } diff --git a/source3/smbd/pysmbd.c b/source3/smbd/pysmbd.c index 63fc5d68c33..f5a536ee186 100644 --- a/source3/smbd/pysmbd.c +++ b/source3/smbd/pysmbd.c @@ -419,6 +419,20 @@ static SMB_ACL_T make_simple_acl(TALLOC_CTX *mem_ctx, return acl; } +static SMB_ACL_T make_simple_nfsv4_acl(TALLOC_CTX *mem_ctx, + gid_t gid, + mode_t chmod_mode) +{ + /* + * This function needs to create an NFSv4 ACL. Currently, the only way + * to do so is to use the operating system interface, or to use the + * functions in source3/modules/nfs4_acls.c. These seems ugly and + * hacky. NFSv4 ACL's should be a first class citizen and + * librpc/idl/smb_acl.idl should be modified accordingly. + */ + return NULL; +} + /* set a simple ACL on a file, as a test */ @@ -491,7 +505,85 @@ static PyObject *py_smbd_set_simple_acl(PyObject *self Py_RETURN_NONE; } + /* + set a simple NFSv4 ACL on a file, as a test + */ +static PyObject *py_smbd_set_simple_nfsv4_acl(PyObject *self, PyObject *args, PyObject *kwargs) +{ + const char * const kwnames[] = { + "fname", + "mode", + "session_info", + "gid", + "service", + NULL + }; + char *fname, *service = NULL; + PyObject *py_session = Py_None; + struct auth_session_info *session_info = NULL; + int ret; + int mode, gid = -1; + SMB_ACL_T acl; + TALLOC_CTX *frame; + connection_struct *conn; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siO|iz", + discard_const_p(char *, kwnames), + &fname, + &mode, + &py_session, + &gid, + &service)) + return NULL; + + if (!py_check_dcerpc_type(py_session, + "samba.dcerpc.auth", + "session_info")) { + return NULL; + } + session_info = pytalloc_get_type(py_session, + struct auth_session_info); + if (session_info == NULL) { + PyErr_Format(PyExc_TypeError, + "Expected auth_session_info for session_info argument got %s", + pytalloc_get_name(py_session)); + return NULL; + } + + frame = talloc_stackframe(); + + acl = make_simple_nfsv4_acl(frame, gid, mode); + if (acl == NULL) { + TALLOC_FREE(frame); + Py_RETURN_NONE; + } + + conn = get_conn_tos(service, session_info); + if (!conn) { + TALLOC_FREE(frame); + Py_RETURN_NONE; + } + + /* + * SMB_ACL_TYPE_ACCESS -> ACL_TYPE_ACCESS -> Not valid for NFSv4 ACL + */ + ret = 0; + + /* ret = set_sys_acl_conn(fname, SMB_ACL_TYPE_ACCESS, acl, conn); */ + + if (ret != 0) { + TALLOC_FREE(frame); + errno = ret; + return PyErr_SetFromErrno(PyExc_OSError); + } + + TALLOC_FREE(frame); + + Py_RETURN_NONE; +} + +/* chown a file */ static PyObject *py_smbd_chown(PyObject *self, PyObject *args, PyObject *kwargs) @@ -665,7 +757,7 @@ static PyObject *py_smbd_unlink(PyObject *self, PyObje } /* - check if we have ACL support + check if we have POSIX.1e ACL support */ static PyObject *py_smbd_have_posix_acls(PyObject *self, PyObject *Py_UNUSED(ignored)) @@ -677,7 +769,84 @@ static PyObject *py_smbd_have_posix_acls(PyObject *sel #endif } +static PyObject *py_smbd_has_posix_acls(PyObject *self, PyObject *args, PyObject *kwargs) +{ + const char * const kwnames[] = { "path", NULL }; + char *path = NULL; + TALLOC_CTX *frame; + struct statfs fs; + int ret = false; + + frame = talloc_stackframe(); + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|z", + discard_const_p(char *, kwnames), &path)) { + TALLOC_FREE(frame); + return NULL; + } + + if (statfs(path, &fs) != 0) { + TALLOC_FREE(frame); + return NULL; + } + + if (fs.f_flags & MNT_ACLS) + ret = true; + + TALLOC_FREE(frame); + return PyBool_FromLong(ret); +} + /* + check if we have NFSv4 ACL support + */ +static PyObject *py_smbd_have_nfsv4_acls(PyObject *self) +{ +#ifdef HAVE_LIBSUNACL + return PyBool_FromLong(true); +#else + return PyBool_FromLong(false); +#endif +} + +static PyObject *py_smbd_has_nfsv4_acls(PyObject *self, PyObject *args, PyObject *kwargs) +{ + const char * const kwnames[] = { "path", NULL }; + char *path = NULL; + TALLOC_CTX *frame; + struct statfs fs; + int ret = false; + + frame = talloc_stackframe(); + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s|z", + discard_const_p(char *, kwnames), &path)) { + TALLOC_FREE(frame); + return NULL; + } + + if (statfs(path, &fs) != 0) { + TALLOC_FREE(frame); + return NULL; + } + + if (fs.f_flags & MNT_NFS4ACLS) + ret = true; + + TALLOC_FREE(frame); + return PyBool_FromLong(ret); +} + + +static PyObject *py_smbd_set_nfsv4_defaults(PyObject *self) +{ + /* + * It is really be done in source3/param/loadparm.c + */ + Py_RETURN_NONE; +} + +/* set the NT ACL on a file */ static PyObject *py_smbd_set_nt_acl(PyObject *self, PyObject *args, PyObject *kwargs) @@ -1124,8 +1296,26 @@ static PyMethodDef py_smbd_methods[] = { { "have_posix_acls", (PyCFunction)py_smbd_have_posix_acls, METH_NOARGS, NULL }, + { "has_posix_acls", + PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_has_posix_acls), + METH_VARARGS|METH_KEYWORDS, + NULL }, + { "have_nfsv4_acls", + (PyCFunction)py_smbd_have_nfsv4_acls, METH_NOARGS, + NULL }, + { "has_nfsv4_acls", + PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_has_nfsv4_acls), + METH_VARARGS|METH_KEYWORDS, + NULL }, + { "set_nfsv4_defaults", + (PyCFunction)py_smbd_set_nfsv4_defaults, METH_NOARGS, + NULL }, { "set_simple_acl", PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_set_simple_acl), + METH_VARARGS|METH_KEYWORDS, + NULL }, + { "set_simple_nfsv4_acl", + PY_DISCARD_FUNC_SIG(PyCFunction, py_smbd_set_simple_nfsv4_acl), METH_VARARGS|METH_KEYWORDS, NULL }, { "set_nt_acl", -- 2.14.2