summaryrefslogtreecommitdiff
path: root/source4/scripting/python
diff options
context:
space:
mode:
Diffstat (limited to 'source4/scripting/python')
-rw-r--r--source4/scripting/python/config.mk35
-rw-r--r--source4/scripting/python/examples/netbios.py2
-rwxr-xr-xsource4/scripting/python/examples/samr.py2
-rwxr-xr-xsource4/scripting/python/examples/winreg.py2
-rw-r--r--source4/scripting/python/modules.c77
-rw-r--r--source4/scripting/python/modules.h5
-rw-r--r--source4/scripting/python/pyglue.c540
-rw-r--r--source4/scripting/python/samba/__init__.py375
-rw-r--r--source4/scripting/python/samba/drs_utils.py173
-rw-r--r--source4/scripting/python/samba/getopt.py160
-rw-r--r--source4/scripting/python/samba/hostconfig.py66
-rw-r--r--source4/scripting/python/samba/idmap.py29
-rw-r--r--source4/scripting/python/samba/join.py582
-rw-r--r--source4/scripting/python/samba/ms_display_specifiers.py2
-rw-r--r--source4/scripting/python/samba/ms_schema.py35
-rw-r--r--source4/scripting/python/samba/ndr.py31
-rw-r--r--source4/scripting/python/samba/netcmd/__init__.py215
-rw-r--r--source4/scripting/python/samba/netcmd/common.py24
-rw-r--r--source4/scripting/python/samba/netcmd/domainlevel.py247
-rw-r--r--source4/scripting/python/samba/netcmd/drs.py477
-rw-r--r--source4/scripting/python/samba/netcmd/dsacl.py182
-rw-r--r--source4/scripting/python/samba/netcmd/enableaccount.py60
-rw-r--r--source4/scripting/python/samba/netcmd/export.py56
-rw-r--r--source4/scripting/python/samba/netcmd/fsmo.py197
-rw-r--r--source4/scripting/python/samba/netcmd/gpo.py245
-rw-r--r--source4/scripting/python/samba/netcmd/group.py189
-rw-r--r--source4/scripting/python/samba/netcmd/join.py78
-rwxr-xr-xsource4/scripting/python/samba/netcmd/ldapcmp.py949
-rw-r--r--source4/scripting/python/samba/netcmd/machinepw.py53
-rw-r--r--source4/scripting/python/samba/netcmd/netacl.py33
-rw-r--r--source4/scripting/python/samba/netcmd/newuser.py97
-rw-r--r--source4/scripting/python/samba/netcmd/ntacl.py119
-rw-r--r--source4/scripting/python/samba/netcmd/pwsettings.py197
-rw-r--r--source4/scripting/python/samba/netcmd/rodc.py115
-rw-r--r--source4/scripting/python/samba/netcmd/setexpiry.py67
-rw-r--r--source4/scripting/python/samba/netcmd/setpassword.py80
-rw-r--r--source4/scripting/python/samba/netcmd/spn.py217
-rw-r--r--source4/scripting/python/samba/netcmd/time.py47
-rw-r--r--source4/scripting/python/samba/netcmd/user.py76
-rw-r--r--source4/scripting/python/samba/netcmd/vampire.py56
-rw-r--r--source4/scripting/python/samba/ntacls.py171
-rw-r--r--source4/scripting/python/samba/provision.py2067
-rw-r--r--source4/scripting/python/samba/provision/__init__.py1929
-rw-r--r--source4/scripting/python/samba/provision/backend.py772
-rw-r--r--source4/scripting/python/samba/samba3.py14
-rw-r--r--source4/scripting/python/samba/samdb.py678
-rw-r--r--source4/scripting/python/samba/schema.py204
-rw-r--r--source4/scripting/python/samba/sd_utils.py79
-rw-r--r--source4/scripting/python/samba/shares.py61
-rw-r--r--source4/scripting/python/samba/tests/__init__.py213
-rw-r--r--source4/scripting/python/samba/tests/auth.py33
-rw-r--r--source4/scripting/python/samba/tests/blackbox/__init__.py1
-rwxr-xr-xsource4/scripting/python/samba/tests/blackbox/ndrdump.py36
-rw-r--r--source4/scripting/python/samba/tests/blackbox/samba_tool_drs.py100
-rw-r--r--source4/scripting/python/samba/tests/core.py65
-rw-r--r--source4/scripting/python/samba/tests/credentials.py100
-rw-r--r--source4/scripting/python/samba/tests/dcerpc/__init__.py9
-rw-r--r--source4/scripting/python/samba/tests/dcerpc/bare.py23
-rw-r--r--source4/scripting/python/samba/tests/dcerpc/misc.py14
-rw-r--r--source4/scripting/python/samba/tests/dcerpc/registry.py5
-rwxr-xr-xsource4/scripting/python/samba/tests/dcerpc/rpc_talloc.py70
-rw-r--r--source4/scripting/python/samba/tests/dcerpc/rpcecho.py12
-rw-r--r--source4/scripting/python/samba/tests/dcerpc/sam.py6
-rw-r--r--source4/scripting/python/samba/tests/dcerpc/testrpc.py130
-rw-r--r--source4/scripting/python/samba/tests/dcerpc/unix.py19
-rw-r--r--source4/scripting/python/samba/tests/dsdb.py135
-rw-r--r--source4/scripting/python/samba/tests/gensec.py90
-rw-r--r--source4/scripting/python/samba/tests/messaging.py60
-rw-r--r--source4/scripting/python/samba/tests/netcmd.py35
-rw-r--r--source4/scripting/python/samba/tests/ntacls.py101
-rw-r--r--source4/scripting/python/samba/tests/param.py59
-rw-r--r--source4/scripting/python/samba/tests/provision.py45
-rw-r--r--source4/scripting/python/samba/tests/registry.py62
-rw-r--r--source4/scripting/python/samba/tests/samba3.py72
-rw-r--r--source4/scripting/python/samba/tests/samba3sam.py1096
-rw-r--r--source4/scripting/python/samba/tests/samdb.py76
-rw-r--r--source4/scripting/python/samba/tests/security.py145
-rw-r--r--source4/scripting/python/samba/tests/shares.py (renamed from source4/scripting/python/samba/tests/hostconfig.py)12
-rw-r--r--source4/scripting/python/samba/tests/upgrade.py6
-rw-r--r--source4/scripting/python/samba/tests/upgradeprovision.py139
-rw-r--r--source4/scripting/python/samba/tests/upgradeprovisionneeddc.py180
-rw-r--r--source4/scripting/python/samba/tests/xattr.py105
-rwxr-xr-xsource4/scripting/python/samba/torture/pytorture51
-rw-r--r--source4/scripting/python/samba/torture/spoolss.py437
-rwxr-xr-xsource4/scripting/python/samba/torture/torture_samr.py221
-rwxr-xr-xsource4/scripting/python/samba/torture/torture_tdb.py90
-rwxr-xr-xsource4/scripting/python/samba/torture/winreg.py165
-rw-r--r--source4/scripting/python/samba/upgrade.py188
-rwxr-xr-xsource4/scripting/python/samba/upgradehelpers.py953
-rw-r--r--source4/scripting/python/samba/web_server/__init__.py52
-rw-r--r--source4/scripting/python/samba_external/README4
-rw-r--r--source4/scripting/python/uuidmodule.c2
-rw-r--r--source4/scripting/python/wscript_build39
93 files changed, 4234 insertions, 13389 deletions
diff --git a/source4/scripting/python/config.mk b/source4/scripting/python/config.mk
new file mode 100644
index 0000000000..a5e3f25d59
--- /dev/null
+++ b/source4/scripting/python/config.mk
@@ -0,0 +1,35 @@
+[SUBSYSTEM::LIBPYTHON]
+PUBLIC_DEPENDENCIES = EXT_LIB_PYTHON
+PRIVATE_DEPENDENCIES = PYTALLOC
+INIT_FUNCTION_SENTINEL = { NULL, NULL }
+
+LIBPYTHON_OBJ_FILES = $(addprefix $(pyscriptsrcdir)/, modules.o)
+
+[SUBSYSTEM::PYTALLOC]
+PUBLIC_DEPENDENCIES = EXT_LIB_PYTHON LIBTALLOC
+
+PYTALLOC_OBJ_FILES = ../lib/talloc/pytalloc.o
+
+[PYTHON::python_uuid]
+PRIVATE_DEPENDENCIES = LIBNDR
+
+python_uuid_OBJ_FILES = $(pyscriptsrcdir)/uuidmodule.o
+
+[PYTHON::python_glue]
+LIBRARY_REALNAME = samba/glue.$(SHLIBEXT)
+PRIVATE_DEPENDENCIES = LIBNDR LIBLDB SAMDB CREDENTIALS pyldb python_dcerpc_misc python_dcerpc_security pyauth pyldb_util pyparam_util
+
+python_glue_OBJ_FILES = $(pyscriptsrcdir)/pyglue.o
+
+$(python_glue_OBJ_FILES): CFLAGS+=-I$(ldbsrcdir)
+
+_PY_FILES = $(shell find $(pyscriptsrcdir)/samba ../lib/subunit/python -name "*.py")
+
+$(eval $(foreach pyfile, $(_PY_FILES),$(call python_py_module_template,$(patsubst $(pyscriptsrcdir)/%,%,$(subst ../lib/subunit/python,,$(pyfile))),$(pyfile))))
+
+EPYDOC_OPTIONS = --no-private --url http://www.samba.org/ --no-sourcecode
+
+epydoc:: pythonmods
+ PYTHONPATH=$(pythonbuilddir):../lib/subunit/python epydoc $(EPYDOC_OPTIONS) samba tdb ldb subunit
+
+install:: installpython
diff --git a/source4/scripting/python/examples/netbios.py b/source4/scripting/python/examples/netbios.py
index a29b09f051..3671076a59 100644
--- a/source4/scripting/python/examples/netbios.py
+++ b/source4/scripting/python/examples/netbios.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
# Unix SMB/CIFS implementation.
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
diff --git a/source4/scripting/python/examples/samr.py b/source4/scripting/python/examples/samr.py
index 9b8e31e434..c0e3167a97 100755
--- a/source4/scripting/python/examples/samr.py
+++ b/source4/scripting/python/examples/samr.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
# -*- coding: utf-8 -*-
# Unix SMB/CIFS implementation.
diff --git a/source4/scripting/python/examples/winreg.py b/source4/scripting/python/examples/winreg.py
index 484a69b842..80b48ecfd7 100755
--- a/source4/scripting/python/examples/winreg.py
+++ b/source4/scripting/python/examples/winreg.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
#
# tool to manipulate a remote registry
# Copyright Andrew Tridgell 2005
diff --git a/source4/scripting/python/modules.c b/source4/scripting/python/modules.c
index 78cdbc0d87..e53f4cfaf2 100644
--- a/source4/scripting/python/modules.c
+++ b/source4/scripting/python/modules.c
@@ -17,47 +17,54 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <Python.h>
#include "includes.h"
#include "scripting/python/modules.h"
-#include "dynconfig/dynconfig.h"
+#include <Python.h>
-static bool PySys_PathPrepend(PyObject *list, const char *path)
-{
- PyObject *py_path = PyString_FromString(path);
- if (py_path == NULL)
- return false;
+extern void init_ldb(void);
+extern void init_security(void);
+extern void init_registry(void);
+extern void init_param(void);
+extern void init_misc(void);
+extern void init_ldb(void);
+extern void init_auth(void);
+extern void init_credentials(void);
+extern void init_tdb(void);
+extern void init_dcerpc(void);
+extern void init_events(void);
+extern void inituuid(void);
+extern void init_net(void);
+extern void initecho(void);
+extern void initdfs(void);
+extern void initdrsuapi(void);
+extern void initwinreg(void);
+extern void initepmapper(void);
+extern void initinitshutdown(void);
+extern void initmgmt(void);
+extern void initnet(void);
+extern void initatsvc(void);
+extern void initsamr(void);
+extern void initlsa(void);
+extern void initsvcctl(void);
+extern void initwkssvc(void);
+extern void initunixinfo(void);
+extern void init_libcli_nbt(void);
+extern void init_libcli_smb(void);
- return (PyList_Insert(list, 0, py_path) == 0);
-}
+static struct _inittab py_modules[] = { STATIC_LIBPYTHON_MODULES };
-bool py_update_path(void)
+void py_load_samba_modules(void)
{
- PyObject *mod_sys, *py_path;
-
- mod_sys = PyImport_ImportModule("sys");
- if (mod_sys == NULL) {
- return false;
- }
-
- py_path = PyObject_GetAttrString(mod_sys, "path");
- if (py_path == NULL) {
- return false;
- }
-
- if (!PyList_Check(py_path)) {
- return false;
- }
-
- if (!PySys_PathPrepend(py_path, dyn_PYTHONDIR)) {
- return false;
- }
-
- if (strcmp(dyn_PYTHONARCHDIR, dyn_PYTHONDIR) != 0) {
- if (!PySys_PathPrepend(py_path, dyn_PYTHONARCHDIR)) {
- return false;
- }
+ int i;
+ for (i = 0; i < ARRAY_SIZE(py_modules); i++) {
+ PyImport_ExtendInittab(&py_modules[i]);
}
+}
- return true;
+void py_update_path(const char *bindir)
+{
+ char *newpath;
+ asprintf(&newpath, "%s/python:%s/../scripting/python:%s", bindir, bindir, Py_GetPath());
+ PySys_SetPath(newpath);
+ free(newpath);
}
diff --git a/source4/scripting/python/modules.h b/source4/scripting/python/modules.h
index e7e97aa1bf..6b242ee257 100644
--- a/source4/scripting/python/modules.h
+++ b/source4/scripting/python/modules.h
@@ -20,6 +20,9 @@
#ifndef __SAMBA_PYTHON_MODULES_H__
#define __SAMBA_PYTHON_MODULES_H__
-bool py_update_path(void);
+void py_load_samba_modules(void);
+void py_update_path(const char *bindir);
+
+#define py_iconv_convenience(mem_ctx) smb_iconv_convenience_init(mem_ctx, "ASCII", PyUnicode_GetDefaultEncoding(), true)
#endif /* __SAMBA_PYTHON_MODULES_H__ */
diff --git a/source4/scripting/python/pyglue.c b/source4/scripting/python/pyglue.c
index f89785f971..753f2df464 100644
--- a/source4/scripting/python/pyglue.c
+++ b/source4/scripting/python/pyglue.c
@@ -17,13 +17,55 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <Python.h>
#include "includes.h"
+#include "ldb.h"
+#include "ldb_errors.h"
+#include "ldb_wrap.h"
+#include "param/param.h"
+#include "auth/credentials/credentials.h"
+#include "dsdb/samdb/samdb.h"
+#include "lib/ldb-samba/ldif_handlers.h"
+#include "librpc/ndr/libndr.h"
#include "version.h"
+#include <Python.h>
+#include "lib/ldb/pyldb.h"
+#include "libcli/util/pyerrors.h"
+#include "libcli/security/security.h"
+#include "auth/pyauth.h"
#include "param/pyparam.h"
-#include "lib/socket/netif.h"
+#include "auth/credentials/pycredentials.h"
+
+#ifndef Py_RETURN_NONE
+#define Py_RETURN_NONE return Py_INCREF(Py_None), Py_None
+#endif
+
+/* FIXME: These should be in a header file somewhere, once we finish moving
+ * away from SWIG .. */
+#define PyErr_LDB_OR_RAISE(py_ldb, ldb) \
+/* if (!PyLdb_Check(py_ldb)) { \
+ PyErr_SetString(py_ldb_get_exception(), "Ldb connection object required"); \
+ return NULL; \
+ } */\
+ ldb = PyLdb_AsLdbContext(py_ldb);
+
+static void PyErr_SetLdbError(PyObject *error, int ret, struct ldb_context *ldb_ctx)
+{
+ if (ret == LDB_ERR_PYTHON_EXCEPTION)
+ return; /* Python exception should already be set, just keep that */
+
+ PyErr_SetObject(error,
+ Py_BuildValue(discard_const_p(char, "(i,s)"), ret,
+ ldb_ctx == NULL?ldb_strerror(ret):ldb_errstring(ldb_ctx)));
+}
-void init_glue(void);
+static PyObject *py_ldb_get_exception(void)
+{
+ PyObject *mod = PyImport_ImportModule("ldb");
+ if (mod == NULL)
+ return NULL;
+
+ return PyObject_GetAttrString(mod, "LdbError");
+}
static PyObject *py_generate_random_str(PyObject *self, PyObject *args)
{
@@ -39,181 +81,473 @@ static PyObject *py_generate_random_str(PyObject *self, PyObject *args)
return ret;
}
-static PyObject *py_generate_random_password(PyObject *self, PyObject *args)
+static PyObject *py_unix2nttime(PyObject *self, PyObject *args)
+{
+ time_t t;
+ NTTIME nt;
+ if (!PyArg_ParseTuple(args, "I", &t))
+ return NULL;
+
+ unix_to_nt_time(&nt, t);
+
+ return PyInt_FromLong((uint64_t)nt);
+}
+
+static PyObject *py_set_debug_level(PyObject *self, PyObject *args)
+{
+ unsigned level;
+ if (!PyArg_ParseTuple(args, "I", &level))
+ return NULL;
+ (DEBUGLEVEL) = level;
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_set_credentials(PyObject *self, PyObject *args)
+{
+ PyObject *py_creds, *py_ldb;
+ struct cli_credentials *creds;
+ struct ldb_context *ldb;
+ if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_creds))
+ return NULL;
+
+ PyErr_LDB_OR_RAISE(py_ldb, ldb);
+
+ creds = cli_credentials_from_py_object(py_creds);
+ if (creds == NULL) {
+ PyErr_SetString(PyExc_TypeError, "Expected credentials object");
+ return NULL;
+ }
+
+ ldb_set_opaque(ldb, "credentials", creds);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_set_loadparm(PyObject *self, PyObject *args)
{
- int min, max;
+ PyObject *py_lp_ctx, *py_ldb;
+ struct loadparm_context *lp_ctx;
+ struct ldb_context *ldb;
+ if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_lp_ctx))
+ return NULL;
+
+ PyErr_LDB_OR_RAISE(py_ldb, ldb);
+
+ lp_ctx = lp_from_py_object(py_lp_ctx);
+ if (lp_ctx == NULL) {
+ PyErr_SetString(PyExc_TypeError, "Expected loadparm object");
+ return NULL;
+ }
+
+ ldb_set_opaque(ldb, "loadparm", lp_ctx);
+
+ Py_RETURN_NONE;
+}
+
+
+static PyObject *py_ldb_set_session_info(PyObject *self, PyObject *args)
+{
+ PyObject *py_session_info, *py_ldb;
+ struct auth_session_info *info;
+ struct ldb_context *ldb;
+ if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_session_info))
+ return NULL;
+
+ PyErr_LDB_OR_RAISE(py_ldb, ldb);
+ /*if (!PyAuthSession_Check(py_session_info)) {
+ PyErr_SetString(PyExc_TypeError, "Expected session info object");
+ return NULL;
+ }*/
+
+ info = PyAuthSession_AsSession(py_session_info);
+
+ ldb_set_opaque(ldb, "sessionInfo", info);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_ldb_set_utf8_casefold(PyObject *self, PyObject *args)
+{
+ PyObject *py_ldb;
+ struct ldb_context *ldb;
+
+ if (!PyArg_ParseTuple(args, "O", &py_ldb))
+ return NULL;
+
+ PyErr_LDB_OR_RAISE(py_ldb, ldb);
+
+ ldb_set_utf8_fns(ldb, NULL, wrap_casefold);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_samdb_set_domain_sid(PyLdbObject *self, PyObject *args)
+{
+ PyObject *py_ldb, *py_sid;
+ struct ldb_context *ldb;
+ struct dom_sid *sid;
+ bool ret;
+
+ if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_sid))
+ return NULL;
+
+ PyErr_LDB_OR_RAISE(py_ldb, ldb);
+
+ sid = dom_sid_parse_talloc(NULL, PyString_AsString(py_sid));
+
+ ret = samdb_set_domain_sid(ldb, sid);
+ if (!ret) {
+ PyErr_SetString(PyExc_RuntimeError, "set_domain_sid failed");
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_samdb_get_domain_sid(PyLdbObject *self, PyObject *args)
+{
+ PyObject *py_ldb;
+ struct ldb_context *ldb;
+ const struct dom_sid *sid;
PyObject *ret;
char *retstr;
- if (!PyArg_ParseTuple(args, "ii", &min, &max))
+
+ if (!PyArg_ParseTuple(args, "O", &py_ldb))
return NULL;
+
+ PyErr_LDB_OR_RAISE(py_ldb, ldb);
- retstr = generate_random_password(NULL, min, max);
- if (retstr == NULL) {
+ sid = samdb_domain_sid(ldb);
+ if (!sid) {
+ PyErr_SetString(PyExc_RuntimeError, "samdb_domain_sid failed");
return NULL;
- }
+ }
+ retstr = dom_sid_string(NULL, sid);
ret = PyString_FromString(retstr);
talloc_free(retstr);
return ret;
}
-static PyObject *py_unix2nttime(PyObject *self, PyObject *args)
+static PyObject *py_ldb_register_samba_handlers(PyObject *self, PyObject *args)
{
- time_t t;
- NTTIME nt;
- if (!PyArg_ParseTuple(args, "I", &t))
+ PyObject *py_ldb;
+ struct ldb_context *ldb;
+ int ret;
+
+ if (!PyArg_ParseTuple(args, "O", &py_ldb))
return NULL;
- unix_to_nt_time(&nt, t);
+ PyErr_LDB_OR_RAISE(py_ldb, ldb);
+ ret = ldb_register_samba_handlers(ldb);
- return PyLong_FromLongLong((uint64_t)nt);
+ PyErr_LDB_ERROR_IS_ERR_RAISE(py_ldb_get_exception(), ret, ldb);
+ Py_RETURN_NONE;
}
-static PyObject *py_nttime2unix(PyObject *self, PyObject *args)
+static PyObject *py_dsdb_set_ntds_invocation_id(PyObject *self, PyObject *args)
{
- time_t t;
- NTTIME nt;
- if (!PyArg_ParseTuple(args, "K", &nt))
+ PyObject *py_ldb, *py_guid;
+ bool ret;
+ struct GUID guid;
+ struct ldb_context *ldb;
+ if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_guid))
return NULL;
- t = nt_time_to_unix(nt);
+ PyErr_LDB_OR_RAISE(py_ldb, ldb);
+ GUID_from_string(PyString_AsString(py_guid), &guid);
- return PyInt_FromLong((uint64_t)t);
+ ret = samdb_set_ntds_invocation_id(ldb, &guid);
+ if (!ret) {
+ PyErr_SetString(PyExc_RuntimeError, "set_ntds_invocation_id failed");
+ return NULL;
+ }
+ Py_RETURN_NONE;
}
-static PyObject *py_nttime2string(PyObject *self, PyObject *args)
+static PyObject *py_dsdb_set_opaque_integer(PyObject *self, PyObject *args)
{
- PyObject *ret;
- NTTIME nt;
+ PyObject *py_ldb;
+ int value;
+ int *old_val, *new_val;
+ char *py_opaque_name, *opaque_name_talloc;
+ struct ldb_context *ldb;
TALLOC_CTX *tmp_ctx;
- const char *string;
- if (!PyArg_ParseTuple(args, "K", &nt))
+
+ if (!PyArg_ParseTuple(args, "Osi", &py_ldb, &py_opaque_name, &value))
return NULL;
- tmp_ctx = talloc_new(NULL);
+ PyErr_LDB_OR_RAISE(py_ldb, ldb);
+
+ /* see if we have a cached copy */
+ old_val = (int *)ldb_get_opaque(ldb,
+ py_opaque_name);
+
+ if (old_val) {
+ *old_val = value;
+ Py_RETURN_NONE;
+ }
+
+ tmp_ctx = talloc_new(ldb);
if (tmp_ctx == NULL) {
- PyErr_NoMemory();
- return NULL;
+ goto failed;
+ }
+
+ new_val = talloc(tmp_ctx, int);
+ if (!new_val) {
+ goto failed;
+ }
+
+ opaque_name_talloc = talloc_strdup(tmp_ctx, py_opaque_name);
+ if (!opaque_name_talloc) {
+ goto failed;
}
+
+ *new_val = value;
- string = nt_time_string(tmp_ctx, nt);
- ret = PyString_FromString(string);
+ /* cache the domain_sid in the ldb */
+ if (ldb_set_opaque(ldb, opaque_name_talloc, new_val) != LDB_SUCCESS) {
+ goto failed;
+ }
+ talloc_steal(ldb, new_val);
+ talloc_steal(ldb, opaque_name_talloc);
talloc_free(tmp_ctx);
- return ret;
+ Py_RETURN_NONE;
+
+failed:
+ talloc_free(tmp_ctx);
+ PyErr_SetString(PyExc_RuntimeError, "Failed to set opaque integer into the ldb!\n");
+ return NULL;
}
-static PyObject *py_set_debug_level(PyObject *self, PyObject *args)
+static PyObject *py_dsdb_set_global_schema(PyObject *self, PyObject *args)
{
- unsigned level;
- if (!PyArg_ParseTuple(args, "I", &level))
+ PyObject *py_ldb;
+ struct ldb_context *ldb;
+ int ret;
+ if (!PyArg_ParseTuple(args, "O", &py_ldb))
return NULL;
- (DEBUGLEVEL) = level;
+
+ PyErr_LDB_OR_RAISE(py_ldb, ldb);
+
+ ret = dsdb_set_global_schema(ldb);
+ PyErr_LDB_ERROR_IS_ERR_RAISE(py_ldb_get_exception(), ret, ldb);
+
Py_RETURN_NONE;
}
-static PyObject *py_get_debug_level(PyObject *self)
+static PyObject *py_dsdb_set_schema_from_ldif(PyObject *self, PyObject *args)
{
- return PyInt_FromLong(DEBUGLEVEL);
+ WERROR result;
+ char *pf, *df;
+ PyObject *py_ldb;
+ struct ldb_context *ldb;
+
+ if (!PyArg_ParseTuple(args, "Oss", &py_ldb, &pf, &df))
+ return NULL;
+
+ PyErr_LDB_OR_RAISE(py_ldb, ldb);
+
+ result = dsdb_set_schema_from_ldif(ldb, pf, df);
+ PyErr_WERROR_IS_ERR_RAISE(result);
+
+ Py_RETURN_NONE;
}
-/*
- return the list of interface IPs we have configured
- takes an loadparm context, returns a list of IPs in string form
+static PyObject *py_dsdb_convert_schema_to_openldap(PyObject *self, PyObject *args)
+{
+ char *target_str, *mapping;
+ PyObject *py_ldb;
+ struct ldb_context *ldb;
+ PyObject *ret;
+ char *retstr;
+
+ if (!PyArg_ParseTuple(args, "Oss", &py_ldb, &target_str, &mapping))
+ return NULL;
+
+ PyErr_LDB_OR_RAISE(py_ldb, ldb);
+
+ retstr = dsdb_convert_schema_to_openldap(ldb, target_str, mapping);
+ if (!retstr) {
+ PyErr_SetString(PyExc_RuntimeError, "dsdb_convert_schema_to_openldap failed");
+ return NULL;
+ }
+ ret = PyString_FromString(retstr);
+ talloc_free(retstr);
+ return ret;
+}
- Does not return addresses on 127.0.0.0/8
- */
-static PyObject *py_interface_ips(PyObject *self, PyObject *args)
+static PyObject *py_dsdb_write_prefixes_from_schema_to_ldb(PyObject *self, PyObject *args)
{
- PyObject *pylist;
- int count;
- TALLOC_CTX *tmp_ctx;
- PyObject *py_lp_ctx;
- struct loadparm_context *lp_ctx;
- struct interface *ifaces;
- int i, ifcount;
- int all_interfaces;
+ PyObject *py_ldb;
+ struct ldb_context *ldb;
+ WERROR result;
+ struct dsdb_schema *schema;
- if (!PyArg_ParseTuple(args, "Oi", &py_lp_ctx, &all_interfaces))
+ if (!PyArg_ParseTuple(args, "O", &py_ldb))
return NULL;
- tmp_ctx = talloc_new(NULL);
- if (tmp_ctx == NULL) {
- PyErr_NoMemory();
+ PyErr_LDB_OR_RAISE(py_ldb, ldb);
+
+ schema = dsdb_get_schema(ldb);
+ if (!schema) {
+ PyErr_SetString(PyExc_RuntimeError, "Failed to set find a schema on ldb!\n");
return NULL;
}
- lp_ctx = lpcfg_from_py_object(tmp_ctx, py_lp_ctx);
- if (lp_ctx == NULL) {
- talloc_free(tmp_ctx);
+ result = dsdb_write_prefixes_from_schema_to_ldb(NULL, ldb, schema);
+ PyErr_WERROR_IS_ERR_RAISE(result);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_dsdb_set_schema_from_ldb(PyObject *self, PyObject *args)
+{
+ PyObject *py_ldb;
+ struct ldb_context *ldb;
+ PyObject *py_from_ldb;
+ struct ldb_context *from_ldb;
+ struct dsdb_schema *schema;
+ int ret;
+ if (!PyArg_ParseTuple(args, "OO", &py_ldb, &py_from_ldb))
return NULL;
- }
- load_interfaces(tmp_ctx, lpcfg_interfaces(lp_ctx), &ifaces);
+ PyErr_LDB_OR_RAISE(py_ldb, ldb);
- count = iface_count(ifaces);
+ PyErr_LDB_OR_RAISE(py_from_ldb, from_ldb);
- /* first count how many are not loopback addresses */
- for (ifcount = i = 0; i<count; i++) {
- const char *ip = iface_n_ip(ifaces, i);
- if (!(!all_interfaces && iface_same_net(ip, "127.0.0.1", "255.0.0.0"))) {
- ifcount++;
- }
+ schema = dsdb_get_schema(from_ldb);
+ if (!schema) {
+ PyErr_SetString(PyExc_RuntimeError, "Failed to set find a schema on 'from' ldb!\n");
+ return NULL;
}
- pylist = PyList_New(ifcount);
- for (ifcount = i = 0; i<count; i++) {
- const char *ip = iface_n_ip(ifaces, i);
- if (!(!all_interfaces && iface_same_net(ip, "127.0.0.1", "255.0.0.0"))) {
- PyList_SetItem(pylist, ifcount, PyString_FromString(ip));
- ifcount++;
- }
+ ret = dsdb_reference_schema(ldb, schema, true);
+ PyErr_LDB_ERROR_IS_ERR_RAISE(py_ldb_get_exception(), ret, ldb);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *py_dom_sid_to_rid(PyLdbObject *self, PyObject *args)
+{
+ PyObject *py_sid;
+ struct dom_sid *sid;
+ uint32_t rid;
+ NTSTATUS status;
+
+ if(!PyArg_ParseTuple(args, "O", &py_sid))
+ return NULL;
+
+ sid = dom_sid_parse_talloc(NULL, PyString_AsString(py_sid));
+
+ status = dom_sid_split_rid(NULL, sid, NULL, &rid);
+ if (!NT_STATUS_IS_OK(status)) {
+ PyErr_SetString(PyExc_RuntimeError, "dom_sid_split_rid failed");
+ return NULL;
}
- talloc_free(tmp_ctx);
- return pylist;
+
+ return PyInt_FromLong(rid);
}
static PyMethodDef py_misc_methods[] = {
{ "generate_random_str", (PyCFunction)py_generate_random_str, METH_VARARGS,
- "generate_random_str(len) -> string\n"
- "Generate random string with specified length." },
- { "generate_random_password", (PyCFunction)py_generate_random_password,
- METH_VARARGS, "generate_random_password(min, max) -> string\n"
- "Generate random password with a length >= min and <= max." },
+ "random_password(len) -> string\n"
+ "Generate random password with specified length." },
{ "unix2nttime", (PyCFunction)py_unix2nttime, METH_VARARGS,
"unix2nttime(timestamp) -> nttime" },
- { "nttime2unix", (PyCFunction)py_nttime2unix, METH_VARARGS,
- "nttime2unix(nttime) -> timestamp" },
- { "nttime2string", (PyCFunction)py_nttime2string, METH_VARARGS,
- "nttime2string(nttime) -> string" },
+ { "ldb_set_credentials", (PyCFunction)py_ldb_set_credentials, METH_VARARGS,
+ "ldb_set_credentials(ldb, credentials) -> None\n"
+ "Set credentials to use when connecting." },
+ { "ldb_set_session_info", (PyCFunction)py_ldb_set_session_info, METH_VARARGS,
+ "ldb_set_session_info(ldb, session_info)\n"
+ "Set session info to use when connecting." },
+ { "ldb_set_loadparm", (PyCFunction)py_ldb_set_loadparm, METH_VARARGS,
+ "ldb_set_loadparm(ldb, session_info)\n"
+ "Set loadparm context to use when connecting." },
+ { "samdb_set_domain_sid", (PyCFunction)py_samdb_set_domain_sid, METH_VARARGS,
+ "samdb_set_domain_sid(samdb, sid)\n"
+ "Set SID of domain to use." },
+ { "samdb_get_domain_sid", (PyCFunction)py_samdb_get_domain_sid, METH_VARARGS,
+ "samdb_get_domain_sid(samdb)\n"
+ "Get SID of domain in use." },
+ { "ldb_register_samba_handlers", (PyCFunction)py_ldb_register_samba_handlers, METH_VARARGS,
+ "ldb_register_samba_handlers(ldb)\n"
+ "Register Samba-specific LDB modules and schemas." },
+ { "ldb_set_utf8_casefold", (PyCFunction)py_ldb_set_utf8_casefold, METH_VARARGS,
+ "ldb_set_utf8_casefold(ldb)\n"
+ "Set the right Samba casefolding function for UTF8 charset." },
+ { "dsdb_set_ntds_invocation_id", (PyCFunction)py_dsdb_set_ntds_invocation_id, METH_VARARGS,
+ NULL },
+ { "dsdb_set_opaque_integer", (PyCFunction)py_dsdb_set_opaque_integer, METH_VARARGS,
+ NULL },
+ { "dsdb_set_global_schema", (PyCFunction)py_dsdb_set_global_schema, METH_VARARGS,
+ NULL },
+ { "dsdb_set_schema_from_ldif", (PyCFunction)py_dsdb_set_schema_from_ldif, METH_VARARGS,
+ NULL },
+ { "dsdb_write_prefixes_from_schema_to_ldb", (PyCFunction)py_dsdb_write_prefixes_from_schema_to_ldb, METH_VARARGS,
+ NULL },
+ { "dsdb_set_schema_from_ldb", (PyCFunction)py_dsdb_set_schema_from_ldb, METH_VARARGS,
+ NULL },
+ { "dsdb_convert_schema_to_openldap", (PyCFunction)py_dsdb_convert_schema_to_openldap, METH_VARARGS,
+ NULL },
+ { "dom_sid_to_rid", (PyCFunction)py_dom_sid_to_rid, METH_VARARGS,
+ NULL },
{ "set_debug_level", (PyCFunction)py_set_debug_level, METH_VARARGS,
"set debug level" },
- { "get_debug_level", (PyCFunction)py_get_debug_level, METH_NOARGS,
- "get debug level" },
- { "interface_ips", (PyCFunction)py_interface_ips, METH_VARARGS,
- "get interface IP address list"},
{ NULL }
};
-void init_glue(void)
+void initglue(void)
{
PyObject *m;
- debug_setup_talloc_log();
-
- m = Py_InitModule3("_glue", py_misc_methods,
+ m = Py_InitModule3("glue", py_misc_methods,
"Python bindings for miscellaneous Samba functions.");
if (m == NULL)
return;
- PyModule_AddObject(m, "version",
- PyString_FromString(SAMBA_VERSION_STRING));
-
- /* one of the most annoying things about python scripts is
- that they don't die when you hit control-C. This fixes that
- sillyness. As we do all database operations using
- transactions, this is also safe.
- */
- signal(SIGINT, SIG_DFL);
+ PyModule_AddObject(m, "version", PyString_FromString(SAMBA_VERSION_STRING));
+
+ /* "userAccountControl" flags */
+ PyModule_AddObject(m, "UF_NORMAL_ACCOUNT", PyInt_FromLong(UF_NORMAL_ACCOUNT));
+ PyModule_AddObject(m, "UF_TEMP_DUPLICATE_ACCOUNT", PyInt_FromLong(UF_TEMP_DUPLICATE_ACCOUNT));
+ PyModule_AddObject(m, "UF_SERVER_TRUST_ACCOUNT", PyInt_FromLong(UF_SERVER_TRUST_ACCOUNT));
+ PyModule_AddObject(m, "UF_WORKSTATION_TRUST_ACCOUNT", PyInt_FromLong(UF_WORKSTATION_TRUST_ACCOUNT));
+ PyModule_AddObject(m, "UF_INTERDOMAIN_TRUST_ACCOUNT", PyInt_FromLong(UF_INTERDOMAIN_TRUST_ACCOUNT));
+ PyModule_AddObject(m, "UF_PASSWD_NOTREQD", PyInt_FromLong(UF_PASSWD_NOTREQD));
+ PyModule_AddObject(m, "UF_ACCOUNTDISABLE", PyInt_FromLong(UF_ACCOUNTDISABLE));
+
+ /* "groupType" flags */
+ PyModule_AddObject(m, "GTYPE_SECURITY_BUILTIN_LOCAL_GROUP", PyInt_FromLong(GTYPE_SECURITY_BUILTIN_LOCAL_GROUP));
+ PyModule_AddObject(m, "GTYPE_SECURITY_GLOBAL_GROUP", PyInt_FromLong(GTYPE_SECURITY_GLOBAL_GROUP));
+ PyModule_AddObject(m, "GTYPE_SECURITY_DOMAIN_LOCAL_GROUP", PyInt_FromLong(GTYPE_SECURITY_DOMAIN_LOCAL_GROUP));
+ PyModule_AddObject(m, "GTYPE_SECURITY_UNIVERSAL_GROUP", PyInt_FromLong(GTYPE_SECURITY_UNIVERSAL_GROUP));
+ PyModule_AddObject(m, "GTYPE_DISTRIBUTION_GLOBAL_GROUP", PyInt_FromLong(GTYPE_DISTRIBUTION_GLOBAL_GROUP));
+ PyModule_AddObject(m, "GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP", PyInt_FromLong(GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP));
+ PyModule_AddObject(m, "GTYPE_DISTRIBUTION_UNIVERSAL_GROUP", PyInt_FromLong(GTYPE_DISTRIBUTION_UNIVERSAL_GROUP));
+
+ /* "sAMAccountType" flags */
+ PyModule_AddObject(m, "ATYPE_NORMAL_ACCOUNT", PyInt_FromLong(ATYPE_NORMAL_ACCOUNT));
+ PyModule_AddObject(m, "ATYPE_WORKSTATION_TRUST", PyInt_FromLong(ATYPE_WORKSTATION_TRUST));
+ PyModule_AddObject(m, "ATYPE_INTERDOMAIN_TRUST", PyInt_FromLong(ATYPE_INTERDOMAIN_TRUST));
+ PyModule_AddObject(m, "ATYPE_SECURITY_GLOBAL_GROUP", PyInt_FromLong(ATYPE_SECURITY_GLOBAL_GROUP));
+ PyModule_AddObject(m, "ATYPE_SECURITY_LOCAL_GROUP", PyInt_FromLong(ATYPE_SECURITY_LOCAL_GROUP));
+ PyModule_AddObject(m, "ATYPE_SECURITY_UNIVERSAL_GROUP", PyInt_FromLong(ATYPE_SECURITY_UNIVERSAL_GROUP));
+ PyModule_AddObject(m, "ATYPE_DISTRIBUTION_GLOBAL_GROUP", PyInt_FromLong(ATYPE_DISTRIBUTION_GLOBAL_GROUP));
+ PyModule_AddObject(m, "ATYPE_DISTRIBUTION_LOCAL_GROUP", PyInt_FromLong(ATYPE_DISTRIBUTION_LOCAL_GROUP));
+ PyModule_AddObject(m, "ATYPE_DISTRIBUTION_UNIVERSAL_GROUP", PyInt_FromLong(ATYPE_DISTRIBUTION_UNIVERSAL_GROUP));
+
+ /* "domainFunctionality", "forestFunctionality" flags in the rootDSE */
+ PyModule_AddObject(m, "DS_DOMAIN_FUNCTION_2000", PyInt_FromLong(DS_DOMAIN_FUNCTION_2000));
+ PyModule_AddObject(m, "DS_DOMAIN_FUNCTION_2003_MIXED", PyInt_FromLong(DS_DOMAIN_FUNCTION_2003_MIXED));
+ PyModule_AddObject(m, "DS_DOMAIN_FUNCTION_2003", PyInt_FromLong(DS_DOMAIN_FUNCTION_2003));
+ PyModule_AddObject(m, "DS_DOMAIN_FUNCTION_2008", PyInt_FromLong(DS_DOMAIN_FUNCTION_2008));
+ PyModule_AddObject(m, "DS_DOMAIN_FUNCTION_2008_R2", PyInt_FromLong(DS_DOMAIN_FUNCTION_2008_R2));
+
+ /* "domainControllerFunctionality" flags in the rootDSE */
+ PyModule_AddObject(m, "DS_DC_FUNCTION_2000", PyInt_FromLong(DS_DC_FUNCTION_2000));
+ PyModule_AddObject(m, "DS_DC_FUNCTION_2003", PyInt_FromLong(DS_DC_FUNCTION_2003));
+ PyModule_AddObject(m, "DS_DC_FUNCTION_2008", PyInt_FromLong(DS_DC_FUNCTION_2008));
+ PyModule_AddObject(m, "DS_DC_FUNCTION_2008_R2", PyInt_FromLong(DS_DC_FUNCTION_2008_R2));
}
diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py
index 2a54f47d2b..82df4960cf 100644
--- a/source4/scripting/python/samba/__init__.py
+++ b/source4/scripting/python/samba/__init__.py
@@ -1,21 +1,21 @@
-#!/usr/bin/env python
+#!/usr/bin/python
# Unix SMB/CIFS implementation.
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
-#
+#
# Based on the original in EJS:
# Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
-#
+#
# 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/>.
#
@@ -25,39 +25,33 @@
__docformat__ = "restructuredText"
import os
-import sys
-
-def source_tree_topdir():
- '''return the top level directory (the one containing the source4 directory)'''
- paths = [ "../../..", "../../../.." ]
- for p in paths:
- topdir = os.path.normpath(os.path.join(os.path.dirname(__file__), p))
- if os.path.exists(os.path.join(topdir, 'source4')):
- return topdir
- raise RuntimeError("unable to find top level source directory")
-
-def in_source_tree():
- '''return True if we are running from within the samba source tree'''
- try:
- topdir = source_tree_topdir()
- except RuntimeError:
- return False
- return True
+def _in_source_tree():
+ """Check whether the script is being run from the source dir. """
+ return os.path.exists("%s/../../../selftest/skip" % os.path.dirname(__file__))
+
+
+# When running, in-tree, make sure bin/python is in the PYTHONPATH
+if _in_source_tree():
+ import sys
+ srcdir = "%s/../../.." % os.path.dirname(__file__)
+ sys.path.append("%s/bin/python" % srcdir)
+ default_ldb_modules_dir = "%s/bin/modules/ldb" % srcdir
+else:
+ default_ldb_modules_dir = None
import ldb
-from samba._ldb import Ldb as _Ldb
+import glue
-class Ldb(_Ldb):
- """Simple Samba-specific LDB subclass that takes care
+class Ldb(ldb.Ldb):
+ """Simple Samba-specific LDB subclass that takes care
of setting up the modules dir, credentials pointers, etc.
-
- Please note that this is intended to be for all Samba LDB files,
- not necessarily the Sam database. For Sam-specific helper
+
+ Please note that this is intended to be for all Samba LDB files,
+ not necessarily the Sam database. For Sam-specific helper
functions see samdb.py.
"""
-
def __init__(self, url=None, lp=None, modules_dir=None, session_info=None,
credentials=None, flags=0, options=None):
"""Opens a Samba Ldb file.
@@ -71,12 +65,14 @@ class Ldb(_Ldb):
:param options: Additional options (optional)
This is different from a regular Ldb file in that the Samba-specific
- modules-dir is used by default and that credentials and session_info
+ modules-dir is used by default and that credentials and session_info
can be passed through (required by some modules).
"""
if modules_dir is not None:
self.set_modules_dir(modules_dir)
+ elif default_ldb_modules_dir is not None:
+ self.set_modules_dir(default_ldb_modules_dir)
elif lp is not None:
self.set_modules_dir(os.path.join(lp.get("modules dir"), "ldb"))
@@ -92,30 +88,37 @@ class Ldb(_Ldb):
# This must be done before we load the schema, as these handlers for
# objectSid and objectGUID etc must take precedence over the 'binary
# attribute' declaration in the schema
- self.register_samba_handlers()
+ glue.ldb_register_samba_handlers(self)
# TODO set debug
- def msg(l, text):
+ def msg(l,text):
print text
#self.set_debug(msg)
- self.set_utf8_casefold()
+ glue.ldb_set_utf8_casefold(self)
# Allow admins to force non-sync ldb for all databases
if lp is not None:
nosync_p = lp.get("nosync", "ldb")
- if nosync_p is not None and nosync_p == True:
- flags |= ldb.FLG_NOSYNC
-
- self.set_create_perms(0600)
+ if nosync_p is not None and nosync_p == true:
+ flags |= FLG_NOSYNC
if url is not None:
self.connect(url, flags, options)
- def searchone(self, attribute, basedn=None, expression=None,
+ def set_credentials(self, credentials):
+ glue.ldb_set_credentials(self, credentials)
+
+ def set_session_info(self, session_info):
+ glue.ldb_set_session_info(self, session_info)
+
+ def set_loadparm(self, lp_ctx):
+ glue.ldb_set_loadparm(self, lp_ctx)
+
+ def searchone(self, attribute, basedn=None, expression=None,
scope=ldb.SCOPE_BASE):
"""Search for one attribute as a string.
-
+
:param basedn: BaseDN for the search.
:param attribute: Name of the attribute
:param expression: Optional search expression.
@@ -130,36 +133,25 @@ class Ldb(_Ldb):
return self.schema_format_value(attribute, values.pop())
def erase_users_computers(self, dn):
- """Erases user and computer objects from our AD.
-
- This is needed since the 'samldb' module denies the deletion of primary
- groups. Therefore all groups shouldn't be primary somewhere anymore.
- """
+ """Erases user and computer objects from our AD. This is needed since the 'samldb' module denies the deletion of primary groups. Therefore all groups shouldn't be primary somewhere anymore."""
try:
res = self.search(base=dn, scope=ldb.SCOPE_SUBTREE, attrs=[],
expression="(|(objectclass=user)(objectclass=computer))")
- except ldb.LdbError, (errno, _):
- if errno == ldb.ERR_NO_SUCH_OBJECT:
- # Ignore no such object errors
- return
- else:
- raise
+ except ldb.LdbError, (ldb.ERR_NO_SUCH_OBJECT, _):
+ # Ignore no such object errors
+ return
+ pass
try:
for msg in res:
- self.delete(msg.dn, ["relax:0"])
- except ldb.LdbError, (errno, _):
- if errno != ldb.ERR_NO_SUCH_OBJECT:
- # Ignore no such object errors
- raise
+ self.delete(msg.dn)
+ except ldb.LdbError, (ldb.ERR_NO_SUCH_OBJECT, _):
+ # Ignore no such object errors
+ return
def erase_except_schema_controlled(self):
- """Erase this ldb.
-
- :note: Removes all records, except those that are controlled by
- Samba4's schema.
- """
+ """Erase this ldb, removing all records, except those that are controlled by Samba4's schema."""
basedn = ""
@@ -167,42 +159,73 @@ class Ldb(_Ldb):
self.erase_users_computers(basedn)
# Delete the 'visible' records, and the invisble 'deleted' records (if this DB supports it)
- for msg in self.search(basedn, ldb.SCOPE_SUBTREE,
- "(&(|(objectclass=*)(distinguishedName=*))(!(distinguishedName=@BASEINFO)))",
- [], controls=["show_deleted:0", "show_recycled:0"]):
+ for msg in self.search(basedn, ldb.SCOPE_SUBTREE,
+ "(&(|(objectclass=*)(distinguishedName=*))(!(distinguishedName=@BASEINFO)))",
+ [], controls=["show_deleted:0"]):
try:
- self.delete(msg.dn, ["relax:0"])
- except ldb.LdbError, (errno, _):
- if errno != ldb.ERR_NO_SUCH_OBJECT:
- # Ignore no such object errors
- raise
-
- res = self.search(basedn, ldb.SCOPE_SUBTREE,
- "(&(|(objectclass=*)(distinguishedName=*))(!(distinguishedName=@BASEINFO)))", [], controls=["show_deleted:0", "show_recycled:0"])
+ self.delete(msg.dn)
+ except ldb.LdbError, (ldb.ERR_NO_SUCH_OBJECT, _):
+ # Ignore no such object errors
+ pass
+
+ res = self.search(basedn, ldb.SCOPE_SUBTREE,
+ "(&(|(objectclass=*)(distinguishedName=*))(!(distinguishedName=@BASEINFO)))",
+ [], controls=["show_deleted:0"])
assert len(res) == 0
# delete the specials
- for attr in ["@SUBCLASSES", "@MODULES",
+ for attr in ["@SUBCLASSES", "@MODULES",
"@OPTIONS", "@PARTITION", "@KLUDGEACL"]:
try:
- self.delete(attr, ["relax:0"])
- except ldb.LdbError, (errno, _):
- if errno != ldb.ERR_NO_SUCH_OBJECT:
- # Ignore missing dn errors
- raise
+ self.delete(attr)
+ except ldb.LdbError, (ldb.ERR_NO_SUCH_OBJECT, _):
+ # Ignore missing dn errors
+ pass
def erase(self):
"""Erase this ldb, removing all records."""
+
self.erase_except_schema_controlled()
# delete the specials
for attr in ["@INDEXLIST", "@ATTRIBUTES"]:
try:
- self.delete(attr, ["relax:0"])
- except ldb.LdbError, (errno, _):
- if errno != ldb.ERR_NO_SUCH_OBJECT:
- # Ignore missing dn errors
- raise
+ self.delete(attr)
+ except ldb.LdbError, (ldb.ERR_NO_SUCH_OBJECT, _):
+ # Ignore missing dn errors
+ pass
+
+ def erase_partitions(self):
+ """Erase an ldb, removing all records."""
+
+ def erase_recursive(self, dn):
+ try:
+ res = self.search(base=dn, scope=ldb.SCOPE_ONELEVEL, attrs=[],
+ controls=["show_deleted:0"])
+ except ldb.LdbError, (ldb.ERR_NO_SUCH_OBJECT, _):
+ # Ignore no such object errors
+ return
+ pass
+
+ for msg in res:
+ erase_recursive(self, msg.dn)
+
+ try:
+ self.delete(dn)
+ except ldb.LdbError, (ldb.ERR_NO_SUCH_OBJECT, _):
+ # Ignore no such object errors
+ pass
+
+ res = self.search("", ldb.SCOPE_BASE, "(objectClass=*)",
+ ["namingContexts"])
+ assert len(res) == 1
+ if not "namingContexts" in res[0]:
+ return
+ for basedn in res[0]["namingContexts"]:
+ # Try to delete user/computer accounts to allow deletion of groups
+ self.erase_users_computers(basedn)
+ # Try and erase from the bottom-up in the tree
+ erase_recursive(self, basedn)
def load_ldif_file_add(self, ldif_path):
"""Load a LDIF file.
@@ -211,31 +234,68 @@ class Ldb(_Ldb):
"""
self.add_ldif(open(ldif_path, 'r').read())
- def add_ldif(self, ldif, controls=None):
+ def add_ldif(self, ldif):
"""Add data based on a LDIF string.
:param ldif: LDIF text.
"""
for changetype, msg in self.parse_ldif(ldif):
assert changetype == ldb.CHANGETYPE_NONE
- self.add(msg, controls)
+ self.add(msg)
- def modify_ldif(self, ldif, controls=None):
+ def modify_ldif(self, ldif):
"""Modify database based on a LDIF string.
:param ldif: LDIF text.
"""
for changetype, msg in self.parse_ldif(ldif):
- if changetype == ldb.CHANGETYPE_ADD:
- self.add(msg, controls)
- else:
- self.modify(msg, controls)
+ self.modify(msg)
+ def set_domain_sid(self, sid):
+ """Change the domain SID used by this LDB.
-def substitute_var(text, values):
- """Substitute strings of the form ${NAME} in str, replacing
- with substitutions from values.
+ :param sid: The new domain sid to use.
+ """
+ glue.samdb_set_domain_sid(self, sid)
+
+ def domain_sid(self):
+ """Read the domain SID used by this LDB.
+
+ """
+ glue.samdb_get_domain_sid(self)
+
+ def set_schema_from_ldif(self, pf, df):
+ glue.dsdb_set_schema_from_ldif(self, pf, df)
+
+ def set_schema_from_ldb(self, ldb):
+ glue.dsdb_set_schema_from_ldb(self, ldb)
+
+ def write_prefixes_from_schema(self):
+ glue.dsdb_write_prefixes_from_schema_to_ldb(self)
+ def convert_schema_to_openldap(self, target, mapping):
+ return glue.dsdb_convert_schema_to_openldap(self, target, mapping)
+
+ def set_invocation_id(self, invocation_id):
+ """Set the invocation id for this SamDB handle.
+
+ :param invocation_id: GUID of the invocation id.
+ """
+ glue.dsdb_set_ntds_invocation_id(self, invocation_id)
+
+ def set_opaque_integer(self, name, value):
+ """Set an integer as an opaque (a flag or other value) value on the database
+
+ :param name: The name for the opaque value
+ :param value: The integer value
+ """
+ glue.dsdb_set_opaque_integer(self, name, value)
+
+
+def substitute_var(text, values):
+ """substitute strings of the form ${NAME} in str, replacing
+ with substitutions from subobj.
+
:param text: Text in which to subsitute.
:param values: Dictionary with keys and values.
"""
@@ -249,51 +309,18 @@ def substitute_var(text, values):
def check_all_substituted(text):
- """Check that all substitution variables in a string have been replaced.
-
+ """Make sure that all substitution variables in a string have been replaced.
If not, raise an exception.
-
+
:param text: The text to search for substitution variables
"""
if not "${" in text:
return
-
+
var_start = text.find("${")
var_end = text.find("}", var_start)
-
- raise Exception("Not all variables substituted: %s" %
- text[var_start:var_end+1])
-
-
-def read_and_sub_file(file_name, subst_vars):
- """Read a file and sub in variables found in it
-
- :param file_name: File to be read (typically from setup directory)
- param subst_vars: Optional variables to subsitute in the file.
- """
- data = open(file_name, 'r').read()
- if subst_vars is not None:
- data = substitute_var(data, subst_vars)
- check_all_substituted(data)
- return data
-
-
-def setup_file(template, fname, subst_vars=None):
- """Setup a file in the private dir.
-
- :param template: Path of the template file.
- :param fname: Path of the file to create.
- :param subst_vars: Substitution variables.
- """
- if os.path.exists(fname):
- os.unlink(fname)
-
- data = read_and_sub_file(template, subst_vars)
- f = open(fname, 'w')
- try:
- f.write(data)
- finally:
- f.close()
+
+ raise Exception("Not all variables substituted: %s" % text[var_start:var_end+1])
def valid_netbios_name(name):
@@ -307,44 +334,56 @@ def valid_netbios_name(name):
return True
-def import_bundled_package(modulename, location):
- """Import the bundled version of a package.
+def dom_sid_to_rid(sid_str):
+ """Converts a domain SID to the relative RID.
- :note: This should only be called if the system version of the package
- is not adequate.
-
- :param modulename: Module name to import
- :param location: Location to add to sys.path (can be relative to
- ${srcdir}/lib)
+ :param sid_str: The domain SID formatted as string
"""
- if in_source_tree():
- sys.path.insert(0, os.path.join(source_tree_topdir(), "lib", location))
- sys.modules[modulename] = __import__(modulename)
- else:
- sys.modules[modulename] = __import__(
- "samba.external.%s" % modulename, fromlist=["samba.external"])
-
-def ensure_external_module(modulename, location):
- """Add a location to sys.path if an external dependency can't be found.
+ return glue.dom_sid_to_rid(sid_str)
+
+
+version = glue.version
+
+# "userAccountControl" flags
+UF_NORMAL_ACCOUNT = glue.UF_NORMAL_ACCOUNT
+UF_TEMP_DUPLICATE_ACCOUNT = glue.UF_TEMP_DUPLICATE_ACCOUNT
+UF_SERVER_TRUST_ACCOUNT = glue.UF_SERVER_TRUST_ACCOUNT
+UF_WORKSTATION_TRUST_ACCOUNT = glue.UF_WORKSTATION_TRUST_ACCOUNT
+UF_INTERDOMAIN_TRUST_ACCOUNT = glue.UF_INTERDOMAIN_TRUST_ACCOUNT
+UF_PASSWD_NOTREQD = glue.UF_PASSWD_NOTREQD
+UF_ACCOUNTDISABLE = glue.UF_ACCOUNTDISABLE
+
+# "groupType" flags
+GTYPE_SECURITY_BUILTIN_LOCAL_GROUP = glue.GTYPE_SECURITY_BUILTIN_LOCAL_GROUP
+GTYPE_SECURITY_GLOBAL_GROUP = glue.GTYPE_SECURITY_GLOBAL_GROUP
+GTYPE_SECURITY_DOMAIN_LOCAL_GROUP = glue.GTYPE_SECURITY_DOMAIN_LOCAL_GROUP
+GTYPE_SECURITY_UNIVERSAL_GROUP = glue.GTYPE_SECURITY_UNIVERSAL_GROUP
+GTYPE_DISTRIBUTION_GLOBAL_GROUP = glue.GTYPE_DISTRIBUTION_GLOBAL_GROUP
+GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP = glue.GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP
+GTYPE_DISTRIBUTION_UNIVERSAL_GROUP = glue.GTYPE_DISTRIBUTION_UNIVERSAL_GROUP
+
+# "sAMAccountType" flags
+ATYPE_NORMAL_ACCOUNT = glue.ATYPE_NORMAL_ACCOUNT
+ATYPE_WORKSTATION_TRUST = glue.ATYPE_WORKSTATION_TRUST
+ATYPE_INTERDOMAIN_TRUST = glue.ATYPE_INTERDOMAIN_TRUST
+ATYPE_SECURITY_GLOBAL_GROUP = glue.ATYPE_SECURITY_GLOBAL_GROUP
+ATYPE_SECURITY_LOCAL_GROUP = glue.ATYPE_SECURITY_LOCAL_GROUP
+ATYPE_SECURITY_UNIVERSAL_GROUP = glue.ATYPE_SECURITY_UNIVERSAL_GROUP
+ATYPE_DISTRIBUTION_GLOBAL_GROUP = glue.ATYPE_DISTRIBUTION_GLOBAL_GROUP
+ATYPE_DISTRIBUTION_LOCAL_GROUP = glue.ATYPE_DISTRIBUTION_LOCAL_GROUP
+ATYPE_DISTRIBUTION_UNIVERSAL_GROUP = glue.ATYPE_DISTRIBUTION_UNIVERSAL_GROUP
+
+# "domainFunctionality", "forestFunctionality" flags in the rootDSE */
+DS_DOMAIN_FUNCTION_2000 = glue.DS_DOMAIN_FUNCTION_2000
+DS_DOMAIN_FUNCTION_2003_MIXED = glue.DS_DOMAIN_FUNCTION_2003_MIXED
+DS_DOMAIN_FUNCTION_2003 = glue.DS_DOMAIN_FUNCTION_2003
+DS_DOMAIN_FUNCTION_2008 = glue.DS_DOMAIN_FUNCTION_2008
+DS_DOMAIN_FUNCTION_2008_R2 = glue.DS_DOMAIN_FUNCTION_2008_R2
+
+# "domainControllerFunctionality" flags in the rootDSE */
+DS_DC_FUNCTION_2000 = glue.DS_DC_FUNCTION_2000
+DS_DC_FUNCTION_2003 = glue.DS_DC_FUNCTION_2003
+DS_DC_FUNCTION_2008 = glue.DS_DC_FUNCTION_2008
+DS_DC_FUNCTION_2008_R2 = glue.DS_DC_FUNCTION_2008_R2
- :param modulename: Module name to import
- :param location: Location to add to sys.path (can be relative to
- ${srcdir}/lib)
- """
- try:
- __import__(modulename)
- except ImportError:
- import_bundled_package(modulename, location)
-
-
-from samba import _glue
-version = _glue.version
-interface_ips = _glue.interface_ips
-set_debug_level = _glue.set_debug_level
-get_debug_level = _glue.get_debug_level
-unix2nttime = _glue.unix2nttime
-nttime2string = _glue.nttime2string
-nttime2unix = _glue.nttime2unix
-unix2nttime = _glue.unix2nttime
-generate_random_password = _glue.generate_random_password
diff --git a/source4/scripting/python/samba/drs_utils.py b/source4/scripting/python/samba/drs_utils.py
deleted file mode 100644
index 77f415ed17..0000000000
--- a/source4/scripting/python/samba/drs_utils.py
+++ /dev/null
@@ -1,173 +0,0 @@
-#!/usr/bin/env python
-#
-# DRS utility code
-#
-# Copyright Andrew Tridgell 2010
-# Copyright Andrew Bartlett 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/>.
-#
-
-from samba.dcerpc import drsuapi, misc
-from samba.net import Net
-import samba, ldb
-
-
-def drs_DsBind(drs):
- '''make a DsBind call, returning the binding handle'''
- bind_info = drsuapi.DsBindInfoCtr()
- bind_info.length = 28
- bind_info.info = drsuapi.DsBindInfo28()
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_BASE
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7
- bind_info.info.supported_extensions |= drsuapi.DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT
- (info, handle) = drs.DsBind(misc.GUID(drsuapi.DRSUAPI_DS_BIND_GUID), bind_info)
-
- return (handle, info.info.supported_extensions)
-
-
-class drs_Replicate:
- '''DRS replication calls'''
-
- def __init__(self, binding_string, lp, creds, samdb):
- self.drs = drsuapi.drsuapi(binding_string, lp, creds)
- (self.drs_handle, self.supported_extensions) = drs_DsBind(self.drs)
- self.net = Net(creds=creds, lp=lp)
- self.samdb = samdb
- self.replication_state = self.net.replicate_init(self.samdb, lp, self.drs)
-
- def drs_get_rodc_partial_attribute_set(self):
- '''get a list of attributes for RODC replication'''
- partial_attribute_set = drsuapi.DsPartialAttributeSet()
- partial_attribute_set.version = 1
-
- attids = []
-
- # the exact list of attids we send is quite critical. Note that
- # we do ask for the secret attributes, but set SPECIAL_SECRET_PROCESSING
- # to zero them out
- schema_dn = self.samdb.get_schema_basedn()
- res = self.samdb.search(base=schema_dn, scope=ldb.SCOPE_SUBTREE,
- expression="objectClass=attributeSchema",
- attrs=["lDAPDisplayName", "systemFlags",
- "searchFlags"])
-
- for r in res:
- ldap_display_name = r["lDAPDisplayName"][0]
- if "systemFlags" in r:
- system_flags = r["systemFlags"][0]
- if (int(system_flags) & (samba.dsdb.DS_FLAG_ATTR_NOT_REPLICATED |
- samba.dsdb.DS_FLAG_ATTR_IS_CONSTRUCTED)):
- continue
- if "searchFlags" in r:
- search_flags = r["searchFlags"][0]
- if (int(search_flags) & samba.dsdb.SEARCH_FLAG_RODC_ATTRIBUTE):
- continue
- attid = self.samdb.get_attid_from_lDAPDisplayName(ldap_display_name)
- attids.append(int(attid))
-
- # the attids do need to be sorted, or windows doesn't return
- # all the attributes we need
- attids.sort()
- partial_attribute_set.attids = attids
- partial_attribute_set.num_attids = len(attids)
- return partial_attribute_set
-
- def replicate(self, dn, source_dsa_invocation_id, destination_dsa_guid,
- schema=False, exop=drsuapi.DRSUAPI_EXOP_NONE, rodc=False,
- replica_flags=None):
- '''replicate a single DN'''
-
- # setup for a GetNCChanges call
- req8 = drsuapi.DsGetNCChangesRequest8()
-
- req8.destination_dsa_guid = destination_dsa_guid
- req8.source_dsa_invocation_id = source_dsa_invocation_id
- req8.naming_context = drsuapi.DsReplicaObjectIdentifier()
- req8.naming_context.dn = dn
- req8.highwatermark = drsuapi.DsReplicaHighWaterMark()
- req8.highwatermark.tmp_highest_usn = 0
- req8.highwatermark.reserved_usn = 0
- req8.highwatermark.highest_usn = 0
- req8.uptodateness_vector = None
- if replica_flags is not None:
- req8.replica_flags = replica_flags
- elif exop == drsuapi.DRSUAPI_EXOP_REPL_SECRET:
- req8.replica_flags = 0
- else:
- req8.replica_flags = (drsuapi.DRSUAPI_DRS_INIT_SYNC |
- drsuapi.DRSUAPI_DRS_PER_SYNC |
- drsuapi.DRSUAPI_DRS_GET_ANC |
- drsuapi.DRSUAPI_DRS_NEVER_SYNCED)
- if rodc:
- req8.replica_flags |= drsuapi.DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING
- else:
- req8.replica_flags |= drsuapi.DRSUAPI_DRS_WRIT_REP
- req8.max_object_count = 402
- req8.max_ndr_size = 402116
- req8.extended_op = exop
- req8.fsmo_info = 0
- req8.partial_attribute_set = None
- req8.partial_attribute_set_ex = None
- req8.mapping_ctr.num_mappings = 0
- req8.mapping_ctr.mappings = None
-
- if not schema and rodc:
- req8.partial_attribute_set = self.drs_get_rodc_partial_attribute_set()
-
- if self.supported_extensions & drsuapi.DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8:
- req_level = 8
- req = req8
- else:
- req_level = 5
- req5 = drsuapi.DsGetNCChangesRequest5()
- for a in dir(req5):
- if a[0] != '_':
- setattr(req5, a, getattr(req8, a))
- req = req5
-
-
- while True:
- (level, ctr) = self.drs.DsGetNCChanges(self.drs_handle, req_level, req)
- if ctr.first_object == None and ctr.object_count != 0:
- raise RuntimeError("DsGetNCChanges: NULL first_object with object_count=%u" % (ctr.object_count))
- self.net.replicate_chunk(self.replication_state, level, ctr, schema=schema)
- if ctr.more_data == 0:
- break
- req.highwatermark.tmp_highest_usn = ctr.new_highwatermark.tmp_highest_usn
diff --git a/source4/scripting/python/samba/getopt.py b/source4/scripting/python/samba/getopt.py
index 671142b552..8b756b2d6f 100644
--- a/source4/scripting/python/samba/getopt.py
+++ b/source4/scripting/python/samba/getopt.py
@@ -1,56 +1,38 @@
-#!/usr/bin/env python
+#!/usr/bin/python
# Samba-specific bits for optparse
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
-#
+#
# 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/>.
#
"""Support for parsing Samba-related command-line options."""
-__docformat__ = "restructuredText"
-
-import optparse, os
-from samba.credentials import (
- Credentials,
- DONT_USE_KERBEROS,
- MUST_USE_KERBEROS,
- )
-from samba.hostconfig import Hostconfig
-import sys
+import optparse
+from credentials import Credentials, DONT_USE_KERBEROS, MUST_USE_KERBEROS
+from hostconfig import Hostconfig
+__docformat__ = "restructuredText"
class SambaOptions(optparse.OptionGroup):
"""General Samba-related command line options."""
-
def __init__(self, parser):
- from samba.param import LoadParm
optparse.OptionGroup.__init__(self, parser, "Samba Common Options")
self.add_option("-s", "--configfile", action="callback",
- type=str, metavar="FILE", help="Configuration file",
+ type=str, metavar="FILE", help="Configuration file",
callback=self._load_configfile)
- self.add_option("-d", "--debuglevel", action="callback",
- type=int, metavar="DEBUGLEVEL", help="debug level",
- callback=self._set_debuglevel)
- self.add_option("--option", action="callback",
- type=str, metavar="OPTION", help="set smb.conf option from command line",
- callback=self._set_option)
- self.add_option("--realm", action="callback",
- type=str, metavar="REALM", help="set the realm name",
- callback=self._set_realm)
self._configfile = None
- self._lp = LoadParm()
def get_loadparm_path(self):
"""Return the path to the smb.conf file specified on the command line. """
@@ -59,28 +41,17 @@ class SambaOptions(optparse.OptionGroup):
def _load_configfile(self, option, opt_str, arg, parser):
self._configfile = arg
- def _set_debuglevel(self, option, opt_str, arg, parser):
- self._lp.set('debug level', str(arg))
-
- def _set_realm(self, option, opt_str, arg, parser):
- self._lp.set('realm', arg)
-
- def _set_option(self, option, opt_str, arg, parser):
- if arg.find('=') == -1:
- print("--option takes a 'a=b' argument")
- sys.exit(1)
- a = arg.split('=')
- self._lp.set(a[0], a[1])
-
def get_loadparm(self):
"""Return a loadparm object with data specified on the command line. """
+ import os, param
+ lp = param.LoadParm()
if self._configfile is not None:
- self._lp.load(self._configfile)
+ lp.load(self._configfile)
elif os.getenv("SMB_CONF_PATH") is not None:
- self._lp.load(os.getenv("SMB_CONF_PATH"))
+ lp.load(os.getenv("SMB_CONF_PATH"))
else:
- self._lp.load_default()
- return self._lp
+ lp.load_default()
+ return lp
def get_hostconfig(self):
return Hostconfig(self.get_loadparm())
@@ -90,41 +61,29 @@ class VersionOptions(optparse.OptionGroup):
"""Command line option for printing Samba version."""
def __init__(self, parser):
optparse.OptionGroup.__init__(self, parser, "Version Options")
- self.add_option("--version", action="callback",
- callback=self._display_version,
- help="Display version number")
-
- def _display_version(self, option, opt_str, arg, parser):
- import samba
- print samba.version
- sys.exit(0)
class CredentialsOptions(optparse.OptionGroup):
"""Command line options for specifying credentials."""
def __init__(self, parser):
- self.no_pass = True
- self.ipaddress = None
+ self.no_pass = False
optparse.OptionGroup.__init__(self, parser, "Credentials Options")
self.add_option("--simple-bind-dn", metavar="DN", action="callback",
callback=self._set_simple_bind_dn, type=str,
help="DN to use for a simple bind")
self.add_option("--password", metavar="PASSWORD", action="callback",
help="Password", type=str, callback=self._set_password)
- self.add_option("-U", "--username", metavar="USERNAME",
+ self.add_option("-U", "--username", metavar="USERNAME",
action="callback", type=str,
help="Username", callback=self._parse_username)
- self.add_option("-W", "--workgroup", metavar="WORKGROUP",
+ self.add_option("-W", "--workgroup", metavar="WORKGROUP",
action="callback", type=str,
help="Workgroup", callback=self._parse_workgroup)
self.add_option("-N", "--no-pass", action="store_true",
help="Don't ask for a password")
- self.add_option("-k", "--kerberos", metavar="KERBEROS",
+ self.add_option("-k", "--kerberos", metavar="KERBEROS",
action="callback", type=str,
help="Use Kerberos", callback=self._set_kerberos)
- self.add_option("", "--ipaddress", metavar="IPADDRESS",
- action="callback", type=str,
- help="IP address of server", callback=self._set_ipaddress)
self.creds = Credentials()
def _parse_username(self, option, opt_str, arg, parser):
@@ -135,96 +94,23 @@ class CredentialsOptions(optparse.OptionGroup):
def _set_password(self, option, opt_str, arg, parser):
self.creds.set_password(arg)
- self.no_pass = False
-
- def _set_ipaddress(self, option, opt_str, arg, parser):
- self.ipaddress = arg
def _set_kerberos(self, option, opt_str, arg, parser):
- if arg.lower() in ["yes", 'true', '1']:
+ if bool(arg) or arg.lower() == "yes":
self.creds.set_kerberos_state(MUST_USE_KERBEROS)
- elif arg.lower() in ["no", 'false', '0']:
- self.creds.set_kerberos_state(DONT_USE_KERBEROS)
else:
- raise optparse.BadOptionErr("invalid kerberos option: %s" % arg)
+ self.creds.set_kerberos_state(DONT_USE_KERBEROS)
def _set_simple_bind_dn(self, option, opt_str, arg, parser):
self.creds.set_bind_dn(arg)
- def get_credentials(self, lp, fallback_machine=False):
+ def get_credentials(self, lp):
"""Obtain the credentials set on the command-line.
:param lp: Loadparm object to use.
:return: Credentials object
"""
self.creds.guess(lp)
- if self.no_pass:
+ if not self.no_pass:
self.creds.set_cmdline_callbacks()
-
- # possibly fallback to using the machine account, if we have
- # access to the secrets db
- if fallback_machine and not self.creds.authentication_requested():
- try:
- self.creds.set_machine_account(lp)
- except Exception:
- pass
-
return self.creds
-
-class CredentialsOptionsDouble(CredentialsOptions):
- """Command line options for specifying credentials of two servers."""
- def __init__(self, parser):
- CredentialsOptions.__init__(self, parser)
- self.no_pass2 = True
- self.add_option("--simple-bind-dn2", metavar="DN2", action="callback",
- callback=self._set_simple_bind_dn2, type=str,
- help="DN to use for a simple bind")
- self.add_option("--password2", metavar="PASSWORD2", action="callback",
- help="Password", type=str, callback=self._set_password2)
- self.add_option("--username2", metavar="USERNAME2",
- action="callback", type=str,
- help="Username for second server", callback=self._parse_username2)
- self.add_option("--workgroup2", metavar="WORKGROUP2",
- action="callback", type=str,
- help="Workgroup for second server", callback=self._parse_workgroup2)
- self.add_option("--no-pass2", action="store_true",
- help="Don't ask for a password for the second server")
- self.add_option("--kerberos2", metavar="KERBEROS2",
- action="callback", type=str,
- help="Use Kerberos", callback=self._set_kerberos2)
- self.creds2 = Credentials()
-
- def _parse_username2(self, option, opt_str, arg, parser):
- self.creds2.parse_string(arg)
-
- def _parse_workgroup2(self, option, opt_str, arg, parser):
- self.creds2.set_domain(arg)
-
- def _set_password2(self, option, opt_str, arg, parser):
- self.creds2.set_password(arg)
- self.no_pass2 = False
-
- def _set_kerberos2(self, option, opt_str, arg, parser):
- if bool(arg) or arg.lower() == "yes":
- self.creds2.set_kerberos_state(MUST_USE_KERBEROS)
- else:
- self.creds2.set_kerberos_state(DONT_USE_KERBEROS)
-
- def _set_simple_bind_dn2(self, option, opt_str, arg, parser):
- self.creds2.set_bind_dn(arg)
-
- def get_credentials2(self, lp, guess=True):
- """Obtain the credentials set on the command-line.
-
- :param lp: Loadparm object to use.
- :param guess: Try guess Credentials from environment
- :return: Credentials object
- """
- if guess:
- self.creds2.guess(lp)
- elif not self.creds2.get_username():
- self.creds2.set_anonymous()
-
- if self.no_pass2:
- self.creds2.set_cmdline_callbacks()
- return self.creds2
diff --git a/source4/scripting/python/samba/hostconfig.py b/source4/scripting/python/samba/hostconfig.py
index 3e6dc6b1dd..313e3420b0 100644
--- a/source4/scripting/python/samba/hostconfig.py
+++ b/source4/scripting/python/samba/hostconfig.py
@@ -1,83 +1,33 @@
-#!/usr/bin/env python
+#!/usr/bin/python
# Unix SMB/CIFS implementation.
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
-#
+#
# 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/>.
#
-"""Local host configuration."""
-
from samdb import SamDB
class Hostconfig(object):
- """Aggregate object that contains all information about the configuration
+ """Aggregate object that contains all information about the configuration
of a Samba host."""
- def __init__(self, lp):
+ def __init__(self, lp):
self.lp = lp
- def get_shares(self):
- return SharesContainer(self.lp)
-
def get_samdb(self, session_info, credentials):
- """Access the SamDB host.
-
- :param session_info: Session info to use
- :param credentials: Credentials to access the SamDB with
- """
- return SamDB(url=self.lp.get("sam database"),
- session_info=session_info, credentials=credentials,
+ return SamDB(url=self.lp.get("sam database"),
+ session_info=session_info, credentials=credentials,
lp=self.lp)
-
-# TODO: Rather than accessing Loadparm directly here, we should really
-# have bindings to the param/shares.c and use those.
-
-
-class SharesContainer(object):
- """A shares container."""
-
- def __init__(self, lp):
- self._lp = lp
-
- def __getitem__(self, name):
- if name == "global":
- # [global] is not a share
- raise KeyError
- return Share(self._lp[name])
-
- def __len__(self):
- if "global" in self._lp.services():
- return len(self._lp)-1
- return len(self._lp)
-
- def keys(self):
- return [name for name in self._lp.services() if name != "global"]
-
- def __iter__(self):
- return iter(self.keys())
-
-
-class Share(object):
- """A file share."""
-
- def __init__(self, service):
- self._service = service
-
- def __getitem__(self, name):
- return self._service[name]
-
- def __setitem__(self, name, value):
- self._service[name] = value
diff --git a/source4/scripting/python/samba/idmap.py b/source4/scripting/python/samba/idmap.py
index 93fca46edd..ad209f42de 100644
--- a/source4/scripting/python/samba/idmap.py
+++ b/source4/scripting/python/samba/idmap.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
# Unix SMB/CIFS implementation.
# Copyright (C) 2008 Kai Blin <kai@samba.org>
@@ -22,7 +22,6 @@
__docformat__ = "restructuredText"
-import ldb
import samba
class IDmapDB(samba.Ldb):
@@ -51,34 +50,12 @@ class IDmapDB(samba.Ldb):
super(IDmapDB, self).connect(url=self.lp.private_path(url), flags=flags,
options=options)
-
- def increment_xid(self):
- """Increment xidNumber, if not present it create and assign it to the lowerBound
-
- :return xid can that be used for SID/unixid mapping
- """
- res = self.search(expression="dn=CN=CONFIG", base="",
- scope=ldb.SCOPE_SUBTREE)
- id = res[0].get("xidNumber")
- flag = ldb.FLAG_MOD_REPLACE
- if id is None:
- id = res[0].get("lowerBound")
- flag = ldb.FLAG_MOD_ADD
- newid = int(str(id)) + 1
- msg = ldb.Message()
- msg.dn = ldb.Dn(self, "CN=CONFIG")
- msg["xidNumber"] = ldb.MessageElement(str(newid), flag, "xidNumber")
- self.modify(msg)
- return id
-
- def setup_name_mapping(self, sid, type, unixid=None):
+ def setup_name_mapping(self, sid, type, unixid):
"""Setup a mapping between a sam name and a unix name.
:param sid: SID of the NT-side of the mapping.
- :param unixname: Unix id to map to, if none supplied the next one will be selected
+ :param unixname: Unix name to map to.
"""
- if unixid is None:
- unixid = self.increment_xid()
type_string = ""
if type == self.TYPE_UID:
type_string = "ID_TYPE_UID"
diff --git a/source4/scripting/python/samba/join.py b/source4/scripting/python/samba/join.py
deleted file mode 100644
index 401f262154..0000000000
--- a/source4/scripting/python/samba/join.py
+++ /dev/null
@@ -1,582 +0,0 @@
-#!/usr/bin/env python
-#
-# python join code
-# Copyright Andrew Tridgell 2010
-# Copyright Andrew Bartlett 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/>.
-#
-
-"""Joining a domain."""
-
-from samba.auth import system_session
-from samba.samdb import SamDB
-from samba import gensec, Ldb, drs_utils
-import ldb, samba, sys, os, uuid
-from samba.ndr import ndr_pack
-from samba.dcerpc import security, drsuapi, misc, nbt
-from samba.credentials import Credentials, DONT_USE_KERBEROS
-from samba.provision import secretsdb_self_join, provision, FILL_DRS
-from samba.schema import Schema
-from samba.net import Net
-import logging
-import talloc
-
-# this makes debugging easier
-talloc.enable_null_tracking()
-
-
-class dc_join(object):
- '''perform a DC join'''
-
- def __init__(ctx, server=None, creds=None, lp=None, site=None,
- netbios_name=None, targetdir=None, domain=None):
- ctx.creds = creds
- ctx.lp = lp
- ctx.site = site
- ctx.netbios_name = netbios_name
- ctx.targetdir = targetdir
-
- ctx.creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL)
- ctx.net = Net(creds=ctx.creds, lp=ctx.lp)
-
- if server is not None:
- ctx.server = server
- else:
- print("Finding a writeable DC for domain '%s'" % domain)
- ctx.server = ctx.find_dc(domain)
- print("Found DC %s" % ctx.server)
-
- ctx.samdb = SamDB(url="ldap://%s" % ctx.server,
- session_info=system_session(),
- credentials=ctx.creds, lp=ctx.lp)
-
- ctx.myname = netbios_name
- ctx.samname = "%s$" % ctx.myname
- ctx.base_dn = str(ctx.samdb.get_default_basedn())
- ctx.root_dn = str(ctx.samdb.get_root_basedn())
- ctx.schema_dn = str(ctx.samdb.get_schema_basedn())
- ctx.config_dn = str(ctx.samdb.get_config_basedn())
- ctx.domsid = ctx.samdb.get_domain_sid()
- ctx.domain_name = ctx.get_domain_name()
-
- lp.set("workgroup", ctx.domain_name)
- print("workgroup is %s" % ctx.domain_name)
-
- ctx.dc_ntds_dn = ctx.get_dsServiceName()
- ctx.dc_dnsHostName = ctx.get_dnsHostName()
- ctx.behavior_version = ctx.get_behavior_version()
-
- ctx.acct_pass = samba.generate_random_password(32, 40)
-
- # work out the DNs of all the objects we will be adding
- ctx.server_dn = "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (ctx.myname, ctx.site, ctx.config_dn)
- ctx.ntds_dn = "CN=NTDS Settings,%s" % ctx.server_dn
- topology_base = "CN=Topology,CN=Domain System Volume,CN=DFSR-GlobalSettings,CN=System,%s" % ctx.base_dn
- if ctx.dn_exists(topology_base):
- ctx.topology_dn = "CN=%s,%s" % (ctx.myname, topology_base)
- else:
- ctx.topology_dn = None
-
- ctx.dnsdomain = ldb.Dn(ctx.samdb, ctx.base_dn).canonical_str().split('/')[0]
-
- ctx.realm = ctx.dnsdomain
- lp.set("realm", ctx.realm)
-
- print("realm is %s" % ctx.realm)
-
- ctx.dnshostname = "%s.%s" % (ctx.myname.lower(), ctx.dnsdomain)
-
- ctx.acct_dn = "CN=%s,OU=Domain Controllers,%s" % (ctx.myname, ctx.base_dn)
-
- ctx.tmp_samdb = None
-
- ctx.SPNs = [ "HOST/%s" % ctx.myname,
- "HOST/%s" % ctx.dnshostname,
- "GC/%s/%s" % (ctx.dnshostname, ctx.dnsdomain) ]
-
- # these elements are optional
- ctx.never_reveal_sid = None
- ctx.reveal_sid = None
- ctx.connection_dn = None
- ctx.RODC = False
- ctx.krbtgt_dn = None
- ctx.drsuapi = None
- ctx.managedby = None
-
-
- def del_noerror(ctx, dn, recursive=False):
- if recursive:
- try:
- res = ctx.samdb.search(base=dn, scope=ldb.SCOPE_ONELEVEL, attrs=["dn"])
- except Exception:
- return
- for r in res:
- ctx.del_noerror(r.dn, recursive=True)
- try:
- ctx.samdb.delete(dn)
- print "Deleted %s" % dn
- except Exception:
- pass
-
- def cleanup_old_join(ctx):
- '''remove any DNs from a previous join'''
- try:
- # find the krbtgt link
- print("checking samaccountname")
- res = ctx.samdb.search(base=ctx.samdb.get_default_basedn(),
- expression='samAccountName=%s' % ctx.samname,
- attrs=["msDS-krbTgtLink"])
- if res:
- ctx.del_noerror(res[0].dn, recursive=True)
- if ctx.connection_dn is not None:
- ctx.del_noerror(ctx.connection_dn)
- if ctx.krbtgt_dn is not None:
- ctx.del_noerror(ctx.krbtgt_dn)
- ctx.del_noerror(ctx.ntds_dn)
- ctx.del_noerror(ctx.server_dn, recursive=True)
- if ctx.topology_dn:
- ctx.del_noerror(ctx.topology_dn)
- if res:
- ctx.new_krbtgt_dn = res[0]["msDS-Krbtgtlink"][0]
- ctx.del_noerror(ctx.new_krbtgt_dn)
- except Exception:
- pass
-
- def find_dc(ctx, domain):
- '''find a writeable DC for the given domain'''
- try:
- ctx.cldap_ret = ctx.net.finddc(domain, nbt.NBT_SERVER_LDAP | nbt.NBT_SERVER_DS | nbt.NBT_SERVER_WRITABLE)
- except Exception:
- raise Exception("Failed to find a writeable DC for domain '%s'" % domain)
- if ctx.cldap_ret.client_site is not None and ctx.cldap_ret.client_site != "":
- ctx.site = ctx.cldap_ret.client_site
- return ctx.cldap_ret.pdc_dns_name
-
-
- def get_dsServiceName(ctx):
- res = ctx.samdb.search(base="", scope=ldb.SCOPE_BASE, attrs=["dsServiceName"])
- return res[0]["dsServiceName"][0]
-
- def get_behavior_version(ctx):
- res = ctx.samdb.search(base=ctx.base_dn, scope=ldb.SCOPE_BASE, attrs=["msDS-Behavior-Version"])
- if "msDS-Behavior-Version" in res[0]:
- return int(res[0]["msDS-Behavior-Version"][0])
- else:
- return samba.dsdb.DS_DOMAIN_FUNCTION_2000
-
- def get_dnsHostName(ctx):
- res = ctx.samdb.search(base="", scope=ldb.SCOPE_BASE, attrs=["dnsHostName"])
- return res[0]["dnsHostName"][0]
-
- def get_domain_name(ctx):
- '''get netbios name of the domain from the partitions record'''
- partitions_dn = ctx.samdb.get_partitions_dn()
- res = ctx.samdb.search(base=partitions_dn, scope=ldb.SCOPE_ONELEVEL, attrs=["nETBIOSName"],
- expression='ncName=%s' % ctx.samdb.get_default_basedn())
- return res[0]["nETBIOSName"][0]
-
- def get_mysid(ctx):
- '''get the SID of the connected user. Only works with w2k8 and later,
- so only used for RODC join'''
- res = ctx.samdb.search(base="", scope=ldb.SCOPE_BASE, attrs=["tokenGroups"])
- binsid = res[0]["tokenGroups"][0]
- return ctx.samdb.schema_format_value("objectSID", binsid)
-
- def dn_exists(ctx, dn):
- '''check if a DN exists'''
- try:
- res = ctx.samdb.search(base=dn, scope=ldb.SCOPE_BASE, attrs=[])
- except ldb.LdbError, (enum, estr):
- if enum == ldb.ERR_NO_SUCH_OBJECT:
- return False
- raise
- return True
-
- def add_krbtgt_account(ctx):
- '''RODCs need a special krbtgt account'''
- print "Adding %s" % ctx.krbtgt_dn
- rec = {
- "dn" : ctx.krbtgt_dn,
- "objectclass" : "user",
- "useraccountcontrol" : str(samba.dsdb.UF_NORMAL_ACCOUNT |
- samba.dsdb.UF_ACCOUNTDISABLE),
- "showinadvancedviewonly" : "TRUE",
- "description" : "krbtgt for %s" % ctx.samname}
- ctx.samdb.add(rec, ["rodc_join:1:1"])
-
- # now we need to search for the samAccountName attribute on the krbtgt DN,
- # as this will have been magically set to the krbtgt number
- res = ctx.samdb.search(base=ctx.krbtgt_dn, scope=ldb.SCOPE_BASE, attrs=["samAccountName"])
- ctx.krbtgt_name = res[0]["samAccountName"][0]
-
- print "Got krbtgt_name=%s" % ctx.krbtgt_name
-
- m = ldb.Message()
- m.dn = ldb.Dn(ctx.samdb, ctx.acct_dn)
- m["msDS-krbTgtLink"] = ldb.MessageElement(ctx.krbtgt_dn,
- ldb.FLAG_MOD_REPLACE, "msDS-krbTgtLink")
- ctx.samdb.modify(m)
-
- ctx.new_krbtgt_dn = "CN=%s,CN=Users,%s" % (ctx.krbtgt_name, ctx.base_dn)
- print "Renaming %s to %s" % (ctx.krbtgt_dn, ctx.new_krbtgt_dn)
- ctx.samdb.rename(ctx.krbtgt_dn, ctx.new_krbtgt_dn)
-
- def drsuapi_connect(ctx):
- '''make a DRSUAPI connection to the server'''
- binding_options = "seal"
- if ctx.lp.get("log level") >= 5:
- binding_options += ",print"
- binding_string = "ncacn_ip_tcp:%s[%s]" % (ctx.server, binding_options)
- ctx.drsuapi = drsuapi.drsuapi(binding_string, ctx.lp, ctx.creds)
- (ctx.drsuapi_handle, ctx.bind_supported_extensions) = drs_utils.drs_DsBind(ctx.drsuapi)
-
- def create_tmp_samdb(ctx):
- '''create a temporary samdb object for schema queries'''
- ctx.tmp_schema = Schema(security.dom_sid(ctx.domsid),
- schemadn=ctx.schema_dn)
- ctx.tmp_samdb = SamDB(session_info=system_session(), url=None, auto_connect=False,
- credentials=ctx.creds, lp=ctx.lp, global_schema=False,
- am_rodc=False)
- ctx.tmp_samdb.set_schema(ctx.tmp_schema)
-
- def build_DsReplicaAttribute(ctx, attrname, attrvalue):
- '''build a DsReplicaAttributeCtr object'''
- r = drsuapi.DsReplicaAttribute()
- r.attid = ctx.tmp_samdb.get_attid_from_lDAPDisplayName(attrname)
- r.value_ctr = 1
-
-
- def DsAddEntry(ctx, rec):
- '''add a record via the DRSUAPI DsAddEntry call'''
- if ctx.drsuapi is None:
- ctx.drsuapi_connect()
- if ctx.tmp_samdb is None:
- ctx.create_tmp_samdb()
-
- id = drsuapi.DsReplicaObjectIdentifier()
- id.dn = rec['dn']
-
- attrs = []
- for a in rec:
- if a == 'dn':
- continue
- if not isinstance(rec[a], list):
- v = [rec[a]]
- else:
- v = rec[a]
- rattr = ctx.tmp_samdb.dsdb_DsReplicaAttribute(ctx.tmp_samdb, a, v)
- attrs.append(rattr)
-
- attribute_ctr = drsuapi.DsReplicaAttributeCtr()
- attribute_ctr.num_attributes = len(attrs)
- attribute_ctr.attributes = attrs
-
- object = drsuapi.DsReplicaObject()
- object.identifier = id
- object.attribute_ctr = attribute_ctr
-
- first_object = drsuapi.DsReplicaObjectListItem()
- first_object.object = object
-
- req2 = drsuapi.DsAddEntryRequest2()
- req2.first_object = first_object
-
- (level, ctr) = ctx.drsuapi.DsAddEntry(ctx.drsuapi_handle, 2, req2)
- if ctr.err_ver != 1:
- raise RuntimeError("expected err_ver 1, got %u" % ctr.err_ver)
- if ctr.err_data.status != (0, 'WERR_OK'):
- print("DsAddEntry failed with status %s info %s" % (ctr.err_data.status,
- ctr.err_data.info.extended_err))
- raise RuntimeError("DsAddEntry failed")
-
- def join_add_objects(ctx):
- '''add the various objects needed for the join'''
- print "Adding %s" % ctx.acct_dn
- rec = {
- "dn" : ctx.acct_dn,
- "objectClass": "computer",
- "displayname": ctx.samname,
- "samaccountname" : ctx.samname,
- "userAccountControl" : str(ctx.userAccountControl | samba.dsdb.UF_ACCOUNTDISABLE),
- "dnshostname" : ctx.dnshostname}
- if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2008:
- rec['msDS-SupportedEncryptionTypes'] = str(samba.dsdb.ENC_ALL_TYPES)
- if ctx.managedby:
- rec["managedby"] = ctx.managedby
- if ctx.never_reveal_sid:
- rec["msDS-NeverRevealGroup"] = ctx.never_reveal_sid
- if ctx.reveal_sid:
- rec["msDS-RevealOnDemandGroup"] = ctx.reveal_sid
- ctx.samdb.add(rec)
-
- if ctx.krbtgt_dn:
- ctx.add_krbtgt_account()
-
- print "Adding %s" % ctx.server_dn
- rec = {
- "dn": ctx.server_dn,
- "objectclass" : "server",
- "systemFlags" : str(samba.dsdb.SYSTEM_FLAG_CONFIG_ALLOW_RENAME |
- samba.dsdb.SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE |
- samba.dsdb.SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE),
- "serverReference" : ctx.acct_dn,
- "dnsHostName" : ctx.dnshostname}
- ctx.samdb.add(rec)
-
- # FIXME: the partition (NC) assignment has to be made dynamic
- print "Adding %s" % ctx.ntds_dn
- rec = {
- "dn" : ctx.ntds_dn,
- "objectclass" : "nTDSDSA",
- "systemFlags" : str(samba.dsdb.SYSTEM_FLAG_DISALLOW_MOVE_ON_DELETE),
- "dMDLocation" : ctx.schema_dn}
-
- if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003:
- rec["msDS-Behavior-Version"] = str(ctx.behavior_version)
-
- if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003:
- rec["msDS-HasDomainNCs"] = ctx.base_dn
-
- if ctx.RODC:
- rec["objectCategory"] = "CN=NTDS-DSA-RO,%s" % ctx.schema_dn
- rec["msDS-HasFullReplicaNCs"] = [ ctx.base_dn, ctx.config_dn, ctx.schema_dn ]
- rec["options"] = "37"
- ctx.samdb.add(rec, ["rodc_join:1:1"])
- else:
- rec["objectCategory"] = "CN=NTDS-DSA,%s" % ctx.schema_dn
- rec["HasMasterNCs"] = [ ctx.base_dn, ctx.config_dn, ctx.schema_dn ]
- if ctx.behavior_version >= samba.dsdb.DS_DOMAIN_FUNCTION_2003:
- rec["msDS-HasMasterNCs"] = [ ctx.base_dn, ctx.config_dn, ctx.schema_dn ]
- rec["options"] = "1"
- rec["invocationId"] = ndr_pack(misc.GUID(str(uuid.uuid4())))
- ctx.DsAddEntry(rec)
-
- # find the GUID of our NTDS DN
- res = ctx.samdb.search(base=ctx.ntds_dn, scope=ldb.SCOPE_BASE, attrs=["objectGUID"])
- ctx.ntds_guid = misc.GUID(ctx.samdb.schema_format_value("objectGUID", res[0]["objectGUID"][0]))
-
- if ctx.connection_dn is not None:
- print "Adding %s" % ctx.connection_dn
- rec = {
- "dn" : ctx.connection_dn,
- "objectclass" : "nTDSConnection",
- "enabledconnection" : "TRUE",
- "options" : "65",
- "fromServer" : ctx.dc_ntds_dn}
- ctx.samdb.add(rec)
-
- if ctx.topology_dn:
- print "Adding %s" % ctx.topology_dn
- rec = {
- "dn" : ctx.topology_dn,
- "objectclass" : "msDFSR-Member",
- "msDFSR-ComputerReference" : ctx.acct_dn,
- "serverReference" : ctx.ntds_dn}
- ctx.samdb.add(rec)
-
- print "Adding SPNs to %s" % ctx.acct_dn
- m = ldb.Message()
- m.dn = ldb.Dn(ctx.samdb, ctx.acct_dn)
- for i in range(len(ctx.SPNs)):
- ctx.SPNs[i] = ctx.SPNs[i].replace("$NTDSGUID", str(ctx.ntds_guid))
- m["servicePrincipalName"] = ldb.MessageElement(ctx.SPNs,
- ldb.FLAG_MOD_ADD,
- "servicePrincipalName")
- ctx.samdb.modify(m)
-
- print "Setting account password for %s" % ctx.samname
- ctx.samdb.setpassword("(&(objectClass=user)(sAMAccountName=%s))" % ctx.samname,
- ctx.acct_pass,
- force_change_at_next_login=False,
- username=ctx.samname)
- res = ctx.samdb.search(base=ctx.acct_dn, scope=ldb.SCOPE_BASE, attrs=["msDS-keyVersionNumber"])
- ctx.key_version_number = int(res[0]["msDS-keyVersionNumber"][0])
-
- print("Enabling account")
- m = ldb.Message()
- m.dn = ldb.Dn(ctx.samdb, ctx.acct_dn)
- m["userAccountControl"] = ldb.MessageElement(str(ctx.userAccountControl),
- ldb.FLAG_MOD_REPLACE,
- "userAccountControl")
- ctx.samdb.modify(m)
-
- def join_provision(ctx):
- '''provision the local SAM'''
-
- print "Calling bare provision"
-
- logger = logging.getLogger("provision")
- logger.addHandler(logging.StreamHandler(sys.stdout))
- smbconf = ctx.lp.configfile
-
- presult = provision(logger, system_session(), None,
- smbconf=smbconf, targetdir=ctx.targetdir, samdb_fill=FILL_DRS,
- realm=ctx.realm, rootdn=ctx.root_dn, domaindn=ctx.base_dn,
- schemadn=ctx.schema_dn,
- configdn=ctx.config_dn,
- serverdn=ctx.server_dn, domain=ctx.domain_name,
- hostname=ctx.myname, domainsid=ctx.domsid,
- machinepass=ctx.acct_pass, serverrole="domain controller",
- sitename=ctx.site, lp=ctx.lp)
- print "Provision OK for domain DN %s" % presult.domaindn
- ctx.local_samdb = presult.samdb
- ctx.lp = presult.lp
- ctx.paths = presult.paths
-
-
- def join_replicate(ctx):
- '''replicate the SAM'''
-
- print "Starting replication"
- ctx.local_samdb.transaction_start()
- try:
- source_dsa_invocation_id = misc.GUID(ctx.samdb.get_invocation_id())
- destination_dsa_guid = ctx.ntds_guid
-
- if ctx.RODC:
- repl_creds = Credentials()
- repl_creds.guess(ctx.lp)
- repl_creds.set_kerberos_state(DONT_USE_KERBEROS)
- repl_creds.set_username(ctx.samname)
- repl_creds.set_password(ctx.acct_pass)
- else:
- repl_creds = ctx.creds
-
- binding_options = "seal"
- if ctx.lp.get("debug level") >= 5:
- binding_options += ",print"
- repl = drs_utils.drs_Replicate(
- "ncacn_ip_tcp:%s[%s]" % (ctx.server, binding_options),
- ctx.lp, repl_creds, ctx.local_samdb)
-
- repl.replicate(ctx.schema_dn, source_dsa_invocation_id,
- destination_dsa_guid, schema=True, rodc=ctx.RODC,
- replica_flags=ctx.replica_flags)
- repl.replicate(ctx.config_dn, source_dsa_invocation_id,
- destination_dsa_guid, rodc=ctx.RODC,
- replica_flags=ctx.replica_flags)
- repl.replicate(ctx.base_dn, source_dsa_invocation_id,
- destination_dsa_guid, rodc=ctx.RODC,
- replica_flags=ctx.replica_flags)
- if ctx.RODC:
- repl.replicate(ctx.acct_dn, source_dsa_invocation_id,
- destination_dsa_guid,
- exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET, rodc=True)
- repl.replicate(ctx.new_krbtgt_dn, source_dsa_invocation_id,
- destination_dsa_guid,
- exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET, rodc=True)
-
- print "Committing SAM database"
- except:
- ctx.local_samdb.transaction_cancel()
- raise
- else:
- ctx.local_samdb.transaction_commit()
-
-
- def join_finalise(ctx):
- '''finalise the join, mark us synchronised and setup secrets db'''
-
- print "Setting isSynchronized"
- m = ldb.Message()
- m.dn = ldb.Dn(ctx.samdb, '@ROOTDSE')
- m["isSynchronized"] = ldb.MessageElement("TRUE", ldb.FLAG_MOD_REPLACE, "isSynchronized")
- ctx.samdb.modify(m)
-
- secrets_ldb = Ldb(ctx.paths.secrets, session_info=system_session(), lp=ctx.lp)
-
- print "Setting up secrets database"
- secretsdb_self_join(secrets_ldb, domain=ctx.domain_name,
- realm=ctx.realm,
- dnsdomain=ctx.dnsdomain,
- netbiosname=ctx.myname,
- domainsid=security.dom_sid(ctx.domsid),
- machinepass=ctx.acct_pass,
- secure_channel_type=ctx.secure_channel_type,
- key_version_number=ctx.key_version_number)
-
- def do_join(ctx):
- ctx.cleanup_old_join()
- try:
- ctx.join_add_objects()
- ctx.join_provision()
- ctx.join_replicate()
- ctx.join_finalise()
- except Exception:
- print "Join failed - cleaning up"
- ctx.cleanup_old_join()
- raise
-
-
-def join_RODC(server=None, creds=None, lp=None, site=None, netbios_name=None,
- targetdir=None, domain=None):
- """join as a RODC"""
-
- ctx = dc_join(server, creds, lp, site, netbios_name, targetdir, domain)
-
- ctx.krbtgt_dn = "CN=krbtgt_%s,CN=Users,%s" % (ctx.myname, ctx.base_dn)
-
- # setup some defaults for accounts that should be replicated to this RODC
- ctx.never_reveal_sid = [ "<SID=%s-%s>" % (ctx.domsid, security.DOMAIN_RID_RODC_DENY),
- "<SID=%s>" % security.SID_BUILTIN_ADMINISTRATORS,
- "<SID=%s>" % security.SID_BUILTIN_SERVER_OPERATORS,
- "<SID=%s>" % security.SID_BUILTIN_BACKUP_OPERATORS,
- "<SID=%s>" % security.SID_BUILTIN_ACCOUNT_OPERATORS ]
- ctx.reveal_sid = "<SID=%s-%s>" % (ctx.domsid, security.DOMAIN_RID_RODC_ALLOW)
-
- mysid = ctx.get_mysid()
- admin_dn = "<SID=%s>" % mysid
- ctx.managedby = admin_dn
-
- ctx.userAccountControl = (samba.dsdb.UF_WORKSTATION_TRUST_ACCOUNT |
- samba.dsdb.UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION |
- samba.dsdb.UF_PARTIAL_SECRETS_ACCOUNT)
-
- ctx.SPNs.extend([ "RestrictedKrbHost/%s" % ctx.myname,
- "RestrictedKrbHost/%s" % ctx.dnshostname ])
-
- ctx.connection_dn = "CN=RODC Connection (FRS),%s" % ctx.ntds_dn
- ctx.secure_channel_type = misc.SEC_CHAN_RODC
- ctx.RODC = True
- ctx.replica_flags = (drsuapi.DRSUAPI_DRS_INIT_SYNC |
- drsuapi.DRSUAPI_DRS_PER_SYNC |
- drsuapi.DRSUAPI_DRS_GET_ANC |
- drsuapi.DRSUAPI_DRS_NEVER_SYNCED |
- drsuapi.DRSUAPI_DRS_SPECIAL_SECRET_PROCESSING |
- drsuapi.DRSUAPI_DRS_GET_ALL_GROUP_MEMBERSHIP)
- ctx.do_join()
-
-
- print "Joined domain %s (SID %s) as an RODC" % (ctx.domain_name, ctx.domsid)
-
-
-def join_DC(server=None, creds=None, lp=None, site=None, netbios_name=None,
- targetdir=None, domain=None):
- """join as a DC"""
- ctx = dc_join(server, creds, lp, site, netbios_name, targetdir, domain)
-
- ctx.userAccountControl = samba.dsdb.UF_SERVER_TRUST_ACCOUNT | samba.dsdb.UF_TRUSTED_FOR_DELEGATION
-
- ctx.SPNs.append('E3514235-4B06-11D1-AB04-00C04FC2DCD2/$NTDSGUID/%s' % ctx.dnsdomain)
- ctx.secure_channel_type = misc.SEC_CHAN_BDC
-
- ctx.replica_flags = (drsuapi.DRSUAPI_DRS_WRIT_REP |
- drsuapi.DRSUAPI_DRS_INIT_SYNC |
- drsuapi.DRSUAPI_DRS_PER_SYNC |
- drsuapi.DRSUAPI_DRS_FULL_SYNC_IN_PROGRESS |
- drsuapi.DRSUAPI_DRS_NEVER_SYNCED)
-
- ctx.do_join()
- print "Joined domain %s (SID %s) as a DC" % (ctx.domain_name, ctx.domsid)
diff --git a/source4/scripting/python/samba/ms_display_specifiers.py b/source4/scripting/python/samba/ms_display_specifiers.py
index fd92b20e66..2a54e4ae0e 100644
--- a/source4/scripting/python/samba/ms_display_specifiers.py
+++ b/source4/scripting/python/samba/ms_display_specifiers.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
#
# Create DisplaySpecifiers LDIF (as a string) from the documents provided by
# Microsoft under the WSPP.
diff --git a/source4/scripting/python/samba/ms_schema.py b/source4/scripting/python/samba/ms_schema.py
index 64bb28a967..a0abc337ce 100644
--- a/source4/scripting/python/samba/ms_schema.py
+++ b/source4/scripting/python/samba/ms_schema.py
@@ -1,14 +1,12 @@
+#!/usr/bin/env python
#
# create schema.ldif (as a string) from WSPP documentation
#
# based on minschema.py and minschema_wspp
#
-"""Generate LDIF from WSPP documentation."""
-
import re
import base64
-import uuid
bitFields = {}
@@ -35,19 +33,19 @@ bitFields["searchflags"] = {
# ADTS: 2.2.10
bitFields["systemflags"] = {
- 'FLAG_ATTR_NOT_REPLICATED': 31, 'FLAG_CR_NTDS_NC': 31, # NR
- 'FLAG_ATTR_REQ_PARTIAL_SET_MEMBER': 30, 'FLAG_CR_NTDS_DOMAIN': 30, # PS
- 'FLAG_ATTR_IS_CONSTRUCTED': 29, 'FLAG_CR_NTDS_NOT_GC_REPLICATED': 29, # CS
- 'FLAG_ATTR_IS_OPERATIONAL': 28, # OP
- 'FLAG_SCHEMA_BASE_OBJECT': 27, # BS
- 'FLAG_ATTR_IS_RDN': 26, # RD
- 'FLAG_DISALLOW_MOVE_ON_DELETE': 6, # DE
- 'FLAG_DOMAIN_DISALLOW_MOVE': 5, # DM
- 'FLAG_DOMAIN_DISALLOW_RENAME': 4, # DR
- 'FLAG_CONFIG_ALLOW_LIMITED_MOVE': 3, # AL
- 'FLAG_CONFIG_ALLOW_MOVE': 2, # AM
- 'FLAG_CONFIG_ALLOW_RENAME': 1, # AR
- 'FLAG_DISALLOW_DELETE': 0 # DD
+ 'FLAG_ATTR_NOT_REPLICATED': 31, 'FLAG_CR_NTDS_NC': 31, # NR
+ 'FLAG_ATTR_REQ_PARTIAL_SET_MEMBER': 30, 'FLAG_CR_NTDS_DOMAIN': 30, # PS
+ 'FLAG_ATTR_IS_CONSTRUCTED': 29, 'FLAG_CR_NTDS_NOT_GC_REPLICATED': 29, # CS
+ 'FLAG_ATTR_IS_OPERATIONAL': 28, # OP
+ 'FLAG_SCHEMA_BASE_OBJECT': 27, # BS
+ 'FLAG_ATTR_IS_RDN': 26, # RD
+ 'FLAG_DISALLOW_MOVE_ON_DELETE': 6, # DE
+ 'FLAG_DOMAIN_DISALLOW_MOVE': 5, # DM
+ 'FLAG_DOMAIN_DISALLOW_RENAME': 4, # DR
+ 'FLAG_CONFIG_ALLOW_LIMITED_MOVE': 3, # AL
+ 'FLAG_CONFIG_ALLOW_MOVE': 2, # AM
+ 'FLAG_CONFIG_ALLOW_RENAME': 1, # AR
+ 'FLAG_DISALLOW_DELETE': 0 # DD
}
# ADTS: 2.2.11
@@ -229,9 +227,6 @@ def __transform_entry(entry, objectClass):
entry.insert(0, ["dn", "CN=%s,${SCHEMADN}" % cn])
entry.insert(1, ["objectClass", ["top", objectClass]])
entry.insert(2, ["cn", cn])
- entry.insert(2, ["objectGUID", str(uuid.uuid4())])
- entry.insert(2, ["adminDescription", cn])
- entry.insert(2, ["adminDisplayName", cn])
for l in entry:
key = l[0].lower()
@@ -277,3 +272,5 @@ if __name__ == '__main__':
sys.exit(1)
print read_ms_schema(attr_file, classes_file)
+
+
diff --git a/source4/scripting/python/samba/ndr.py b/source4/scripting/python/samba/ndr.py
index 112668523f..e718ff3422 100644
--- a/source4/scripting/python/samba/ndr.py
+++ b/source4/scripting/python/samba/ndr.py
@@ -1,49 +1,28 @@
+#!/usr/bin/python
# -*- coding: utf-8 -*-
# Unix SMB/CIFS implementation.
# Copyright © Jelmer Vernooij <jelmer@samba.org> 2008
-#
+#
# 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/>.
#
-
-"""Network Data Representation (NDR) marshalling and unmarshalling."""
-
-
def ndr_pack(object):
- """Pack a NDR object.
-
- :param object: Object to pack
- :return: String object with marshalled object.
- """
- ndr_pack = getattr(object, "__ndr_pack__", None)
- if ndr_pack is None:
- raise TypeError("%r is not a NDR object" % object)
- return ndr_pack()
+ return object.__ndr_pack__()
def ndr_unpack(cls, data):
- """NDR unpack an object.
-
- :param cls: Class of the object to unpack
- :param data: Buffer to unpack
- :return: Unpacked object
- """
object = cls()
object.__ndr_unpack__(data)
return object
-
-
-def ndr_print(object):
- return object.__ndr_print__()
diff --git a/source4/scripting/python/samba/netcmd/__init__.py b/source4/scripting/python/samba/netcmd/__init__.py
deleted file mode 100644
index aa74f657b2..0000000000
--- a/source4/scripting/python/samba/netcmd/__init__.py
+++ /dev/null
@@ -1,215 +0,0 @@
-#!/usr/bin/env python
-
-# Unix SMB/CIFS implementation.
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2009
-#
-# 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/>.
-#
-
-import optparse, samba
-from samba import getopt as options
-from ldb import LdbError
-import sys, traceback
-
-
-class Option(optparse.Option):
- pass
-
-
-class Command(object):
- """A net command."""
-
- def _get_description(self):
- return self.__doc__.splitlines()[0].rstrip("\n")
-
- def _get_name(self):
- name = self.__class__.__name__
- if name.startswith("cmd_"):
- return name[4:]
- return name
-
- name = property(_get_name)
-
- def usage(self, *args):
- parser, _ = self._create_parser()
- parser.print_usage()
-
- description = property(_get_description)
-
- def _get_synopsis(self):
- ret = self.name
- if self.takes_args:
- ret += " " + " ".join([x.upper() for x in self.takes_args])
- return ret
-
- def show_command_error(self, e):
- '''display a command error'''
- if isinstance(e, CommandError):
- (etype, evalue, etraceback) = e.exception_info
- inner_exception = e.inner_exception
- message = e.message
- force_traceback = False
- else:
- (etype, evalue, etraceback) = sys.exc_info()
- inner_exception = e
- message = "uncaught exception"
- force_traceback = True
-
- if isinstance(inner_exception, LdbError):
- (ldb_ecode, ldb_emsg) = inner_exception
- print >>sys.stderr, "ERROR(ldb): %s - %s" % (message, ldb_emsg)
- elif isinstance(inner_exception, AssertionError):
- print >>sys.stderr, "ERROR(assert): %s" % message
- force_traceback = True
- elif isinstance(inner_exception, RuntimeError):
- print >>sys.stderr, "ERROR(runtime): %s - %s" % (message, evalue)
- elif type(inner_exception) is Exception:
- print >>sys.stderr, "ERROR(exception): %s - %s" % (message, evalue)
- force_traceback = True
- elif inner_exception is None:
- print >>sys.stderr, "ERROR: %s" % (message)
- else:
- print >>sys.stderr, "ERROR(%s): %s - %s" % (str(etype), message, evalue)
- force_traceback = True
-
- if force_traceback or samba.get_debug_level() >= 3:
- traceback.print_tb(etraceback)
-
-
- synopsis = property(_get_synopsis)
-
- outf = sys.stdout
-
- takes_args = []
- takes_options = []
- takes_optiongroups = {}
-
- def _create_parser(self):
- parser = optparse.OptionParser(self.synopsis)
- parser.prog = "net"
- parser.add_options(self.takes_options)
- optiongroups = {}
- for name, optiongroup in self.takes_optiongroups.iteritems():
- optiongroups[name] = optiongroup(parser)
- parser.add_option_group(optiongroups[name])
- return parser, optiongroups
-
- def message(self, text):
- print text
-
- def _run(self, *argv):
- parser, optiongroups = self._create_parser()
- opts, args = parser.parse_args(list(argv))
- # Filter out options from option groups
- args = args[1:]
- kwargs = dict(opts.__dict__)
- for option_group in parser.option_groups:
- for option in option_group.option_list:
- if option.dest is not None:
- del kwargs[option.dest]
- kwargs.update(optiongroups)
- min_args = 0
- max_args = 0
- for i, arg in enumerate(self.takes_args):
- if arg[-1] not in ("?", "*"):
- min_args += 1
- max_args += 1
- if arg[-1] == "*":
- max_args = -1
- if len(args) < min_args or (max_args != -1 and len(args) > max_args):
- self.usage(*args)
- return -1
- try:
- return self.run(*args, **kwargs)
- except Exception, e:
- self.show_command_error(e)
- return -1
-
- def run(self):
- """Run the command. This should be overriden by all subclasses."""
- raise NotImplementedError(self.run)
-
-
-class SuperCommand(Command):
- """A command with subcommands."""
-
- subcommands = {}
-
- def _run(self, myname, subcommand=None, *args):
- if subcommand in self.subcommands:
- return self.subcommands[subcommand]._run(subcommand, *args)
- print "Available subcommands:"
- for cmd in self.subcommands:
- print "\t%-20s - %s" % (cmd, self.subcommands[cmd].description)
- if subcommand in [None, 'help', '-h', '--help' ]:
- return 0
- raise CommandError("No such subcommand '%s'" % subcommand)
-
- def usage(self, myname, subcommand=None, *args):
- if subcommand is None or not subcommand in self.subcommands:
- print "Usage: %s (%s) [options]" % (myname,
- " | ".join(self.subcommands.keys()))
- else:
- return self.subcommands[subcommand].usage(*args)
-
-
-class CommandError(Exception):
- '''an exception class for netcmd errors'''
- def __init__(self, message, inner_exception=None):
- self.message = message
- self.inner_exception = inner_exception
- self.exception_info = sys.exc_info()
-
-
-commands = {}
-from samba.netcmd.pwsettings import cmd_pwsettings
-commands["pwsettings"] = cmd_pwsettings()
-from samba.netcmd.domainlevel import cmd_domainlevel
-commands["domainlevel"] = cmd_domainlevel()
-from samba.netcmd.setpassword import cmd_setpassword
-commands["setpassword"] = cmd_setpassword()
-from samba.netcmd.setexpiry import cmd_setexpiry
-commands["setexpiry"] = cmd_setexpiry()
-from samba.netcmd.enableaccount import cmd_enableaccount
-commands["enableaccount"] = cmd_enableaccount()
-from samba.netcmd.newuser import cmd_newuser
-commands["newuser"] = cmd_newuser()
-from samba.netcmd.netacl import cmd_acl
-commands["acl"] = cmd_acl()
-from samba.netcmd.fsmo import cmd_fsmo
-commands["fsmo"] = cmd_fsmo()
-from samba.netcmd.export import cmd_export
-commands["export"] = cmd_export()
-from samba.netcmd.time import cmd_time
-commands["time"] = cmd_time()
-from samba.netcmd.user import cmd_user
-commands["user"] = cmd_user()
-from samba.netcmd.vampire import cmd_vampire
-commands["vampire"] = cmd_vampire()
-from samba.netcmd.machinepw import cmd_machinepw
-commands["machinepw"] = cmd_machinepw()
-from samba.netcmd.spn import cmd_spn
-commands["spn"] = cmd_spn()
-from samba.netcmd.group import cmd_group
-commands["group"] = cmd_group()
-from samba.netcmd.join import cmd_join
-commands["join"] = cmd_join()
-from samba.netcmd.rodc import cmd_rodc
-commands["rodc"] = cmd_rodc()
-from samba.netcmd.drs import cmd_drs
-commands["drs"] = cmd_drs()
-from samba.netcmd.gpo import cmd_gpo
-commands["gpo2"] = cmd_gpo()
-from samba.netcmd.ldapcmp import cmd_ldapcmp
-commands["ldapcmp"] = cmd_ldapcmp()
diff --git a/source4/scripting/python/samba/netcmd/common.py b/source4/scripting/python/samba/netcmd/common.py
deleted file mode 100644
index bd72c8f361..0000000000
--- a/source4/scripting/python/samba/netcmd/common.py
+++ /dev/null
@@ -1,24 +0,0 @@
-#!/usr/bin/env python
-#
-# common functions for samba-tool python commands
-#
-# Copyright Andrew Tridgell 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/>.
-#
-
-def netcmd_dnsname(lp):
- '''return the full DNS name of our own host. Used as a default
- for hostname when running status queries'''
- return lp.get('netbios name').lower() + "." + lp.get('realm').lower()
diff --git a/source4/scripting/python/samba/netcmd/domainlevel.py b/source4/scripting/python/samba/netcmd/domainlevel.py
deleted file mode 100644
index 3d50ccea78..0000000000
--- a/source4/scripting/python/samba/netcmd/domainlevel.py
+++ /dev/null
@@ -1,247 +0,0 @@
-#!/usr/bin/env python
-#
-# Raises domain and forest function levels
-#
-# Copyright Matthias Dieter Wallnoefer 2009
-# Copyright Jelmer Vernooij 2009
-#
-# 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/>.
-#
-
-# Notice: At the moment we have some more checks to do here on the special
-# attributes (consider attribute "msDS-Behavior-Version). This is due to the
-# fact that we on s4 LDB don't implement their change policy (only certain
-# values, only increments possible...) yet.
-
-import samba.getopt as options
-import ldb
-
-from samba.auth import system_session
-from samba.netcmd import (
- Command,
- CommandError,
- Option,
- )
-from samba.samdb import SamDB
-from samba.dsdb import (
- DS_DOMAIN_FUNCTION_2000,
- DS_DOMAIN_FUNCTION_2003,
- DS_DOMAIN_FUNCTION_2003_MIXED,
- DS_DOMAIN_FUNCTION_2008,
- DS_DOMAIN_FUNCTION_2008_R2,
- )
-
-class cmd_domainlevel(Command):
- """Raises domain and forest function levels"""
-
- synopsis = "(show | raise <options>)"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "credopts": options.CredentialsOptions,
- "versionopts": options.VersionOptions,
- }
-
- takes_options = [
- Option("-H", help="LDB URL for database or target server", type=str),
- Option("--quiet", help="Be quiet", action="store_true"),
- Option("--forest", type="choice", choices=["2003", "2008", "2008_R2"],
- help="The forest function level (2003 | 2008 | 2008_R2)"),
- Option("--domain", type="choice", choices=["2003", "2008", "2008_R2"],
- help="The domain function level (2003 | 2008 | 2008_R2)"),
- ]
-
- takes_args = ["subcommand"]
-
- def run(self, subcommand, H=None, forest=None, domain=None, quiet=False,
- credopts=None, sambaopts=None, versionopts=None):
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp, fallback_machine=True)
-
- samdb = SamDB(url=H, session_info=system_session(),
- credentials=creds, lp=lp)
-
- domain_dn = samdb.domain_dn()
-
- res_forest = samdb.search("CN=Partitions,CN=Configuration," + domain_dn,
- scope=ldb.SCOPE_BASE, attrs=["msDS-Behavior-Version"])
- assert len(res_forest) == 1
-
- res_domain = samdb.search(domain_dn, scope=ldb.SCOPE_BASE,
- attrs=["msDS-Behavior-Version", "nTMixedDomain"])
- assert len(res_domain) == 1
-
- res_dc_s = samdb.search("CN=Sites,CN=Configuration," + domain_dn,
- scope=ldb.SCOPE_SUBTREE, expression="(objectClass=nTDSDSA)",
- attrs=["msDS-Behavior-Version"])
- assert len(res_dc_s) >= 1
-
- try:
- level_forest = int(res_forest[0]["msDS-Behavior-Version"][0])
- level_domain = int(res_domain[0]["msDS-Behavior-Version"][0])
- level_domain_mixed = int(res_domain[0]["nTMixedDomain"][0])
-
- min_level_dc = int(res_dc_s[0]["msDS-Behavior-Version"][0]) # Init value
- for msg in res_dc_s:
- if int(msg["msDS-Behavior-Version"][0]) < min_level_dc:
- min_level_dc = int(msg["msDS-Behavior-Version"][0])
-
- if level_forest < 0 or level_domain < 0:
- raise CommandError("Domain and/or forest function level(s) is/are invalid. Correct them or reprovision!")
- if min_level_dc < 0:
- raise CommandError("Lowest function level of a DC is invalid. Correct this or reprovision!")
- if level_forest > level_domain:
- raise CommandError("Forest function level is higher than the domain level(s). Correct this or reprovision!")
- if level_domain > min_level_dc:
- raise CommandError("Domain function level is higher than the lowest function level of a DC. Correct this or reprovision!")
-
- except KeyError:
- raise CommandError("Could not retrieve the actual domain, forest level and/or lowest DC function level!")
-
- if subcommand == "show":
- self.message("Domain and forest function level for domain '%s'" % domain_dn)
- if level_forest == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed != 0:
- self.message("\nATTENTION: You run SAMBA 4 on a forest function level lower than Windows 2000 (Native). This isn't supported! Please raise!")
- if level_domain == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed != 0:
- self.message("\nATTENTION: You run SAMBA 4 on a domain function level lower than Windows 2000 (Native). This isn't supported! Please raise!")
- if min_level_dc == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed != 0:
- self.message("\nATTENTION: You run SAMBA 4 on a lowest function level of a DC lower than Windows 2003. This isn't supported! Please step-up or upgrade the concerning DC(s)!")
-
- self.message("")
-
- if level_forest == DS_DOMAIN_FUNCTION_2000:
- outstr = "2000"
- elif level_forest == DS_DOMAIN_FUNCTION_2003_MIXED:
- outstr = "2003 with mixed domains/interim (NT4 DC support)"
- elif level_forest == DS_DOMAIN_FUNCTION_2003:
- outstr = "2003"
- elif level_forest == DS_DOMAIN_FUNCTION_2008:
- outstr = "2008"
- elif level_forest == DS_DOMAIN_FUNCTION_2008_R2:
- outstr = "2008 R2"
- else:
- outstr = "higher than 2008 R2"
- self.message("Forest function level: (Windows) " + outstr)
-
- if level_domain == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed != 0:
- outstr = "2000 mixed (NT4 DC support)"
- elif level_domain == DS_DOMAIN_FUNCTION_2000 and level_domain_mixed == 0:
- outstr = "2000"
- elif level_domain == DS_DOMAIN_FUNCTION_2003_MIXED:
- outstr = "2003 with mixed domains/interim (NT4 DC support)"
- elif level_domain == DS_DOMAIN_FUNCTION_2003:
- outstr = "2003"
- elif level_domain == DS_DOMAIN_FUNCTION_2008:
- outstr = "2008"
- elif level_domain == DS_DOMAIN_FUNCTION_2008_R2:
- outstr = "2008 R2"
- else:
- outstr = "higher than 2008 R2"
- self.message("Domain function level: (Windows) " + outstr)
-
- if min_level_dc == DS_DOMAIN_FUNCTION_2000:
- outstr = "2000"
- elif min_level_dc == DS_DOMAIN_FUNCTION_2003:
- outstr = "2003"
- elif min_level_dc == DS_DOMAIN_FUNCTION_2008:
- outstr = "2008"
- elif min_level_dc == DS_DOMAIN_FUNCTION_2008_R2:
- outstr = "2008 R2"
- else:
- outstr = "higher than 2008 R2"
- self.message("Lowest function level of a DC: (Windows) " + outstr)
-
- elif subcommand == "raise":
- msgs = []
-
- if domain is not None:
- if domain == "2003":
- new_level_domain = DS_DOMAIN_FUNCTION_2003
- elif domain == "2008":
- new_level_domain = DS_DOMAIN_FUNCTION_2008
- elif domain == "2008_R2":
- new_level_domain = DS_DOMAIN_FUNCTION_2008_R2
-
- if new_level_domain <= level_domain and level_domain_mixed == 0:
- raise CommandError("Domain function level can't be smaller equal to the actual one!")
-
- if new_level_domain > min_level_dc:
- raise CommandError("Domain function level can't be higher than the lowest function level of a DC!")
-
- # Deactivate mixed/interim domain support
- if level_domain_mixed != 0:
- # Directly on the base DN
- m = ldb.Message()
- m.dn = ldb.Dn(samdb, domain_dn)
- m["nTMixedDomain"] = ldb.MessageElement("0",
- ldb.FLAG_MOD_REPLACE, "nTMixedDomain")
- samdb.modify(m)
- # Under partitions
- m = ldb.Message()
- m.dn = ldb.Dn(samdb, "CN=" + lp.get("workgroup")
- + ",CN=Partitions,CN=Configuration," + domain_dn)
- m["nTMixedDomain"] = ldb.MessageElement("0",
- ldb.FLAG_MOD_REPLACE, "nTMixedDomain")
- try:
- samdb.modify(m)
- except ldb.LdbError, (enum, emsg):
- if enum != ldb.ERR_UNWILLING_TO_PERFORM:
- raise
-
- # Directly on the base DN
- m = ldb.Message()
- m.dn = ldb.Dn(samdb, domain_dn)
- m["msDS-Behavior-Version"]= ldb.MessageElement(
- str(new_level_domain), ldb.FLAG_MOD_REPLACE,
- "msDS-Behavior-Version")
- samdb.modify(m)
- # Under partitions
- m = ldb.Message()
- m.dn = ldb.Dn(samdb, "CN=" + lp.get("workgroup")
- + ",CN=Partitions,CN=Configuration," + domain_dn)
- m["msDS-Behavior-Version"]= ldb.MessageElement(
- str(new_level_domain), ldb.FLAG_MOD_REPLACE,
- "msDS-Behavior-Version")
- try:
- samdb.modify(m)
- except ldb.LdbError, (enum, emsg):
- if enum != ldb.ERR_UNWILLING_TO_PERFORM:
- raise
-
- level_domain = new_level_domain
- msgs.append("Domain function level changed!")
-
- if forest is not None:
- if forest == "2003":
- new_level_forest = DS_DOMAIN_FUNCTION_2003
- elif forest == "2008":
- new_level_forest = DS_DOMAIN_FUNCTION_2008
- elif forest == "2008_R2":
- new_level_forest = DS_DOMAIN_FUNCTION_2008_R2
- if new_level_forest <= level_forest:
- raise CommandError("Forest function level can't be smaller equal to the actual one!")
- if new_level_forest > level_domain:
- raise CommandError("Forest function level can't be higher than the domain function level(s). Please raise it/them first!")
- m = ldb.Message()
- m.dn = ldb.Dn(samdb, "CN=Partitions,CN=Configuration,"
- + domain_dn)
- m["msDS-Behavior-Version"]= ldb.MessageElement(
- str(new_level_forest), ldb.FLAG_MOD_REPLACE,
- "msDS-Behavior-Version")
- samdb.modify(m)
- msgs.append("Forest function level changed!")
- msgs.append("All changes applied successfully!")
- self.message("\n".join(msgs))
- else:
- raise CommandError("Wrong argument '%s'!" % subcommand)
diff --git a/source4/scripting/python/samba/netcmd/drs.py b/source4/scripting/python/samba/netcmd/drs.py
deleted file mode 100644
index 7dea9de856..0000000000
--- a/source4/scripting/python/samba/netcmd/drs.py
+++ /dev/null
@@ -1,477 +0,0 @@
-#!/usr/bin/env python
-#
-# implement samba_tool drs commands
-#
-# Copyright Andrew Tridgell 2010
-#
-# based on C implementation by Kamen Mazdrashki <kamen.mazdrashki@postpath.com>
-#
-# 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/>.
-#
-
-import samba.getopt as options
-import ldb
-
-from samba.auth import system_session
-from samba.netcmd import (
- Command,
- CommandError,
- Option,
- SuperCommand,
- )
-from samba.samdb import SamDB
-from samba import drs_utils, nttime2string, dsdb
-from samba.dcerpc import drsuapi, misc
-import common
-
-def drsuapi_connect(ctx):
- '''make a DRSUAPI connection to the server'''
- binding_options = "seal"
- if ctx.lp.get("log level") >= 5:
- binding_options += ",print"
- binding_string = "ncacn_ip_tcp:%s[%s]" % (ctx.server, binding_options)
- try:
- ctx.drsuapi = drsuapi.drsuapi(binding_string, ctx.lp, ctx.creds)
- (ctx.drsuapi_handle, ctx.bind_supported_extensions) = drs_utils.drs_DsBind(ctx.drsuapi)
- except Exception, e:
- raise CommandError("DRS connection to %s failed" % ctx.server, e)
-
-
-def samdb_connect(ctx):
- '''make a ldap connection to the server'''
- try:
- ctx.samdb = SamDB(url="ldap://%s" % ctx.server,
- session_info=system_session(),
- credentials=ctx.creds, lp=ctx.lp)
- except Exception, e:
- raise CommandError("LDAP connection to %s failed" % ctx.server, e)
-
-
-def drs_errmsg(werr):
- '''return "was successful" or an error string'''
- (ecode, estring) = werr
- if ecode == 0:
- return "was successful"
- return "failed, result %u (%s)" % (ecode, estring)
-
-
-def attr_default(msg, attrname, default):
- '''get an attribute from a ldap msg with a default'''
- if attrname in msg:
- return msg[attrname][0]
- return default
-
-
-def drs_parse_ntds_dn(ntds_dn):
- '''parse a NTDS DN returning a site and server'''
- a = ntds_dn.split(',')
- if a[0] != "CN=NTDS Settings" or a[2] != "CN=Servers" or a[4] != 'CN=Sites':
- raise RuntimeError("bad NTDS DN %s" % ntds_dn)
- server = a[1].split('=')[1]
- site = a[3].split('=')[1]
- return (site, server)
-
-
-def get_dsServiceName(samdb):
- '''get the NTDS DN from the rootDSE'''
- res = samdb.search(base="", scope=ldb.SCOPE_BASE, attrs=["dsServiceName"])
- return res[0]["dsServiceName"][0]
-
-
-class cmd_drs_showrepl(Command):
- """show replication status"""
-
- synopsis = "%prog drs showrepl <DC>"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "versionopts": options.VersionOptions,
- "credopts": options.CredentialsOptions,
- }
-
- takes_args = ["DC?"]
-
- def print_neighbour(self, n):
- '''print one set of neighbour information'''
- self.message("%s" % n.naming_context_dn)
- try:
- (site, server) = drs_parse_ntds_dn(n.source_dsa_obj_dn)
- self.message("\t%s\%s via RPC" % (site, server))
- except RuntimeError:
- self.message("\tNTDS DN: %s" % n.source_dsa_obj_dn)
- self.message("\t\tDSA object GUID: %s" % n.source_dsa_obj_guid)
- self.message("\t\tLast attempt @ %s %s" % (nttime2string(n.last_attempt),
- drs_errmsg(n.result_last_attempt)))
- self.message("\t\t%u consecutive failure(s)." % n.consecutive_sync_failures)
- self.message("\t\tLast success @ %s" % nttime2string(n.last_success))
- self.message("")
-
- def drsuapi_ReplicaInfo(ctx, info_type):
- '''call a DsReplicaInfo'''
-
- req1 = drsuapi.DsReplicaGetInfoRequest1()
- req1.info_type = info_type
- try:
- (info_type, info) = ctx.drsuapi.DsReplicaGetInfo(ctx.drsuapi_handle, 1, req1)
- except Exception, e:
- raise CommandError("DsReplicaGetInfo of type %u failed" % info_type, e)
- return (info_type, info)
-
-
- def run(self, DC=None, sambaopts=None,
- credopts=None, versionopts=None, server=None):
-
- self.lp = sambaopts.get_loadparm()
- if DC is None:
- DC = common.netcmd_dnsname(self.lp)
- self.server = DC
- self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
-
- drsuapi_connect(self)
- samdb_connect(self)
-
- # show domain information
- ntds_dn = get_dsServiceName(self.samdb)
- server_dns = self.samdb.search(base="", scope=ldb.SCOPE_BASE, attrs=["dnsHostName"])[0]['dnsHostName'][0]
-
- (site, server) = drs_parse_ntds_dn(ntds_dn)
- try:
- ntds = self.samdb.search(base=ntds_dn, scope=ldb.SCOPE_BASE, attrs=['options', 'objectGUID', 'invocationId'])
- except Exception, e:
- raise CommandError("Failed to search NTDS DN %s" % ntds_dn)
- conn = self.samdb.search(base=ntds_dn, expression="(objectClass=nTDSConnection)")
-
- self.message("%s\\%s" % (site, server))
- self.message("DSA Options: 0x%08x" % int(attr_default(ntds[0], "options", 0)))
- self.message("DSA object GUID: %s" % self.samdb.schema_format_value("objectGUID", ntds[0]["objectGUID"][0]))
- self.message("DSA invocationId: %s\n" % self.samdb.schema_format_value("objectGUID", ntds[0]["invocationId"][0]))
-
- self.message("==== INBOUND NEIGHBORS ====\n")
- (info_type, info) = self.drsuapi_ReplicaInfo(drsuapi.DRSUAPI_DS_REPLICA_INFO_NEIGHBORS)
- for n in info.array:
- self.print_neighbour(n)
-
-
- self.message("==== OUTBOUND NEIGHBORS ====\n")
- (info_type, info) = self.drsuapi_ReplicaInfo(drsuapi.DRSUAPI_DS_REPLICA_INFO_REPSTO)
- for n in info.array:
- self.print_neighbour(n)
-
- reasons = ['NTDSCONN_KCC_GC_TOPOLOGY',
- 'NTDSCONN_KCC_RING_TOPOLOGY',
- 'NTDSCONN_KCC_MINIMIZE_HOPS_TOPOLOGY',
- 'NTDSCONN_KCC_STALE_SERVERS_TOPOLOGY',
- 'NTDSCONN_KCC_OSCILLATING_CONNECTION_TOPOLOGY',
- 'NTDSCONN_KCC_INTERSITE_GC_TOPOLOGY',
- 'NTDSCONN_KCC_INTERSITE_TOPOLOGY',
- 'NTDSCONN_KCC_SERVER_FAILOVER_TOPOLOGY',
- 'NTDSCONN_KCC_SITE_FAILOVER_TOPOLOGY',
- 'NTDSCONN_KCC_REDUNDANT_SERVER_TOPOLOGY']
-
- self.message("==== KCC CONNECTION OBJECTS ====\n")
- for c in conn:
- self.message("Connection --")
- self.message("\tConnection name: %s" % c['name'][0])
- self.message("\tEnabled : %s" % attr_default(c, 'enabledConnection', 'TRUE'))
- self.message("\tServer DNS name : %s" % server_dns)
- self.message("\tServer DN name : %s" % c['fromServer'][0])
- self.message("\t\tTransportType: RPC")
- self.message("\t\toptions: 0x%08X" % int(attr_default(c, 'options', 0)))
- if not 'mS-DS-ReplicatesNCReason' in c:
- self.message("Warning: No NC replicated for Connection!")
- continue
- for r in c['mS-DS-ReplicatesNCReason']:
- a = str(r).split(':')
- self.message("\t\tReplicatesNC: %s" % a[3])
- self.message("\t\tReason: 0x%08x" % int(a[2]))
- for s in reasons:
- if getattr(dsdb, s, 0) & int(a[2]):
- self.message("\t\t\t%s" % s)
-
-
-class cmd_drs_kcc(Command):
- """trigger knowledge consistency center run"""
-
- synopsis = "%prog drs kcc <DC>"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "versionopts": options.VersionOptions,
- "credopts": options.CredentialsOptions,
- }
-
- takes_args = ["DC?"]
-
- def run(self, DC=None, sambaopts=None,
- credopts=None, versionopts=None, server=None):
-
- self.lp = sambaopts.get_loadparm()
- if DC is None:
- DC = common.netcmd_dnsname(self.lp)
- self.server = DC
-
- self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
-
- drsuapi_connect(self)
-
- req1 = drsuapi.DsExecuteKCC1()
- try:
- self.drsuapi.DsExecuteKCC(self.drsuapi_handle, 1, req1)
- except Exception, e:
- raise CommandError("DsExecuteKCC failed", e)
- self.message("Consistency check on %s successful." % DC)
-
-
-
-class cmd_drs_replicate(Command):
- """replicate a naming context between two DCs"""
-
- synopsis = "%prog drs replicate <DEST_DC> <SOURCE_DC> <NC>"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "versionopts": options.VersionOptions,
- "credopts": options.CredentialsOptions,
- }
-
- takes_args = ["DEST_DC", "SOURCE_DC", "NC"]
-
- takes_options = [
- Option("--add-ref", help="use ADD_REF to add to repsTo on source", action="store_true"),
- Option("--sync-forced", help="use SYNC_FORCED to force inbound replication", action="store_true"),
- ]
-
- def run(self, DEST_DC, SOURCE_DC, NC, add_ref=False, sync_forced=False,
- sambaopts=None,
- credopts=None, versionopts=None, server=None):
-
- self.server = DEST_DC
- self.lp = sambaopts.get_loadparm()
-
- self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
-
- drsuapi_connect(self)
- samdb_connect(self)
-
- # we need to find the NTDS GUID of the source DC
- msg = self.samdb.search(base=self.samdb.get_config_basedn(),
- expression="(&(objectCategory=server)(|(name=%s)(dNSHostName=%s)))" % (SOURCE_DC,
- SOURCE_DC),
- attrs=[])
- if len(msg) == 0:
- raise CommandError("Failed to find source DC %s" % SOURCE_DC)
- server_dn = msg[0]['dn']
-
- msg = self.samdb.search(base=server_dn, scope=ldb.SCOPE_ONELEVEL,
- expression="(|(objectCategory=nTDSDSA)(objectCategory=nTDSDSARO))",
- attrs=['objectGUID', 'options'])
- if len(msg) == 0:
- raise CommandError("Failed to find source NTDS DN %s" % SOURCE_DC)
- source_dsa_guid = msg[0]['objectGUID'][0]
- options = int(attr_default(msg, 'options', 0))
-
- nc = drsuapi.DsReplicaObjectIdentifier()
- nc.dn = NC
-
- req1 = drsuapi.DsReplicaSyncRequest1()
- req1.naming_context = nc;
- req1.options = 0
- if not (options & dsdb.DS_NTDSDSA_OPT_DISABLE_OUTBOUND_REPL):
- req1.options |= drsuapi.DRSUAPI_DRS_WRIT_REP
- if add_ref:
- req1.options |= drsuapi.DRSUAPI_DRS_ADD_REF
- if sync_forced:
- req1.options |= drsuapi.DRSUAPI_DRS_SYNC_FORCED
- req1.source_dsa_guid = misc.GUID(source_dsa_guid)
-
- try:
- self.drsuapi.DsReplicaSync(self.drsuapi_handle, 1, req1)
- except Exception, estr:
- raise CommandError("DsReplicaSync failed", estr)
- self.message("Replicate from %s to %s was successful." % (SOURCE_DC, DEST_DC))
-
-
-
-class cmd_drs_bind(Command):
- """show DRS capabilities of a server"""
-
- synopsis = "%prog drs bind <DC>"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "versionopts": options.VersionOptions,
- "credopts": options.CredentialsOptions,
- }
-
- takes_args = ["DC?"]
-
- def run(self, DC=None, sambaopts=None,
- credopts=None, versionopts=None, server=None):
-
- self.lp = sambaopts.get_loadparm()
- if DC is None:
- DC = common.netcmd_dnsname(self.lp)
- self.server = DC
- self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
-
- drsuapi_connect(self)
- samdb_connect(self)
-
- bind_info = drsuapi.DsBindInfoCtr()
- bind_info.length = 28
- bind_info.info = drsuapi.DsBindInfo28()
- (info, handle) = self.drsuapi.DsBind(misc.GUID(drsuapi.DRSUAPI_DS_BIND_GUID), bind_info)
-
- optmap = [
- ("DRSUAPI_SUPPORTED_EXTENSION_BASE" , "DRS_EXT_BASE"),
- ("DRSUAPI_SUPPORTED_EXTENSION_ASYNC_REPLICATION" , "DRS_EXT_ASYNCREPL"),
- ("DRSUAPI_SUPPORTED_EXTENSION_REMOVEAPI" , "DRS_EXT_REMOVEAPI"),
- ("DRSUAPI_SUPPORTED_EXTENSION_MOVEREQ_V2" , "DRS_EXT_MOVEREQ_V2"),
- ("DRSUAPI_SUPPORTED_EXTENSION_GETCHG_COMPRESS" , "DRS_EXT_GETCHG_DEFLATE"),
- ("DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V1" , "DRS_EXT_DCINFO_V1"),
- ("DRSUAPI_SUPPORTED_EXTENSION_RESTORE_USN_OPTIMIZATION" , "DRS_EXT_RESTORE_USN_OPTIMIZATION"),
- ("DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY" , "DRS_EXT_ADDENTRY"),
- ("DRSUAPI_SUPPORTED_EXTENSION_KCC_EXECUTE" , "DRS_EXT_KCC_EXECUTE"),
- ("DRSUAPI_SUPPORTED_EXTENSION_ADDENTRY_V2" , "DRS_EXT_ADDENTRY_V2"),
- ("DRSUAPI_SUPPORTED_EXTENSION_LINKED_VALUE_REPLICATION" , "DRS_EXT_LINKED_VALUE_REPLICATION"),
- ("DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V2" , "DRS_EXT_DCINFO_V2"),
- ("DRSUAPI_SUPPORTED_EXTENSION_INSTANCE_TYPE_NOT_REQ_ON_MOD","DRS_EXT_INSTANCE_TYPE_NOT_REQ_ON_MOD"),
- ("DRSUAPI_SUPPORTED_EXTENSION_CRYPTO_BIND" , "DRS_EXT_CRYPTO_BIND"),
- ("DRSUAPI_SUPPORTED_EXTENSION_GET_REPL_INFO" , "DRS_EXT_GET_REPL_INFO"),
- ("DRSUAPI_SUPPORTED_EXTENSION_STRONG_ENCRYPTION" , "DRS_EXT_STRONG_ENCRYPTION"),
- ("DRSUAPI_SUPPORTED_EXTENSION_DCINFO_V01" , "DRS_EXT_DCINFO_VFFFFFFFF"),
- ("DRSUAPI_SUPPORTED_EXTENSION_TRANSITIVE_MEMBERSHIP" , "DRS_EXT_TRANSITIVE_MEMBERSHIP"),
- ("DRSUAPI_SUPPORTED_EXTENSION_ADD_SID_HISTORY" , "DRS_EXT_ADD_SID_HISTORY"),
- ("DRSUAPI_SUPPORTED_EXTENSION_POST_BETA3" , "DRS_EXT_POST_BETA3"),
- ("DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V5" , "DRS_EXT_GETCHGREQ_V5"),
- ("DRSUAPI_SUPPORTED_EXTENSION_GET_MEMBERSHIPS2" , "DRS_EXT_GETMEMBERSHIPS2"),
- ("DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V6" , "DRS_EXT_GETCHGREQ_V6"),
- ("DRSUAPI_SUPPORTED_EXTENSION_NONDOMAIN_NCS" , "DRS_EXT_NONDOMAIN_NCS"),
- ("DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V8" , "DRS_EXT_GETCHGREQ_V8"),
- ("DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V5" , "DRS_EXT_GETCHGREPLY_V5"),
- ("DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V6" , "DRS_EXT_GETCHGREPLY_V6"),
- ("DRSUAPI_SUPPORTED_EXTENSION_ADDENTRYREPLY_V3" , "DRS_EXT_WHISTLER_BETA3"),
- ("DRSUAPI_SUPPORTED_EXTENSION_GETCHGREPLY_V7" , "DRS_EXT_WHISTLER_BETA3"),
- ("DRSUAPI_SUPPORTED_EXTENSION_VERIFY_OBJECT" , "DRS_EXT_WHISTLER_BETA3"),
- ("DRSUAPI_SUPPORTED_EXTENSION_XPRESS_COMPRESS" , "DRS_EXT_W2K3_DEFLATE"),
- ("DRSUAPI_SUPPORTED_EXTENSION_GETCHGREQ_V10" , "DRS_EXT_GETCHGREQ_V10"),
- ("DRSUAPI_SUPPORTED_EXTENSION_RESERVED_PART2" , "DRS_EXT_RESERVED_FOR_WIN2K_OR_DOTNET_PART2"),
- ("DRSUAPI_SUPPORTED_EXTENSION_RESERVED_PART3" , "DRS_EXT_RESERVED_FOR_WIN2K_OR_DOTNET_PART3")
- ]
-
- optmap_ext = [
- ("DRSUAPI_SUPPORTED_EXTENSION_ADAM", "DRS_EXT_ADAM"),
- ("DRSUAPI_SUPPORTED_EXTENSION_LH_BETA2", "DRS_EXT_LH_BETA2"),
- ("DRSUAPI_SUPPORTED_EXTENSION_RECYCLE_BIN", "DRS_EXT_RECYCLE_BIN")]
-
- self.message("Bind to %s succeeded." % DC)
- self.message("Extensions supported:")
- for (opt, str) in optmap:
- optval = getattr(drsuapi, opt, 0)
- if info.info.supported_extensions & optval:
- yesno = "Yes"
- else:
- yesno = "No "
- self.message(" %-60s: %s (%s)" % (opt, yesno, str))
-
- if isinstance(info.info, drsuapi.DsBindInfo48):
- self.message("\nExtended Extensions supported:")
- for (opt, str) in optmap_ext:
- optval = getattr(drsuapi, opt, 0)
- if info.info.supported_extensions_ext & optval:
- yesno = "Yes"
- else:
- yesno = "No "
- self.message(" %-60s: %s (%s)" % (opt, yesno, str))
-
- self.message("\nSite GUID: %s" % info.info.site_guid)
- self.message("Repl epoch: %u" % info.info.repl_epoch)
- if isinstance(info.info, drsuapi.DsBindInfo48):
- self.message("Forest GUID: %s" % info.info.config_dn_guid)
-
-
-
-class cmd_drs_options(Command):
- """query or change 'options' for NTDS Settings object of a domain controller"""
-
- synopsis = ("%prog drs options <DC>"
- " [--dsa-option={+|-}IS_GC | {+|-}DISABLE_INBOUND_REPL"
- " |{+|-}DISABLE_OUTBOUND_REPL | {+|-}DISABLE_NTDSCONN_XLATE]")
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "versionopts": options.VersionOptions,
- "credopts": options.CredentialsOptions,
- }
-
- takes_args = ["DC"]
-
- takes_options = [
- Option("--dsa-option", help="DSA option to enable/disable", type="str"),
- ]
-
- option_map = {"IS_GC": 0x00000001,
- "DISABLE_INBOUND_REPL": 0x00000002,
- "DISABLE_OUTBOUND_REPL": 0x00000004,
- "DISABLE_NTDSCONN_XLATE": 0x00000008}
-
- def run(self, DC, dsa_option=None,
- sambaopts=None, credopts=None, versionopts=None):
-
- self.lp = sambaopts.get_loadparm()
- if DC is None:
- DC = common.netcmd_dnsname(self.lp)
- self.server = DC
- self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
-
- samdb_connect(self)
-
- ntds_dn = get_dsServiceName(self.samdb)
- res = self.samdb.search(base=ntds_dn, scope=ldb.SCOPE_BASE, attrs=["options"])
- dsa_opts = int(res[0]["options"][0])
-
- # print out current DSA options
- cur_opts = [x for x in self.option_map if self.option_map[x] & dsa_opts]
- self.message("Current DSA options: " + ", ".join(cur_opts))
-
- # modify options
- if dsa_option:
- if dsa_option[:1] not in ("+", "-"):
- raise CommandError("Unknown option %s" % dsa_option)
- flag = dsa_option[1:]
- if flag not in self.option_map.keys():
- raise CommandError("Unknown option %s" % dsa_option)
- if dsa_option[:1] == "+":
- dsa_opts |= self.option_map[flag]
- else:
- dsa_opts &= ~self.option_map[flag]
- #save new options
- m = ldb.Message()
- m.dn = ldb.Dn(self.samdb, ntds_dn)
- m["options"]= ldb.MessageElement(str(dsa_opts), ldb.FLAG_MOD_REPLACE, "options")
- self.samdb.modify(m)
- # print out new DSA options
- cur_opts = [x for x in self.option_map if self.option_map[x] & dsa_opts]
- self.message("New DSA options: " + ", ".join(cur_opts))
-
-
-class cmd_drs(SuperCommand):
- """DRS commands"""
-
- subcommands = {}
- subcommands["bind"] = cmd_drs_bind()
- subcommands["kcc"] = cmd_drs_kcc()
- subcommands["replicate"] = cmd_drs_replicate()
- subcommands["showrepl"] = cmd_drs_showrepl()
- subcommands["options"] = cmd_drs_options()
diff --git a/source4/scripting/python/samba/netcmd/dsacl.py b/source4/scripting/python/samba/netcmd/dsacl.py
deleted file mode 100644
index 58a3552687..0000000000
--- a/source4/scripting/python/samba/netcmd/dsacl.py
+++ /dev/null
@@ -1,182 +0,0 @@
-#!/usr/bin/env python
-#
-# Manipulate ACLs on directory objects
-#
-# Copyright (C) Nadezhda Ivanova <nivanova@samba.org> 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/>.
-#
-
-import samba.getopt as options
-from samba.dcerpc import security
-from samba.samdb import SamDB
-from samba.ndr import ndr_unpack, ndr_pack
-from samba.dcerpc.security import (
- GUID_DRS_ALLOCATE_RIDS, GUID_DRS_CHANGE_DOMAIN_MASTER,
- GUID_DRS_CHANGE_INFR_MASTER, GUID_DRS_CHANGE_PDC,
- GUID_DRS_CHANGE_RID_MASTER, GUID_DRS_CHANGE_SCHEMA_MASTER,
- GUID_DRS_GET_CHANGES, GUID_DRS_GET_ALL_CHANGES,
- GUID_DRS_GET_FILTERED_ATTRIBUTES, GUID_DRS_MANAGE_TOPOLOGY,
- GUID_DRS_MONITOR_TOPOLOGY, GUID_DRS_REPL_SYNCRONIZE,
- GUID_DRS_RO_REPL_SECRET_SYNC)
-
-
-import ldb
-from ldb import SCOPE_BASE
-import re
-
-from samba.auth import system_session
-from samba.netcmd import (
- Command,
- CommandError,
- SuperCommand,
- Option,
- )
-
-class cmd_ds_acl_set(Command):
- """Modify access list on a directory object"""
-
- synopsis = "set --objectdn=objectdn --car=control right --action=[deny|allow] --trusteedn=trustee-dn"
- car_help = """ The access control right to allow or deny """
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "credopts": options.CredentialsOptions,
- "versionopts": options.VersionOptions,
- }
-
- takes_options = [
- Option("--host", help="LDB URL for database or target server",
- type=str),
- Option("--car", type="choice", choices=["change-rid",
- "change-pdc",
- "change-infrastructure",
- "change-schema",
- "change-naming",
- "allocate_rids",
- "get-changes",
- "get-changes-all",
- "get-changes-filtered",
- "topology-manage",
- "topology-monitor",
- "repl-sync",
- "ro-repl-secret-sync"],
- help=car_help),
- Option("--action", type="choice", choices=["allow", "deny"],
- help="""Deny or allow access"""),
- Option("--objectdn", help="DN of the object whose SD to modify",
- type="string"),
- Option("--trusteedn", help="DN of the entity that gets access",
- type="string"),
- Option("--sddl", help="An ACE or group of ACEs to be added on the object",
- type="string"),
- ]
-
- def find_trustee_sid(self, samdb, trusteedn):
- res = samdb.search(base=trusteedn, expression="(objectClass=*)",
- scope=SCOPE_BASE)
- assert(len(res) == 1)
- return ndr_unpack( security.dom_sid,res[0]["objectSid"][0])
-
- def modify_descriptor(self, samdb, object_dn, desc, controls=None):
- assert(isinstance(desc, security.descriptor))
- m = ldb.Message()
- m.dn = ldb.Dn(samdb, object_dn)
- m["nTSecurityDescriptor"]= ldb.MessageElement(
- (ndr_pack(desc)), ldb.FLAG_MOD_REPLACE,
- "nTSecurityDescriptor")
- samdb.modify(m)
-
- def read_descriptor(self, samdb, object_dn):
- res = samdb.search(base=object_dn, scope=SCOPE_BASE,
- attrs=["nTSecurityDescriptor"])
- # we should theoretically always have an SD
- assert(len(res) == 1)
- desc = res[0]["nTSecurityDescriptor"][0]
- return ndr_unpack(security.descriptor, desc)
-
- def get_domain_sid(self, samdb):
- res = samdb.search(base=samdb.domain_dn(),
- expression="(objectClass=*)", scope=SCOPE_BASE)
- return ndr_unpack( security.dom_sid,res[0]["objectSid"][0])
-
- def add_ace(self, samdb, object_dn, new_ace):
- """Add new ace explicitly."""
- desc = self.read_descriptor(samdb, object_dn)
- desc_sddl = desc.as_sddl(self.get_domain_sid(samdb))
- #TODO add bindings for descriptor manipulation and get rid of this
- desc_aces = re.findall("\(.*?\)", desc_sddl)
- for ace in desc_aces:
- if ("ID" in ace):
- desc_sddl = desc_sddl.replace(ace, "")
- if new_ace in desc_sddl:
- return
- if desc_sddl.find("(") >= 0:
- desc_sddl = desc_sddl[:desc_sddl.index("(")] + new_ace + desc_sddl[desc_sddl.index("("):]
- else:
- desc_sddl = desc_sddl + new_ace
- desc = security.descriptor.from_sddl(desc_sddl, self.get_domain_sid(samdb))
- self.modify_descriptor(samdb, object_dn, desc)
-
- def print_new_acl(self, samdb, object_dn):
- desc = self.read_descriptor(samdb, object_dn)
- desc_sddl = desc.as_sddl(self.get_domain_sid(samdb))
- print "new descriptor for %s:" % object_dn
- print desc_sddl
-
- def run(self, car, action, objectdn, trusteedn, sddl,
- host=None, credopts=None, sambaopts=None, versionopts=None):
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp)
-
- if sddl is None and (car is None or action is None
- or objectdn is None or trusteedn is None):
- return self.usage()
-
- samdb = SamDB(url=host, session_info=system_session(),
- credentials=creds, lp=lp)
- cars = {'change-rid' : GUID_DRS_CHANGE_RID_MASTER,
- 'change-pdc' : GUID_DRS_CHANGE_PDC,
- 'change-infrastructure' : GUID_DRS_CHANGE_INFR_MASTER,
- 'change-schema' : GUID_DRS_CHANGE_SCHEMA_MASTER,
- 'change-naming' : GUID_DRS_CHANGE_DOMAIN_MASTER,
- 'allocate_rids' : GUID_DRS_ALLOCATE_RIDS,
- 'get-changes' : GUID_DRS_GET_CHANGES,
- 'get-changes-all' : GUID_DRS_GET_ALL_CHANGES,
- 'get-changes-filtered' : GUID_DRS_GET_FILTERED_ATTRIBUTES,
- 'topology-manage' : GUID_DRS_MANAGE_TOPOLOGY,
- 'topology-monitor' : GUID_DRS_MONITOR_TOPOLOGY,
- 'repl-sync' : GUID_DRS_REPL_SYNCRONIZE,
- 'ro-repl-secret-sync' : GUID_DRS_RO_REPL_SECRET_SYNC,
- }
- sid = self.find_trustee_sid(samdb, trusteedn)
- if sddl:
- new_ace = sddl
- elif action == "allow":
- new_ace = "(OA;;CR;%s;;%s)" % (cars[car], str(sid))
- elif action == "deny":
- new_ace = "(OD;;CR;%s;;%s)" % (cars[car], str(sid))
- else:
- raise CommandError("Wrong argument '%s'!" % action)
-
- self.print_new_acl(samdb, objectdn)
- self.add_ace(samdb, objectdn, new_ace)
- self.print_new_acl(samdb, objectdn)
-
-
-class cmd_ds_acl(SuperCommand):
- """DS ACLs manipulation"""
-
- subcommands = {}
- subcommands["set"] = cmd_ds_acl_set()
diff --git a/source4/scripting/python/samba/netcmd/enableaccount.py b/source4/scripting/python/samba/netcmd/enableaccount.py
deleted file mode 100644
index 3ceddb3fd9..0000000000
--- a/source4/scripting/python/samba/netcmd/enableaccount.py
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/usr/bin/env python
-#
-# Enables an user account on a Samba4 server
-# Copyright Jelmer Vernooij 2008
-#
-# Based on the original in EJS:
-# Copyright Andrew Tridgell 2005
-#
-# 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/>.
-#
-
-import samba.getopt as options
-
-from samba.auth import system_session
-from samba.netcmd import Command, CommandError, Option
-from samba.samdb import SamDB
-
-class cmd_enableaccount(Command):
- """Enables a user"""
-
- synopsis = "enableaccount [username] [options]"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "versionopts": options.VersionOptions,
- "credopts": options.CredentialsOptions,
- }
-
- takes_options = [
- Option("-H", help="LDB URL for database or target server", type=str),
- Option("--filter", help="LDAP Filter to set password on", type=str),
- ]
-
- takes_args = ["username?"]
-
- def run(self, username=None, sambaopts=None, credopts=None,
- versionopts=None, filter=None, H=None):
- if username is None and filter is None:
- raise CommandError("Either the username or '--filter' must be specified!")
-
- if filter is None:
- filter = "(&(objectClass=user)(sAMAccountName=%s))" % (username)
-
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp, fallback_machine=True)
-
- samdb = SamDB(url=H, session_info=system_session(),
- credentials=creds, lp=lp)
- samdb.enable_account(filter)
diff --git a/source4/scripting/python/samba/netcmd/export.py b/source4/scripting/python/samba/netcmd/export.py
deleted file mode 100644
index 649a2621b1..0000000000
--- a/source4/scripting/python/samba/netcmd/export.py
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/env python
-#
-# Export keytab
-#
-# Copyright Jelmer Vernooij 2010 <jelmer@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/>.
-#
-
-import samba.getopt as options
-
-from samba.net import Net
-
-from samba.netcmd import (
- Command,
- SuperCommand,
- )
-
-class cmd_export_keytab(Command):
- """Dumps kerberos keys of the domain into a keytab"""
- synopsis = "%prog export keytab <keytab>"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "credopts": options.CredentialsOptions,
- "versionopts": options.VersionOptions,
- }
-
- takes_options = [
- ]
-
- takes_args = ["keytab"]
-
- def run(self, keytab, credopts=None, sambaopts=None, versionopts=None):
- lp = sambaopts.get_loadparm()
- net = Net(None, lp, server=credopts.ipaddress)
- net.export_keytab(keytab=keytab)
-
-
-class cmd_export(SuperCommand):
- """Dumps the sam of the domain we are joined to [server connection needed]"""
-
- subcommands = {}
- subcommands["keytab"] = cmd_export_keytab()
-
diff --git a/source4/scripting/python/samba/netcmd/fsmo.py b/source4/scripting/python/samba/netcmd/fsmo.py
deleted file mode 100644
index 0c8d17c74f..0000000000
--- a/source4/scripting/python/samba/netcmd/fsmo.py
+++ /dev/null
@@ -1,197 +0,0 @@
-#!/usr/bin/env python
-#
-# Changes a FSMO role owner
-#
-# Copyright Nadezhda Ivanova 2009
-# Copyright Jelmer Vernooij 2009
-#
-# 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/>.
-#
-
-import samba.getopt as options
-import ldb
-from ldb import LdbError
-
-from samba.auth import system_session
-from samba.netcmd import (
- Command,
- CommandError,
- Option,
- )
-from samba.samdb import SamDB
-
-class cmd_fsmo(Command):
- """Makes the targer DC transfer or seize a fsmo role [server connection needed]"""
-
- synopsis = "(show | transfer <options> | seize <options>)"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "credopts": options.CredentialsOptions,
- "versionopts": options.VersionOptions,
- }
-
- takes_options = [
- Option("--host", help="LDB URL for database or target server", type=str),
- Option("--force", help="Force seizing of the role without attempting to transfer first.", action="store_true"),
- Option("--role", type="choice", choices=["rid", "pdc", "infrastructure","schema","naming","all"],
- help="""The FSMO role to seize or transfer.\n
-rid=RidAllocationMasterRole\n
-schema=SchemaMasterRole\n
-pdc=PdcEmulationMasterRole\n
-naming=DomainNamingMasterRole\n
-infrastructure=InfrastructureMasterRole\n
-all=all of the above"""),
- ]
-
- takes_args = ["subcommand"]
-
- def transfer_role(self, role, samdb):
- m = ldb.Message()
- m.dn = ldb.Dn(samdb, "")
- if role == "rid":
- m["becomeRidMaster"]= ldb.MessageElement(
- "1", ldb.FLAG_MOD_REPLACE,
- "becomeRidMaster")
- elif role == "pdc":
- domain_dn = samdb.domain_dn()
- res = samdb.search(domain_dn,
- scope=ldb.SCOPE_BASE, attrs=["objectSid"])
- assert len(res) == 1
- sid = res[0]["objectSid"][0]
- m["becomePdc"]= ldb.MessageElement(
- sid, ldb.FLAG_MOD_REPLACE,
- "becomePdc")
- elif role == "naming":
- m["becomeDomainMaster"]= ldb.MessageElement(
- "1", ldb.FLAG_MOD_REPLACE,
- "becomeDomainMaster")
- samdb.modify(m)
- elif role == "infrastructure":
- m["becomeInfrastructureMaster"]= ldb.MessageElement(
- "1", ldb.FLAG_MOD_REPLACE,
- "becomeInfrastructureMaster")
- elif role == "schema":
- m["becomeSchemaMaster"]= ldb.MessageElement(
- "1", ldb.FLAG_MOD_REPLACE,
- "becomeSchemaMaster")
- else:
- raise CommandError("Invalid FSMO role.")
- samdb.modify(m)
-
- def seize_role(self, role, samdb, force):
- res = samdb.search("",
- scope=ldb.SCOPE_BASE, attrs=["dsServiceName"])
- assert len(res) == 1
- serviceName = res[0]["dsServiceName"][0]
- domain_dn = samdb.domain_dn()
- m = ldb.Message()
- if role == "rid":
- m.dn = ldb.Dn(samdb, self.rid_dn)
- elif role == "pdc":
- m.dn = ldb.Dn(samdb, domain_dn)
- elif role == "naming":
- m.dn = ldb.Dn(samdb, self.naming_dn)
- elif role == "infrastructure":
- m.dn = ldb.Dn(samdb, self.infrastructure_dn)
- elif role == "schema":
- m.dn = ldb.Dn(samdb, self.schema_dn)
- else:
- raise CommandError("Invalid FSMO role.")
- #first try to transfer to avoid problem if the owner is still active
- if force is None:
- self.message("Attempting transfer...")
- try:
- self.transfer_role(role, samdb)
- except LdbError, (num, _):
- #transfer failed, use the big axe...
- self.message("Transfer unsuccessfull, seizing...")
- m["fSMORoleOwner"]= ldb.MessageElement(
- serviceName, ldb.FLAG_MOD_REPLACE,
- "fSMORoleOwner")
- samdb.modify(m)
- else:
- self.message("Transfer succeeded.")
- else:
- self.message("Will not attempt transfer, seizing...")
- m["fSMORoleOwner"]= ldb.MessageElement(
- serviceName, ldb.FLAG_MOD_REPLACE,
- "fSMORoleOwner")
- samdb.modify(m)
-
- def run(self, subcommand, force=None, host=None, role=None,
- credopts=None, sambaopts=None, versionopts=None):
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp, fallback_machine=True)
-
- samdb = SamDB(url=host, session_info=system_session(),
- credentials=creds, lp=lp)
-
- domain_dn = samdb.domain_dn()
- self.infrastructure_dn = "CN=Infrastructure," + domain_dn
- self.naming_dn = "CN=Partitions,CN=Configuration," + domain_dn
- self.schema_dn = "CN=Schema,CN=Configuration," + domain_dn
- self.rid_dn = "CN=RID Manager$,CN=System," + domain_dn
-
- res = samdb.search(self.infrastructure_dn,
- scope=ldb.SCOPE_BASE, attrs=["fSMORoleOwner"])
- assert len(res) == 1
- self.infrastructureMaster = res[0]["fSMORoleOwner"][0]
-
- res = samdb.search(domain_dn,
- scope=ldb.SCOPE_BASE, attrs=["fSMORoleOwner"])
- assert len(res) == 1
- self.pdcEmulator = res[0]["fSMORoleOwner"][0]
-
- res = samdb.search(self.naming_dn,
- scope=ldb.SCOPE_BASE, attrs=["fSMORoleOwner"])
- assert len(res) == 1
- self.namingMaster = res[0]["fSMORoleOwner"][0]
-
- res = samdb.search(self.schema_dn,
- scope=ldb.SCOPE_BASE, attrs=["fSMORoleOwner"])
- assert len(res) == 1
- self.schemaMaster = res[0]["fSMORoleOwner"][0]
-
- res = samdb.search(self.rid_dn,
- scope=ldb.SCOPE_BASE, attrs=["fSMORoleOwner"])
- assert len(res) == 1
- self.ridMaster = res[0]["fSMORoleOwner"][0]
-
- if subcommand == "show":
- self.message("InfrastructureMasterRole owner: " + self.infrastructureMaster)
- self.message("RidAllocationMasterRole owner: " + self.ridMaster)
- self.message("PdcEmulationMasterRole owner: " + self.pdcEmulator)
- self.message("DomainNamingMasterRole owner: " + self.namingMaster)
- self.message("SchemaMasterRole owner: " + self.schemaMaster)
- elif subcommand == "transfer":
- if role == "all":
- self.transfer_role("rid", samdb)
- self.transfer_role("pdc", samdb)
- self.transfer_role("naming", samdb)
- self.transfer_role("infrastructure", samdb)
- self.transfer_role("schema", samdb)
- else:
- self.transfer_role(role, samdb)
- elif subcommand == "seize":
- if role == "all":
- self.seize_role("rid", samdb, force)
- self.seize_role("pdc", samdb, force)
- self.seize_role("naming", samdb, force)
- self.seize_role("infrastructure", samdb, force)
- self.seize_role("schema", samdb, force)
- else:
- self.seize_role(role, samdb, force)
- else:
- raise CommandError("Wrong argument '%s'!" % subcommand)
diff --git a/source4/scripting/python/samba/netcmd/gpo.py b/source4/scripting/python/samba/netcmd/gpo.py
deleted file mode 100644
index 19007b361c..0000000000
--- a/source4/scripting/python/samba/netcmd/gpo.py
+++ /dev/null
@@ -1,245 +0,0 @@
-#!/usr/bin/env python
-#
-# implement samba_tool gpo commands
-#
-# Copyright Andrew Tridgell 2010
-#
-# based on C implementation by Guenther Deschner and Wilco Baan Hofman
-#
-# 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/>.
-#
-
-import samba.getopt as options
-import ldb
-
-from samba.auth import system_session
-from samba.netcmd import (
- Command,
- CommandError,
- Option,
- SuperCommand,
- )
-from samba.samdb import SamDB
-from samba import drs_utils, nttime2string, dsdb, dcerpc
-from samba.dcerpc import misc
-from samba.ndr import ndr_unpack
-import samba.security
-import samba.auth
-from samba.auth import AUTH_SESSION_INFO_DEFAULT_GROUPS, AUTH_SESSION_INFO_AUTHENTICATED, AUTH_SESSION_INFO_SIMPLE_PRIVILEGES
-
-def samdb_connect(ctx):
- '''make a ldap connection to the server'''
- try:
- ctx.samdb = SamDB(url=ctx.url,
- session_info=system_session(),
- credentials=ctx.creds, lp=ctx.lp)
- except Exception, e:
- raise CommandError("LDAP connection to %s failed " % ctx.url, e)
-
-
-def attr_default(msg, attrname, default):
- '''get an attribute from a ldap msg with a default'''
- if attrname in msg:
- return msg[attrname][0]
- return default
-
-
-def flags_string(flags, value):
- '''return a set of flags as a string'''
- if value == 0:
- return 'NONE'
- ret = ''
- for (str, val) in flags:
- if val & value:
- ret += str + ' '
- value &= ~val
- if value != 0:
- ret += '0x%08x' % value
- return ret.rstrip()
-
-
-def parse_gplink(gplink):
- '''parse a gPLink into an array of dn and options'''
- ret = []
- a = gplink.split(']')
- for g in a:
- if not g:
- continue
- d = g.split(';')
- if len(d) != 2 or not d[0].startswith("[LDAP://"):
- raise RuntimeError("Badly formed gPLink '%s'" % g)
- ret.append({ 'dn' : d[0][8:], 'options' : int(d[1])})
- return ret
-
-
-class cmd_listall(Command):
- """list all GPOs"""
-
- synopsis = "%prog gpo listall"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "versionopts": options.VersionOptions,
- "credopts": options.CredentialsOptions,
- }
-
- takes_options = [
- Option("-H", help="LDB URL for database or target server", type=str)
- ]
-
- def run(self, H=None, sambaopts=None,
- credopts=None, versionopts=None, server=None):
-
- self.url = H
- self.lp = sambaopts.get_loadparm()
-
- self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
-
- samdb_connect(self)
-
- policies_dn = self.samdb.get_default_basedn()
- policies_dn.add_child(ldb.Dn(self.samdb, "CN=Policies,CN=System"))
-
- gpo_flags = [
- ("GPO_FLAG_USER_DISABLE", dsdb.GPO_FLAG_USER_DISABLE ),
- ( "GPO_FLAG_MACHINE_DISABLE", dsdb.GPO_FLAG_MACHINE_DISABLE ) ]
-
- try:
- msg = self.samdb.search(base=policies_dn, scope=ldb.SCOPE_ONELEVEL,
- expression="(objectClass=groupPolicyContainer)",
- attrs=['nTSecurityDescriptor', 'versionNumber', 'flags', 'name', 'displayName', 'gPCFileSysPath'])
- except Exception, e:
- raise CommandError("Failed to list policies in %s" % policies_dn, e)
- for m in msg:
- print("GPO : %s" % m['name'][0])
- print("display name : %s" % m['displayName'][0])
- print("path : %s" % m['gPCFileSysPath'][0])
- print("dn : %s" % m.dn)
- print("version : %s" % attr_default(m, 'version', '0'))
- print("flags : %s" % flags_string(gpo_flags, int(attr_default(m, 'flags', 0))))
- print("")
-
-
-class cmd_list(Command):
- """list GPOs for a user"""
-
- synopsis = "%prog gpo list <username>"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "versionopts": options.VersionOptions,
- "credopts": options.CredentialsOptions,
- }
-
- takes_args = [ 'username' ]
-
- takes_options = [
- Option("-H", help="LDB URL for database or target server", type=str)
- ]
-
- def run(self, username, H=None, sambaopts=None,
- credopts=None, versionopts=None, server=None):
-
- self.url = H
- self.lp = sambaopts.get_loadparm()
-
- self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
-
- samdb_connect(self)
-
- try:
- user_dn = self.samdb.search(expression='(&(samAccountName=%s)(objectclass=User))' % username)[0].dn
- except Exception, e:
- raise CommandError("Failed to find user %s" % username, e)
-
- # check if its a computer account
- try:
- msg = self.samdb.search(base=user_dn, scope=ldb.SCOPE_BASE, attrs=['objectClass'])[0]
- is_computer = 'computer' in msg['objectClass']
- except Exception, e:
- raise CommandError("Failed to find objectClass for user %s" % username, e)
-
- session_info_flags = ( AUTH_SESSION_INFO_DEFAULT_GROUPS |
- AUTH_SESSION_INFO_AUTHENTICATED )
-
- # When connecting to a remote server, don't look up the local privilege DB
- if self.url is not None and self.url.startswith('ldap'):
- session_info_flags |= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES
-
- session = samba.auth.user_session(self.samdb, lp_ctx=self.lp, dn=user_dn,
- session_info_flags=session_info_flags)
-
- token = session.security_token
-
- gpos = []
-
- inherit = True
- dn = ldb.Dn(self.samdb, str(user_dn)).parent()
- while True:
- msg = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, attrs=['gPLink', 'gPOptions'])[0]
- if 'gPLink' in msg:
- glist = parse_gplink(msg['gPLink'][0])
- for g in glist:
- if not inherit and not (g['options'] & dsdb.GPLINK_OPT_ENFORCE):
- continue
- if g['options'] & dsdb.GPLINK_OPT_DISABLE:
- continue
-
- try:
- gmsg = self.samdb.search(base=g['dn'], scope=ldb.SCOPE_BASE,
- attrs=['flags', 'ntSecurityDescriptor'])
- except Exception:
- print "Failed to fetch gpo object %s" % g['dn']
- continue
-
- secdesc_ndr = gmsg[0]['ntSecurityDescriptor'][0]
- secdesc = ndr_unpack(dcerpc.security.descriptor, secdesc_ndr)
-
- try:
- samba.security.access_check(secdesc, token,
- dcerpc.security.SEC_STD_READ_CONTROL |
- dcerpc.security.SEC_ADS_LIST |
- dcerpc.security.SEC_ADS_READ_PROP)
- except RuntimeError:
- print "Failed access check on %s" % msg.dn
- continue
-
- # check the flags on the GPO
- flags = int(attr_default(gmsg[0], 'flags', 0))
- if is_computer and (flags & dsdb.GPO_FLAG_MACHINE_DISABLE):
- continue
- if not is_computer and (flags & dsdb.GPO_FLAG_USER_DISABLE):
- continue
- gpos.append(g)
-
- # check if this blocks inheritance
- gpoptions = int(attr_default(msg, 'gPOptions', 0))
- if gpoptions & dsdb.GPO_BLOCK_INHERITANCE:
- inherit = False
-
- if dn == self.samdb.get_default_basedn():
- break
- dn = dn.parent()
-
- print("GPO's for user %s" % username)
- for g in gpos:
- print("\t%s" % g['dn'])
-
-
-class cmd_gpo(SuperCommand):
- """GPO commands"""
-
- subcommands = {}
- subcommands["listall"] = cmd_listall()
- subcommands["list"] = cmd_list()
diff --git a/source4/scripting/python/samba/netcmd/group.py b/source4/scripting/python/samba/netcmd/group.py
deleted file mode 100644
index 620a7be866..0000000000
--- a/source4/scripting/python/samba/netcmd/group.py
+++ /dev/null
@@ -1,189 +0,0 @@
-#!/usr/bin/env python
-#
-# Adds a new user to a Samba4 server
-# Copyright Jelmer Vernooij 2008
-#
-# Based on the original in EJS:
-# Copyright Andrew Tridgell 2005
-#
-# 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/>.
-
-import samba.getopt as options
-from samba.netcmd import Command, SuperCommand, CommandError, Option
-import ldb
-
-from getpass import getpass
-from samba.auth import system_session
-from samba.samdb import SamDB
-from samba.dsdb import (
- GTYPE_SECURITY_DOMAIN_LOCAL_GROUP,
- GTYPE_SECURITY_GLOBAL_GROUP,
- GTYPE_SECURITY_UNIVERSAL_GROUP,
- GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP,
- GTYPE_DISTRIBUTION_GLOBAL_GROUP,
- GTYPE_DISTRIBUTION_UNIVERSAL_GROUP,
-)
-
-security_group = dict({"Domain": GTYPE_SECURITY_DOMAIN_LOCAL_GROUP, "Global": GTYPE_SECURITY_GLOBAL_GROUP, "Universal": GTYPE_SECURITY_UNIVERSAL_GROUP})
-distribution_group = dict({"Domain": GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP, "Global": GTYPE_DISTRIBUTION_GLOBAL_GROUP, "Universal": GTYPE_DISTRIBUTION_UNIVERSAL_GROUP})
-
-
-class cmd_group_add(Command):
- """Creates a new group"""
-
- synopsis = "%prog group add [options] <groupname>"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "versionopts": options.VersionOptions,
- "credopts": options.CredentialsOptions,
- }
-
- takes_options = [
- Option("-H", help="LDB URL for database or target server", type=str),
- Option("--groupou",
- help="Alternative location (without domainDN counterpart) to default CN=Users in which new user object will be created",
- type=str),
- Option("--group-scope", type="choice", choices=["Domain", "Global", "Universal"],
- help="Group scope (Domain | Global | Universal)"),
- Option("--group-type", type="choice", choices=["Security", "Distribution"],
- help="Group type (Security | Distribution)"),
- Option("--description", help="Group's description", type=str),
- Option("--mail-address", help="Group's email address", type=str),
- Option("--notes", help="Groups's notes", type=str),
- ]
-
- takes_args = ["groupname"]
-
- def run(self, groupname, credopts=None, sambaopts=None,
- versionopts=None, H=None, groupou=None, group_scope=None,
- group_type=None, description=None, mail_address=None, notes=None):
-
- if (group_type or "Security") == "Security":
- gtype = security_group.get(group_scope, GTYPE_SECURITY_GLOBAL_GROUP)
- else:
- gtype = distribution_group.get(group_scope, GTYPE_DISTRIBUTION_GLOBAL_GROUP)
-
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp, fallback_machine=True)
-
- try:
- samdb = SamDB(url=H, session_info=system_session(),
- credentials=creds, lp=lp)
- samdb.newgroup(groupname, groupou=groupou, grouptype = gtype,
- description=description, mailaddress=mail_address, notes=notes)
- except Exception, e:
- raise CommandError('Failed to create group "%s"' % groupname, e)
-
-
-class cmd_group_delete(Command):
- """Delete a group"""
-
- synopsis = "%prog group delete <groupname>"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "versionopts": options.VersionOptions,
- "credopts": options.CredentialsOptions,
- }
-
- takes_options = [
- Option("-H", help="LDB URL for database or target server", type=str),
- ]
-
- takes_args = ["groupname"]
-
- def run(self, groupname, credopts=None, sambaopts=None, versionopts=None, H=None):
-
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp, fallback_machine=True)
-
- try:
- samdb = SamDB(url=H, session_info=system_session(),
- credentials=creds, lp=lp)
- samdb.deletegroup(groupname)
- except Exception, e:
- raise CommandError('Failed to remove group "%s"' % groupname, e)
-
-
-class cmd_group_add_members(Command):
- """Add (comma-separated list of) group members"""
-
- synopsis = "%prog group addmembers <groupname> <listofmembers>"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "versionopts": options.VersionOptions,
- "credopts": options.CredentialsOptions,
- }
-
- takes_options = [
- Option("-H", help="LDB URL for database or target server", type=str),
- ]
-
- takes_args = ["groupname", "listofmembers"]
-
- def run(self, groupname, listofmembers, credopts=None, sambaopts=None,
- versionopts=None, H=None):
-
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp, fallback_machine=True)
-
- try:
- samdb = SamDB(url=H, session_info=system_session(),
- credentials=creds, lp=lp)
- samdb.add_remove_group_members(groupname, listofmembers, add_members_operation=True)
- except Exception, e:
- raise CommandError('Failed to add members "%s" to group "%s"' % (listofmembers, groupname), e)
-
-
-class cmd_group_remove_members(Command):
- """Remove (comma-separated list of) group members"""
-
- synopsis = "%prog group removemembers <groupname> <listofmembers>"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "versionopts": options.VersionOptions,
- "credopts": options.CredentialsOptions,
- }
-
- takes_options = [
- Option("-H", help="LDB URL for database or target server", type=str),
- ]
-
- takes_args = ["groupname", "listofmembers"]
-
- def run(self, groupname, listofmembers, credopts=None, sambaopts=None,
- versionopts=None, H=None):
-
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp, fallback_machine=True)
-
- try:
- samdb = SamDB(url=H, session_info=system_session(),
- credentials=creds, lp=lp)
- samdb.add_remove_group_members(groupname, listofmembers, add_members_operation=False)
- except Exception, e:
- raise CommandError('Failed to remove members "%s" from group "%s"' % (listofmembers, groupname), e)
-
-
-class cmd_group(SuperCommand):
- """Group management"""
-
- subcommands = {}
- subcommands["add"] = cmd_group_add()
- subcommands["delete"] = cmd_group_delete()
- subcommands["addmembers"] = cmd_group_add_members()
- subcommands["removemembers"] = cmd_group_remove_members()
diff --git a/source4/scripting/python/samba/netcmd/join.py b/source4/scripting/python/samba/netcmd/join.py
deleted file mode 100644
index 507253ab81..0000000000
--- a/source4/scripting/python/samba/netcmd/join.py
+++ /dev/null
@@ -1,78 +0,0 @@
-#!/usr/bin/env python
-#
-# joins
-#
-# Copyright Jelmer Vernooij 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/>.
-#
-
-import samba.getopt as options
-
-from samba.net import Net, LIBNET_JOIN_AUTOMATIC
-from samba.netcmd import Command, CommandError, Option
-from samba.dcerpc.misc import SEC_CHAN_WKSTA, SEC_CHAN_BDC
-from samba.join import join_RODC, join_DC
-
-class cmd_join(Command):
- """Joins domain as either member or backup domain controller [server connection needed]"""
-
- synopsis = "%prog join <dnsdomain> [DC | RODC | MEMBER] [options]"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "versionopts": options.VersionOptions,
- "credopts": options.CredentialsOptions,
- }
-
- takes_options = [
- Option("--server", help="DC to join", type=str),
- Option("--site", help="site to join", type=str),
- ]
-
- takes_args = ["domain", "role?"]
-
- def run(self, domain, role=None, sambaopts=None, credopts=None,
- versionopts=None, server=None, site=None):
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp)
- net = Net(creds, lp, server=credopts.ipaddress)
-
- if site is None:
- site = "Default-First-Site-Name"
-
- netbios_name = lp.get("netbios name")
-
- if not role is None:
- role = role.upper()
-
- if role is None or role == "MEMBER":
- secure_channel_type = SEC_CHAN_WKSTA
- elif role == "DC":
- join_DC(server=server, creds=creds, lp=lp, domain=domain,
- site=site, netbios_name=netbios_name)
- return
- elif role == "RODC":
- join_RODC(server=server, creds=creds, lp=lp, domain=domain,
- site=site, netbios_name=netbios_name)
- return
- else:
- raise CommandError("Invalid role %s (possible values: MEMBER, BDC, RODC)" % role)
-
- (join_password, sid, domain_name) = net.join(domain,
- netbios_name,
- secure_channel_type,
- LIBNET_JOIN_AUTOMATIC)
-
- self.outf.write("Joined domain %s (%s)\n" % (domain_name, sid))
diff --git a/source4/scripting/python/samba/netcmd/ldapcmp.py b/source4/scripting/python/samba/netcmd/ldapcmp.py
deleted file mode 100755
index 160aa31258..0000000000
--- a/source4/scripting/python/samba/netcmd/ldapcmp.py
+++ /dev/null
@@ -1,949 +0,0 @@
-#!/usr/bin/env python
-#
-# Unix SMB/CIFS implementation.
-# A command to compare differences of objects and attributes between
-# two LDAP servers both running at the same time. It generally compares
-# one of the three pratitions DOMAIN, CONFIGURATION or SCHEMA. Users
-# that have to be provided sheould be able to read objects in any of the
-# above partitions.
-
-# Copyright (C) Zahari Zahariev <zahari.zahariev@postpath.com> 2009, 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/>.
-#
-
-import os
-import re
-import sys
-
-import samba
-import samba.getopt as options
-from samba import Ldb
-from samba.ndr import ndr_pack, ndr_unpack
-from samba.dcerpc import security
-from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, ERR_NO_SUCH_OBJECT, LdbError
-from samba.netcmd import (
- Command,
- CommandError,
- Option,
- SuperCommand,
- )
-
-global summary
-summary = {}
-
-class LDAPBase(object):
-
- def __init__(self, host, creds, lp,
- two=False, quiet=False, descriptor=False, sort_aces=False, verbose=False,
- view="section", base="", scope="SUB"):
- ldb_options = []
- samdb_url = host
- if not "://" in host:
- if os.path.isfile(host):
- samdb_url = "tdb://%s" % host
- else:
- samdb_url = "ldap://%s" % host
- # use 'paged_search' module when connecting remotely
- if samdb_url.lower().startswith("ldap://"):
- ldb_options = ["modules:paged_searches"]
- self.ldb = Ldb(url=samdb_url,
- credentials=creds,
- lp=lp,
- options=ldb_options)
- self.search_base = base
- self.search_scope = scope
- self.two_domains = two
- self.quiet = quiet
- self.descriptor = descriptor
- self.sort_aces = sort_aces
- self.view = view
- self.verbose = verbose
- self.host = host
- self.base_dn = self.find_basedn()
- self.domain_netbios = self.find_netbios()
- self.server_names = self.find_servers()
- self.domain_name = re.sub("[Dd][Cc]=", "", self.base_dn).replace(",", ".")
- self.domain_sid = self.find_domain_sid()
- self.get_guid_map()
- self.get_sid_map()
- #
- # Log some domain controller specific place-holers that are being used
- # when compare content of two DCs. Uncomment for DEBUG purposes.
- if self.two_domains and not self.quiet:
- print "\n* Place-holders for %s:" % self.host
- print 4*" " + "${DOMAIN_DN} => %s" % self.base_dn
- print 4*" " + "${DOMAIN_NETBIOS} => %s" % self.domain_netbios
- print 4*" " + "${SERVER_NAME} => %s" % self.server_names
- print 4*" " + "${DOMAIN_NAME} => %s" % self.domain_name
-
- def find_domain_sid(self):
- res = self.ldb.search(base=self.base_dn, expression="(objectClass=*)", scope=SCOPE_BASE)
- return ndr_unpack(security.dom_sid,res[0]["objectSid"][0])
-
- def find_servers(self):
- """
- """
- res = self.ldb.search(base="OU=Domain Controllers,%s" % self.base_dn, \
- scope=SCOPE_SUBTREE, expression="(objectClass=computer)", attrs=["cn"])
- assert len(res) > 0
- srv = []
- for x in res:
- srv.append(x["cn"][0])
- return srv
-
- def find_netbios(self):
- res = self.ldb.search(base="CN=Partitions,CN=Configuration,%s" % self.base_dn, \
- scope=SCOPE_SUBTREE, attrs=["nETBIOSName"])
- assert len(res) > 0
- for x in res:
- if "nETBIOSName" in x.keys():
- return x["nETBIOSName"][0]
-
- def find_basedn(self):
- res = self.ldb.search(base="", expression="(objectClass=*)", scope=SCOPE_BASE,
- attrs=["defaultNamingContext"])
- assert len(res) == 1
- return res[0]["defaultNamingContext"][0]
-
- def object_exists(self, object_dn):
- res = None
- try:
- res = self.ldb.search(base=object_dn, scope=SCOPE_BASE)
- except LdbError, (enum, estr):
- if enum == ERR_NO_SUCH_OBJECT:
- return False
- raise
- return len(res) == 1
-
- def delete_force(self, object_dn):
- try:
- self.ldb.delete(object_dn)
- except Ldb.LdbError, e:
- assert "No such object" in str(e)
-
- def get_attribute_name(self, key):
- """ Returns the real attribute name
- It resolved ranged results e.g. member;range=0-1499
- """
-
- r = re.compile("^([^;]+);range=(\d+)-(\d+|\*)$")
-
- m = r.match(key)
- if m is None:
- return key
-
- return m.group(1)
-
- def get_attribute_values(self, object_dn, key, vals):
- """ Returns list with all attribute values
- It resolved ranged results e.g. member;range=0-1499
- """
-
- r = re.compile("^([^;]+);range=(\d+)-(\d+|\*)$")
-
- m = r.match(key)
- if m is None:
- # no range, just return the values
- return vals
-
- attr = m.group(1)
- hi = int(m.group(3))
-
- # get additional values in a loop
- # until we get a response with '*' at the end
- while True:
-
- n = "%s;range=%d-*" % (attr, hi + 1)
- res = self.ldb.search(base=object_dn, scope=SCOPE_BASE, attrs=[n])
- assert len(res) == 1
- res = dict(res[0])
- del res["dn"]
-
- fm = None
- fvals = None
-
- for key in res.keys():
- m = r.match(key)
-
- if m is None:
- continue
-
- if m.group(1) != attr:
- continue
-
- fm = m
- fvals = list(res[key])
- break
-
- if fm is None:
- break
-
- vals.extend(fvals)
- if fm.group(3) == "*":
- # if we got "*" we're done
- break
-
- assert int(fm.group(2)) == hi + 1
- hi = int(fm.group(3))
-
- return vals
-
- def get_attributes(self, object_dn):
- """ Returns dict with all default visible attributes
- """
- res = self.ldb.search(base=object_dn, scope=SCOPE_BASE, attrs=["*"])
- assert len(res) == 1
- res = dict(res[0])
- # 'Dn' element is not iterable and we have it as 'distinguishedName'
- del res["dn"]
- for key in res.keys():
- vals = list(res[key])
- del res[key]
- name = self.get_attribute_name(key)
- res[name] = self.get_attribute_values(object_dn, key, vals)
-
- return res
-
- def get_descriptor_sddl(self, object_dn):
- res = self.ldb.search(base=object_dn, scope=SCOPE_BASE, attrs=["nTSecurityDescriptor"])
- desc = res[0]["nTSecurityDescriptor"][0]
- desc = ndr_unpack(security.descriptor, desc)
- return desc.as_sddl(self.domain_sid)
-
- def guid_as_string(self, guid_blob):
- """ Translate binary representation of schemaIDGUID to standard string representation.
- @gid_blob: binary schemaIDGUID
- """
- blob = "%s" % guid_blob
- stops = [4, 2, 2, 2, 6]
- index = 0
- res = ""
- x = 0
- while x < len(stops):
- tmp = ""
- y = 0
- while y < stops[x]:
- c = hex(ord(blob[index])).replace("0x", "")
- c = [None, "0" + c, c][len(c)]
- if 2 * index < len(blob):
- tmp = c + tmp
- else:
- tmp += c
- index += 1
- y += 1
- res += tmp + " "
- x += 1
- assert index == len(blob)
- return res.strip().replace(" ", "-")
-
- def get_guid_map(self):
- """ Build dictionary that maps GUID to 'name' attribute found in Schema or Extended-Rights.
- """
- self.guid_map = {}
- res = self.ldb.search(base="cn=schema,cn=configuration,%s" % self.base_dn, \
- expression="(schemaIdGuid=*)", scope=SCOPE_SUBTREE, attrs=["schemaIdGuid", "name"])
- for item in res:
- self.guid_map[self.guid_as_string(item["schemaIdGuid"]).lower()] = item["name"][0]
- #
- res = self.ldb.search(base="cn=extended-rights,cn=configuration,%s" % self.base_dn, \
- expression="(rightsGuid=*)", scope=SCOPE_SUBTREE, attrs=["rightsGuid", "name"])
- for item in res:
- self.guid_map[str(item["rightsGuid"]).lower()] = item["name"][0]
-
- def get_sid_map(self):
- """ Build dictionary that maps GUID to 'name' attribute found in Schema or Extended-Rights.
- """
- self.sid_map = {}
- res = self.ldb.search(base="%s" % self.base_dn, \
- expression="(objectSid=*)", scope=SCOPE_SUBTREE, attrs=["objectSid", "sAMAccountName"])
- for item in res:
- try:
- self.sid_map["%s" % ndr_unpack(security.dom_sid, item["objectSid"][0])] = item["sAMAccountName"][0]
- except KeyError:
- pass
-
-class Descriptor(object):
- def __init__(self, connection, dn):
- self.con = connection
- self.dn = dn
- self.sddl = self.con.get_descriptor_sddl(self.dn)
- self.dacl_list = self.extract_dacl()
- if self.con.sort_aces:
- self.dacl_list.sort()
-
- def extract_dacl(self):
- """ Extracts the DACL as a list of ACE string (with the brakets).
- """
- try:
- if "S:" in self.sddl:
- res = re.search("D:(.*?)(\(.*?\))S:", self.sddl).group(2)
- else:
- res = re.search("D:(.*?)(\(.*\))", self.sddl).group(2)
- except AttributeError:
- return []
- return re.findall("(\(.*?\))", res)
-
- def fix_guid(self, ace):
- res = "%s" % ace
- guids = re.findall("[a-z0-9]+?-[a-z0-9]+-[a-z0-9]+-[a-z0-9]+-[a-z0-9]+", res)
- # If there are not GUIDs to replace return the same ACE
- if len(guids) == 0:
- return res
- for guid in guids:
- try:
- name = self.con.guid_map[guid.lower()]
- res = res.replace(guid, name)
- except KeyError:
- # Do not bother if the GUID is not found in
- # cn=Schema or cn=Extended-Rights
- pass
- return res
-
- def fix_sid(self, ace):
- res = "%s" % ace
- sids = re.findall("S-[-0-9]+", res)
- # If there are not SIDs to replace return the same ACE
- if len(sids) == 0:
- return res
- for sid in sids:
- try:
- name = self.con.sid_map[sid]
- res = res.replace(sid, name)
- except KeyError:
- # Do not bother if the SID is not found in baseDN
- pass
- return res
-
- def fixit(self, ace):
- """ Combine all replacement methods in one
- """
- res = "%s" % ace
- res = self.fix_guid(res)
- res = self.fix_sid(res)
- return res
-
- def diff_1(self, other):
- res = ""
- if len(self.dacl_list) != len(other.dacl_list):
- res += 4*" " + "Difference in ACE count:\n"
- res += 8*" " + "=> %s\n" % len(self.dacl_list)
- res += 8*" " + "=> %s\n" % len(other.dacl_list)
- #
- i = 0
- flag = True
- while True:
- self_ace = None
- other_ace = None
- try:
- self_ace = "%s" % self.dacl_list[i]
- except IndexError:
- self_ace = ""
- #
- try:
- other_ace = "%s" % other.dacl_list[i]
- except IndexError:
- other_ace = ""
- if len(self_ace) + len(other_ace) == 0:
- break
- self_ace_fixed = "%s" % self.fixit(self_ace)
- other_ace_fixed = "%s" % other.fixit(other_ace)
- if self_ace_fixed != other_ace_fixed:
- res += "%60s * %s\n" % ( self_ace_fixed, other_ace_fixed )
- flag = False
- else:
- res += "%60s | %s\n" % ( self_ace_fixed, other_ace_fixed )
- i += 1
- return (flag, res)
-
- def diff_2(self, other):
- res = ""
- if len(self.dacl_list) != len(other.dacl_list):
- res += 4*" " + "Difference in ACE count:\n"
- res += 8*" " + "=> %s\n" % len(self.dacl_list)
- res += 8*" " + "=> %s\n" % len(other.dacl_list)
- #
- common_aces = []
- self_aces = []
- other_aces = []
- self_dacl_list_fixed = []
- other_dacl_list_fixed = []
- [self_dacl_list_fixed.append( self.fixit(ace) ) for ace in self.dacl_list]
- [other_dacl_list_fixed.append( other.fixit(ace) ) for ace in other.dacl_list]
- for ace in self_dacl_list_fixed:
- try:
- other_dacl_list_fixed.index(ace)
- except ValueError:
- self_aces.append(ace)
- else:
- common_aces.append(ace)
- self_aces = sorted(self_aces)
- if len(self_aces) > 0:
- res += 4*" " + "ACEs found only in %s:\n" % self.con.host
- for ace in self_aces:
- res += 8*" " + ace + "\n"
- #
- for ace in other_dacl_list_fixed:
- try:
- self_dacl_list_fixed.index(ace)
- except ValueError:
- other_aces.append(ace)
- else:
- common_aces.append(ace)
- other_aces = sorted(other_aces)
- if len(other_aces) > 0:
- res += 4*" " + "ACEs found only in %s:\n" % other.con.host
- for ace in other_aces:
- res += 8*" " + ace + "\n"
- #
- common_aces = sorted(list(set(common_aces)))
- if self.con.verbose:
- res += 4*" " + "ACEs found in both:\n"
- for ace in common_aces:
- res += 8*" " + ace + "\n"
- return (self_aces == [] and other_aces == [], res)
-
-class LDAPObject(object):
- def __init__(self, connection, dn, summary):
- self.con = connection
- self.two_domains = self.con.two_domains
- self.quiet = self.con.quiet
- self.verbose = self.con.verbose
- self.summary = summary
- self.dn = dn.replace("${DOMAIN_DN}", self.con.base_dn)
- self.dn = self.dn.replace("CN=${DOMAIN_NETBIOS}", "CN=%s" % self.con.domain_netbios)
- for x in self.con.server_names:
- self.dn = self.dn.replace("CN=${SERVER_NAME}", "CN=%s" % x)
- self.attributes = self.con.get_attributes(self.dn)
- # Attributes that are considered always to be different e.g based on timestamp etc.
- #
- # One domain - two domain controllers
- self.ignore_attributes = [
- # Default Naming Context
- "lastLogon", "lastLogoff", "badPwdCount", "logonCount", "badPasswordTime", "modifiedCount",
- "operatingSystemVersion","oEMInformation",
- # Configuration Naming Context
- "repsFrom", "dSCorePropagationData", "msExchServer1HighestUSN",
- "replUpToDateVector", "repsTo", "whenChanged", "uSNChanged", "uSNCreated",
- # Schema Naming Context
- "prefixMap",]
- self.dn_attributes = []
- self.domain_attributes = []
- self.servername_attributes = []
- self.netbios_attributes = []
- self.other_attributes = []
- # Two domains - two domain controllers
-
- if self.two_domains:
- self.ignore_attributes += [
- "objectCategory", "objectGUID", "objectSid", "whenCreated", "pwdLastSet", "uSNCreated", "creationTime",
- "modifiedCount", "priorSetTime", "rIDManagerReference", "gPLink", "ipsecNFAReference",
- "fRSPrimaryMember", "fSMORoleOwner", "masteredBy", "ipsecOwnersReference", "wellKnownObjects",
- "badPwdCount", "ipsecISAKMPReference", "ipsecFilterReference", "msDs-masteredBy", "lastSetTime",
- "ipsecNegotiationPolicyReference", "subRefs", "gPCFileSysPath", "accountExpires", "invocationId",
- # After Exchange preps
- "targetAddress", "msExchMailboxGuid", "siteFolderGUID"]
- #
- # Attributes that contain the unique DN tail part e.g. 'DC=samba,DC=org'
- self.dn_attributes = [
- "distinguishedName", "defaultObjectCategory", "member", "memberOf", "siteList", "nCName",
- "homeMDB", "homeMTA", "interSiteTopologyGenerator", "serverReference",
- "msDS-HasInstantiatedNCs", "hasMasterNCs", "msDS-hasMasterNCs", "msDS-HasDomainNCs", "dMDLocation",
- "msDS-IsDomainFor", "rIDSetReferences", "serverReferenceBL",
- # After Exchange preps
- "msExchHomeRoutingGroup", "msExchResponsibleMTAServer", "siteFolderServer", "msExchRoutingMasterDN",
- "msExchRoutingGroupMembersBL", "homeMDBBL", "msExchHomePublicMDB", "msExchOwningServer", "templateRoots",
- "addressBookRoots", "msExchPolicyRoots", "globalAddressList", "msExchOwningPFTree",
- "msExchResponsibleMTAServerBL", "msExchOwningPFTreeBL",]
- self.dn_attributes = [x.upper() for x in self.dn_attributes]
- #
- # Attributes that contain the Domain name e.g. 'samba.org'
- self.domain_attributes = [
- "proxyAddresses", "mail", "userPrincipalName", "msExchSmtpFullyQualifiedDomainName",
- "dnsHostName", "networkAddress", "dnsRoot", "servicePrincipalName",]
- self.domain_attributes = [x.upper() for x in self.domain_attributes]
- #
- # May contain DOMAIN_NETBIOS and SERVER_NAME
- self.servername_attributes = [ "distinguishedName", "name", "CN", "sAMAccountName", "dNSHostName",
- "servicePrincipalName", "rIDSetReferences", "serverReference", "serverReferenceBL",
- "msDS-IsDomainFor", "interSiteTopologyGenerator",]
- self.servername_attributes = [x.upper() for x in self.servername_attributes]
- #
- self.netbios_attributes = [ "servicePrincipalName", "CN", "distinguishedName", "nETBIOSName", "name",]
- self.netbios_attributes = [x.upper() for x in self.netbios_attributes]
- #
- self.other_attributes = [ "name", "DC",]
- self.other_attributes = [x.upper() for x in self.other_attributes]
- #
- self.ignore_attributes = [x.upper() for x in self.ignore_attributes]
-
- def log(self, msg):
- """
- Log on the screen if there is no --quiet oprion set
- """
- if not self.quiet:
- print msg
-
- def fix_dn(self, s):
- res = "%s" % s
- if not self.two_domains:
- return res
- if res.upper().endswith(self.con.base_dn.upper()):
- res = res[:len(res)-len(self.con.base_dn)] + "${DOMAIN_DN}"
- return res
-
- def fix_domain_name(self, s):
- res = "%s" % s
- if not self.two_domains:
- return res
- res = res.replace(self.con.domain_name.lower(), self.con.domain_name.upper())
- res = res.replace(self.con.domain_name.upper(), "${DOMAIN_NAME}")
- return res
-
- def fix_domain_netbios(self, s):
- res = "%s" % s
- if not self.two_domains:
- return res
- res = res.replace(self.con.domain_netbios.lower(), self.con.domain_netbios.upper())
- res = res.replace(self.con.domain_netbios.upper(), "${DOMAIN_NETBIOS}")
- return res
-
- def fix_server_name(self, s):
- res = "%s" % s
- if not self.two_domains or len(self.con.server_names) > 1:
- return res
- for x in self.con.server_names:
- res = res.upper().replace(x, "${SERVER_NAME}")
- return res
-
- def __eq__(self, other):
- if self.con.descriptor:
- return self.cmp_desc(other)
- return self.cmp_attrs(other)
-
- def cmp_desc(self, other):
- d1 = Descriptor(self.con, self.dn)
- d2 = Descriptor(other.con, other.dn)
- if self.con.view == "section":
- res = d1.diff_2(d2)
- elif self.con.view == "collision":
- res = d1.diff_1(d2)
- else:
- raise Exception("Unknown --view option value.")
- #
- self.screen_output = res[1][:-1]
- other.screen_output = res[1][:-1]
- #
- return res[0]
-
- def cmp_attrs(self, other):
- res = ""
- self.unique_attrs = []
- self.df_value_attrs = []
- other.unique_attrs = []
- if self.attributes.keys() != other.attributes.keys():
- #
- title = 4*" " + "Attributes found only in %s:" % self.con.host
- for x in self.attributes.keys():
- if not x in other.attributes.keys() and \
- not x.upper() in [q.upper() for q in other.ignore_attributes]:
- if title:
- res += title + "\n"
- title = None
- res += 8*" " + x + "\n"
- self.unique_attrs.append(x)
- #
- title = 4*" " + "Attributes found only in %s:" % other.con.host
- for x in other.attributes.keys():
- if not x in self.attributes.keys() and \
- not x.upper() in [q.upper() for q in self.ignore_attributes]:
- if title:
- res += title + "\n"
- title = None
- res += 8*" " + x + "\n"
- other.unique_attrs.append(x)
- #
- missing_attrs = [x.upper() for x in self.unique_attrs]
- missing_attrs += [x.upper() for x in other.unique_attrs]
- title = 4*" " + "Difference in attribute values:"
- for x in self.attributes.keys():
- if x.upper() in self.ignore_attributes or x.upper() in missing_attrs:
- continue
- if isinstance(self.attributes[x], list) and isinstance(other.attributes[x], list):
- self.attributes[x] = sorted(self.attributes[x])
- other.attributes[x] = sorted(other.attributes[x])
- if self.attributes[x] != other.attributes[x]:
- p = None
- q = None
- m = None
- n = None
- # First check if the difference can be fixed but shunting the first part
- # of the DomainHostName e.g. 'mysamba4.test.local' => 'mysamba4'
- if x.upper() in self.other_attributes:
- p = [self.con.domain_name.split(".")[0] == j for j in self.attributes[x]]
- q = [other.con.domain_name.split(".")[0] == j for j in other.attributes[x]]
- if p == q:
- continue
- # Attribute values that are list that contain DN based values that may differ
- elif x.upper() in self.dn_attributes:
- m = p
- n = q
- if not p and not q:
- m = self.attributes[x]
- n = other.attributes[x]
- p = [self.fix_dn(j) for j in m]
- q = [other.fix_dn(j) for j in n]
- if p == q:
- continue
- # Attributes that contain the Domain name in them
- if x.upper() in self.domain_attributes:
- m = p
- n = q
- if not p and not q:
- m = self.attributes[x]
- n = other.attributes[x]
- p = [self.fix_domain_name(j) for j in m]
- q = [other.fix_domain_name(j) for j in n]
- if p == q:
- continue
- #
- if x.upper() in self.servername_attributes:
- # Attributes with SERVER_NAME
- m = p
- n = q
- if not p and not q:
- m = self.attributes[x]
- n = other.attributes[x]
- p = [self.fix_server_name(j) for j in m]
- q = [other.fix_server_name(j) for j in n]
- if p == q:
- continue
- #
- if x.upper() in self.netbios_attributes:
- # Attributes with NETBIOS Domain name
- m = p
- n = q
- if not p and not q:
- m = self.attributes[x]
- n = other.attributes[x]
- p = [self.fix_domain_netbios(j) for j in m]
- q = [other.fix_domain_netbios(j) for j in n]
- if p == q:
- continue
- #
- if title:
- res += title + "\n"
- title = None
- if p and q:
- res += 8*" " + x + " => \n%s\n%s" % (p, q) + "\n"
- else:
- res += 8*" " + x + " => \n%s\n%s" % (self.attributes[x], other.attributes[x]) + "\n"
- self.df_value_attrs.append(x)
- #
- if self.unique_attrs + other.unique_attrs != []:
- assert self.unique_attrs != other.unique_attrs
- self.summary["unique_attrs"] += self.unique_attrs
- self.summary["df_value_attrs"] += self.df_value_attrs
- other.summary["unique_attrs"] += other.unique_attrs
- other.summary["df_value_attrs"] += self.df_value_attrs # they are the same
- #
- self.screen_output = res[:-1]
- other.screen_output = res[:-1]
- #
- return res == ""
-
-
-class LDAPBundel(object):
- def __init__(self, connection, context, dn_list=None):
- self.con = connection
- self.two_domains = self.con.two_domains
- self.quiet = self.con.quiet
- self.verbose = self.con.verbose
- self.search_base = self.con.search_base
- self.search_scope = self.con.search_scope
- self.summary = {}
- self.summary["unique_attrs"] = []
- self.summary["df_value_attrs"] = []
- self.summary["known_ignored_dn"] = []
- self.summary["abnormal_ignored_dn"] = []
- if dn_list:
- self.dn_list = dn_list
- elif context.upper() in ["DOMAIN", "CONFIGURATION", "SCHEMA"]:
- self.context = context.upper()
- self.dn_list = self.get_dn_list(context)
- else:
- raise Exception("Unknown initialization data for LDAPBundel().")
- counter = 0
- while counter < len(self.dn_list) and self.two_domains:
- # Use alias reference
- tmp = self.dn_list[counter]
- tmp = tmp[:len(tmp)-len(self.con.base_dn)] + "${DOMAIN_DN}"
- tmp = tmp.replace("CN=%s" % self.con.domain_netbios, "CN=${DOMAIN_NETBIOS}")
- if len(self.con.server_names) == 1:
- for x in self.con.server_names:
- tmp = tmp.replace("CN=%s" % x, "CN=${SERVER_NAME}")
- self.dn_list[counter] = tmp
- counter += 1
- self.dn_list = list(set(self.dn_list))
- self.dn_list = sorted(self.dn_list)
- self.size = len(self.dn_list)
-
- def log(self, msg):
- """
- Log on the screen if there is no --quiet oprion set
- """
- if not self.quiet:
- print msg
-
- def update_size(self):
- self.size = len(self.dn_list)
- self.dn_list = sorted(self.dn_list)
-
- def __eq__(self, other):
- res = True
- if self.size != other.size:
- self.log( "\n* DN lists have different size: %s != %s" % (self.size, other.size) )
- res = False
- #
- # This is the case where we want to explicitly compare two objects with different DNs.
- # It does not matter if they are in the same DC, in two DC in one domain or in two
- # different domains.
- if self.search_scope != SCOPE_BASE:
- title= "\n* DNs found only in %s:" % self.con.host
- for x in self.dn_list:
- if not x.upper() in [q.upper() for q in other.dn_list]:
- if title:
- self.log( title )
- title = None
- res = False
- self.log( 4*" " + x )
- self.dn_list[self.dn_list.index(x)] = ""
- self.dn_list = [x for x in self.dn_list if x]
- #
- title= "\n* DNs found only in %s:" % other.con.host
- for x in other.dn_list:
- if not x.upper() in [q.upper() for q in self.dn_list]:
- if title:
- self.log( title )
- title = None
- res = False
- self.log( 4*" " + x )
- other.dn_list[other.dn_list.index(x)] = ""
- other.dn_list = [x for x in other.dn_list if x]
- #
- self.update_size()
- other.update_size()
- assert self.size == other.size
- assert sorted([x.upper() for x in self.dn_list]) == sorted([x.upper() for x in other.dn_list])
- self.log( "\n* Objects to be compared: %s" % self.size )
-
- index = 0
- while index < self.size:
- skip = False
- try:
- object1 = LDAPObject(connection=self.con,
- dn=self.dn_list[index],
- summary=self.summary)
- except LdbError, (enum, estr):
- if enum == ERR_NO_SUCH_OBJECT:
- self.log( "\n!!! Object not found: %s" % self.dn_list[index] )
- skip = True
- raise
- try:
- object2 = LDAPObject(connection=other.con,
- dn=other.dn_list[index],
- summary=other.summary)
- except LdbError, (enum, estr):
- if enum == ERR_NO_SUCH_OBJECT:
- self.log( "\n!!! Object not found: %s" % other.dn_list[index] )
- skip = True
- raise
- if skip:
- index += 1
- continue
- if object1 == object2:
- if self.con.verbose:
- self.log( "\nComparing:" )
- self.log( "'%s' [%s]" % (object1.dn, object1.con.host) )
- self.log( "'%s' [%s]" % (object2.dn, object2.con.host) )
- self.log( 4*" " + "OK" )
- else:
- self.log( "\nComparing:" )
- self.log( "'%s' [%s]" % (object1.dn, object1.con.host) )
- self.log( "'%s' [%s]" % (object2.dn, object2.con.host) )
- self.log( object1.screen_output )
- self.log( 4*" " + "FAILED" )
- res = False
- self.summary = object1.summary
- other.summary = object2.summary
- index += 1
- #
- return res
-
- def get_dn_list(self, context):
- """ Query LDAP server about the DNs of certain naming self.con.ext Domain (or Default), Configuration, Schema.
- Parse all DNs and filter those that are 'strange' or abnormal.
- """
- if context.upper() == "DOMAIN":
- search_base = "%s" % self.con.base_dn
- elif context.upper() == "CONFIGURATION":
- search_base = "CN=Configuration,%s" % self.con.base_dn
- elif context.upper() == "SCHEMA":
- search_base = "CN=Schema,CN=Configuration,%s" % self.con.base_dn
-
- dn_list = []
- if not self.search_base:
- self.search_base = search_base
- self.search_scope = self.search_scope.upper()
- if self.search_scope == "SUB":
- self.search_scope = SCOPE_SUBTREE
- elif self.search_scope == "BASE":
- self.search_scope = SCOPE_BASE
- elif self.search_scope == "ONE":
- self.search_scope = SCOPE_ONELEVEL
- else:
- raise StandardError("Wrong 'scope' given. Choose from: SUB, ONE, BASE")
- if not self.search_base.upper().endswith(search_base.upper()):
- raise StandardError("Invalid search base specified: %s" % self.search_base)
- res = self.con.ldb.search(base=self.search_base, scope=self.search_scope, attrs=["dn"])
- for x in res:
- dn_list.append(x["dn"].get_linearized())
- #
- global summary
- #
- return dn_list
-
- def print_summary(self):
- self.summary["unique_attrs"] = list(set(self.summary["unique_attrs"]))
- self.summary["df_value_attrs"] = list(set(self.summary["df_value_attrs"]))
- #
- if self.summary["unique_attrs"]:
- self.log( "\nAttributes found only in %s:" % self.con.host )
- self.log( "".join([str("\n" + 4*" " + x) for x in self.summary["unique_attrs"]]) )
- #
- if self.summary["df_value_attrs"]:
- self.log( "\nAttributes with different values:" )
- self.log( "".join([str("\n" + 4*" " + x) for x in self.summary["df_value_attrs"]]) )
- self.summary["df_value_attrs"] = []
-
-class cmd_ldapcmp(Command):
- """compare two ldap databases"""
- synopsis = "ldapcmp URL1 URL2 <domain|configuration|schema> [options]"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "versionopts": options.VersionOptions,
- "credopts": options.CredentialsOptionsDouble,
- }
-
- takes_args = ["URL1", "URL2", "context1?", "context2?", "context3?"]
-
- takes_options = [
- Option("-w", "--two", dest="two", action="store_true", default=False,
- help="Hosts are in two different domains"),
- Option("-q", "--quiet", dest="quiet", action="store_true", default=False,
- help="Do not print anything but relay on just exit code"),
- Option("-v", "--verbose", dest="verbose", action="store_true", default=False,
- help="Print all DN pairs that have been compared"),
- Option("--sd", dest="descriptor", action="store_true", default=False,
- help="Compare nTSecurityDescriptor attibutes only"),
- Option("--sort-aces", dest="sort_aces", action="store_true", default=False,
- help="Sort ACEs before comparison of nTSecurityDescriptor attribute"),
- Option("--view", dest="view", default="section",
- help="Display mode for nTSecurityDescriptor results. Possible values: section or collision."),
- Option("--base", dest="base", default="",
- help="Pass search base that will build DN list for the first DC."),
- Option("--base2", dest="base2", default="",
- help="Pass search base that will build DN list for the second DC. Used when --two or when compare two different DNs."),
- Option("--scope", dest="scope", default="SUB",
- help="Pass search scope that builds DN list. Options: SUB, ONE, BASE"),
- ]
-
- def run(self, URL1, URL2,
- context1=None, context2=None, context3=None,
- two=False, quiet=False, verbose=False, descriptor=False, sort_aces=False, view="section",
- base="", base2="", scope="SUB", credopts=None, sambaopts=None, versionopts=None):
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp, fallback_machine=True)
- creds2 = credopts.get_credentials2(lp, guess=False)
- if creds2.is_anonymous():
- creds2 = creds
- else:
- creds2.set_domain("")
- creds2.set_workstation("")
- if not creds.authentication_requested():
- raise CommandError("You must supply at least one username/password pair")
-
- # make a list of contexts to compare in
- contexts = []
- if context1 is None:
- if base and base2:
- # If search bases are specified context is defaulted to
- # DOMAIN so the given search bases can be verified.
- contexts = ["DOMAIN"]
- else:
- # if no argument given, we compare all contexts
- contexts = ["DOMAIN", "CONFIGURATION", "SCHEMA"]
- else:
- for c in [context1, context2, context3]:
- if c is None:
- continue
- if not c.upper() in ["DOMAIN", "CONFIGURATION", "SCHEMA"]:
- raise CommandError("Incorrect argument: %s" % c)
- contexts.append(c.upper())
-
- if verbose and quiet:
- raise CommandError("You cannot set --verbose and --quiet together")
- if (not base and base2) or (base and not base2):
- raise CommandError("You need to specify both --base and --base2 at the same time")
- if descriptor and view.upper() not in ["SECTION", "COLLISION"]:
- raise CommandError("Invalid --view value. Choose from: section or collision")
- if not scope.upper() in ["SUB", "ONE", "BASE"]:
- raise CommandError("Invalid --scope value. Choose from: SUB, ONE, BASE")
-
- con1 = LDAPBase(URL1, creds, lp,
- two=two, quiet=quiet, descriptor=descriptor, sort_aces=sort_aces,
- verbose=verbose,view=view, base=base, scope=scope)
- assert len(con1.base_dn) > 0
-
- con2 = LDAPBase(URL2, creds2, lp,
- two=two, quiet=quiet, descriptor=descriptor, sort_aces=sort_aces,
- verbose=verbose, view=view, base=base2, scope=scope)
- assert len(con2.base_dn) > 0
-
- status = 0
- for context in contexts:
- if not quiet:
- print "\n* Comparing [%s] context..." % context
-
- b1 = LDAPBundel(con1, context=context)
- b2 = LDAPBundel(con2, context=context)
-
- if b1 == b2:
- if not quiet:
- print "\n* Result for [%s]: SUCCESS" % context
- else:
- if not quiet:
- print "\n* Result for [%s]: FAILURE" % context
- if not descriptor:
- assert len(b1.summary["df_value_attrs"]) == len(b2.summary["df_value_attrs"])
- b2.summary["df_value_attrs"] = []
- print "\nSUMMARY"
- print "---------"
- b1.print_summary()
- b2.print_summary()
- # mark exit status as FAILURE if a least one comparison failed
- status = -1
- if status != 0:
- raise CommandError("Compare failed: %d" % status)
diff --git a/source4/scripting/python/samba/netcmd/machinepw.py b/source4/scripting/python/samba/netcmd/machinepw.py
deleted file mode 100644
index d822b22794..0000000000
--- a/source4/scripting/python/samba/netcmd/machinepw.py
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/env python
-#
-# Machine passwords
-# Copyright Jelmer Vernooij 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/>.
-#
-
-import samba.getopt as options
-
-from samba import Ldb
-from samba.auth import system_session
-from samba.netcmd import Command, CommandError
-
-
-class cmd_machinepw(Command):
- """Gets a machine password out of our SAM"""
-
- synopsis = "%prog machinepw <accountname>"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "versionopts": options.VersionOptions,
- "credopts": options.CredentialsOptions,
- }
-
- takes_args = ["secret"]
-
- def run(self, secret, sambaopts=None, credopts=None, versionopts=None):
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp, fallback_machine=True)
- url = lp.get("secrets database")
- secretsdb = Ldb(url=url, session_info=system_session(),
- credentials=creds, lp=lp)
-
- result = secretsdb.search(attrs=["secret"],
- expression="(&(objectclass=primaryDomain)(samaccountname=%s))" % secret)
-
- if len(result) != 1:
- raise CommandError("search returned %d records, expected 1" % len(result))
-
- self.outf.write("%s\n" % result[0]["secret"])
diff --git a/source4/scripting/python/samba/netcmd/netacl.py b/source4/scripting/python/samba/netcmd/netacl.py
deleted file mode 100644
index 3f68ee756c..0000000000
--- a/source4/scripting/python/samba/netcmd/netacl.py
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/env python
-#
-# Manipulate ACLs
-#
-# Copyright (C) Matthieu Patou <mat@matws.net> 2010
-# Copyright (C) Nadezhda Ivanova <nivanova@samba.org> 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/>.
-#
-
-from samba.netcmd import (
- SuperCommand,
- )
-from samba.netcmd.ntacl import cmd_nt_acl
-from samba.netcmd.dsacl import cmd_ds_acl
-
-class cmd_acl(SuperCommand):
- """NT ACLs manipulation"""
-
- subcommands = {}
- subcommands["nt"] = cmd_nt_acl()
- subcommands["ds"] = cmd_ds_acl()
diff --git a/source4/scripting/python/samba/netcmd/newuser.py b/source4/scripting/python/samba/netcmd/newuser.py
deleted file mode 100644
index 3581340577..0000000000
--- a/source4/scripting/python/samba/netcmd/newuser.py
+++ /dev/null
@@ -1,97 +0,0 @@
-#!/usr/bin/env python
-#
-# Adds a new user to a Samba4 server
-# Copyright Jelmer Vernooij 2008
-#
-# Based on the original in EJS:
-# Copyright Andrew Tridgell 2005
-#
-# 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/>.
-
-import samba.getopt as options
-from samba.netcmd import Command, CommandError, Option
-import ldb
-
-from getpass import getpass
-from samba.auth import system_session
-from samba.samdb import SamDB
-
-class cmd_newuser(Command):
- """Creates a new user"""
-
- synopsis = "newuser [options] <username> [<password>]"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "versionopts": options.VersionOptions,
- "credopts": options.CredentialsOptions,
- }
-
- takes_options = [
- Option("-H", help="LDB URL for database or target server", type=str),
- Option("--must-change-at-next-login",
- help="Force password to be changed on next login",
- action="store_true"),
- Option("--use-username-as-cn",
- help="Force use of username as user's CN",
- action="store_true"),
- Option("--userou",
- help="Alternative location (without domainDN counterpart) to default CN=Users in which new user object will be created",
- type=str),
- Option("--surname", help="User's surname", type=str),
- Option("--given-name", help="User's given name", type=str),
- Option("--initials", help="User's initials", type=str),
- Option("--profile-path", help="User's profile path", type=str),
- Option("--script-path", help="User's logon script path", type=str),
- Option("--home-drive", help="User's home drive letter", type=str),
- Option("--home-directory", help="User's home directory path", type=str),
- Option("--job-title", help="User's job title", type=str),
- Option("--department", help="User's department", type=str),
- Option("--company", help="User's company", type=str),
- Option("--description", help="User's description", type=str),
- Option("--mail-address", help="User's email address", type=str),
- Option("--internet-address", help="User's home page", type=str),
- Option("--telephone-number", help="User's phone number", type=str),
- Option("--physical-delivery-office", help="User's office location", type=str),
- ]
-
- takes_args = ["username", "password?"]
-
- def run(self, username, password=None, credopts=None, sambaopts=None,
- versionopts=None, H=None, must_change_at_next_login=None,
- use_username_as_cn=None, userou=None, surname=None, given_name=None, initials=None,
- profile_path=None, script_path=None, home_drive=None, home_directory=None,
- job_title=None, department=None, company=None, description=None,
- mail_address=None, internet_address=None, telephone_number=None, physical_delivery_office=None):
-
- if password is None:
- password = getpass("New Password: ")
-
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp)
-
- try:
- samdb = SamDB(url=H, session_info=system_session(),
- credentials=creds, lp=lp)
- samdb.newuser(username, password,
- force_password_change_at_next_login_req=must_change_at_next_login,
- useusernameascn=use_username_as_cn, userou=userou, surname=surname, givenname=given_name, initials=initials,
- profilepath=profile_path, homedrive=home_drive, scriptpath=script_path, homedirectory=home_directory,
- jobtitle=job_title, department=department, company=company, description=description,
- mailaddress=mail_address, internetaddress=internet_address,
- telephonenumber=telephone_number, physicaldeliveryoffice=physical_delivery_office)
- except Exception, e:
- raise CommandError('Failed to create user "%s"' % username, e)
-
- print("User %s created successfully" % username)
diff --git a/source4/scripting/python/samba/netcmd/ntacl.py b/source4/scripting/python/samba/netcmd/ntacl.py
deleted file mode 100644
index 49f8fbc77f..0000000000
--- a/source4/scripting/python/samba/netcmd/ntacl.py
+++ /dev/null
@@ -1,119 +0,0 @@
-#!/usr/bin/env python
-#
-# Manipulate file NT ACLs
-#
-# Copyright Matthieu Patou 2010 <mat@matws.net>
-#
-# 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/>.
-#
-
-from samba.credentials import DONT_USE_KERBEROS
-import samba.getopt as options
-from samba.dcerpc import security
-from samba.ntacls import setntacl, getntacl
-from samba import Ldb
-from samba.ndr import ndr_unpack
-
-from ldb import SCOPE_BASE
-import os
-
-from samba.auth import system_session
-from samba.netcmd import (
- Command,
- CommandError,
- SuperCommand,
- Option,
- )
-
-class cmd_acl_set(Command):
- """Set ACLs on a file"""
- synopsis = "%prog set <acl> <file> [--xattr-backend=native|tdb] [--eadb-file=file] [options]"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "credopts": options.CredentialsOptions,
- "versionopts": options.VersionOptions,
- }
-
- takes_options = [
- Option("--quiet", help="Be quiet", action="store_true"),
- Option("--xattr-backend", type="choice", help="xattr backend type (native fs or tdb)",
- choices=["native","tdb"]),
- Option("--eadb-file", help="Name of the tdb file where attributes are stored", type="string"),
- ]
-
- takes_args = ["acl","file"]
-
- def run(self, acl, file, quiet=False,xattr_backend=None,eadb_file=None,
- credopts=None, sambaopts=None, versionopts=None):
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp)
- path = os.path.join(lp.get("private dir"), lp.get("secrets database") or "secrets.ldb")
- creds = credopts.get_credentials(lp)
- creds.set_kerberos_state(DONT_USE_KERBEROS)
- try:
- ldb = Ldb(path, session_info=system_session(), credentials=creds,
- lp=lp)
- except Exception, e:
- raise CommandError("Unable to read domain SID from configuration files", e)
- attrs = ["objectSid"]
- print lp.get("realm")
- res = ldb.search(expression="(objectClass=*)",
- base="flatname=%s,cn=Primary Domains" % lp.get("workgroup"),
- scope=SCOPE_BASE, attrs=attrs)
- if len(res) !=0:
- domainsid = ndr_unpack(security.dom_sid, res[0]["objectSid"][0])
- setntacl(lp, file, acl, str(domainsid), xattr_backend, eadb_file)
- else:
- raise CommandError("Unable to read domain SID from configuration files")
-
-
-class cmd_acl_get(Command):
- """Set ACLs on a file"""
- synopsis = "%prog get <file> [--as-sddl] [--xattr-backend=native|tdb] [--eadb-file=file] [options]"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "credopts": options.CredentialsOptions,
- "versionopts": options.VersionOptions,
- }
-
- takes_options = [
- Option("--as-sddl", help="Output ACL in the SDDL format", action="store_true"),
- Option("--xattr-backend", type="choice", help="xattr backend type (native fs or tdb)",
- choices=["native","tdb"]),
- Option("--eadb-file", help="Name of the tdb file where attributes are stored", type="string"),
- ]
-
- takes_args = ["file"]
-
- def run(self, file, as_sddl=False, xattr_backend=None, eadb_file=None,
- credopts=None, sambaopts=None, versionopts=None):
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp)
- acl = getntacl(lp, file, xattr_backend, eadb_file)
- if as_sddl:
- anysid = security.dom_sid(security.SID_NT_SELF)
- print acl.info.as_sddl(anysid)
- else:
- acl.dump()
-
-
-class cmd_nt_acl(SuperCommand):
- """NT ACLs manipulation"""
-
- subcommands = {}
- subcommands["set"] = cmd_acl_set()
- subcommands["get"] = cmd_acl_get()
-
diff --git a/source4/scripting/python/samba/netcmd/pwsettings.py b/source4/scripting/python/samba/netcmd/pwsettings.py
deleted file mode 100644
index 3f1a8e189d..0000000000
--- a/source4/scripting/python/samba/netcmd/pwsettings.py
+++ /dev/null
@@ -1,197 +0,0 @@
-#!/usr/bin/env python
-#
-# Sets password settings.
-# (Password complexity, history length, minimum password length, the minimum
-# and maximum password age) on a Samba4 server
-#
-# Copyright Matthias Dieter Wallnoefer 2009
-# Copyright Andrew Kroeger 2009
-# Copyright Jelmer Vernooij 2009
-#
-# 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/>.
-#
-
-import samba.getopt as options
-import ldb
-
-from samba.auth import system_session
-from samba.samdb import SamDB
-from samba.dcerpc.samr import DOMAIN_PASSWORD_COMPLEX, DOMAIN_PASSWORD_STORE_CLEARTEXT
-from samba.netcmd import Command, CommandError, Option
-
-class cmd_pwsettings(Command):
- """Sets password settings
-
- Password complexity, history length, minimum password length, the minimum
- and maximum password age) on a Samba4 server.
- """
-
- synopsis = "(show | set <options>)"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "versionopts": options.VersionOptions,
- "credopts": options.CredentialsOptions,
- }
-
- takes_options = [
- Option("-H", help="LDB URL for database or target server", type=str),
- Option("--quiet", help="Be quiet", action="store_true"),
- Option("--complexity", type="choice", choices=["on","off","default"],
- help="The password complexity (on | off | default). Default is 'on'"),
- Option("--store-plaintext", type="choice", choices=["on","off","default"],
- help="Store plaintext passwords where account have 'store passwords with reversible encryption' set (on | off | default). Default is 'off'"),
- Option("--history-length",
- help="The password history length (<integer> | default). Default is 24.", type=str),
- Option("--min-pwd-length",
- help="The minimum password length (<integer> | default). Default is 7.", type=str),
- Option("--min-pwd-age",
- help="The minimum password age (<integer in days> | default). Default is 1.", type=str),
- Option("--max-pwd-age",
- help="The maximum password age (<integer in days> | default). Default is 43.", type=str),
- ]
-
- takes_args = ["subcommand"]
-
- def run(self, subcommand, H=None, min_pwd_age=None, max_pwd_age=None,
- quiet=False, complexity=None, store_plaintext=None, history_length=None,
- min_pwd_length=None, credopts=None, sambaopts=None,
- versionopts=None):
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp)
-
- samdb = SamDB(url=H, session_info=system_session(),
- credentials=creds, lp=lp)
-
- domain_dn = samdb.domain_dn()
- res = samdb.search(domain_dn, scope=ldb.SCOPE_BASE,
- attrs=["pwdProperties", "pwdHistoryLength", "minPwdLength",
- "minPwdAge", "maxPwdAge"])
- assert(len(res) == 1)
- try:
- pwd_props = int(res[0]["pwdProperties"][0])
- pwd_hist_len = int(res[0]["pwdHistoryLength"][0])
- cur_min_pwd_len = int(res[0]["minPwdLength"][0])
- # ticks -> days
- cur_min_pwd_age = int(abs(int(res[0]["minPwdAge"][0])) / (1e7 * 60 * 60 * 24))
- cur_max_pwd_age = int(abs(int(res[0]["maxPwdAge"][0])) / (1e7 * 60 * 60 * 24))
- except Exception, e:
- raise CommandError("Could not retrieve password properties!", e)
-
- if subcommand == "show":
- self.message("Password informations for domain '%s'" % domain_dn)
- self.message("")
- if pwd_props & DOMAIN_PASSWORD_COMPLEX != 0:
- self.message("Password complexity: on")
- else:
- self.message("Password complexity: off")
- if pwd_props & DOMAIN_PASSWORD_STORE_CLEARTEXT != 0:
- self.message("Store plaintext passwords: on")
- else:
- self.message("Store plaintext passwords: off")
- self.message("Password history length: %d" % pwd_hist_len)
- self.message("Minimum password length: %d" % cur_min_pwd_len)
- self.message("Minimum password age (days): %d" % cur_min_pwd_age)
- self.message("Maximum password age (days): %d" % cur_max_pwd_age)
- elif subcommand == "set":
- msgs = []
- m = ldb.Message()
- m.dn = ldb.Dn(samdb, domain_dn)
-
- if complexity is not None:
- if complexity == "on" or complexity == "default":
- pwd_props = pwd_props | DOMAIN_PASSWORD_COMPLEX
- msgs.append("Password complexity activated!")
- elif complexity == "off":
- pwd_props = pwd_props & (~DOMAIN_PASSWORD_COMPLEX)
- msgs.append("Password complexity deactivated!")
-
- if store_plaintext is not None:
- if store_plaintext == "on" or store_plaintext == "default":
- pwd_props = pwd_props | DOMAIN_PASSWORD_STORE_CLEARTEXT
- msgs.append("Plaintext password storage for changed passwords activated!")
- elif store_plaintext == "off":
- pwd_props = pwd_props & (~DOMAIN_PASSWORD_STORE_CLEARTEXT)
- msgs.append("Plaintext password storage for changed passwords deactivated!")
-
- if complexity is not None or store_plaintext is not None:
- m["pwdProperties"] = ldb.MessageElement(str(pwd_props),
- ldb.FLAG_MOD_REPLACE, "pwdProperties")
-
- if history_length is not None:
- if history_length == "default":
- pwd_hist_len = 24
- else:
- pwd_hist_len = int(history_length)
-
- if pwd_hist_len < 0 or pwd_hist_len > 24:
- raise CommandError("Password history length must be in the range of 0 to 24!")
-
- m["pwdHistoryLength"] = ldb.MessageElement(str(pwd_hist_len),
- ldb.FLAG_MOD_REPLACE, "pwdHistoryLength")
- msgs.append("Password history length changed!")
-
- if min_pwd_length is not None:
- if min_pwd_length == "default":
- min_pwd_len = 7
- else:
- min_pwd_len = int(min_pwd_length)
-
- if min_pwd_len < 0 or min_pwd_len > 14:
- raise CommandError("Minimum password length must be in the range of 0 to 14!")
-
- m["minPwdLength"] = ldb.MessageElement(str(min_pwd_len),
- ldb.FLAG_MOD_REPLACE, "minPwdLength")
- msgs.append("Minimum password length changed!")
-
- if min_pwd_age is not None:
- if min_pwd_age == "default":
- min_pwd_age = 1
- else:
- min_pwd_age = int(min_pwd_age)
-
- if min_pwd_age < 0 or min_pwd_age > 998:
- raise CommandError("Minimum password age must be in the range of 0 to 998!")
-
- # days -> ticks
- min_pwd_age_ticks = -int(min_pwd_age * (24 * 60 * 60 * 1e7))
-
- m["minPwdAge"] = ldb.MessageElement(str(min_pwd_age_ticks),
- ldb.FLAG_MOD_REPLACE, "minPwdAge")
- msgs.append("Minimum password age changed!")
-
- if max_pwd_age is not None:
- if max_pwd_age == "default":
- max_pwd_age = 43
- else:
- max_pwd_age = int(max_pwd_age)
-
- if max_pwd_age < 0 or max_pwd_age > 999:
- raise CommandError("Maximum password age must be in the range of 0 to 999!")
-
- # days -> ticks
- max_pwd_age_ticks = -int(max_pwd_age * (24 * 60 * 60 * 1e7))
-
- m["maxPwdAge"] = ldb.MessageElement(str(max_pwd_age_ticks),
- ldb.FLAG_MOD_REPLACE, "maxPwdAge")
- msgs.append("Maximum password age changed!")
-
- if max_pwd_age > 0 and min_pwd_age >= max_pwd_age:
- raise CommandError("Maximum password age (%d) must be greater than minimum password age (%d)!" % (max_pwd_age, min_pwd_age))
-
- samdb.modify(m)
- msgs.append("All changes applied successfully!")
- self.message("\n".join(msgs))
- else:
- raise CommandError("Wrong argument '%s'!" % subcommand)
diff --git a/source4/scripting/python/samba/netcmd/rodc.py b/source4/scripting/python/samba/netcmd/rodc.py
deleted file mode 100644
index f4daac853d..0000000000
--- a/source4/scripting/python/samba/netcmd/rodc.py
+++ /dev/null
@@ -1,115 +0,0 @@
-#!/usr/bin/env python
-#
-# rodc related commands
-#
-# Copyright Andrew Tridgell 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/>.
-#
-
-from samba.netcmd import Command, CommandError, Option, SuperCommand
-import samba.getopt as options
-from samba.samdb import SamDB
-from samba.auth import system_session
-import ldb
-from samba.dcerpc import misc, drsuapi
-from samba.credentials import Credentials
-from samba.drs_utils import drs_Replicate
-
-class cmd_rodc_preload(Command):
- """Preload one account for an RODC"""
-
- synopsis = "%prog rodc preload <SID|DN|accountname>"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "versionopts": options.VersionOptions,
- "credopts": options.CredentialsOptions,
- }
-
- takes_options = [
- Option("--server", help="DC to use", type=str),
- ]
-
- takes_args = ["account"]
-
- def get_dn(self, samdb, account):
- '''work out what DN they meant'''
-
- # we accept the account in SID, accountname or DN form
- if account[0:2] == 'S-':
- res = samdb.search(base="<SID=%s>" % account,
- expression="objectclass=user",
- scope=ldb.SCOPE_BASE, attrs=[])
- elif account.find('=') >= 0:
- res = samdb.search(base=account,
- expression="objectclass=user",
- scope=ldb.SCOPE_BASE, attrs=[])
- else:
- res = samdb.search(expression="(&(samAccountName=%s)(objectclass=user))" % account,
- scope=ldb.SCOPE_SUBTREE, attrs=[])
- if len(res) != 1:
- raise Exception("Failed to find account '%s'" % account)
- return str(res[0]["dn"])
-
-
- def get_dsServiceName(self, samdb):
- res = samdb.search(base="", scope=ldb.SCOPE_BASE, attrs=["dsServiceName"])
- return res[0]["dsServiceName"][0]
-
-
- def run(self, account, sambaopts=None,
- credopts=None, versionopts=None, server=None):
-
- if server is None:
- raise Exception("You must supply a server")
-
- lp = sambaopts.get_loadparm()
-
- creds = credopts.get_credentials(lp, fallback_machine=True)
-
- # connect to the remote and local SAMs
- samdb = SamDB(url="ldap://%s" % server,
- session_info=system_session(),
- credentials=creds, lp=lp)
-
- local_samdb = SamDB(url=None, session_info=system_session(),
- credentials=creds, lp=lp)
-
- # work out the source and destination GUIDs
- dc_ntds_dn = self.get_dsServiceName(samdb)
- res = samdb.search(base=dc_ntds_dn, scope=ldb.SCOPE_BASE, attrs=["invocationId"])
- source_dsa_invocation_id = misc.GUID(local_samdb.schema_format_value("objectGUID", res[0]["invocationId"][0]))
-
- dn = self.get_dn(samdb, account)
- print "Replicating DN %s" % dn
-
- destination_dsa_guid = misc.GUID(local_samdb.get_ntds_GUID())
-
- local_samdb.transaction_start()
- repl = drs_Replicate("ncacn_ip_tcp:%s[seal,print]" % server, lp, creds, local_samdb)
- try:
- repl.replicate(dn, source_dsa_invocation_id, destination_dsa_guid,
- exop=drsuapi.DRSUAPI_EXOP_REPL_SECRET, rodc=True)
- except Exception, e:
- raise CommandError("Error replicating DN %s" % dn, e)
- local_samdb.transaction_commit()
-
-
-
-class cmd_rodc(SuperCommand):
- """RODC commands"""
-
- subcommands = {}
- subcommands["preload"] = cmd_rodc_preload()
diff --git a/source4/scripting/python/samba/netcmd/setexpiry.py b/source4/scripting/python/samba/netcmd/setexpiry.py
deleted file mode 100644
index bd8ea166fa..0000000000
--- a/source4/scripting/python/samba/netcmd/setexpiry.py
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/usr/bin/env python
-#
-# Sets the user password expiry on a Samba4 server
-# Copyright Jelmer Vernooij 2008
-#
-# Based on the original in EJS:
-# Copyright Andrew Tridgell 2005
-#
-# 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/>.
-#
-
-from samba.netcmd import Command, CommandError, Option
-
-import samba.getopt as options
-
-from samba.auth import system_session
-from samba.samdb import SamDB
-
-class cmd_setexpiry(Command):
- """Sets the expiration of a user account"""
-
- synopsis = "setexpiry [username] [options]"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "versionopts": options.VersionOptions,
- "credopts": options.CredentialsOptions,
- }
-
- takes_options = [
- Option("-H", help="LDB URL for database or target server", type=str),
- Option("--filter", help="LDAP Filter to set password on", type=str),
- Option("--days", help="Days to expiry", type=int),
- Option("--noexpiry", help="Password does never expire", action="store_true"),
- ]
-
- takes_args = ["username?"]
-
- def run(self, username=None, sambaopts=None, credopts=None,
- versionopts=None, H=None, filter=None, days=None, noexpiry=None):
- if username is None and filter is None:
- raise CommandError("Either the username or '--filter' must be specified!")
-
- if filter is None:
- filter = "(&(objectClass=user)(sAMAccountName=%s))" % (username)
-
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp)
-
- if days is None:
- days = 0
-
- samdb = SamDB(url=H, session_info=system_session(),
- credentials=creds, lp=lp)
-
- samdb.setexpiry(filter, days*24*3600, no_expiry_req=noexpiry)
diff --git a/source4/scripting/python/samba/netcmd/setpassword.py b/source4/scripting/python/samba/netcmd/setpassword.py
deleted file mode 100644
index b32b651822..0000000000
--- a/source4/scripting/python/samba/netcmd/setpassword.py
+++ /dev/null
@@ -1,80 +0,0 @@
-#!/usr/bin/env python
-#
-# Sets a user password on a Samba4 server
-# Copyright Jelmer Vernooij 2008
-#
-# Based on the original in EJS:
-# Copyright Andrew Tridgell 2005
-#
-# 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/>.
-#
-
-import samba.getopt as options
-from samba.netcmd import Command, CommandError, Option
-from getpass import getpass
-from samba.auth import system_session
-from samba.samdb import SamDB
-from samba import gensec
-import ldb
-
-class cmd_setpassword(Command):
- """(Re)sets the password on a user account"""
-
- synopsis = "setpassword [username] [options]"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "versionopts": options.VersionOptions,
- "credopts": options.CredentialsOptions,
- }
-
- takes_options = [
- Option("-H", help="LDB URL for database or target server", type=str),
- Option("--filter", help="LDAP Filter to set password on", type=str),
- Option("--newpassword", help="Set password", type=str),
- Option("--must-change-at-next-login",
- help="Force password to be changed on next login",
- action="store_true"),
- ]
-
- takes_args = ["username?"]
-
- def run(self, username=None, filter=None, credopts=None, sambaopts=None,
- versionopts=None, H=None, newpassword=None,
- must_change_at_next_login=None):
- if filter is None and username is None:
- raise CommandError("Either the username or '--filter' must be specified!")
-
- password = newpassword
- if password is None:
- password = getpass("New Password: ")
-
- if filter is None:
- filter = "(&(objectClass=user)(sAMAccountName=%s))" % (username)
-
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp)
-
- creds.set_gensec_features(creds.get_gensec_features() | gensec.FEATURE_SEAL)
-
- samdb = SamDB(url=H, session_info=system_session(),
- credentials=creds, lp=lp)
-
- try:
- samdb.setpassword(filter, password,
- force_change_at_next_login=must_change_at_next_login,
- username=username)
- except Exception, e:
- raise CommandError('Failed to set password for user "%s"' % username, e)
- print "Changed password OK"
diff --git a/source4/scripting/python/samba/netcmd/spn.py b/source4/scripting/python/samba/netcmd/spn.py
deleted file mode 100644
index 4cfa21fa03..0000000000
--- a/source4/scripting/python/samba/netcmd/spn.py
+++ /dev/null
@@ -1,217 +0,0 @@
-#!/usr/bin/env python
-#
-# spn management
-#
-# Copyright Matthieu Patou mat@samba.org 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/>.
-#
-
-import samba.getopt as options
-import ldb
-import re
-from samba import provision
-from samba.samdb import SamDB
-from samba.auth import system_session
-from samba.netcmd import (
- Command,
- CommandError,
- SuperCommand,
- Option
- )
-
-def _get_user_realm_domain(user):
- """ get the realm or the domain and the base user
- from user like:
- * username
- * DOMAIN\username
- * username@REALM
- """
- baseuser = user
- realm = ""
- domain = ""
- m = re.match(r"(\w+)\\(\w+$)", user)
- if m:
- domain = m.group(1)
- baseuser = m.group(2)
- return (baseuser.lower(), domain.upper(), realm)
- m = re.match(r"(\w+)@(\w+)", user)
- if m:
- baseuser = m.group(1)
- realm = m.group(2)
- return (baseuser.lower(), domain, realm.upper())
-
-class cmd_spn_list(Command):
- """List spns of a given user."""
- synopsis = "%prog spn list <user>"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "credopts": options.CredentialsOptions,
- "versionopts": options.VersionOptions,
- }
-
- takes_args = ["user"]
-
- def run(self, user, credopts=None, sambaopts=None, versionopts=None):
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp)
- paths = provision.provision_paths_from_lp(lp, lp.get("realm"))
- sam = SamDB(paths.samdb, session_info=system_session(),
- credentials=creds, lp=lp)
- # TODO once I understand how, use the domain info to naildown
- # to the correct domain
- (cleaneduser, realm, domain) = _get_user_realm_domain(user)
- print cleaneduser
- res = sam.search(expression="samaccountname=%s" % cleaneduser,
- scope=ldb.SCOPE_SUBTREE,
- attrs=["servicePrincipalName"])
- if len(res) >0:
- spns = res[0].get("servicePrincipalName")
- found = False
- flag = ldb.FLAG_MOD_ADD
- if spns != None:
- print "User %s has the following servicePrincipalName: " % str(res[0].dn)
- for e in spns:
- print "\t %s" % (str(e))
-
- else:
- print "User %s has no servicePrincipalName" % str(res[0].dn)
- else:
- raise CommandError("User %s not found" % user)
-
-class cmd_spn_add(Command):
- """Create a new spn."""
- synopsis = "%prog spn add [--force] <name> <user>"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "credopts": options.CredentialsOptions,
- "versionopts": options.VersionOptions,
- }
- takes_options = [
- Option("--force", help="Force the addition of the spn"\
- " even it exists already", action="store_true"),
- ]
- takes_args = ["name", "user"]
-
- def run(self, name, user, force=False, credopts=None, sambaopts=None, versionopts=None):
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp)
- paths = provision.provision_paths_from_lp(lp, lp.get("realm"))
- sam = SamDB(paths.samdb, session_info=system_session(),
- credentials=creds, lp=lp)
- res = sam.search(expression="servicePrincipalName=%s" % name,
- scope=ldb.SCOPE_SUBTREE,
- )
- if len(res) != 0 and not force:
- raise CommandError("Service principal %s already"
- " affected to another user" % name)
-
- (cleaneduser, realm, domain) = _get_user_realm_domain(user)
- res = sam.search(expression="samaccountname=%s" % cleaneduser,
- scope=ldb.SCOPE_SUBTREE,
- attrs=["servicePrincipalName"])
- if len(res) >0:
- res[0].dn
- msg = ldb.Message()
- spns = res[0].get("servicePrincipalName")
- tab = []
- found = False
- flag = ldb.FLAG_MOD_ADD
- if spns != None:
- for e in spns:
- if str(e) == name:
- found = True
- tab.append(str(e))
- flag = ldb.FLAG_MOD_REPLACE
- tab.append(name)
- msg.dn = res[0].dn
- msg["servicePrincipalName"] = ldb.MessageElement(tab, flag,
- "servicePrincipalName")
- if not found:
- sam.modify(msg)
- else:
- raise CommandError("Service principal %s already"
- " affected to %s" % (name, user))
- else:
- raise CommandError("User %s not found" % user)
-
-
-class cmd_spn_delete(Command):
- """Delete a spn."""
- synopsis = "%prog spn delete <name> [user]"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "credopts": options.CredentialsOptions,
- "versionopts": options.VersionOptions,
- }
-
- takes_args = ["name", "user?"]
-
- def run(self, name, user=None, credopts=None, sambaopts=None, versionopts=None):
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp)
- paths = provision.provision_paths_from_lp(lp, lp.get("realm"))
- sam = SamDB(paths.samdb, session_info=system_session(),
- credentials=creds, lp=lp)
- res = sam.search(expression="servicePrincipalName=%s" % name,
- scope=ldb.SCOPE_SUBTREE,
- attrs=["servicePrincipalName", "samAccountName"])
- if len(res) >0:
- result = None
- if user is not None:
- (cleaneduser, realm, domain) = _get_user_realm_domain(user)
- for elem in res:
- if str(elem["samAccountName"]).lower() == cleaneduser:
- result = elem
- if result is None:
- raise CommandError("Unable to find user %s with"
- " spn %s" % (user, name))
- else:
- if len(res) != 1:
- listUser = ""
- for r in res:
- listUser = "%s\n%s" % (listUser, str(r.dn))
- raise CommandError("More than one user has the spn %s "\
- "and no specific user was specified, list of users"\
- " with this spn:%s" % (name, listUser))
- else:
- result=res[0]
-
-
- msg = ldb.Message()
- spns = result.get("servicePrincipalName")
- tab = []
- if spns != None:
- for e in spns:
- if str(e) != name:
- tab.append(str(e))
- flag = ldb.FLAG_MOD_REPLACE
- msg.dn = result.dn
- msg["servicePrincipalName"] = ldb.MessageElement(tab, flag,
- "servicePrincipalName")
- sam.modify(msg)
- else:
- raise CommandError("Service principal %s not affected" % name)
-
-class cmd_spn(SuperCommand):
- """SPN management [server connection needed]"""
-
- subcommands = {}
- subcommands["add"] = cmd_spn_add()
- subcommands["list"] = cmd_spn_list()
- subcommands["delete"] = cmd_spn_delete()
-
diff --git a/source4/scripting/python/samba/netcmd/time.py b/source4/scripting/python/samba/netcmd/time.py
deleted file mode 100644
index e13d3df96c..0000000000
--- a/source4/scripting/python/samba/netcmd/time.py
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/env python
-#
-# time
-#
-# Copyright Jelmer Vernooij 2010 <jelmer@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/>.
-#
-
-import samba.getopt as options
-import common
-from samba.net import Net
-
-from samba.netcmd import (
- Command,
- )
-
-class cmd_time(Command):
- """Retrieve the time on a remote server [server connection needed]"""
- synopsis = "%prog time <server-name>"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "credopts": options.CredentialsOptions,
- "versionopts": options.VersionOptions,
- }
-
- takes_args = ["server_name?"]
-
- def run(self, server_name=None, credopts=None, sambaopts=None, versionopts=None):
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp, fallback_machine=True)
- net = Net(creds, lp, server=credopts.ipaddress)
- if server_name is None:
- server_name = common.netcmd_dnsname(lp)
- print net.time(server_name)
diff --git a/source4/scripting/python/samba/netcmd/user.py b/source4/scripting/python/samba/netcmd/user.py
deleted file mode 100644
index bbc972bcc7..0000000000
--- a/source4/scripting/python/samba/netcmd/user.py
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/usr/bin/env python
-#
-# user management
-#
-# Copyright Jelmer Vernooij 2010 <jelmer@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/>.
-#
-
-import samba.getopt as options
-
-from samba.net import Net
-
-from samba.netcmd import (
- Command,
- SuperCommand,
- )
-
-class cmd_user_add(Command):
- """Create a new user."""
- synopsis = "%prog user add <name> [<password>]"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "credopts": options.CredentialsOptions,
- "versionopts": options.VersionOptions,
- }
-
- takes_args = ["name", "password?"]
-
- def run(self, name, password=None, credopts=None, sambaopts=None, versionopts=None):
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp )
- net = Net(creds, lp, server=credopts.ipaddress)
- net.create_user(name)
- if password is not None:
- net.set_password(name, creds.get_domain(), password, creds)
-
-
-class cmd_user_delete(Command):
- """Delete a user."""
- synopsis = "%prog user delete <name>"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "credopts": options.CredentialsOptions,
- "versionopts": options.VersionOptions,
- }
-
- takes_args = ["name"]
-
- def run(self, name, credopts=None, sambaopts=None, versionopts=None):
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp, fallback_machine=True)
- net = Net(creds, lp, server=credopts.ipaddress)
- net.delete_user(name)
-
-
-class cmd_user(SuperCommand):
- """User management [server connection needed]"""
-
- subcommands = {}
- subcommands["add"] = cmd_user_add()
- subcommands["delete"] = cmd_user_delete()
-
diff --git a/source4/scripting/python/samba/netcmd/vampire.py b/source4/scripting/python/samba/netcmd/vampire.py
deleted file mode 100644
index 509aa8aacd..0000000000
--- a/source4/scripting/python/samba/netcmd/vampire.py
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/usr/bin/env python
-#
-# Vampire
-#
-# Copyright Jelmer Vernooij 2010 <jelmer@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/>.
-#
-
-import samba.getopt as options
-
-from samba.net import Net
-
-from samba.netcmd import (
- Command,
- Option,
- SuperCommand,
- CommandError
- )
-
-class cmd_vampire(Command):
- """Join and synchronise a remote AD domain to the local server [server connection needed]"""
- synopsis = "%prog vampire [options] <domain>"
-
- takes_optiongroups = {
- "sambaopts": options.SambaOptions,
- "credopts": options.CredentialsOptions,
- "versionopts": options.VersionOptions,
- }
-
- takes_options = [
- Option("--target-dir", help="Target directory.", type=str),
- Option("--force", help="force run", action='store_true', default=False),
- ]
-
- takes_args = ["domain"]
-
- def run(self, domain, target_dir=None, credopts=None, sambaopts=None, versionopts=None, force=False):
- if not force:
- raise CommandError("samba-tool vampire is deprecated, please use samba-tool join. Use --force to override")
- lp = sambaopts.get_loadparm()
- creds = credopts.get_credentials(lp)
- net = Net(creds, lp, server=credopts.ipaddress)
- (domain_name, domain_sid) = net.vampire(domain=domain, target_dir=target_dir)
- self.outf.write("Vampired domain %s (%s)\n" % (domain_name, domain_sid))
diff --git a/source4/scripting/python/samba/ntacls.py b/source4/scripting/python/samba/ntacls.py
deleted file mode 100644
index 78365e98b8..0000000000
--- a/source4/scripting/python/samba/ntacls.py
+++ /dev/null
@@ -1,171 +0,0 @@
-#!/usr/bin/env python
-
-# Unix SMB/CIFS implementation.
-# Copyright (C) Matthieu Patou <mat@matws.net> 2009-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/>.
-#
-
-"""NT Acls."""
-
-
-import os
-import samba.xattr_native, samba.xattr_tdb
-from samba.dcerpc import security, xattr
-from samba.ndr import ndr_pack, ndr_unpack
-
-class XattrBackendError(Exception):
- """A generic xattr backend error."""
-
-
-def checkset_backend(lp, backend, eadbfile):
- '''return the path to the eadb, or None'''
- if backend is None:
- return lp.get("posix:eadb")
- elif backend == "native":
- return None
- elif backend == "tdb":
- if eadbfile is not None:
- return eadbfile
- else:
- return os.path.abspath(os.path.join(lp.get("private dir"), "eadb.tdb"))
- else:
- raise XattrBackendError("Invalid xattr backend choice %s"%backend)
-
-
-def getntacl(lp, file, backend=None, eadbfile=None):
- eadbname = checkset_backend(lp, backend, eadbfile)
- if eadbname is not None:
- try:
- attribute = samba.xattr_tdb.wrap_getxattr(eadbname, file,
- xattr.XATTR_NTACL_NAME)
- except Exception:
- # FIXME: Don't catch all exceptions, just those related to opening
- # xattrdb
- print "Fail to open %s" % eadbname
- attribute = samba.xattr_native.wrap_getxattr(file,
- xattr.XATTR_NTACL_NAME)
- else:
- attribute = samba.xattr_native.wrap_getxattr(file,
- xattr.XATTR_NTACL_NAME)
- ntacl = ndr_unpack(xattr.NTACL, attribute)
- return ntacl
-
-
-def setntacl(lp, file, sddl, domsid, backend=None, eadbfile=None):
- eadbname = checkset_backend(lp, backend, eadbfile)
- ntacl = xattr.NTACL()
- ntacl.version = 1
- sid = security.dom_sid(domsid)
- sd = security.descriptor.from_sddl(sddl, sid)
- ntacl.info = sd
- if eadbname is not None:
- try:
- samba.xattr_tdb.wrap_setxattr(eadbname,
- file, xattr.XATTR_NTACL_NAME, ndr_pack(ntacl))
- except Exception:
- # FIXME: Don't catch all exceptions, just those related to opening
- # xattrdb
- print "Fail to open %s" % eadbname
- samba.xattr_native.wrap_setxattr(file, xattr.XATTR_NTACL_NAME,
- ndr_pack(ntacl))
- else:
- samba.xattr_native.wrap_setxattr(file, xattr.XATTR_NTACL_NAME,
- ndr_pack(ntacl))
-
-
-def ldapmask2filemask(ldm):
- """Takes the access mask of a DS ACE and transform them in a File ACE mask.
- """
- RIGHT_DS_CREATE_CHILD = 0x00000001
- RIGHT_DS_DELETE_CHILD = 0x00000002
- RIGHT_DS_LIST_CONTENTS = 0x00000004
- ACTRL_DS_SELF = 0x00000008
- RIGHT_DS_READ_PROPERTY = 0x00000010
- RIGHT_DS_WRITE_PROPERTY = 0x00000020
- RIGHT_DS_DELETE_TREE = 0x00000040
- RIGHT_DS_LIST_OBJECT = 0x00000080
- RIGHT_DS_CONTROL_ACCESS = 0x00000100
- FILE_READ_DATA = 0x0001
- FILE_LIST_DIRECTORY = 0x0001
- FILE_WRITE_DATA = 0x0002
- FILE_ADD_FILE = 0x0002
- FILE_APPEND_DATA = 0x0004
- FILE_ADD_SUBDIRECTORY = 0x0004
- FILE_CREATE_PIPE_INSTANCE = 0x0004
- FILE_READ_EA = 0x0008
- FILE_WRITE_EA = 0x0010
- FILE_EXECUTE = 0x0020
- FILE_TRAVERSE = 0x0020
- FILE_DELETE_CHILD = 0x0040
- FILE_READ_ATTRIBUTES = 0x0080
- FILE_WRITE_ATTRIBUTES = 0x0100
- DELETE = 0x00010000
- READ_CONTROL = 0x00020000
- WRITE_DAC = 0x00040000
- WRITE_OWNER = 0x00080000
- SYNCHRONIZE = 0x00100000
- STANDARD_RIGHTS_ALL = 0x001F0000
-
- filemask = ldm & STANDARD_RIGHTS_ALL
-
- if (ldm & RIGHT_DS_READ_PROPERTY) and (ldm & RIGHT_DS_LIST_CONTENTS):
- filemask = filemask | (SYNCHRONIZE | FILE_LIST_DIRECTORY |\
- FILE_READ_ATTRIBUTES | FILE_READ_EA |\
- FILE_READ_DATA | FILE_EXECUTE)
-
- if ldm & RIGHT_DS_WRITE_PROPERTY:
- filemask = filemask | (SYNCHRONIZE | FILE_WRITE_DATA |\
- FILE_APPEND_DATA | FILE_WRITE_EA |\
- FILE_WRITE_ATTRIBUTES | FILE_ADD_FILE |\
- FILE_ADD_SUBDIRECTORY)
-
- if ldm & RIGHT_DS_CREATE_CHILD:
- filemask = filemask | (FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE)
-
- if ldm & RIGHT_DS_DELETE_CHILD:
- filemask = filemask | FILE_DELETE_CHILD
-
- return filemask
-
-
-def dsacl2fsacl(dssddl, domsid):
- """
-
- This function takes an the SDDL representation of a DS
- ACL and return the SDDL representation of this ACL adapted
- for files. It's used for Policy object provision
- """
- sid = security.dom_sid(domsid)
- ref = security.descriptor.from_sddl(dssddl, sid)
- fdescr = security.descriptor()
- fdescr.owner_sid = ref.owner_sid
- fdescr.group_sid = ref.group_sid
- fdescr.type = ref.type
- fdescr.revision = ref.revision
- fdescr.sacl = ref.sacl
- aces = ref.dacl.aces
- for i in range(0, len(aces)):
- ace = aces[i]
- if not ace.type & security.SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT and str(ace.trustee) != security.SID_BUILTIN_PREW2K:
- # if fdescr.type & security.SEC_DESC_DACL_AUTO_INHERITED:
- ace.flags = ace.flags | security.SEC_ACE_FLAG_OBJECT_INHERIT | security.SEC_ACE_FLAG_CONTAINER_INHERIT
- if str(ace.trustee) == security.SID_CREATOR_OWNER:
- # For Creator/Owner the IO flag is set as this ACE has only a sense for child objects
- ace.flags = ace.flags | security.SEC_ACE_FLAG_INHERIT_ONLY
- ace.access_mask = ldapmask2filemask(ace.access_mask)
- fdescr.dacl_add(ace)
-
- return fdescr.as_sddl(sid)
diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py
new file mode 100644
index 0000000000..64491c2b18
--- /dev/null
+++ b/source4/scripting/python/samba/provision.py
@@ -0,0 +1,2067 @@
+#
+# Unix SMB/CIFS implementation.
+# backend code for provisioning a Samba4 server
+
+# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
+# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008-2009
+# Copyright (C) Oliver Liebel <oliver@itc.li> 2008-2009
+#
+# Based on the original in EJS:
+# Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
+#
+# 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/>.
+#
+
+"""Functions for setting up a Samba configuration."""
+
+from base64 import b64encode
+import os
+import sys
+import pwd
+import grp
+import time
+import uuid, glue
+import socket
+import param
+import registry
+import samba
+import subprocess
+import ldb
+
+import shutil
+from credentials import Credentials, DONT_USE_KERBEROS
+from auth import system_session, admin_session
+from samba import version, Ldb, substitute_var, valid_netbios_name
+from samba import check_all_substituted
+from samba import DS_DOMAIN_FUNCTION_2000, DS_DOMAIN_FUNCTION_2008, DS_DC_FUNCTION_2008, DS_DC_FUNCTION_2008_R2
+from samba.samdb import SamDB
+from samba.idmap import IDmapDB
+from samba.dcerpc import security
+from samba.ndr import ndr_pack
+import urllib
+from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, timestring
+from ms_schema import read_ms_schema
+from ms_display_specifiers import read_ms_ldif
+from signal import SIGTERM
+from dcerpc.misc import SEC_CHAN_BDC, SEC_CHAN_WKSTA
+
+__docformat__ = "restructuredText"
+
+def find_setup_dir():
+ """Find the setup directory used by provision."""
+ dirname = os.path.dirname(__file__)
+ if "/site-packages/" in dirname:
+ prefix = "/".join(dirname[:dirname.index("/site-packages/")].split("/")[:-2])
+ for suffix in ["share/setup", "share/samba/setup", "setup"]:
+ ret = os.path.join(prefix, suffix)
+ if os.path.isdir(ret):
+ return ret
+ # In source tree
+ ret = os.path.join(dirname, "../../../setup")
+ if os.path.isdir(ret):
+ return ret
+ raise Exception("Unable to find setup directory.")
+
+def get_schema_descriptor(domain_sid):
+ sddl = "O:SAG:SAD:(A;CI;RPLCLORC;;;AU)(A;CI;RPWPCRCCLCLORCWOWDSW;;;SA)" \
+ "(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
+ "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
+ "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
+ "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
+ "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
+ "S:(AU;SA;WPCCDCWOWDSDDTSW;;;WD)" \
+ "(AU;CISA;WP;;;WD)(AU;SA;CR;;;BA)" \
+ "(AU;SA;CR;;;DU)(OU;SA;CR;e12b56b6-0a95-11d1-adbb-00c04fd8d5cd;;WD)" \
+ "(OU;SA;CR;45ec5156-db7e-47bb-b53f-dbeb2d03c40f;;WD)"
+ sec = security.descriptor.from_sddl(sddl, domain_sid)
+ return b64encode(ndr_pack(sec))
+
+def get_config_descriptor(domain_sid):
+ sddl = "O:EAG:EAD:(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
+ "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
+ "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
+ "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
+ "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
+ "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
+ "(A;;RPLCLORC;;;AU)(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
+ "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;CIIO;RPWPCRCCLCLORCWOWDSDSW;;;DA)" \
+ "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
+ "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
+ "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
+ "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
+ "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;S-1-5-21-3191434175-1265308384-3577286990-498)" \
+ "S:(AU;SA;WPWOWD;;;WD)(AU;SA;CR;;;BA)(AU;SA;CR;;;DU)" \
+ "(OU;SA;CR;45ec5156-db7e-47bb-b53f-dbeb2d03c40f;;WD)"
+ sec = security.descriptor.from_sddl(sddl, domain_sid)
+ return b64encode(ndr_pack(sec))
+
+
+DEFAULTSITE = "Default-First-Site-Name"
+
+# Exception classes
+
+class ProvisioningError(Exception):
+ """A generic provision error."""
+
+class InvalidNetbiosName(Exception):
+ """A specified name was not a valid NetBIOS name."""
+ def __init__(self, name):
+ super(InvalidNetbiosName, self).__init__("The name '%r' is not a valid NetBIOS name" % name)
+
+
+class ProvisionPaths(object):
+ def __init__(self):
+ self.shareconf = None
+ self.hklm = None
+ self.hkcu = None
+ self.hkcr = None
+ self.hku = None
+ self.hkpd = None
+ self.hkpt = None
+ self.samdb = None
+ self.idmapdb = None
+ self.secrets = None
+ self.keytab = None
+ self.dns_keytab = None
+ self.dns = None
+ self.winsdb = None
+ self.private_dir = None
+ self.ldapdir = None
+ self.slapdconf = None
+ self.modulesconf = None
+ self.memberofconf = None
+ self.fedoradsinf = None
+ self.fedoradspartitions = None
+ self.fedoradssasl = None
+ self.olmmron = None
+ self.olmmrserveridsconf = None
+ self.olmmrsyncreplconf = None
+ self.olcdir = None
+ self.olslapd = None
+ self.olcseedldif = None
+
+
+class ProvisionNames(object):
+ def __init__(self):
+ self.rootdn = None
+ self.domaindn = None
+ self.configdn = None
+ self.schemadn = None
+ self.sambadn = None
+ self.ldapmanagerdn = None
+ self.dnsdomain = None
+ self.realm = None
+ self.netbiosname = None
+ self.domain = None
+ self.hostname = None
+ self.sitename = None
+ self.smbconf = None
+
+
+class ProvisionResult(object):
+ def __init__(self):
+ self.paths = None
+ self.domaindn = None
+ self.lp = None
+ self.samdb = None
+
+class Schema(object):
+ def __init__(self, setup_path, domain_sid, schemadn=None,
+ serverdn=None, sambadn=None, ldap_backend_type=None):
+ """Load schema for the SamDB from the AD schema files and samba4_schema.ldif
+
+ :param samdb: Load a schema into a SamDB.
+ :param setup_path: Setup path function.
+ :param schemadn: DN of the schema
+ :param serverdn: DN of the server
+
+ Returns the schema data loaded, to avoid double-parsing when then needing to add it to the db
+ """
+
+ self.ldb = Ldb()
+ self.schema_data = read_ms_schema(setup_path('ad-schema/MS-AD_Schema_2K8_Attributes.txt'),
+ setup_path('ad-schema/MS-AD_Schema_2K8_Classes.txt'))
+ self.schema_data += open(setup_path("schema_samba4.ldif"), 'r').read()
+ self.schema_data = substitute_var(self.schema_data, {"SCHEMADN": schemadn})
+ check_all_substituted(self.schema_data)
+
+ self.schema_dn_modify = read_and_sub_file(setup_path("provision_schema_basedn_modify.ldif"),
+ {"SCHEMADN": schemadn,
+ "SERVERDN": serverdn,
+ })
+
+ descr = get_schema_descriptor(domain_sid)
+ self.schema_dn_add = read_and_sub_file(setup_path("provision_schema_basedn.ldif"),
+ {"SCHEMADN": schemadn,
+ "DESCRIPTOR": descr
+ })
+
+ prefixmap = open(setup_path("prefixMap.txt"), 'r').read()
+ prefixmap = b64encode(prefixmap)
+
+ # We don't actually add this ldif, just parse it
+ prefixmap_ldif = "dn: cn=schema\nprefixMap:: %s\n\n" % prefixmap
+ self.ldb.set_schema_from_ldif(prefixmap_ldif, self.schema_data)
+
+
+# Return a hash with the forward attribute as a key and the back as the value
+def get_linked_attributes(schemadn,schemaldb):
+ attrs = ["linkID", "lDAPDisplayName"]
+ res = schemaldb.search(expression="(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1))(objectclass=attributeSchema)(attributeSyntax=2.5.5.1))", base=schemadn, scope=SCOPE_ONELEVEL, attrs=attrs)
+ attributes = {}
+ for i in range (0, len(res)):
+ expression = "(&(objectclass=attributeSchema)(linkID=%d)(attributeSyntax=2.5.5.1))" % (int(res[i]["linkID"][0])+1)
+ target = schemaldb.searchone(basedn=schemadn,
+ expression=expression,
+ attribute="lDAPDisplayName",
+ scope=SCOPE_SUBTREE)
+ if target is not None:
+ attributes[str(res[i]["lDAPDisplayName"])]=str(target)
+
+ return attributes
+
+def get_dnsyntax_attributes(schemadn,schemaldb):
+ attrs = ["linkID", "lDAPDisplayName"]
+ res = schemaldb.search(expression="(&(!(linkID=*))(objectclass=attributeSchema)(attributeSyntax=2.5.5.1))", base=schemadn, scope=SCOPE_ONELEVEL, attrs=attrs)
+ attributes = []
+ for i in range (0, len(res)):
+ attributes.append(str(res[i]["lDAPDisplayName"]))
+
+ return attributes
+
+
+def check_install(lp, session_info, credentials):
+ """Check whether the current install seems ok.
+
+ :param lp: Loadparm context
+ :param session_info: Session information
+ :param credentials: Credentials
+ """
+ if lp.get("realm") == "":
+ raise Exception("Realm empty")
+ ldb = Ldb(lp.get("sam database"), session_info=session_info,
+ credentials=credentials, lp=lp)
+ if len(ldb.search("(cn=Administrator)")) != 1:
+ raise ProvisioningError("No administrator account found")
+
+
+def findnss(nssfn, names):
+ """Find a user or group from a list of possibilities.
+
+ :param nssfn: NSS Function to try (should raise KeyError if not found)
+ :param names: Names to check.
+ :return: Value return by first names list.
+ """
+ for name in names:
+ try:
+ return nssfn(name)
+ except KeyError:
+ pass
+ raise KeyError("Unable to find user/group %r" % names)
+
+
+findnss_uid = lambda names: findnss(pwd.getpwnam, names)[2]
+findnss_gid = lambda names: findnss(grp.getgrnam, names)[2]
+
+
+def read_and_sub_file(file, subst_vars):
+ """Read a file and sub in variables found in it
+
+ :param file: File to be read (typically from setup directory)
+ param subst_vars: Optional variables to subsitute in the file.
+ """
+ data = open(file, 'r').read()
+ if subst_vars is not None:
+ data = substitute_var(data, subst_vars)
+ check_all_substituted(data)
+ return data
+
+
+def setup_add_ldif(ldb, ldif_path, subst_vars=None):
+ """Setup a ldb in the private dir.
+
+ :param ldb: LDB file to import data into
+ :param ldif_path: Path of the LDIF file to load
+ :param subst_vars: Optional variables to subsitute in LDIF.
+ """
+ assert isinstance(ldif_path, str)
+
+ data = read_and_sub_file(ldif_path, subst_vars)
+ ldb.add_ldif(data)
+
+
+def setup_modify_ldif(ldb, ldif_path, subst_vars=None):
+ """Modify a ldb in the private dir.
+
+ :param ldb: LDB object.
+ :param ldif_path: LDIF file path.
+ :param subst_vars: Optional dictionary with substitution variables.
+ """
+ data = read_and_sub_file(ldif_path, subst_vars)
+
+ ldb.modify_ldif(data)
+
+
+def setup_ldb(ldb, ldif_path, subst_vars):
+ """Import a LDIF a file into a LDB handle, optionally substituting variables.
+
+ :note: Either all LDIF data will be added or none (using transactions).
+
+ :param ldb: LDB file to import into.
+ :param ldif_path: Path to the LDIF file.
+ :param subst_vars: Dictionary with substitution variables.
+ """
+ assert ldb is not None
+ ldb.transaction_start()
+ try:
+ setup_add_ldif(ldb, ldif_path, subst_vars)
+ except:
+ ldb.transaction_cancel()
+ raise
+ ldb.transaction_commit()
+
+
+def setup_file(template, fname, subst_vars):
+ """Setup a file in the private dir.
+
+ :param template: Path of the template file.
+ :param fname: Path of the file to create.
+ :param subst_vars: Substitution variables.
+ """
+ f = fname
+
+ if os.path.exists(f):
+ os.unlink(f)
+
+ data = read_and_sub_file(template, subst_vars)
+ open(f, 'w').write(data)
+
+
+def provision_paths_from_lp(lp, dnsdomain):
+ """Set the default paths for provisioning.
+
+ :param lp: Loadparm context.
+ :param dnsdomain: DNS Domain name
+ """
+ paths = ProvisionPaths()
+ paths.private_dir = lp.get("private dir")
+ paths.dns_keytab = "dns.keytab"
+
+ paths.shareconf = os.path.join(paths.private_dir, "share.ldb")
+ paths.samdb = os.path.join(paths.private_dir, lp.get("sam database") or "samdb.ldb")
+ paths.idmapdb = os.path.join(paths.private_dir, lp.get("idmap database") or "idmap.ldb")
+ paths.secrets = os.path.join(paths.private_dir, lp.get("secrets database") or "secrets.ldb")
+ paths.dns = os.path.join(paths.private_dir, dnsdomain + ".zone")
+ paths.namedconf = os.path.join(paths.private_dir, "named.conf")
+ paths.namedtxt = os.path.join(paths.private_dir, "named.txt")
+ paths.krb5conf = os.path.join(paths.private_dir, "krb5.conf")
+ paths.winsdb = os.path.join(paths.private_dir, "wins.ldb")
+ paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi")
+ paths.phpldapadminconfig = os.path.join(paths.private_dir,
+ "phpldapadmin-config.php")
+ paths.ldapdir = os.path.join(paths.private_dir,
+ "ldap")
+ paths.slapdconf = os.path.join(paths.ldapdir,
+ "slapd.conf")
+ paths.slapdpid = os.path.join(paths.ldapdir,
+ "slapd.pid")
+ paths.modulesconf = os.path.join(paths.ldapdir,
+ "modules.conf")
+ paths.memberofconf = os.path.join(paths.ldapdir,
+ "memberof.conf")
+ paths.fedoradsinf = os.path.join(paths.ldapdir,
+ "fedorads.inf")
+ paths.fedoradspartitions = os.path.join(paths.ldapdir,
+ "fedorads-partitions.ldif")
+ paths.fedoradssasl = os.path.join(paths.ldapdir,
+ "fedorads-sasl.ldif")
+ paths.fedoradssamba = os.path.join(paths.ldapdir,
+ "fedorads-samba.ldif")
+ paths.olmmrserveridsconf = os.path.join(paths.ldapdir,
+ "mmr_serverids.conf")
+ paths.olmmrsyncreplconf = os.path.join(paths.ldapdir,
+ "mmr_syncrepl.conf")
+ paths.olcdir = os.path.join(paths.ldapdir,
+ "slapd.d")
+ paths.olcseedldif = os.path.join(paths.ldapdir,
+ "olc_seed.ldif")
+ paths.hklm = "hklm.ldb"
+ paths.hkcr = "hkcr.ldb"
+ paths.hkcu = "hkcu.ldb"
+ paths.hku = "hku.ldb"
+ paths.hkpd = "hkpd.ldb"
+ paths.hkpt = "hkpt.ldb"
+
+ paths.sysvol = lp.get("path", "sysvol")
+
+ paths.netlogon = lp.get("path", "netlogon")
+
+ paths.smbconf = lp.configfile
+
+ return paths
+
+
+def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None,
+ serverrole=None, rootdn=None, domaindn=None, configdn=None,
+ schemadn=None, serverdn=None, sitename=None, sambadn=None):
+ """Guess configuration settings to use."""
+
+ if hostname is None:
+ hostname = socket.gethostname().split(".")[0].lower()
+
+ netbiosname = hostname.upper()
+ if not valid_netbios_name(netbiosname):
+ raise InvalidNetbiosName(netbiosname)
+
+ hostname = hostname.lower()
+
+ if dnsdomain is None:
+ dnsdomain = lp.get("realm")
+
+ if serverrole is None:
+ serverrole = lp.get("server role")
+
+ assert dnsdomain is not None
+ realm = dnsdomain.upper()
+
+ if lp.get("realm").upper() != realm:
+ raise Exception("realm '%s' in %s must match chosen realm '%s'" %
+ (lp.get("realm"), lp.configfile, realm))
+
+ dnsdomain = dnsdomain.lower()
+
+ if serverrole == "domain controller":
+ if domain is None:
+ domain = lp.get("workgroup")
+ if domaindn is None:
+ domaindn = "DC=" + dnsdomain.replace(".", ",DC=")
+ if lp.get("workgroup").upper() != domain.upper():
+ raise Exception("workgroup '%s' in smb.conf must match chosen domain '%s'",
+ lp.get("workgroup"), domain)
+ else:
+ domain = netbiosname
+ if domaindn is None:
+ domaindn = "CN=" + netbiosname
+
+ assert domain is not None
+ domain = domain.upper()
+ if not valid_netbios_name(domain):
+ raise InvalidNetbiosName(domain)
+
+ if netbiosname.upper() == realm.upper():
+ raise Exception("realm %s must not be equal to netbios domain name %s", realm, netbiosname)
+
+ if hostname.upper() == realm.upper():
+ raise Exception("realm %s must not be equal to hostname %s", realm, hostname)
+
+ if domain.upper() == realm.upper():
+ raise Exception("realm %s must not be equal to domain name %s", realm, domain)
+
+ if rootdn is None:
+ rootdn = domaindn
+
+ if configdn is None:
+ configdn = "CN=Configuration," + rootdn
+ if schemadn is None:
+ schemadn = "CN=Schema," + configdn
+ if sambadn is None:
+ sambadn = "CN=Samba"
+
+ if sitename is None:
+ sitename=DEFAULTSITE
+
+ names = ProvisionNames()
+ names.rootdn = rootdn
+ names.domaindn = domaindn
+ names.configdn = configdn
+ names.schemadn = schemadn
+ names.sambadn = sambadn
+ names.ldapmanagerdn = "CN=Manager," + rootdn
+ names.dnsdomain = dnsdomain
+ names.domain = domain
+ names.realm = realm
+ names.netbiosname = netbiosname
+ names.hostname = hostname
+ names.sitename = sitename
+ names.serverdn = "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (netbiosname, sitename, configdn)
+
+ return names
+
+
+def make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
+ targetdir):
+ """Create a new smb.conf file based on a couple of basic settings.
+ """
+ assert smbconf is not None
+ if hostname is None:
+ hostname = socket.gethostname().split(".")[0].lower()
+
+ if serverrole is None:
+ serverrole = "standalone"
+
+ assert serverrole in ("domain controller", "member server", "standalone")
+ if serverrole == "domain controller":
+ smbconfsuffix = "dc"
+ elif serverrole == "member server":
+ smbconfsuffix = "member"
+ elif serverrole == "standalone":
+ smbconfsuffix = "standalone"
+
+ assert domain is not None
+ assert realm is not None
+
+ default_lp = param.LoadParm()
+ #Load non-existant file
+ if os.path.exists(smbconf):
+ default_lp.load(smbconf)
+
+ if targetdir is not None:
+ privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private"))
+ lockdir_line = "lock dir = " + os.path.abspath(targetdir)
+
+ default_lp.set("lock dir", os.path.abspath(targetdir))
+ else:
+ privatedir_line = ""
+ lockdir_line = ""
+
+ sysvol = os.path.join(default_lp.get("lock dir"), "sysvol")
+ netlogon = os.path.join(sysvol, realm.lower(), "scripts")
+
+ setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix),
+ smbconf, {
+ "HOSTNAME": hostname,
+ "DOMAIN": domain,
+ "REALM": realm,
+ "SERVERROLE": serverrole,
+ "NETLOGONPATH": netlogon,
+ "SYSVOLPATH": sysvol,
+ "PRIVATEDIR_LINE": privatedir_line,
+ "LOCKDIR_LINE": lockdir_line
+ })
+
+
+def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid,
+ users_gid, wheel_gid):
+ """setup reasonable name mappings for sam names to unix names.
+
+ :param samdb: SamDB object.
+ :param idmap: IDmap db object.
+ :param sid: The domain sid.
+ :param domaindn: The domain DN.
+ :param root_uid: uid of the UNIX root user.
+ :param nobody_uid: uid of the UNIX nobody user.
+ :param users_gid: gid of the UNIX users group.
+ :param wheel_gid: gid of the UNIX wheel group."""
+
+ idmap.setup_name_mapping("S-1-5-7", idmap.TYPE_UID, nobody_uid)
+ idmap.setup_name_mapping("S-1-5-32-544", idmap.TYPE_GID, wheel_gid)
+
+ idmap.setup_name_mapping(sid + "-500", idmap.TYPE_UID, root_uid)
+ idmap.setup_name_mapping(sid + "-513", idmap.TYPE_GID, users_gid)
+
+def setup_samdb_partitions(samdb_path, setup_path, message, lp, session_info,
+ credentials, names,
+ serverrole, ldap_backend=None,
+ erase=False):
+ """Setup the partitions for the SAM database.
+
+ Alternatively, provision() may call this, and then populate the database.
+
+ :note: This will wipe the Sam Database!
+
+ :note: This function always removes the local SAM LDB file. The erase
+ parameter controls whether to erase the existing data, which
+ may not be stored locally but in LDAP.
+ """
+ assert session_info is not None
+
+ # We use options=["modules:"] to stop the modules loading - we
+ # just want to wipe and re-initialise the database, not start it up
+
+ try:
+ samdb = Ldb(url=samdb_path, session_info=session_info,
+ credentials=credentials, lp=lp, options=["modules:"])
+ # Wipes the database
+ samdb.erase_except_schema_controlled()
+ except LdbError:
+ os.unlink(samdb_path)
+ samdb = Ldb(url=samdb_path, session_info=session_info,
+ credentials=credentials, lp=lp, options=["modules:"])
+ # Wipes the database
+ samdb.erase_except_schema_controlled()
+
+
+ #Add modules to the list to activate them by default
+ #beware often order is important
+ #
+ # Some Known ordering constraints:
+ # - rootdse must be first, as it makes redirects from "" -> cn=rootdse
+ # - objectclass must be before password_hash, because password_hash checks
+ # that the objectclass is of type person (filled in by objectclass
+ # module when expanding the objectclass list)
+ # - partition must be last
+ # - each partition has its own module list then
+ modules_list = ["resolve_oids",
+ "rootdse",
+ "acl",
+ "paged_results",
+ "ranged_results",
+ "anr",
+ "server_sort",
+ "asq",
+ "extended_dn_store",
+ "extended_dn_in",
+ "rdn_name",
+ "objectclass",
+ "descriptor",
+ "samldb",
+ "password_hash",
+ "operational",
+ "kludge_acl"]
+ tdb_modules_list = [
+ "subtree_rename",
+ "subtree_delete",
+ "linked_attributes",
+ "extended_dn_out_ldb"]
+ modules_list2 = ["show_deleted",
+ "partition"]
+
+ domaindn_ldb = "users.ldb"
+ configdn_ldb = "configuration.ldb"
+ schemadn_ldb = "schema.ldb"
+ if ldap_backend is not None:
+ domaindn_ldb = ldap_backend.ldapi_uri
+ configdn_ldb = ldap_backend.ldapi_uri
+ schemadn_ldb = ldap_backend.ldapi_uri
+
+ if ldap_backend.ldap_backend_type == "fedora-ds":
+ backend_modules = ["nsuniqueid", "paged_searches"]
+ # We can handle linked attributes here, as we don't have directory-side subtree operations
+ tdb_modules_list = ["linked_attributes", "extended_dn_out_dereference"]
+ elif ldap_backend.ldap_backend_type == "openldap":
+ backend_modules = ["entryuuid", "paged_searches"]
+ # OpenLDAP handles subtree renames, so we don't want to do any of these things
+ tdb_modules_list = ["extended_dn_out_dereference"]
+
+ elif serverrole == "domain controller":
+ tdb_modules_list.insert(0, "repl_meta_data")
+ backend_modules = []
+ else:
+ backend_modules = ["objectguid"]
+
+ if tdb_modules_list is None:
+ tdb_modules_list_as_string = ""
+ else:
+ tdb_modules_list_as_string = ","+",".join(tdb_modules_list)
+
+ samdb.transaction_start()
+ try:
+ message("Setting up sam.ldb partitions and settings")
+ setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), {
+ "SCHEMADN": names.schemadn,
+ "SCHEMADN_LDB": schemadn_ldb,
+ "SCHEMADN_MOD2": ",objectguid",
+ "CONFIGDN": names.configdn,
+ "CONFIGDN_LDB": configdn_ldb,
+ "DOMAINDN": names.domaindn,
+ "DOMAINDN_LDB": domaindn_ldb,
+ "SCHEMADN_MOD": "schema_fsmo,instancetype",
+ "CONFIGDN_MOD": "naming_fsmo,instancetype",
+ "DOMAINDN_MOD": "pdc_fsmo,instancetype",
+ "MODULES_LIST": ",".join(modules_list),
+ "TDB_MODULES_LIST": tdb_modules_list_as_string,
+ "MODULES_LIST2": ",".join(modules_list2),
+ "BACKEND_MOD": ",".join(backend_modules),
+ })
+
+ samdb.load_ldif_file_add(setup_path("provision_init.ldif"))
+
+ message("Setting up sam.ldb rootDSE")
+ setup_samdb_rootdse(samdb, setup_path, names)
+
+ except:
+ samdb.transaction_cancel()
+ raise
+
+ samdb.transaction_commit()
+
+def secretsdb_self_join(secretsdb, domain,
+ netbiosname, domainsid, machinepass,
+ realm=None, dnsdomain=None,
+ keytab_path=None,
+ key_version_number=1,
+ secure_channel_type=SEC_CHAN_WKSTA):
+ """Add domain join-specific bits to a secrets database.
+
+ :param secretsdb: Ldb Handle to the secrets database
+ :param machinepass: Machine password
+ """
+ attrs=["whenChanged",
+ "secret",
+ "priorSecret",
+ "priorChanged",
+ "krb5Keytab",
+ "privateKeytab"]
+
+
+ msg = ldb.Message(ldb.Dn(secretsdb, "flatname=%s,cn=Primary Domains" % domain));
+ msg["secureChannelType"] = str(secure_channel_type)
+ msg["flatname"] = [domain]
+ msg["objectClass"] = ["top", "primaryDomain"]
+ if realm is not None:
+ if dnsdomain is None:
+ dnsdomain = realm.lower()
+ msg["objectClass"] = ["top", "primaryDomain", "kerberosSecret"]
+ msg["realm"] = realm
+ msg["saltPrincipal"] = "host/%s.%s@%s" % (netbiosname.lower(), dnsdomain.lower(), realm.upper())
+ msg["msDS-KeyVersionNumber"] = [str(key_version_number)]
+ msg["privateKeytab"] = ["secrets.keytab"];
+
+
+ msg["secret"] = [machinepass]
+ msg["samAccountName"] = ["%s$" % netbiosname]
+ msg["secureChannelType"] = [str(secure_channel_type)]
+ msg["objectSid"] = [ndr_pack(domainsid)]
+
+ res = secretsdb.search(base="cn=Primary Domains",
+ attrs=attrs,
+ expression=("(&(|(flatname=%s)(realm=%s)(objectSid=%s))(objectclass=primaryDomain))" % (domain, realm, str(domainsid))),
+ scope=SCOPE_ONELEVEL)
+
+ for del_msg in res:
+ if del_msg.dn is not msg.dn:
+ secretsdb.delete(del_msg.dn)
+
+ res = secretsdb.search(base=msg.dn, attrs=attrs, scope=SCOPE_BASE)
+
+ if len(res) == 1:
+ msg["priorSecret"] = res[0]["secret"]
+ msg["priorWhenChanged"] = res[0]["whenChanged"]
+
+ if res["privateKeytab"] is not None:
+ msg["privateKeytab"] = res[0]["privateKeytab"]
+
+ if res["krb5Keytab"] is not None:
+ msg["krb5Keytab"] = res[0]["krb5Keytab"]
+
+ for el in msg:
+ el.set_flags(ldb.FLAG_MOD_REPLACE)
+ secretsdb.modify(msg)
+ else:
+ secretsdb.add(msg)
+
+
+def secretsdb_setup_dns(secretsdb, setup_path, realm, dnsdomain,
+ dns_keytab_path, dnspass):
+ """Add DNS specific bits to a secrets database.
+
+ :param secretsdb: Ldb Handle to the secrets database
+ :param setup_path: Setup path function
+ :param machinepass: Machine password
+ """
+ setup_ldb(secretsdb, setup_path("secrets_dns.ldif"), {
+ "REALM": realm,
+ "DNSDOMAIN": dnsdomain,
+ "DNS_KEYTAB": dns_keytab_path,
+ "DNSPASS_B64": b64encode(dnspass),
+ })
+
+
+def setup_secretsdb(path, setup_path, session_info, credentials, lp):
+ """Setup the secrets database.
+
+ :param path: Path to the secrets database.
+ :param setup_path: Get the path to a setup file.
+ :param session_info: Session info.
+ :param credentials: Credentials
+ :param lp: Loadparm context
+ :return: LDB handle for the created secrets database
+ """
+ if os.path.exists(path):
+ os.unlink(path)
+ secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
+ lp=lp)
+ secrets_ldb.erase()
+ secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif"))
+ secrets_ldb = Ldb(path, session_info=session_info, credentials=credentials,
+ lp=lp)
+ secrets_ldb.transaction_start()
+ secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
+
+ if credentials is not None and credentials.authentication_requested():
+ if credentials.get_bind_dn() is not None:
+ setup_add_ldif(secrets_ldb, setup_path("secrets_simple_ldap.ldif"), {
+ "LDAPMANAGERDN": credentials.get_bind_dn(),
+ "LDAPMANAGERPASS_B64": b64encode(credentials.get_password())
+ })
+ else:
+ setup_add_ldif(secrets_ldb, setup_path("secrets_sasl_ldap.ldif"), {
+ "LDAPADMINUSER": credentials.get_username(),
+ "LDAPADMINREALM": credentials.get_realm(),
+ "LDAPADMINPASS_B64": b64encode(credentials.get_password())
+ })
+
+ return secrets_ldb
+
+def setup_registry(path, setup_path, session_info, lp):
+ """Setup the registry.
+
+ :param path: Path to the registry database
+ :param setup_path: Function that returns the path to a setup.
+ :param session_info: Session information
+ :param credentials: Credentials
+ :param lp: Loadparm context
+ """
+ reg = registry.Registry()
+ hive = registry.open_ldb(path, session_info=session_info,
+ lp_ctx=lp)
+ reg.mount_hive(hive, registry.HKEY_LOCAL_MACHINE)
+ provision_reg = setup_path("provision.reg")
+ assert os.path.exists(provision_reg)
+ reg.diff_apply(provision_reg)
+
+
+def setup_idmapdb(path, setup_path, session_info, lp):
+ """Setup the idmap database.
+
+ :param path: path to the idmap database
+ :param setup_path: Function that returns a path to a setup file
+ :param session_info: Session information
+ :param credentials: Credentials
+ :param lp: Loadparm context
+ """
+ if os.path.exists(path):
+ os.unlink(path)
+
+ idmap_ldb = IDmapDB(path, session_info=session_info,
+ lp=lp)
+
+ idmap_ldb.erase()
+ idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif"))
+ return idmap_ldb
+
+
+def setup_samdb_rootdse(samdb, setup_path, names):
+ """Setup the SamDB rootdse.
+
+ :param samdb: Sam Database handle
+ :param setup_path: Obtain setup path
+ """
+ setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), {
+ "SCHEMADN": names.schemadn,
+ "NETBIOSNAME": names.netbiosname,
+ "DNSDOMAIN": names.dnsdomain,
+ "REALM": names.realm,
+ "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
+ "DOMAINDN": names.domaindn,
+ "ROOTDN": names.rootdn,
+ "CONFIGDN": names.configdn,
+ "SERVERDN": names.serverdn,
+ })
+
+
+def setup_self_join(samdb, names,
+ machinepass, dnspass,
+ domainsid, invocationid, setup_path,
+ policyguid, policyguid_dc, domainControllerFunctionality):
+ """Join a host to its own domain."""
+ assert isinstance(invocationid, str)
+ setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), {
+ "CONFIGDN": names.configdn,
+ "SCHEMADN": names.schemadn,
+ "DOMAINDN": names.domaindn,
+ "SERVERDN": names.serverdn,
+ "INVOCATIONID": invocationid,
+ "NETBIOSNAME": names.netbiosname,
+ "DEFAULTSITE": names.sitename,
+ "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
+ "MACHINEPASS_B64": b64encode(machinepass),
+ "DNSPASS_B64": b64encode(dnspass),
+ "REALM": names.realm,
+ "DOMAIN": names.domain,
+ "DNSDOMAIN": names.dnsdomain,
+ "SAMBA_VERSION_STRING": version,
+ "DOMAIN_CONTROLLER_FUNCTIONALITY": str(domainControllerFunctionality)})
+
+ setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), {
+ "POLICYGUID": policyguid,
+ "POLICYGUID_DC": policyguid_dc,
+ "DNSDOMAIN": names.dnsdomain,
+ "DOMAINSID": str(domainsid),
+ "DOMAINDN": names.domaindn})
+
+ # add the NTDSGUID based SPNs
+ ntds_dn = "CN=NTDS Settings,CN=%s,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,%s" % (names.hostname, names.domaindn)
+ names.ntdsguid = samdb.searchone(basedn=ntds_dn, attribute="objectGUID",
+ expression="", scope=SCOPE_BASE)
+ assert isinstance(names.ntdsguid, str)
+
+ # Setup fSMORoleOwner entries to point at the newly created DC entry
+ setup_modify_ldif(samdb, setup_path("provision_self_join_modify.ldif"), {
+ "DOMAIN": names.domain,
+ "DNSDOMAIN": names.dnsdomain,
+ "DOMAINDN": names.domaindn,
+ "CONFIGDN": names.configdn,
+ "SCHEMADN": names.schemadn,
+ "DEFAULTSITE": names.sitename,
+ "SERVERDN": names.serverdn,
+ "NETBIOSNAME": names.netbiosname,
+ "NTDSGUID": names.ntdsguid
+ })
+
+
+def setup_samdb(path, setup_path, session_info, credentials, lp,
+ names, message,
+ domainsid, domainguid, policyguid, policyguid_dc,
+ fill, adminpass, krbtgtpass,
+ machinepass, invocationid, dnspass,
+ serverrole, schema=None, ldap_backend=None):
+ """Setup a complete SAM Database.
+
+ :note: This will wipe the main SAM database file!
+ """
+
+ # Do NOT change these default values without discussion with the team and reslease manager.
+ domainFunctionality = DS_DOMAIN_FUNCTION_2008
+ forestFunctionality = DS_DOMAIN_FUNCTION_2008
+ domainControllerFunctionality = DS_DC_FUNCTION_2008
+
+ # Also wipes the database
+ setup_samdb_partitions(path, setup_path, message=message, lp=lp,
+ credentials=credentials, session_info=session_info,
+ names=names,
+ ldap_backend=ldap_backend, serverrole=serverrole)
+
+ if (schema == None):
+ schema = Schema(setup_path, domainsid, schemadn=names.schemadn, serverdn=names.serverdn,
+ sambadn=names.sambadn, ldap_backend_type=ldap_backend.ldap_backend_type)
+
+ # Load the database, but importantly, use Ldb not SamDB as we don't want to load the global schema
+ samdb = Ldb(session_info=session_info,
+ credentials=credentials, lp=lp)
+
+ message("Pre-loading the Samba 4 and AD schema")
+
+ # Load the schema from the one we computed earlier
+ samdb.set_schema_from_ldb(schema.ldb)
+
+ # And now we can connect to the DB - the schema won't be loaded from the DB
+ samdb.connect(path)
+
+ # Load @OPTIONS
+ samdb.load_ldif_file_add(setup_path("provision_options.ldif"))
+
+ if fill == FILL_DRS:
+ return samdb
+
+ samdb.transaction_start()
+ try:
+ message("Erasing data from partitions")
+ # Load the schema (again). This time it will force a reindex,
+ # and will therefore make the erase_partitions() below
+ # computationally sane
+ samdb.set_schema_from_ldb(schema.ldb)
+ samdb.erase_partitions()
+
+ # Set the domain functionality levels onto the database.
+ # Various module (the password_hash module in particular) need
+ # to know what level of AD we are emulating.
+
+ # These will be fixed into the database via the database
+ # modifictions below, but we need them set from the start.
+ samdb.set_opaque_integer("domainFunctionality", domainFunctionality)
+ samdb.set_opaque_integer("forestFunctionality", forestFunctionality)
+ samdb.set_opaque_integer("domainControllerFunctionality", domainControllerFunctionality)
+
+ samdb.set_domain_sid(str(domainsid))
+ if serverrole == "domain controller":
+ samdb.set_invocation_id(invocationid)
+
+ message("Adding DomainDN: %s" % names.domaindn)
+ if serverrole == "domain controller":
+ domain_oc = "domainDNS"
+ else:
+ domain_oc = "samba4LocalDomain"
+
+#impersonate domain admin
+ admin_session_info = admin_session(lp, str(domainsid))
+ samdb.set_session_info(admin_session_info)
+
+ setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), {
+ "DOMAINDN": names.domaindn,
+ "DOMAIN_OC": domain_oc
+ })
+
+ message("Modifying DomainDN: " + names.domaindn + "")
+ if domainguid is not None:
+ domainguid_mod = "replace: objectGUID\nobjectGUID: %s\n-" % domainguid
+ else:
+ domainguid_mod = ""
+
+ setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), {
+ "CREATTIME": str(int(time.time()) * 1e7), # seconds -> ticks
+ "DOMAINSID": str(domainsid),
+ "SCHEMADN": names.schemadn,
+ "NETBIOSNAME": names.netbiosname,
+ "DEFAULTSITE": names.sitename,
+ "CONFIGDN": names.configdn,
+ "SERVERDN": names.serverdn,
+ "POLICYGUID": policyguid,
+ "DOMAINDN": names.domaindn,
+ "DOMAINGUID_MOD": domainguid_mod,
+ "DOMAIN_FUNCTIONALITY": str(domainFunctionality),
+ "SAMBA_VERSION_STRING": version
+ })
+
+ message("Adding configuration container")
+ descr = get_config_descriptor(domainsid);
+ setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), {
+ "CONFIGDN": names.configdn,
+ "DESCRIPTOR": descr,
+ })
+ message("Modifying configuration container")
+ setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), {
+ "CONFIGDN": names.configdn,
+ "SCHEMADN": names.schemadn,
+ })
+
+ # The LDIF here was created when the Schema object was constructed
+ message("Setting up sam.ldb schema")
+ samdb.add_ldif(schema.schema_dn_add)
+ samdb.modify_ldif(schema.schema_dn_modify)
+ samdb.write_prefixes_from_schema()
+ samdb.add_ldif(schema.schema_data)
+ setup_add_ldif(samdb, setup_path("aggregate_schema.ldif"),
+ {"SCHEMADN": names.schemadn})
+
+ message("Setting up sam.ldb configuration data")
+ setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
+ "CONFIGDN": names.configdn,
+ "NETBIOSNAME": names.netbiosname,
+ "DEFAULTSITE": names.sitename,
+ "DNSDOMAIN": names.dnsdomain,
+ "DOMAIN": names.domain,
+ "SCHEMADN": names.schemadn,
+ "DOMAINDN": names.domaindn,
+ "SERVERDN": names.serverdn,
+ "FOREST_FUNCTIONALALITY": str(forestFunctionality)
+ })
+
+ message("Setting up display specifiers")
+ display_specifiers_ldif = read_ms_ldif(setup_path('display-specifiers/DisplaySpecifiers-Win2k8R2.txt'))
+ display_specifiers_ldif = substitute_var(display_specifiers_ldif, {"CONFIGDN": names.configdn})
+ check_all_substituted(display_specifiers_ldif)
+ samdb.add_ldif(display_specifiers_ldif)
+
+ message("Adding users container")
+ setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), {
+ "DOMAINDN": names.domaindn})
+ message("Modifying users container")
+ setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), {
+ "DOMAINDN": names.domaindn})
+ message("Adding computers container")
+ setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), {
+ "DOMAINDN": names.domaindn})
+ message("Modifying computers container")
+ setup_modify_ldif(samdb, setup_path("provision_computers_modify.ldif"), {
+ "DOMAINDN": names.domaindn})
+ message("Setting up sam.ldb data")
+ setup_add_ldif(samdb, setup_path("provision.ldif"), {
+ "CREATTIME": str(int(time.time()) * 1e7), # seconds -> ticks
+ "DOMAINDN": names.domaindn,
+ "NETBIOSNAME": names.netbiosname,
+ "DEFAULTSITE": names.sitename,
+ "CONFIGDN": names.configdn,
+ "SERVERDN": names.serverdn,
+ "POLICYGUID_DC": policyguid_dc
+ })
+
+ if fill == FILL_FULL:
+ message("Setting up sam.ldb users and groups")
+ setup_add_ldif(samdb, setup_path("provision_users.ldif"), {
+ "DOMAINDN": names.domaindn,
+ "DOMAINSID": str(domainsid),
+ "CONFIGDN": names.configdn,
+ "ADMINPASS_B64": b64encode(adminpass),
+ "KRBTGTPASS_B64": b64encode(krbtgtpass),
+ })
+
+ if serverrole == "domain controller":
+ message("Setting up self join")
+ setup_self_join(samdb, names=names, invocationid=invocationid,
+ dnspass=dnspass,
+ machinepass=machinepass,
+ domainsid=domainsid, policyguid=policyguid,
+ policyguid_dc=policyguid_dc,
+ setup_path=setup_path,
+ domainControllerFunctionality=domainControllerFunctionality)
+
+ ntds_dn = "CN=NTDS Settings,CN=%s,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,%s" % (names.hostname, names.domaindn)
+ names.ntdsguid = samdb.searchone(basedn=ntds_dn,
+ attribute="objectGUID", expression="", scope=SCOPE_BASE)
+ assert isinstance(names.ntdsguid, str)
+
+ except:
+ samdb.transaction_cancel()
+ raise
+
+ samdb.transaction_commit()
+ return samdb
+
+
+FILL_FULL = "FULL"
+FILL_NT4SYNC = "NT4SYNC"
+FILL_DRS = "DRS"
+
+
+def provision(setup_dir, message, session_info,
+ credentials, smbconf=None, targetdir=None, samdb_fill=FILL_FULL,
+ realm=None,
+ rootdn=None, domaindn=None, schemadn=None, configdn=None,
+ serverdn=None,
+ domain=None, hostname=None, hostip=None, hostip6=None,
+ domainsid=None, adminpass=None, ldapadminpass=None,
+ krbtgtpass=None, domainguid=None,
+ policyguid=None, policyguid_dc=None, invocationid=None,
+ machinepass=None,
+ dnspass=None, root=None, nobody=None, users=None,
+ wheel=None, backup=None, aci=None, serverrole=None,
+ ldap_backend_extra_port=None, ldap_backend_type=None,
+ sitename=None,
+ ol_mmr_urls=None, ol_olc=None,
+ setup_ds_path=None, slapd_path=None, nosync=False,
+ ldap_dryrun_mode=False):
+ """Provision samba4
+
+ :note: caution, this wipes all existing data!
+ """
+
+ def setup_path(file):
+ return os.path.join(setup_dir, file)
+
+ if domainsid is None:
+ domainsid = security.random_sid()
+ else:
+ domainsid = security.dom_sid(domainsid)
+
+
+ # create/adapt the group policy GUIDs
+ if policyguid is None:
+ policyguid = str(uuid.uuid4())
+ policyguid = policyguid.upper()
+ if policyguid_dc is None:
+ policyguid_dc = str(uuid.uuid4())
+ policyguid_dc = policyguid_dc.upper()
+
+ if adminpass is None:
+ adminpass = glue.generate_random_str(12)
+ if krbtgtpass is None:
+ krbtgtpass = glue.generate_random_str(12)
+ if machinepass is None:
+ machinepass = glue.generate_random_str(12)
+ if dnspass is None:
+ dnspass = glue.generate_random_str(12)
+ if ldapadminpass is None:
+ #Make a new, random password between Samba and it's LDAP server
+ ldapadminpass=glue.generate_random_str(12)
+
+
+ root_uid = findnss_uid([root or "root"])
+ nobody_uid = findnss_uid([nobody or "nobody"])
+ users_gid = findnss_gid([users or "users"])
+ if wheel is None:
+ wheel_gid = findnss_gid(["wheel", "adm"])
+ else:
+ wheel_gid = findnss_gid([wheel])
+
+ if targetdir is not None:
+ if (not os.path.exists(os.path.join(targetdir, "etc"))):
+ os.makedirs(os.path.join(targetdir, "etc"))
+ smbconf = os.path.join(targetdir, "etc", "smb.conf")
+ elif smbconf is None:
+ smbconf = param.default_path()
+
+ # only install a new smb.conf if there isn't one there already
+ if not os.path.exists(smbconf):
+ make_smbconf(smbconf, setup_path, hostname, domain, realm, serverrole,
+ targetdir)
+
+ lp = param.LoadParm()
+ lp.load(smbconf)
+
+ names = guess_names(lp=lp, hostname=hostname, domain=domain,
+ dnsdomain=realm, serverrole=serverrole, sitename=sitename,
+ rootdn=rootdn, domaindn=domaindn, configdn=configdn, schemadn=schemadn,
+ serverdn=serverdn)
+
+ paths = provision_paths_from_lp(lp, names.dnsdomain)
+
+ if hostip is None:
+ try:
+ hostip = socket.getaddrinfo(names.hostname, None, socket.AF_INET, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
+ except socket.gaierror, (socket.EAI_NODATA, msg):
+ hostip = None
+
+ if hostip6 is None:
+ try:
+ hostip6 = socket.getaddrinfo(names.hostname, None, socket.AF_INET6, socket.AI_CANONNAME, socket.IPPROTO_IP)[0][-1][0]
+ except socket.gaierror, (socket.EAI_NODATA, msg):
+ hostip6 = None
+
+ if serverrole is None:
+ serverrole = lp.get("server role")
+
+ assert serverrole in ("domain controller", "member server", "standalone")
+ if invocationid is None and serverrole == "domain controller":
+ invocationid = str(uuid.uuid4())
+
+ if not os.path.exists(paths.private_dir):
+ os.mkdir(paths.private_dir)
+
+ ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="")
+
+ schema = Schema(setup_path, domainsid, schemadn=names.schemadn, serverdn=names.serverdn,
+ sambadn=names.sambadn, ldap_backend_type=ldap_backend_type)
+
+ secrets_credentials = credentials
+ provision_backend = None
+ if ldap_backend_type:
+ # We only support an LDAP backend over ldapi://
+
+ provision_backend = ProvisionBackend(paths=paths, setup_path=setup_path,
+ lp=lp, credentials=credentials,
+ names=names,
+ message=message, hostname=hostname,
+ root=root, schema=schema,
+ ldap_backend_type=ldap_backend_type,
+ ldapadminpass=ldapadminpass,
+ ldap_backend_extra_port=ldap_backend_extra_port,
+ ol_mmr_urls=ol_mmr_urls,
+ slapd_path=slapd_path,
+ setup_ds_path=setup_ds_path,
+ ldap_dryrun_mode=ldap_dryrun_mode)
+
+ # Now use the backend credentials to access the databases
+ credentials = provision_backend.credentials
+ secrets_credentials = provision_backend.adminCredentials
+ ldapi_url = provision_backend.ldapi_uri
+
+ # only install a new shares config db if there is none
+ if not os.path.exists(paths.shareconf):
+ message("Setting up share.ldb")
+ share_ldb = Ldb(paths.shareconf, session_info=session_info,
+ credentials=credentials, lp=lp)
+ share_ldb.load_ldif_file_add(setup_path("share.ldif"))
+
+
+ message("Setting up secrets.ldb")
+ secrets_ldb = setup_secretsdb(paths.secrets, setup_path,
+ session_info=session_info,
+ credentials=secrets_credentials, lp=lp)
+
+ message("Setting up the registry")
+ setup_registry(paths.hklm, setup_path, session_info,
+ lp=lp)
+
+ message("Setting up idmap db")
+ idmap = setup_idmapdb(paths.idmapdb, setup_path, session_info=session_info,
+ lp=lp)
+
+ message("Setting up SAM db")
+ samdb = setup_samdb(paths.samdb, setup_path, session_info=session_info,
+ credentials=credentials, lp=lp, names=names,
+ message=message,
+ domainsid=domainsid,
+ schema=schema, domainguid=domainguid,
+ policyguid=policyguid, policyguid_dc=policyguid_dc,
+ fill=samdb_fill,
+ adminpass=adminpass, krbtgtpass=krbtgtpass,
+ invocationid=invocationid,
+ machinepass=machinepass, dnspass=dnspass,
+ serverrole=serverrole, ldap_backend=provision_backend)
+
+ if serverrole == "domain controller":
+ if paths.netlogon is None:
+ message("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.")
+ message("Please either remove %s or see the template at %s" %
+ ( paths.smbconf, setup_path("provision.smb.conf.dc")))
+ assert(paths.netlogon is not None)
+
+ if paths.sysvol is None:
+ message("Existing smb.conf does not have a [sysvol] share, but you are configuring a DC.")
+ message("Please either remove %s or see the template at %s" %
+ (paths.smbconf, setup_path("provision.smb.conf.dc")))
+ assert(paths.sysvol is not None)
+
+ # Set up group policies (domain policy and domain controller policy)
+
+ policy_path = os.path.join(paths.sysvol, names.dnsdomain, "Policies",
+ "{" + policyguid + "}")
+ os.makedirs(policy_path, 0755)
+ open(os.path.join(policy_path, "GPT.INI"), 'w').write(
+ "[General]\r\nVersion=65543")
+ os.makedirs(os.path.join(policy_path, "MACHINE"), 0755)
+ os.makedirs(os.path.join(policy_path, "USER"), 0755)
+
+ policy_path_dc = os.path.join(paths.sysvol, names.dnsdomain, "Policies",
+ "{" + policyguid_dc + "}")
+ os.makedirs(policy_path_dc, 0755)
+ open(os.path.join(policy_path_dc, "GPT.INI"), 'w').write(
+ "[General]\r\nVersion=2")
+ os.makedirs(os.path.join(policy_path_dc, "MACHINE"), 0755)
+ os.makedirs(os.path.join(policy_path_dc, "USER"), 0755)
+
+ if not os.path.isdir(paths.netlogon):
+ os.makedirs(paths.netlogon, 0755)
+
+ if samdb_fill == FILL_FULL:
+ setup_name_mappings(samdb, idmap, str(domainsid), names.domaindn,
+ root_uid=root_uid, nobody_uid=nobody_uid,
+ users_gid=users_gid, wheel_gid=wheel_gid)
+
+ message("Setting up sam.ldb rootDSE marking as synchronized")
+ setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"))
+
+ # Only make a zone file on the first DC, it should be replicated with DNS replication
+ if serverrole == "domain controller":
+ secretsdb_self_join(secrets_ldb, domain=domain,
+ realm=names.realm,
+ dnsdomain=names.dnsdomain,
+ netbiosname=names.netbiosname,
+ domainsid=domainsid,
+ machinepass=machinepass,
+ secure_channel_type=SEC_CHAN_BDC)
+
+ secretsdb_setup_dns(secrets_ldb, setup_path,
+ realm=names.realm, dnsdomain=names.dnsdomain,
+ dns_keytab_path=paths.dns_keytab,
+ dnspass=dnspass)
+
+ domainguid = samdb.searchone(basedn=domaindn, attribute="objectGUID")
+ assert isinstance(domainguid, str)
+
+ create_zone_file(paths.dns, setup_path, dnsdomain=names.dnsdomain,
+ domaindn=names.domaindn, hostip=hostip,
+ hostip6=hostip6, hostname=names.hostname,
+ dnspass=dnspass, realm=names.realm,
+ domainguid=domainguid, ntdsguid=names.ntdsguid)
+
+ create_named_conf(paths.namedconf, setup_path, realm=names.realm,
+ dnsdomain=names.dnsdomain, private_dir=paths.private_dir)
+
+ create_named_txt(paths.namedtxt, setup_path, realm=names.realm,
+ dnsdomain=names.dnsdomain, private_dir=paths.private_dir,
+ keytab_name=paths.dns_keytab)
+ message("See %s for an example configuration include file for BIND" % paths.namedconf)
+ message("and %s for further documentation required for secure DNS updates" % paths.namedtxt)
+
+ create_krb5_conf(paths.krb5conf, setup_path,
+ dnsdomain=names.dnsdomain, hostname=names.hostname,
+ realm=names.realm)
+ message("A Kerberos configuration suitable for Samba 4 has been generated at %s" % paths.krb5conf)
+
+ #Now commit the secrets.ldb to disk
+ secrets_ldb.transaction_commit()
+
+ if provision_backend is not None:
+ if ldap_backend_type == "fedora-ds":
+ ldapi_db = Ldb(provision_backend.ldapi_uri, lp=lp, credentials=credentials)
+
+ # delete default SASL mappings
+ res = ldapi_db.search(expression="(!(cn=samba-admin mapping))", base="cn=mapping,cn=sasl,cn=config", scope=SCOPE_ONELEVEL, attrs=["dn"])
+
+ # configure in-directory access control on Fedora DS via the aci attribute (over a direct ldapi:// socket)
+ for i in range (0, len(res)):
+ dn = str(res[i]["dn"])
+ ldapi_db.delete(dn)
+
+ aci = """(targetattr = "*") (version 3.0;acl "full access to all by samba-admin";allow (all)(userdn = "ldap:///CN=samba-admin,%s");)""" % names.sambadn
+
+ m = ldb.Message()
+ m["aci"] = ldb.MessageElement([aci], ldb.FLAG_MOD_REPLACE, "aci")
+
+ m.dn = ldb.Dn(1, names.domaindn)
+ ldapi_db.modify(m)
+
+ m.dn = ldb.Dn(1, names.configdn)
+ ldapi_db.modify(m)
+
+ m.dn = ldb.Dn(1, names.schemadn)
+ ldapi_db.modify(m)
+
+ # if an LDAP backend is in use, terminate slapd after final provision and check its proper termination
+ if provision_backend.slapd.poll() is None:
+ #Kill the slapd
+ if hasattr(provision_backend.slapd, "terminate"):
+ provision_backend.slapd.terminate()
+ else:
+ # Older python versions don't have .terminate()
+ import signal
+ os.kill(provision_backend.slapd.pid, signal.SIGTERM)
+
+ #and now wait for it to die
+ provision_backend.slapd.communicate()
+
+ # now display slapd_command_file.txt to show how slapd must be started next time
+ message("Use later the following commandline to start slapd, then Samba:")
+ slapd_command = "\'" + "\' \'".join(provision_backend.slapd_command) + "\'"
+ message(slapd_command)
+ message("This slapd-Commandline is also stored under: " + paths.ldapdir + "/ldap_backend_startup.sh")
+
+ setup_file(setup_path("ldap_backend_startup.sh"), paths.ldapdir + "/ldap_backend_startup.sh", {
+ "SLAPD_COMMAND" : slapd_command})
+
+
+ create_phpldapadmin_config(paths.phpldapadminconfig, setup_path,
+ ldapi_url)
+
+ message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig)
+
+ message("Once the above files are installed, your Samba4 server will be ready to use")
+ message("Server Role: %s" % serverrole)
+ message("Hostname: %s" % names.hostname)
+ message("NetBIOS Domain: %s" % names.domain)
+ message("DNS Domain: %s" % names.dnsdomain)
+ message("DOMAIN SID: %s" % str(domainsid))
+ if samdb_fill == FILL_FULL:
+ message("Admin password: %s" % adminpass)
+ if provision_backend:
+ if provision_backend.credentials.get_bind_dn() is not None:
+ message("LDAP Backend Admin DN: %s" % provision_backend.credentials.get_bind_dn())
+ else:
+ message("LDAP Admin User: %s" % provision_backend.credentials.get_username())
+
+ message("LDAP Admin Password: %s" % provision_backend.credentials.get_password())
+
+ result = ProvisionResult()
+ result.domaindn = domaindn
+ result.paths = paths
+ result.lp = lp
+ result.samdb = samdb
+ return result
+
+
+
+def provision_become_dc(setup_dir=None,
+ smbconf=None, targetdir=None, realm=None,
+ rootdn=None, domaindn=None, schemadn=None,
+ configdn=None, serverdn=None,
+ domain=None, hostname=None, domainsid=None,
+ adminpass=None, krbtgtpass=None, domainguid=None,
+ policyguid=None, policyguid_dc=None, invocationid=None,
+ machinepass=None,
+ dnspass=None, root=None, nobody=None, users=None,
+ wheel=None, backup=None, serverrole=None,
+ ldap_backend=None, ldap_backend_type=None,
+ sitename=None, debuglevel=1):
+
+ def message(text):
+ """print a message if quiet is not set."""
+ print text
+
+ glue.set_debug_level(debuglevel)
+
+ return provision(setup_dir, message, system_session(), None,
+ smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS,
+ realm=realm, rootdn=rootdn, domaindn=domaindn, schemadn=schemadn,
+ configdn=configdn, serverdn=serverdn, domain=domain,
+ hostname=hostname, hostip="127.0.0.1", domainsid=domainsid,
+ machinepass=machinepass, serverrole="domain controller",
+ sitename=sitename)
+
+
+def setup_db_config(setup_path, dbdir):
+ """Setup a Berkeley database.
+
+ :param setup_path: Setup path function.
+ :param dbdir: Database directory."""
+ if not os.path.isdir(os.path.join(dbdir, "bdb-logs")):
+ os.makedirs(os.path.join(dbdir, "bdb-logs"), 0700)
+ if not os.path.isdir(os.path.join(dbdir, "tmp")):
+ os.makedirs(os.path.join(dbdir, "tmp"), 0700)
+
+ setup_file(setup_path("DB_CONFIG"), os.path.join(dbdir, "DB_CONFIG"),
+ {"LDAPDBDIR": dbdir})
+
+class ProvisionBackend(object):
+ def __init__(self, paths=None, setup_path=None, lp=None, credentials=None,
+ names=None, message=None,
+ hostname=None, root=None,
+ schema=None, ldapadminpass=None,
+ ldap_backend_type=None, ldap_backend_extra_port=None,
+ ol_mmr_urls=None,
+ setup_ds_path=None, slapd_path=None,
+ nosync=False, ldap_dryrun_mode=False):
+ """Provision an LDAP backend for samba4
+
+ This works for OpenLDAP and Fedora DS
+ """
+
+ self.ldapi_uri = "ldapi://" + urllib.quote(os.path.join(paths.ldapdir, "ldapi"), safe="")
+
+ if not os.path.isdir(paths.ldapdir):
+ os.makedirs(paths.ldapdir, 0700)
+
+ if ldap_backend_type == "existing":
+ #Check to see that this 'existing' LDAP backend in fact exists
+ ldapi_db = Ldb(self.ldapi_uri, credentials=credentials)
+ search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE,
+ expression="(objectClass=OpenLDAProotDSE)")
+
+ # If we have got here, then we must have a valid connection to the LDAP server, with valid credentials supplied
+ # This caused them to be set into the long-term database later in the script.
+ self.credentials = credentials
+ self.ldap_backend_type = "openldap" #For now, assume existing backends at least emulate OpenLDAP
+ return
+
+ # we will shortly start slapd with ldapi for final provisioning. first check with ldapsearch -> rootDSE via self.ldapi_uri
+ # if another instance of slapd is already running
+ try:
+ ldapi_db = Ldb(self.ldapi_uri)
+ search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE,
+ expression="(objectClass=OpenLDAProotDSE)");
+ try:
+ f = open(paths.slapdpid, "r")
+ p = f.read()
+ f.close()
+ message("Check for slapd Process with PID: " + str(p) + " and terminate it manually.")
+ except:
+ pass
+
+ raise ProvisioningError("Warning: Another slapd Instance seems already running on this host, listening to " + self.ldapi_uri + ". Please shut it down before you continue. ")
+
+ except LdbError, e:
+ pass
+
+ # Try to print helpful messages when the user has not specified the path to slapd
+ if slapd_path is None:
+ raise ProvisioningError("Warning: LDAP-Backend must be setup with path to slapd, e.g. --slapd-path=\"/usr/local/libexec/slapd\"!")
+ if not os.path.exists(slapd_path):
+ message (slapd_path)
+ raise ProvisioningError("Warning: Given Path to slapd does not exist!")
+
+ schemadb_path = os.path.join(paths.ldapdir, "schema-tmp.ldb")
+ try:
+ os.unlink(schemadb_path)
+ except OSError:
+ pass
+
+
+ # Put the LDIF of the schema into a database so we can search on
+ # it to generate schema-dependent configurations in Fedora DS and
+ # OpenLDAP
+ os.path.join(paths.ldapdir, "schema-tmp.ldb")
+ schema.ldb.connect(schemadb_path)
+ schema.ldb.transaction_start()
+
+ # These bits of LDIF are supplied when the Schema object is created
+ schema.ldb.add_ldif(schema.schema_dn_add)
+ schema.ldb.modify_ldif(schema.schema_dn_modify)
+ schema.ldb.add_ldif(schema.schema_data)
+ schema.ldb.transaction_commit()
+
+ self.credentials = Credentials()
+ self.credentials.guess(lp)
+ #Kerberos to an ldapi:// backend makes no sense
+ self.credentials.set_kerberos_state(DONT_USE_KERBEROS)
+
+ self.adminCredentials = Credentials()
+ self.adminCredentials.guess(lp)
+ #Kerberos to an ldapi:// backend makes no sense
+ self.adminCredentials.set_kerberos_state(DONT_USE_KERBEROS)
+
+ self.ldap_backend_type = ldap_backend_type
+
+ if ldap_backend_type == "fedora-ds":
+ provision_fds_backend(self, paths=paths, setup_path=setup_path,
+ names=names, message=message,
+ hostname=hostname,
+ ldapadminpass=ldapadminpass, root=root,
+ schema=schema,
+ ldap_backend_extra_port=ldap_backend_extra_port,
+ setup_ds_path=setup_ds_path,
+ slapd_path=slapd_path,
+ nosync=nosync,
+ ldap_dryrun_mode=ldap_dryrun_mode)
+
+ elif ldap_backend_type == "openldap":
+ provision_openldap_backend(self, paths=paths, setup_path=setup_path,
+ names=names, message=message,
+ hostname=hostname,
+ ldapadminpass=ldapadminpass, root=root,
+ schema=schema,
+ ldap_backend_extra_port=ldap_backend_extra_port,
+ ol_mmr_urls=ol_mmr_urls,
+ slapd_path=slapd_path,
+ nosync=nosync,
+ ldap_dryrun_mode=ldap_dryrun_mode)
+ else:
+ raise ProvisioningError("Unknown LDAP backend type selected")
+
+ self.credentials.set_password(ldapadminpass)
+ self.adminCredentials.set_username("samba-admin")
+ self.adminCredentials.set_password(ldapadminpass)
+
+ # Now start the slapd, so we can provision onto it. We keep the
+ # subprocess context around, to kill this off at the successful
+ # end of the script
+ self.slapd = subprocess.Popen(self.slapd_provision_command, close_fds=True, shell=False)
+
+ while self.slapd.poll() is None:
+ # Wait until the socket appears
+ try:
+ ldapi_db = Ldb(self.ldapi_uri, lp=lp, credentials=self.credentials)
+ search_ol_rootdse = ldapi_db.search(base="", scope=SCOPE_BASE,
+ expression="(objectClass=OpenLDAProotDSE)")
+ # If we have got here, then we must have a valid connection to the LDAP server!
+ return
+ except LdbError, e:
+ time.sleep(1)
+ pass
+
+ raise ProvisioningError("slapd died before we could make a connection to it")
+
+
+def provision_openldap_backend(result, paths=None, setup_path=None, names=None,
+ message=None,
+ hostname=None, ldapadminpass=None, root=None,
+ schema=None,
+ ldap_backend_extra_port=None,
+ ol_mmr_urls=None,
+ slapd_path=None, nosync=False,
+ ldap_dryrun_mode=False):
+
+ #Allow the test scripts to turn off fsync() for OpenLDAP as for TDB and LDB
+ nosync_config = ""
+ if nosync:
+ nosync_config = "dbnosync"
+
+ lnkattr = get_linked_attributes(names.schemadn,schema.ldb)
+ refint_attributes = ""
+ memberof_config = "# Generated from Samba4 schema\n"
+ for att in lnkattr.keys():
+ if lnkattr[att] is not None:
+ refint_attributes = refint_attributes + " " + att
+
+ memberof_config += read_and_sub_file(setup_path("memberof.conf"),
+ { "MEMBER_ATTR" : att ,
+ "MEMBEROF_ATTR" : lnkattr[att] })
+
+ refint_config = read_and_sub_file(setup_path("refint.conf"),
+ { "LINK_ATTRS" : refint_attributes})
+
+ attrs = ["linkID", "lDAPDisplayName"]
+ res = schema.ldb.search(expression="(&(objectclass=attributeSchema)(searchFlags:1.2.840.113556.1.4.803:=1))", base=names.schemadn, scope=SCOPE_ONELEVEL, attrs=attrs)
+ index_config = ""
+ for i in range (0, len(res)):
+ index_attr = res[i]["lDAPDisplayName"][0]
+ if index_attr == "objectGUID":
+ index_attr = "entryUUID"
+
+ index_config += "index " + index_attr + " eq\n"
+
+# generate serverids, ldap-urls and syncrepl-blocks for mmr hosts
+ mmr_on_config = ""
+ mmr_replicator_acl = ""
+ mmr_serverids_config = ""
+ mmr_syncrepl_schema_config = ""
+ mmr_syncrepl_config_config = ""
+ mmr_syncrepl_user_config = ""
+
+
+ if ol_mmr_urls is not None:
+ # For now, make these equal
+ mmr_pass = ldapadminpass
+
+ url_list=filter(None,ol_mmr_urls.split(' '))
+ if (len(url_list) == 1):
+ url_list=filter(None,ol_mmr_urls.split(','))
+
+
+ mmr_on_config = "MirrorMode On"
+ mmr_replicator_acl = " by dn=cn=replicator,cn=samba read"
+ serverid=0
+ for url in url_list:
+ serverid=serverid+1
+ mmr_serverids_config += read_and_sub_file(setup_path("mmr_serverids.conf"),
+ { "SERVERID" : str(serverid),
+ "LDAPSERVER" : url })
+ rid=serverid*10
+ rid=rid+1
+ mmr_syncrepl_schema_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
+ { "RID" : str(rid),
+ "MMRDN": names.schemadn,
+ "LDAPSERVER" : url,
+ "MMR_PASSWORD": mmr_pass})
+
+ rid=rid+1
+ mmr_syncrepl_config_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
+ { "RID" : str(rid),
+ "MMRDN": names.configdn,
+ "LDAPSERVER" : url,
+ "MMR_PASSWORD": mmr_pass})
+
+ rid=rid+1
+ mmr_syncrepl_user_config += read_and_sub_file(setup_path("mmr_syncrepl.conf"),
+ { "RID" : str(rid),
+ "MMRDN": names.domaindn,
+ "LDAPSERVER" : url,
+ "MMR_PASSWORD": mmr_pass })
+ # OpenLDAP cn=config initialisation
+ olc_syncrepl_config = ""
+ olc_mmr_config = ""
+ # if mmr = yes, generate cn=config-replication directives
+ # and olc_seed.lif for the other mmr-servers
+ if ol_mmr_urls is not None:
+ serverid=0
+ olc_serverids_config = ""
+ olc_syncrepl_seed_config = ""
+ olc_mmr_config += read_and_sub_file(setup_path("olc_mmr.conf"),{})
+ rid=1000
+ for url in url_list:
+ serverid=serverid+1
+ olc_serverids_config += read_and_sub_file(setup_path("olc_serverid.conf"),
+ { "SERVERID" : str(serverid),
+ "LDAPSERVER" : url })
+
+ rid=rid+1
+ olc_syncrepl_config += read_and_sub_file(setup_path("olc_syncrepl.conf"),
+ { "RID" : str(rid),
+ "LDAPSERVER" : url,
+ "MMR_PASSWORD": mmr_pass})
+
+ olc_syncrepl_seed_config += read_and_sub_file(setup_path("olc_syncrepl_seed.conf"),
+ { "RID" : str(rid),
+ "LDAPSERVER" : url})
+
+ setup_file(setup_path("olc_seed.ldif"), paths.olcseedldif,
+ {"OLC_SERVER_ID_CONF": olc_serverids_config,
+ "OLC_PW": ldapadminpass,
+ "OLC_SYNCREPL_CONF": olc_syncrepl_seed_config})
+ # end olc
+
+ setup_file(setup_path("slapd.conf"), paths.slapdconf,
+ {"DNSDOMAIN": names.dnsdomain,
+ "LDAPDIR": paths.ldapdir,
+ "DOMAINDN": names.domaindn,
+ "CONFIGDN": names.configdn,
+ "SCHEMADN": names.schemadn,
+ "MEMBEROF_CONFIG": memberof_config,
+ "MIRRORMODE": mmr_on_config,
+ "REPLICATOR_ACL": mmr_replicator_acl,
+ "MMR_SERVERIDS_CONFIG": mmr_serverids_config,
+ "MMR_SYNCREPL_SCHEMA_CONFIG": mmr_syncrepl_schema_config,
+ "MMR_SYNCREPL_CONFIG_CONFIG": mmr_syncrepl_config_config,
+ "MMR_SYNCREPL_USER_CONFIG": mmr_syncrepl_user_config,
+ "OLC_SYNCREPL_CONFIG": olc_syncrepl_config,
+ "OLC_MMR_CONFIG": olc_mmr_config,
+ "REFINT_CONFIG": refint_config,
+ "INDEX_CONFIG": index_config,
+ "NOSYNC": nosync_config})
+
+ setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "user"))
+ setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "config"))
+ setup_db_config(setup_path, os.path.join(paths.ldapdir, "db", "schema"))
+
+ if not os.path.exists(os.path.join(paths.ldapdir, "db", "samba", "cn=samba")):
+ os.makedirs(os.path.join(paths.ldapdir, "db", "samba", "cn=samba"), 0700)
+
+ setup_file(setup_path("cn=samba.ldif"),
+ os.path.join(paths.ldapdir, "db", "samba", "cn=samba.ldif"),
+ { "UUID": str(uuid.uuid4()),
+ "LDAPTIME": timestring(int(time.time()))} )
+ setup_file(setup_path("cn=samba-admin.ldif"),
+ os.path.join(paths.ldapdir, "db", "samba", "cn=samba", "cn=samba-admin.ldif"),
+ {"LDAPADMINPASS_B64": b64encode(ldapadminpass),
+ "UUID": str(uuid.uuid4()),
+ "LDAPTIME": timestring(int(time.time()))} )
+
+ if ol_mmr_urls is not None:
+ setup_file(setup_path("cn=replicator.ldif"),
+ os.path.join(paths.ldapdir, "db", "samba", "cn=samba", "cn=replicator.ldif"),
+ {"MMR_PASSWORD_B64": b64encode(mmr_pass),
+ "UUID": str(uuid.uuid4()),
+ "LDAPTIME": timestring(int(time.time()))} )
+
+
+ mapping = "schema-map-openldap-2.3"
+ backend_schema = "backend-schema.schema"
+
+ backend_schema_data = schema.ldb.convert_schema_to_openldap("openldap", open(setup_path(mapping), 'r').read())
+ assert backend_schema_data is not None
+ open(os.path.join(paths.ldapdir, backend_schema), 'w').write(backend_schema_data)
+
+ # now we generate the needed strings to start slapd automatically,
+ # first ldapi_uri...
+ if ldap_backend_extra_port is not None:
+ # When we use MMR, we can't use 0.0.0.0 as it uses the name
+ # specified there as part of it's clue as to it's own name,
+ # and not to replicate to itself
+ if ol_mmr_urls is None:
+ server_port_string = "ldap://0.0.0.0:%d" % ldap_backend_extra_port
+ else:
+ server_port_string = "ldap://" + names.hostname + "." + names.dnsdomain +":%d" % ldap_backend_extra_port
+ else:
+ server_port_string = ""
+
+ # Prepare the 'result' information - the commands to return in particular
+ result.slapd_provision_command = [slapd_path]
+
+ result.slapd_provision_command.append("-F" + paths.olcdir)
+
+ result.slapd_provision_command.append("-h")
+
+ # copy this command so we have two version, one with -d0 and only ldapi, and one with all the listen commands
+ result.slapd_command = list(result.slapd_provision_command)
+
+ result.slapd_provision_command.append(result.ldapi_uri)
+ result.slapd_provision_command.append("-d0")
+
+ uris = result.ldapi_uri
+ if server_port_string is not "":
+ uris = uris + " " + server_port_string
+
+ result.slapd_command.append(uris)
+
+ # Set the username - done here because Fedora DS still uses the admin DN and simple bind
+ result.credentials.set_username("samba-admin")
+
+ # If we were just looking for crashes up to this point, it's a
+ # good time to exit before we realise we don't have OpenLDAP on
+ # this system
+ if ldap_dryrun_mode:
+ sys.exit(0)
+
+ # Finally, convert the configuration into cn=config style!
+ if not os.path.isdir(paths.olcdir):
+ os.makedirs(paths.olcdir, 0770)
+
+ retcode = subprocess.call([slapd_path, "-Ttest", "-f", paths.slapdconf, "-F", paths.olcdir], close_fds=True, shell=False)
+
+# We can't do this, as OpenLDAP is strange. It gives an error
+# output to the above, but does the conversion sucessfully...
+#
+# if retcode != 0:
+# raise ProvisioningError("conversion from slapd.conf to cn=config failed")
+
+ if not os.path.exists(os.path.join(paths.olcdir, "cn=config.ldif")):
+ raise ProvisioningError("conversion from slapd.conf to cn=config failed")
+
+ # Don't confuse the admin by leaving the slapd.conf around
+ os.remove(paths.slapdconf)
+
+
+def provision_fds_backend(result, paths=None, setup_path=None, names=None,
+ message=None,
+ hostname=None, ldapadminpass=None, root=None,
+ schema=None,
+ ldap_backend_extra_port=None,
+ setup_ds_path=None,
+ slapd_path=None,
+ nosync=False,
+ ldap_dryrun_mode=False):
+
+ if ldap_backend_extra_port is not None:
+ serverport = "ServerPort=%d" % ldap_backend_extra_port
+ else:
+ serverport = ""
+
+ setup_file(setup_path("fedorads.inf"), paths.fedoradsinf,
+ {"ROOT": root,
+ "HOSTNAME": hostname,
+ "DNSDOMAIN": names.dnsdomain,
+ "LDAPDIR": paths.ldapdir,
+ "DOMAINDN": names.domaindn,
+ "LDAPMANAGERDN": names.ldapmanagerdn,
+ "LDAPMANAGERPASS": ldapadminpass,
+ "SERVERPORT": serverport})
+
+ setup_file(setup_path("fedorads-partitions.ldif"), paths.fedoradspartitions,
+ {"CONFIGDN": names.configdn,
+ "SCHEMADN": names.schemadn,
+ "SAMBADN": names.sambadn,
+ })
+
+ setup_file(setup_path("fedorads-sasl.ldif"), paths.fedoradssasl,
+ {"SAMBADN": names.sambadn,
+ })
+
+ setup_file(setup_path("fedorads-samba.ldif"), paths.fedoradssamba,
+ {"SAMBADN": names.sambadn,
+ "LDAPADMINPASS": ldapadminpass
+ })
+
+ mapping = "schema-map-fedora-ds-1.0"
+ backend_schema = "99_ad.ldif"
+
+ # Build a schema file in Fedora DS format
+ backend_schema_data = schema.ldb.convert_schema_to_openldap("fedora-ds", open(setup_path(mapping), 'r').read())
+ assert backend_schema_data is not None
+ open(os.path.join(paths.ldapdir, backend_schema), 'w').write(backend_schema_data)
+
+ result.credentials.set_bind_dn(names.ldapmanagerdn)
+
+ # Destory the target directory, or else setup-ds.pl will complain
+ fedora_ds_dir = os.path.join(paths.ldapdir, "slapd-samba4")
+ shutil.rmtree(fedora_ds_dir, True)
+
+ result.slapd_provision_command = [slapd_path, "-D", fedora_ds_dir, "-i", paths.slapdpid];
+ #In the 'provision' command line, stay in the foreground so we can easily kill it
+ result.slapd_provision_command.append("-d0")
+
+ #the command for the final run is the normal script
+ result.slapd_command = [os.path.join(paths.ldapdir, "slapd-samba4", "start-slapd")]
+
+ # If we were just looking for crashes up to this point, it's a
+ # good time to exit before we realise we don't have Fedora DS on
+ if ldap_dryrun_mode:
+ sys.exit(0)
+
+ # Try to print helpful messages when the user has not specified the path to the setup-ds tool
+ if setup_ds_path is None:
+ raise ProvisioningError("Warning: Fedora DS LDAP-Backend must be setup with path to setup-ds, e.g. --setup-ds-path=\"/usr/sbin/setup-ds.pl\"!")
+ if not os.path.exists(setup_ds_path):
+ message (setup_ds_path)
+ raise ProvisioningError("Warning: Given Path to slapd does not exist!")
+
+ # Run the Fedora DS setup utility
+ retcode = subprocess.call([setup_ds_path, "--silent", "--file", paths.fedoradsinf], close_fds=True, shell=False)
+ if retcode != 0:
+ raise ProvisioningError("setup-ds failed")
+
+ # Load samba-admin
+ retcode = subprocess.call([
+ os.path.join(paths.ldapdir, "slapd-samba4", "ldif2db"), "-s", names.sambadn, "-i", paths.fedoradssamba],
+ close_fds=True, shell=False)
+ if retcode != 0:
+ raise("ldib2db failed")
+
+def create_phpldapadmin_config(path, setup_path, ldapi_uri):
+ """Create a PHP LDAP admin configuration file.
+
+ :param path: Path to write the configuration to.
+ :param setup_path: Function to generate setup paths.
+ """
+ setup_file(setup_path("phpldapadmin-config.php"), path,
+ {"S4_LDAPI_URI": ldapi_uri})
+
+
+def create_zone_file(path, setup_path, dnsdomain, domaindn,
+ hostip, hostip6, hostname, dnspass, realm, domainguid,
+ ntdsguid):
+ """Write out a DNS zone file, from the info in the current database.
+
+ :param path: Path of the new zone file.
+ :param setup_path: Setup path function.
+ :param dnsdomain: DNS Domain name
+ :param domaindn: DN of the Domain
+ :param hostip: Local IPv4 IP
+ :param hostip6: Local IPv6 IP
+ :param hostname: Local hostname
+ :param dnspass: Password for DNS
+ :param realm: Realm name
+ :param domainguid: GUID of the domain.
+ :param ntdsguid: GUID of the hosts nTDSDSA record.
+ """
+ assert isinstance(domainguid, str)
+
+ if hostip6 is not None:
+ hostip6_base_line = " IN AAAA " + hostip6
+ hostip6_host_line = hostname + " IN AAAA " + hostip6
+ else:
+ hostip6_base_line = ""
+ hostip6_host_line = ""
+
+ if hostip is not None:
+ hostip_base_line = " IN A " + hostip
+ hostip_host_line = hostname + " IN A " + hostip
+ else:
+ hostip_base_line = ""
+ hostip_host_line = ""
+
+ setup_file(setup_path("provision.zone"), path, {
+ "DNSPASS_B64": b64encode(dnspass),
+ "HOSTNAME": hostname,
+ "DNSDOMAIN": dnsdomain,
+ "REALM": realm,
+ "HOSTIP_BASE_LINE": hostip_base_line,
+ "HOSTIP_HOST_LINE": hostip_host_line,
+ "DOMAINGUID": domainguid,
+ "DATESTRING": time.strftime("%Y%m%d%H"),
+ "DEFAULTSITE": DEFAULTSITE,
+ "NTDSGUID": ntdsguid,
+ "HOSTIP6_BASE_LINE": hostip6_base_line,
+ "HOSTIP6_HOST_LINE": hostip6_host_line,
+ })
+
+
+def create_named_conf(path, setup_path, realm, dnsdomain,
+ private_dir):
+ """Write out a file containing zone statements suitable for inclusion in a
+ named.conf file (including GSS-TSIG configuration).
+
+ :param path: Path of the new named.conf file.
+ :param setup_path: Setup path function.
+ :param realm: Realm name
+ :param dnsdomain: DNS Domain name
+ :param private_dir: Path to private directory
+ :param keytab_name: File name of DNS keytab file
+ """
+
+ setup_file(setup_path("named.conf"), path, {
+ "DNSDOMAIN": dnsdomain,
+ "REALM": realm,
+ "REALM_WC": "*." + ".".join(realm.split(".")[1:]),
+ "PRIVATE_DIR": private_dir
+ })
+
+def create_named_txt(path, setup_path, realm, dnsdomain,
+ private_dir, keytab_name):
+ """Write out a file containing zone statements suitable for inclusion in a
+ named.conf file (including GSS-TSIG configuration).
+
+ :param path: Path of the new named.conf file.
+ :param setup_path: Setup path function.
+ :param realm: Realm name
+ :param dnsdomain: DNS Domain name
+ :param private_dir: Path to private directory
+ :param keytab_name: File name of DNS keytab file
+ """
+
+ setup_file(setup_path("named.txt"), path, {
+ "DNSDOMAIN": dnsdomain,
+ "REALM": realm,
+ "DNS_KEYTAB": keytab_name,
+ "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name),
+ "PRIVATE_DIR": private_dir
+ })
+
+def create_krb5_conf(path, setup_path, dnsdomain, hostname, realm):
+ """Write out a file containing zone statements suitable for inclusion in a
+ named.conf file (including GSS-TSIG configuration).
+
+ :param path: Path of the new named.conf file.
+ :param setup_path: Setup path function.
+ :param dnsdomain: DNS Domain name
+ :param hostname: Local hostname
+ :param realm: Realm name
+ """
+
+ setup_file(setup_path("krb5.conf"), path, {
+ "DNSDOMAIN": dnsdomain,
+ "HOSTNAME": hostname,
+ "REALM": realm,
+ })
+
+
diff --git a/source4/scripting/python/samba/provision/__init__.py b/source4/scripting/python/samba/provision/__init__.py
deleted file mode 100644
index 55774c225b..0000000000
--- a/source4/scripting/python/samba/provision/__init__.py
+++ /dev/null
@@ -1,1929 +0,0 @@
-
-# Unix SMB/CIFS implementation.
-# backend code for provisioning a Samba4 server
-
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2010
-# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008-2009
-# Copyright (C) Oliver Liebel <oliver@itc.li> 2008-2009
-#
-# Based on the original in EJS:
-# Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
-#
-# 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/>.
-#
-
-"""Functions for setting up a Samba configuration."""
-
-__docformat__ = "restructuredText"
-
-from base64 import b64encode
-import os
-import re
-import pwd
-import grp
-import logging
-import time
-import uuid
-import socket
-import urllib
-import shutil
-
-import ldb
-
-from samba.auth import system_session, admin_session
-import samba
-from samba import (
- Ldb,
- check_all_substituted,
- in_source_tree,
- source_tree_topdir,
- read_and_sub_file,
- setup_file,
- substitute_var,
- valid_netbios_name,
- version,
- )
-from samba.dcerpc import security
-from samba.dcerpc.misc import (
- SEC_CHAN_BDC,
- SEC_CHAN_WKSTA,
- )
-from samba.dsdb import (
- DS_DOMAIN_FUNCTION_2003,
- DS_DOMAIN_FUNCTION_2008_R2,
- ENC_ALL_TYPES,
- )
-from samba.idmap import IDmapDB
-from samba.ms_display_specifiers import read_ms_ldif
-from samba.ntacls import setntacl, dsacl2fsacl
-from samba.ndr import ndr_pack, ndr_unpack
-from samba.provision.backend import (
- ExistingBackend,
- FDSBackend,
- LDBBackend,
- OpenLDAPBackend,
- )
-import samba.param
-import samba.registry
-from samba.schema import Schema
-from samba.samdb import SamDB
-
-VALID_NETBIOS_CHARS = " !#$%&'()-.@^_{}~"
-DEFAULT_POLICY_GUID = "31B2F340-016D-11D2-945F-00C04FB984F9"
-DEFAULT_DC_POLICY_GUID = "6AC1786C-016F-11D2-945F-00C04fB984F9"
-DEFAULTSITE = "Default-First-Site-Name"
-LAST_PROVISION_USN_ATTRIBUTE = "lastProvisionUSN"
-
-
-def setup_path(file):
- """Return an absolute path to the provision tempate file specified by file"""
- return os.path.join(samba.param.setup_dir(), file)
-
-# Descriptors of naming contexts and other important objects
-
-# "get_schema_descriptor" is located in "schema.py"
-
-def get_sites_descriptor(domain_sid):
- sddl = "D:(A;;RPLCLORC;;;AU)" \
- "(A;;RPWPCRCCLCLORCWOWDSW;;;EA)" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
- "S:AI(AU;CISA;CCDCSDDT;;;WD)" \
- "(OU;CIIOSA;CR;;f0f8ffab-1191-11d0-a060-00aa006c33ed;WD)" \
- "(OU;CIIOSA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967ab3-0de6-11d0-a285-00aa003049e2;WD)" \
- "(OU;CIIOSA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967ab3-0de6-11d0-a285-00aa003049e2;WD)" \
- "(OU;CIIOSA;WP;3e10944c-c354-11d0-aff8-0000f80367c1;b7b13124-b82e-11d0-afee-0000f80367c1;WD)"
- sec = security.descriptor.from_sddl(sddl, domain_sid)
- return ndr_pack(sec)
-
-
-def get_config_descriptor(domain_sid):
- sddl = "O:EAG:EAD:(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(A;;RPLCLORC;;;AU)(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)(A;CIIO;RPWPCRCCLCLORCWOWDSDSW;;;DA)" \
- "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
- "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
- "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ER)" \
- "S:(AU;SA;WPWOWD;;;WD)(AU;SA;CR;;;BA)(AU;SA;CR;;;DU)" \
- "(OU;SA;CR;45ec5156-db7e-47bb-b53f-dbeb2d03c40f;;WD)"
- sec = security.descriptor.from_sddl(sddl, domain_sid)
- return ndr_pack(sec)
-
-
-def get_domain_descriptor(domain_sid):
- sddl= "O:BAG:BAD:AI(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RP;4c164200-20c0-11d0-a768-00aa006e0529;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RP;5f202010-79a5-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RP;bc0ac240-79a9-11d0-9020-00c04fc2d4cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RP;59ba2f42-79a2-11d0-9020-00c04fc2d3cf;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RP;037088f8-0ae1-11d2-b422-00a0c968f939;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ER)" \
- "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;DD)" \
- "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a86-0de6-11d0-a285-00aa003049e2;ED)" \
- "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967a9c-0de6-11d0-a285-00aa003049e2;ED)" \
- "(OA;CIIO;RP;b7c69e6d-2cc7-11d2-854e-00a0c983f608;bf967aba-0de6-11d0-a285-00aa003049e2;ED)" \
- "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
- "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;1131f6ae-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;e2a36dc9-ae17-47c3-b58b-be34c55ba633;;IF)" \
- "(OA;;RP;c7407360-20bf-11d0-a768-00aa006e0529;;RU)" \
- "(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;RU)" \
- "(OA;CIIO;RPLCLORC;;4828cc14-1437-45bc-9b07-ad6f015e5f28;RU)" \
- "(OA;CIIO;RPLCLORC;;bf967a9c-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;CIIO;RPLCLORC;;bf967aba-0de6-11d0-a285-00aa003049e2;RU)" \
- "(OA;;CR;05c74c5e-4deb-43b4-bd9f-86664c2a7fd5;;AU)" \
- "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
- "(OA;;CR;ccc2dc7d-a6ad-4a7a-8846-c04e3cc53501;;AU)" \
- "(OA;;CR;280f369c-67c7-438e-ae98-1d46f3c6f541;;AU)" \
- "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;1131f6ae-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;RP;b8119fd0-04f6-4762-ab7a-4986c76b3f9a;;AU)" \
- "(OA;CIIO;RPWPCR;91e647de-d96f-4b70-9557-d63ff4f3ccd8;;PS)" \
- "(A;;RPWPCRCCLCLORCWOWDSW;;;DA)" \
- "(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;EA)" \
- "(A;;RPRC;;;RU)" \
- "(A;CI;LC;;;RU)" \
- "(A;CI;RPWPCRCCLCLORCWOWDSDSW;;;BA)" \
- "(A;;RP;;;WD)" \
- "(A;;RPLCLORC;;;ED)" \
- "(A;;RPLCLORC;;;AU)" \
- "(A;;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
- "S:AI(OU;CISA;WP;f30e3bbe-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)" \
- "(OU;CISA;WP;f30e3bbf-9ff0-11d1-b603-0000f80367c1;bf967aa5-0de6-11d0-a285-00aa003049e2;WD)" \
- "(AU;SA;CR;;;DU)(AU;SA;CR;;;BA)(AU;SA;WPWOWD;;;WD)"
- sec = security.descriptor.from_sddl(sddl, domain_sid)
- return ndr_pack(sec)
-
-
-class ProvisionPaths(object):
-
- def __init__(self):
- self.shareconf = None
- self.hklm = None
- self.hkcu = None
- self.hkcr = None
- self.hku = None
- self.hkpd = None
- self.hkpt = None
- self.samdb = None
- self.idmapdb = None
- self.secrets = None
- self.keytab = None
- self.dns_keytab = None
- self.dns = None
- self.winsdb = None
- self.private_dir = None
-
-
-class ProvisionNames(object):
-
- def __init__(self):
- self.rootdn = None
- self.domaindn = None
- self.configdn = None
- self.schemadn = None
- self.ldapmanagerdn = None
- self.dnsdomain = None
- self.realm = None
- self.netbiosname = None
- self.domain = None
- self.hostname = None
- self.sitename = None
- self.smbconf = None
-
-
-def update_provision_usn(samdb, low, high, replace=False):
- """Update the field provisionUSN in sam.ldb
-
- This field is used to track range of USN modified by provision and
- upgradeprovision.
- This value is used afterward by next provision to figure out if
- the field have been modified since last provision.
-
- :param samdb: An LDB object connect to sam.ldb
- :param low: The lowest USN modified by this upgrade
- :param high: The highest USN modified by this upgrade
- :param replace: A boolean indicating if the range should replace any
- existing one or appended (default)
- """
-
- tab = []
- if not replace:
- entry = samdb.search(expression="(&(dn=@PROVISION)(%s=*))" %
- LAST_PROVISION_USN_ATTRIBUTE, base="",
- scope=ldb.SCOPE_SUBTREE,
- attrs=[LAST_PROVISION_USN_ATTRIBUTE, "dn"])
- for e in entry[0][LAST_PROVISION_USN_ATTRIBUTE]:
- tab.append(str(e))
-
- tab.append("%s-%s" % (low, high))
- delta = ldb.Message()
- delta.dn = ldb.Dn(samdb, "@PROVISION")
- delta[LAST_PROVISION_USN_ATTRIBUTE] = ldb.MessageElement(tab,
- ldb.FLAG_MOD_REPLACE, LAST_PROVISION_USN_ATTRIBUTE)
- samdb.modify(delta)
-
-
-def set_provision_usn(samdb, low, high):
- """Set the field provisionUSN in sam.ldb
- This field is used to track range of USN modified by provision and
- upgradeprovision.
- This value is used afterward by next provision to figure out if
- the field have been modified since last provision.
-
- :param samdb: An LDB object connect to sam.ldb
- :param low: The lowest USN modified by this upgrade
- :param high: The highest USN modified by this upgrade"""
- tab = []
- tab.append("%s-%s" % (low, high))
- delta = ldb.Message()
- delta.dn = ldb.Dn(samdb, "@PROVISION")
- delta[LAST_PROVISION_USN_ATTRIBUTE] = ldb.MessageElement(tab,
- ldb.FLAG_MOD_ADD, LAST_PROVISION_USN_ATTRIBUTE)
- samdb.add(delta)
-
-
-def get_max_usn(samdb,basedn):
- """ This function return the biggest USN present in the provision
-
- :param samdb: A LDB object pointing to the sam.ldb
- :param basedn: A string containing the base DN of the provision
- (ie. DC=foo, DC=bar)
- :return: The biggest USN in the provision"""
-
- res = samdb.search(expression="objectClass=*",base=basedn,
- scope=ldb.SCOPE_SUBTREE,attrs=["uSNChanged"],
- controls=["search_options:1:2",
- "server_sort:1:1:uSNChanged",
- "paged_results:1:1"])
- return res[0]["uSNChanged"]
-
-
-def get_last_provision_usn(sam):
- """Get the lastest USN modified by a provision or an upgradeprovision
-
- :param sam: An LDB object pointing to the sam.ldb
- :return: an integer corresponding to the highest USN modified by
- (upgrade)provision, 0 is this value is unknown
- """
- entry = sam.search(expression="(&(dn=@PROVISION)(%s=*))" %
- LAST_PROVISION_USN_ATTRIBUTE,
- base="", scope=ldb.SCOPE_SUBTREE,
- attrs=[LAST_PROVISION_USN_ATTRIBUTE])
- if len(entry):
- range = []
- idx = 0
- p = re.compile(r'-')
- for r in entry[0][LAST_PROVISION_USN_ATTRIBUTE]:
- tab = p.split(str(r))
- range.append(tab[0])
- range.append(tab[1])
- idx = idx + 1
- return range
- else:
- return None
-
-
-class ProvisionResult(object):
-
- def __init__(self):
- self.paths = None
- self.domaindn = None
- self.lp = None
- self.samdb = None
-
-
-def check_install(lp, session_info, credentials):
- """Check whether the current install seems ok.
-
- :param lp: Loadparm context
- :param session_info: Session information
- :param credentials: Credentials
- """
- if lp.get("realm") == "":
- raise Exception("Realm empty")
- samdb = Ldb(lp.get("sam database"), session_info=session_info,
- credentials=credentials, lp=lp)
- if len(samdb.search("(cn=Administrator)")) != 1:
- raise ProvisioningError("No administrator account found")
-
-
-def findnss(nssfn, names):
- """Find a user or group from a list of possibilities.
-
- :param nssfn: NSS Function to try (should raise KeyError if not found)
- :param names: Names to check.
- :return: Value return by first names list.
- """
- for name in names:
- try:
- return nssfn(name)
- except KeyError:
- pass
- raise KeyError("Unable to find user/group in %r" % names)
-
-
-findnss_uid = lambda names: findnss(pwd.getpwnam, names)[2]
-findnss_gid = lambda names: findnss(grp.getgrnam, names)[2]
-
-
-def setup_add_ldif(ldb, ldif_path, subst_vars=None,controls=["relax:0"]):
- """Setup a ldb in the private dir.
-
- :param ldb: LDB file to import data into
- :param ldif_path: Path of the LDIF file to load
- :param subst_vars: Optional variables to subsitute in LDIF.
- :param nocontrols: Optional list of controls, can be None for no controls
- """
- assert isinstance(ldif_path, str)
- data = read_and_sub_file(ldif_path, subst_vars)
- ldb.add_ldif(data, controls)
-
-
-def setup_modify_ldif(ldb, ldif_path, subst_vars=None,controls=["relax:0"]):
- """Modify a ldb in the private dir.
-
- :param ldb: LDB object.
- :param ldif_path: LDIF file path.
- :param subst_vars: Optional dictionary with substitution variables.
- """
- data = read_and_sub_file(ldif_path, subst_vars)
- ldb.modify_ldif(data, controls)
-
-
-def setup_ldb(ldb, ldif_path, subst_vars):
- """Import a LDIF a file into a LDB handle, optionally substituting
- variables.
-
- :note: Either all LDIF data will be added or none (using transactions).
-
- :param ldb: LDB file to import into.
- :param ldif_path: Path to the LDIF file.
- :param subst_vars: Dictionary with substitution variables.
- """
- assert ldb is not None
- ldb.transaction_start()
- try:
- setup_add_ldif(ldb, ldif_path, subst_vars)
- except Exception:
- ldb.transaction_cancel()
- raise
- else:
- ldb.transaction_commit()
-
-
-def provision_paths_from_lp(lp, dnsdomain):
- """Set the default paths for provisioning.
-
- :param lp: Loadparm context.
- :param dnsdomain: DNS Domain name
- """
- paths = ProvisionPaths()
- paths.private_dir = lp.get("private dir")
-
- # This is stored without path prefix for the "privateKeytab" attribute in
- # "secrets_dns.ldif".
- paths.dns_keytab = "dns.keytab"
- paths.keytab = "secrets.keytab"
-
- paths.shareconf = os.path.join(paths.private_dir, "share.ldb")
- paths.samdb = os.path.join(paths.private_dir,
- lp.get("sam database") or "samdb.ldb")
- paths.idmapdb = os.path.join(paths.private_dir,
- lp.get("idmap database") or "idmap.ldb")
- paths.secrets = os.path.join(paths.private_dir,
- lp.get("secrets database") or "secrets.ldb")
- paths.privilege = os.path.join(paths.private_dir, "privilege.ldb")
- paths.dns = os.path.join(paths.private_dir, "dns", dnsdomain + ".zone")
- paths.dns_update_list = os.path.join(paths.private_dir, "dns_update_list")
- paths.spn_update_list = os.path.join(paths.private_dir, "spn_update_list")
- paths.namedconf = os.path.join(paths.private_dir, "named.conf")
- paths.namedconf_update = os.path.join(paths.private_dir, "named.conf.update")
- paths.namedtxt = os.path.join(paths.private_dir, "named.txt")
- paths.krb5conf = os.path.join(paths.private_dir, "krb5.conf")
- paths.winsdb = os.path.join(paths.private_dir, "wins.ldb")
- paths.s4_ldapi_path = os.path.join(paths.private_dir, "ldapi")
- paths.phpldapadminconfig = os.path.join(paths.private_dir,
- "phpldapadmin-config.php")
- paths.hklm = "hklm.ldb"
- paths.hkcr = "hkcr.ldb"
- paths.hkcu = "hkcu.ldb"
- paths.hku = "hku.ldb"
- paths.hkpd = "hkpd.ldb"
- paths.hkpt = "hkpt.ldb"
- paths.sysvol = lp.get("path", "sysvol")
- paths.netlogon = lp.get("path", "netlogon")
- paths.smbconf = lp.configfile
- return paths
-
-
-def guess_names(lp=None, hostname=None, domain=None, dnsdomain=None,
- serverrole=None, rootdn=None, domaindn=None, configdn=None,
- schemadn=None, serverdn=None, sitename=None):
- """Guess configuration settings to use."""
-
- if hostname is None:
- hostname = socket.gethostname().split(".")[0]
-
- netbiosname = lp.get("netbios name")
- if netbiosname is None:
- netbiosname = hostname
- # remove forbidden chars
- newnbname = ""
- for x in netbiosname:
- if x.isalnum() or x in VALID_NETBIOS_CHARS:
- newnbname = "%s%c" % (newnbname, x)
- # force the length to be <16
- netbiosname = newnbname[0:15]
- assert netbiosname is not None
- netbiosname = netbiosname.upper()
- if not valid_netbios_name(netbiosname):
- raise InvalidNetbiosName(netbiosname)
-
- if dnsdomain is None:
- dnsdomain = lp.get("realm")
- if dnsdomain is None or dnsdomain == "":
- raise ProvisioningError("guess_names: 'realm' not specified in supplied %s!", lp.configfile)
-
- dnsdomain = dnsdomain.lower()
-
- if serverrole is None:
- serverrole = lp.get("server role")
- if serverrole is None:
- raise ProvisioningError("guess_names: 'server role' not specified in supplied %s!" % lp.configfile)
-
- serverrole = serverrole.lower()
-
- realm = dnsdomain.upper()
-
- if lp.get("realm") == "":
- raise ProvisioningError("guess_names: 'realm =' was not specified in supplied %s. Please remove the smb.conf file and let provision generate it" % lp.configfile)
-
- if lp.get("realm").upper() != realm:
- raise ProvisioningError("guess_names: 'realm=%s' in %s must match chosen realm '%s'! Please remove the smb.conf file and let provision generate it" % (lp.get("realm").upper(), realm, lp.configfile))
-
- if lp.get("server role").lower() != serverrole:
- raise ProvisioningError("guess_names: 'server role=%s' in %s must match chosen server role '%s'! Please remove the smb.conf file and let provision generate it" % (lp.get("server role").upper(), serverrole, lp.configfile))
-
- if serverrole == "domain controller":
- if domain is None:
- # This will, for better or worse, default to 'WORKGROUP'
- domain = lp.get("workgroup")
- domain = domain.upper()
-
- if lp.get("workgroup").upper() != domain:
- raise ProvisioningError("guess_names: Workgroup '%s' in smb.conf must match chosen domain '%s'! Please remove the %s file and let provision generate it" % (lp.get("workgroup").upper(), domain, lp.configfile))
-
- if domaindn is None:
- domaindn = "DC=" + dnsdomain.replace(".", ",DC=")
-
- if domain == netbiosname:
- raise ProvisioningError("guess_names: Domain '%s' must not be equal to short host name '%s'!" % (domain, netbiosname))
- else:
- domain = netbiosname
- if domaindn is None:
- domaindn = "DC=" + netbiosname
-
- if not valid_netbios_name(domain):
- raise InvalidNetbiosName(domain)
-
- if hostname.upper() == realm:
- raise ProvisioningError("guess_names: Realm '%s' must not be equal to hostname '%s'!" % (realm, hostname))
- if netbiosname.upper() == realm:
- raise ProvisioningError("guess_names: Realm '%s' must not be equal to netbios hostname '%s'!" % (realm, netbiosname))
- if domain == realm:
- raise ProvisioningError("guess_names: Realm '%s' must not be equal to short domain name '%s'!" % (realm, domain))
-
- if rootdn is None:
- rootdn = domaindn
-
- if configdn is None:
- configdn = "CN=Configuration," + rootdn
- if schemadn is None:
- schemadn = "CN=Schema," + configdn
-
- if sitename is None:
- sitename=DEFAULTSITE
-
- names = ProvisionNames()
- names.rootdn = rootdn
- names.domaindn = domaindn
- names.configdn = configdn
- names.schemadn = schemadn
- names.ldapmanagerdn = "CN=Manager," + rootdn
- names.dnsdomain = dnsdomain
- names.domain = domain
- names.realm = realm
- names.netbiosname = netbiosname
- names.hostname = hostname
- names.sitename = sitename
- names.serverdn = "CN=%s,CN=Servers,CN=%s,CN=Sites,%s" % (
- netbiosname, sitename, configdn)
-
- return names
-
-
-def make_smbconf(smbconf, hostname, domain, realm, serverrole,
- targetdir, sid_generator="internal", eadb=False, lp=None):
- """Create a new smb.conf file based on a couple of basic settings.
- """
- assert smbconf is not None
- if hostname is None:
- hostname = socket.gethostname().split(".")[0]
- netbiosname = hostname.upper()
- # remove forbidden chars
- newnbname = ""
- for x in netbiosname:
- if x.isalnum() or x in VALID_NETBIOS_CHARS:
- newnbname = "%s%c" % (newnbname, x)
- #force the length to be <16
- netbiosname = newnbname[0:15]
- else:
- netbiosname = hostname.upper()
-
- if serverrole is None:
- serverrole = "standalone"
-
- assert serverrole in ("domain controller", "member server", "standalone")
- if serverrole == "domain controller":
- smbconfsuffix = "dc"
- elif serverrole == "member server":
- smbconfsuffix = "member"
- elif serverrole == "standalone":
- smbconfsuffix = "standalone"
-
- if sid_generator is None:
- sid_generator = "internal"
-
- assert domain is not None
- domain = domain.upper()
-
- assert realm is not None
- realm = realm.upper()
-
- if lp is None:
- lp = samba.param.LoadParm()
- #Load non-existant file
- if os.path.exists(smbconf):
- lp.load(smbconf)
- if eadb and not lp.get("posix:eadb"):
- if targetdir is not None:
- privdir = os.path.join(targetdir, "private")
- else:
- privdir = lp.get("private dir")
- lp.set("posix:eadb", os.path.abspath(os.path.join(privdir, "eadb.tdb")))
-
- if targetdir is not None:
- privatedir_line = "private dir = " + os.path.abspath(os.path.join(targetdir, "private"))
- lockdir_line = "lock dir = " + os.path.abspath(targetdir)
-
- lp.set("lock dir", os.path.abspath(targetdir))
- else:
- privatedir_line = ""
- lockdir_line = ""
-
- if sid_generator == "internal":
- sid_generator_line = ""
- else:
- sid_generator_line = "sid generator = " + sid_generator
-
- sysvol = os.path.join(lp.get("lock dir"), "sysvol")
- netlogon = os.path.join(sysvol, realm.lower(), "scripts")
-
- setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix),
- smbconf, {
- "NETBIOS_NAME": netbiosname,
- "DOMAIN": domain,
- "REALM": realm,
- "SERVERROLE": serverrole,
- "NETLOGONPATH": netlogon,
- "SYSVOLPATH": sysvol,
- "SIDGENERATOR_LINE": sid_generator_line,
- "PRIVATEDIR_LINE": privatedir_line,
- "LOCKDIR_LINE": lockdir_line
- })
-
- # reload the smb.conf
- lp.load(smbconf)
-
- # and dump it without any values that are the default
- # this ensures that any smb.conf parameters that were set
- # on the provision/join command line are set in the resulting smb.conf
- f = open(smbconf, mode='w')
- lp.dump(f, False)
- f.close()
-
-
-
-def setup_name_mappings(samdb, idmap, sid, domaindn, root_uid, nobody_uid,
- users_gid, wheel_gid):
- """setup reasonable name mappings for sam names to unix names.
-
- :param samdb: SamDB object.
- :param idmap: IDmap db object.
- :param sid: The domain sid.
- :param domaindn: The domain DN.
- :param root_uid: uid of the UNIX root user.
- :param nobody_uid: uid of the UNIX nobody user.
- :param users_gid: gid of the UNIX users group.
- :param wheel_gid: gid of the UNIX wheel group.
- """
- idmap.setup_name_mapping("S-1-5-7", idmap.TYPE_UID, nobody_uid)
- idmap.setup_name_mapping("S-1-5-32-544", idmap.TYPE_GID, wheel_gid)
-
- idmap.setup_name_mapping(sid + "-500", idmap.TYPE_UID, root_uid)
- idmap.setup_name_mapping(sid + "-513", idmap.TYPE_GID, users_gid)
-
-
-def setup_samdb_partitions(samdb_path, logger, lp, session_info,
- provision_backend, names, schema, serverrole,
- erase=False):
- """Setup the partitions for the SAM database.
-
- Alternatively, provision() may call this, and then populate the database.
-
- :note: This will wipe the Sam Database!
-
- :note: This function always removes the local SAM LDB file. The erase
- parameter controls whether to erase the existing data, which
- may not be stored locally but in LDAP.
-
- """
- assert session_info is not None
-
- # We use options=["modules:"] to stop the modules loading - we
- # just want to wipe and re-initialise the database, not start it up
-
- try:
- os.unlink(samdb_path)
- except OSError:
- pass
-
- samdb = Ldb(url=samdb_path, session_info=session_info,
- lp=lp, options=["modules:"])
-
- ldap_backend_line = "# No LDAP backend"
- if provision_backend.type is not "ldb":
- ldap_backend_line = "ldapBackend: %s" % provision_backend.ldap_uri
-
- samdb.transaction_start()
- try:
- logger.info("Setting up sam.ldb partitions and settings")
- setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), {
- "SCHEMADN": ldb.Dn(schema.ldb, names.schemadn).get_casefold(),
- "CONFIGDN": ldb.Dn(schema.ldb, names.configdn).get_casefold(),
- "DOMAINDN": ldb.Dn(schema.ldb, names.domaindn).get_casefold(),
- "LDAP_BACKEND_LINE": ldap_backend_line,
- })
-
-
- setup_add_ldif(samdb, setup_path("provision_init.ldif"), {
- "BACKEND_TYPE": provision_backend.type,
- "SERVER_ROLE": serverrole
- })
-
- logger.info("Setting up sam.ldb rootDSE")
- setup_samdb_rootdse(samdb, names)
- except Exception:
- samdb.transaction_cancel()
- raise
- else:
- samdb.transaction_commit()
-
-
-def secretsdb_self_join(secretsdb, domain,
- netbiosname, machinepass, domainsid=None,
- realm=None, dnsdomain=None,
- keytab_path=None,
- key_version_number=1,
- secure_channel_type=SEC_CHAN_WKSTA):
- """Add domain join-specific bits to a secrets database.
-
- :param secretsdb: Ldb Handle to the secrets database
- :param machinepass: Machine password
- """
- attrs = ["whenChanged",
- "secret",
- "priorSecret",
- "priorChanged",
- "krb5Keytab",
- "privateKeytab"]
-
- if realm is not None:
- if dnsdomain is None:
- dnsdomain = realm.lower()
- dnsname = '%s.%s' % (netbiosname.lower(), dnsdomain.lower())
- else:
- dnsname = None
- shortname = netbiosname.lower()
-
- # We don't need to set msg["flatname"] here, because rdn_name will handle
- # it, and it causes problems for modifies anyway
- msg = ldb.Message(ldb.Dn(secretsdb, "flatname=%s,cn=Primary Domains" % domain))
- msg["secureChannelType"] = [str(secure_channel_type)]
- msg["objectClass"] = ["top", "primaryDomain"]
- if dnsname is not None:
- msg["objectClass"] = ["top", "primaryDomain", "kerberosSecret"]
- msg["realm"] = [realm]
- msg["saltPrincipal"] = ["host/%s@%s" % (dnsname, realm.upper())]
- msg["msDS-KeyVersionNumber"] = [str(key_version_number)]
- msg["privateKeytab"] = ["secrets.keytab"]
-
- msg["secret"] = [machinepass]
- msg["samAccountName"] = ["%s$" % netbiosname]
- msg["secureChannelType"] = [str(secure_channel_type)]
- if domainsid is not None:
- msg["objectSid"] = [ndr_pack(domainsid)]
-
- # This complex expression tries to ensure that we don't have more
- # than one record for this SID, realm or netbios domain at a time,
- # but we don't delete the old record that we are about to modify,
- # because that would delete the keytab and previous password.
- res = secretsdb.search(base="cn=Primary Domains", attrs=attrs,
- expression=("(&(|(flatname=%s)(realm=%s)(objectSid=%s))(objectclass=primaryDomain)(!(dn=%s)))" % (domain, realm, str(domainsid), str(msg.dn))),
- scope=ldb.SCOPE_ONELEVEL)
-
- for del_msg in res:
- secretsdb.delete(del_msg.dn)
-
- res = secretsdb.search(base=msg.dn, attrs=attrs, scope=ldb.SCOPE_BASE)
-
- if len(res) == 1:
- msg["priorSecret"] = [res[0]["secret"][0]]
- msg["priorWhenChanged"] = [res[0]["whenChanged"][0]]
-
- try:
- msg["privateKeytab"] = [res[0]["privateKeytab"][0]]
- except KeyError:
- pass
-
- try:
- msg["krb5Keytab"] = [res[0]["krb5Keytab"][0]]
- except KeyError:
- pass
-
- for el in msg:
- if el != 'dn':
- msg[el].set_flags(ldb.FLAG_MOD_REPLACE)
- secretsdb.modify(msg)
- secretsdb.rename(res[0].dn, msg.dn)
- else:
- spn = [ 'HOST/%s' % shortname ]
- if secure_channel_type == SEC_CHAN_BDC and dnsname is not None:
- # we are a domain controller then we add servicePrincipalName
- # entries for the keytab code to update.
- spn.extend([ 'HOST/%s' % dnsname ])
- msg["servicePrincipalName"] = spn
-
- secretsdb.add(msg)
-
-
-def secretsdb_setup_dns(secretsdb, names, private_dir, realm,
- dnsdomain, dns_keytab_path, dnspass):
- """Add DNS specific bits to a secrets database.
-
- :param secretsdb: Ldb Handle to the secrets database
- :param machinepass: Machine password
- """
- try:
- os.unlink(os.path.join(private_dir, dns_keytab_path))
- except OSError:
- pass
-
- setup_ldb(secretsdb, setup_path("secrets_dns.ldif"), {
- "REALM": realm,
- "DNSDOMAIN": dnsdomain,
- "DNS_KEYTAB": dns_keytab_path,
- "DNSPASS_B64": b64encode(dnspass),
- "HOSTNAME": names.hostname,
- "DNSNAME" : '%s.%s' % (
- names.netbiosname.lower(), names.dnsdomain.lower())
- })
-
-
-def setup_secretsdb(paths, session_info, backend_credentials, lp):
- """Setup the secrets database.
-
- :note: This function does not handle exceptions and transaction on purpose,
- it's up to the caller to do this job.
-
- :param path: Path to the secrets database.
- :param session_info: Session info.
- :param credentials: Credentials
- :param lp: Loadparm context
- :return: LDB handle for the created secrets database
- """
- if os.path.exists(paths.secrets):
- os.unlink(paths.secrets)
-
- keytab_path = os.path.join(paths.private_dir, paths.keytab)
- if os.path.exists(keytab_path):
- os.unlink(keytab_path)
-
- dns_keytab_path = os.path.join(paths.private_dir, paths.dns_keytab)
- if os.path.exists(dns_keytab_path):
- os.unlink(dns_keytab_path)
-
- path = paths.secrets
-
- secrets_ldb = Ldb(path, session_info=session_info,
- lp=lp)
- secrets_ldb.erase()
- secrets_ldb.load_ldif_file_add(setup_path("secrets_init.ldif"))
- secrets_ldb = Ldb(path, session_info=session_info,
- lp=lp)
- secrets_ldb.transaction_start()
- try:
- secrets_ldb.load_ldif_file_add(setup_path("secrets.ldif"))
-
- if (backend_credentials is not None and
- backend_credentials.authentication_requested()):
- if backend_credentials.get_bind_dn() is not None:
- setup_add_ldif(secrets_ldb,
- setup_path("secrets_simple_ldap.ldif"), {
- "LDAPMANAGERDN": backend_credentials.get_bind_dn(),
- "LDAPMANAGERPASS_B64": b64encode(backend_credentials.get_password())
- })
- else:
- setup_add_ldif(secrets_ldb,
- setup_path("secrets_sasl_ldap.ldif"), {
- "LDAPADMINUSER": backend_credentials.get_username(),
- "LDAPADMINREALM": backend_credentials.get_realm(),
- "LDAPADMINPASS_B64": b64encode(backend_credentials.get_password())
- })
-
- return secrets_ldb
- except Exception:
- secrets_ldb.transaction_cancel()
- raise
-
-
-def setup_privileges(path, session_info, lp):
- """Setup the privileges database.
-
- :param path: Path to the privileges database.
- :param session_info: Session info.
- :param credentials: Credentials
- :param lp: Loadparm context
- :return: LDB handle for the created secrets database
- """
- if os.path.exists(path):
- os.unlink(path)
- privilege_ldb = Ldb(path, session_info=session_info, lp=lp)
- privilege_ldb.erase()
- privilege_ldb.load_ldif_file_add(setup_path("provision_privilege.ldif"))
-
-
-def setup_registry(path, session_info, lp):
- """Setup the registry.
-
- :param path: Path to the registry database
- :param session_info: Session information
- :param credentials: Credentials
- :param lp: Loadparm context
- """
- reg = samba.registry.Registry()
- hive = samba.registry.open_ldb(path, session_info=session_info, lp_ctx=lp)
- reg.mount_hive(hive, samba.registry.HKEY_LOCAL_MACHINE)
- provision_reg = setup_path("provision.reg")
- assert os.path.exists(provision_reg)
- reg.diff_apply(provision_reg)
-
-
-def setup_idmapdb(path, session_info, lp):
- """Setup the idmap database.
-
- :param path: path to the idmap database
- :param session_info: Session information
- :param credentials: Credentials
- :param lp: Loadparm context
- """
- if os.path.exists(path):
- os.unlink(path)
-
- idmap_ldb = IDmapDB(path, session_info=session_info, lp=lp)
- idmap_ldb.erase()
- idmap_ldb.load_ldif_file_add(setup_path("idmap_init.ldif"))
- return idmap_ldb
-
-
-def setup_samdb_rootdse(samdb, names):
- """Setup the SamDB rootdse.
-
- :param samdb: Sam Database handle
- """
- setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), {
- "SCHEMADN": names.schemadn,
- "DOMAINDN": names.domaindn,
- "ROOTDN": names.rootdn,
- "CONFIGDN": names.configdn,
- "SERVERDN": names.serverdn,
- })
-
-
-def setup_self_join(samdb, names, machinepass, dnspass,
- domainsid, next_rid, invocationid,
- policyguid, policyguid_dc, domainControllerFunctionality,
- ntdsguid):
- """Join a host to its own domain."""
- assert isinstance(invocationid, str)
- if ntdsguid is not None:
- ntdsguid_line = "objectGUID: %s\n"%ntdsguid
- else:
- ntdsguid_line = ""
- setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), {
- "CONFIGDN": names.configdn,
- "SCHEMADN": names.schemadn,
- "DOMAINDN": names.domaindn,
- "SERVERDN": names.serverdn,
- "INVOCATIONID": invocationid,
- "NETBIOSNAME": names.netbiosname,
- "DNSNAME": "%s.%s" % (names.hostname, names.dnsdomain),
- "MACHINEPASS_B64": b64encode(machinepass.encode('utf-16-le')),
- "DOMAINSID": str(domainsid),
- "DCRID": str(next_rid),
- "SAMBA_VERSION_STRING": version,
- "NTDSGUID": ntdsguid_line,
- "DOMAIN_CONTROLLER_FUNCTIONALITY": str(
- domainControllerFunctionality)})
-
- setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), {
- "POLICYGUID": policyguid,
- "POLICYGUID_DC": policyguid_dc,
- "DNSDOMAIN": names.dnsdomain,
- "DOMAINDN": names.domaindn})
-
- # add the NTDSGUID based SPNs
- ntds_dn = "CN=NTDS Settings,%s" % names.serverdn
- names.ntdsguid = samdb.searchone(basedn=ntds_dn, attribute="objectGUID",
- expression="", scope=ldb.SCOPE_BASE)
- assert isinstance(names.ntdsguid, str)
-
- # Setup fSMORoleOwner entries to point at the newly created DC entry
- setup_modify_ldif(samdb, setup_path("provision_self_join_modify.ldif"), {
- "DOMAINDN": names.domaindn,
- "CONFIGDN": names.configdn,
- "SCHEMADN": names.schemadn,
- "DEFAULTSITE": names.sitename,
- "SERVERDN": names.serverdn,
- "NETBIOSNAME": names.netbiosname,
- "RIDALLOCATIONSTART": str(next_rid + 100),
- "RIDALLOCATIONEND": str(next_rid + 100 + 499),
- })
-
- # This is partially Samba4 specific and should be replaced by the correct
- # DNS AD-style setup
- setup_add_ldif(samdb, setup_path("provision_dns_add.ldif"), {
- "DNSDOMAIN": names.dnsdomain,
- "DOMAINDN": names.domaindn,
- "DNSPASS_B64": b64encode(dnspass.encode('utf-16-le')),
- "HOSTNAME" : names.hostname,
- "DNSNAME" : '%s.%s' % (
- names.netbiosname.lower(), names.dnsdomain.lower())
- })
-
-
-def getpolicypath(sysvolpath, dnsdomain, guid):
- """Return the physical path of policy given its guid.
-
- :param sysvolpath: Path to the sysvol folder
- :param dnsdomain: DNS name of the AD domain
- :param guid: The GUID of the policy
- :return: A string with the complete path to the policy folder
- """
-
- if guid[0] != "{":
- guid = "{%s}" % guid
- policy_path = os.path.join(sysvolpath, dnsdomain, "Policies", guid)
- return policy_path
-
-
-def create_gpo_struct(policy_path):
- if not os.path.exists(policy_path):
- os.makedirs(policy_path, 0775)
- open(os.path.join(policy_path, "GPT.INI"), 'w').write(
- "[General]\r\nVersion=0")
- p = os.path.join(policy_path, "MACHINE")
- if not os.path.exists(p):
- os.makedirs(p, 0775)
- p = os.path.join(policy_path, "USER")
- if not os.path.exists(p):
- os.makedirs(p, 0775)
-
-
-def create_default_gpo(sysvolpath, dnsdomain, policyguid, policyguid_dc):
- """Create the default GPO for a domain
-
- :param sysvolpath: Physical path for the sysvol folder
- :param dnsdomain: DNS domain name of the AD domain
- :param policyguid: GUID of the default domain policy
- :param policyguid_dc: GUID of the default domain controler policy
- """
- policy_path = getpolicypath(sysvolpath,dnsdomain,policyguid)
- create_gpo_struct(policy_path)
-
- policy_path = getpolicypath(sysvolpath,dnsdomain,policyguid_dc)
- create_gpo_struct(policy_path)
-
-
-def setup_samdb(path, session_info, provision_backend, lp, names,
- logger, domainsid, domainguid, policyguid, policyguid_dc, fill,
- adminpass, krbtgtpass, machinepass, invocationid, dnspass, ntdsguid,
- serverrole, am_rodc=False, dom_for_fun_level=None, schema=None,
- next_rid=1000):
- """Setup a complete SAM Database.
-
- :note: This will wipe the main SAM database file!
- """
-
- # Provision does not make much sense values larger than 1000000000
- # as the upper range of the rIDAvailablePool is 1073741823 and
- # we don't want to create a domain that cannot allocate rids.
- if next_rid < 1000 or next_rid > 1000000000:
- error = "You want to run SAMBA 4 with a next_rid of %u, " % (next_rid)
- error += "the valid range is %u-%u. The default is %u." % (
- 1000, 1000000000, 1000)
- raise ProvisioningError(error)
-
- # ATTENTION: Do NOT change these default values without discussion with the
- # team and/or release manager. They have a big impact on the whole program!
- domainControllerFunctionality = DS_DOMAIN_FUNCTION_2008_R2
-
- if dom_for_fun_level is None:
- dom_for_fun_level = DS_DOMAIN_FUNCTION_2003
-
- if dom_for_fun_level > domainControllerFunctionality:
- raise ProvisioningError("You want to run SAMBA 4 on a domain and forest function level which itself is higher than its actual DC function level (2008_R2). This won't work!")
-
- domainFunctionality = dom_for_fun_level
- forestFunctionality = dom_for_fun_level
-
- # Also wipes the database
- setup_samdb_partitions(path, logger=logger, lp=lp,
- provision_backend=provision_backend, session_info=session_info,
- names=names, serverrole=serverrole, schema=schema)
-
- if schema is None:
- schema = Schema(domainsid, schemadn=names.schemadn)
-
- # Load the database, but don's load the global schema and don't connect
- # quite yet
- samdb = SamDB(session_info=session_info, url=None, auto_connect=False,
- credentials=provision_backend.credentials, lp=lp,
- global_schema=False, am_rodc=am_rodc)
-
- logger.info("Pre-loading the Samba 4 and AD schema")
-
- # Load the schema from the one we computed earlier
- samdb.set_schema(schema)
-
- # Set the NTDS settings DN manually - in order to have it already around
- # before the provisioned tree exists and we connect
- samdb.set_ntds_settings_dn("CN=NTDS Settings,%s" % names.serverdn)
-
- # And now we can connect to the DB - the schema won't be loaded from the
- # DB
- samdb.connect(path)
-
- if fill == FILL_DRS:
- return samdb
-
- samdb.transaction_start()
- try:
- # Set the domain functionality levels onto the database.
- # Various module (the password_hash module in particular) need
- # to know what level of AD we are emulating.
-
- # These will be fixed into the database via the database
- # modifictions below, but we need them set from the start.
- samdb.set_opaque_integer("domainFunctionality", domainFunctionality)
- samdb.set_opaque_integer("forestFunctionality", forestFunctionality)
- samdb.set_opaque_integer("domainControllerFunctionality",
- domainControllerFunctionality)
-
- samdb.set_domain_sid(str(domainsid))
- samdb.set_invocation_id(invocationid)
-
- logger.info("Adding DomainDN: %s" % names.domaindn)
-
- # impersonate domain admin
- admin_session_info = admin_session(lp, str(domainsid))
- samdb.set_session_info(admin_session_info)
- if domainguid is not None:
- domainguid_line = "objectGUID: %s\n-" % domainguid
- else:
- domainguid_line = ""
-
- descr = b64encode(get_domain_descriptor(domainsid))
- setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), {
- "DOMAINDN": names.domaindn,
- "DOMAINSID": str(domainsid),
- "DESCRIPTOR": descr,
- "DOMAINGUID": domainguid_line
- })
-
- setup_modify_ldif(samdb, setup_path("provision_basedn_modify.ldif"), {
- "DOMAINDN": names.domaindn,
- "CREATTIME": str(int(time.time() * 1e7)), # seconds -> ticks
- "NEXTRID": str(next_rid),
- "DEFAULTSITE": names.sitename,
- "CONFIGDN": names.configdn,
- "POLICYGUID": policyguid,
- "DOMAIN_FUNCTIONALITY": str(domainFunctionality),
- "SAMBA_VERSION_STRING": version
- })
-
- logger.info("Adding configuration container")
- descr = b64encode(get_config_descriptor(domainsid))
- setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), {
- "CONFIGDN": names.configdn,
- "DESCRIPTOR": descr,
- })
-
- # The LDIF here was created when the Schema object was constructed
- logger.info("Setting up sam.ldb schema")
- samdb.add_ldif(schema.schema_dn_add, controls=["relax:0"])
- samdb.modify_ldif(schema.schema_dn_modify)
- samdb.write_prefixes_from_schema()
- samdb.add_ldif(schema.schema_data, controls=["relax:0"])
- setup_add_ldif(samdb, setup_path("aggregate_schema.ldif"),
- {"SCHEMADN": names.schemadn})
-
- logger.info("Reopening sam.ldb with new schema")
- except Exception:
- samdb.transaction_cancel()
- raise
- else:
- samdb.transaction_commit()
-
- samdb = SamDB(session_info=admin_session_info, auto_connect=False,
- credentials=provision_backend.credentials, lp=lp,
- global_schema=False, am_rodc=am_rodc)
-
- # Set the NTDS settings DN manually - in order to have it already around
- # before the provisioned tree exists and we connect
- samdb.set_ntds_settings_dn("CN=NTDS Settings,%s" % names.serverdn)
- samdb.connect(path)
-
- samdb.transaction_start()
- try:
- samdb.invocation_id = invocationid
-
- logger.info("Setting up sam.ldb configuration data")
- descr = b64encode(get_sites_descriptor(domainsid))
- setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), {
- "CONFIGDN": names.configdn,
- "NETBIOSNAME": names.netbiosname,
- "DEFAULTSITE": names.sitename,
- "DNSDOMAIN": names.dnsdomain,
- "DOMAIN": names.domain,
- "SCHEMADN": names.schemadn,
- "DOMAINDN": names.domaindn,
- "SERVERDN": names.serverdn,
- "FOREST_FUNCTIONALITY": str(forestFunctionality),
- "DOMAIN_FUNCTIONALITY": str(domainFunctionality),
- "SITES_DESCRIPTOR": descr
- })
-
- logger.info("Setting up display specifiers")
- display_specifiers_ldif = read_ms_ldif(
- setup_path('display-specifiers/DisplaySpecifiers-Win2k8R2.txt'))
- display_specifiers_ldif = substitute_var(display_specifiers_ldif,
- {"CONFIGDN": names.configdn})
- check_all_substituted(display_specifiers_ldif)
- samdb.add_ldif(display_specifiers_ldif)
-
- logger.info("Adding users container")
- setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), {
- "DOMAINDN": names.domaindn})
- logger.info("Modifying users container")
- setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), {
- "DOMAINDN": names.domaindn})
- logger.info("Adding computers container")
- setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), {
- "DOMAINDN": names.domaindn})
- logger.info("Modifying computers container")
- setup_modify_ldif(samdb,
- setup_path("provision_computers_modify.ldif"), {
- "DOMAINDN": names.domaindn})
- logger.info("Setting up sam.ldb data")
- setup_add_ldif(samdb, setup_path("provision.ldif"), {
- "CREATTIME": str(int(time.time() * 1e7)), # seconds -> ticks
- "DOMAINDN": names.domaindn,
- "NETBIOSNAME": names.netbiosname,
- "DEFAULTSITE": names.sitename,
- "CONFIGDN": names.configdn,
- "SERVERDN": names.serverdn,
- "RIDAVAILABLESTART": str(next_rid + 600),
- "POLICYGUID_DC": policyguid_dc
- })
-
- setup_modify_ldif(samdb,
- setup_path("provision_basedn_references.ldif"), {
- "DOMAINDN": names.domaindn})
-
- setup_modify_ldif(samdb,
- setup_path("provision_configuration_references.ldif"), {
- "CONFIGDN": names.configdn,
- "SCHEMADN": names.schemadn})
- if fill == FILL_FULL:
- logger.info("Setting up sam.ldb users and groups")
- setup_add_ldif(samdb, setup_path("provision_users.ldif"), {
- "DOMAINDN": names.domaindn,
- "DOMAINSID": str(domainsid),
- "CONFIGDN": names.configdn,
- "ADMINPASS_B64": b64encode(adminpass.encode('utf-16-le')),
- "KRBTGTPASS_B64": b64encode(krbtgtpass.encode('utf-16-le'))
- })
-
- logger.info("Setting up self join")
- setup_self_join(samdb, names=names, invocationid=invocationid,
- dnspass=dnspass,
- machinepass=machinepass,
- domainsid=domainsid,
- next_rid=next_rid,
- policyguid=policyguid,
- policyguid_dc=policyguid_dc,
- domainControllerFunctionality=domainControllerFunctionality,
- ntdsguid=ntdsguid)
-
- ntds_dn = "CN=NTDS Settings,%s" % names.serverdn
- names.ntdsguid = samdb.searchone(basedn=ntds_dn,
- attribute="objectGUID", expression="", scope=ldb.SCOPE_BASE)
- assert isinstance(names.ntdsguid, str)
- except Exception:
- samdb.transaction_cancel()
- raise
- else:
- samdb.transaction_commit()
- return samdb
-
-
-FILL_FULL = "FULL"
-FILL_NT4SYNC = "NT4SYNC"
-FILL_DRS = "DRS"
-SYSVOL_ACL = "O:LAG:BAD:P(A;OICI;0x001f01ff;;;BA)(A;OICI;0x001200a9;;;SO)(A;OICI;0x001f01ff;;;SY)(A;OICI;0x001200a9;;;AU)"
-POLICIES_ACL = "O:LAG:BAD:P(A;OICI;0x001f01ff;;;BA)(A;OICI;0x001200a9;;;SO)(A;OICI;0x001f01ff;;;SY)(A;OICI;0x001200a9;;;AU)(A;OICI;0x001301bf;;;PA)"
-
-
-def set_dir_acl(path, acl, lp, domsid):
- setntacl(lp, path, acl, domsid)
- for root, dirs, files in os.walk(path, topdown=False):
- for name in files:
- setntacl(lp, os.path.join(root, name), acl, domsid)
- for name in dirs:
- setntacl(lp, os.path.join(root, name), acl, domsid)
-
-
-def set_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp):
- """Set ACL on the sysvol/<dnsname>/Policies folder and the policy
- folders beneath.
-
- :param sysvol: Physical path for the sysvol folder
- :param dnsdomain: The DNS name of the domain
- :param domainsid: The SID of the domain
- :param domaindn: The DN of the domain (ie. DC=...)
- :param samdb: An LDB object on the SAM db
- :param lp: an LP object
- """
-
- # Set ACL for GPO root folder
- root_policy_path = os.path.join(sysvol, dnsdomain, "Policies")
- setntacl(lp, root_policy_path, POLICIES_ACL, str(domainsid))
-
- res = samdb.search(base="CN=Policies,CN=System,%s"%(domaindn),
- attrs=["cn", "nTSecurityDescriptor"],
- expression="", scope=ldb.SCOPE_ONELEVEL)
-
- for policy in res:
- acl = ndr_unpack(security.descriptor,
- str(policy["nTSecurityDescriptor"])).as_sddl()
- policy_path = getpolicypath(sysvol, dnsdomain, str(policy["cn"]))
- set_dir_acl(policy_path, dsacl2fsacl(acl, str(domainsid)), lp,
- str(domainsid))
-
-
-def setsysvolacl(samdb, netlogon, sysvol, gid, domainsid, dnsdomain, domaindn,
- lp):
- """Set the ACL for the sysvol share and the subfolders
-
- :param samdb: An LDB object on the SAM db
- :param netlogon: Physical path for the netlogon folder
- :param sysvol: Physical path for the sysvol folder
- :param gid: The GID of the "Domain adminstrators" group
- :param domainsid: The SID of the domain
- :param dnsdomain: The DNS name of the domain
- :param domaindn: The DN of the domain (ie. DC=...)
- """
-
- try:
- os.chown(sysvol, -1, gid)
- except OSError:
- canchown = False
- else:
- canchown = True
-
- # Set the SYSVOL_ACL on the sysvol folder and subfolder (first level)
- setntacl(lp,sysvol, SYSVOL_ACL, str(domainsid))
- for root, dirs, files in os.walk(sysvol, topdown=False):
- for name in files:
- if canchown:
- os.chown(os.path.join(root, name), -1, gid)
- setntacl(lp, os.path.join(root, name), SYSVOL_ACL, str(domainsid))
- for name in dirs:
- if canchown:
- os.chown(os.path.join(root, name), -1, gid)
- setntacl(lp, os.path.join(root, name), SYSVOL_ACL, str(domainsid))
-
- # Set acls on Policy folder and policies folders
- set_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp)
-
-
-def provision(logger, session_info, credentials, smbconf=None,
- targetdir=None, samdb_fill=FILL_FULL, realm=None, rootdn=None,
- domaindn=None, schemadn=None, configdn=None, serverdn=None,
- domain=None, hostname=None, hostip=None, hostip6=None, domainsid=None,
- next_rid=1000, adminpass=None, ldapadminpass=None, krbtgtpass=None,
- domainguid=None, policyguid=None, policyguid_dc=None,
- invocationid=None, machinepass=None, ntdsguid=None, dnspass=None,
- root=None, nobody=None, users=None, wheel=None, backup=None, aci=None,
- serverrole=None, dom_for_fun_level=None, ldap_backend_extra_port=None,
- ldap_backend_forced_uri=None, backend_type=None, sitename=None,
- ol_mmr_urls=None, ol_olc=None, setup_ds_path=None, slapd_path=None,
- nosync=False, ldap_dryrun_mode=False, useeadb=False, am_rodc=False,
- lp=None):
- """Provision samba4
-
- :note: caution, this wipes all existing data!
- """
-
- if domainsid is None:
- domainsid = security.random_sid()
- else:
- domainsid = security.dom_sid(domainsid)
-
- # create/adapt the group policy GUIDs
- # Default GUID for default policy are described at
- # "How Core Group Policy Works"
- # http://technet.microsoft.com/en-us/library/cc784268%28WS.10%29.aspx
- if policyguid is None:
- policyguid = DEFAULT_POLICY_GUID
- policyguid = policyguid.upper()
- if policyguid_dc is None:
- policyguid_dc = DEFAULT_DC_POLICY_GUID
- policyguid_dc = policyguid_dc.upper()
-
- if adminpass is None:
- adminpass = samba.generate_random_password(12, 32)
- if krbtgtpass is None:
- krbtgtpass = samba.generate_random_password(128, 255)
- if machinepass is None:
- machinepass = samba.generate_random_password(128, 255)
- if dnspass is None:
- dnspass = samba.generate_random_password(128, 255)
- if ldapadminpass is None:
- # Make a new, random password between Samba and it's LDAP server
- ldapadminpass=samba.generate_random_password(128, 255)
-
- if backend_type is None:
- backend_type = "ldb"
-
- sid_generator = "internal"
- if backend_type == "fedora-ds":
- sid_generator = "backend"
-
- root_uid = findnss_uid([root or "root"])
- nobody_uid = findnss_uid([nobody or "nobody"])
- users_gid = findnss_gid([users or "users", 'users', 'other', 'staff'])
- if wheel is None:
- wheel_gid = findnss_gid(["wheel", "adm"])
- else:
- wheel_gid = findnss_gid([wheel])
- try:
- bind_gid = findnss_gid(["bind", "named"])
- except KeyError:
- bind_gid = None
-
- if targetdir is not None:
- smbconf = os.path.join(targetdir, "etc", "smb.conf")
- elif smbconf is None:
- smbconf = samba.param.default_path()
- if not os.path.exists(os.path.dirname(smbconf)):
- os.makedirs(os.path.dirname(smbconf))
-
- # only install a new smb.conf if there isn't one there already
- if os.path.exists(smbconf):
- # if Samba Team members can't figure out the weird errors
- # loading an empty smb.conf gives, then we need to be smarter.
- # Pretend it just didn't exist --abartlet
- data = open(smbconf, 'r').read()
- data = data.lstrip()
- if data is None or data == "":
- make_smbconf(smbconf, hostname, domain, realm,
- serverrole, targetdir, sid_generator, useeadb,
- lp=lp)
- else:
- make_smbconf(smbconf, hostname, domain, realm, serverrole,
- targetdir, sid_generator, useeadb, lp=lp)
-
- if lp is None:
- lp = samba.param.LoadParm()
- lp.load(smbconf)
- names = guess_names(lp=lp, hostname=hostname, domain=domain,
- dnsdomain=realm, serverrole=serverrole, domaindn=domaindn,
- configdn=configdn, schemadn=schemadn, serverdn=serverdn,
- sitename=sitename)
- paths = provision_paths_from_lp(lp, names.dnsdomain)
-
- paths.bind_gid = bind_gid
-
- if hostip is None:
- logger.info("Looking up IPv4 addresses")
- hostips = samba.interface_ips(lp, False)
- if len(hostips) == 0:
- logger.warning("No external IPv4 address has been found. Using loopback.")
- hostip = '127.0.0.1'
- else:
- hostip = hostips[0]
- if len(hostips) > 1:
- logger.warning("More than one IPv4 address found. Using %s.",
- hostip)
-
- if serverrole is None:
- serverrole = lp.get("server role")
-
- assert serverrole in ("domain controller", "member server", "standalone")
- if invocationid is None:
- invocationid = str(uuid.uuid4())
-
- if not os.path.exists(paths.private_dir):
- os.mkdir(paths.private_dir)
- if not os.path.exists(os.path.join(paths.private_dir, "tls")):
- os.mkdir(os.path.join(paths.private_dir, "tls"))
-
- ldapi_url = "ldapi://%s" % urllib.quote(paths.s4_ldapi_path, safe="")
-
- schema = Schema(domainsid, invocationid=invocationid,
- schemadn=names.schemadn)
-
- if backend_type == "ldb":
- provision_backend = LDBBackend(backend_type, paths=paths,
- lp=lp, credentials=credentials,
- names=names, logger=logger)
- elif backend_type == "existing":
- provision_backend = ExistingBackend(backend_type, paths=paths,
- lp=lp, credentials=credentials,
- names=names, logger=logger,
- ldap_backend_forced_uri=ldap_backend_forced_uri)
- elif backend_type == "fedora-ds":
- provision_backend = FDSBackend(backend_type, paths=paths,
- lp=lp, credentials=credentials,
- names=names, logger=logger, domainsid=domainsid,
- schema=schema, hostname=hostname, ldapadminpass=ldapadminpass,
- slapd_path=slapd_path,
- ldap_backend_extra_port=ldap_backend_extra_port,
- ldap_dryrun_mode=ldap_dryrun_mode, root=root,
- setup_ds_path=setup_ds_path,
- ldap_backend_forced_uri=ldap_backend_forced_uri)
- elif backend_type == "openldap":
- provision_backend = OpenLDAPBackend(backend_type, paths=paths,
- lp=lp, credentials=credentials,
- names=names, logger=logger, domainsid=domainsid,
- schema=schema, hostname=hostname, ldapadminpass=ldapadminpass,
- slapd_path=slapd_path,
- ldap_backend_extra_port=ldap_backend_extra_port,
- ldap_dryrun_mode=ldap_dryrun_mode, ol_mmr_urls=ol_mmr_urls,
- nosync=nosync,
- ldap_backend_forced_uri=ldap_backend_forced_uri)
- else:
- raise ValueError("Unknown LDAP backend type selected")
-
- provision_backend.init()
- provision_backend.start()
-
- # only install a new shares config db if there is none
- if not os.path.exists(paths.shareconf):
- logger.info("Setting up share.ldb")
- share_ldb = Ldb(paths.shareconf, session_info=session_info,
- lp=lp)
- share_ldb.load_ldif_file_add(setup_path("share.ldif"))
-
- logger.info("Setting up secrets.ldb")
- secrets_ldb = setup_secretsdb(paths,
- session_info=session_info,
- backend_credentials=provision_backend.secrets_credentials, lp=lp)
-
- try:
- logger.info("Setting up the registry")
- setup_registry(paths.hklm, session_info,
- lp=lp)
-
- logger.info("Setting up the privileges database")
- setup_privileges(paths.privilege, session_info, lp=lp)
-
- logger.info("Setting up idmap db")
- idmap = setup_idmapdb(paths.idmapdb,
- session_info=session_info, lp=lp)
-
- logger.info("Setting up SAM db")
- samdb = setup_samdb(paths.samdb, session_info,
- provision_backend, lp, names, logger=logger,
- domainsid=domainsid, schema=schema, domainguid=domainguid,
- policyguid=policyguid, policyguid_dc=policyguid_dc,
- fill=samdb_fill, adminpass=adminpass, krbtgtpass=krbtgtpass,
- invocationid=invocationid, machinepass=machinepass,
- dnspass=dnspass, ntdsguid=ntdsguid, serverrole=serverrole,
- dom_for_fun_level=dom_for_fun_level, am_rodc=am_rodc,
- next_rid=next_rid)
-
- if serverrole == "domain controller":
- if paths.netlogon is None:
- logger.info("Existing smb.conf does not have a [netlogon] share, but you are configuring a DC.")
- logger.info("Please either remove %s or see the template at %s" %
- (paths.smbconf, setup_path("provision.smb.conf.dc")))
- assert paths.netlogon is not None
-
- if paths.sysvol is None:
- logger.info("Existing smb.conf does not have a [sysvol] share, but you"
- " are configuring a DC.")
- logger.info("Please either remove %s or see the template at %s" %
- (paths.smbconf, setup_path("provision.smb.conf.dc")))
- assert paths.sysvol is not None
-
- if not os.path.isdir(paths.netlogon):
- os.makedirs(paths.netlogon, 0755)
-
- if samdb_fill == FILL_FULL:
- setup_name_mappings(samdb, idmap, str(domainsid), names.domaindn,
- root_uid=root_uid, nobody_uid=nobody_uid,
- users_gid=users_gid, wheel_gid=wheel_gid)
-
- if serverrole == "domain controller":
- # Set up group policies (domain policy and domain controller
- # policy)
- create_default_gpo(paths.sysvol, names.dnsdomain, policyguid,
- policyguid_dc)
- setsysvolacl(samdb, paths.netlogon, paths.sysvol, wheel_gid,
- domainsid, names.dnsdomain, names.domaindn, lp)
-
- logger.info("Setting up sam.ldb rootDSE marking as synchronized")
- setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif"))
-
- secretsdb_self_join(secrets_ldb, domain=names.domain,
- realm=names.realm, dnsdomain=names.dnsdomain,
- netbiosname=names.netbiosname, domainsid=domainsid,
- machinepass=machinepass, secure_channel_type=SEC_CHAN_BDC)
-
- # Now set up the right msDS-SupportedEncryptionTypes into the DB
- # In future, this might be determined from some configuration
- kerberos_enctypes = str(ENC_ALL_TYPES)
-
- try:
- msg = ldb.Message(ldb.Dn(samdb,
- samdb.searchone("distinguishedName",
- expression="samAccountName=%s$" % names.netbiosname,
- scope=ldb.SCOPE_SUBTREE)))
- msg["msDS-SupportedEncryptionTypes"] = ldb.MessageElement(
- elements=kerberos_enctypes, flags=ldb.FLAG_MOD_REPLACE,
- name="msDS-SupportedEncryptionTypes")
- samdb.modify(msg)
- except ldb.LdbError, (enum, estr):
- if enum != ldb.ERR_NO_SUCH_ATTRIBUTE:
- # It might be that this attribute does not exist in this schema
- raise
-
- if serverrole == "domain controller":
- secretsdb_setup_dns(secrets_ldb, names,
- paths.private_dir, realm=names.realm,
- dnsdomain=names.dnsdomain,
- dns_keytab_path=paths.dns_keytab, dnspass=dnspass)
-
- domainguid = samdb.searchone(basedn=domaindn,
- attribute="objectGUID")
- assert isinstance(domainguid, str)
-
- # Only make a zone file on the first DC, it should be
- # replicated with DNS replication
- create_zone_file(lp, logger, paths, targetdir,
- dnsdomain=names.dnsdomain, hostip=hostip, hostip6=hostip6,
- hostname=names.hostname, realm=names.realm,
- domainguid=domainguid, ntdsguid=names.ntdsguid)
-
- create_named_conf(paths, realm=names.realm,
- dnsdomain=names.dnsdomain, private_dir=paths.private_dir)
-
- create_named_txt(paths.namedtxt,
- realm=names.realm, dnsdomain=names.dnsdomain,
- private_dir=paths.private_dir,
- keytab_name=paths.dns_keytab)
- logger.info("See %s for an example configuration include file for BIND", paths.namedconf)
- logger.info("and %s for further documentation required for secure DNS "
- "updates", paths.namedtxt)
-
- lastProvisionUSNs = get_last_provision_usn(samdb)
- maxUSN = get_max_usn(samdb, str(names.rootdn))
- if lastProvisionUSNs is not None:
- update_provision_usn(samdb, 0, maxUSN, 1)
- else:
- set_provision_usn(samdb, 0, maxUSN)
-
- create_krb5_conf(paths.krb5conf,
- dnsdomain=names.dnsdomain, hostname=names.hostname,
- realm=names.realm)
- logger.info("A Kerberos configuration suitable for Samba 4 has been "
- "generated at %s", paths.krb5conf)
-
- if serverrole == "domain controller":
- create_dns_update_list(lp, logger, paths)
-
- provision_backend.post_setup()
- provision_backend.shutdown()
-
- create_phpldapadmin_config(paths.phpldapadminconfig,
- ldapi_url)
- except Exception:
- secrets_ldb.transaction_cancel()
- raise
-
- # Now commit the secrets.ldb to disk
- secrets_ldb.transaction_commit()
-
- # the commit creates the dns.keytab, now chown it
- dns_keytab_path = os.path.join(paths.private_dir, paths.dns_keytab)
- if os.path.isfile(dns_keytab_path) and paths.bind_gid is not None:
- try:
- os.chmod(dns_keytab_path, 0640)
- os.chown(dns_keytab_path, -1, paths.bind_gid)
- except OSError:
- if not os.environ.has_key('SAMBA_SELFTEST'):
- logger.info("Failed to chown %s to bind gid %u",
- dns_keytab_path, paths.bind_gid)
-
-
- logger.info("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php",
- paths.phpldapadminconfig)
-
- logger.info("Once the above files are installed, your Samba4 server will be ready to use")
- logger.info("Server Role: %s" % serverrole)
- logger.info("Hostname: %s" % names.hostname)
- logger.info("NetBIOS Domain: %s" % names.domain)
- logger.info("DNS Domain: %s" % names.dnsdomain)
- logger.info("DOMAIN SID: %s" % str(domainsid))
- if samdb_fill == FILL_FULL:
- logger.info("Admin password: %s" % adminpass)
- if provision_backend.type is not "ldb":
- if provision_backend.credentials.get_bind_dn() is not None:
- logger.info("LDAP Backend Admin DN: %s" %
- provision_backend.credentials.get_bind_dn())
- else:
- logger.info("LDAP Admin User: %s" %
- provision_backend.credentials.get_username())
-
- logger.info("LDAP Admin Password: %s" %
- provision_backend.credentials.get_password())
-
- if provision_backend.slapd_command_escaped is not None:
- # now display slapd_command_file.txt to show how slapd must be
- # started next time
- logger.info("Use later the following commandline to start slapd, then Samba:")
- logger.info(provision_backend.slapd_command_escaped)
- logger.info("This slapd-Commandline is also stored under: %s/ldap_backend_startup.sh",
- provision_backend.ldapdir)
-
- result = ProvisionResult()
- result.domaindn = domaindn
- result.paths = paths
- result.lp = lp
- result.samdb = samdb
- return result
-
-
-def provision_become_dc(smbconf=None, targetdir=None,
- realm=None, rootdn=None, domaindn=None, schemadn=None, configdn=None,
- serverdn=None, domain=None, hostname=None, domainsid=None,
- adminpass=None, krbtgtpass=None, domainguid=None, policyguid=None,
- policyguid_dc=None, invocationid=None, machinepass=None, dnspass=None,
- root=None, nobody=None, users=None, wheel=None, backup=None,
- serverrole=None, ldap_backend=None, ldap_backend_type=None,
- sitename=None, debuglevel=1):
-
- logger = logging.getLogger("provision")
- samba.set_debug_level(debuglevel)
-
- res = provision(logger, system_session(), None,
- smbconf=smbconf, targetdir=targetdir, samdb_fill=FILL_DRS,
- realm=realm, rootdn=rootdn, domaindn=domaindn, schemadn=schemadn,
- configdn=configdn, serverdn=serverdn, domain=domain,
- hostname=hostname, hostip="127.0.0.1", domainsid=domainsid,
- machinepass=machinepass, serverrole="domain controller",
- sitename=sitename)
- res.lp.set("debuglevel", str(debuglevel))
- return res
-
-
-def create_phpldapadmin_config(path, ldapi_uri):
- """Create a PHP LDAP admin configuration file.
-
- :param path: Path to write the configuration to.
- """
- setup_file(setup_path("phpldapadmin-config.php"), path,
- {"S4_LDAPI_URI": ldapi_uri})
-
-
-def create_zone_file(lp, logger, paths, targetdir, dnsdomain,
- hostip, hostip6, hostname, realm, domainguid,
- ntdsguid):
- """Write out a DNS zone file, from the info in the current database.
-
- :param paths: paths object
- :param dnsdomain: DNS Domain name
- :param domaindn: DN of the Domain
- :param hostip: Local IPv4 IP
- :param hostip6: Local IPv6 IP
- :param hostname: Local hostname
- :param realm: Realm name
- :param domainguid: GUID of the domain.
- :param ntdsguid: GUID of the hosts nTDSDSA record.
- """
- assert isinstance(domainguid, str)
-
- if hostip6 is not None:
- hostip6_base_line = " IN AAAA " + hostip6
- hostip6_host_line = hostname + " IN AAAA " + hostip6
- gc_msdcs_ip6_line = "gc._msdcs IN AAAA " + hostip6
- else:
- hostip6_base_line = ""
- hostip6_host_line = ""
- gc_msdcs_ip6_line = ""
-
- if hostip is not None:
- hostip_base_line = " IN A " + hostip
- hostip_host_line = hostname + " IN A " + hostip
- gc_msdcs_ip_line = "gc._msdcs IN A " + hostip
- else:
- hostip_base_line = ""
- hostip_host_line = ""
- gc_msdcs_ip_line = ""
-
- dns_dir = os.path.dirname(paths.dns)
-
- try:
- shutil.rmtree(dns_dir, True)
- except OSError:
- pass
-
- os.mkdir(dns_dir, 0775)
-
- # we need to freeze the zone while we update the contents
- if targetdir is None:
- rndc = ' '.join(lp.get("rndc command"))
- os.system(rndc + " freeze " + lp.get("realm"))
-
- setup_file(setup_path("provision.zone"), paths.dns, {
- "HOSTNAME": hostname,
- "DNSDOMAIN": dnsdomain,
- "REALM": realm,
- "HOSTIP_BASE_LINE": hostip_base_line,
- "HOSTIP_HOST_LINE": hostip_host_line,
- "DOMAINGUID": domainguid,
- "DATESTRING": time.strftime("%Y%m%d%H"),
- "DEFAULTSITE": DEFAULTSITE,
- "NTDSGUID": ntdsguid,
- "HOSTIP6_BASE_LINE": hostip6_base_line,
- "HOSTIP6_HOST_LINE": hostip6_host_line,
- "GC_MSDCS_IP_LINE": gc_msdcs_ip_line,
- "GC_MSDCS_IP6_LINE": gc_msdcs_ip6_line,
- })
-
- # note that we use no variable substitution on this file
- # the substitution is done at runtime by samba_dnsupdate
- setup_file(setup_path("dns_update_list"), paths.dns_update_list, None)
-
- # and the SPN update list
- setup_file(setup_path("spn_update_list"), paths.spn_update_list, None)
-
- if paths.bind_gid is not None:
- try:
- os.chown(dns_dir, -1, paths.bind_gid)
- os.chown(paths.dns, -1, paths.bind_gid)
- # chmod needed to cope with umask
- os.chmod(dns_dir, 0775)
- os.chmod(paths.dns, 0664)
- except OSError:
- if not os.environ.has_key('SAMBA_SELFTEST'):
- logger.error("Failed to chown %s to bind gid %u" % (
- dns_dir, paths.bind_gid))
-
- if targetdir is None:
- os.system(rndc + " unfreeze " + lp.get("realm"))
-
-
-def create_dns_update_list(lp, logger, paths):
- """Write out a dns_update_list file"""
- # note that we use no variable substitution on this file
- # the substitution is done at runtime by samba_dnsupdate
- setup_file(setup_path("dns_update_list"), paths.dns_update_list, None)
- setup_file(setup_path("spn_update_list"), paths.spn_update_list, None)
-
-
-def create_named_conf(paths, realm, dnsdomain,
- private_dir):
- """Write out a file containing zone statements suitable for inclusion in a
- named.conf file (including GSS-TSIG configuration).
-
- :param paths: all paths
- :param realm: Realm name
- :param dnsdomain: DNS Domain name
- :param private_dir: Path to private directory
- :param keytab_name: File name of DNS keytab file
- """
-
- setup_file(setup_path("named.conf"), paths.namedconf, {
- "DNSDOMAIN": dnsdomain,
- "REALM": realm,
- "ZONE_FILE": paths.dns,
- "REALM_WC": "*." + ".".join(realm.split(".")[1:]),
- "NAMED_CONF": paths.namedconf,
- "NAMED_CONF_UPDATE": paths.namedconf_update
- })
-
- setup_file(setup_path("named.conf.update"), paths.namedconf_update)
-
-
-def create_named_txt(path, realm, dnsdomain, private_dir,
- keytab_name):
- """Write out a file containing zone statements suitable for inclusion in a
- named.conf file (including GSS-TSIG configuration).
-
- :param path: Path of the new named.conf file.
- :param realm: Realm name
- :param dnsdomain: DNS Domain name
- :param private_dir: Path to private directory
- :param keytab_name: File name of DNS keytab file
- """
- setup_file(setup_path("named.txt"), path, {
- "DNSDOMAIN": dnsdomain,
- "REALM": realm,
- "DNS_KEYTAB": keytab_name,
- "DNS_KEYTAB_ABS": os.path.join(private_dir, keytab_name),
- "PRIVATE_DIR": private_dir
- })
-
-
-def create_krb5_conf(path, dnsdomain, hostname, realm):
- """Write out a file containing zone statements suitable for inclusion in a
- named.conf file (including GSS-TSIG configuration).
-
- :param path: Path of the new named.conf file.
- :param dnsdomain: DNS Domain name
- :param hostname: Local hostname
- :param realm: Realm name
- """
- setup_file(setup_path("krb5.conf"), path, {
- "DNSDOMAIN": dnsdomain,
- "HOSTNAME": hostname,
- "REALM": realm,
- })
-
-
-class ProvisioningError(Exception):
- """A generic provision error."""
-
- def __init__(self, value):
- self.value = value
-
- def __str__(self):
- return "ProvisioningError: " + self.value
-
-
-class InvalidNetbiosName(Exception):
- """A specified name was not a valid NetBIOS name."""
- def __init__(self, name):
- super(InvalidNetbiosName, self).__init__(
- "The name '%r' is not a valid NetBIOS name" % name)
diff --git a/source4/scripting/python/samba/provision/backend.py b/source4/scripting/python/samba/provision/backend.py
deleted file mode 100644
index f9dbba85f6..0000000000
--- a/source4/scripting/python/samba/provision/backend.py
+++ /dev/null
@@ -1,772 +0,0 @@
-#
-# Unix SMB/CIFS implementation.
-# backend code for provisioning a Samba4 server
-
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
-# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008-2009
-# Copyright (C) Oliver Liebel <oliver@itc.li> 2008-2009
-#
-# Based on the original in EJS:
-# Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
-#
-# 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/>.
-#
-
-"""Functions for setting up a Samba configuration (LDB and LDAP backends)."""
-
-from base64 import b64encode
-import errno
-import ldb
-import os
-import sys
-import uuid
-import time
-import shutil
-import subprocess
-import urllib
-
-from ldb import SCOPE_BASE, SCOPE_ONELEVEL, LdbError, timestring
-
-from samba import Ldb, read_and_sub_file, setup_file
-from samba.credentials import Credentials, DONT_USE_KERBEROS
-from samba.schema import Schema
-
-class SlapdAlreadyRunning(Exception):
-
- def __init__(self, uri):
- self.ldapi_uri = uri
- super(SlapdAlreadyRunning, self).__init__("Another slapd Instance "
- "seems already running on this host, listening to %s." %
- self.ldapi_uri)
-
-
-class ProvisionBackend(object):
- def __init__(self, backend_type, paths=None, lp=None,
- credentials=None, names=None, logger=None):
- """Provision a backend for samba4"""
- self.paths = paths
- self.lp = lp
- self.credentials = credentials
- self.names = names
- self.logger = logger
-
- self.type = backend_type
-
- # Set a default - the code for "existing" below replaces this
- self.ldap_backend_type = backend_type
-
- def init(self):
- """Initialize the backend."""
- raise NotImplementedError(self.init)
-
- def start(self):
- """Start the backend."""
- raise NotImplementedError(self.start)
-
- def shutdown(self):
- """Shutdown the backend."""
- raise NotImplementedError(self.shutdown)
-
- def post_setup(self):
- """Post setup."""
- raise NotImplementedError(self.post_setup)
-
-
-class LDBBackend(ProvisionBackend):
-
- def init(self):
- self.credentials = None
- self.secrets_credentials = None
-
- # Wipe the old sam.ldb databases away
- shutil.rmtree(self.paths.samdb + ".d", True)
-
- def start(self):
- pass
-
- def shutdown(self):
- pass
-
- def post_setup(self):
- pass
-
-
-class ExistingBackend(ProvisionBackend):
-
- def __init__(self, backend_type, paths=None, lp=None,
- credentials=None, names=None, logger=None, ldapi_uri=None):
-
- super(ExistingBackend, self).__init__(backend_type=backend_type,
- paths=paths, lp=lp,
- credentials=credentials, names=names, logger=logger,
- ldap_backend_forced_uri=ldapi_uri)
-
- def init(self):
- # Check to see that this 'existing' LDAP backend in fact exists
- ldapi_db = Ldb(self.ldapi_uri, credentials=self.credentials)
- ldapi_db.search(base="", scope=SCOPE_BASE,
- expression="(objectClass=OpenLDAProotDSE)")
-
- # If we have got here, then we must have a valid connection to the LDAP
- # server, with valid credentials supplied This caused them to be set
- # into the long-term database later in the script.
- self.secrets_credentials = self.credentials
-
- # For now, assume existing backends at least emulate OpenLDAP
- self.ldap_backend_type = "openldap"
-
-
-class LDAPBackend(ProvisionBackend):
-
- def __init__(self, backend_type, paths=None, lp=None,
- credentials=None, names=None, logger=None, domainsid=None,
- schema=None, hostname=None, ldapadminpass=None,
- slapd_path=None, ldap_backend_extra_port=None,
- ldap_backend_forced_uri=None, ldap_dryrun_mode=False):
-
- super(LDAPBackend, self).__init__(backend_type=backend_type,
- paths=paths, lp=lp,
- credentials=credentials, names=names, logger=logger)
-
- self.domainsid = domainsid
- self.schema = schema
- self.hostname = hostname
-
- self.ldapdir = os.path.join(paths.private_dir, "ldap")
- self.ldapadminpass = ldapadminpass
-
- self.slapd_path = slapd_path
- self.slapd_command = None
- self.slapd_command_escaped = None
- self.slapd_pid = os.path.join(self.ldapdir, "slapd.pid")
-
- self.ldap_backend_extra_port = ldap_backend_extra_port
- self.ldap_dryrun_mode = ldap_dryrun_mode
-
- if ldap_backend_forced_uri is not None:
- self.ldap_uri = ldap_backend_forced_uri
- else:
- self.ldap_uri = "ldapi://%s" % urllib.quote(
- os.path.join(self.ldapdir, "ldapi"), safe="")
-
- if not os.path.exists(self.ldapdir):
- os.mkdir(self.ldapdir)
-
- def init(self):
- from samba.provision import ProvisioningError
- # we will shortly start slapd with ldapi for final provisioning. first
- # check with ldapsearch -> rootDSE via self.ldap_uri if another
- # instance of slapd is already running
- try:
- ldapi_db = Ldb(self.ldap_uri)
- ldapi_db.search(base="", scope=SCOPE_BASE,
- expression="(objectClass=OpenLDAProotDSE)")
- try:
- f = open(self.slapd_pid, "r")
- except IOError, err:
- if err != errno.ENOENT:
- raise
- else:
- p = f.read()
- f.close()
- self.logger.info("Check for slapd Process with PID: %s and terminate it manually." % p)
- raise SlapdAlreadyRunning(self.ldap_uri)
- except LdbError:
- # XXX: We should never be catching all Ldb errors
- pass
-
- # Try to print helpful messages when the user has not specified the
- # path to slapd
- if self.slapd_path is None:
- raise ProvisioningError("Warning: LDAP-Backend must be setup with path to slapd, e.g. --slapd-path=\"/usr/local/libexec/slapd\"!")
- if not os.path.exists(self.slapd_path):
- self.logger.warning("Path (%s) to slapd does not exist!",
- self.slapd_path)
-
- if not os.path.isdir(self.ldapdir):
- os.makedirs(self.ldapdir, 0700)
-
- # Put the LDIF of the schema into a database so we can search on
- # it to generate schema-dependent configurations in Fedora DS and
- # OpenLDAP
- schemadb_path = os.path.join(self.ldapdir, "schema-tmp.ldb")
- try:
- os.unlink(schemadb_path)
- except OSError:
- pass
-
- self.schema.write_to_tmp_ldb(schemadb_path)
-
- self.credentials = Credentials()
- self.credentials.guess(self.lp)
- # Kerberos to an ldapi:// backend makes no sense
- self.credentials.set_kerberos_state(DONT_USE_KERBEROS)
- self.credentials.set_password(self.ldapadminpass)
-
- self.secrets_credentials = Credentials()
- self.secrets_credentials.guess(self.lp)
- # Kerberos to an ldapi:// backend makes no sense
- self.secrets_credentials.set_kerberos_state(DONT_USE_KERBEROS)
- self.secrets_credentials.set_username("samba-admin")
- self.secrets_credentials.set_password(self.ldapadminpass)
-
- self.provision()
-
- def provision(self):
- pass
-
- def start(self):
- from samba.provision import ProvisioningError
- self.slapd_command_escaped = "\'" + "\' \'".join(self.slapd_command) + "\'"
- f = open(os.path.join(self.ldapdir, "ldap_backend_startup.sh"), 'w')
- try:
- f.write("#!/bin/sh\n" + self.slapd_command_escaped + "\n")
- finally:
- f.close()
-
- # Now start the slapd, so we can provision onto it. We keep the
- # subprocess context around, to kill this off at the successful
- # end of the script
- self.slapd = subprocess.Popen(self.slapd_provision_command,
- close_fds=True, shell=False)
-
- count = 0
- while self.slapd.poll() is None:
- # Wait until the socket appears
- try:
- ldapi_db = Ldb(self.ldap_uri, lp=self.lp, credentials=self.credentials)
- ldapi_db.search(base="", scope=SCOPE_BASE,
- expression="(objectClass=OpenLDAProotDSE)")
- # If we have got here, then we must have a valid connection to
- # the LDAP server!
- return
- except LdbError:
- time.sleep(1)
- count = count + 1
-
- if count > 15:
- self.logger.error("Could not connect to slapd started with: %s" % "\'" + "\' \'".join(self.slapd_provision_command) + "\'")
- raise ProvisioningError("slapd never accepted a connection within 15 seconds of starting")
-
- self.logger.error("Could not start slapd with: %s" % "\'" + "\' \'".join(self.slapd_provision_command) + "\'")
- raise ProvisioningError("slapd died before we could make a connection to it")
-
- def shutdown(self):
- # if an LDAP backend is in use, terminate slapd after final provision
- # and check its proper termination
- if self.slapd.poll() is None:
- # Kill the slapd
- if getattr(self.slapd, "terminate", None) is not None:
- self.slapd.terminate()
- else:
- # Older python versions don't have .terminate()
- import signal
- os.kill(self.slapd.pid, signal.SIGTERM)
-
- # and now wait for it to die
- self.slapd.communicate()
-
- def post_setup(self):
- pass
-
-
-class OpenLDAPBackend(LDAPBackend):
-
- def __init__(self, backend_type, paths=None, lp=None,
- credentials=None, names=None, logger=None, domainsid=None,
- schema=None, hostname=None, ldapadminpass=None, slapd_path=None,
- ldap_backend_extra_port=None, ldap_dryrun_mode=False,
- ol_mmr_urls=None, nosync=False, ldap_backend_forced_uri=None):
- from samba.provision import setup_path
- super(OpenLDAPBackend, self).__init__( backend_type=backend_type,
- paths=paths, lp=lp,
- credentials=credentials, names=names, logger=logger,
- domainsid=domainsid, schema=schema, hostname=hostname,
- ldapadminpass=ldapadminpass, slapd_path=slapd_path,
- ldap_backend_extra_port=ldap_backend_extra_port,
- ldap_backend_forced_uri=ldap_backend_forced_uri,
- ldap_dryrun_mode=ldap_dryrun_mode)
-
- self.ol_mmr_urls = ol_mmr_urls
- self.nosync = nosync
-
- self.slapdconf = os.path.join(self.ldapdir, "slapd.conf")
- self.modulesconf = os.path.join(self.ldapdir, "modules.conf")
- self.memberofconf = os.path.join(self.ldapdir, "memberof.conf")
- self.olmmrserveridsconf = os.path.join(self.ldapdir, "mmr_serverids.conf")
- self.olmmrsyncreplconf = os.path.join(self.ldapdir, "mmr_syncrepl.conf")
- self.olcdir = os.path.join(self.ldapdir, "slapd.d")
- self.olcseedldif = os.path.join(self.ldapdir, "olc_seed.ldif")
-
- self.schema = Schema(self.domainsid,
- schemadn=self.names.schemadn, files=[
- setup_path("schema_samba4.ldif")])
-
- def setup_db_config(self, dbdir):
- """Setup a Berkeley database.
-
- :param dbdir: Database directory.
- """
- from samba.provision import setup_path
- if not os.path.isdir(os.path.join(dbdir, "bdb-logs")):
- os.makedirs(os.path.join(dbdir, "bdb-logs"), 0700)
- if not os.path.isdir(os.path.join(dbdir, "tmp")):
- os.makedirs(os.path.join(dbdir, "tmp"), 0700)
-
- setup_file(setup_path("DB_CONFIG"),
- os.path.join(dbdir, "DB_CONFIG"), {"LDAPDBDIR": dbdir})
-
- def provision(self):
- from samba.provision import ProvisioningError, setup_path
- # Wipe the directories so we can start
- shutil.rmtree(os.path.join(self.ldapdir, "db"), True)
-
- # Allow the test scripts to turn off fsync() for OpenLDAP as for TDB
- # and LDB
- nosync_config = ""
- if self.nosync:
- nosync_config = "dbnosync"
-
- lnkattr = self.schema.linked_attributes()
- refint_attributes = ""
- memberof_config = "# Generated from Samba4 schema\n"
- for att in lnkattr.keys():
- if lnkattr[att] is not None:
- refint_attributes = refint_attributes + " " + att
-
- memberof_config += read_and_sub_file(
- setup_path("memberof.conf"), {
- "MEMBER_ATTR": att,
- "MEMBEROF_ATTR" : lnkattr[att] })
-
- refint_config = read_and_sub_file(setup_path("refint.conf"),
- { "LINK_ATTRS" : refint_attributes})
-
- attrs = ["linkID", "lDAPDisplayName"]
- res = self.schema.ldb.search(expression="(&(objectclass=attributeSchema)(searchFlags:1.2.840.113556.1.4.803:=1))", base=self.names.schemadn, scope=SCOPE_ONELEVEL, attrs=attrs)
- index_config = ""
- for i in range (0, len(res)):
- index_attr = res[i]["lDAPDisplayName"][0]
- if index_attr == "objectGUID":
- index_attr = "entryUUID"
-
- index_config += "index " + index_attr + " eq\n"
-
- # generate serverids, ldap-urls and syncrepl-blocks for mmr hosts
- mmr_on_config = ""
- mmr_replicator_acl = ""
- mmr_serverids_config = ""
- mmr_syncrepl_schema_config = ""
- mmr_syncrepl_config_config = ""
- mmr_syncrepl_user_config = ""
-
- if self.ol_mmr_urls is not None:
- # For now, make these equal
- mmr_pass = self.ldapadminpass
-
- url_list = filter(None,self.ol_mmr_urls.split(','))
- for url in url_list:
- self.logger.info("Using LDAP-URL: "+url)
- if len(url_list) == 1:
- raise ProvisioningError("At least 2 LDAP-URLs needed for MMR!")
-
- mmr_on_config = "MirrorMode On"
- mmr_replicator_acl = " by dn=cn=replicator,cn=samba read"
- serverid = 0
- for url in url_list:
- serverid = serverid + 1
- mmr_serverids_config += read_and_sub_file(
- setup_path("mmr_serverids.conf"), {
- "SERVERID": str(serverid),
- "LDAPSERVER": url })
- rid = serverid * 10
- rid = rid + 1
- mmr_syncrepl_schema_config += read_and_sub_file(
- setup_path("mmr_syncrepl.conf"), {
- "RID" : str(rid),
- "MMRDN": self.names.schemadn,
- "LDAPSERVER" : url,
- "MMR_PASSWORD": mmr_pass})
-
- rid = rid + 1
- mmr_syncrepl_config_config += read_and_sub_file(
- setup_path("mmr_syncrepl.conf"), {
- "RID" : str(rid),
- "MMRDN": self.names.configdn,
- "LDAPSERVER" : url,
- "MMR_PASSWORD": mmr_pass})
-
- rid = rid + 1
- mmr_syncrepl_user_config += read_and_sub_file(
- setup_path("mmr_syncrepl.conf"), {
- "RID" : str(rid),
- "MMRDN": self.names.domaindn,
- "LDAPSERVER" : url,
- "MMR_PASSWORD": mmr_pass })
- # OpenLDAP cn=config initialisation
- olc_syncrepl_config = ""
- olc_mmr_config = ""
- # if mmr = yes, generate cn=config-replication directives
- # and olc_seed.lif for the other mmr-servers
- if self.ol_mmr_urls is not None:
- serverid = 0
- olc_serverids_config = ""
- olc_syncrepl_seed_config = ""
- olc_mmr_config += read_and_sub_file(
- setup_path("olc_mmr.conf"), {})
- rid = 500
- for url in url_list:
- serverid = serverid + 1
- olc_serverids_config += read_and_sub_file(
- setup_path("olc_serverid.conf"), {
- "SERVERID" : str(serverid), "LDAPSERVER" : url })
-
- rid = rid + 1
- olc_syncrepl_config += read_and_sub_file(
- setup_path("olc_syncrepl.conf"), {
- "RID" : str(rid), "LDAPSERVER" : url,
- "MMR_PASSWORD": mmr_pass})
-
- olc_syncrepl_seed_config += read_and_sub_file(
- setup_path("olc_syncrepl_seed.conf"), {
- "RID" : str(rid), "LDAPSERVER" : url})
-
- setup_file(setup_path("olc_seed.ldif"), self.olcseedldif,
- {"OLC_SERVER_ID_CONF": olc_serverids_config,
- "OLC_PW": self.ldapadminpass,
- "OLC_SYNCREPL_CONF": olc_syncrepl_seed_config})
- # end olc
-
- setup_file(setup_path("slapd.conf"), self.slapdconf,
- {"DNSDOMAIN": self.names.dnsdomain,
- "LDAPDIR": self.ldapdir,
- "DOMAINDN": self.names.domaindn,
- "CONFIGDN": self.names.configdn,
- "SCHEMADN": self.names.schemadn,
- "MEMBEROF_CONFIG": memberof_config,
- "MIRRORMODE": mmr_on_config,
- "REPLICATOR_ACL": mmr_replicator_acl,
- "MMR_SERVERIDS_CONFIG": mmr_serverids_config,
- "MMR_SYNCREPL_SCHEMA_CONFIG": mmr_syncrepl_schema_config,
- "MMR_SYNCREPL_CONFIG_CONFIG": mmr_syncrepl_config_config,
- "MMR_SYNCREPL_USER_CONFIG": mmr_syncrepl_user_config,
- "OLC_SYNCREPL_CONFIG": olc_syncrepl_config,
- "OLC_MMR_CONFIG": olc_mmr_config,
- "REFINT_CONFIG": refint_config,
- "INDEX_CONFIG": index_config,
- "NOSYNC": nosync_config})
-
- self.setup_db_config(os.path.join(self.ldapdir, "db", "user"))
- self.setup_db_config(os.path.join(self.ldapdir, "db", "config"))
- self.setup_db_config(os.path.join(self.ldapdir, "db", "schema"))
-
- if not os.path.exists(os.path.join(self.ldapdir, "db", "samba", "cn=samba")):
- os.makedirs(os.path.join(self.ldapdir, "db", "samba", "cn=samba"), 0700)
-
- setup_file(setup_path("cn=samba.ldif"),
- os.path.join(self.ldapdir, "db", "samba", "cn=samba.ldif"),
- { "UUID": str(uuid.uuid4()),
- "LDAPTIME": timestring(int(time.time()))} )
- setup_file(setup_path("cn=samba-admin.ldif"),
- os.path.join(self.ldapdir, "db", "samba", "cn=samba", "cn=samba-admin.ldif"),
- {"LDAPADMINPASS_B64": b64encode(self.ldapadminpass),
- "UUID": str(uuid.uuid4()),
- "LDAPTIME": timestring(int(time.time()))} )
-
- if self.ol_mmr_urls is not None:
- setup_file(setup_path("cn=replicator.ldif"),
- os.path.join(self.ldapdir, "db", "samba", "cn=samba", "cn=replicator.ldif"),
- {"MMR_PASSWORD_B64": b64encode(mmr_pass),
- "UUID": str(uuid.uuid4()),
- "LDAPTIME": timestring(int(time.time()))} )
-
- mapping = "schema-map-openldap-2.3"
- backend_schema = "backend-schema.schema"
-
- f = open(setup_path(mapping), 'r')
- backend_schema_data = self.schema.convert_to_openldap(
- "openldap", f.read())
- assert backend_schema_data is not None
- f = open(os.path.join(self.ldapdir, backend_schema), 'w')
- try:
- f.write(backend_schema_data)
- finally:
- f.close()
-
- # now we generate the needed strings to start slapd automatically,
- if self.ldap_backend_extra_port is not None:
- # When we use MMR, we can't use 0.0.0.0 as it uses the name
- # specified there as part of it's clue as to it's own name,
- # and not to replicate to itself
- if self.ol_mmr_urls is None:
- server_port_string = "ldap://0.0.0.0:%d" % self.ldap_backend_extra_port
- else:
- server_port_string = "ldap://%s.%s:%d" (self.names.hostname,
- self.names.dnsdomain, self.ldap_backend_extra_port)
- else:
- server_port_string = ""
-
- # Prepare the 'result' information - the commands to return in
- # particular
- self.slapd_provision_command = [self.slapd_path, "-F" + self.olcdir,
- "-h"]
-
- # copy this command so we have two version, one with -d0 and only
- # ldapi (or the forced ldap_uri), and one with all the listen commands
- self.slapd_command = list(self.slapd_provision_command)
-
- self.slapd_provision_command.extend([self.ldap_uri, "-d0"])
-
- uris = self.ldap_uri
- if server_port_string is not "":
- uris = uris + " " + server_port_string
-
- self.slapd_command.append(uris)
-
- # Set the username - done here because Fedora DS still uses the admin
- # DN and simple bind
- self.credentials.set_username("samba-admin")
-
- # Wipe the old sam.ldb databases away
- shutil.rmtree(self.olcdir, True)
- os.makedirs(self.olcdir, 0770)
-
- # If we were just looking for crashes up to this point, it's a
- # good time to exit before we realise we don't have OpenLDAP on
- # this system
- if self.ldap_dryrun_mode:
- sys.exit(0)
-
- slapd_cmd = [self.slapd_path, "-Ttest", "-n", "0", "-f",
- self.slapdconf, "-F", self.olcdir]
- retcode = subprocess.call(slapd_cmd, close_fds=True, shell=False)
-
- if retcode != 0:
- self.logger.error("conversion from slapd.conf to cn=config failed slapd started with: %s" % "\'" + "\' \'".join(slapd_cmd) + "\'")
- raise ProvisioningError("conversion from slapd.conf to cn=config failed")
-
- if not os.path.exists(os.path.join(self.olcdir, "cn=config.ldif")):
- raise ProvisioningError("conversion from slapd.conf to cn=config failed")
-
- # Don't confuse the admin by leaving the slapd.conf around
- os.remove(self.slapdconf)
-
-
-class FDSBackend(LDAPBackend):
-
- def __init__(self, backend_type, paths=None, lp=None,
- credentials=None, names=None, logger=None, domainsid=None,
- schema=None, hostname=None, ldapadminpass=None, slapd_path=None,
- ldap_backend_extra_port=None, ldap_dryrun_mode=False, root=None,
- setup_ds_path=None):
-
- from samba.provision import setup_path
-
- super(FDSBackend, self).__init__(backend_type=backend_type,
- paths=paths, lp=lp,
- credentials=credentials, names=names, logger=logger,
- domainsid=domainsid, schema=schema, hostname=hostname,
- ldapadminpass=ldapadminpass, slapd_path=slapd_path,
- ldap_backend_extra_port=ldap_backend_extra_port,
- ldap_backend_forced_uri=ldap_backend_forced_uri,
- ldap_dryrun_mode=ldap_dryrun_mode)
-
- self.root = root
- self.setup_ds_path = setup_ds_path
- self.ldap_instance = self.names.netbiosname.lower()
-
- self.sambadn = "CN=Samba"
-
- self.fedoradsinf = os.path.join(self.ldapdir, "fedorads.inf")
- self.partitions_ldif = os.path.join(self.ldapdir,
- "fedorads-partitions.ldif")
- self.sasl_ldif = os.path.join(self.ldapdir, "fedorads-sasl.ldif")
- self.dna_ldif = os.path.join(self.ldapdir, "fedorads-dna.ldif")
- self.pam_ldif = os.path.join(self.ldapdir, "fedorads-pam.ldif")
- self.refint_ldif = os.path.join(self.ldapdir, "fedorads-refint.ldif")
- self.linked_attrs_ldif = os.path.join(self.ldapdir,
- "fedorads-linked-attributes.ldif")
- self.index_ldif = os.path.join(self.ldapdir, "fedorads-index.ldif")
- self.samba_ldif = os.path.join(self.ldapdir, "fedorads-samba.ldif")
-
- self.samba3_schema = setup_path(
- "../../examples/LDAP/samba.schema")
- self.samba3_ldif = os.path.join(self.ldapdir, "samba3.ldif")
-
- self.retcode = subprocess.call(["bin/oLschema2ldif",
- "-I", self.samba3_schema,
- "-O", self.samba3_ldif,
- "-b", self.names.domaindn],
- close_fds=True, shell=False)
-
- if self.retcode != 0:
- raise Exception("Unable to convert Samba 3 schema.")
-
- self.schema = Schema(
- self.domainsid,
- schemadn=self.names.schemadn,
- files=[setup_path("schema_samba4.ldif"), self.samba3_ldif],
- additional_prefixmap=["1000:1.3.6.1.4.1.7165.2.1",
- "1001:1.3.6.1.4.1.7165.2.2"])
-
- def provision(self):
- from samba.provision import ProvisioningError, setup_path
- if self.ldap_backend_extra_port is not None:
- serverport = "ServerPort=%d" % self.ldap_backend_extra_port
- else:
- serverport = ""
-
- setup_file(setup_path("fedorads.inf"), self.fedoradsinf,
- {"ROOT": self.root,
- "HOSTNAME": self.hostname,
- "DNSDOMAIN": self.names.dnsdomain,
- "LDAPDIR": self.ldapdir,
- "DOMAINDN": self.names.domaindn,
- "LDAP_INSTANCE": self.ldap_instance,
- "LDAPMANAGERDN": self.names.ldapmanagerdn,
- "LDAPMANAGERPASS": self.ldapadminpass,
- "SERVERPORT": serverport})
-
- setup_file(setup_path("fedorads-partitions.ldif"),
- self.partitions_ldif,
- {"CONFIGDN": self.names.configdn,
- "SCHEMADN": self.names.schemadn,
- "SAMBADN": self.sambadn,
- })
-
- setup_file(setup_path("fedorads-sasl.ldif"), self.sasl_ldif,
- {"SAMBADN": self.sambadn,
- })
-
- setup_file(setup_path("fedorads-dna.ldif"), self.dna_ldif,
- {"DOMAINDN": self.names.domaindn,
- "SAMBADN": self.sambadn,
- "DOMAINSID": str(self.domainsid),
- })
-
- setup_file(setup_path("fedorads-pam.ldif"), self.pam_ldif)
-
- lnkattr = self.schema.linked_attributes()
-
- refint_config = open(setup_path("fedorads-refint-delete.ldif"), 'r').read()
- memberof_config = ""
- index_config = ""
- argnum = 3
-
- for attr in lnkattr.keys():
- if lnkattr[attr] is not None:
- refint_config += read_and_sub_file(
- setup_path("fedorads-refint-add.ldif"),
- { "ARG_NUMBER" : str(argnum),
- "LINK_ATTR" : attr })
- memberof_config += read_and_sub_file(
- setup_path("fedorads-linked-attributes.ldif"),
- { "MEMBER_ATTR" : attr,
- "MEMBEROF_ATTR" : lnkattr[attr] })
- index_config += read_and_sub_file(
- setup_path("fedorads-index.ldif"), { "ATTR" : attr })
- argnum += 1
-
- open(self.refint_ldif, 'w').write(refint_config)
- open(self.linked_attrs_ldif, 'w').write(memberof_config)
-
- attrs = ["lDAPDisplayName"]
- res = self.schema.ldb.search(expression="(&(objectclass=attributeSchema)(searchFlags:1.2.840.113556.1.4.803:=1))", base=self.names.schemadn, scope=SCOPE_ONELEVEL, attrs=attrs)
-
- for i in range (0, len(res)):
- attr = res[i]["lDAPDisplayName"][0]
-
- if attr == "objectGUID":
- attr = "nsUniqueId"
-
- index_config += read_and_sub_file(
- setup_path("fedorads-index.ldif"), { "ATTR" : attr })
-
- open(self.index_ldif, 'w').write(index_config)
-
- setup_file(setup_path("fedorads-samba.ldif"), self.samba_ldif, {
- "SAMBADN": self.sambadn,
- "LDAPADMINPASS": self.ldapadminpass
- })
-
- mapping = "schema-map-fedora-ds-1.0"
- backend_schema = "99_ad.ldif"
-
- # Build a schema file in Fedora DS format
- backend_schema_data = self.schema.convert_to_openldap("fedora-ds",
- open(setup_path(mapping), 'r').read())
- assert backend_schema_data is not None
- f = open(os.path.join(self.ldapdir, backend_schema), 'w')
- try:
- f.write(backend_schema_data)
- finally:
- f.close()
-
- self.credentials.set_bind_dn(self.names.ldapmanagerdn)
-
- # Destory the target directory, or else setup-ds.pl will complain
- fedora_ds_dir = os.path.join(self.ldapdir,
- "slapd-" + self.ldap_instance)
- shutil.rmtree(fedora_ds_dir, True)
-
- self.slapd_provision_command = [self.slapd_path, "-D", fedora_ds_dir,
- "-i", self.slapd_pid]
- # In the 'provision' command line, stay in the foreground so we can
- # easily kill it
- self.slapd_provision_command.append("-d0")
-
- #the command for the final run is the normal script
- self.slapd_command = [os.path.join(self.ldapdir,
- "slapd-" + self.ldap_instance, "start-slapd")]
-
- # If we were just looking for crashes up to this point, it's a
- # good time to exit before we realise we don't have Fedora DS on
- if self.ldap_dryrun_mode:
- sys.exit(0)
-
- # Try to print helpful messages when the user has not specified the
- # path to the setup-ds tool
- if self.setup_ds_path is None:
- raise ProvisioningError("Fedora DS LDAP-Backend must be setup with path to setup-ds, e.g. --setup-ds-path=\"/usr/sbin/setup-ds.pl\"!")
- if not os.path.exists(self.setup_ds_path):
- self.logger.warning("Path (%s) to slapd does not exist!",
- self.setup_ds_path)
-
- # Run the Fedora DS setup utility
- retcode = subprocess.call([self.setup_ds_path, "--silent", "--file",
- self.fedoradsinf], close_fds=True, shell=False)
- if retcode != 0:
- raise ProvisioningError("setup-ds failed")
-
- # Load samba-admin
- retcode = subprocess.call([
- os.path.join(self.ldapdir, "slapd-" + self.ldap_instance, "ldif2db"), "-s", self.sambadn, "-i", self.samba_ldif],
- close_fds=True, shell=False)
- if retcode != 0:
- raise ProvisioningError("ldif2db failed")
-
- def post_setup(self):
- ldapi_db = Ldb(self.ldap_uri, credentials=self.credentials)
-
- # configure in-directory access control on Fedora DS via the aci
- # attribute (over a direct ldapi:// socket)
- aci = """(targetattr = "*") (version 3.0;acl "full access to all by samba-admin";allow (all)(userdn = "ldap:///CN=samba-admin,%s");)""" % self.sambadn
-
- m = ldb.Message()
- m["aci"] = ldb.MessageElement([aci], ldb.FLAG_MOD_REPLACE, "aci")
-
- for dnstring in (self.names.domaindn, self.names.configdn,
- self.names.schemadn):
- m.dn = ldb.Dn(ldapi_db, dnstring)
- ldapi_db.modify(m)
diff --git a/source4/scripting/python/samba/samba3.py b/source4/scripting/python/samba/samba3.py
index 2c323bd0b4..179efa2700 100644
--- a/source4/scripting/python/samba/samba3.py
+++ b/source4/scripting/python/samba/samba3.py
@@ -1,16 +1,18 @@
+#!/usr/bin/python
+
# Unix SMB/CIFS implementation.
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
-#
+#
# 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/>.
#
@@ -65,7 +67,7 @@ class TdbDatabase(object):
class Registry(TdbDatabase):
"""Simple read-only support for reading the Samba3 registry.
-
+
:note: This object uses the same syntax for registry key paths as
Samba 3. This particular format uses forward slashes for key path
separators and abbreviations for the predefined key names.
@@ -681,7 +683,7 @@ class ParamFile(object):
section = None
for i, l in enumerate(open(filename, 'r').xreadlines()):
l = l.strip()
- if not l or l[0] == '#' or l[0] == ';':
+ if not l:
continue
if l[0] == "[" and l[-1] == "]":
section = self._sanitize_name(l[1:-1])
@@ -767,7 +769,7 @@ class Samba3(object):
def get_policy_db(self):
return PolicyDatabase(self.libdir_path("account_policy.tdb"))
-
+
def get_registry(self):
return Registry(self.libdir_path("registry.tdb"))
diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py
index 99f141e664..39cf1d6c40 100644
--- a/source4/scripting/python/samba/samdb.py
+++ b/source4/scripting/python/samba/samdb.py
@@ -1,22 +1,22 @@
-#!/usr/bin/env python
+#!/usr/bin/python
# Unix SMB/CIFS implementation.
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2010
+# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
# Copyright (C) Matthias Dieter Wallnoefer 2009
#
# Based on the original in EJS:
# Copyright (C) Andrew Tridgell <tridge@samba.org> 2005
-#
+#
# 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/>.
#
@@ -24,71 +24,62 @@
"""Convenience functions for using the SAM."""
import samba
+import glue
import ldb
+from samba.idmap import IDmapDB
+import pwd
import time
import base64
-from samba import dsdb
-from samba.ndr import ndr_unpack, ndr_pack
-from samba.dcerpc import drsblobs, misc
__docformat__ = "restructuredText"
-
class SamDB(samba.Ldb):
"""The SAM database."""
- hash_oid_name = {}
-
def __init__(self, url=None, lp=None, modules_dir=None, session_info=None,
- credentials=None, flags=0, options=None, global_schema=True,
- auto_connect=True, am_rodc=None):
+ credentials=None, flags=0, options=None):
+ """Opens the SAM Database
+ For parameter meanings see the super class (samba.Ldb)
+ """
+
self.lp = lp
- if not auto_connect:
- url = None
- elif url is None and lp is not None:
- url = lp.get("sam database")
+ if url is None:
+ url = lp.get("sam database")
super(SamDB, self).__init__(url=url, lp=lp, modules_dir=modules_dir,
- session_info=session_info, credentials=credentials, flags=flags,
- options=options)
-
- if global_schema:
- dsdb._dsdb_set_global_schema(self)
+ session_info=session_info, credentials=credentials, flags=flags,
+ options=options)
- if am_rodc is not None:
- dsdb._dsdb_set_am_rodc(self, am_rodc)
+ glue.dsdb_set_global_schema(self)
def connect(self, url=None, flags=0, options=None):
- if self.lp is not None:
- url = self.lp.private_path(url)
-
- super(SamDB, self).connect(url=url, flags=flags,
+ super(SamDB, self).connect(url=self.lp.private_path(url), flags=flags,
options=options)
- def am_rodc(self):
- return dsdb._am_rodc(self)
-
def domain_dn(self):
- return str(self.get_default_basedn())
-
- def enable_account(self, search_filter):
+ # find the DNs for the domain
+ res = self.search(base="",
+ scope=ldb.SCOPE_BASE,
+ expression="(defaultNamingContext=*)",
+ attrs=["defaultNamingContext"])
+ assert(len(res) == 1 and res[0]["defaultNamingContext"] is not None)
+ return res[0]["defaultNamingContext"][0]
+
+ def enable_account(self, filter):
"""Enables an account
-
- :param search_filter: LDAP filter to find the user (eg
- samccountname=name)
+
+ :param filter: LDAP filter to find the user (eg samccountname=name)
"""
res = self.search(base=self.domain_dn(), scope=ldb.SCOPE_SUBTREE,
- expression=search_filter, attrs=["userAccountControl"])
+ expression=filter, attrs=["userAccountControl"])
assert(len(res) == 1)
user_dn = res[0].dn
userAccountControl = int(res[0]["userAccountControl"][0])
- if userAccountControl & 0x2:
- # remove disabled bit
- userAccountControl = userAccountControl & ~0x2
- if userAccountControl & 0x20:
- # remove 'no password required' bit
- userAccountControl = userAccountControl & ~0x20
+ if (userAccountControl & 0x2):
+ userAccountControl = userAccountControl & ~0x2 # remove disabled bit
+ if (userAccountControl & 0x20):
+ userAccountControl = userAccountControl & ~0x20 # remove 'no password required' bit
mod = """
dn: %s
@@ -97,15 +88,14 @@ replace: userAccountControl
userAccountControl: %u
""" % (user_dn, userAccountControl)
self.modify_ldif(mod)
-
- def force_password_change_at_next_login(self, search_filter):
+
+ def force_password_change_at_next_login(self, filter):
"""Forces a password change at next login
-
- :param search_filter: LDAP filter to find the user (eg
- samccountname=name)
+
+ :param filter: LDAP filter to find the user (eg samccountname=name)
"""
res = self.search(base=self.domain_dn(), scope=ldb.SCOPE_SUBTREE,
- expression=search_filter, attrs=[])
+ expression=filter, attrs=[])
assert(len(res) == 1)
user_dn = res[0].dn
@@ -117,297 +107,102 @@ pwdLastSet: 0
""" % (user_dn)
self.modify_ldif(mod)
- def newgroup(self, groupname, groupou=None, grouptype=None,
- description=None, mailaddress=None, notes=None, sd=None):
- """Adds a new group with additional parameters
-
- :param groupname: Name of the new group
- :param grouptype: Type of the new group
- :param description: Description of the new group
- :param mailaddress: Email address of the new group
- :param notes: Notes of the new group
- :param sd: security descriptor of the object
- """
-
- group_dn = "CN=%s,%s,%s" % (groupname, (groupou or "CN=Users"), self.domain_dn())
-
- # The new user record. Note the reliance on the SAMLDB module which
- # fills in the default informations
- ldbmessage = {"dn": group_dn,
- "sAMAccountName": groupname,
- "objectClass": "group"}
-
- if grouptype is not None:
- ldbmessage["groupType"] = "%d" % grouptype
-
- if description is not None:
- ldbmessage["description"] = description
-
- if mailaddress is not None:
- ldbmessage["mail"] = mailaddress
-
- if notes is not None:
- ldbmessage["info"] = notes
-
- if sd is not None:
- ldbmessage["nTSecurityDescriptor"] = ndr_pack(sd)
-
- self.add(ldbmessage)
-
- def deletegroup(self, groupname):
- """Deletes a group
-
- :param groupname: Name of the target group
- """
-
- groupfilter = "(&(sAMAccountName=%s)(objectCategory=%s,%s))" % (groupname, "CN=Group,CN=Schema,CN=Configuration", self.domain_dn())
- self.transaction_start()
- try:
- targetgroup = self.search(base=self.domain_dn(), scope=ldb.SCOPE_SUBTREE,
- expression=groupfilter, attrs=[])
- if len(targetgroup) == 0:
- raise Exception('Unable to find group "%s"' % groupname)
- assert(len(targetgroup) == 1)
- self.delete(targetgroup[0].dn)
- except Exception:
- self.transaction_cancel()
- raise
- else:
- self.transaction_commit()
-
- def add_remove_group_members(self, groupname, listofmembers,
- add_members_operation=True):
- """Adds or removes group members
-
- :param groupname: Name of the target group
- :param listofmembers: Comma-separated list of group members
- :param add_members_operation: Defines if its an add or remove
- operation
- """
-
- groupfilter = "(&(sAMAccountName=%s)(objectCategory=%s,%s))" % (groupname, "CN=Group,CN=Schema,CN=Configuration", self.domain_dn())
- groupmembers = listofmembers.split(',')
-
- self.transaction_start()
- try:
- targetgroup = self.search(base=self.domain_dn(), scope=ldb.SCOPE_SUBTREE,
- expression=groupfilter, attrs=['member'])
- if len(targetgroup) == 0:
- raise Exception('Unable to find group "%s"' % groupname)
- assert(len(targetgroup) == 1)
-
- modified = False
-
- addtargettogroup = """
-dn: %s
-changetype: modify
-""" % (str(targetgroup[0].dn))
-
- for member in groupmembers:
- targetmember = self.search(base=self.domain_dn(), scope=ldb.SCOPE_SUBTREE,
- expression="(|(sAMAccountName=%s)(CN=%s))" % (member, member), attrs=[])
-
- if len(targetmember) != 1:
- continue
-
- if add_members_operation is True and (targetgroup[0].get('member') is None or str(targetmember[0].dn) not in targetgroup[0]['member']):
- modified = True
- addtargettogroup += """add: member
-member: %s
-""" % (str(targetmember[0].dn))
-
- elif add_members_operation is False and (targetgroup[0].get('member') is not None and str(targetmember[0].dn) in targetgroup[0]['member']):
- modified = True
- addtargettogroup += """delete: member
-member: %s
-""" % (str(targetmember[0].dn))
-
- if modified is True:
- self.modify_ldif(addtargettogroup)
-
- except Exception:
- self.transaction_cancel()
- raise
- else:
- self.transaction_commit()
-
- def newuser(self, username, password,
- force_password_change_at_next_login_req=False,
- useusernameascn=False, userou=None, surname=None, givenname=None,
- initials=None, profilepath=None, scriptpath=None, homedrive=None,
- homedirectory=None, jobtitle=None, department=None, company=None,
- description=None, mailaddress=None, internetaddress=None,
- telephonenumber=None, physicaldeliveryoffice=None, sd=None,
- setpassword=True):
- """Adds a new user with additional parameters
+ def newuser(self, username, unixname, password, force_password_change_at_next_login_req=False):
+ """Adds a new user
+ Note: This call adds also the ID mapping for winbind; therefore it works
+ *only* on SAMBA 4.
+
:param username: Name of the new user
+ :param unixname: Name of the unix user to map to
:param password: Password for the new user
:param force_password_change_at_next_login_req: Force password change
- :param useusernameascn: Use username as cn rather that firstname +
- initials + lastname
- :param userou: Object container (without domainDN postfix) for new user
- :param surname: Surname of the new user
- :param givenname: First name of the new user
- :param initials: Initials of the new user
- :param profilepath: Profile path of the new user
- :param scriptpath: Logon script path of the new user
- :param homedrive: Home drive of the new user
- :param homedirectory: Home directory of the new user
- :param jobtitle: Job title of the new user
- :param department: Department of the new user
- :param company: Company of the new user
- :param description: of the new user
- :param mailaddress: Email address of the new user
- :param internetaddress: Home page of the new user
- :param telephonenumber: Phone number of the new user
- :param physicaldeliveryoffice: Office location of the new user
- :param sd: security descriptor of the object
- :param setpassword: optionally disable password reset
"""
-
- displayname = ""
- if givenname is not None:
- displayname += givenname
-
- if initials is not None:
- displayname += ' %s.' % initials
-
- if surname is not None:
- displayname += ' %s' % surname
-
- cn = username
- if useusernameascn is None and displayname is not "":
- cn = displayname
-
- user_dn = "CN=%s,%s,%s" % (cn, (userou or "CN=Users"), self.domain_dn())
-
- dnsdomain = ldb.Dn(self, self.domain_dn()).canonical_str().replace("/", "")
- user_principal_name = "%s@%s" % (username, dnsdomain)
- # The new user record. Note the reliance on the SAMLDB module which
- # fills in the default informations
- ldbmessage = {"dn": user_dn,
- "sAMAccountName": username,
- "userPrincipalName": user_principal_name,
- "objectClass": "user"}
-
- if surname is not None:
- ldbmessage["sn"] = surname
-
- if givenname is not None:
- ldbmessage["givenName"] = givenname
-
- if displayname is not "":
- ldbmessage["displayName"] = displayname
- ldbmessage["name"] = displayname
-
- if initials is not None:
- ldbmessage["initials"] = '%s.' % initials
-
- if profilepath is not None:
- ldbmessage["profilePath"] = profilepath
-
- if scriptpath is not None:
- ldbmessage["scriptPath"] = scriptpath
-
- if homedrive is not None:
- ldbmessage["homeDrive"] = homedrive
-
- if homedirectory is not None:
- ldbmessage["homeDirectory"] = homedirectory
-
- if jobtitle is not None:
- ldbmessage["title"] = jobtitle
-
- if department is not None:
- ldbmessage["department"] = department
-
- if company is not None:
- ldbmessage["company"] = company
-
- if description is not None:
- ldbmessage["description"] = description
-
- if mailaddress is not None:
- ldbmessage["mail"] = mailaddress
-
- if internetaddress is not None:
- ldbmessage["wWWHomePage"] = internetaddress
-
- if telephonenumber is not None:
- ldbmessage["telephoneNumber"] = telephonenumber
-
- if physicaldeliveryoffice is not None:
- ldbmessage["physicalDeliveryOfficeName"] = physicaldeliveryoffice
-
- if sd is not None:
- ldbmessage["nTSecurityDescriptor"] = ndr_pack(sd)
-
self.transaction_start()
try:
- self.add(ldbmessage)
+ user_dn = "CN=%s,CN=Users,%s" % (username, self.domain_dn())
+
+ # The new user record. Note the reliance on the SAMLDB module which
+ # fills in the default informations
+ self.add({"dn": user_dn,
+ "sAMAccountName": username,
+ "objectClass": "user"})
# Sets the password for it
- if setpassword:
- self.setpassword("(samAccountName=%s)" % username, password,
- force_password_change_at_next_login_req)
- except Exception:
+ self.setpassword("(dn=" + user_dn + ")", password,
+ force_password_change_at_next_login_req)
+
+ # Gets the user SID (for the account mapping setup)
+ res = self.search(user_dn, scope=ldb.SCOPE_BASE,
+ expression="objectclass=*",
+ attrs=["objectSid"])
+ assert len(res) == 1
+ user_sid = self.schema_format_value("objectSid", res[0]["objectSid"][0])
+
+ try:
+ idmap = IDmapDB(lp=self.lp)
+
+ user = pwd.getpwnam(unixname)
+
+ # setup ID mapping for this UID
+ idmap.setup_name_mapping(user_sid, idmap.TYPE_UID, user[2])
+
+ except KeyError:
+ pass
+ except:
self.transaction_cancel()
raise
- else:
- self.transaction_commit()
+ self.transaction_commit()
- def setpassword(self, search_filter, password,
- force_change_at_next_login=False, username=None):
+ def setpassword(self, filter, password, force_password_change_at_next_login_req=False):
"""Sets the password for a user
+
+ Note: This call uses the "userPassword" attribute to set the password.
+ This works correctly on SAMBA 4 and on Windows DCs with
+ "2003 Native" or higer domain function level.
- :param search_filter: LDAP filter to find the user (eg
- samccountname=name)
+ :param filter: LDAP filter to find the user (eg samccountname=name)
:param password: Password for the user
- :param force_change_at_next_login: Force password change
+ :param force_password_change_at_next_login_req: Force password change
"""
self.transaction_start()
try:
res = self.search(base=self.domain_dn(), scope=ldb.SCOPE_SUBTREE,
- expression=search_filter, attrs=[])
- if len(res) == 0:
- raise Exception('Unable to find user "%s"' % (username or search_filter))
- if len(res) > 1:
- raise Exception('Matched %u multiple users with filter "%s"' % (len(res), search_filter))
+ expression=filter, attrs=[])
+ assert(len(res) == 1)
user_dn = res[0].dn
+
setpw = """
dn: %s
changetype: modify
-replace: unicodePwd
-unicodePwd:: %s
-""" % (user_dn, base64.b64encode(("\"" + password + "\"").encode('utf-16-le')))
+replace: userPassword
+userPassword:: %s
+""" % (user_dn, base64.b64encode(password))
self.modify_ldif(setpw)
- if force_change_at_next_login:
+ if force_password_change_at_next_login_req:
self.force_password_change_at_next_login(
"(dn=" + str(user_dn) + ")")
# modify the userAccountControl to remove the disabled bit
- self.enable_account(search_filter)
- except Exception:
+ self.enable_account(filter)
+ except:
self.transaction_cancel()
raise
- else:
- self.transaction_commit()
+ self.transaction_commit()
- def setexpiry(self, search_filter, expiry_seconds, no_expiry_req=False):
+ def setexpiry(self, filter, expiry_seconds, no_expiry_req=False):
"""Sets the account expiry for a user
-
- :param search_filter: LDAP filter to find the user (eg
- samaccountname=name)
+
+ :param filter: LDAP filter to find the user (eg samccountname=name)
:param expiry_seconds: expiry time from now in seconds
:param no_expiry_req: if set, then don't expire password
"""
self.transaction_start()
try:
res = self.search(base=self.domain_dn(), scope=ldb.SCOPE_SUBTREE,
- expression=search_filter,
+ expression=filter,
attrs=["userAccountControl", "accountExpires"])
assert(len(res) == 1)
user_dn = res[0].dn
@@ -419,7 +214,7 @@ unicodePwd:: %s
accountExpires = 0
else:
userAccountControl = userAccountControl & ~0x10000
- accountExpires = samba.unix2nttime(expiry_seconds + int(time.time()))
+ accountExpires = glue.unix2nttime(expiry_seconds + int(time.time()))
setexp = """
dn: %s
@@ -431,283 +226,8 @@ accountExpires: %u
""" % (user_dn, userAccountControl, accountExpires)
self.modify_ldif(setexp)
- except Exception:
+ except:
self.transaction_cancel()
raise
- else:
- self.transaction_commit()
-
- def set_domain_sid(self, sid):
- """Change the domain SID used by this LDB.
-
- :param sid: The new domain sid to use.
- """
- dsdb._samdb_set_domain_sid(self, sid)
-
- def get_domain_sid(self):
- """Read the domain SID used by this LDB. """
- return dsdb._samdb_get_domain_sid(self)
-
- domain_sid = property(get_domain_sid, set_domain_sid,
- "SID for the domain")
-
- def set_invocation_id(self, invocation_id):
- """Set the invocation id for this SamDB handle.
-
- :param invocation_id: GUID of the invocation id.
- """
- dsdb._dsdb_set_ntds_invocation_id(self, invocation_id)
-
- def get_invocation_id(self):
- """Get the invocation_id id"""
- return dsdb._samdb_ntds_invocation_id(self)
-
- invocation_id = property(get_invocation_id, set_invocation_id,
- "Invocation ID GUID")
-
- def get_oid_from_attid(self, attid):
- return dsdb._dsdb_get_oid_from_attid(self, attid)
-
- def get_attid_from_lDAPDisplayName(self, ldap_display_name,
- is_schema_nc=False):
- return dsdb._dsdb_get_attid_from_lDAPDisplayName(self,
- ldap_display_name, is_schema_nc)
-
- def set_ntds_settings_dn(self, ntds_settings_dn):
- """Set the NTDS Settings DN, as would be returned on the dsServiceName
- rootDSE attribute.
-
- This allows the DN to be set before the database fully exists
-
- :param ntds_settings_dn: The new DN to use
- """
- dsdb._samdb_set_ntds_settings_dn(self, ntds_settings_dn)
-
- def get_ntds_GUID(self):
- """Get the NTDS objectGUID"""
- return dsdb._samdb_ntds_objectGUID(self)
-
- def server_site_name(self):
- """Get the server site name"""
- return dsdb._samdb_server_site_name(self)
-
- def load_partition_usn(self, base_dn):
- return dsdb._dsdb_load_partition_usn(self, base_dn)
-
- def set_schema(self, schema):
- self.set_schema_from_ldb(schema.ldb)
-
- def set_schema_from_ldb(self, ldb_conn):
- dsdb._dsdb_set_schema_from_ldb(self, ldb_conn)
-
- def dsdb_DsReplicaAttribute(self, ldb, ldap_display_name, ldif_elements):
- return dsdb._dsdb_DsReplicaAttribute(ldb, ldap_display_name, ldif_elements)
-
- def get_attribute_from_attid(self, attid):
- """ Get from an attid the associated attribute
-
- :param attid: The attribute id for searched attribute
- :return: The name of the attribute associated with this id
- """
- if len(self.hash_oid_name.keys()) == 0:
- self._populate_oid_attid()
- if self.hash_oid_name.has_key(self.get_oid_from_attid(attid)):
- return self.hash_oid_name[self.get_oid_from_attid(attid)]
- else:
- return None
-
- def _populate_oid_attid(self):
- """Populate the hash hash_oid_name.
-
- This hash contains the oid of the attribute as a key and
- its display name as a value
- """
- self.hash_oid_name = {}
- res = self.search(expression="objectClass=attributeSchema",
- controls=["search_options:1:2"],
- attrs=["attributeID",
- "lDAPDisplayName"])
- if len(res) > 0:
- for e in res:
- strDisplay = str(e.get("lDAPDisplayName"))
- self.hash_oid_name[str(e.get("attributeID"))] = strDisplay
-
- def get_attribute_replmetadata_version(self, dn, att):
- """Get the version field trom the replPropertyMetaData for
- the given field
-
- :param dn: The on which we want to get the version
- :param att: The name of the attribute
- :return: The value of the version field in the replPropertyMetaData
- for the given attribute. None if the attribute is not replicated
- """
-
- res = self.search(expression="dn=%s" % dn,
- scope=ldb.SCOPE_SUBTREE,
- controls=["search_options:1:2"],
- attrs=["replPropertyMetaData"])
- if len(res) == 0:
- return None
-
- repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob,
- str(res[0]["replPropertyMetaData"]))
- ctr = repl.ctr
- if len(self.hash_oid_name.keys()) == 0:
- self._populate_oid_attid()
- for o in ctr.array:
- # Search for Description
- att_oid = self.get_oid_from_attid(o.attid)
- if self.hash_oid_name.has_key(att_oid) and\
- att.lower() == self.hash_oid_name[att_oid].lower():
- return o.version
- return None
-
- def set_attribute_replmetadata_version(self, dn, att, value,
- addifnotexist=False):
- res = self.search(expression="dn=%s" % dn,
- scope=ldb.SCOPE_SUBTREE,
- controls=["search_options:1:2"],
- attrs=["replPropertyMetaData"])
- if len(res) == 0:
- return None
-
- repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob,
- str(res[0]["replPropertyMetaData"]))
- ctr = repl.ctr
- now = samba.unix2nttime(int(time.time()))
- found = False
- if len(self.hash_oid_name.keys()) == 0:
- self._populate_oid_attid()
- for o in ctr.array:
- # Search for Description
- att_oid = self.get_oid_from_attid(o.attid)
- if self.hash_oid_name.has_key(att_oid) and\
- att.lower() == self.hash_oid_name[att_oid].lower():
- found = True
- seq = self.sequence_number(ldb.SEQ_NEXT)
- o.version = value
- o.originating_change_time = now
- o.originating_invocation_id = misc.GUID(self.get_invocation_id())
- o.originating_usn = seq
- o.local_usn = seq
-
- if not found and addifnotexist and len(ctr.array) >0:
- o2 = drsblobs.replPropertyMetaData1()
- o2.attid = 589914
- att_oid = self.get_oid_from_attid(o2.attid)
- seq = self.sequence_number(ldb.SEQ_NEXT)
- o2.version = value
- o2.originating_change_time = now
- o2.originating_invocation_id = misc.GUID(self.get_invocation_id())
- o2.originating_usn = seq
- o2.local_usn = seq
- found = True
- tab = ctr.array
- tab.append(o2)
- ctr.count = ctr.count + 1
- ctr.array = tab
-
- if found :
- replBlob = ndr_pack(repl)
- msg = ldb.Message()
- msg.dn = res[0].dn
- msg["replPropertyMetaData"] = ldb.MessageElement(replBlob,
- ldb.FLAG_MOD_REPLACE,
- "replPropertyMetaData")
- self.modify(msg, ["local_oid:1.3.6.1.4.1.7165.4.3.14:0"])
-
- def write_prefixes_from_schema(self):
- dsdb._dsdb_write_prefixes_from_schema_to_ldb(self)
-
- def get_partitions_dn(self):
- return dsdb._dsdb_get_partitions_dn(self)
-
- def set_minPwdAge(self, value):
- m = ldb.Message()
- m.dn = ldb.Dn(self, self.domain_dn())
- m["minPwdAge"] = ldb.MessageElement(value, ldb.FLAG_MOD_REPLACE, "minPwdAge")
- self.modify(m)
-
- def get_minPwdAge(self):
- res = self.search(self.domain_dn(), scope=ldb.SCOPE_BASE, attrs=["minPwdAge"])
- if len(res) == 0:
- return None
- elif not "minPwdAge" in res[0]:
- return None
- else:
- return res[0]["minPwdAge"][0]
-
- def set_minPwdLength(self, value):
- m = ldb.Message()
- m.dn = ldb.Dn(self, self.domain_dn())
- m["minPwdLength"] = ldb.MessageElement(value, ldb.FLAG_MOD_REPLACE, "minPwdLength")
- self.modify(m)
-
- def get_minPwdLength(self):
- res = self.search(self.domain_dn(), scope=ldb.SCOPE_BASE, attrs=["minPwdLength"])
- if len(res) == 0:
- return None
- elif not "minPwdLength" in res[0]:
- return None
- else:
- return res[0]["minPwdLength"][0]
-
- def set_pwdProperties(self, value):
- m = ldb.Message()
- m.dn = ldb.Dn(self, self.domain_dn())
- m["pwdProperties"] = ldb.MessageElement(value, ldb.FLAG_MOD_REPLACE, "pwdProperties")
- self.modify(m)
-
- def get_pwdProperties(self):
- res = self.search(self.domain_dn(), scope=ldb.SCOPE_BASE, attrs=["pwdProperties"])
- if len(res) == 0:
- return None
- elif not "pwdProperties" in res[0]:
- return None
- else:
- return res[0]["pwdProperties"][0]
-
- def set_dsheuristics(self, dsheuristics):
- m = ldb.Message()
- m.dn = ldb.Dn(self, "CN=Directory Service,CN=Windows NT,CN=Services,%s"
- % self.get_config_basedn().get_linearized())
- if dsheuristics is not None:
- m["dSHeuristics"] = ldb.MessageElement(dsheuristics,
- ldb.FLAG_MOD_REPLACE, "dSHeuristics")
- else:
- m["dSHeuristics"] = ldb.MessageElement([], ldb.FLAG_MOD_DELETE,
- "dSHeuristics")
- self.modify(m)
-
- def get_dsheuristics(self):
- res = self.search("CN=Directory Service,CN=Windows NT,CN=Services,%s"
- % self.get_config_basedn().get_linearized(),
- scope=ldb.SCOPE_BASE, attrs=["dSHeuristics"])
- if len(res) == 0:
- dsheuristics = None
- elif "dSHeuristics" in res[0]:
- dsheuristics = res[0]["dSHeuristics"][0]
- else:
- dsheuristics = None
-
- return dsheuristics
-
- def create_ou(self, ou_dn, description=None, name=None, sd=None):
- """Creates an organizationalUnit object
- :param ou_dn: dn of the new object
- :param description: description attribute
- :param name: name atttribute
- :param sd: security descriptor of the object, can be
- an SDDL string or security.descriptor type
- """
- m = {"dn": ou_dn,
- "objectClass": "organizationalUnit"}
-
- if description:
- m["description"] = description
- if name:
- m["name"] = name
+ self.transaction_commit();
- if sd:
- m["nTSecurityDescriptor"] = ndr_pack(sd)
- self.add(m)
diff --git a/source4/scripting/python/samba/schema.py b/source4/scripting/python/samba/schema.py
deleted file mode 100644
index 8bac26e24f..0000000000
--- a/source4/scripting/python/samba/schema.py
+++ /dev/null
@@ -1,204 +0,0 @@
-#
-# Unix SMB/CIFS implementation.
-# backend code for provisioning a Samba4 server
-#
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
-# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008-2009
-# Copyright (C) Oliver Liebel <oliver@itc.li> 2008-2009
-#
-# 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/>.
-#
-
-"""Functions for setting up a Samba Schema."""
-
-from base64 import b64encode
-from samba import read_and_sub_file, substitute_var, check_all_substituted
-from samba.dcerpc import security
-from samba.ms_schema import read_ms_schema
-from samba.ndr import ndr_pack
-from samba.samdb import SamDB
-from samba import dsdb
-from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL
-import os
-
-def get_schema_descriptor(domain_sid):
- sddl = "O:SAG:SAD:AI(OA;;CR;e12b56b6-0a95-11d1-adbb-00c04fd8d5cd;;SA)" \
- "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;1131f6ab-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;1131f6ac-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(A;CI;RPLCLORC;;;AU)" \
- "(A;CI;RPWPCRCCLCLORCWOWDSW;;;SA)" \
- "(A;CI;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)" \
- "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ED)" \
- "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ED)" \
- "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;BA)" \
- "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;BA)" \
- "(OA;;CR;1131f6aa-9c07-11d1-f79f-00c04fc2dcd2;;ER)" \
- "(OA;;CR;1131f6ad-9c07-11d1-f79f-00c04fc2dcd2;;ER)" \
- "(OA;;CR;89e95b76-444d-4c62-991a-0facbeda640c;;ER)" \
- "S:(AU;SA;WPCCDCWOWDSDDTSW;;;WD)" \
- "(AU;CISA;WP;;;WD)" \
- "(AU;SA;CR;;;BA)" \
- "(AU;SA;CR;;;DU)" \
- "(OU;SA;CR;e12b56b6-0a95-11d1-adbb-00c04fd8d5cd;;WD)" \
- "(OU;SA;CR;45ec5156-db7e-47bb-b53f-dbeb2d03c40f;;WD)"
- sec = security.descriptor.from_sddl(sddl, domain_sid)
- return ndr_pack(sec)
-
-
-class Schema(object):
-
- def __init__(self, domain_sid, invocationid=None, schemadn=None,
- files=None, override_prefixmap=None, additional_prefixmap=None):
- from samba.provision import setup_path
-
- """Load schema for the SamDB from the AD schema files and
- samba4_schema.ldif
-
- :param samdb: Load a schema into a SamDB.
- :param schemadn: DN of the schema
-
- Returns the schema data loaded, to avoid double-parsing when then
- needing to add it to the db
- """
-
- self.schemadn = schemadn
- # We need to have the am_rodc=False just to keep some warnings quiet -
- # this isn't a real SAM, so it's meaningless.
- self.ldb = SamDB(global_schema=False, am_rodc=False)
- if invocationid is not None:
- self.ldb.set_invocation_id(invocationid)
-
- self.schema_data = read_ms_schema(
- setup_path('ad-schema/MS-AD_Schema_2K8_R2_Attributes.txt'),
- setup_path('ad-schema/MS-AD_Schema_2K8_R2_Classes.txt'))
-
- if files is not None:
- for file in files:
- self.schema_data += open(file, 'r').read()
-
- self.schema_data = substitute_var(self.schema_data,
- {"SCHEMADN": schemadn})
- check_all_substituted(self.schema_data)
-
- self.schema_dn_modify = read_and_sub_file(
- setup_path("provision_schema_basedn_modify.ldif"),
- {"SCHEMADN": schemadn})
-
- descr = b64encode(get_schema_descriptor(domain_sid))
- self.schema_dn_add = read_and_sub_file(
- setup_path("provision_schema_basedn.ldif"),
- {"SCHEMADN": schemadn, "DESCRIPTOR": descr})
-
- if override_prefixmap is not None:
- self.prefixmap_data = override_prefixmap
- else:
- self.prefixmap_data = open(setup_path("prefixMap.txt"), 'r').read()
-
- if additional_prefixmap is not None:
- for map in additional_prefixmap:
- self.prefixmap_data += "%s\n" % map
-
- self.prefixmap_data = b64encode(self.prefixmap_data)
-
- # We don't actually add this ldif, just parse it
- prefixmap_ldif = "dn: cn=schema\nprefixMap:: %s\n\n" % self.prefixmap_data
- self.set_from_ldif(prefixmap_ldif, self.schema_data)
-
- def set_from_ldif(self, pf, df):
- dsdb._dsdb_set_schema_from_ldif(self.ldb, pf, df)
-
- def write_to_tmp_ldb(self, schemadb_path):
- self.ldb.connect(url=schemadb_path)
- self.ldb.transaction_start()
- try:
- self.ldb.add_ldif("""dn: @ATTRIBUTES
-linkID: INTEGER
-
-dn: @INDEXLIST
-@IDXATTR: linkID
-@IDXATTR: attributeSyntax
-""")
- # These bits of LDIF are supplied when the Schema object is created
- self.ldb.add_ldif(self.schema_dn_add)
- self.ldb.modify_ldif(self.schema_dn_modify)
- self.ldb.add_ldif(self.schema_data)
- except Exception:
- self.ldb.transaction_cancel()
- raise
- else:
- self.ldb.transaction_commit()
-
- # Return a hash with the forward attribute as a key and the back as the
- # value
- def linked_attributes(self):
- return get_linked_attributes(self.schemadn, self.ldb)
-
- def dnsyntax_attributes(self):
- return get_dnsyntax_attributes(self.schemadn, self.ldb)
-
- def convert_to_openldap(self, target, mapping):
- return dsdb._dsdb_convert_schema_to_openldap(self.ldb, target, mapping)
-
-
-# Return a hash with the forward attribute as a key and the back as the value
-def get_linked_attributes(schemadn,schemaldb):
- attrs = ["linkID", "lDAPDisplayName"]
- res = schemaldb.search(expression="(&(linkID=*)(!(linkID:1.2.840.113556.1.4.803:=1))(objectclass=attributeSchema)(attributeSyntax=2.5.5.1))", base=schemadn, scope=SCOPE_ONELEVEL, attrs=attrs)
- attributes = {}
- for i in range (0, len(res)):
- expression = "(&(objectclass=attributeSchema)(linkID=%d)(attributeSyntax=2.5.5.1))" % (int(res[i]["linkID"][0])+1)
- target = schemaldb.searchone(basedn=schemadn,
- expression=expression,
- attribute="lDAPDisplayName",
- scope=SCOPE_SUBTREE)
- if target is not None:
- attributes[str(res[i]["lDAPDisplayName"])]=str(target)
-
- return attributes
-
-
-def get_dnsyntax_attributes(schemadn,schemaldb):
- res = schemaldb.search(
- expression="(&(!(linkID=*))(objectclass=attributeSchema)(attributeSyntax=2.5.5.1))",
- base=schemadn, scope=SCOPE_ONELEVEL,
- attrs=["linkID", "lDAPDisplayName"])
- attributes = []
- for i in range (0, len(res)):
- attributes.append(str(res[i]["lDAPDisplayName"]))
- return attributes
-
-
-def ldb_with_schema(schemadn="cn=schema,cn=configuration,dc=example,dc=com",
- domainsid=None,
- override_prefixmap=None):
- """Load schema for the SamDB from the AD schema files and samba4_schema.ldif
-
- :param schemadn: DN of the schema
- :param serverdn: DN of the server
-
- Returns the schema data loaded as an object, with .ldb being a
- new ldb with the schema loaded. This allows certain tests to
- operate without a remote or local schema.
- """
-
- if domainsid is None:
- domainsid = security.random_sid()
- else:
- domainsid = security.dom_sid(domainsid)
- return Schema(domainsid, schemadn=schemadn,
- override_prefixmap=override_prefixmap)
diff --git a/source4/scripting/python/samba/sd_utils.py b/source4/scripting/python/samba/sd_utils.py
deleted file mode 100644
index 4694f4cc76..0000000000
--- a/source4/scripting/python/samba/sd_utils.py
+++ /dev/null
@@ -1,79 +0,0 @@
-#!/usr/bin/env python
-#
-# Utility methods for security descriptor manipulation
-#
-# Copyright Nadezhda Ivanova 2010 <nivanova@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/>.
-#
-
-import samba
-from ldb import Message, MessageElement, Dn
-from ldb import FLAG_MOD_REPLACE, SCOPE_BASE
-from samba.ndr import ndr_pack, ndr_unpack
-from samba.dcerpc import security
-
-class SDUtils:
- '''Some utilities for manipulation of security descriptors
- on objects'''
-
- def __init__(self, samdb):
- self.ldb = samdb
- self.domain_sid = security.dom_sid(self.ldb.get_domain_sid())
-
- def modify_sd_on_dn(self, object_dn, sd, controls=None):
- """ Modify security descriptor using either SDDL string
- or security.descriptor object
- """
- m = Message()
- m.dn = Dn(self.ldb, object_dn)
- assert(isinstance(sd, str) or isinstance(sd, security.descriptor))
- if isinstance(sd, str):
- tmp_desc = security.descriptor.from_sddl(sd, self.domain_sid)
- elif isinstance(sd, security.descriptor):
- tmp_desc = sd
-
- m["nTSecurityDescriptor"] = MessageElement(ndr_pack(tmp_desc),
- FLAG_MOD_REPLACE,
- "nTSecurityDescriptor")
- self.ldb.modify(m, controls)
-
- def read_sd_on_dn(self, object_dn, controls=None):
- res = self.ldb.search(object_dn, SCOPE_BASE, None,
- ["nTSecurityDescriptor"], controls=controls)
- desc = res[0]["nTSecurityDescriptor"][0]
- return ndr_unpack(security.descriptor, desc)
-
- def get_object_sid(self, object_dn):
- res = self.ldb.search(object_dn)
- return ndr_unpack(security.dom_sid, res[0]["objectSid"][0])
-
- def dacl_add_ace(self, object_dn, ace):
- """ Adds an ACE to an objects security descriptor
- """
- desc = self.read_sd_on_dn(object_dn)
- desc_sddl = desc.as_sddl(self.domain_sid)
- if ace in desc_sddl:
- return
- if desc_sddl.find("(") >= 0:
- desc_sddl = desc_sddl[:desc_sddl.index("(")] + ace + desc_sddl[desc_sddl.index("("):]
- else:
- desc_sddl = desc_sddl + ace
- self.modify_sd_on_dn(object_dn, desc_sddl)
-
- def get_sd_as_sddl(self, object_dn, controls=None):
- """ Return object nTSecutiryDescriptor in SDDL format
- """
- desc = self.read_sd_on_dn(object_dn, controls=controls)
- return desc.as_sddl(self.domain_sid)
diff --git a/source4/scripting/python/samba/shares.py b/source4/scripting/python/samba/shares.py
new file mode 100644
index 0000000000..89a312e855
--- /dev/null
+++ b/source4/scripting/python/samba/shares.py
@@ -0,0 +1,61 @@
+#!/usr/bin/python
+
+# Unix SMB/CIFS implementation.
+# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2009
+#
+# 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/>.
+#
+
+"""Share management."""
+
+
+# TODO: Rather than accessing Loadparm directly here, we should really
+# have bindings to the param/shares.c and use those.
+
+
+class SharesContainer(object):
+ """A shares container."""
+
+ def __init__(self, lp):
+ self._lp = lp
+
+ def __getitem__(self, name):
+ if name == "global":
+ # [global] is not a share
+ raise KeyError
+ return Share(self._lp[name])
+
+ def __len__(self):
+ if "global" in self._lp:
+ return len(self._lp)-1
+ return len(self._lp)
+
+ def keys(self):
+ return [name for name in self._lp.services() if name != "global"]
+
+ def __iter__(self):
+ return iter(self.keys())
+
+
+class Share(object):
+ """A file share."""
+
+ def __init__(self, service):
+ self._service = service
+
+ def __getitem__(self, name):
+ return self._service[name]
+
+ def __setitem__(self, name, value):
+ self._service[name] = value
diff --git a/source4/scripting/python/samba/tests/__init__.py b/source4/scripting/python/samba/tests/__init__.py
index 58e4130998..ae7a707e35 100644
--- a/source4/scripting/python/samba/tests/__init__.py
+++ b/source4/scripting/python/samba/tests/__init__.py
@@ -1,18 +1,18 @@
-#!/usr/bin/env python
+#!/usr/bin/python
# Unix SMB/CIFS implementation.
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2010
-#
+# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
+#
# 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/>.
#
@@ -22,43 +22,13 @@
import os
import ldb
import samba
-import samba.auth
-from samba import param
-from samba.samdb import SamDB
-import subprocess
import tempfile
+import unittest
-# Other modules import these two classes from here, for convenience:
-from testtools.testcase import (
- TestCase as TesttoolsTestCase,
- TestSkipped,
- )
-
-
-class TestCase(TesttoolsTestCase):
- """A Samba test case."""
-
- def setUp(self):
- super(TestCase, self).setUp()
- test_debug_level = os.getenv("TEST_DEBUG_LEVEL")
- if test_debug_level is not None:
- test_debug_level = int(test_debug_level)
- self._old_debug_level = samba.get_debug_level()
- samba.set_debug_level(test_debug_level)
- self.addCleanup(samba.set_debug_level, test_debug_level)
-
- def get_loadparm(self):
- return env_loadparm()
-
- def get_credentials(self):
- return cmdline_credentials
-
+class LdbTestCase(unittest.TestCase):
-class LdbTestCase(TesttoolsTestCase):
"""Trivial test case for running tests against a LDB."""
-
def setUp(self):
- super(LdbTestCase, self).setUp()
self.filename = os.tempnam()
self.ldb = samba.Ldb(self.filename)
@@ -71,7 +41,7 @@ class LdbTestCase(TesttoolsTestCase):
self.ldb = samba.Ldb(self.filename)
-class TestCaseInTempDir(TestCase):
+class TestCaseInTempDir(unittest.TestCase):
def setUp(self):
super(TestCaseInTempDir, self).setUp()
@@ -83,33 +53,57 @@ class TestCaseInTempDir(TestCase):
os.rmdir(self.tempdir)
-def env_loadparm():
- lp = param.LoadParm()
- try:
- lp.load(os.environ["SMB_CONF_PATH"])
- except KeyError:
- raise Exception("SMB_CONF_PATH not set")
- return lp
+class SubstituteVarTestCase(unittest.TestCase):
+
+ def test_empty(self):
+ self.assertEquals("", samba.substitute_var("", {}))
+
+ def test_nothing(self):
+ self.assertEquals("foo bar", samba.substitute_var("foo bar", {"bar": "bla"}))
+
+ def test_replace(self):
+ self.assertEquals("foo bla", samba.substitute_var("foo ${bar}", {"bar": "bla"}))
+ def test_broken(self):
+ self.assertEquals("foo ${bdkjfhsdkfh sdkfh ",
+ samba.substitute_var("foo ${bdkjfhsdkfh sdkfh ", {"bar": "bla"}))
-def env_get_var_value(var_name):
- """Returns value for variable in os.environ
+ def test_unknown_var(self):
+ self.assertEquals("foo ${bla} gsff",
+ samba.substitute_var("foo ${bla} gsff", {"bar": "bla"}))
+
+ def test_check_all_substituted(self):
+ samba.check_all_substituted("nothing to see here")
+ self.assertRaises(Exception, samba.check_all_substituted, "Not subsituted: ${FOOBAR}")
- Function throws AssertionError if variable is defined.
- Unit-test based python tests require certain input params
- to be set in environment, otherwise they can't be run
- """
- assert var_name in os.environ.keys(), "Please supply %s in environment" % var_name
- return os.environ[var_name]
+class LdbExtensionTests(TestCaseInTempDir):
+ def test_searchone(self):
+ path = self.tempdir + "/searchone.ldb"
+ l = samba.Ldb(path)
+ try:
+ l.add({"dn": "foo=dc", "bar": "bla"})
+ self.assertEquals("bla", l.searchone(basedn=ldb.Dn(l, "foo=dc"), attribute="bar"))
+ finally:
+ del l
+ os.unlink(path)
+
+
+cmdline_loadparm = None
cmdline_credentials = None
-class RpcInterfaceTestCase(TestCase):
- """DCE/RPC Test case."""
+class RpcInterfaceTestCase(unittest.TestCase):
+ def get_loadparm(self):
+ assert cmdline_loadparm is not None
+ return cmdline_loadparm
+
+ def get_credentials(self):
+ return cmdline_credentials
-class ValidNetbiosNameTests(TestCase):
+
+class ValidNetbiosNameTests(unittest.TestCase):
def test_valid(self):
self.assertTrue(samba.valid_netbios_name("FOO"))
@@ -119,110 +113,3 @@ class ValidNetbiosNameTests(TestCase):
def test_invalid_characters(self):
self.assertFalse(samba.valid_netbios_name("*BLA"))
-
-
-class BlackboxProcessError(subprocess.CalledProcessError):
- """This exception is raised when a process run by check_output() returns
- a non-zero exit status. Exception instance should contain
- the exact exit code (S.returncode), command line (S.cmd),
- process output (S.stdout) and process error stream (S.stderr)"""
- def __init__(self, returncode, cmd, stdout, stderr):
- super(BlackboxProcessError, self).__init__(returncode, cmd)
- self.stdout = stdout
- self.stderr = stderr
- def __str__(self):
- return "Command '%s'; exit status %d; stdout: '%s'; stderr: '%s'" % (self.cmd, self.returncode,
- self.stdout, self.stderr)
-
-class BlackboxTestCase(TestCase):
- """Base test case for blackbox tests."""
-
- def _make_cmdline(self, line):
- bindir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../../../../bin"))
- parts = line.split(" ")
- if os.path.exists(os.path.join(bindir, parts[0])):
- parts[0] = os.path.join(bindir, parts[0])
- line = " ".join(parts)
- return line
-
- def check_run(self, line):
- line = self._make_cmdline(line)
- subprocess.check_call(line, shell=True)
-
- def check_output(self, line):
- line = self._make_cmdline(line)
- p = subprocess.Popen(line, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, close_fds=True)
- retcode = p.wait()
- if retcode:
- raise BlackboxProcessError(retcode, line, p.stdout.read(), p.stderr.read())
- return p.stdout.read()
-
-def connect_samdb(samdb_url, lp=None, session_info=None, credentials=None,
- flags=0, ldb_options=None, ldap_only=False):
- """Create SamDB instance and connects to samdb_url database.
-
- :param samdb_url: Url for database to connect to.
- :param lp: Optional loadparm object
- :param session_info: Optional session information
- :param credentials: Optional credentials, defaults to anonymous.
- :param flags: Optional LDB flags
- :param ldap_only: If set, only remote LDAP connection will be created.
-
- Added value for tests is that we have a shorthand function
- to make proper URL for ldb.connect() while using default
- parameters for connection based on test environment
- """
- samdb_url = samdb_url.lower()
- if not "://" in samdb_url:
- if not ldap_only and os.path.isfile(samdb_url):
- samdb_url = "tdb://%s" % samdb_url
- else:
- samdb_url = "ldap://%s" % samdb_url
- # use 'paged_search' module when connecting remotely
- if samdb_url.startswith("ldap://"):
- ldb_options = ["modules:paged_searches"]
- elif ldap_only:
- raise AssertionError("Trying to connect to %s while remote "
- "connection is required" % samdb_url)
-
- # set defaults for test environment
- if lp is None:
- lp = env_loadparm()
- if session_info is None:
- session_info = samba.auth.system_session(lp)
- if credentials is None:
- credentials = cmdline_credentials
-
- return SamDB(url=samdb_url,
- lp=lp,
- session_info=session_info,
- credentials=credentials,
- flags=flags,
- options=ldb_options)
-
-
-def connect_samdb_ex(samdb_url, lp=None, session_info=None, credentials=None,
- flags=0, ldb_options=None, ldap_only=False):
- """Connects to samdb_url database
-
- :param samdb_url: Url for database to connect to.
- :param lp: Optional loadparm object
- :param session_info: Optional session information
- :param credentials: Optional credentials, defaults to anonymous.
- :param flags: Optional LDB flags
- :param ldap_only: If set, only remote LDAP connection will be created.
- :return: (sam_db_connection, rootDse_record) tuple
- """
- sam_db = connect_samdb(samdb_url, lp, session_info, credentials,
- flags, ldb_options, ldap_only)
- # fetch RootDse
- res = sam_db.search(base="", expression="", scope=ldb.SCOPE_BASE,
- attrs=["*"])
- return (sam_db, res[0])
-
-
-def delete_force(samdb, dn):
- try:
- samdb.delete(dn)
- except ldb.LdbError, (num, _):
- assert(num == ldb.ERR_NO_SUCH_OBJECT)
diff --git a/source4/scripting/python/samba/tests/auth.py b/source4/scripting/python/samba/tests/auth.py
deleted file mode 100644
index 6ecfc2047f..0000000000
--- a/source4/scripting/python/samba/tests/auth.py
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/usr/bin/env python
-
-# Unix SMB/CIFS implementation.
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
-#
-# 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/>.
-#
-
-"""Tests for the Auth Python bindings.
-
-Note that this just tests the bindings work. It does not intend to test
-the functionality, that's already done in other tests.
-"""
-
-from samba import auth
-import samba.tests
-
-class AuthTests(samba.tests.TestCase):
-
- def test_system_session(self):
- auth.system_session()
-
diff --git a/source4/scripting/python/samba/tests/blackbox/__init__.py b/source4/scripting/python/samba/tests/blackbox/__init__.py
deleted file mode 100644
index 8569cb55bd..0000000000
--- a/source4/scripting/python/samba/tests/blackbox/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-"""Blackbox tests. """
diff --git a/source4/scripting/python/samba/tests/blackbox/ndrdump.py b/source4/scripting/python/samba/tests/blackbox/ndrdump.py
deleted file mode 100755
index c07e32a24f..0000000000
--- a/source4/scripting/python/samba/tests/blackbox/ndrdump.py
+++ /dev/null
@@ -1,36 +0,0 @@
-#!/usr/bin/python
-# Blackbox tests for ndrdump
-# Copyright (C) 2008 Andrew Tridgell <tridge@samba.org>
-# Copyright (C) 2008 Andrew Bartlett <abartlet@samba.org>
-# Copyright (C) 2010 Jelmer Vernooij <jelmer@samba.org>
-# based on test_smbclient.sh
-
-"""Blackbox tests for ndrdump."""
-
-import os
-from samba.tests import BlackboxTestCase
-
-for p in [ "../../../../../source4/librpc/tests", "../../../../../librpc/tests"]:
- data_path_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), p))
- print data_path_dir
- if os.path.exists(data_path_dir):
- break
-
-
-class NdrDumpTests(BlackboxTestCase):
- """Blackbox tests for ndrdump."""
-
- def data_path(self, name):
- return os.path.join(data_path_dir, name)
-
- def test_ndrdump_with_in(self):
- self.check_run("ndrdump samr samr_CreateUser in %s" % (self.data_path("samr-CreateUser-in.dat")))
-
- def test_ndrdump_with_out(self):
- self.check_run("ndrdump samr samr_CreateUser out %s" % (self.data_path("samr-CreateUser-out.dat")))
-
- def test_ndrdump_context_file(self):
- self.check_run("ndrdump --context-file %s samr samr_CreateUser out %s" % (self.data_path("samr-CreateUser-in.dat"), self.data_path("samr-CreateUser-out.dat")))
-
- def test_ndrdump_with_validate(self):
- self.check_run("ndrdump --validate samr samr_CreateUser in %s" % (self.data_path("samr-CreateUser-in.dat")))
diff --git a/source4/scripting/python/samba/tests/blackbox/samba_tool_drs.py b/source4/scripting/python/samba/tests/blackbox/samba_tool_drs.py
deleted file mode 100644
index 51274cc9bd..0000000000
--- a/source4/scripting/python/samba/tests/blackbox/samba_tool_drs.py
+++ /dev/null
@@ -1,100 +0,0 @@
-#!/usr/bin/env python
-
-# Blackbox tests for "samba-tool drs" command
-# Copyright (C) Kamen Mazdrashki <kamenim@samba.org> 2011
-#
-# 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/>.
-#
-
-"""Blackbox tests for samba-tool drs."""
-
-import os
-import samba.tests
-
-
-class SambaToolDrsTests(samba.tests.BlackboxTestCase):
- """Blackbox test case for samba-tool drs."""
-
- def setUp(self):
- super(SambaToolDrsTests, self).setUp()
-
- self.dc1 = samba.tests.env_get_var_value("DC1")
- self.dc2 = samba.tests.env_get_var_value("DC2")
-
- creds = self.get_credentials()
- self.cmdline_creds = "-U%s/%s%%%s" % (creds.get_domain(),
- creds.get_username(), creds.get_password())
-
- def _get_rootDSE(self, dc):
- samdb = samba.tests.connect_samdb(dc, lp=self.get_loadparm(),
- credentials=self.get_credentials(),
- ldap_only=True)
- return samdb.search(base="", scope=samba.tests.ldb.SCOPE_BASE)[0]
-
- def test_samba_tool_bind(self):
- """Tests 'samba-tool drs bind' command
- Output should be like:
- Extensions supported:
- <list-of-supported-extensions>
- Site GUID: <GUID>
- Repl epoch: 0"""
- out = self.check_output("samba-tool drs bind %s %s" % (self.dc1,
- self.cmdline_creds))
- self.assertTrue("Site GUID:" in out)
- self.assertTrue("Repl epoch:" in out)
-
- def test_samba_tool_kcc(self):
- """Tests 'samba-tool drs kcc' command
- Output should be like 'Consistency check on <DC> successful.'"""
- out = self.check_output("samba-tool drs kcc %s %s" % (self.dc1,
- self.cmdline_creds))
- self.assertTrue("Consistency check on" in out)
- self.assertTrue("successful" in out)
-
- def test_samba_tool_showrepl(self):
- """Tests 'samba-tool drs showrepl' command
- Output should be like:
- <site-name>/<domain-name>
- DSA Options: <hex-options>
- DSA object GUID: <DSA-object-GUID>
- DSA invocationId: <DSA-invocationId>
- <Inbound-connections-list>
- <Outbound-connections-list>
- <KCC-objects>
- ...
- TODO: Perhaps we should check at least for
- DSA's objectGUDI and invocationId"""
- out = self.check_output("samba-tool drs showrepl %s %s" % (self.dc1,
- self.cmdline_creds))
- self.assertTrue("DSA Options:" in out)
- self.assertTrue("DSA object GUID:" in out)
- self.assertTrue("DSA invocationId:" in out)
-
- def test_samba_tool_options(self):
- """Tests 'samba-tool drs options' command
- Output should be like 'Current DSA options: IS_GC <OTHER_FLAGS>'"""
- out = self.check_output("samba-tool drs options %s %s" % (self.dc1,
- self.cmdline_creds))
- self.assertTrue("Current DSA options:" in out)
-
- def test_samba_tool_replicate(self):
- """Tests 'samba-tool drs replicate' command
- Output should be like 'Replicate from <DC-SRC> to <DC-DEST> was successful.'"""
- nc_name = self._get_rootDSE(self.dc1)["defaultNamingContext"]
- out = self.check_output("samba-tool drs replicate %s %s %s %s" % (self.dc1,
- self.dc2,
- nc_name,
- self.cmdline_creds))
- self.assertTrue("Replicate from" in out)
- self.assertTrue("was successful" in out)
diff --git a/source4/scripting/python/samba/tests/core.py b/source4/scripting/python/samba/tests/core.py
deleted file mode 100644
index 1c3d7dbe44..0000000000
--- a/source4/scripting/python/samba/tests/core.py
+++ /dev/null
@@ -1,65 +0,0 @@
-#!/usr/bin/env python
-
-# Unix SMB/CIFS implementation.
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
-#
-# 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/>.
-#
-
-"""Samba Python tests."""
-
-import ldb
-import os
-import samba
-from samba.tests import TestCase, TestCaseInTempDir
-
-class SubstituteVarTestCase(TestCase):
-
- def test_empty(self):
- self.assertEquals("", samba.substitute_var("", {}))
-
- def test_nothing(self):
- self.assertEquals("foo bar",
- samba.substitute_var("foo bar", {"bar": "bla"}))
-
- def test_replace(self):
- self.assertEquals("foo bla",
- samba.substitute_var("foo ${bar}", {"bar": "bla"}))
-
- def test_broken(self):
- self.assertEquals("foo ${bdkjfhsdkfh sdkfh ",
- samba.substitute_var("foo ${bdkjfhsdkfh sdkfh ", {"bar": "bla"}))
-
- def test_unknown_var(self):
- self.assertEquals("foo ${bla} gsff",
- samba.substitute_var("foo ${bla} gsff", {"bar": "bla"}))
-
- def test_check_all_substituted(self):
- samba.check_all_substituted("nothing to see here")
- self.assertRaises(Exception, samba.check_all_substituted,
- "Not subsituted: ${FOOBAR}")
-
-
-class LdbExtensionTests(TestCaseInTempDir):
-
- def test_searchone(self):
- path = self.tempdir + "/searchone.ldb"
- l = samba.Ldb(path)
- try:
- l.add({"dn": "foo=dc", "bar": "bla"})
- self.assertEquals("bla",
- l.searchone(basedn=ldb.Dn(l, "foo=dc"), attribute="bar"))
- finally:
- del l
- os.unlink(path)
diff --git a/source4/scripting/python/samba/tests/credentials.py b/source4/scripting/python/samba/tests/credentials.py
deleted file mode 100644
index 5ed61c6b21..0000000000
--- a/source4/scripting/python/samba/tests/credentials.py
+++ /dev/null
@@ -1,100 +0,0 @@
-#!/usr/bin/env python
-
-# Unix SMB/CIFS implementation.
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
-#
-# 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/>.
-#
-
-"""Tests for the Credentials Python bindings.
-
-Note that this just tests the bindings work. It does not intend to test
-the functionality, that's already done in other tests.
-"""
-
-from samba import credentials
-import samba.tests
-
-class CredentialsTests(samba.tests.TestCase):
-
- def setUp(self):
- super(CredentialsTests, self).setUp()
- self.creds = credentials.Credentials()
-
- def test_set_username(self):
- self.creds.set_username("somebody")
- self.assertEquals("somebody", self.creds.get_username())
-
- def test_set_password(self):
- self.creds.set_password("S3CreT")
- self.assertEquals("S3CreT", self.creds.get_password())
-
- def test_set_domain(self):
- self.creds.set_domain("ABMAS")
- self.assertEquals("ABMAS", self.creds.get_domain())
-
- def test_set_realm(self):
- self.creds.set_realm("myrealm")
- self.assertEquals("MYREALM", self.creds.get_realm())
-
- def test_parse_string_anon(self):
- self.creds.parse_string("%")
- self.assertEquals("", self.creds.get_username())
- self.assertEquals(None, self.creds.get_password())
-
- def test_parse_string_user_pw_domain(self):
- self.creds.parse_string("dom\\someone%secr")
- self.assertEquals("someone", self.creds.get_username())
- self.assertEquals("secr", self.creds.get_password())
- self.assertEquals("DOM", self.creds.get_domain())
-
- def test_bind_dn(self):
- self.assertEquals(None, self.creds.get_bind_dn())
- self.creds.set_bind_dn("dc=foo,cn=bar")
- self.assertEquals("dc=foo,cn=bar", self.creds.get_bind_dn())
-
- def test_is_anon(self):
- self.creds.set_username("")
- self.assertTrue(self.creds.is_anonymous())
- self.creds.set_username("somebody")
- self.assertFalse(self.creds.is_anonymous())
- self.creds.set_anonymous()
- self.assertTrue(self.creds.is_anonymous())
-
- def test_workstation(self):
- # FIXME: This is uninitialised, it should be None
- #self.assertEquals(None, self.creds.get_workstation())
- self.creds.set_workstation("myworksta")
- self.assertEquals("myworksta", self.creds.get_workstation())
-
- def test_get_nt_hash(self):
- self.creds.set_password("geheim")
- self.assertEquals('\xc2\xae\x1f\xe6\xe6H\x84cRE>\x81o*\xeb\x93',
- self.creds.get_nt_hash())
-
- def test_guess(self):
- # Just check the method is there and doesn't raise an exception
- self.creds.guess()
-
- def test_set_cmdline_callbacks(self):
- self.creds.set_cmdline_callbacks()
-
- def test_authentication_requested(self):
- self.creds.set_username("")
- self.assertFalse(self.creds.authentication_requested())
- self.creds.set_username("somebody")
- self.assertTrue(self.creds.authentication_requested())
-
- def test_wrong_password(self):
- self.assertFalse(self.creds.wrong_password())
diff --git a/source4/scripting/python/samba/tests/dcerpc/__init__.py b/source4/scripting/python/samba/tests/dcerpc/__init__.py
index 0f9625570a..c64c9dc9f6 100644
--- a/source4/scripting/python/samba/tests/dcerpc/__init__.py
+++ b/source4/scripting/python/samba/tests/dcerpc/__init__.py
@@ -1,14 +1,14 @@
-#!/usr/bin/env python
+#!/usr/bin/python
# -*- coding: utf-8 -*-
# Unix SMB/CIFS implementation.
# Copyright © Jelmer Vernooij <jelmer@samba.org> 2008
-#
+#
# 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
@@ -16,6 +16,5 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-"""Tests for the DCE/RPC Python bindings."""
+#
diff --git a/source4/scripting/python/samba/tests/dcerpc/bare.py b/source4/scripting/python/samba/tests/dcerpc/bare.py
index 22163697f8..6cadad89f1 100644
--- a/source4/scripting/python/samba/tests/dcerpc/bare.py
+++ b/source4/scripting/python/samba/tests/dcerpc/bare.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
# -*- coding: utf-8 -*-
# Unix SMB/CIFS implementation.
@@ -18,35 +18,32 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-"""Tests for samba.dcerpc.bare."""
-
from samba.dcerpc import ClientConnection
-import samba.tests
+from unittest import TestCase
+from samba.tests import cmdline_loadparm
+
-class BareTestCase(samba.tests.TestCase):
+class BareTestCase(TestCase):
def test_bare(self):
# Connect to the echo pipe
x = ClientConnection("ncalrpc:localhost[DEFAULT]",
- ("60a15ec5-4de8-11d7-a637-005056a20182", 1),
- lp_ctx=samba.tests.env_loadparm())
+ ("60a15ec5-4de8-11d7-a637-005056a20182", 1), lp_ctx=cmdline_loadparm)
self.assertEquals("\x01\x00\x00\x00", x.request(0, chr(0) * 4))
def test_alter_context(self):
x = ClientConnection("ncalrpc:localhost[DEFAULT]",
- ("12345778-1234-abcd-ef00-0123456789ac", 1),
- lp_ctx=samba.tests.env_loadparm())
+ ("12345778-1234-abcd-ef00-0123456789ac", 1), lp_ctx=cmdline_loadparm)
y = ClientConnection("ncalrpc:localhost",
("60a15ec5-4de8-11d7-a637-005056a20182", 1),
- basis_connection=x, lp_ctx=samba.tests.env_loadparm())
+ basis_connection=x, lp_ctx=cmdline_loadparm)
x.alter_context(("60a15ec5-4de8-11d7-a637-005056a20182", 1))
# FIXME: self.assertEquals("\x01\x00\x00\x00", x.request(0, chr(0) * 4))
def test_two_connections(self):
x = ClientConnection("ncalrpc:localhost[DEFAULT]",
- ("60a15ec5-4de8-11d7-a637-005056a20182", 1),
- lp_ctx=samba.tests.env_loadparm())
+ ("60a15ec5-4de8-11d7-a637-005056a20182", 1), lp_ctx=cmdline_loadparm)
y = ClientConnection("ncalrpc:localhost",
("60a15ec5-4de8-11d7-a637-005056a20182", 1),
- basis_connection=x, lp_ctx=samba.tests.env_loadparm())
+ basis_connection=x, lp_ctx=cmdline_loadparm)
self.assertEquals("\x01\x00\x00\x00", y.request(0, chr(0) * 4))
diff --git a/source4/scripting/python/samba/tests/dcerpc/misc.py b/source4/scripting/python/samba/tests/dcerpc/misc.py
index 37a647a842..ab76efc536 100644
--- a/source4/scripting/python/samba/tests/dcerpc/misc.py
+++ b/source4/scripting/python/samba/tests/dcerpc/misc.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
# Unix SMB/CIFS implementation.
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
@@ -17,15 +17,13 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-"""Tests for samba.dcerpc.misc."""
-
+import unittest
from samba.dcerpc import misc
-import samba.tests
text1 = "76f53846-a7c2-476a-ae2c-20e2b80d7b34"
text2 = "344edffa-330a-4b39-b96e-2c34da52e8b1"
-class GUIDTests(samba.tests.TestCase):
+class GUIDTests(unittest.TestCase):
def test_str(self):
guid = misc.GUID(text1)
@@ -45,9 +43,9 @@ class GUIDTests(samba.tests.TestCase):
guid2 = misc.GUID(text1)
self.assertEquals(0, cmp(guid1, guid2))
self.assertEquals(guid1, guid2)
-
-
-class PolicyHandleTests(samba.tests.TestCase):
+
+
+class PolicyHandleTests(unittest.TestCase):
def test_init(self):
x = misc.policy_handle(text1, 1)
diff --git a/source4/scripting/python/samba/tests/dcerpc/registry.py b/source4/scripting/python/samba/tests/dcerpc/registry.py
index f0716d5ffb..f1cd83790d 100644
--- a/source4/scripting/python/samba/tests/dcerpc/registry.py
+++ b/source4/scripting/python/samba/tests/dcerpc/registry.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
# Unix SMB/CIFS implementation.
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
@@ -17,8 +17,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-"""Tests for samba.dcerpc.registry."""
-
from samba.dcerpc import winreg
from samba.tests import RpcInterfaceTestCase
@@ -26,7 +24,6 @@ from samba.tests import RpcInterfaceTestCase
class WinregTests(RpcInterfaceTestCase):
def setUp(self):
- super(WinregTests, self).setUp()
self.conn = winreg.winreg("ncalrpc:", self.get_loadparm(),
self.get_credentials())
diff --git a/source4/scripting/python/samba/tests/dcerpc/rpc_talloc.py b/source4/scripting/python/samba/tests/dcerpc/rpc_talloc.py
deleted file mode 100755
index fe0f93ef9b..0000000000
--- a/source4/scripting/python/samba/tests/dcerpc/rpc_talloc.py
+++ /dev/null
@@ -1,70 +0,0 @@
-#!/usr/bin/env python
-# test generated python code from pidl
-# Andrew Tridgell August 2010
-#
-# to run this test, use one of these:
-#
-# python -m testtools.run samba.tests.dcerpc.rpc_talloc
-#
-# or if you have trial installed (from twisted), use
-#
-# trial samba.tests.dcerpc.rpc_talloc
-
-"""Tests for the talloc handling in the generated Python DCE/RPC bindings."""
-
-import sys
-
-sys.path.insert(0, "bin/python")
-
-import samba
-import samba.tests
-from samba.dcerpc import drsuapi
-import talloc
-
-talloc.enable_null_tracking()
-
-class TallocTests(samba.tests.TestCase):
- '''test talloc behaviour of pidl generated python code'''
-
- def check_blocks(self, object, num_expected):
- '''check that the number of allocated blocks is correct'''
- nblocks = talloc.total_blocks(object)
- if object is None:
- nblocks -= self.initial_blocks
- self.assertEquals(nblocks, num_expected)
-
- def get_rodc_partial_attribute_set(self):
- '''get a list of attributes for RODC replication'''
- partial_attribute_set = drsuapi.DsPartialAttributeSet()
-
- # we expect one block for the object, and one for the structure
- self.check_blocks(partial_attribute_set, 2)
-
- attids = [ 1, 2, 3]
- partial_attribute_set.version = 1
- partial_attribute_set.attids = attids
- partial_attribute_set.num_attids = len(attids)
-
- # we expect one block object, a structure, an ARRAY, and a
- # reference to the array
- self.check_blocks(partial_attribute_set, 3)
-
- return partial_attribute_set
-
- def pas_test(self):
- pas = self.get_rodc_partial_attribute_set()
- self.check_blocks(pas, 3)
- req8 = drsuapi.DsGetNCChangesRequest8()
- self.check_blocks(req8, 2)
- self.check_blocks(None, 5)
- req8.partial_attribute_set = pas
- if req8.partial_attribute_set.attids[1] != 2:
- raise Exception("Wrong value in attids[2]")
- # we now get an additional reference
- self.check_blocks(None, 6)
-
- def test_run(self):
- self.initial_blocks = talloc.total_blocks(None)
- self.check_blocks(None, 0)
- self.pas_test()
- self.check_blocks(None, 0)
diff --git a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py
index ba7ad9688b..72eb87d750 100644
--- a/source4/scripting/python/samba/tests/dcerpc/rpcecho.py
+++ b/source4/scripting/python/samba/tests/dcerpc/rpcecho.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
# Unix SMB/CIFS implementation.
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
@@ -17,17 +17,15 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-"""Tests for samba.dceprc.rpcecho."""
-
from samba.dcerpc import echo
from samba.ndr import ndr_pack, ndr_unpack
-from samba.tests import RpcInterfaceTestCase, TestCase
+import unittest
+from samba.tests import RpcInterfaceTestCase
class RpcEchoTests(RpcInterfaceTestCase):
def setUp(self):
- super(RpcEchoTests, self).setUp()
self.conn = echo.rpcecho("ncalrpc:", self.get_loadparm())
def test_two_contexts(self):
@@ -35,7 +33,7 @@ class RpcEchoTests(RpcInterfaceTestCase):
self.assertEquals(3, self.conn2.AddOne(2))
def test_abstract_syntax(self):
- self.assertEquals(("60a15ec5-4de8-11d7-a637-005056a20182", 1),
+ self.assertEquals(("60a15ec5-4de8-11d7-a637-005056a20182", 1),
self.conn.abstract_syntax)
def test_addone(self):
@@ -61,7 +59,7 @@ class RpcEchoTests(RpcInterfaceTestCase):
self.assertEquals(None, self.conn.server_name)
-class NdrEchoTests(TestCase):
+class NdrEchoTests(unittest.TestCase):
def test_info1_push(self):
x = echo.info1()
diff --git a/source4/scripting/python/samba/tests/dcerpc/sam.py b/source4/scripting/python/samba/tests/dcerpc/sam.py
index 38b381d3aa..9532333a00 100644
--- a/source4/scripting/python/samba/tests/dcerpc/sam.py
+++ b/source4/scripting/python/samba/tests/dcerpc/sam.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
# -*- coding: utf-8 -*-
# Unix SMB/CIFS implementation.
@@ -18,8 +18,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-"""Tests for samba.dcerpc.sam."""
-
from samba.dcerpc import samr, security
from samba.tests import RpcInterfaceTestCase
@@ -34,7 +32,6 @@ def toArray((handle, array, num_entries)):
class SamrTests(RpcInterfaceTestCase):
def setUp(self):
- super(SamrTests, self).setUp()
self.conn = samr.samr("ncalrpc:", self.get_loadparm())
def test_connect5(self):
@@ -42,7 +39,6 @@ class SamrTests(RpcInterfaceTestCase):
def test_connect2(self):
handle = self.conn.Connect2(None, security.SEC_FLAG_MAXIMUM_ALLOWED)
- self.assertTrue(handle is not None)
def test_EnumDomains(self):
handle = self.conn.Connect2(None, security.SEC_FLAG_MAXIMUM_ALLOWED)
diff --git a/source4/scripting/python/samba/tests/dcerpc/testrpc.py b/source4/scripting/python/samba/tests/dcerpc/testrpc.py
deleted file mode 100644
index 2f3a6a0aef..0000000000
--- a/source4/scripting/python/samba/tests/dcerpc/testrpc.py
+++ /dev/null
@@ -1,130 +0,0 @@
-#!/usr/bin/env python
-#
-# test generated python code from pidl
-# Andrew Tridgell August 2010
-#
-import sys
-
-sys.path.insert(0, "bin/python")
-
-import samba
-import samba.tests
-from samba.dcerpc import drsuapi
-import talloc
-
-talloc.enable_null_tracking()
-
-class RpcTests(object):
- '''test type behaviour of pidl generated python RPC code'''
-
- def check_blocks(self, object, num_expected):
- '''check that the number of allocated blocks is correct'''
- nblocks = talloc.total_blocks(object)
- if object is None:
- nblocks -= self.initial_blocks
- leaked_blocks = (nblocks - num_expected)
- if leaked_blocks != 0:
- print "Leaked %d blocks" % leaked_blocks
-
- def check_type(self, interface, typename, type):
- print "Checking type %s" % typename
- v = type()
- for n in dir(v):
- if n[0] == '_':
- continue
- try:
- value = getattr(v, n)
- except TypeError, errstr:
- if str(errstr) == "unknown union level":
- print "ERROR: Unknown union level in %s.%s" % (typename, n)
- self.errcount += 1
- continue
- print str(errstr)[1:21]
- if str(errstr)[0:21] == "Can not convert C Type":
- print "ERROR: Unknown C type for %s.%s" % (typename, n)
- self.errcount += 1
- continue
- else:
- print "ERROR: Failed to instantiate %s.%s" % (typename, n)
- self.errcount += 1
- continue
- except:
- print "ERROR: Failed to instantiate %s.%s" % (typename, n)
- self.errcount += 1
- continue
-
- # now try setting the value back
- try:
- print "Setting %s.%s" % (typename, n)
- setattr(v, n, value)
- except Exception, e:
- if isinstance(e, AttributeError) and str(e).endswith("is read-only"):
- # readonly, ignore
- continue
- else:
- print "ERROR: Failed to set %s.%s: %r: %s" % (typename, n, e.__class__, e)
- self.errcount += 1
- continue
-
- # and try a comparison
- try:
- if value != getattr(v, n):
- print "ERROR: Comparison failed for %s.%s: %r != %r" % (typename, n, value, getattr(v, n))
- continue
- except Exception, e:
- print "ERROR: compare exception for %s.%s: %r: %s" % (typename, n, e.__class__, e)
- continue
-
- def check_interface(self, interface, iname):
- errcount = self.errcount
- for n in dir(interface):
- if n[0] == '_' or n == iname:
- # skip the special ones
- continue
- value = getattr(interface, n)
- if isinstance(value, str):
- #print "%s=\"%s\"" % (n, value)
- pass
- elif isinstance(value, int) or isinstance(value, long):
- #print "%s=%d" % (n, value)
- pass
- elif isinstance(value, type):
- try:
- initial_blocks = talloc.total_blocks(None)
- self.check_type(interface, n, value)
- self.check_blocks(None, initial_blocks)
- except Exception, e:
- print "ERROR: Failed to check_type %s.%s: %r: %s" % (iname, n, e.__class__, e)
- self.errcount += 1
- elif callable(value):
- pass # Method
- else:
- print "UNKNOWN: %s=%s" % (n, value)
- if self.errcount - errcount != 0:
- print "Found %d errors in %s" % (self.errcount - errcount, iname)
-
- def check_all_interfaces(self):
- for iname in dir(samba.dcerpc):
- if iname[0] == '_':
- continue
- if iname == 'ClientConnection' or iname == 'base':
- continue
- print "Checking interface %s" % iname
- iface = getattr(samba.dcerpc, iname)
- initial_blocks = talloc.total_blocks(None)
- self.check_interface(iface, iname)
- self.check_blocks(None, initial_blocks)
-
- def run(self):
- self.initial_blocks = talloc.total_blocks(None)
- self.errcount = 0
- self.check_all_interfaces()
- return self.errcount
-
-tests = RpcTests()
-errcount = tests.run()
-if errcount == 0:
- sys.exit(0)
-else:
- print "%d failures" % errcount
- sys.exit(1)
diff --git a/source4/scripting/python/samba/tests/dcerpc/unix.py b/source4/scripting/python/samba/tests/dcerpc/unix.py
index 16bf37e749..62169ad12c 100644
--- a/source4/scripting/python/samba/tests/dcerpc/unix.py
+++ b/source4/scripting/python/samba/tests/dcerpc/unix.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
# Unix SMB/CIFS implementation.
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
@@ -17,35 +17,22 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-"""Tests for samba.dcerpc.unixinfo."""
-
-
from samba.dcerpc import unixinfo
from samba.tests import RpcInterfaceTestCase
class UnixinfoTests(RpcInterfaceTestCase):
def setUp(self):
- super(UnixinfoTests, self).setUp()
self.conn = unixinfo.unixinfo("ncalrpc:", self.get_loadparm())
- def test_getpwuid_int(self):
- infos = self.conn.GetPWUid(range(512))
- self.assertEquals(512, len(infos))
- self.assertEquals("/bin/false", infos[0].shell)
- self.assertTrue(isinstance(infos[0].homedir, unicode))
-
def test_getpwuid(self):
- infos = self.conn.GetPWUid(map(long, range(512)))
+ infos = self.conn.GetPWUid(range(512))
self.assertEquals(512, len(infos))
self.assertEquals("/bin/false", infos[0].shell)
self.assertTrue(isinstance(infos[0].homedir, unicode))
def test_gidtosid(self):
- self.conn.GidToSid(1000L)
+ self.conn.GidToSid(1000)
def test_uidtosid(self):
self.conn.UidToSid(1000)
-
- def test_uidtosid_fail(self):
- self.assertRaises(TypeError, self.conn.UidToSid, "100")
diff --git a/source4/scripting/python/samba/tests/dsdb.py b/source4/scripting/python/samba/tests/dsdb.py
deleted file mode 100644
index d4331f3ef5..0000000000
--- a/source4/scripting/python/samba/tests/dsdb.py
+++ /dev/null
@@ -1,135 +0,0 @@
-#!/usr/bin/env python
-
-# Unix SMB/CIFS implementation. Tests for dsdb
-# Copyright (C) Matthieu Patou <mat@matws.net> 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/>.
-#
-
-"""Tests for samba.dsdb."""
-
-from samba.credentials import Credentials
-from samba.samdb import SamDB
-from samba.auth import system_session
-from testtools.testcase import TestCase
-from samba.ndr import ndr_unpack, ndr_pack
-from samba.dcerpc import drsblobs
-import ldb
-import os
-import samba
-
-
-class DsdbTests(TestCase):
-
-
- def setUp(self):
- super(DsdbTests, self).setUp()
- self.lp = samba.param.LoadParm()
- self.lp.load(os.path.join(os.path.join(self.baseprovpath(), "etc"), "smb.conf"))
- self.creds = Credentials()
- self.creds.guess(self.lp)
- self.session = system_session()
- self.samdb = SamDB(os.path.join(self.baseprovpath(), "private", "sam.ldb"),
- session_info=self.session, credentials=self.creds,lp=self.lp)
-
-
- def baseprovpath(self):
- return os.path.join(os.environ['SELFTEST_PREFIX'], "dc")
-
-
- def test_get_oid_from_attrid(self):
- oid = self.samdb.get_oid_from_attid(591614)
- self.assertEquals(oid, "1.2.840.113556.1.4.1790")
-
- def test_error_replpropertymetadata(self):
- res = self.samdb.search(expression="cn=Administrator",
- scope=ldb.SCOPE_SUBTREE,
- attrs=["replPropertyMetaData"])
- repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob,
- str(res[0]["replPropertyMetaData"]))
- ctr = repl.ctr
- for o in ctr.array:
- # Search for Description
- if o.attid == 13:
- old_version = o.version
- o.version = o.version + 1
- replBlob = ndr_pack(repl)
- msg = ldb.Message()
- msg.dn = res[0].dn
- msg["replPropertyMetaData"] = ldb.MessageElement(replBlob, ldb.FLAG_MOD_REPLACE, "replPropertyMetaData")
- self.assertRaises(ldb.LdbError, self.samdb.modify, msg, ["local_oid:1.3.6.1.4.1.7165.4.3.14:0"])
-
- def test_twoatt_replpropertymetadata(self):
- res = self.samdb.search(expression="cn=Administrator",
- scope=ldb.SCOPE_SUBTREE,
- attrs=["replPropertyMetaData", "uSNChanged"])
- repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob,
- str(res[0]["replPropertyMetaData"]))
- ctr = repl.ctr
- for o in ctr.array:
- # Search for Description
- if o.attid == 13:
- old_version = o.version
- o.version = o.version + 1
- o.local_usn = long(str(res[0]["uSNChanged"])) + 1
- replBlob = ndr_pack(repl)
- msg = ldb.Message()
- msg.dn = res[0].dn
- msg["replPropertyMetaData"] = ldb.MessageElement(replBlob, ldb.FLAG_MOD_REPLACE, "replPropertyMetaData")
- msg["description"] = ldb.MessageElement("new val", ldb.FLAG_MOD_REPLACE, "description")
- self.assertRaises(ldb.LdbError, self.samdb.modify, msg, ["local_oid:1.3.6.1.4.1.7165.4.3.14:0"])
-
- def test_set_replpropertymetadata(self):
- res = self.samdb.search(expression="cn=Administrator",
- scope=ldb.SCOPE_SUBTREE,
- attrs=["replPropertyMetaData", "uSNChanged"])
- repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob,
- str(res[0]["replPropertyMetaData"]))
- ctr = repl.ctr
- for o in ctr.array:
- # Search for Description
- if o.attid == 13:
- old_version = o.version
- o.version = o.version + 1
- o.local_usn = long(str(res[0]["uSNChanged"])) + 1
- o.originating_usn = long(str(res[0]["uSNChanged"])) + 1
- replBlob = ndr_pack(repl)
- msg = ldb.Message()
- msg.dn = res[0].dn
- msg["replPropertyMetaData"] = ldb.MessageElement(replBlob, ldb.FLAG_MOD_REPLACE, "replPropertyMetaData")
- self.samdb.modify(msg, ["local_oid:1.3.6.1.4.1.7165.4.3.14:0"])
-
- def test_ok_get_attribute_from_attid(self):
- self.assertEquals(self.samdb.get_attribute_from_attid(13), "description")
-
- def test_ko_get_attribute_from_attid(self):
- self.assertEquals(self.samdb.get_attribute_from_attid(11979), None)
-
- def test_get_attribute_replmetadata_version(self):
- res = self.samdb.search(expression="cn=Administrator",
- scope=ldb.SCOPE_SUBTREE,
- attrs=["dn"])
- self.assertEquals(len(res), 1)
- dn = str(res[0].dn)
- self.assertEqual(self.samdb.get_attribute_replmetadata_version(dn, "unicodePwd"), 1)
-
- def test_set_attribute_replmetadata_version(self):
- res = self.samdb.search(expression="cn=Administrator",
- scope=ldb.SCOPE_SUBTREE,
- attrs=["dn"])
- self.assertEquals(len(res), 1)
- dn = str(res[0].dn)
- version = self.samdb.get_attribute_replmetadata_version(dn, "description")
- self.samdb.set_attribute_replmetadata_version(dn, "description", version + 2)
- self.assertEqual(self.samdb.get_attribute_replmetadata_version(dn, "description"), version + 2)
diff --git a/source4/scripting/python/samba/tests/gensec.py b/source4/scripting/python/samba/tests/gensec.py
deleted file mode 100644
index ddca0df980..0000000000
--- a/source4/scripting/python/samba/tests/gensec.py
+++ /dev/null
@@ -1,90 +0,0 @@
-#!/usr/bin/env python
-
-# Unix SMB/CIFS implementation.
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2009
-#
-# 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/>.
-#
-
-"""Tests for GENSEC.
-
-Note that this just tests the bindings work. It does not intend to test
-the functionality, that's already done in other tests.
-"""
-
-from samba.credentials import Credentials
-from samba import gensec
-import samba.tests
-
-class GensecTests(samba.tests.TestCase):
-
- def setUp(self):
- super(GensecTests, self).setUp()
- self.settings = {}
- self.settings["lp_ctx"] = self.lp_ctx = samba.tests.env_loadparm()
- self.settings["target_hostname"] = self.lp_ctx.get("netbios name")
- """This is just for the API tests"""
- self.gensec = gensec.Security.start_client(self.settings)
-
- def test_start_mech_by_unknown_name(self):
- self.assertRaises(RuntimeError, self.gensec.start_mech_by_name, "foo")
-
- def test_start_mech_by_name(self):
- self.gensec.start_mech_by_name("spnego")
-
- def test_info_uninitialized(self):
- self.assertRaises(RuntimeError, self.gensec.session_info)
-
- def test_update(self):
- """Test GENSEC by doing an exchange with ourselves using GSSAPI against a KDC"""
-
- """Start up a client and server GENSEC instance to test things with"""
-
- self.gensec_client = gensec.Security.start_client(self.settings)
- self.gensec_client.set_credentials(self.get_credentials())
- self.gensec_client.want_feature(gensec.FEATURE_SEAL)
- self.gensec_client.start_mech_by_sasl_name("GSSAPI")
-
- self.gensec_server = gensec.Security.start_server(self.settings)
- creds = Credentials()
- creds.guess(self.lp_ctx)
- creds.set_machine_account(self.lp_ctx)
- self.gensec_server.set_credentials(creds)
-
- self.gensec_server.want_feature(gensec.FEATURE_SEAL)
- self.gensec_server.start_mech_by_sasl_name("GSSAPI")
-
- client_finished = False
- server_finished = False
- server_to_client = ""
-
- """Run the actual call loop"""
- while client_finished == False and server_finished == False:
- if not client_finished:
- print "running client gensec_update"
- (client_finished, client_to_server) = self.gensec_client.update(server_to_client)
- if not server_finished:
- print "running server gensec_update"
- (server_finished, server_to_client) = self.gensec_server.update(client_to_server)
- session_info = self.gensec_server.session_info()
-
- test_string = "Hello Server"
- test_wrapped = self.gensec_client.wrap(test_string)
- test_unwrapped = self.gensec_server.unwrap(test_wrapped)
- self.assertEqual(test_string, test_unwrapped)
- test_string = "Hello Client"
- test_wrapped = self.gensec_server.wrap(test_string)
- test_unwrapped = self.gensec_client.unwrap(test_wrapped)
- self.assertEqual(test_string, test_unwrapped)
-
diff --git a/source4/scripting/python/samba/tests/messaging.py b/source4/scripting/python/samba/tests/messaging.py
deleted file mode 100644
index d2a0b73775..0000000000
--- a/source4/scripting/python/samba/tests/messaging.py
+++ /dev/null
@@ -1,60 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# Unix SMB/CIFS implementation.
-# Copyright © Jelmer Vernooij <jelmer@samba.org> 2008
-#
-# 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/>.
-#
-
-"""Tests for samba.messaging."""
-
-from samba.messaging import Messaging
-from samba.tests import TestCase
-
-class MessagingTests(TestCase):
-
- def get_context(self, *args, **kwargs):
- kwargs["messaging_path"] = "."
- return Messaging(*args, **kwargs)
-
- def test_register(self):
- x = self.get_context()
- def callback():
- pass
- msg_type = x.register(callback)
- x.deregister(callback, msg_type)
-
- def test_assign_server_id(self):
- x = self.get_context()
- self.assertTrue(isinstance(x.server_id, tuple))
- self.assertEquals(3, len(x.server_id))
-
- def test_ping_speed(self):
- server_ctx = self.get_context((0, 1))
- def ping_callback(src, data):
- server_ctx.send(src, data)
- def exit_callback():
- print "received exit"
- msg_ping = server_ctx.register(ping_callback)
- msg_exit = server_ctx.register(exit_callback)
-
- def pong_callback():
- print "received pong"
- client_ctx = self.get_context((0, 2))
- msg_pong = client_ctx.register(pong_callback)
-
- client_ctx.send((0, 1), msg_ping, "testing")
- client_ctx.send((0, 1), msg_ping, "")
-
diff --git a/source4/scripting/python/samba/tests/netcmd.py b/source4/scripting/python/samba/tests/netcmd.py
deleted file mode 100644
index 787bcd5a72..0000000000
--- a/source4/scripting/python/samba/tests/netcmd.py
+++ /dev/null
@@ -1,35 +0,0 @@
-#!/usr/bin/env python
-
-# Unix SMB/CIFS implementation.
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2009
-#
-# 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/>.
-#
-
-"""Tests for samba.netcmd."""
-
-from samba.netcmd import Command
-import samba.tests
-
-class CommandTests(samba.tests.TestCase):
-
- def test_name(self):
- class cmd_foo(Command):
- pass
- self.assertEquals("foo", cmd_foo().name)
-
- def test_description(self):
- class cmd_foo(Command):
- """Mydescription"""
- self.assertEquals("Mydescription", cmd_foo().description)
diff --git a/source4/scripting/python/samba/tests/ntacls.py b/source4/scripting/python/samba/tests/ntacls.py
deleted file mode 100644
index 2d8d6b9d67..0000000000
--- a/source4/scripting/python/samba/tests/ntacls.py
+++ /dev/null
@@ -1,101 +0,0 @@
-#!/usr/bin/env python
-
-# Unix SMB/CIFS implementation. Tests for ntacls manipulation
-# Copyright (C) Matthieu Patou <mat@matws.net> 2009-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/>.
-#
-
-"""Tests for samba.ntacls."""
-
-from samba.ntacls import setntacl, getntacl, XattrBackendError
-from samba.dcerpc import xattr, security
-from samba.param import LoadParm
-from samba.tests import TestCase, TestSkipped
-import random
-import os
-
-class NtaclsTests(TestCase):
-
- def test_setntacl(self):
- random.seed()
- lp = LoadParm()
- path = os.environ['SELFTEST_PREFIX']
- acl = "O:S-1-5-21-2212615479-2695158682-2101375467-512G:S-1-5-21-2212615479-2695158682-2101375467-513D:(A;OICI;0x001f01ff;;;S-1-5-21-2212615479-2695158682-2101375467-512)"
- tempf = os.path.join(path,"pytests"+str(int(100000*random.random())))
- ntacl = xattr.NTACL()
- ntacl.version = 1
- open(tempf, 'w').write("empty")
- lp.set("posix:eadb",os.path.join(path,"eadbtest.tdb"))
- setntacl(lp, tempf, acl, "S-1-5-21-2212615479-2695158682-2101375467")
- os.unlink(tempf)
-
- def test_setntacl_getntacl(self):
- random.seed()
- lp = LoadParm()
- path = None
- path = os.environ['SELFTEST_PREFIX']
- acl = "O:S-1-5-21-2212615479-2695158682-2101375467-512G:S-1-5-21-2212615479-2695158682-2101375467-513D:(A;OICI;0x001f01ff;;;S-1-5-21-2212615479-2695158682-2101375467-512)"
- tempf = os.path.join(path,"pytests"+str(int(100000*random.random())))
- ntacl = xattr.NTACL()
- ntacl.version = 1
- open(tempf, 'w').write("empty")
- lp.set("posix:eadb",os.path.join(path,"eadbtest.tdb"))
- setntacl(lp,tempf,acl,"S-1-5-21-2212615479-2695158682-2101375467")
- facl = getntacl(lp,tempf)
- anysid = security.dom_sid(security.SID_NT_SELF)
- self.assertEquals(facl.info.as_sddl(anysid),acl)
- os.unlink(tempf)
-
- def test_setntacl_getntacl_param(self):
- random.seed()
- lp = LoadParm()
- acl = "O:S-1-5-21-2212615479-2695158682-2101375467-512G:S-1-5-21-2212615479-2695158682-2101375467-513D:(A;OICI;0x001f01ff;;;S-1-5-21-2212615479-2695158682-2101375467-512)"
- path = os.environ['SELFTEST_PREFIX']
- tempf = os.path.join(path,"pytests"+str(int(100000*random.random())))
- ntacl = xattr.NTACL()
- ntacl.version = 1
- open(tempf, 'w').write("empty")
- setntacl(lp,tempf,acl,"S-1-5-21-2212615479-2695158682-2101375467","tdb",os.path.join(path,"eadbtest.tdb"))
- facl=getntacl(lp,tempf,"tdb",os.path.join(path,"eadbtest.tdb"))
- domsid=security.dom_sid(security.SID_NT_SELF)
- self.assertEquals(facl.info.as_sddl(domsid),acl)
- os.unlink(tempf)
-
- def test_setntacl_invalidbackend(self):
- random.seed()
- lp = LoadParm()
- acl = "O:S-1-5-21-2212615479-2695158682-2101375467-512G:S-1-5-21-2212615479-2695158682-2101375467-513D:(A;OICI;0x001f01ff;;;S-1-5-21-2212615479-2695158682-2101375467-512)"
- path = os.environ['SELFTEST_PREFIX']
- tempf = os.path.join(path,"pytests"+str(int(100000*random.random())))
- ntacl = xattr.NTACL()
- ntacl.version = 1
- open(tempf, 'w').write("empty")
- self.assertRaises(XattrBackendError, setntacl, lp, tempf, acl, "S-1-5-21-2212615479-2695158682-2101375467","ttdb", os.path.join(path,"eadbtest.tdb"))
-
- def test_setntacl_forcenative(self):
- if os.getuid() == 0:
- raise TestSkipped("Running test as root, test skipped")
- random.seed()
- lp = LoadParm()
- acl = "O:S-1-5-21-2212615479-2695158682-2101375467-512G:S-1-5-21-2212615479-2695158682-2101375467-513D:(A;OICI;0x001f01ff;;;S-1-5-21-2212615479-2695158682-2101375467-512)"
- path = os.environ['SELFTEST_PREFIX']
- tempf = os.path.join(path,"pytests"+str(int(100000*random.random())))
- ntacl = xattr.NTACL()
- ntacl.version = 1
- open(tempf, 'w').write("empty")
- lp.set("posix:eadb", os.path.join(path,"eadbtest.tdb"))
- self.assertRaises(Exception, setntacl, lp, tempf ,acl,
- "S-1-5-21-2212615479-2695158682-2101375467","native")
- os.unlink(tempf)
diff --git a/source4/scripting/python/samba/tests/param.py b/source4/scripting/python/samba/tests/param.py
deleted file mode 100644
index 7848e1c23b..0000000000
--- a/source4/scripting/python/samba/tests/param.py
+++ /dev/null
@@ -1,59 +0,0 @@
-#!/usr/bin/env python
-
-# Unix SMB/CIFS implementation.
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
-#
-# 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/>.
-#
-
-"""Tests for samba.param."""
-
-from samba import param
-import samba.tests
-
-class LoadParmTestCase(samba.tests.TestCase):
-
- def test_init(self):
- file = param.LoadParm()
- self.assertTrue(file is not None)
-
- def test_length(self):
- file = param.LoadParm()
- self.assertEquals(0, len(file))
-
- def test_set_workgroup(self):
- file = param.LoadParm()
- file.set("workgroup", "bla")
- self.assertEquals("BLA", file.get("workgroup"))
-
- def test_is_mydomain(self):
- file = param.LoadParm()
- file.set("workgroup", "bla")
- self.assertTrue(file.is_mydomain("BLA"))
- self.assertFalse(file.is_mydomain("FOOBAR"))
-
- def test_is_myname(self):
- file = param.LoadParm()
- file.set("netbios name", "bla")
- self.assertTrue(file.is_myname("BLA"))
- self.assertFalse(file.is_myname("FOOBAR"))
-
- def test_load_default(self):
- file = param.LoadParm()
- file.load_default()
-
- def test_section_nonexistant(self):
- samba_lp = param.LoadParm()
- samba_lp.load_default()
- self.assertRaises(KeyError, samba_lp.__getitem__, "nonexistant")
diff --git a/source4/scripting/python/samba/tests/provision.py b/source4/scripting/python/samba/tests/provision.py
index 39a01606bb..f34073504c 100644
--- a/source4/scripting/python/samba/tests/provision.py
+++ b/source4/scripting/python/samba/tests/provision.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
# Unix SMB/CIFS implementation.
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
@@ -17,44 +17,26 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-"""Tests for samba.provision."""
-
import os
-from samba.provision import setup_secretsdb, findnss, ProvisionPaths
+from samba.provision import setup_secretsdb, findnss
import samba.tests
-from samba.tests import env_loadparm, TestCase
+from ldb import Dn
+from samba import param
+import unittest
-def create_dummy_secretsdb(path, lp=None):
- """Create a dummy secrets database for use in tests.
+lp = samba.tests.cmdline_loadparm
- :param path: Path to store the secrets db
- :param lp: Optional loadparm context. A simple one will
- be generated if not specified.
- """
- if lp is None:
- lp = env_loadparm()
- paths = ProvisionPaths()
- paths.secrets = path
- paths.private_dir = os.path.dirname(path)
- paths.keytab = "no.keytab"
- paths.dns_keytab = "no.dns.keytab"
- secrets_ldb = setup_secretsdb(paths, None, None, lp=lp)
- secrets_ldb.transaction_commit()
- return secrets_ldb
+setup_dir = "setup"
+def setup_path(file):
+ return os.path.join(setup_dir, file)
class ProvisionTestCase(samba.tests.TestCaseInTempDir):
"""Some simple tests for individual functions in the provisioning code.
"""
-
def test_setup_secretsdb(self):
path = os.path.join(self.tempdir, "secrets.ldb")
- paths = ProvisionPaths()
- paths.secrets = path
- paths.private_dir = os.path.dirname(path)
- paths.keytab = "no.keytab"
- paths.dns_keytab = "no.dns.keytab"
- ldb = setup_secretsdb(paths, None, None, lp=env_loadparm())
+ ldb = setup_secretsdb(path, setup_path, None, None, lp=lp)
try:
self.assertEquals("LSA Secrets",
ldb.searchone(basedn="CN=LSA Secrets", attribute="CN"))
@@ -63,9 +45,8 @@ class ProvisionTestCase(samba.tests.TestCaseInTempDir):
os.unlink(path)
-class FindNssTests(TestCase):
+class FindNssTests(unittest.TestCase):
"""Test findnss() function."""
-
def test_nothing(self):
def x(y):
raise KeyError
@@ -83,7 +64,6 @@ class FindNssTests(TestCase):
class Disabled(object):
-
def test_setup_templatesdb(self):
raise NotImplementedError(self.test_setup_templatesdb)
@@ -114,4 +94,7 @@ class Disabled(object):
def test_vampire(self):
raise NotImplementedError(self.test_vampire)
+ def test_erase_partitions(self):
+ raise NotImplementedError(self.test_erase_partitions)
+
diff --git a/source4/scripting/python/samba/tests/registry.py b/source4/scripting/python/samba/tests/registry.py
deleted file mode 100644
index 97926850d2..0000000000
--- a/source4/scripting/python/samba/tests/registry.py
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/usr/bin/env python
-
-# Unix SMB/CIFS implementation.
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
-#
-# 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/>.
-#
-
-"""Tests for samba.registry."""
-
-import os
-from samba import registry
-import samba.tests
-
-class HelperTests(samba.tests.TestCase):
-
- def test_predef_to_name(self):
- self.assertEquals("HKEY_LOCAL_MACHINE",
- registry.get_predef_name(0x80000002))
-
- def test_str_regtype(self):
- self.assertEquals("REG_DWORD", registry.str_regtype(4))
-
-
-
-class HiveTests(samba.tests.TestCaseInTempDir):
-
- def setUp(self):
- super(HiveTests, self).setUp()
- self.hive_path = os.path.join(self.tempdir, "ldb_new.ldb")
- self.hive = registry.open_ldb(self.hive_path)
-
- def tearDown(self):
- del self.hive
- os.unlink(self.hive_path)
- super(HiveTests, self).tearDown()
-
- def test_ldb_new(self):
- self.assertTrue(self.hive is not None)
-
- #def test_flush(self):
- # self.hive.flush()
-
- #def test_del_value(self):
- # self.hive.del_value("FOO")
-
-
-class RegistryTests(samba.tests.TestCase):
-
- def test_new(self):
- self.registry = registry.Registry()
diff --git a/source4/scripting/python/samba/tests/samba3.py b/source4/scripting/python/samba/tests/samba3.py
index 3a4b851c75..71e08bdd7f 100644
--- a/source4/scripting/python/samba/tests/samba3.py
+++ b/source4/scripting/python/samba/tests/samba3.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
# Unix SMB/CIFS implementation.
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
@@ -17,30 +17,20 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-"""Tests for samba.samba3."""
-
-from samba.samba3 import (GroupMappingDatabase, Registry, PolicyDatabase,
- SecretsDatabase, TdbSam)
-from samba.samba3 import (WinsDatabase, SmbpasswdFile, ACB_NORMAL,
- IdmapDatabase, SAMUser, ParamFile)
-from samba.tests import TestCase
+import unittest
+from samba.samba3 import GroupMappingDatabase, Registry, PolicyDatabase, SecretsDatabase, TdbSam
+from samba.samba3 import WinsDatabase, SmbpasswdFile, ACB_NORMAL, IdmapDatabase, SAMUser, ParamFile
import os
-for p in [ "../../../../../testdata/samba3", "../../../../testdata/samba3" ]:
- DATADIR = os.path.join(os.path.dirname(__file__), p)
- if os.path.exists(DATADIR):
- break
-
-
-class RegistryTestCase(TestCase):
+DATADIR=os.path.join(os.path.dirname(__file__), "../../../../../testdata/samba3")
+print "Samba 3 data dir: %s" % DATADIR
+class RegistryTestCase(unittest.TestCase):
def setUp(self):
- super(RegistryTestCase, self).setUp()
self.registry = Registry(os.path.join(DATADIR, "registry.tdb"))
def tearDown(self):
self.registry.close()
- super(RegistryTestCase, self).tearDown()
def test_length(self):
self.assertEquals(28, len(self.registry))
@@ -57,10 +47,8 @@ class RegistryTestCase(TestCase):
self.registry.values("HKLM/SYSTEM/CURRENTCONTROLSET/SERVICES/EVENTLOG"))
-class PolicyTestCase(TestCase):
-
+class PolicyTestCase(unittest.TestCase):
def setUp(self):
- super(PolicyTestCase, self).setUp()
self.policy = PolicyDatabase(os.path.join(DATADIR, "account_policy.tdb"))
def test_policy(self):
@@ -76,15 +64,12 @@ class PolicyTestCase(TestCase):
self.assertEquals(self.policy.bad_lockout_minutes, None)
-class GroupsTestCase(TestCase):
-
+class GroupsTestCase(unittest.TestCase):
def setUp(self):
- super(GroupsTestCase, self).setUp()
self.groupdb = GroupMappingDatabase(os.path.join(DATADIR, "group_mapping.tdb"))
def tearDown(self):
self.groupdb.close()
- super(GroupsTestCase, self).tearDown()
def test_group_length(self):
self.assertEquals(13, len(list(self.groupdb.groupsids())))
@@ -100,29 +85,23 @@ class GroupsTestCase(TestCase):
self.assertEquals(0, len(list(self.groupdb.aliases())))
-class SecretsDbTestCase(TestCase):
-
+class SecretsDbTestCase(unittest.TestCase):
def setUp(self):
- super(SecretsDbTestCase, self).setUp()
self.secretsdb = SecretsDatabase(os.path.join(DATADIR, "secrets.tdb"))
def tearDown(self):
self.secretsdb.close()
- super(SecretsDbTestCase, self).tearDown()
def test_get_sid(self):
self.assertTrue(self.secretsdb.get_sid("BEDWYR") is not None)
-class TdbSamTestCase(TestCase):
-
+class TdbSamTestCase(unittest.TestCase):
def setUp(self):
- super(TdbSamTestCase, self).setUp()
self.samdb = TdbSam(os.path.join(DATADIR, "passdb.tdb"))
def tearDown(self):
self.samdb.close()
- super(TdbSamTestCase, self).tearDown()
def test_usernames(self):
self.assertEquals(3, len(list(self.samdb.usernames())))
@@ -161,10 +140,8 @@ class TdbSamTestCase(TestCase):
self.assertEquals(user, other)
-class WinsDatabaseTestCase(TestCase):
-
+class WinsDatabaseTestCase(unittest.TestCase):
def setUp(self):
- super(WinsDatabaseTestCase, self).setUp()
self.winsdb = WinsDatabase(os.path.join(DATADIR, "wins.dat"))
def test_length(self):
@@ -175,13 +152,10 @@ class WinsDatabaseTestCase(TestCase):
def tearDown(self):
self.winsdb.close()
- super(WinsDatabaseTestCase, self).tearDown()
-class SmbpasswdTestCase(TestCase):
-
+class SmbpasswdTestCase(unittest.TestCase):
def setUp(self):
- super(SmbpasswdTestCase, self).setUp()
self.samdb = SmbpasswdFile(os.path.join(DATADIR, "smbpasswd"))
def test_length(self):
@@ -198,15 +172,11 @@ class SmbpasswdTestCase(TestCase):
def tearDown(self):
self.samdb.close()
- super(SmbpasswdTestCase, self).tearDown()
-
-class IdmapDbTestCase(TestCase):
+class IdmapDbTestCase(unittest.TestCase):
def setUp(self):
- super(IdmapDbTestCase, self).setUp()
- self.idmapdb = IdmapDatabase(os.path.join(DATADIR,
- "winbindd_idmap.tdb"))
+ self.idmapdb = IdmapDatabase(os.path.join(DATADIR, "winbindd_idmap.tdb"))
def test_user_hwm(self):
self.assertEquals(10000, self.idmapdb.get_user_hwm())
@@ -228,11 +198,19 @@ class IdmapDbTestCase(TestCase):
def tearDown(self):
self.idmapdb.close()
- super(IdmapDbTestCase, self).tearDown()
-class ParamTestCase(TestCase):
+class ShareInfoTestCase(unittest.TestCase):
+ def setUp(self):
+ self.shareinfodb = ShareInfoDatabase(os.path.join(DATADIR, "share_info.tdb"))
+
+ # FIXME: needs proper data so it can be tested
+
+ def tearDown(self):
+ self.shareinfodb.close()
+
+class ParamTestCase(unittest.TestCase):
def test_init(self):
file = ParamFile()
self.assertTrue(file is not None)
diff --git a/source4/scripting/python/samba/tests/samba3sam.py b/source4/scripting/python/samba/tests/samba3sam.py
deleted file mode 100644
index a34f0f620c..0000000000
--- a/source4/scripting/python/samba/tests/samba3sam.py
+++ /dev/null
@@ -1,1096 +0,0 @@
-#!/usr/bin/env python
-
-# Unix SMB/CIFS implementation.
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2005-2008
-# Copyright (C) Martin Kuehl <mkhl@samba.org> 2006
-#
-# This is a Python port of the original in testprogs/ejs/samba3sam.js
-#
-# 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/>.
-#
-
-"""Tests for the samba3sam LDB module, which maps Samba3 LDAP to AD LDAP."""
-
-import os
-import ldb
-from ldb import SCOPE_DEFAULT, SCOPE_BASE
-from samba import Ldb, substitute_var
-from samba.tests import TestCaseInTempDir, env_loadparm
-import samba.dcerpc.security
-import samba.ndr
-from samba.auth import system_session
-
-
-def read_datafile(filename):
- paths = [ "../../../../../testdata/samba3",
- "../../../../testdata/samba3" ]
- for p in paths:
- datadir = os.path.join(os.path.dirname(__file__), p)
- if os.path.exists(datadir):
- break
- return open(os.path.join(datadir, filename), 'r').read()
-
-def ldb_debug(l, text):
- print text
-
-
-class MapBaseTestCase(TestCaseInTempDir):
- """Base test case for mapping tests."""
-
- def setup_modules(self, ldb, s3, s4):
- ldb.add({"dn": "@MAP=samba3sam",
- "@FROM": s4.basedn,
- "@TO": "sambaDomainName=TESTS," + s3.basedn})
-
- ldb.add({"dn": "@MODULES",
- "@LIST": "rootdse,paged_results,server_sort,asq,samldb,password_hash,operational,objectguid,rdn_name,samba3sam,samba3sid,partition"})
-
- ldb.add({"dn": "@PARTITION",
- "partition": ["%s" % (s4.basedn_casefold),
- "%s" % (s3.basedn_casefold)],
- "replicateEntries": ["@ATTRIBUTES", "@INDEXLIST"],
- "modules": "*:"})
-
- def setUp(self):
- self.lp = env_loadparm()
- self.lp.set("sid generator", "backend")
- self.lp.set("workgroup", "TESTS")
- self.lp.set("netbios name", "TESTS")
- super(MapBaseTestCase, self).setUp()
-
- def make_dn(basedn, rdn):
- return "%s,sambaDomainName=TESTS,%s" % (rdn, basedn)
-
- def make_s4dn(basedn, rdn):
- return "%s,%s" % (rdn, basedn)
-
- self.ldbfile = os.path.join(self.tempdir, "test.ldb")
- self.ldburl = "tdb://" + self.ldbfile
-
- tempdir = self.tempdir
-
- class Target:
- """Simple helper class that contains data for a specific SAM
- connection."""
-
- def __init__(self, basedn, dn, lp):
- self.db = Ldb(lp=lp, session_info=system_session())
- self.basedn = basedn
- self.basedn_casefold = ldb.Dn(self.db, basedn).get_casefold()
- self.substvars = {"BASEDN": self.basedn}
- self.file = os.path.join(tempdir, "%s.ldb" % self.basedn_casefold)
- self.url = "tdb://" + self.file
- self._dn = dn
-
- def dn(self, rdn):
- return self._dn(self.basedn, rdn)
-
- def connect(self):
- return self.db.connect(self.url)
-
- def setup_data(self, path):
- self.add_ldif(read_datafile(path))
-
- def subst(self, text):
- return substitute_var(text, self.substvars)
-
- def add_ldif(self, ldif):
- self.db.add_ldif(self.subst(ldif))
-
- def modify_ldif(self, ldif):
- self.db.modify_ldif(self.subst(ldif))
-
- self.samba4 = Target("dc=vernstok,dc=nl", make_s4dn, self.lp)
- self.samba3 = Target("cn=Samba3Sam", make_dn, self.lp)
-
- self.samba3.connect()
- self.samba4.connect()
-
- def tearDown(self):
- os.unlink(self.ldbfile)
- os.unlink(self.samba3.file)
- os.unlink(self.samba4.file)
- super(MapBaseTestCase, self).tearDown()
-
- def assertSidEquals(self, text, ndr_sid):
- sid_obj1 = samba.ndr.ndr_unpack(samba.dcerpc.security.dom_sid,
- str(ndr_sid[0]))
- sid_obj2 = samba.dcerpc.security.dom_sid(text)
- self.assertEquals(sid_obj1, sid_obj2)
-
-
-class Samba3SamTestCase(MapBaseTestCase):
-
- def setUp(self):
- super(Samba3SamTestCase, self).setUp()
- ldb = Ldb(self.ldburl, lp=self.lp, session_info=system_session())
- self.samba3.setup_data("samba3.ldif")
- ldif = read_datafile("provision_samba3sam.ldif")
- ldb.add_ldif(self.samba4.subst(ldif))
- self.setup_modules(ldb, self.samba3, self.samba4)
- del ldb
- self.ldb = Ldb(self.ldburl, lp=self.lp, session_info=system_session())
-
- def test_search_non_mapped(self):
- """Looking up by non-mapped attribute"""
- msg = self.ldb.search(expression="(cn=Administrator)")
- self.assertEquals(len(msg), 1)
- self.assertEquals(msg[0]["cn"], "Administrator")
-
- def test_search_non_mapped(self):
- """Looking up by mapped attribute"""
- msg = self.ldb.search(expression="(name=Backup Operators)")
- self.assertEquals(len(msg), 1)
- self.assertEquals(str(msg[0]["name"]), "Backup Operators")
-
- def test_old_name_of_renamed(self):
- """Looking up by old name of renamed attribute"""
- msg = self.ldb.search(expression="(displayName=Backup Operators)")
- self.assertEquals(len(msg), 0)
-
- def test_mapped_containing_sid(self):
- """Looking up mapped entry containing SID"""
- msg = self.ldb.search(expression="(cn=Replicator)")
- self.assertEquals(len(msg), 1)
- self.assertEquals(str(msg[0].dn),
- "cn=Replicator,ou=Groups,dc=vernstok,dc=nl")
- self.assertTrue("objectSid" in msg[0])
- self.assertSidEquals("S-1-5-21-4231626423-2410014848-2360679739-552",
- msg[0]["objectSid"])
- oc = set(msg[0]["objectClass"])
- self.assertEquals(oc, set(["group"]))
-
- def test_search_by_objclass(self):
- """Looking up by objectClass"""
- msg = self.ldb.search(expression="(|(objectClass=user)(cn=Administrator))")
- self.assertEquals(set([str(m.dn) for m in msg]),
- set(["unixName=Administrator,ou=Users,dc=vernstok,dc=nl",
- "unixName=nobody,ou=Users,dc=vernstok,dc=nl"]))
-
- def test_s3sam_modify(self):
- # Adding a record that will be fallbacked
- self.ldb.add({"dn": "cn=Foo",
- "foo": "bar",
- "blah": "Blie",
- "cn": "Foo",
- "showInAdvancedViewOnly": "TRUE"}
- )
-
- # Checking for existence of record (local)
- # TODO: This record must be searched in the local database, which is
- # currently only supported for base searches
- # msg = ldb.search(expression="(cn=Foo)", ['foo','blah','cn','showInAdvancedViewOnly')]
- # TODO: Actually, this version should work as well but doesn't...
- #
- #
- msg = self.ldb.search(expression="(cn=Foo)", base="cn=Foo",
- scope=SCOPE_BASE,
- attrs=['foo','blah','cn','showInAdvancedViewOnly'])
- self.assertEquals(len(msg), 1)
- self.assertEquals(str(msg[0]["showInAdvancedViewOnly"]), "TRUE")
- self.assertEquals(str(msg[0]["foo"]), "bar")
- self.assertEquals(str(msg[0]["blah"]), "Blie")
-
- # Adding record that will be mapped
- self.ldb.add({"dn": "cn=Niemand,cn=Users,dc=vernstok,dc=nl",
- "objectClass": "user",
- "unixName": "bin",
- "sambaUnicodePwd": "geheim",
- "cn": "Niemand"})
-
- # Checking for existence of record (remote)
- msg = self.ldb.search(expression="(unixName=bin)",
- attrs=['unixName','cn','dn', 'sambaUnicodePwd'])
- self.assertEquals(len(msg), 1)
- self.assertEquals(str(msg[0]["cn"]), "Niemand")
- self.assertEquals(str(msg[0]["sambaUnicodePwd"]), "geheim")
-
- # Checking for existence of record (local && remote)
- msg = self.ldb.search(expression="(&(unixName=bin)(sambaUnicodePwd=geheim))",
- attrs=['unixName','cn','dn', 'sambaUnicodePwd'])
- self.assertEquals(len(msg), 1) # TODO: should check with more records
- self.assertEquals(str(msg[0]["cn"]), "Niemand")
- self.assertEquals(str(msg[0]["unixName"]), "bin")
- self.assertEquals(str(msg[0]["sambaUnicodePwd"]), "geheim")
-
- # Checking for existence of record (local || remote)
- msg = self.ldb.search(expression="(|(unixName=bin)(sambaUnicodePwd=geheim))",
- attrs=['unixName','cn','dn', 'sambaUnicodePwd'])
- #print "got %d replies" % len(msg)
- self.assertEquals(len(msg), 1) # TODO: should check with more records
- self.assertEquals(str(msg[0]["cn"]), "Niemand")
- self.assertEquals(str(msg[0]["unixName"]), "bin")
- self.assertEquals(str(msg[0]["sambaUnicodePwd"]), "geheim")
-
- # Checking for data in destination database
- msg = self.samba3.db.search(expression="(cn=Niemand)")
- self.assertTrue(len(msg) >= 1)
- self.assertEquals(str(msg[0]["sambaSID"]),
- "S-1-5-21-4231626423-2410014848-2360679739-2001")
- self.assertEquals(str(msg[0]["displayName"]), "Niemand")
-
- # Adding attribute...
- self.ldb.modify_ldif("""
-dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl
-changetype: modify
-add: description
-description: Blah
-""")
-
- # Checking whether changes are still there...
- msg = self.ldb.search(expression="(cn=Niemand)")
- self.assertTrue(len(msg) >= 1)
- self.assertEquals(str(msg[0]["cn"]), "Niemand")
- self.assertEquals(str(msg[0]["description"]), "Blah")
-
- # Modifying attribute...
- self.ldb.modify_ldif("""
-dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl
-changetype: modify
-replace: description
-description: Blie
-""")
-
- # Checking whether changes are still there...
- msg = self.ldb.search(expression="(cn=Niemand)")
- self.assertTrue(len(msg) >= 1)
- self.assertEquals(str(msg[0]["description"]), "Blie")
-
- # Deleting attribute...
- self.ldb.modify_ldif("""
-dn: cn=Niemand,cn=Users,dc=vernstok,dc=nl
-changetype: modify
-delete: description
-""")
-
- # Checking whether changes are no longer there...
- msg = self.ldb.search(expression="(cn=Niemand)")
- self.assertTrue(len(msg) >= 1)
- self.assertTrue(not "description" in msg[0])
-
- # Renaming record...
- self.ldb.rename("cn=Niemand,cn=Users,dc=vernstok,dc=nl",
- "cn=Niemand2,cn=Users,dc=vernstok,dc=nl")
-
- # Checking whether DN has changed...
- msg = self.ldb.search(expression="(cn=Niemand2)")
- self.assertEquals(len(msg), 1)
- self.assertEquals(str(msg[0].dn),
- "cn=Niemand2,cn=Users,dc=vernstok,dc=nl")
-
- # Deleting record...
- self.ldb.delete("cn=Niemand2,cn=Users,dc=vernstok,dc=nl")
-
- # Checking whether record is gone...
- msg = self.ldb.search(expression="(cn=Niemand2)")
- self.assertEquals(len(msg), 0)
-
-
-class MapTestCase(MapBaseTestCase):
-
- def setUp(self):
- super(MapTestCase, self).setUp()
- ldb = Ldb(self.ldburl, lp=self.lp, session_info=system_session())
- ldif = read_datafile("provision_samba3sam.ldif")
- ldb.add_ldif(self.samba4.subst(ldif))
- self.setup_modules(ldb, self.samba3, self.samba4)
- del ldb
- self.ldb = Ldb(self.ldburl, lp=self.lp, session_info=system_session())
-
- def test_map_search(self):
- """Running search tests on mapped data."""
- self.samba3.db.add({
- "dn": "sambaDomainName=TESTS," + self.samba3.basedn,
- "objectclass": ["sambaDomain", "top"],
- "sambaSID": "S-1-5-21-4231626423-2410014848-2360679739",
- "sambaNextRid": "2000",
- "sambaDomainName": "TESTS"
- })
-
- # Add a set of split records
- self.ldb.add_ldif("""
-dn: """+ self.samba4.dn("cn=Domain Users") + """
-objectClass: group
-cn: Domain Users
-objectSid: S-1-5-21-4231626423-2410014848-2360679739-513
-""")
-
- # Add a set of split records
- self.ldb.add_ldif("""
-dn: """+ self.samba4.dn("cn=X") + """
-objectClass: user
-cn: X
-codePage: x
-revision: x
-dnsHostName: x
-nextRid: y
-lastLogon: x
-description: x
-objectSid: S-1-5-21-4231626423-2410014848-2360679739-552
-""")
-
- self.ldb.add({
- "dn": self.samba4.dn("cn=Y"),
- "objectClass": "top",
- "cn": "Y",
- "codePage": "x",
- "revision": "x",
- "dnsHostName": "y",
- "nextRid": "y",
- "lastLogon": "y",
- "description": "x"})
-
- self.ldb.add({
- "dn": self.samba4.dn("cn=Z"),
- "objectClass": "top",
- "cn": "Z",
- "codePage": "x",
- "revision": "y",
- "dnsHostName": "z",
- "nextRid": "y",
- "lastLogon": "z",
- "description": "y"})
-
- # Add a set of remote records
-
- self.samba3.db.add({
- "dn": self.samba3.dn("cn=A"),
- "objectClass": "posixAccount",
- "cn": "A",
- "sambaNextRid": "x",
- "sambaBadPasswordCount": "x",
- "sambaLogonTime": "x",
- "description": "x",
- "sambaSID": "S-1-5-21-4231626423-2410014848-2360679739-552",
- "sambaPrimaryGroupSID": "S-1-5-21-4231626423-2410014848-2360679739-512"})
-
- self.samba3.db.add({
- "dn": self.samba3.dn("cn=B"),
- "objectClass": "top",
- "cn": "B",
- "sambaNextRid": "x",
- "sambaBadPasswordCount": "x",
- "sambaLogonTime": "y",
- "description": "x"})
-
- self.samba3.db.add({
- "dn": self.samba3.dn("cn=C"),
- "objectClass": "top",
- "cn": "C",
- "sambaNextRid": "x",
- "sambaBadPasswordCount": "y",
- "sambaLogonTime": "z",
- "description": "y"})
-
- # Testing search by DN
-
- # Search remote record by local DN
- dn = self.samba4.dn("cn=A")
- res = self.ldb.search(dn, scope=SCOPE_BASE,
- attrs=["dnsHostName", "lastLogon"])
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn)
- self.assertTrue(not "dnsHostName" in res[0])
- self.assertEquals(str(res[0]["lastLogon"]), "x")
-
- # Search remote record by remote DN
- dn = self.samba3.dn("cn=A")
- res = self.samba3.db.search(dn, scope=SCOPE_BASE,
- attrs=["dnsHostName", "lastLogon", "sambaLogonTime"])
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn)
- self.assertTrue(not "dnsHostName" in res[0])
- self.assertTrue(not "lastLogon" in res[0])
- self.assertEquals(str(res[0]["sambaLogonTime"]), "x")
-
- # Search split record by local DN
- dn = self.samba4.dn("cn=X")
- res = self.ldb.search(dn, scope=SCOPE_BASE,
- attrs=["dnsHostName", "lastLogon"])
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn)
- self.assertEquals(str(res[0]["dnsHostName"]), "x")
- self.assertEquals(str(res[0]["lastLogon"]), "x")
-
- # Search split record by remote DN
- dn = self.samba3.dn("cn=X")
- res = self.samba3.db.search(dn, scope=SCOPE_BASE,
- attrs=["dnsHostName", "lastLogon", "sambaLogonTime"])
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn)
- self.assertTrue(not "dnsHostName" in res[0])
- self.assertTrue(not "lastLogon" in res[0])
- self.assertEquals(str(res[0]["sambaLogonTime"]), "x")
-
- # Testing search by attribute
-
- # Search by ignored attribute
- res = self.ldb.search(expression="(revision=x)", scope=SCOPE_DEFAULT,
- attrs=["dnsHostName", "lastLogon"])
- self.assertEquals(len(res), 2)
- self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y"))
- self.assertEquals(str(res[0]["dnsHostName"]), "y")
- self.assertEquals(str(res[0]["lastLogon"]), "y")
- self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X"))
- self.assertEquals(str(res[1]["dnsHostName"]), "x")
- self.assertEquals(str(res[1]["lastLogon"]), "x")
-
- # Search by kept attribute
- res = self.ldb.search(expression="(description=y)",
- scope=SCOPE_DEFAULT, attrs=["dnsHostName", "lastLogon"])
- self.assertEquals(len(res), 2)
- self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Z"))
- self.assertEquals(str(res[0]["dnsHostName"]), "z")
- self.assertEquals(str(res[0]["lastLogon"]), "z")
- self.assertEquals(str(res[1].dn), self.samba4.dn("cn=C"))
- self.assertTrue(not "dnsHostName" in res[1])
- self.assertEquals(str(res[1]["lastLogon"]), "z")
-
- # Search by renamed attribute
- res = self.ldb.search(expression="(badPwdCount=x)", scope=SCOPE_DEFAULT,
- attrs=["dnsHostName", "lastLogon"])
- self.assertEquals(len(res), 2)
- self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B"))
- self.assertTrue(not "dnsHostName" in res[0])
- self.assertEquals(str(res[0]["lastLogon"]), "y")
- self.assertEquals(str(res[1].dn), self.samba4.dn("cn=A"))
- self.assertTrue(not "dnsHostName" in res[1])
- self.assertEquals(str(res[1]["lastLogon"]), "x")
-
- # Search by converted attribute
- # TODO:
- # Using the SID directly in the parse tree leads to conversion
- # errors, letting the search fail with no results.
- #res = self.ldb.search("(objectSid=S-1-5-21-4231626423-2410014848-2360679739-552)", scope=SCOPE_DEFAULT, attrs)
- res = self.ldb.search(expression="(objectSid=*)", base=None, scope=SCOPE_DEFAULT, attrs=["dnsHostName", "lastLogon", "objectSid"])
- self.assertEquals(len(res), 4)
- self.assertEquals(str(res[0].dn), self.samba4.dn("cn=X"))
- self.assertEquals(str(res[0]["dnsHostName"]), "x")
- self.assertEquals(str(res[0]["lastLogon"]), "x")
- self.assertSidEquals("S-1-5-21-4231626423-2410014848-2360679739-552",
- res[0]["objectSid"])
- self.assertTrue("objectSid" in res[0])
- self.assertEquals(str(res[1].dn), self.samba4.dn("cn=A"))
- self.assertTrue(not "dnsHostName" in res[1])
- self.assertEquals(str(res[1]["lastLogon"]), "x")
- self.assertSidEquals("S-1-5-21-4231626423-2410014848-2360679739-552",
- res[1]["objectSid"])
- self.assertTrue("objectSid" in res[1])
-
- # Search by generated attribute
- # In most cases, this even works when the mapping is missing
- # a `convert_operator' by enumerating the remote db.
- res = self.ldb.search(expression="(primaryGroupID=512)",
- attrs=["dnsHostName", "lastLogon", "primaryGroupID"])
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A"))
- self.assertTrue(not "dnsHostName" in res[0])
- self.assertEquals(str(res[0]["lastLogon"]), "x")
- self.assertEquals(str(res[0]["primaryGroupID"]), "512")
-
- # Note that Xs "objectSid" seems to be fine in the previous search for
- # "objectSid"...
- #res = ldb.search(expression="(primaryGroupID=*)", NULL, ldb. SCOPE_DEFAULT, attrs)
- #print len(res) + " results found"
- #for i in range(len(res)):
- # for (obj in res[i]) {
- # print obj + ": " + res[i][obj]
- # }
- # print "---"
- #
-
- # Search by remote name of renamed attribute */
- res = self.ldb.search(expression="(sambaBadPasswordCount=*)",
- attrs=["dnsHostName", "lastLogon"])
- self.assertEquals(len(res), 0)
-
- # Search by objectClass
- attrs = ["dnsHostName", "lastLogon", "objectClass"]
- res = self.ldb.search(expression="(objectClass=user)", attrs=attrs)
- self.assertEquals(len(res), 2)
- self.assertEquals(str(res[0].dn), self.samba4.dn("cn=X"))
- self.assertEquals(str(res[0]["dnsHostName"]), "x")
- self.assertEquals(str(res[0]["lastLogon"]), "x")
- self.assertEquals(str(res[0]["objectClass"][0]), "user")
- self.assertEquals(str(res[1].dn), self.samba4.dn("cn=A"))
- self.assertTrue(not "dnsHostName" in res[1])
- self.assertEquals(str(res[1]["lastLogon"]), "x")
- self.assertEquals(str(res[1]["objectClass"][0]), "user")
-
- # Prove that the objectClass is actually used for the search
- res = self.ldb.search(expression="(|(objectClass=user)(badPwdCount=x))",
- attrs=attrs)
- self.assertEquals(len(res), 3)
- self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B"))
- self.assertTrue(not "dnsHostName" in res[0])
- self.assertEquals(str(res[0]["lastLogon"]), "y")
- self.assertEquals(set(res[0]["objectClass"]), set(["top"]))
- self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X"))
- self.assertEquals(str(res[1]["dnsHostName"]), "x")
- self.assertEquals(str(res[1]["lastLogon"]), "x")
- self.assertEquals(str(res[1]["objectClass"][0]), "user")
- self.assertEquals(str(res[2].dn), self.samba4.dn("cn=A"))
- self.assertTrue(not "dnsHostName" in res[2])
- self.assertEquals(str(res[2]["lastLogon"]), "x")
- self.assertEquals(res[2]["objectClass"][0], "user")
-
- # Testing search by parse tree
-
- # Search by conjunction of local attributes
- res = self.ldb.search(expression="(&(codePage=x)(revision=x))",
- attrs=["dnsHostName", "lastLogon"])
- self.assertEquals(len(res), 2)
- self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y"))
- self.assertEquals(str(res[0]["dnsHostName"]), "y")
- self.assertEquals(str(res[0]["lastLogon"]), "y")
- self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X"))
- self.assertEquals(str(res[1]["dnsHostName"]), "x")
- self.assertEquals(str(res[1]["lastLogon"]), "x")
-
- # Search by conjunction of remote attributes
- res = self.ldb.search(expression="(&(lastLogon=x)(description=x))",
- attrs=["dnsHostName", "lastLogon"])
- self.assertEquals(len(res), 2)
- self.assertEquals(str(res[0].dn), self.samba4.dn("cn=X"))
- self.assertEquals(str(res[0]["dnsHostName"]), "x")
- self.assertEquals(str(res[0]["lastLogon"]), "x")
- self.assertEquals(str(res[1].dn), self.samba4.dn("cn=A"))
- self.assertTrue(not "dnsHostName" in res[1])
- self.assertEquals(str(res[1]["lastLogon"]), "x")
-
- # Search by conjunction of local and remote attribute
- res = self.ldb.search(expression="(&(codePage=x)(description=x))",
- attrs=["dnsHostName", "lastLogon"])
- self.assertEquals(len(res), 2)
- self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y"))
- self.assertEquals(str(res[0]["dnsHostName"]), "y")
- self.assertEquals(str(res[0]["lastLogon"]), "y")
- self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X"))
- self.assertEquals(str(res[1]["dnsHostName"]), "x")
- self.assertEquals(str(res[1]["lastLogon"]), "x")
-
- # Search by conjunction of local and remote attribute w/o match
- attrs = ["dnsHostName", "lastLogon"]
- res = self.ldb.search(expression="(&(codePage=x)(nextRid=x))",
- attrs=attrs)
- self.assertEquals(len(res), 0)
- res = self.ldb.search(expression="(&(revision=x)(lastLogon=z))",
- attrs=attrs)
- self.assertEquals(len(res), 0)
-
- # Search by disjunction of local attributes
- res = self.ldb.search(expression="(|(revision=x)(dnsHostName=x))",
- attrs=["dnsHostName", "lastLogon"])
- self.assertEquals(len(res), 2)
- self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y"))
- self.assertEquals(str(res[0]["dnsHostName"]), "y")
- self.assertEquals(str(res[0]["lastLogon"]), "y")
- self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X"))
- self.assertEquals(str(res[1]["dnsHostName"]), "x")
- self.assertEquals(str(res[1]["lastLogon"]), "x")
-
- # Search by disjunction of remote attributes
- res = self.ldb.search(expression="(|(badPwdCount=x)(lastLogon=x))",
- attrs=["dnsHostName", "lastLogon"])
- self.assertEquals(len(res), 3)
- self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B"))
- self.assertFalse("dnsHostName" in res[0])
- self.assertEquals(str(res[0]["lastLogon"]), "y")
- self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X"))
- self.assertEquals(str(res[1]["dnsHostName"]), "x")
- self.assertEquals(str(res[1]["lastLogon"]), "x")
- self.assertEquals(str(res[2].dn), self.samba4.dn("cn=A"))
- self.assertFalse("dnsHostName" in res[2])
- self.assertEquals(str(res[2]["lastLogon"]), "x")
-
- # Search by disjunction of local and remote attribute
- res = self.ldb.search(expression="(|(revision=x)(lastLogon=y))",
- attrs=["dnsHostName", "lastLogon"])
- self.assertEquals(len(res), 3)
- self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y"))
- self.assertEquals(str(res[0]["dnsHostName"]), "y")
- self.assertEquals(str(res[0]["lastLogon"]), "y")
- self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B"))
- self.assertFalse("dnsHostName" in res[1])
- self.assertEquals(str(res[1]["lastLogon"]), "y")
- self.assertEquals(str(res[2].dn), self.samba4.dn("cn=X"))
- self.assertEquals(str(res[2]["dnsHostName"]), "x")
- self.assertEquals(str(res[2]["lastLogon"]), "x")
-
- # Search by disjunction of local and remote attribute w/o match
- res = self.ldb.search(expression="(|(codePage=y)(nextRid=z))",
- attrs=["dnsHostName", "lastLogon"])
- self.assertEquals(len(res), 0)
-
- # Search by negated local attribute
- res = self.ldb.search(expression="(!(revision=x))",
- attrs=["dnsHostName", "lastLogon"])
- self.assertEquals(len(res), 6)
- self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B"))
- self.assertTrue(not "dnsHostName" in res[0])
- self.assertEquals(str(res[0]["lastLogon"]), "y")
- self.assertEquals(str(res[1].dn), self.samba4.dn("cn=A"))
- self.assertTrue(not "dnsHostName" in res[1])
- self.assertEquals(str(res[1]["lastLogon"]), "x")
- self.assertEquals(str(res[2].dn), self.samba4.dn("cn=Z"))
- self.assertEquals(str(res[2]["dnsHostName"]), "z")
- self.assertEquals(str(res[2]["lastLogon"]), "z")
- self.assertEquals(str(res[3].dn), self.samba4.dn("cn=C"))
- self.assertTrue(not "dnsHostName" in res[3])
- self.assertEquals(str(res[3]["lastLogon"]), "z")
-
- # Search by negated remote attribute
- res = self.ldb.search(expression="(!(description=x))",
- attrs=["dnsHostName", "lastLogon"])
- self.assertEquals(len(res), 4)
- self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Z"))
- self.assertEquals(str(res[0]["dnsHostName"]), "z")
- self.assertEquals(str(res[0]["lastLogon"]), "z")
- self.assertEquals(str(res[1].dn), self.samba4.dn("cn=C"))
- self.assertTrue(not "dnsHostName" in res[1])
- self.assertEquals(str(res[1]["lastLogon"]), "z")
-
- # Search by negated conjunction of local attributes
- res = self.ldb.search(expression="(!(&(codePage=x)(revision=x)))",
- attrs=["dnsHostName", "lastLogon"])
- self.assertEquals(len(res), 6)
- self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B"))
- self.assertTrue(not "dnsHostName" in res[0])
- self.assertEquals(str(res[0]["lastLogon"]), "y")
- self.assertEquals(str(res[1].dn), self.samba4.dn("cn=A"))
- self.assertTrue(not "dnsHostName" in res[1])
- self.assertEquals(str(res[1]["lastLogon"]), "x")
- self.assertEquals(str(res[2].dn), self.samba4.dn("cn=Z"))
- self.assertEquals(str(res[2]["dnsHostName"]), "z")
- self.assertEquals(str(res[2]["lastLogon"]), "z")
- self.assertEquals(str(res[3].dn), self.samba4.dn("cn=C"))
- self.assertTrue(not "dnsHostName" in res[3])
- self.assertEquals(str(res[3]["lastLogon"]), "z")
-
- # Search by negated conjunction of remote attributes
- res = self.ldb.search(expression="(!(&(lastLogon=x)(description=x)))",
- attrs=["dnsHostName", "lastLogon"])
- self.assertEquals(len(res), 6)
- self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y"))
- self.assertEquals(str(res[0]["dnsHostName"]), "y")
- self.assertEquals(str(res[0]["lastLogon"]), "y")
- self.assertEquals(str(res[1].dn), self.samba4.dn("cn=B"))
- self.assertTrue(not "dnsHostName" in res[1])
- self.assertEquals(str(res[1]["lastLogon"]), "y")
- self.assertEquals(str(res[2].dn), self.samba4.dn("cn=Z"))
- self.assertEquals(str(res[2]["dnsHostName"]), "z")
- self.assertEquals(str(res[2]["lastLogon"]), "z")
- self.assertEquals(str(res[3].dn), self.samba4.dn("cn=C"))
- self.assertTrue(not "dnsHostName" in res[3])
- self.assertEquals(str(res[3]["lastLogon"]), "z")
-
- # Search by negated conjunction of local and remote attribute
- res = self.ldb.search(expression="(!(&(codePage=x)(description=x)))",
- attrs=["dnsHostName", "lastLogon"])
- self.assertEquals(len(res), 6)
- self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B"))
- self.assertTrue(not "dnsHostName" in res[0])
- self.assertEquals(str(res[0]["lastLogon"]), "y")
- self.assertEquals(str(res[1].dn), self.samba4.dn("cn=A"))
- self.assertTrue(not "dnsHostName" in res[1])
- self.assertEquals(str(res[1]["lastLogon"]), "x")
- self.assertEquals(str(res[2].dn), self.samba4.dn("cn=Z"))
- self.assertEquals(str(res[2]["dnsHostName"]), "z")
- self.assertEquals(str(res[2]["lastLogon"]), "z")
- self.assertEquals(str(res[3].dn), self.samba4.dn("cn=C"))
- self.assertTrue(not "dnsHostName" in res[3])
- self.assertEquals(str(res[3]["lastLogon"]), "z")
-
- # Search by negated disjunction of local attributes
- res = self.ldb.search(expression="(!(|(revision=x)(dnsHostName=x)))",
- attrs=["dnsHostName", "lastLogon"])
- self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B"))
- self.assertTrue(not "dnsHostName" in res[0])
- self.assertEquals(str(res[0]["lastLogon"]), "y")
- self.assertEquals(str(res[1].dn), self.samba4.dn("cn=A"))
- self.assertTrue(not "dnsHostName" in res[1])
- self.assertEquals(str(res[1]["lastLogon"]), "x")
- self.assertEquals(str(res[2].dn), self.samba4.dn("cn=Z"))
- self.assertEquals(str(res[2]["dnsHostName"]), "z")
- self.assertEquals(str(res[2]["lastLogon"]), "z")
- self.assertEquals(str(res[3].dn), self.samba4.dn("cn=C"))
- self.assertTrue(not "dnsHostName" in res[3])
- self.assertEquals(str(res[3]["lastLogon"]), "z")
-
- # Search by negated disjunction of remote attributes
- res = self.ldb.search(expression="(!(|(badPwdCount=x)(lastLogon=x)))",
- attrs=["dnsHostName", "lastLogon"])
- self.assertEquals(len(res), 5)
- self.assertEquals(str(res[0].dn), self.samba4.dn("cn=Y"))
- self.assertEquals(str(res[0]["dnsHostName"]), "y")
- self.assertEquals(str(res[0]["lastLogon"]), "y")
- self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Z"))
- self.assertEquals(str(res[1]["dnsHostName"]), "z")
- self.assertEquals(str(res[1]["lastLogon"]), "z")
- self.assertEquals(str(res[2].dn), self.samba4.dn("cn=C"))
- self.assertTrue(not "dnsHostName" in res[2])
- self.assertEquals(str(res[2]["lastLogon"]), "z")
-
- # Search by negated disjunction of local and remote attribute
- res = self.ldb.search(expression="(!(|(revision=x)(lastLogon=y)))",
- attrs=["dnsHostName", "lastLogon"])
- self.assertEquals(len(res), 5)
- self.assertEquals(str(res[0].dn), self.samba4.dn("cn=A"))
- self.assertTrue(not "dnsHostName" in res[0])
- self.assertEquals(str(res[0]["lastLogon"]), "x")
- self.assertEquals(str(res[1].dn), self.samba4.dn("cn=Z"))
- self.assertEquals(str(res[1]["dnsHostName"]), "z")
- self.assertEquals(str(res[1]["lastLogon"]), "z")
- self.assertEquals(str(res[2].dn), self.samba4.dn("cn=C"))
- self.assertTrue(not "dnsHostName" in res[2])
- self.assertEquals(str(res[2]["lastLogon"]), "z")
-
- # Search by complex parse tree
- res = self.ldb.search(expression="(|(&(revision=x)(dnsHostName=x))(!(&(description=x)(nextRid=y)))(badPwdCount=y))", attrs=["dnsHostName", "lastLogon"])
- self.assertEquals(len(res), 7)
- self.assertEquals(str(res[0].dn), self.samba4.dn("cn=B"))
- self.assertTrue(not "dnsHostName" in res[0])
- self.assertEquals(str(res[0]["lastLogon"]), "y")
- self.assertEquals(str(res[1].dn), self.samba4.dn("cn=X"))
- self.assertEquals(str(res[1]["dnsHostName"]), "x")
- self.assertEquals(str(res[1]["lastLogon"]), "x")
- self.assertEquals(str(res[2].dn), self.samba4.dn("cn=A"))
- self.assertTrue(not "dnsHostName" in res[2])
- self.assertEquals(str(res[2]["lastLogon"]), "x")
- self.assertEquals(str(res[3].dn), self.samba4.dn("cn=Z"))
- self.assertEquals(str(res[3]["dnsHostName"]), "z")
- self.assertEquals(str(res[3]["lastLogon"]), "z")
- self.assertEquals(str(res[4].dn), self.samba4.dn("cn=C"))
- self.assertTrue(not "dnsHostName" in res[4])
- self.assertEquals(str(res[4]["lastLogon"]), "z")
-
- # Clean up
- dns = [self.samba4.dn("cn=%s" % n) for n in ["A","B","C","X","Y","Z"]]
- for dn in dns:
- self.ldb.delete(dn)
-
- def test_map_modify_local(self):
- """Modification of local records."""
- # Add local record
- dn = "cn=test,dc=idealx,dc=org"
- self.ldb.add({"dn": dn,
- "cn": "test",
- "foo": "bar",
- "revision": "1",
- "description": "test"})
- # Check it's there
- attrs = ["foo", "revision", "description"]
- res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs)
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn)
- self.assertEquals(str(res[0]["foo"]), "bar")
- self.assertEquals(str(res[0]["revision"]), "1")
- self.assertEquals(str(res[0]["description"]), "test")
- # Check it's not in the local db
- res = self.samba4.db.search(expression="(cn=test)",
- scope=SCOPE_DEFAULT, attrs=attrs)
- self.assertEquals(len(res), 0)
- # Check it's not in the remote db
- res = self.samba3.db.search(expression="(cn=test)",
- scope=SCOPE_DEFAULT, attrs=attrs)
- self.assertEquals(len(res), 0)
-
- # Modify local record
- ldif = """
-dn: """ + dn + """
-replace: foo
-foo: baz
-replace: description
-description: foo
-"""
- self.ldb.modify_ldif(ldif)
- # Check in local db
- res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs)
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn)
- self.assertEquals(str(res[0]["foo"]), "baz")
- self.assertEquals(str(res[0]["revision"]), "1")
- self.assertEquals(str(res[0]["description"]), "foo")
-
- # Rename local record
- dn2 = "cn=toast,dc=idealx,dc=org"
- self.ldb.rename(dn, dn2)
- # Check in local db
- res = self.ldb.search(dn2, scope=SCOPE_BASE, attrs=attrs)
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn2)
- self.assertEquals(str(res[0]["foo"]), "baz")
- self.assertEquals(str(res[0]["revision"]), "1")
- self.assertEquals(str(res[0]["description"]), "foo")
-
- # Delete local record
- self.ldb.delete(dn2)
- # Check it's gone
- res = self.ldb.search(dn2, scope=SCOPE_BASE)
- self.assertEquals(len(res), 0)
-
- def test_map_modify_remote_remote(self):
- """Modification of remote data of remote records"""
- # Add remote record
- dn = self.samba4.dn("cn=test")
- dn2 = self.samba3.dn("cn=test")
- self.samba3.db.add({"dn": dn2,
- "cn": "test",
- "description": "foo",
- "sambaBadPasswordCount": "3",
- "sambaNextRid": "1001"})
- # Check it's there
- res = self.samba3.db.search(dn2, scope=SCOPE_BASE,
- attrs=["description", "sambaBadPasswordCount", "sambaNextRid"])
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn2)
- self.assertEquals(str(res[0]["description"]), "foo")
- self.assertEquals(str(res[0]["sambaBadPasswordCount"]), "3")
- self.assertEquals(str(res[0]["sambaNextRid"]), "1001")
- # Check in mapped db
- attrs = ["description", "badPwdCount", "nextRid"]
- res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs, expression="")
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn)
- self.assertEquals(str(res[0]["description"]), "foo")
- self.assertEquals(str(res[0]["badPwdCount"]), "3")
- self.assertEquals(str(res[0]["nextRid"]), "1001")
- # Check in local db
- res = self.samba4.db.search(dn, scope=SCOPE_BASE, attrs=attrs)
- self.assertEquals(len(res), 0)
-
- # Modify remote data of remote record
- ldif = """
-dn: """ + dn + """
-replace: description
-description: test
-replace: badPwdCount
-badPwdCount: 4
-"""
- self.ldb.modify_ldif(ldif)
- # Check in mapped db
- res = self.ldb.search(dn, scope=SCOPE_BASE,
- attrs=["description", "badPwdCount", "nextRid"])
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn)
- self.assertEquals(str(res[0]["description"]), "test")
- self.assertEquals(str(res[0]["badPwdCount"]), "4")
- self.assertEquals(str(res[0]["nextRid"]), "1001")
- # Check in remote db
- res = self.samba3.db.search(dn2, scope=SCOPE_BASE,
- attrs=["description", "sambaBadPasswordCount", "sambaNextRid"])
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn2)
- self.assertEquals(str(res[0]["description"]), "test")
- self.assertEquals(str(res[0]["sambaBadPasswordCount"]), "4")
- self.assertEquals(str(res[0]["sambaNextRid"]), "1001")
-
- # Rename remote record
- dn2 = self.samba4.dn("cn=toast")
- self.ldb.rename(dn, dn2)
- # Check in mapped db
- dn = dn2
- res = self.ldb.search(dn, scope=SCOPE_BASE,
- attrs=["description", "badPwdCount", "nextRid"])
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn)
- self.assertEquals(str(res[0]["description"]), "test")
- self.assertEquals(str(res[0]["badPwdCount"]), "4")
- self.assertEquals(str(res[0]["nextRid"]), "1001")
- # Check in remote db
- dn2 = self.samba3.dn("cn=toast")
- res = self.samba3.db.search(dn2, scope=SCOPE_BASE,
- attrs=["description", "sambaBadPasswordCount", "sambaNextRid"])
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn2)
- self.assertEquals(str(res[0]["description"]), "test")
- self.assertEquals(str(res[0]["sambaBadPasswordCount"]), "4")
- self.assertEquals(str(res[0]["sambaNextRid"]), "1001")
-
- # Delete remote record
- self.ldb.delete(dn)
- # Check in mapped db that it's removed
- res = self.ldb.search(dn, scope=SCOPE_BASE)
- self.assertEquals(len(res), 0)
- # Check in remote db
- res = self.samba3.db.search(dn2, scope=SCOPE_BASE)
- self.assertEquals(len(res), 0)
-
- def test_map_modify_remote_local(self):
- """Modification of local data of remote records"""
- # Add remote record (same as before)
- dn = self.samba4.dn("cn=test")
- dn2 = self.samba3.dn("cn=test")
- self.samba3.db.add({"dn": dn2,
- "cn": "test",
- "description": "foo",
- "sambaBadPasswordCount": "3",
- "sambaNextRid": "1001"})
-
- # Modify local data of remote record
- ldif = """
-dn: """ + dn + """
-add: revision
-revision: 1
-replace: description
-description: test
-
-"""
- self.ldb.modify_ldif(ldif)
- # Check in mapped db
- attrs = ["revision", "description"]
- res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs)
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn)
- self.assertEquals(str(res[0]["description"]), "test")
- self.assertEquals(str(res[0]["revision"]), "1")
- # Check in remote db
- res = self.samba3.db.search(dn2, scope=SCOPE_BASE, attrs=attrs)
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn2)
- self.assertEquals(str(res[0]["description"]), "test")
- self.assertTrue(not "revision" in res[0])
- # Check in local db
- res = self.samba4.db.search(dn, scope=SCOPE_BASE, attrs=attrs)
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn)
- self.assertTrue(not "description" in res[0])
- self.assertEquals(str(res[0]["revision"]), "1")
-
- # Delete (newly) split record
- self.ldb.delete(dn)
-
- def test_map_modify_split(self):
- """Testing modification of split records"""
- # Add split record
- dn = self.samba4.dn("cn=test")
- dn2 = self.samba3.dn("cn=test")
- self.ldb.add({
- "dn": dn,
- "cn": "test",
- "description": "foo",
- "badPwdCount": "3",
- "nextRid": "1001",
- "revision": "1"})
- # Check it's there
- attrs = ["description", "badPwdCount", "nextRid", "revision"]
- res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs)
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn)
- self.assertEquals(str(res[0]["description"]), "foo")
- self.assertEquals(str(res[0]["badPwdCount"]), "3")
- self.assertEquals(str(res[0]["nextRid"]), "1001")
- self.assertEquals(str(res[0]["revision"]), "1")
- # Check in local db
- res = self.samba4.db.search(dn, scope=SCOPE_BASE, attrs=attrs)
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn)
- self.assertTrue(not "description" in res[0])
- self.assertTrue(not "badPwdCount" in res[0])
- self.assertTrue(not "nextRid" in res[0])
- self.assertEquals(str(res[0]["revision"]), "1")
- # Check in remote db
- attrs = ["description", "sambaBadPasswordCount", "sambaNextRid",
- "revision"]
- res = self.samba3.db.search(dn2, scope=SCOPE_BASE, attrs=attrs)
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn2)
- self.assertEquals(str(res[0]["description"]), "foo")
- self.assertEquals(str(res[0]["sambaBadPasswordCount"]), "3")
- self.assertEquals(str(res[0]["sambaNextRid"]), "1001")
- self.assertTrue(not "revision" in res[0])
-
- # Modify of split record
- ldif = """
-dn: """ + dn + """
-replace: description
-description: test
-replace: badPwdCount
-badPwdCount: 4
-replace: revision
-revision: 2
-"""
- self.ldb.modify_ldif(ldif)
- # Check in mapped db
- attrs = ["description", "badPwdCount", "nextRid", "revision"]
- res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs)
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn)
- self.assertEquals(str(res[0]["description"]), "test")
- self.assertEquals(str(res[0]["badPwdCount"]), "4")
- self.assertEquals(str(res[0]["nextRid"]), "1001")
- self.assertEquals(str(res[0]["revision"]), "2")
- # Check in local db
- res = self.samba4.db.search(dn, scope=SCOPE_BASE, attrs=attrs)
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn)
- self.assertTrue(not "description" in res[0])
- self.assertTrue(not "badPwdCount" in res[0])
- self.assertTrue(not "nextRid" in res[0])
- self.assertEquals(str(res[0]["revision"]), "2")
- # Check in remote db
- attrs = ["description", "sambaBadPasswordCount", "sambaNextRid",
- "revision"]
- res = self.samba3.db.search(dn2, scope=SCOPE_BASE, attrs=attrs)
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn2)
- self.assertEquals(str(res[0]["description"]), "test")
- self.assertEquals(str(res[0]["sambaBadPasswordCount"]), "4")
- self.assertEquals(str(res[0]["sambaNextRid"]), "1001")
- self.assertTrue(not "revision" in res[0])
-
- # Rename split record
- dn2 = self.samba4.dn("cn=toast")
- self.ldb.rename(dn, dn2)
- # Check in mapped db
- dn = dn2
- attrs = ["description", "badPwdCount", "nextRid", "revision"]
- res = self.ldb.search(dn, scope=SCOPE_BASE, attrs=attrs)
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn)
- self.assertEquals(str(res[0]["description"]), "test")
- self.assertEquals(str(res[0]["badPwdCount"]), "4")
- self.assertEquals(str(res[0]["nextRid"]), "1001")
- self.assertEquals(str(res[0]["revision"]), "2")
- # Check in local db
- res = self.samba4.db.search(dn, scope=SCOPE_BASE, attrs=attrs)
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn)
- self.assertTrue(not "description" in res[0])
- self.assertTrue(not "badPwdCount" in res[0])
- self.assertTrue(not "nextRid" in res[0])
- self.assertEquals(str(res[0]["revision"]), "2")
- # Check in remote db
- dn2 = self.samba3.dn("cn=toast")
- res = self.samba3.db.search(dn2, scope=SCOPE_BASE,
- attrs=["description", "sambaBadPasswordCount", "sambaNextRid",
- "revision"])
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0].dn), dn2)
- self.assertEquals(str(res[0]["description"]), "test")
- self.assertEquals(str(res[0]["sambaBadPasswordCount"]), "4")
- self.assertEquals(str(res[0]["sambaNextRid"]), "1001")
- self.assertTrue(not "revision" in res[0])
-
- # Delete split record
- self.ldb.delete(dn)
- # Check in mapped db
- res = self.ldb.search(dn, scope=SCOPE_BASE)
- self.assertEquals(len(res), 0)
- # Check in local db
- res = self.samba4.db.search(dn, scope=SCOPE_BASE)
- self.assertEquals(len(res), 0)
- # Check in remote db
- res = self.samba3.db.search(dn2, scope=SCOPE_BASE)
- self.assertEquals(len(res), 0)
diff --git a/source4/scripting/python/samba/tests/samdb.py b/source4/scripting/python/samba/tests/samdb.py
index 3df72b0840..8c7bb0ae98 100644
--- a/source4/scripting/python/samba/tests/samdb.py
+++ b/source4/scripting/python/samba/tests/samdb.py
@@ -1,46 +1,43 @@
-#!/usr/bin/env python
+#!/usr/bin/python
# Unix SMB/CIFS implementation. Tests for SamDB
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008
-#
+#
# 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/>.
#
-
-"""Tests for samba.samdb."""
-
-import logging
-import os
-import uuid
-
from samba.auth import system_session
-from samba.provision import (setup_samdb, guess_names, make_smbconf,
- provision_paths_from_lp)
-from samba.provision import DEFAULT_POLICY_GUID, DEFAULT_DC_POLICY_GUID
-from samba.provision.backend import ProvisionBackend
+from samba.credentials import Credentials
+import os
+from samba.provision import setup_samdb, guess_names, setup_templatesdb, make_smbconf, find_setup_dir
+from samba.samdb import SamDB
from samba.tests import TestCaseInTempDir
from samba.dcerpc import security
-from samba.schema import Schema
+from unittest import TestCase
+import uuid
from samba import param
class SamDBTestCase(TestCaseInTempDir):
"""Base-class for tests with a Sam Database.
-
+
This is used by the Samba SamDB-tests, but e.g. also by the OpenChange
provisioning tests (which need a Sam).
"""
+ def setup_path(self, relpath):
+ return os.path.join(find_setup_dir(), relpath)
+
def setUp(self):
super(SamDBTestCase, self).setUp()
invocationid = str(uuid.uuid4())
@@ -49,8 +46,11 @@ class SamDBTestCase(TestCaseInTempDir):
configdn = "CN=Configuration," + domaindn
schemadn = "CN=Schema," + configdn
domainguid = str(uuid.uuid4())
- policyguid = DEFAULT_POLICY_GUID
+ policyguid = str(uuid.uuid4())
+ creds = Credentials()
+ creds.set_anonymous()
domainsid = security.random_sid()
+ hostguid = str(uuid.uuid4())
path = os.path.join(self.tempdir, "samdb.ldb")
session_info = system_session()
@@ -58,10 +58,9 @@ class SamDBTestCase(TestCaseInTempDir):
domain="EXAMPLE"
dnsdomain="example.com"
serverrole="domain controller"
- policyguid_dc = DEFAULT_DC_POLICY_GUID
smbconf = os.path.join(self.tempdir, "smb.conf")
- make_smbconf(smbconf, hostname, domain, dnsdomain,
+ make_smbconf(smbconf, self.setup_path, hostname, domain, dnsdomain,
serverrole, self.tempdir)
self.lp = param.LoadParm()
@@ -72,27 +71,26 @@ class SamDBTestCase(TestCaseInTempDir):
serverrole=serverrole,
domaindn=self.domaindn, configdn=configdn,
schemadn=schemadn)
-
- paths = provision_paths_from_lp(self.lp, names.dnsdomain)
-
- logger = logging.getLogger("provision")
-
- provision_backend = ProvisionBackend("ldb", paths=paths,
- lp=self.lp, credentials=None,
- names=names, logger=logger)
-
- schema = Schema(domainsid, invocationid=invocationid,
- schemadn=names.schemadn, serverdn=names.serverdn,
- am_rodc=False)
-
- self.samdb = setup_samdb(path, session_info,
- provision_backend, self.lp, names, logger,
- domainsid, domainguid, policyguid, policyguid_dc, False,
- "secret", "secret", "secret", invocationid, "secret",
- None, "domain controller", schema=schema)
+ setup_templatesdb(os.path.join(self.tempdir, "templates.ldb"),
+ self.setup_path, session_info=session_info, lp=self.lp)
+ self.samdb = setup_samdb(path, self.setup_path, session_info, creds,
+ self.lp, names,
+ lambda x: None, domainsid,
+ domainguid,
+ policyguid, False, "secret",
+ "secret", "secret", invocationid,
+ "secret", "domain controller")
def tearDown(self):
- for f in ['schema.ldb', 'configuration.ldb',
+ for f in ['templates.ldb', 'schema.ldb', 'configuration.ldb',
'users.ldb', 'samdb.ldb', 'smb.conf']:
os.remove(os.path.join(self.tempdir, f))
super(SamDBTestCase, self).tearDown()
+
+
+# disable this test till andrew works it out ...
+class SamDBTests(SamDBTestCase):
+ """Tests for the SamDB implementation."""
+
+ print "samdb add_foreign disabled for now"
+# def test_add_foreign(self):
diff --git a/source4/scripting/python/samba/tests/security.py b/source4/scripting/python/samba/tests/security.py
deleted file mode 100644
index 59e3113068..0000000000
--- a/source4/scripting/python/samba/tests/security.py
+++ /dev/null
@@ -1,145 +0,0 @@
-#!/usr/bin/env python
-
-# Unix SMB/CIFS implementation.
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
-#
-# 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/>.
-#
-
-"""Tests for samba.dcerpc.security."""
-
-import samba.tests
-from samba.dcerpc import security
-
-class SecurityTokenTests(samba.tests.TestCase):
-
- def setUp(self):
- super(SecurityTokenTests, self).setUp()
- self.token = security.token()
-
- def test_is_system(self):
- self.assertFalse(self.token.is_system())
-
- def test_is_anonymous(self):
- self.assertFalse(self.token.is_anonymous())
-
- def test_has_builtin_administrators(self):
- self.assertFalse(self.token.has_builtin_administrators())
-
- def test_has_nt_authenticated_users(self):
- self.assertFalse(self.token.has_nt_authenticated_users())
-
- def test_has_priv(self):
- self.assertFalse(self.token.has_privilege(security.SEC_PRIV_SHUTDOWN))
-
- def test_set_priv(self):
- self.assertFalse(self.token.has_privilege(security.SEC_PRIV_SHUTDOWN))
- self.assertFalse(self.token.set_privilege(security.SEC_PRIV_SHUTDOWN))
- self.assertTrue(self.token.has_privilege(security.SEC_PRIV_SHUTDOWN))
-
-
-class SecurityDescriptorTests(samba.tests.TestCase):
-
- def setUp(self):
- super(SecurityDescriptorTests, self).setUp()
- self.descriptor = security.descriptor()
-
- def test_from_sddl(self):
- desc = security.descriptor.from_sddl("O:AOG:DAD:(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)", security.dom_sid("S-2-0-0"))
- self.assertEquals(desc.group_sid, security.dom_sid('S-2-0-0-512'))
- self.assertEquals(desc.owner_sid, security.dom_sid('S-1-5-32-548'))
- self.assertEquals(desc.revision, 1)
- self.assertEquals(desc.sacl, None)
- self.assertEquals(desc.type, 0x8004)
-
- def test_from_sddl_invalidsddl(self):
- self.assertRaises(TypeError,security.descriptor.from_sddl, "foo",security.dom_sid("S-2-0-0"))
-
- def test_from_sddl_invalidtype1(self):
- self.assertRaises(TypeError, security.descriptor.from_sddl, security.dom_sid('S-2-0-0-512'),security.dom_sid("S-2-0-0"))
-
- def test_from_sddl_invalidtype2(self):
- sddl = "O:AOG:DAD:(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)"
- self.assertRaises(TypeError, security.descriptor.from_sddl, sddl,
- "S-2-0-0")
-
- def test_as_sddl(self):
- text = "O:AOG:DAD:(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)"
- dom = security.dom_sid("S-2-0-0")
- desc1 = security.descriptor.from_sddl(text, dom)
- desc2 = security.descriptor.from_sddl(desc1.as_sddl(dom), dom)
- self.assertEquals(desc1.group_sid, desc2.group_sid)
- self.assertEquals(desc1.owner_sid, desc2.owner_sid)
- self.assertEquals(desc1.sacl, desc2.sacl)
- self.assertEquals(desc1.type, desc2.type)
-
- def test_as_sddl_invalid(self):
- text = "O:AOG:DAD:(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)"
- dom = security.dom_sid("S-2-0-0")
- desc1 = security.descriptor.from_sddl(text, dom)
- self.assertRaises(TypeError, desc1.as_sddl,text)
-
-
- def test_as_sddl_no_domainsid(self):
- dom = security.dom_sid("S-2-0-0")
- text = "O:AOG:DAD:(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)"
- desc1 = security.descriptor.from_sddl(text, dom)
- desc2 = security.descriptor.from_sddl(desc1.as_sddl(), dom)
- self.assertEquals(desc1.group_sid, desc2.group_sid)
- self.assertEquals(desc1.owner_sid, desc2.owner_sid)
- self.assertEquals(desc1.sacl, desc2.sacl)
- self.assertEquals(desc1.type, desc2.type)
-
- def test_domsid_nodomsid_as_sddl(self):
- dom = security.dom_sid("S-2-0-0")
- text = "O:AOG:DAD:(A;;RPWPCCDCLCSWRCWDWOGA;;;S-1-0-0)"
- desc1 = security.descriptor.from_sddl(text, dom)
- self.assertNotEqual(desc1.as_sddl(), desc1.as_sddl(dom))
-
- def test_split(self):
- dom = security.dom_sid("S-2-0-7")
- self.assertEquals((security.dom_sid("S-2-0"), 7), dom.split())
-
-
-class DomSidTests(samba.tests.TestCase):
-
- def test_parse_sid(self):
- sid = security.dom_sid("S-1-5-21")
- self.assertEquals("S-1-5-21", str(sid))
-
- def test_sid_equal(self):
- sid1 = security.dom_sid("S-1-5-21")
- sid2 = security.dom_sid("S-1-5-21")
- self.assertEquals(sid1, sid1)
- self.assertEquals(sid1, sid2)
-
- def test_random(self):
- sid = security.random_sid()
- self.assertTrue(str(sid).startswith("S-1-5-21-"))
-
- def test_repr(self):
- sid = security.random_sid()
- self.assertTrue(repr(sid).startswith("dom_sid('S-1-5-21-"))
-
-
-class PrivilegeTests(samba.tests.TestCase):
-
- def test_privilege_name(self):
- self.assertEquals("SeShutdownPrivilege",
- security.privilege_name(security.SEC_PRIV_SHUTDOWN))
-
- def test_privilege_id(self):
- self.assertEquals(security.SEC_PRIV_SHUTDOWN,
- security.privilege_id("SeShutdownPrivilege"))
-
diff --git a/source4/scripting/python/samba/tests/hostconfig.py b/source4/scripting/python/samba/tests/shares.py
index 78ca6202b2..9130c36780 100644
--- a/source4/scripting/python/samba/tests/hostconfig.py
+++ b/source4/scripting/python/samba/tests/shares.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
# Unix SMB/CIFS implementation. Tests for shares
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2009
@@ -16,11 +16,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-
-"""Tests for samba.hostconfig."""
-
-from samba.hostconfig import SharesContainer
-from samba.tests import TestCase
+from samba.shares import SharesContainer
+from unittest import TestCase
class MockService(object):
@@ -40,6 +37,9 @@ class MockLoadParm(object):
def __getitem__(self, name):
return MockService(self.data[name])
+ def __contains__(self, name):
+ return name in self.data
+
def __len__(self):
return len(self.data)
diff --git a/source4/scripting/python/samba/tests/upgrade.py b/source4/scripting/python/samba/tests/upgrade.py
index 16ccbd567e..17ebfa7bf5 100644
--- a/source4/scripting/python/samba/tests/upgrade.py
+++ b/source4/scripting/python/samba/tests/upgrade.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/usr/bin/python
# Unix SMB/CIFS implementation.
# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
@@ -17,13 +17,11 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
-"""Tests for samba.upgrade."""
-
+from samba import Ldb
from samba.upgrade import import_wins
from samba.tests import LdbTestCase
class WinsUpgradeTests(LdbTestCase):
-
def test_upgrade(self):
winsdb = {
"FOO#20": (200, ["127.0.0.1", "127.0.0.2"], 0x60)
diff --git a/source4/scripting/python/samba/tests/upgradeprovision.py b/source4/scripting/python/samba/tests/upgradeprovision.py
deleted file mode 100644
index b81ee8a8ab..0000000000
--- a/source4/scripting/python/samba/tests/upgradeprovision.py
+++ /dev/null
@@ -1,139 +0,0 @@
-#!/usr/bin/env python
-
-# Unix SMB/CIFS implementation.
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
-#
-# 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/>.
-#
-
-"""Tests for samba.upgradeprovision."""
-
-import os
-from samba.upgradehelpers import (usn_in_range, dn_sort,
- get_diff_sddls, update_secrets,
- construct_existor_expr)
-
-from samba.tests.provision import create_dummy_secretsdb
-from samba.tests import TestCaseInTempDir
-from samba import Ldb
-from ldb import SCOPE_SUBTREE
-import samba.tests
-
-def dummymessage(a=None, b=None):
- pass
-
-
-class UpgradeProvisionTestCase(TestCaseInTempDir):
- """Some simple tests for individual functions in the provisioning code.
- """
- def test_usn_in_range(self):
- range = [5, 25, 35, 55]
-
- vals = [3, 26, 56]
-
- for v in vals:
- self.assertFalse(usn_in_range(v, range))
-
- vals = [5, 20, 25, 35, 36]
-
- for v in vals:
- self.assertTrue(usn_in_range(v, range))
-
- def test_dn_sort(self):
- # higher level comes after lower even if lexicographicaly closer
- # ie dc=tata,dc=toto (2 levels), comes after dc=toto
- # even if dc=toto is lexicographicaly after dc=tata, dc=toto
- self.assertEquals(dn_sort("dc=tata,dc=toto", "dc=toto"), 1)
- self.assertEquals(dn_sort("dc=zata", "dc=tata"), 1)
- self.assertEquals(dn_sort("dc=toto,dc=tata",
- "cn=foo,dc=toto,dc=tata"), -1)
- self.assertEquals(dn_sort("cn=bar, dc=toto,dc=tata",
- "cn=foo, dc=toto,dc=tata"), -1)
-
- def test_get_diff_sddl(self):
- sddl = "O:SAG:DUD:AI(A;CIID;RPWPCRCCLCLORCWOWDSW;;;SA)\
-(A;CIID;RP LCLORC;;;AU)(A;CIID;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)S:AI(AU;CIIDSA;WP;;;WD)"
- sddl1 = "O:SAG:DUD:AI(A;CIID;RPWPCRCCLCLORCWOWDSW;;;SA)\
-(A;CIID;RP LCLORC;;;AU)(A;CIID;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)S:AI(AU;CIIDSA;WP;;;WD)"
- sddl2 = "O:BAG:DUD:AI(A;CIID;RPWPCRCCLCLORCWOWDSW;;;SA)\
-(A;CIID;RP LCLORC;;;AU)(A;CIID;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)S:AI(AU;CIIDSA;WP;;;WD)"
- sddl3 = "O:SAG:BAD:AI(A;CIID;RPWPCRCCLCLORCWOWDSW;;;SA)\
-(A;CIID;RP LCLORC;;;AU)(A;CIID;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)S:AI(AU;CIIDSA;WP;;;WD)"
- sddl4 = "O:SAG:DUD:AI(A;CIID;RPWPCRCCLCLORCWOWDSW;;;BA)\
-(A;CIID;RP LCLORC;;;AU)(A;CIID;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)S:AI(AU;CIIDSA;WP;;;WD)"
- sddl5 = "O:SAG:DUD:AI(A;CIID;RPWPCRCCLCLORCWOWDSW;;;SA)\
-(A;CIID;RP LCLORC;;;AU)(A;CIID;RPWPCRCCDCLCLORCWOWDSDDTSW;;;SY)"
-
- self.assertEquals(get_diff_sddls(sddl, sddl1), "")
- txt = get_diff_sddls(sddl, sddl2)
- self.assertEquals(txt, "\tOwner mismatch: SA (in ref) BA(in current)\n")
- txt = get_diff_sddls(sddl, sddl3)
- self.assertEquals(txt, "\tGroup mismatch: DU (in ref) BA(in current)\n")
- txt = get_diff_sddls(sddl, sddl4)
- txtmsg = "\tPart dacl is different between reference and current here\
- is the detail:\n\t\t(A;CIID;RPWPCRCCLCLORCWOWDSW;;;BA) ACE is not present in\
- the reference\n\t\t(A;CIID;RPWPCRCCLCLORCWOWDSW;;;SA) ACE is not present in\
- the current\n"
- self.assertEquals(txt, txtmsg)
- txt = get_diff_sddls(sddl, sddl5)
- self.assertEquals(txt, "\tCurrent ACL hasn't a sacl part\n")
-
- def test_construct_existor_expr(self):
- res = construct_existor_expr([])
- self.assertEquals(res, "")
-
- res = construct_existor_expr(["foo"])
- self.assertEquals(res, "(|(foo=*))")
-
- res = construct_existor_expr(["foo", "bar"])
- self.assertEquals(res, "(|(foo=*)(bar=*))")
-
-
-class UpdateSecretsTests(samba.tests.TestCaseInTempDir):
-
- def setUp(self):
- super(UpdateSecretsTests, self).setUp()
- self.referencedb = create_dummy_secretsdb(
- os.path.join(self.tempdir, "ref.ldb"))
-
- def _getEmptyDb(self):
- return Ldb(os.path.join(self.tempdir, "secrets.ldb"))
-
- def _getCurrentFormatDb(self):
- return create_dummy_secretsdb(
- os.path.join(self.tempdir, "secrets.ldb"))
-
- def test_trivial(self):
- # Test that updating an already up-to-date secretsdb works fine
- self.secretsdb = self._getCurrentFormatDb()
- self.assertEquals(None,
- update_secrets(self.referencedb, self.secretsdb, dummymessage))
-
- def test_update_modules(self):
- empty_db = self._getEmptyDb()
- update_secrets(self.referencedb, empty_db, dummymessage)
- newmodules = empty_db.search(
- expression="dn=@MODULES", base="", scope=SCOPE_SUBTREE)
- refmodules = self.referencedb.search(
- expression="dn=@MODULES", base="", scope=SCOPE_SUBTREE)
- self.assertEquals(newmodules.msgs, refmodules.msgs)
-
- def tearDown(self):
- for name in ["ref.ldb", "secrets.ldb"]:
- path = os.path.join(self.tempdir, name)
- if os.path.exists(path):
- os.unlink(path)
- super(UpdateSecretsTests, self).tearDown()
-
-
diff --git a/source4/scripting/python/samba/tests/upgradeprovisionneeddc.py b/source4/scripting/python/samba/tests/upgradeprovisionneeddc.py
deleted file mode 100644
index 3a9c78e0dc..0000000000
--- a/source4/scripting/python/samba/tests/upgradeprovisionneeddc.py
+++ /dev/null
@@ -1,180 +0,0 @@
-#!/usr/bin/env python
-
-# Unix SMB/CIFS implementation.
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
-#
-# 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/>.
-#
-
-"""Tests for samba.upgradeprovision that need a DC."""
-
-import os
-import re
-import shutil
-
-from samba import param
-from samba.credentials import Credentials
-from samba.auth import system_session
-from samba.provision import getpolicypath
-from samba.upgradehelpers import (get_paths, get_ldbs,
- find_provision_key_parameters, identic_rename,
- updateOEMInfo, getOEMInfo, update_gpo,
- delta_update_basesamdb,
- update_dns_account_password,
- search_constructed_attrs_stored,
- increment_calculated_keyversion_number)
-from samba.tests import env_loadparm, TestCaseInTempDir
-from samba.tests.provision import create_dummy_secretsdb
-import ldb
-
-
-def dummymessage(a=None, b=None):
- pass
-
-smb_conf_path = "%s/%s/%s" % (os.environ["SELFTEST_PREFIX"], "dc", "etc/smb.conf")
-
-class UpgradeProvisionBasicLdbHelpersTestCase(TestCaseInTempDir):
- """Some simple tests for individual functions in the provisioning code.
- """
-
- def test_get_ldbs(self):
- paths = get_paths(param, None, smb_conf_path)
- creds = Credentials()
- lp = env_loadparm()
- creds.guess(lp)
- get_ldbs(paths, creds, system_session(), lp)
-
- def test_find_key_param(self):
- paths = get_paths(param, None, smb_conf_path)
- creds = Credentials()
- lp = env_loadparm()
- creds.guess(lp)
- rootdn = "dc=samba,dc=example,dc=com"
- ldbs = get_ldbs(paths, creds, system_session(), lp)
- names = find_provision_key_parameters(ldbs.sam, ldbs.secrets, ldbs.idmap,
- paths, smb_conf_path, lp)
- self.assertEquals(names.realm, "SAMBA.EXAMPLE.COM")
- self.assertEquals(str(names.rootdn).lower(), rootdn.lower())
- self.assertNotEquals(names.policyid_dc, None)
- self.assertNotEquals(names.ntdsguid, "")
-
-
-class UpgradeProvisionWithLdbTestCase(TestCaseInTempDir):
-
- def _getEmptyDbName(self):
- return os.path.join(self.tempdir, "sam.ldb")
-
- def setUp(self):
- super(UpgradeProvisionWithLdbTestCase, self).setUp()
- paths = get_paths(param, None, smb_conf_path)
- self.creds = Credentials()
- self.lp = env_loadparm()
- self.creds.guess(self.lp)
- self.paths = paths
- self.ldbs = get_ldbs(paths, self.creds, system_session(), self.lp)
- self.names = find_provision_key_parameters(self.ldbs.sam,
- self.ldbs.secrets, self.ldbs.idmap, paths, smb_conf_path,
- self.lp)
- self.referencedb = create_dummy_secretsdb(
- os.path.join(self.tempdir, "ref.ldb"))
-
- def test_search_constructed_attrs_stored(self):
- hashAtt = search_constructed_attrs_stored(self.ldbs.sam,
- self.names.rootdn,
- ["msds-KeyVersionNumber"])
- self.assertFalse(hashAtt.has_key("msds-KeyVersionNumber"))
-
- def test_increment_calculated_keyversion_number(self):
- dn = "CN=Administrator,CN=Users,%s" % self.names.rootdn
- # We conctruct a simple hash for the user administrator
- hash = {}
- # And we want the version to be 140
- hash[dn.lower()] = 140
-
- increment_calculated_keyversion_number(self.ldbs.sam,
- self.names.rootdn,
- hash)
- self.assertEqual(self.ldbs.sam.get_attribute_replmetadata_version(dn,
- "unicodePwd"),
- 140)
- # This function should not decrement the version
- hash[dn.lower()] = 130
-
- increment_calculated_keyversion_number(self.ldbs.sam,
- self.names.rootdn,
- hash)
- self.assertEqual(self.ldbs.sam.get_attribute_replmetadata_version(dn,
- "unicodePwd"),
- 140)
-
- def test_identic_rename(self):
- rootdn = "DC=samba,DC=example,DC=com"
-
- guestDN = ldb.Dn(self.ldbs.sam, "CN=Guest,CN=Users,%s" % rootdn)
- identic_rename(self.ldbs.sam, guestDN)
- res = self.ldbs.sam.search(expression="(name=Guest)", base=rootdn,
- scope=ldb.SCOPE_SUBTREE, attrs=["dn"])
- self.assertEquals(len(res), 1)
- self.assertEquals(str(res[0]["dn"]), "CN=Guest,CN=Users,%s" % rootdn)
-
- def test_delta_update_basesamdb(self):
- dummysampath = self._getEmptyDbName()
- delta_update_basesamdb(self.paths.samdb, dummysampath,
- self.creds, system_session(), self.lp,
- dummymessage)
-
- def test_update_gpo_simple(self):
- dir = getpolicypath(self.paths.sysvol, self.names.dnsdomain,
- self.names.policyid)
- shutil.rmtree(dir)
- self.assertFalse(os.path.isdir(dir))
- update_gpo(self.paths, self.ldbs.sam, self.names, self.lp, dummymessage)
- self.assertTrue(os.path.isdir(dir))
-
- def test_update_gpo_acl(self):
- path = os.path.join(self.tempdir, "testupdategpo")
- save = self.paths.sysvol
- self.paths.sysvol = path
- os.mkdir(path)
- os.mkdir(os.path.join(path, self.names.dnsdomain))
- os.mkdir(os.path.join(os.path.join(path, self.names.dnsdomain),
- "Policies"))
- update_gpo(self.paths, self.ldbs.sam, self.names, self.lp, dummymessage)
- shutil.rmtree(path)
- self.paths.sysvol = save
-
- def test_getOEMInfo(self):
- realm = self.lp.get("realm")
- basedn = "DC=%s" % realm.replace(".", ", DC=")
- oem = getOEMInfo(self.ldbs.sam, basedn)
- self.assertNotEquals(oem, "")
-
- def test_update_dns_account(self):
- update_dns_account_password(self.ldbs.sam, self.ldbs.secrets, self.names)
-
- def test_updateOEMInfo(self):
- realm = self.lp.get("realm")
- basedn = "DC=%s" % realm.replace(".", ", DC=")
- oem = getOEMInfo(self.ldbs.sam, basedn)
- updateOEMInfo(self.ldbs.sam, basedn)
- oem2 = getOEMInfo(self.ldbs.sam, basedn)
- self.assertNotEquals(str(oem), str(oem2))
- self.assertTrue(re.match(".*upgrade to.*", str(oem2)))
-
- def tearDown(self):
- for name in ["ref.ldb", "secrets.ldb", "sam.ldb"]:
- path = os.path.join(self.tempdir, name)
- if os.path.exists(path):
- os.unlink(path)
- super(UpgradeProvisionWithLdbTestCase, self).tearDown()
diff --git a/source4/scripting/python/samba/tests/xattr.py b/source4/scripting/python/samba/tests/xattr.py
deleted file mode 100644
index f978ee5b2a..0000000000
--- a/source4/scripting/python/samba/tests/xattr.py
+++ /dev/null
@@ -1,105 +0,0 @@
-#!/usr/bin/env python
-
-# Unix SMB/CIFS implementation. Tests for xattr manipulation
-# Copyright (C) Matthieu Patou <mat@matws.net> 2009
-#
-# 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/>.
-#
-
-"""Tests for samba.xattr_native and samba.xattr_tdb."""
-
-import samba.xattr_native, samba.xattr_tdb
-from samba.dcerpc import xattr
-from samba.ndr import ndr_pack
-from samba.tests import TestCase, TestSkipped
-import random
-import os
-
-class XattrTests(TestCase):
-
- def _tmpfilename(self):
- random.seed()
- path = os.environ['SELFTEST_PREFIX']
- return os.path.join(path, "pytests"+str(int(100000*random.random())))
-
- def _eadbpath(self):
- return os.path.join(os.environ['SELFTEST_PREFIX'], "eadb.tdb")
-
- def test_set_xattr_native(self):
- if not samba.xattr_native.is_xattr_supported():
- raise TestSkipped()
- ntacl = xattr.NTACL()
- ntacl.version = 1
- tempf = self._tmpfilename()
- open(tempf, 'w').write("empty")
- try:
- samba.xattr_native.wrap_setxattr(tempf, "user.unittests",
- ndr_pack(ntacl))
- except IOError:
- raise TestSkipped("the filesystem where the tests are runned do not support XATTR")
- os.unlink(tempf)
-
- def test_set_and_get_native(self):
- if not samba.xattr_native.is_xattr_supported():
- raise TestSkipped()
- tempf = self._tmpfilename()
- reftxt = "this is a test"
- open(tempf, 'w').write("empty")
- try:
- samba.xattr_native.wrap_setxattr(tempf, "user.unittests", reftxt)
- text = samba.xattr_native.wrap_getxattr(tempf, "user.unittests")
- self.assertEquals(text, reftxt)
- except IOError:
- raise TestSkipped("the filesystem where the tests are runned do not support XATTR")
- os.unlink(tempf)
-
- def test_set_xattr_tdb(self):
- tempf = self._tmpfilename()
- eadb_path = self._eadbpath()
- ntacl = xattr.NTACL()
- ntacl.version = 1
- open(tempf, 'w').write("empty")
- try:
- samba.xattr_tdb.wrap_setxattr(eadb_path,
- tempf, "user.unittests", ndr_pack(ntacl))
- finally:
- os.unlink(tempf)
- os.unlink(eadb_path)
-
- def test_set_tdb_not_open(self):
- tempf = self._tmpfilename()
- ntacl = xattr.NTACL()
- ntacl.version = 1
- open(tempf, 'w').write("empty")
- try:
- self.assertRaises(IOError, samba.xattr_tdb.wrap_setxattr,
- os.path.join("nonexistent", "eadb.tdb"), tempf,
- "user.unittests", ndr_pack(ntacl))
- finally:
- os.unlink(tempf)
-
- def test_set_and_get_tdb(self):
- tempf = self._tmpfilename()
- eadb_path = self._eadbpath()
- reftxt = "this is a test"
- open(tempf, 'w').write("empty")
- try:
- samba.xattr_tdb.wrap_setxattr(eadb_path, tempf, "user.unittests",
- reftxt)
- text = samba.xattr_tdb.wrap_getxattr(eadb_path, tempf,
- "user.unittests")
- self.assertEquals(text, reftxt)
- finally:
- os.unlink(tempf)
- os.unlink(eadb_path)
diff --git a/source4/scripting/python/samba/torture/pytorture b/source4/scripting/python/samba/torture/pytorture
new file mode 100755
index 0000000000..e0123447e8
--- /dev/null
+++ b/source4/scripting/python/samba/torture/pytorture
@@ -0,0 +1,51 @@
+#!/usr/bin/python
+
+import sys
+from optparse import OptionParser
+
+# Parse command line
+
+parser = OptionParser()
+
+parser.add_option("-b", "--binding", action="store", type="string",
+ dest="binding")
+
+parser.add_option("-d", "--domain", action="store", type="string",
+ dest="domain")
+
+parser.add_option("-u", "--username", action="store", type="string",
+ dest="username")
+
+parser.add_option("-p", "--password", action="store", type="string",
+ dest="password")
+
+(options, args) = parser.parse_args()
+
+if not options.binding:
+ parser.error('You must supply a binding string')
+
+if not options.username or not options.password or not options.domain:
+ parser.error('You must supply a domain, username and password')
+
+binding = options.binding
+domain = options.domain
+username = options.username
+password = options.password
+
+if len(args) == 0:
+ parser.error('You must supply the name of a module to test')
+
+# Import and test
+
+for test in args:
+
+ try:
+ module = __import__('torture_%s' % test)
+ except ImportError:
+ print 'No such module "%s"' % test
+ sys.exit(1)
+
+ if not hasattr(module, 'runtests'):
+ print 'Module "%s" does not have a runtests function' % test
+
+ module.runtests(binding, (domain, username, password))
diff --git a/source4/scripting/python/samba/torture/spoolss.py b/source4/scripting/python/samba/torture/spoolss.py
new file mode 100644
index 0000000000..a75385e079
--- /dev/null
+++ b/source4/scripting/python/samba/torture/spoolss.py
@@ -0,0 +1,437 @@
+import sys, string
+import dcerpc
+
+
+def ResizeBufferCall(fn, pipe, r):
+
+ r['buffer'] = None
+ r['buf_size'] = 0
+
+ result = fn(pipe, r)
+
+ if result['result'] == dcerpc.WERR_INSUFFICIENT_BUFFER or \
+ result['result'] == dcerpc.WERR_MORE_DATA:
+ r['buffer'] = result['buf_size'] * '\x00'
+ r['buf_size'] = result['buf_size']
+
+ result = fn(pipe, r)
+
+ return result
+
+
+def test_OpenPrinterEx(pipe, printer):
+
+ print 'spoolss_OpenPrinterEx(%s)' % printer
+
+ printername = '\\\\%s' % dcerpc.dcerpc_server_name(pipe)
+
+ if printer is not None:
+ printername = printername + '\\%s' % printer
+
+ r = {}
+ r['printername'] = printername
+ r['datatype'] = None
+ r['devmode_ctr'] = {}
+ r['devmode_ctr']['size'] = 0
+ r['devmode_ctr']['devmode'] = None
+ r['access_mask'] = 0x02000000
+ r['level'] = 1
+ r['userlevel'] = {}
+ r['userlevel']['level1'] = {}
+ r['userlevel']['level1']['size'] = 0
+ r['userlevel']['level1']['client'] = None
+ r['userlevel']['level1']['user'] = None
+ r['userlevel']['level1']['build'] = 1381
+ r['userlevel']['level1']['major'] = 2
+ r['userlevel']['level1']['minor'] = 0
+ r['userlevel']['level1']['processor'] = 0
+
+ result = dcerpc.spoolss_OpenPrinterEx(pipe, r)
+
+ return result['handle']
+
+
+def test_ClosePrinter(pipe, handle):
+
+ r = {}
+ r['handle'] = handle
+
+ dcerpc.spoolss_ClosePrinter(pipe, r)
+
+
+def test_GetPrinter(pipe, handle):
+
+ r = {}
+ r['handle'] = handle
+
+ for level in [0, 1, 2, 3, 4, 5, 6, 7]:
+
+ print 'spoolss_GetPrinter(level = %d)' % level
+
+ r['level'] = level
+ r['buffer'] = None
+ r['buf_size'] = 0
+
+ result = ResizeBufferCall(dcerpc.spoolss_GetPrinter, pipe, r)
+
+
+def test_EnumForms(pipe, handle):
+
+ print 'spoolss_EnumForms()'
+
+ r = {}
+ r['handle'] = handle
+ r['level'] = 1
+ r['buffer'] = None
+ r['buf_size'] = 0
+
+ result = ResizeBufferCall(dcerpc.spoolss_EnumForms, pipe, r)
+
+ forms = dcerpc.unmarshall_spoolss_FormInfo_array(
+ result['buffer'], r['level'], result['count'])
+
+ for form in forms:
+
+ r = {}
+ r['handle'] = handle
+ r['formname'] = form['info1']['formname']
+ r['level'] = 1
+
+ result = ResizeBufferCall(dcerpc.spoolss_GetForm, pipe, r)
+
+
+def test_EnumPorts(pipe, handle):
+
+ print 'spoolss_EnumPorts()'
+
+ for level in [1, 2]:
+
+ r = {}
+ r['handle'] = handle
+ r['servername'] = None
+ r['level'] = level
+
+ result = ResizeBufferCall(dcerpc.spoolss_EnumPorts, pipe, r)
+
+ ports = dcerpc.unmarshall_spoolss_PortInfo_array(
+ result['buffer'], r['level'], result['count'])
+
+ if level == 1:
+ port_names = map(lambda x: x['info1']['port_name'], ports)
+
+
+def test_DeleteForm(pipe, handle, formname):
+
+ r = {}
+ r['handle'] = handle
+ r['formname'] = formname
+
+ dcerpc.spoolss_DeleteForm(pipe, r)
+
+
+def test_GetForm(pipe, handle, formname):
+
+ r = {}
+ r['handle'] = handle
+ r['formname'] = formname
+ r['level'] = 1
+
+ result = ResizeBufferCall(dcerpc.spoolss_GetForm, pipe, r)
+
+ return result['info']['info1']
+
+
+def test_SetForm(pipe, handle, form):
+
+ print 'spoolss_SetForm()'
+
+ r = {}
+ r['handle'] = handle
+ r['level'] = 1
+ r['formname'] = form['info1']['formname']
+ r['info'] = form
+
+ dcerpc.spoolss_SetForm(pipe, r)
+
+ newform = test_GetForm(pipe, handle, r['formname'])
+
+ if form['info1'] != newform:
+ print 'SetForm: mismatch: %s != %s' % \
+ (r['info']['info1'], f)
+ sys.exit(1)
+
+
+def test_AddForm(pipe, handle):
+
+ print 'spoolss_AddForm()'
+
+ formname = '__testform__'
+
+ r = {}
+ r['handle'] = handle
+ r['level'] = 1
+ r['info'] = {}
+ r['info']['info1'] = {}
+ r['info']['info1']['formname'] = formname
+ r['info']['info1']['flags'] = 0x0002
+ r['info']['info1']['width'] = 100
+ r['info']['info1']['length'] = 100
+ r['info']['info1']['left'] = 0
+ r['info']['info1']['top'] = 1000
+ r['info']['info1']['right'] = 2000
+ r['info']['info1']['bottom'] = 3000
+
+ try:
+ result = dcerpc.spoolss_AddForm(pipe, r)
+ except dcerpc.WERROR, arg:
+ if arg[0] == dcerpc.WERR_ALREADY_EXISTS:
+ test_DeleteForm(pipe, handle, formname)
+ result = dcerpc.spoolss_AddForm(pipe, r)
+
+ f = test_GetForm(pipe, handle, formname)
+
+ if r['info']['info1'] != f:
+ print 'AddForm: mismatch: %s != %s' % \
+ (r['info']['info1'], f)
+ sys.exit(1)
+
+ r['formname'] = formname
+
+ test_SetForm(pipe, handle, r['info'])
+
+ test_DeleteForm(pipe, handle, formname)
+
+
+def test_EnumJobs(pipe, handle):
+
+ print 'spoolss_EnumJobs()'
+
+ r = {}
+ r['handle'] = handle
+ r['firstjob'] = 0
+ r['numjobs'] = 0xffffffff
+ r['level'] = 1
+
+ result = ResizeBufferCall(dcerpc.spoolss_EnumJobs, pipe, r)
+
+ if result['buffer'] is None:
+ return
+
+ jobs = dcerpc.unmarshall_spoolss_JobInfo_array(
+ result['buffer'], r['level'], result['count'])
+
+ for job in jobs:
+
+ s = {}
+ s['handle'] = handle
+ s['job_id'] = job['info1']['job_id']
+ s['level'] = 1
+
+ result = ResizeBufferCall(dcerpc.spoolss_GetJob, pipe, s)
+
+ if result['info'] != job:
+ print 'EnumJobs: mismatch: %s != %s' % (result['info'], job)
+ sys.exit(1)
+
+
+ # TODO: AddJob, DeleteJob, ScheduleJob
+
+
+def test_EnumPrinterData(pipe, handle):
+
+ print 'test_EnumPrinterData()'
+
+ enum_index = 0
+
+ while 1:
+
+ r = {}
+ r['handle'] = handle
+ r['enum_index'] = enum_index
+
+ r['value_offered'] = 0
+ r['data_size'] = 0
+
+ result = dcerpc.spoolss_EnumPrinterData(pipe, r)
+
+ r['value_offered'] = result['value_needed']
+ r['data_size'] = result['data_size']
+
+ result = dcerpc.spoolss_EnumPrinterData(pipe, r)
+
+ if result['result'] == dcerpc.WERR_NO_MORE_ITEMS:
+ break
+
+ s = {}
+ s['handle'] = handle
+ s['value_name'] = result['value_name']
+
+ result2 = ResizeBufferCall(dcerpc.spoolss_GetPrinterData, pipe, s)
+
+ if result['buffer'][:result2['buf_size']] != result2['buffer']:
+ print 'EnumPrinterData/GetPrinterData mismatch'
+ sys.exit(1)
+
+ enum_index += 1
+
+
+def test_SetPrinterDataEx(pipe, handle):
+
+ valuename = '__printerdataextest__'
+ data = '12345'
+
+ r = {}
+ r['handle'] = handle
+ r['key_name'] = 'DsSpooler'
+ r['value_name'] = valuename
+ r['type'] = 3
+ r['buffer'] = data
+ r['buf_size'] = len(data)
+
+ result = dcerpc.spoolss_SetPrinterDataEx(pipe, r)
+
+
+def test_EnumPrinterDataEx(pipe, handle):
+
+ r = {}
+ r['handle'] = handle
+ r['key_name'] = 'DsSpooler'
+ r['buf_size'] = 0
+
+ result = dcerpc.spoolss_EnumPrinterDataEx(pipe, r)
+
+ if result['result'] == dcerpc.WERR_MORE_DATA:
+ r['buf_size'] = result['buf_size']
+
+ result = dcerpc.spoolss_EnumPrinterDataEx(pipe, r)
+
+ # TODO: test spoolss_GetPrinterDataEx()
+
+
+def test_SetPrinterData(pipe, handle):
+
+ print 'testing spoolss_SetPrinterData()'
+
+ valuename = '__printerdatatest__'
+ data = '12345'
+
+ r = {}
+ r['handle'] = handle
+ r['value_name'] = valuename
+ r['type'] = 3 # REG_BINARY
+ r['buffer'] = data
+ r['real_len'] = 5
+
+ dcerpc.spoolss_SetPrinterData(pipe, r)
+
+ s = {}
+ s['handle'] = handle
+ s['value_name'] = valuename
+
+ result = ResizeBufferCall(dcerpc.spoolss_GetPrinterData, pipe, r)
+
+ if result['buffer'] != data:
+ print 'SetPrinterData: mismatch'
+ sys.exit(1)
+
+ dcerpc.spoolss_DeletePrinterData(pipe, r)
+
+
+def test_EnumPrinters(pipe):
+
+ print 'testing spoolss_EnumPrinters()'
+
+ printer_names = None
+
+ r = {}
+ r['flags'] = 0x02
+ r['server'] = None
+
+ for level in [0, 1, 2, 4, 5]:
+
+ print 'test_EnumPrinters(level = %d)' % level
+
+ r['level'] = level
+
+ result = ResizeBufferCall(dcerpc.spoolss_EnumPrinters, pipe, r)
+
+ printers = dcerpc.unmarshall_spoolss_PrinterInfo_array(
+ result['buffer'], r['level'], result['count'])
+
+ if level == 2:
+ for p in printers:
+
+ # A nice check is for the specversion in the
+ # devicemode. This has always been observed to be
+ # 1025.
+
+ if p['info2']['devmode']['specversion'] != 1025:
+ print 'test_EnumPrinters: specversion != 1025'
+ sys.exit(1)
+
+ r['level'] = 1
+ result = ResizeBufferCall(dcerpc.spoolss_EnumPrinters, pipe, r)
+
+ for printer in dcerpc.unmarshall_spoolss_PrinterInfo_array(
+ result['buffer'], r['level'], result['count']):
+
+ if string.find(printer['info1']['name'], '\\\\') == 0:
+ print 'Skipping remote printer %s' % printer['info1']['name']
+ continue
+
+ printername = string.split(printer['info1']['name'], ',')[0]
+
+ handle = test_OpenPrinterEx(pipe, printername)
+
+ test_GetPrinter(pipe, handle)
+ test_EnumPorts(pipe, handle)
+ test_EnumForms(pipe, handle)
+ test_AddForm(pipe, handle)
+ test_EnumJobs(pipe, handle)
+ test_EnumPrinterData(pipe, handle)
+ test_EnumPrinterDataEx(pipe, handle)
+ test_SetPrinterData(pipe, handle)
+# test_SetPrinterDataEx(pipe, handle)
+ test_ClosePrinter(pipe, handle)
+
+
+def test_EnumPrinterDrivers(pipe):
+
+ print 'test spoolss_EnumPrinterDrivers()'
+
+ for level in [1, 2, 3]:
+
+ r = {}
+ r['server'] = None
+ r['environment'] = None
+ r['level'] = level
+
+ result = ResizeBufferCall(dcerpc.spoolss_EnumPrinterDrivers, pipe, r)
+
+ drivers = dcerpc.unmarshall_spoolss_DriverInfo_array(
+ result['buffer'], r['level'], result['count'])
+
+ if level == 1:
+ driver_names = map(lambda x: x['info1']['driver_name'], drivers)
+
+
+def test_PrintServer(pipe):
+
+ handle = test_OpenPrinterEx(pipe, None)
+
+ # EnumForms and AddForm tests return WERR_BADFID here (??)
+
+ test_ClosePrinter(pipe, handle)
+
+
+def runtests(binding, domain, username, password):
+
+ print 'Testing SPOOLSS pipe'
+
+ pipe = dcerpc.pipe_connect(binding,
+ dcerpc.DCERPC_SPOOLSS_UUID, dcerpc.DCERPC_SPOOLSS_VERSION,
+ domain, username, password)
+
+ test_EnumPrinters(pipe)
+ test_EnumPrinterDrivers(pipe)
+ test_PrintServer(pipe)
diff --git a/source4/scripting/python/samba/torture/torture_samr.py b/source4/scripting/python/samba/torture/torture_samr.py
new file mode 100755
index 0000000000..15c6dc1a76
--- /dev/null
+++ b/source4/scripting/python/samba/torture/torture_samr.py
@@ -0,0 +1,221 @@
+#!/usr/bin/python
+
+import sys
+import dcerpc, samr
+
+def test_Connect(pipe):
+
+ handle = samr.Connect(pipe)
+ handle = samr.Connect2(pipe)
+ handle = samr.Connect3(pipe)
+ handle = samr.Connect4(pipe)
+
+ # WIN2K3 only?
+
+ try:
+ handle = samr.Connect5(pipe)
+ except dcerpc.NTSTATUS, arg:
+ if arg[0] != 0xc00000d2L: # NT_STATUS_NET_WRITE_FAULT
+ raise
+
+ return handle
+
+def test_UserHandle(user_handle):
+
+ # QuerySecurity()/SetSecurity()
+
+ user_handle.SetSecurity(user_handle.QuerySecurity())
+
+ # GetUserPwInfo()
+
+ user_handle.GetUserPwInfo()
+
+ # GetUserInfo()
+
+ for level in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 20,
+ 21, 23, 24, 25, 26]:
+
+ try:
+ user_handle.QueryUserInfo(level)
+ user_handle.QueryUserInfo2(level)
+ except dcerpc.NTSTATUS, arg:
+ if arg[0] != 0xc0000003L: # NT_STATUS_INVALID_INFO_CLASS
+ raise
+
+ # GetGroupsForUser()
+
+ user_handle.GetGroupsForUser()
+
+ # TestPrivateFunctionsUser()
+
+ try:
+ user_handle.TestPrivateFunctionsUser()
+ except dcerpc.NTSTATUS, arg:
+ if arg[0] != 0xC0000002L:
+ raise
+
+def test_GroupHandle(group_handle):
+
+ # QuerySecurity()/SetSecurity()
+
+ group_handle.SetSecurity(group_handle.QuerySecurity())
+
+ # QueryGroupInfo()
+
+ for level in [1, 2, 3, 4, 5]:
+ info = group_handle.QueryGroupInfo(level)
+
+ # TODO: SetGroupinfo()
+
+ # QueryGroupMember()
+
+ group_handle.QueryGroupMember()
+
+def test_AliasHandle(alias_handle):
+
+ # QuerySecurity()/SetSecurity()
+
+ alias_handle.SetSecurity(alias_handle.QuerySecurity())
+
+ print alias_handle.GetMembersInAlias()
+
+def test_DomainHandle(name, sid, domain_handle):
+
+ print 'testing %s (%s)' % (name, sid)
+
+ # QuerySecurity()/SetSecurity()
+
+ domain_handle.SetSecurity(domain_handle.QuerySecurity())
+
+ # LookupNames(), none mapped
+
+ try:
+ domain_handle.LookupNames(['xxNONAMExx'])
+ except dcerpc.NTSTATUS, arg:
+ if arg[0] != 0xc0000073L:
+ raise dcerpc.NTSTATUS(arg)
+
+ # LookupNames(), some mapped
+
+ if name != 'Builtin':
+ domain_handle.LookupNames(['Administrator', 'xxNONAMExx'])
+
+ # QueryDomainInfo()/SetDomainInfo()
+
+ levels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13]
+ set_ok = [1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0]
+
+ for i in range(len(levels)):
+
+ info = domain_handle.QueryDomainInfo(level = levels[i])
+
+ try:
+ domain_handle.SetDomainInfo(levels[i], info)
+ except dcerpc.NTSTATUS, arg:
+ if not (arg[0] == 0xc0000003L and not set_ok[i]):
+ raise
+
+ # QueryDomainInfo2()
+
+ levels = [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13]
+
+ for i in range(len(levels)):
+ domain_handle.QueryDomainInfo2(level = levels[i])
+
+ # EnumDomainUsers
+
+ print 'testing users'
+
+ users = domain_handle.EnumDomainUsers()
+ rids = domain_handle.LookupNames(users)
+
+ for i in range(len(users)):
+ test_UserHandle(domain_handle.OpenUser(rids[0][i]))
+
+ # QueryDisplayInfo
+
+ for i in [1, 2, 3, 4, 5]:
+ domain_handle.QueryDisplayInfo(level = i)
+ domain_handle.QueryDisplayInfo2(level = i)
+ domain_handle.QueryDisplayInfo3(level = i)
+
+ # EnumDomainGroups
+
+ print 'testing groups'
+
+ groups = domain_handle.EnumDomainGroups()
+ rids = domain_handle.LookupNames(groups)
+
+ for i in range(len(groups)):
+ test_GroupHandle(domain_handle.OpenGroup(rids[0][i]))
+
+ # EnumDomainAliases
+
+ print 'testing aliases'
+
+ aliases = domain_handle.EnumDomainAliases()
+ rids = domain_handle.LookupNames(aliases)
+
+ for i in range(len(aliases)):
+ test_AliasHandle(domain_handle.OpenAlias(rids[0][i]))
+
+ # CreateUser
+ # CreateUser2
+ # CreateDomAlias
+ # RidToSid
+ # RemoveMemberFromForeignDomain
+ # CreateDomainGroup
+ # GetAliasMembership
+
+ # GetBootKeyInformation()
+
+ try:
+ domain_handle.GetBootKeyInformation()
+ except dcerpc.NTSTATUS, arg:
+ pass
+
+ # TestPrivateFunctionsDomain()
+
+ try:
+ domain_handle.TestPrivateFunctionsDomain()
+ except dcerpc.NTSTATUS, arg:
+ if arg[0] != 0xC0000002L:
+ raise
+
+def test_ConnectHandle(connect_handle):
+
+ print 'testing connect handle'
+
+ # QuerySecurity/SetSecurity
+
+ connect_handle.SetSecurity(connect_handle.QuerySecurity())
+
+ # Lookup bogus domain
+
+ try:
+ connect_handle.LookupDomain('xxNODOMAINxx')
+ except dcerpc.NTSTATUS, arg:
+ if arg[0] != 0xC00000DFL: # NT_STATUS_NO_SUCH_DOMAIN
+ raise
+
+ # Test all domains
+
+ for domain_name in connect_handle.EnumDomains():
+
+ connect_handle.GetDomPwInfo(domain_name)
+ sid = connect_handle.LookupDomain(domain_name)
+ domain_handle = connect_handle.OpenDomain(sid)
+
+ test_DomainHandle(domain_name, sid, domain_handle)
+
+ # TODO: Test Shutdown() function
+
+def runtests(binding, creds):
+
+ print 'Testing SAMR pipe'
+
+ pipe = dcerpc.pipe_connect(binding,
+ dcerpc.DCERPC_SAMR_UUID, int(dcerpc.DCERPC_SAMR_VERSION), creds)
+
+ handle = test_Connect(pipe)
+ test_ConnectHandle(handle)
diff --git a/source4/scripting/python/samba/torture/torture_tdb.py b/source4/scripting/python/samba/torture/torture_tdb.py
new file mode 100755
index 0000000000..7f97caf6cb
--- /dev/null
+++ b/source4/scripting/python/samba/torture/torture_tdb.py
@@ -0,0 +1,90 @@
+#!/usr/bin/python
+
+import sys, os
+import Tdb
+
+def fail(msg):
+ print 'FAILED:', msg
+ sys.exit(1)
+
+tdb_file = '/tmp/torture_tdb.tdb'
+
+# Create temporary tdb file
+
+t = Tdb.Tdb(tdb_file, flags = Tdb.CLEAR_IF_FIRST)
+
+# Check non-existent key throws KeyError exception
+
+try:
+ t['__none__']
+except KeyError:
+ pass
+else:
+ fail('non-existent key did not throw KeyError')
+
+# Check storing key
+
+t['bar'] = '1234'
+if t['bar'] != '1234':
+ fail('store key failed')
+
+# Check key exists
+
+if not t.has_key('bar'):
+ fail('has_key() failed for existing key')
+
+if t.has_key('__none__'):
+ fail('has_key() succeeded for non-existent key')
+
+# Delete key
+
+try:
+ del(t['__none__'])
+except KeyError:
+ pass
+else:
+ fail('delete of non-existent key did not throw KeyError')
+
+del t['bar']
+if t.has_key('bar'):
+ fail('delete of existing key did not delete key')
+
+# Clear all keys
+
+t.clear()
+if len(t) != 0:
+ fail('clear failed to remove all keys')
+
+# Other dict functions
+
+t['a'] = '1'
+t['ab'] = '12'
+t['abc'] = '123'
+
+if len(t) != 3:
+ fail('len method produced wrong value')
+
+keys = t.keys()
+values = t.values()
+items = t.items()
+
+if set(keys) != set(['a', 'ab', 'abc']):
+ fail('keys method produced wrong values')
+
+if set(values) != set(['1', '12', '123']):
+ fail('values method produced wrong values')
+
+if set(items) != set([('a', '1'), ('ab', '12'), ('abc', '123')]):
+ fail('values method produced wrong values')
+
+t.close()
+
+# Re-open read-only
+
+t = Tdb.Tdb(tdb_file, open_flags = os.O_RDONLY)
+t.keys()
+t.close()
+
+# Clean up
+
+os.unlink(tdb_file)
diff --git a/source4/scripting/python/samba/torture/winreg.py b/source4/scripting/python/samba/torture/winreg.py
new file mode 100755
index 0000000000..eb60b9847e
--- /dev/null
+++ b/source4/scripting/python/samba/torture/winreg.py
@@ -0,0 +1,165 @@
+#!/usr/bin/python
+
+import sys, dcerpc
+
+def test_OpenHKLM(pipe):
+
+ r = {}
+ r['unknown'] = {}
+ r['unknown']['unknown0'] = 0x9038
+ r['unknown']['unknown1'] = 0x0000
+ r['access_required'] = 0x02000000
+
+ result = dcerpc.winreg_OpenHKLM(pipe, r)
+
+ return result['handle']
+
+def test_QueryInfoKey(pipe, handle):
+
+ r = {}
+ r['handle'] = handle
+ r['class'] = {}
+ r['class']['name'] = None
+
+ return dcerpc.winreg_QueryInfoKey(pipe, r)
+
+def test_CloseKey(pipe, handle):
+
+ r = {}
+ r['handle'] = handle
+
+ dcerpc.winreg_CloseKey(pipe, r)
+
+def test_FlushKey(pipe, handle):
+
+ r = {}
+ r['handle'] = handle
+
+ dcerpc.winreg_FlushKey(pipe, r)
+
+def test_GetVersion(pipe, handle):
+
+ r = {}
+ r['handle'] = handle
+
+ dcerpc.winreg_GetVersion(pipe, r)
+
+def test_GetKeySecurity(pipe, handle):
+
+ r = {}
+ r['handle'] = handle
+ r['unknown'] = 4
+ r['size'] = None
+ r['data'] = {}
+ r['data']['max_len'] = 0
+ r['data']['data'] = ''
+
+ result = dcerpc.winreg_GetKeySecurity(pipe, r)
+
+ print result
+
+ if result['result'] == dcerpc.WERR_INSUFFICIENT_BUFFER:
+ r['size'] = {}
+ r['size']['max_len'] = result['data']['max_len']
+ r['size']['offset'] = 0
+ r['size']['len'] = result['data']['max_len']
+
+ result = dcerpc.winreg_GetKeySecurity(pipe, r)
+
+ print result
+
+ sys.exit(1)
+
+def test_Key(pipe, handle, name, depth = 0):
+
+ # Don't descend too far. Registries can be very deep.
+
+ if depth > 2:
+ return
+
+ try:
+ keyinfo = test_QueryInfoKey(pipe, handle)
+ except dcerpc.WERROR, arg:
+ if arg[0] == dcerpc.WERR_ACCESS_DENIED:
+ return
+
+ test_GetVersion(pipe, handle)
+
+ test_FlushKey(pipe, handle)
+
+ test_GetKeySecurity(pipe, handle)
+
+ # Enumerate values in this key
+
+ r = {}
+ r['handle'] = handle
+ r['name_in'] = {}
+ r['name_in']['len'] = 0
+ r['name_in']['max_len'] = (keyinfo['max_valnamelen'] + 1) * 2
+ r['name_in']['buffer'] = {}
+ r['name_in']['buffer']['max_len'] = keyinfo['max_valnamelen'] + 1
+ r['name_in']['buffer']['offset'] = 0
+ r['name_in']['buffer']['len'] = 0
+ r['type'] = 0
+ r['value_in'] = {}
+ r['value_in']['max_len'] = keyinfo['max_valbufsize']
+ r['value_in']['offset'] = 0
+ r['value_in']['len'] = 0
+ r['value_len1'] = keyinfo['max_valbufsize']
+ r['value_len2'] = 0
+
+ for i in range(0, keyinfo['num_values']):
+
+ r['enum_index'] = i
+
+ dcerpc.winreg_EnumValue(pipe, r)
+
+ # Recursively test subkeys of this key
+
+ r = {}
+ r['handle'] = handle
+ r['key_name_len'] = 0
+ r['unknown'] = 0x0414
+ r['in_name'] = {}
+ r['in_name']['unknown'] = 0x20a
+ r['in_name']['key_name'] = {}
+ r['in_name']['key_name']['name'] = None
+ r['class'] = {}
+ r['class']['name'] = None
+ r['last_changed_time'] = {}
+ r['last_changed_time']['low'] = 0
+ r['last_changed_time']['high'] = 0
+
+ for i in range(0, keyinfo['num_subkeys']):
+
+ r['enum_index'] = i
+
+ subkey = dcerpc.winreg_EnumKey(pipe, r)
+
+ s = {}
+ s['handle'] = handle
+ s['keyname'] = {}
+ s['keyname']['name'] = subkey['out_name']['name']
+ s['unknown'] = 0
+ s['access_mask'] = 0x02000000
+
+ result = dcerpc.winreg_OpenKey(pipe, s)
+
+ test_Key(pipe, result['handle'], name + '/' + s['keyname']['name'],
+ depth + 1)
+
+ test_CloseKey(pipe, result['handle'])
+
+ # Enumerate values
+
+def runtests(binding, domain, username, password):
+
+ print 'Testing WINREG pipe'
+
+ pipe = dcerpc.pipe_connect(binding,
+ dcerpc.DCERPC_WINREG_UUID, dcerpc.DCERPC_WINREG_VERSION,
+ domain, username, password)
+
+ handle = test_OpenHKLM(pipe)
+
+ test_Key(pipe, handle, 'HKLM')
diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py
index 5bcc4294ba..81945525e6 100644
--- a/source4/scripting/python/samba/upgrade.py
+++ b/source4/scripting/python/samba/upgrade.py
@@ -1,32 +1,22 @@
-# backend code for upgrading from Samba3
-# Copyright Jelmer Vernooij 2005-2007
+#!/usr/bin/python
#
-# 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/>.
+# backend code for upgrading from Samba3
+# Copyright Jelmer Vernooij 2005-2007
+# Released under the GNU GPL v3 or later
#
"""Support code for upgrading from Samba 3 to Samba 4."""
__docformat__ = "restructuredText"
+from provision import provision, FILL_DRS
import grp
import ldb
import time
import pwd
-
-from samba import Ldb, registry
+import registry
+from samba import Ldb
from samba.param import LoadParm
-from samba.provision import provision
def import_sam_policy(samldb, policy, dn):
"""Import a Samba 3 policy database."""
@@ -44,7 +34,7 @@ samba3UserMustLogonToChangePassword: %d
samba3BadLockoutMinutes: %d
samba3DisconnectTime: %d
-""" % (dn, policy.min_password_length,
+""" % (dn, policy.min_password_length,
policy.password_history, policy.minimum_password_age,
policy.maximum_password_age, policy.lockout_duration,
policy.reset_count_minutes, policy.user_must_logon_to_change_password,
@@ -53,7 +43,7 @@ samba3DisconnectTime: %d
def import_sam_account(samldb,acc,domaindn,domainsid):
"""Import a Samba 3 SAM account.
-
+
:param samldb: Samba 4 SAM Database handle
:param acc: Samba 3 account
:param domaindn: Domain DN
@@ -69,7 +59,7 @@ def import_sam_account(samldb,acc,domaindn,domainsid):
if acc.fullname is None:
acc.fullname = acc.username
-
+
assert acc.fullname is not None
assert acc.nt_username is not None
@@ -88,8 +78,8 @@ def import_sam_account(samldb,acc,domaindn,domainsid):
"samba3Domain": acc.domain,
"samba3DirDrive": acc.dir_drive,
"samba3MungedDial": acc.munged_dial,
- "samba3Homedir": acc.homedir,
- "samba3LogonScript": acc.logon_script,
+ "samba3Homedir": acc.homedir,
+ "samba3LogonScript": acc.logon_script,
"samba3ProfilePath": acc.profile_path,
"samba3Workstations": acc.workstations,
"samba3KickOffTime": str(acc.kickoff_time),
@@ -105,7 +95,7 @@ def import_sam_account(samldb,acc,domaindn,domainsid):
def import_sam_group(samldb, sid, gid, sid_name_use, nt_name, comment, domaindn):
"""Upgrade a SAM group.
-
+
:param samldb: SAM database.
:param gid: Group GID
:param sid_name_use: SID name use
@@ -119,7 +109,7 @@ def import_sam_group(samldb, sid, gid, sid_name_use, nt_name, comment, domaindn)
if nt_name in ("Domain Guests", "Domain Users", "Domain Admins"):
return None
-
+
if gid == -1:
gr = grp.getgrnam(nt_name)
else:
@@ -131,12 +121,12 @@ def import_sam_group(samldb, sid, gid, sid_name_use, nt_name, comment, domaindn)
unixname = gr.gr_name
assert unixname is not None
-
+
samldb.add({
"dn": "cn=%s,%s" % (nt_name, domaindn),
"objectClass": ["top", "group"],
"description": comment,
- "cn": nt_name,
+ "cn": nt_name,
"objectSid": sid,
"unixName": unixname,
"samba3SidNameUse": str(sid_name_use)
@@ -170,7 +160,7 @@ def import_idmap(samdb,samba3_idmap,domaindn):
def import_wins(samba4_winsdb, samba3_winsdb):
"""Import settings from a Samba3 WINS database.
-
+
:param samba4_winsdb: WINS database to import to
:param samba3_winsdb: WINS database to import from
"""
@@ -218,6 +208,73 @@ def import_wins(samba4_winsdb, samba3_winsdb):
"objectClass": "winsMaxVersion",
"maxVersion": str(version_id)})
+def upgrade_provision(samba3, setup_dir, message, credentials, session_info, smbconf, targetdir):
+ oldconf = samba3.get_conf()
+
+ if oldconf.get("domain logons") == "True":
+ serverrole = "domain controller"
+ else:
+ if oldconf.get("security") == "user":
+ serverrole = "standalone"
+ else:
+ serverrole = "member server"
+
+ domainname = oldconf.get("workgroup")
+ if domainname:
+ domainname = str(domainname)
+ realm = oldconf.get("realm")
+ netbiosname = oldconf.get("netbios name")
+
+ secrets_db = samba3.get_secrets_db()
+
+ if domainname is None:
+ domainname = secrets_db.domains()[0]
+ message("No domain specified in smb.conf file, assuming '%s'" % domainname)
+
+ if realm is None:
+ realm = domainname.lower()
+ message("No realm specified in smb.conf file, assuming '%s'\n" % realm)
+
+ domainguid = secrets_db.get_domain_guid(domainname)
+ domainsid = secrets_db.get_sid(domainname)
+ if domainsid is None:
+ message("Can't find domain secrets for '%s'; using random SID\n" % domainname)
+
+ if netbiosname is not None:
+ machinepass = secrets_db.get_machine_password(netbiosname)
+ else:
+ machinepass = None
+
+ result = provision(setup_dir=setup_dir, message=message,
+ samdb_fill=FILL_DRS, smbconf=smbconf, session_info=session_info,
+ credentials=credentials, realm=realm,
+ domain=domainname, domainsid=domainsid, domainguid=domainguid,
+ machinepass=machinepass, serverrole=serverrole, targetdir=targetdir)
+
+ import_wins(Ldb(result.paths.winsdb), samba3.get_wins_db())
+
+ # FIXME: import_registry(registry.Registry(), samba3.get_registry())
+
+ # FIXME: import_idmap(samdb,samba3.get_idmap_db(),domaindn)
+
+ groupdb = samba3.get_groupmapping_db()
+ for sid in groupdb.groupsids():
+ (gid, sid_name_use, nt_name, comment) = groupdb.get_group(sid)
+ # FIXME: import_sam_group(samdb, sid, gid, sid_name_use, nt_name, comment, domaindn)
+
+ # FIXME: Aliases
+
+ passdb = samba3.get_sam_db()
+ for name in passdb:
+ user = passdb[name]
+ #FIXME: import_sam_account(result.samdb, user, domaindn, domainsid)
+
+ if hasattr(passdb, 'ldap_url'):
+ message("Enabling Samba3 LDAP mappings for SAM database")
+
+ enable_samba3sam(result.samdb, passdb.ldap_url)
+
+
def enable_samba3sam(samdb, ldapurl):
"""Enable Samba 3 LDAP URL database.
@@ -235,7 +292,7 @@ replace: @LIST
smbconf_keep = [
- "dos charset",
+ "dos charset",
"unix charset",
"display charset",
"comment",
@@ -332,7 +389,7 @@ def upgrade_smbconf(oldconf,mark):
"""Remove configuration variables not present in Samba4
:param oldconf: Old configuration structure
- :param mark: Whether removed configuration variables should be
+ :param mark: Whether removed configuration variables should be
kept in the new configuration as "samba3:<name>"
"""
data = oldconf.data()
@@ -377,76 +434,3 @@ def import_registry(samba4_registry, samba3_regdb):
key_handle.set_value(value_name, value_type, value_data)
-def upgrade_provision(samba3, logger, credentials, session_info,
- smbconf, targetdir):
- oldconf = samba3.get_conf()
-
- if oldconf.get("domain logons") == "True":
- serverrole = "domain controller"
- else:
- if oldconf.get("security") == "user":
- serverrole = "standalone"
- else:
- serverrole = "member server"
-
- domainname = oldconf.get("workgroup")
- realm = oldconf.get("realm")
- netbiosname = oldconf.get("netbios name")
-
- secrets_db = samba3.get_secrets_db()
-
- if domainname is None:
- domainname = secrets_db.domains()[0]
- logger.warning("No domain specified in smb.conf file, assuming '%s'",
- domainname)
-
- if realm is None:
- if oldconf.get("domain logons") == "True":
- logger.warning("No realm specified in smb.conf file and being a DC. That upgrade path doesn't work! Please add a 'realm' directive to your old smb.conf to let us know which one you want to use (generally it's the upcased DNS domainname).")
- return
- else:
- realm = domainname.upper()
- logger.warning("No realm specified in smb.conf file, assuming '%s'",
- realm)
-
- domainguid = secrets_db.get_domain_guid(domainname)
- domainsid = secrets_db.get_sid(domainname)
- if domainsid is None:
- logger.warning("Can't find domain secrets for '%s'; using random SID",
- domainname)
-
- if netbiosname is not None:
- machinepass = secrets_db.get_machine_password(netbiosname)
- else:
- machinepass = None
-
- result = provision(logger=logger,
- session_info=session_info, credentials=credentials,
- targetdir=targetdir, realm=realm, domain=domainname,
- domainguid=domainguid, domainsid=domainsid,
- hostname=netbiosname, machinepass=machinepass,
- serverrole=serverrole)
-
- import_wins(Ldb(result.paths.winsdb), samba3.get_wins_db())
-
- # FIXME: import_registry(registry.Registry(), samba3.get_registry())
-
- # FIXME: import_idmap(samdb,samba3.get_idmap_db(),domaindn)
-
- groupdb = samba3.get_groupmapping_db()
- for sid in groupdb.groupsids():
- (gid, sid_name_use, nt_name, comment) = groupdb.get_group(sid)
- # FIXME: import_sam_group(samdb, sid, gid, sid_name_use, nt_name, comment, domaindn)
-
- # FIXME: Aliases
-
- passdb = samba3.get_sam_db()
- for name in passdb:
- user = passdb[name]
- #FIXME: import_sam_account(result.samdb, user, domaindn, domainsid)
-
- if hasattr(passdb, 'ldap_url'):
- logger.info("Enabling Samba3 LDAP mappings for SAM database")
-
- enable_samba3sam(result.samdb, passdb.ldap_url)
-
diff --git a/source4/scripting/python/samba/upgradehelpers.py b/source4/scripting/python/samba/upgradehelpers.py
deleted file mode 100755
index 3a7dfb3997..0000000000
--- a/source4/scripting/python/samba/upgradehelpers.py
+++ /dev/null
@@ -1,953 +0,0 @@
-#!/usr/bin/env python
-#
-# Helpers for provision stuff
-# Copyright (C) Matthieu Patou <mat@matws.net> 2009-2010
-#
-# Based on provision a Samba4 server by
-# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007-2008
-# Copyright (C) Andrew Bartlett <abartlet@samba.org> 2008
-#
-#
-# 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/>.
-
-"""Helers used for upgrading between different database formats."""
-
-import os
-import string
-import re
-import shutil
-import samba
-
-from samba import Ldb, version, ntacls
-from samba.dsdb import DS_DOMAIN_FUNCTION_2000
-from ldb import SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE
-import ldb
-from samba.provision import (ProvisionNames, provision_paths_from_lp,
- getpolicypath, set_gpos_acl, create_gpo_struct,
- FILL_FULL, provision, ProvisioningError,
- setsysvolacl, secretsdb_self_join)
-from samba.dcerpc import misc, security, xattr
-from samba.dcerpc.misc import SEC_CHAN_BDC
-from samba.ndr import ndr_unpack
-from samba.samdb import SamDB
-
-# All the ldb related to registry are commented because the path for them is
-# relative in the provisionPath object
-# And so opening them create a file in the current directory which is not what
-# we want
-# I still keep them commented because I plan soon to make more cleaner
-ERROR = -1
-SIMPLE = 0x00
-CHANGE = 0x01
-CHANGESD = 0x02
-GUESS = 0x04
-PROVISION = 0x08
-CHANGEALL = 0xff
-
-hashAttrNotCopied = set(["dn", "whenCreated", "whenChanged", "objectGUID",
- "uSNCreated", "replPropertyMetaData", "uSNChanged", "parentGUID",
- "objectCategory", "distinguishedName", "nTMixedDomain",
- "showInAdvancedViewOnly", "instanceType", "msDS-Behavior-Version",
- "nextRid", "cn", "versionNumber", "lmPwdHistory", "pwdLastSet",
- "ntPwdHistory", "unicodePwd","dBCSPwd", "supplementalCredentials",
- "gPCUserExtensionNames", "gPCMachineExtensionNames","maxPwdAge", "secret",
- "possibleInferiors", "privilege", "sAMAccountType"])
-
-
-class ProvisionLDB(object):
-
- def __init__(self):
- self.sam = None
- self.secrets = None
- self.idmap = None
- self.privilege = None
- self.hkcr = None
- self.hkcu = None
- self.hku = None
- self.hklm = None
-
- def startTransactions(self):
- self.sam.transaction_start()
- self.secrets.transaction_start()
- self.idmap.transaction_start()
- self.privilege.transaction_start()
-# TO BE DONE
-# self.hkcr.transaction_start()
-# self.hkcu.transaction_start()
-# self.hku.transaction_start()
-# self.hklm.transaction_start()
-
- def groupedRollback(self):
- ok = True
- try:
- self.sam.transaction_cancel()
- except Exception:
- ok = False
-
- try:
- self.secrets.transaction_cancel()
- except Exception:
- ok = False
-
- try:
- self.idmap.transaction_cancel()
- except Exception:
- ok = False
-
- try:
- self.privilege.transaction_cancel()
- except Exception:
- ok = False
-
- return ok
-# TO BE DONE
-# self.hkcr.transaction_cancel()
-# self.hkcu.transaction_cancel()
-# self.hku.transaction_cancel()
-# self.hklm.transaction_cancel()
-
- def groupedCommit(self):
- try:
- self.sam.transaction_prepare_commit()
- self.secrets.transaction_prepare_commit()
- self.idmap.transaction_prepare_commit()
- self.privilege.transaction_prepare_commit()
- except Exception:
- return self.groupedRollback()
-# TO BE DONE
-# self.hkcr.transaction_prepare_commit()
-# self.hkcu.transaction_prepare_commit()
-# self.hku.transaction_prepare_commit()
-# self.hklm.transaction_prepare_commit()
- try:
- self.sam.transaction_commit()
- self.secrets.transaction_commit()
- self.idmap.transaction_commit()
- self.privilege.transaction_commit()
- except Exception:
- return self.groupedRollback()
-
-# TO BE DONE
-# self.hkcr.transaction_commit()
-# self.hkcu.transaction_commit()
-# self.hku.transaction_commit()
-# self.hklm.transaction_commit()
- return True
-
-def get_ldbs(paths, creds, session, lp):
- """Return LDB object mapped on most important databases
-
- :param paths: An object holding the different importants paths for provision object
- :param creds: Credential used for openning LDB files
- :param session: Session to use for openning LDB files
- :param lp: A loadparam object
- :return: A ProvisionLDB object that contains LDB object for the different LDB files of the provision"""
-
- ldbs = ProvisionLDB()
-
- ldbs.sam = SamDB(paths.samdb, session_info=session, credentials=creds, lp=lp, options=["modules:samba_dsdb"])
- ldbs.secrets = Ldb(paths.secrets, session_info=session, credentials=creds, lp=lp)
- ldbs.idmap = Ldb(paths.idmapdb, session_info=session, credentials=creds, lp=lp)
- ldbs.privilege = Ldb(paths.privilege, session_info=session, credentials=creds, lp=lp)
-# ldbs.hkcr = Ldb(paths.hkcr, session_info=session, credentials=creds, lp=lp)
-# ldbs.hkcu = Ldb(paths.hkcu, session_info=session, credentials=creds, lp=lp)
-# ldbs.hku = Ldb(paths.hku, session_info=session, credentials=creds, lp=lp)
-# ldbs.hklm = Ldb(paths.hklm, session_info=session, credentials=creds, lp=lp)
-
- return ldbs
-
-
-def usn_in_range(usn, range):
- """Check if the usn is in one of the range provided.
- To do so, the value is checked to be between the lower bound and
- higher bound of a range
-
- :param usn: A integer value corresponding to the usn that we want to update
- :param range: A list of integer representing ranges, lower bounds are in
- the even indices, higher in odd indices
- :return: True if the usn is in one of the range, False otherwise
- """
-
- idx = 0
- cont = True
- ok = False
- while cont:
- if idx == len(range):
- cont = False
- continue
- if usn < int(range[idx]):
- if idx %2 == 1:
- ok = True
- cont = False
- if usn == int(range[idx]):
- cont = False
- ok = True
- idx = idx + 1
- return ok
-
-
-def get_paths(param, targetdir=None, smbconf=None):
- """Get paths to important provision objects (smb.conf, ldb files, ...)
-
- :param param: Param object
- :param targetdir: Directory where the provision is (or will be) stored
- :param smbconf: Path to the smb.conf file
- :return: A list with the path of important provision objects"""
- if targetdir is not None:
- etcdir = os.path.join(targetdir, "etc")
- if not os.path.exists(etcdir):
- os.makedirs(etcdir)
- smbconf = os.path.join(etcdir, "smb.conf")
- if smbconf is None:
- smbconf = param.default_path()
-
- if not os.path.exists(smbconf):
- raise ProvisioningError("Unable to find smb.conf")
-
- lp = param.LoadParm()
- lp.load(smbconf)
- paths = provision_paths_from_lp(lp, lp.get("realm"))
- return paths
-
-def update_policyids(names, samdb):
- """Update policy ids that could have changed after sam update
-
- :param names: List of key provision parameters
- :param samdb: An Ldb object conntected with the sam DB
- """
- # policy guid
- res = samdb.search(expression="(displayName=Default Domain Policy)",
- base="CN=Policies,CN=System," + str(names.rootdn),
- scope=SCOPE_ONELEVEL, attrs=["cn","displayName"])
- names.policyid = str(res[0]["cn"]).replace("{","").replace("}","")
- # dc policy guid
- res2 = samdb.search(expression="(displayName=Default Domain Controllers"
- " Policy)",
- base="CN=Policies,CN=System," + str(names.rootdn),
- scope=SCOPE_ONELEVEL, attrs=["cn","displayName"])
- if len(res2) == 1:
- names.policyid_dc = str(res2[0]["cn"]).replace("{","").replace("}","")
- else:
- names.policyid_dc = None
-
-
-def find_provision_key_parameters(samdb, secretsdb, idmapdb, paths, smbconf, lp):
- """Get key provision parameters (realm, domain, ...) from a given provision
-
- :param samdb: An LDB object connected to the sam.ldb file
- :param secretsdb: An LDB object connected to the secrets.ldb file
- :param idmapdb: An LDB object connected to the idmap.ldb file
- :param paths: A list of path to provision object
- :param smbconf: Path to the smb.conf file
- :param lp: A LoadParm object
- :return: A list of key provision parameters
- """
- names = ProvisionNames()
- names.adminpass = None
-
- # NT domain, kerberos realm, root dn, domain dn, domain dns name
- names.domain = string.upper(lp.get("workgroup"))
- names.realm = lp.get("realm")
- basedn = "DC=" + names.realm.replace(".",",DC=")
- names.dnsdomain = names.realm.lower()
- names.realm = string.upper(names.realm)
- # netbiosname
- # Get the netbiosname first (could be obtained from smb.conf in theory)
- res = secretsdb.search(expression="(flatname=%s)" %
- names.domain,base="CN=Primary Domains",
- scope=SCOPE_SUBTREE, attrs=["sAMAccountName"])
- names.netbiosname = str(res[0]["sAMAccountName"]).replace("$","")
-
- names.smbconf = smbconf
-
- # That's a bit simplistic but it's ok as long as we have only 3
- # partitions
- current = samdb.search(expression="(objectClass=*)",
- base="", scope=SCOPE_BASE,
- attrs=["defaultNamingContext", "schemaNamingContext",
- "configurationNamingContext","rootDomainNamingContext"])
-
- names.configdn = current[0]["configurationNamingContext"]
- configdn = str(names.configdn)
- names.schemadn = current[0]["schemaNamingContext"]
- if not (ldb.Dn(samdb, basedn) == (ldb.Dn(samdb,
- current[0]["defaultNamingContext"][0]))):
- raise ProvisioningError(("basedn in %s (%s) and from %s (%s)"
- "is not the same ..." % (paths.samdb,
- str(current[0]["defaultNamingContext"][0]),
- paths.smbconf, basedn)))
-
- names.domaindn=current[0]["defaultNamingContext"]
- names.rootdn=current[0]["rootDomainNamingContext"]
- # default site name
- res3 = samdb.search(expression="(objectClass=*)",
- base="CN=Sites," + configdn, scope=SCOPE_ONELEVEL, attrs=["cn"])
- names.sitename = str(res3[0]["cn"])
-
- # dns hostname and server dn
- res4 = samdb.search(expression="(CN=%s)" % names.netbiosname,
- base="OU=Domain Controllers,%s" % basedn,
- scope=SCOPE_ONELEVEL, attrs=["dNSHostName"])
- names.hostname = str(res4[0]["dNSHostName"]).replace("." + names.dnsdomain,"")
-
- server_res = samdb.search(expression="serverReference=%s" % res4[0].dn,
- attrs=[], base=configdn)
- names.serverdn = server_res[0].dn
-
- # invocation id/objectguid
- res5 = samdb.search(expression="(objectClass=*)",
- base="CN=NTDS Settings,%s" % str(names.serverdn), scope=SCOPE_BASE,
- attrs=["invocationID", "objectGUID"])
- names.invocation = str(ndr_unpack(misc.GUID, res5[0]["invocationId"][0]))
- names.ntdsguid = str(ndr_unpack(misc.GUID, res5[0]["objectGUID"][0]))
-
- # domain guid/sid
- res6 = samdb.search(expression="(objectClass=*)", base=basedn,
- scope=SCOPE_BASE, attrs=["objectGUID",
- "objectSid","msDS-Behavior-Version" ])
- names.domainguid = str(ndr_unpack(misc.GUID, res6[0]["objectGUID"][0]))
- names.domainsid = ndr_unpack( security.dom_sid, res6[0]["objectSid"][0])
- if res6[0].get("msDS-Behavior-Version") is None or \
- int(res6[0]["msDS-Behavior-Version"][0]) < DS_DOMAIN_FUNCTION_2000:
- names.domainlevel = DS_DOMAIN_FUNCTION_2000
- else:
- names.domainlevel = int(res6[0]["msDS-Behavior-Version"][0])
-
- # policy guid
- res7 = samdb.search(expression="(displayName=Default Domain Policy)",
- base="CN=Policies,CN=System," + basedn,
- scope=SCOPE_ONELEVEL, attrs=["cn","displayName"])
- names.policyid = str(res7[0]["cn"]).replace("{","").replace("}","")
- # dc policy guid
- res8 = samdb.search(expression="(displayName=Default Domain Controllers"
- " Policy)",
- base="CN=Policies,CN=System," + basedn,
- scope=SCOPE_ONELEVEL, attrs=["cn","displayName"])
- if len(res8) == 1:
- names.policyid_dc = str(res8[0]["cn"]).replace("{","").replace("}","")
- else:
- names.policyid_dc = None
- res9 = idmapdb.search(expression="(cn=%s)" %
- (security.SID_BUILTIN_ADMINISTRATORS),
- attrs=["xidNumber"])
- if len(res9) == 1:
- names.wheel_gid = res9[0]["xidNumber"]
- else:
- raise ProvisioningError("Unable to find uid/gid for Domain Admins rid")
- return names
-
-
-def newprovision(names, creds, session, smbconf, provdir, logger):
- """Create a new provision.
-
- This provision will be the reference for knowing what has changed in the
- since the latest upgrade in the current provision
-
- :param names: List of provision parameters
- :param creds: Credentials for the authentification
- :param session: Session object
- :param smbconf: Path to the smb.conf file
- :param provdir: Directory where the provision will be stored
- :param logger: A Logger
- """
- if os.path.isdir(provdir):
- shutil.rmtree(provdir)
- os.mkdir(provdir)
- logger.info("Provision stored in %s", provdir)
- provision(logger, session, creds, smbconf=smbconf,
- targetdir=provdir, samdb_fill=FILL_FULL, realm=names.realm,
- domain=names.domain, domainguid=names.domainguid,
- domainsid=str(names.domainsid), ntdsguid=names.ntdsguid,
- policyguid=names.policyid, policyguid_dc=names.policyid_dc,
- hostname=names.netbiosname.lower(), hostip=None, hostip6=None,
- invocationid=names.invocation, adminpass=names.adminpass,
- krbtgtpass=None, machinepass=None, dnspass=None, root=None,
- nobody=None, wheel=None, users=None,
- serverrole="domain controller", ldap_backend_extra_port=None,
- backend_type=None, ldapadminpass=None, ol_mmr_urls=None,
- slapd_path=None, setup_ds_path=None, nosync=None,
- dom_for_fun_level=names.domainlevel,
- ldap_dryrun_mode=None, useeadb=True)
-
-
-def dn_sort(x, y):
- """Sorts two DNs in the lexicographical order it and put higher level DN
- before.
-
- So given the dns cn=bar,cn=foo and cn=foo the later will be return as
- smaller
-
- :param x: First object to compare
- :param y: Second object to compare
- """
- p = re.compile(r'(?<!\\), ?')
- tab1 = p.split(str(x))
- tab2 = p.split(str(y))
- minimum = min(len(tab1), len(tab2))
- len1 = len(tab1)-1
- len2 = len(tab2)-1
- # Note: python range go up to upper limit but do not include it
- for i in range(0, minimum):
- ret = cmp(tab1[len1-i], tab2[len2-i])
- if ret != 0:
- return ret
- else:
- if i == minimum-1:
- assert len1!=len2,"PB PB PB" + " ".join(tab1)+" / " + " ".join(tab2)
- if len1 > len2:
- return 1
- else:
- return -1
- return ret
-
-
-def identic_rename(ldbobj, dn):
- """Perform a back and forth rename to trigger renaming on attribute that
- can't be directly modified.
-
- :param lbdobj: An Ldb Object
- :param dn: DN of the object to manipulate
- """
- (before, after) = str(dn).split('=', 1)
- # we need to use relax to avoid the subtree_rename constraints
- ldbobj.rename(dn, ldb.Dn(ldbobj, "%s=foo%s" % (before, after)), ["relax:0"])
- ldbobj.rename(ldb.Dn(ldbobj, "%s=foo%s" % (before, after)), dn, ["relax:0"])
-
-
-def chunck_acl(acl):
- """Return separate ACE of an ACL
-
- :param acl: A string representing the ACL
- :return: A hash with different parts
- """
-
- p = re.compile(r'(\w+)?(\(.*?\))')
- tab = p.findall(acl)
-
- hash = {}
- hash["aces"] = []
- for e in tab:
- if len(e[0]) > 0:
- hash["flags"] = e[0]
- hash["aces"].append(e[1])
-
- return hash
-
-
-def chunck_sddl(sddl):
- """ Return separate parts of the SDDL (owner, group, ...)
-
- :param sddl: An string containing the SDDL to chunk
- :return: A hash with the different chunk
- """
-
- p = re.compile(r'([OGDS]:)(.*?)(?=(?:[GDS]:|$))')
- tab = p.findall(sddl)
-
- hash = {}
- for e in tab:
- if e[0] == "O:":
- hash["owner"] = e[1]
- if e[0] == "G:":
- hash["group"] = e[1]
- if e[0] == "D:":
- hash["dacl"] = e[1]
- if e[0] == "S:":
- hash["sacl"] = e[1]
-
- return hash
-
-
-def get_diff_sddls(refsddl, cursddl):
- """Get the difference between 2 sddl
-
- This function split the textual representation of ACL into smaller
- chunck in order to not to report a simple permutation as a difference
-
- :param refsddl: First sddl to compare
- :param cursddl: Second sddl to compare
- :return: A string that explain difference between sddls
- """
-
- txt = ""
- hash_new = chunck_sddl(cursddl)
- hash_ref = chunck_sddl(refsddl)
-
- if hash_new["owner"] != hash_ref["owner"]:
- txt = "\tOwner mismatch: %s (in ref) %s" \
- "(in current)\n" % (hash_ref["owner"], hash_new["owner"])
-
- if hash_new["group"] != hash_ref["group"]:
- txt = "%s\tGroup mismatch: %s (in ref) %s" \
- "(in current)\n" % (txt, hash_ref["group"], hash_new["group"])
-
- for part in ["dacl", "sacl"]:
- if hash_new.has_key(part) and hash_ref.has_key(part):
-
- # both are present, check if they contain the same ACE
- h_new = set()
- h_ref = set()
- c_new = chunck_acl(hash_new[part])
- c_ref = chunck_acl(hash_ref[part])
-
- for elem in c_new["aces"]:
- h_new.add(elem)
-
- for elem in c_ref["aces"]:
- h_ref.add(elem)
-
- for k in set(h_ref):
- if k in h_new:
- h_new.remove(k)
- h_ref.remove(k)
-
- if len(h_new) + len(h_ref) > 0:
- txt = "%s\tPart %s is different between reference" \
- " and current here is the detail:\n" % (txt, part)
-
- for item in h_new:
- txt = "%s\t\t%s ACE is not present in the" \
- " reference\n" % (txt, item)
-
- for item in h_ref:
- txt = "%s\t\t%s ACE is not present in the" \
- " current\n" % (txt, item)
-
- elif hash_new.has_key(part) and not hash_ref.has_key(part):
- txt = "%s\tReference ACL hasn't a %s part\n" % (txt, part)
- elif not hash_new.has_key(part) and hash_ref.has_key(part):
- txt = "%s\tCurrent ACL hasn't a %s part\n" % (txt, part)
-
- return txt
-
-
-def update_secrets(newsecrets_ldb, secrets_ldb, messagefunc):
- """Update secrets.ldb
-
- :param newsecrets_ldb: An LDB object that is connected to the secrets.ldb
- of the reference provision
- :param secrets_ldb: An LDB object that is connected to the secrets.ldb
- of the updated provision
- """
-
- messagefunc(SIMPLE, "update secrets.ldb")
- reference = newsecrets_ldb.search(expression="dn=@MODULES", base="",
- scope=SCOPE_SUBTREE)
- current = secrets_ldb.search(expression="dn=@MODULES", base="",
- scope=SCOPE_SUBTREE)
- assert reference, "Reference modules list can not be empty"
- if len(current) == 0:
- # No modules present
- delta = secrets_ldb.msg_diff(ldb.Message(), reference[0])
- delta.dn = reference[0].dn
- secrets_ldb.add(reference[0])
- else:
- delta = secrets_ldb.msg_diff(current[0], reference[0])
- delta.dn = current[0].dn
- secrets_ldb.modify(delta)
-
- reference = newsecrets_ldb.search(expression="objectClass=top", base="",
- scope=SCOPE_SUBTREE, attrs=["dn"])
- current = secrets_ldb.search(expression="objectClass=top", base="",
- scope=SCOPE_SUBTREE, attrs=["dn"])
- hash_new = {}
- hash = {}
- listMissing = []
- listPresent = []
-
- empty = ldb.Message()
- for i in range(0, len(reference)):
- hash_new[str(reference[i]["dn"]).lower()] = reference[i]["dn"]
-
- # Create a hash for speeding the search of existing object in the
- # current provision
- for i in range(0, len(current)):
- hash[str(current[i]["dn"]).lower()] = current[i]["dn"]
-
- for k in hash_new.keys():
- if not hash.has_key(k):
- listMissing.append(hash_new[k])
- else:
- listPresent.append(hash_new[k])
-
- for entry in listMissing:
- reference = newsecrets_ldb.search(expression="dn=%s" % entry,
- base="", scope=SCOPE_SUBTREE)
- current = secrets_ldb.search(expression="dn=%s" % entry,
- base="", scope=SCOPE_SUBTREE)
- delta = secrets_ldb.msg_diff(empty, reference[0])
- for att in hashAttrNotCopied:
- delta.remove(att)
- messagefunc(CHANGE, "Entry %s is missing from secrets.ldb" %
- reference[0].dn)
- for att in delta:
- messagefunc(CHANGE, " Adding attribute %s" % att)
- delta.dn = reference[0].dn
- secrets_ldb.add(delta)
-
- for entry in listPresent:
- reference = newsecrets_ldb.search(expression="dn=%s" % entry,
- base="", scope=SCOPE_SUBTREE)
- current = secrets_ldb.search(expression="dn=%s" % entry, base="",
- scope=SCOPE_SUBTREE)
- delta = secrets_ldb.msg_diff(current[0], reference[0])
- for att in hashAttrNotCopied:
- delta.remove(att)
- for att in delta:
- if att == "name":
- messagefunc(CHANGE, "Found attribute name on %s,"
- " must rename the DN" % (current[0].dn))
- identic_rename(secrets_ldb, reference[0].dn)
- else:
- delta.remove(att)
-
- for entry in listPresent:
- reference = newsecrets_ldb.search(expression="dn=%s" % entry, base="",
- scope=SCOPE_SUBTREE)
- current = secrets_ldb.search(expression="dn=%s" % entry, base="",
- scope=SCOPE_SUBTREE)
- delta = secrets_ldb.msg_diff(current[0], reference[0])
- for att in hashAttrNotCopied:
- delta.remove(att)
- for att in delta:
- if att == "msDS-KeyVersionNumber":
- delta.remove(att)
- if att != "dn":
- messagefunc(CHANGE,
- "Adding/Changing attribute %s to %s" %
- (att, current[0].dn))
-
- delta.dn = current[0].dn
- secrets_ldb.modify(delta)
-
- res2 = secrets_ldb.search(expression="(samaccountname=dns)",
- scope=SCOPE_SUBTREE, attrs=["dn"])
-
- if (len(res2) == 1):
- messagefunc(SIMPLE, "Remove old dns account")
- secrets_ldb.delete(res2[0]["dn"])
-
-
-def getOEMInfo(samdb, rootdn):
- """Return OEM Information on the top level Samba4 use to store version
- info in this field
-
- :param samdb: An LDB object connect to sam.ldb
- :param rootdn: Root DN of the domain
- :return: The content of the field oEMInformation (if any)
- """
- res = samdb.search(expression="(objectClass=*)", base=str(rootdn),
- scope=SCOPE_BASE, attrs=["dn", "oEMInformation"])
- if len(res) > 0:
- info = res[0]["oEMInformation"]
- return info
- else:
- return ""
-
-
-def updateOEMInfo(samdb, rootdn):
- """Update the OEMinfo field to add information about upgrade
-
- :param samdb: an LDB object connected to the sam DB
- :param rootdn: The string representation of the root DN of
- the provision (ie. DC=...,DC=...)
- """
- res = samdb.search(expression="(objectClass=*)", base=rootdn,
- scope=SCOPE_BASE, attrs=["dn", "oEMInformation"])
- if len(res) > 0:
- info = res[0]["oEMInformation"]
- info = "%s, upgrade to %s" % (info, version)
- delta = ldb.Message()
- delta.dn = ldb.Dn(samdb, str(res[0]["dn"]))
- delta["oEMInformation"] = ldb.MessageElement(info, ldb.FLAG_MOD_REPLACE,
- "oEMInformation" )
- samdb.modify(delta)
-
-def update_gpo(paths, samdb, names, lp, message, force=0):
- """Create missing GPO file object if needed
-
- Set ACL correctly also.
- Check ACLs for sysvol/netlogon dirs also
- """
- resetacls = False
- try:
- ntacls.checkset_backend(lp, None, None)
- eadbname = lp.get("posix:eadb")
- if eadbname is not None and eadbname != "":
- try:
- attribute = samba.xattr_tdb.wrap_getxattr(eadbname,
- paths.sysvol, xattr.XATTR_NTACL_NAME)
- except Exception:
- attribute = samba.xattr_native.wrap_getxattr(paths.sysvol,
- xattr.XATTR_NTACL_NAME)
- else:
- attribute = samba.xattr_native.wrap_getxattr(paths.sysvol,
- xattr.XATTR_NTACL_NAME)
- except Exception:
- resetacls = True
-
- if force:
- resetacls = True
-
- dir = getpolicypath(paths.sysvol, names.dnsdomain, names.policyid)
- if not os.path.isdir(dir):
- create_gpo_struct(dir)
-
- if names.policyid_dc is None:
- raise ProvisioningError("Policy ID for Domain controller is missing")
- dir = getpolicypath(paths.sysvol, names.dnsdomain, names.policyid_dc)
- if not os.path.isdir(dir):
- create_gpo_struct(dir)
- # We always reinforce acls on GPO folder because they have to be in sync
- # with the one in DS
- try:
- set_gpos_acl(paths.sysvol, names.dnsdomain, names.domainsid,
- names.domaindn, samdb, lp)
- except TypeError, e:
- message(ERROR, "Unable to set ACLs on policies related objects,"
- " if not using posix:eadb, you must be root to do it")
-
- if resetacls:
- try:
- setsysvolacl(samdb, paths.netlogon, paths.sysvol, names.wheel_gid,
- names.domainsid, names.dnsdomain, names.domaindn, lp)
- except TypeError, e:
- message(ERROR, "Unable to set ACLs on sysvol share, if not using"
- "posix:eadb, you must be root to do it")
-
-def increment_calculated_keyversion_number(samdb, rootdn, hashDns):
- """For a given hash associating dn and a number, this function will
- update the replPropertyMetaData of each dn in the hash, so that the
- calculated value of the msDs-KeyVersionNumber is equal or superior to the
- one associated to the given dn.
-
- :param samdb: An SamDB object pointing to the sam
- :param rootdn: The base DN where we want to start
- :param hashDns: A hash with dn as key and number representing the
- minimum value of msDs-KeyVersionNumber that we want to
- have
- """
- entry = samdb.search(expression='(objectClass=user)',
- base=ldb.Dn(samdb,str(rootdn)),
- scope=SCOPE_SUBTREE, attrs=["msDs-KeyVersionNumber"],
- controls=["search_options:1:2"])
- done = 0
- hashDone = {}
- if len(entry) == 0:
- raise ProvisioningError("Unable to find msDs-KeyVersionNumber")
- else:
- for e in entry:
- if hashDns.has_key(str(e.dn).lower()):
- val = e.get("msDs-KeyVersionNumber")
- if not val:
- val = "0"
- version = int(str(hashDns[str(e.dn).lower()]))
- if int(str(val)) < version:
- done = done + 1
- samdb.set_attribute_replmetadata_version(str(e.dn),
- "unicodePwd",
- version, True)
-def delta_update_basesamdb(refsampath, sampath, creds, session, lp, message):
- """Update the provision container db: sam.ldb
- This function is aimed for alpha9 and newer;
-
- :param refsampath: Path to the samdb in the reference provision
- :param sampath: Path to the samdb in the upgraded provision
- :param creds: Credential used for openning LDB files
- :param session: Session to use for openning LDB files
- :param lp: A loadparam object
- :return: A msg_diff object with the difference between the @ATTRIBUTES
- of the current provision and the reference provision
- """
-
- message(SIMPLE,
- "Update base samdb by searching difference with reference one")
- refsam = Ldb(refsampath, session_info=session, credentials=creds,
- lp=lp, options=["modules:"])
- sam = Ldb(sampath, session_info=session, credentials=creds, lp=lp,
- options=["modules:"])
-
- empty = ldb.Message()
- deltaattr = None
- reference = refsam.search(expression="")
-
- for refentry in reference:
- entry = sam.search(expression="dn=%s" % refentry["dn"],
- scope=SCOPE_SUBTREE)
- if not len(entry):
- delta = sam.msg_diff(empty, refentry)
- message(CHANGE, "Adding %s to sam db" % str(refentry.dn))
- if str(refentry.dn) == "@PROVISION" and\
- delta.get(samba.provision.LAST_PROVISION_USN_ATTRIBUTE):
- delta.remove(samba.provision.LAST_PROVISION_USN_ATTRIBUTE)
- delta.dn = refentry.dn
- sam.add(delta)
- else:
- delta = sam.msg_diff(entry[0], refentry)
- if str(refentry.dn) == "@ATTRIBUTES":
- deltaattr = sam.msg_diff(refentry, entry[0])
- if str(refentry.dn) == "@PROVISION" and\
- delta.get(samba.provision.LAST_PROVISION_USN_ATTRIBUTE):
- delta.remove(samba.provision.LAST_PROVISION_USN_ATTRIBUTE)
- if len(delta.items()) > 1:
- delta.dn = refentry.dn
- sam.modify(delta)
-
- return deltaattr
-
-
-def construct_existor_expr(attrs):
- """Construct a exists or LDAP search expression.
-
- :param attrs: List of attribute on which we want to create the search
- expression.
- :return: A string representing the expression, if attrs is empty an
- empty string is returned
- """
- expr = ""
- if len(attrs) > 0:
- expr = "(|"
- for att in attrs:
- expr = "%s(%s=*)"%(expr,att)
- expr = "%s)"%expr
- return expr
-
-def update_machine_account_password(samdb, secrets_ldb, names):
- """Update (change) the password of the current DC both in the SAM db and in
- secret one
-
- :param samdb: An LDB object related to the sam.ldb file of a given provision
- :param secrets_ldb: An LDB object related to the secrets.ldb file of a given
- provision
- :param names: List of key provision parameters"""
-
- expression = "samAccountName=%s$" % names.netbiosname
- secrets_msg = secrets_ldb.search(expression=expression,
- attrs=["secureChannelType"])
- if int(secrets_msg[0]["secureChannelType"][0]) == SEC_CHAN_BDC:
- res = samdb.search(expression=expression, attrs=[])
- assert(len(res) == 1)
-
- msg = ldb.Message(res[0].dn)
- machinepass = samba.generate_random_password(128, 255)
- mputf16 = machinepass.encode('utf-16-le')
- msg["clearTextPassword"] = ldb.MessageElement(mputf16,
- ldb.FLAG_MOD_REPLACE,
- "clearTextPassword")
- samdb.modify(msg)
-
- res = samdb.search(expression=("samAccountName=%s$" % names.netbiosname),
- attrs=["msDs-keyVersionNumber"])
- assert(len(res) == 1)
- kvno = int(str(res[0]["msDs-keyVersionNumber"]))
- secChanType = int(secrets_msg[0]["secureChannelType"][0])
-
- secretsdb_self_join(secrets_ldb, domain=names.domain,
- realm=names.realm,
- domainsid=names.domainsid,
- dnsdomain=names.dnsdomain,
- netbiosname=names.netbiosname,
- machinepass=machinepass,
- key_version_number=kvno,
- secure_channel_type=secChanType)
- else:
- raise ProvisioningError("Unable to find a Secure Channel"
- "of type SEC_CHAN_BDC")
-
-def update_dns_account_password(samdb, secrets_ldb, names):
- """Update (change) the password of the dns both in the SAM db and in
- secret one
-
- :param samdb: An LDB object related to the sam.ldb file of a given provision
- :param secrets_ldb: An LDB object related to the secrets.ldb file of a given
- provision
- :param names: List of key provision parameters"""
-
- expression = "samAccountName=dns-%s" % names.netbiosname
- secrets_msg = secrets_ldb.search(expression=expression)
- if len(secrets_msg) == 1:
- res = samdb.search(expression=expression, attrs=[])
- assert(len(res) == 1)
-
- msg = ldb.Message(res[0].dn)
- machinepass = samba.generate_random_password(128, 255)
- mputf16 = machinepass.encode('utf-16-le')
- msg["clearTextPassword"] = ldb.MessageElement(mputf16,
- ldb.FLAG_MOD_REPLACE,
- "clearTextPassword")
-
- samdb.modify(msg)
-
- res = samdb.search(expression=expression,
- attrs=["msDs-keyVersionNumber"])
- assert(len(res) == 1)
- kvno = str(res[0]["msDs-keyVersionNumber"])
-
- msg = ldb.Message(secrets_msg[0].dn)
- msg["secret"] = ldb.MessageElement(machinepass,
- ldb.FLAG_MOD_REPLACE,
- "secret")
- msg["msDS-KeyVersionNumber"] = ldb.MessageElement(kvno,
- ldb.FLAG_MOD_REPLACE,
- "msDS-KeyVersionNumber")
-
- secrets_ldb.modify(msg)
- else:
- raise ProvisioningError("Unable to find an object"
- " with %s" % expression )
-
-def search_constructed_attrs_stored(samdb, rootdn, attrs):
- """Search a given sam DB for calculated attributes that are
- still stored in the db.
-
- :param samdb: An LDB object pointing to the sam
- :param rootdn: The base DN where the search should start
- :param attrs: A list of attributes to be searched
- :return: A hash with attributes as key and an array of
- array. Each array contains the dn and the associated
- values for this attribute as they are stored in the
- sam."""
-
- hashAtt = {}
- expr = construct_existor_expr(attrs)
- if expr == "":
- return hashAtt
- entry = samdb.search(expression=expr, base=ldb.Dn(samdb, str(rootdn)),
- scope=SCOPE_SUBTREE, attrs=attrs,
- controls=["search_options:1:2","bypassoperational:0"])
- if len(entry) == 0:
- # Nothing anymore
- return hashAtt
-
- for ent in entry:
- for att in attrs:
- if ent.get(att):
- if hashAtt.has_key(att):
- hashAtt[att][str(ent.dn).lower()] = str(ent[att])
- else:
- hashAtt[att] = {}
- hashAtt[att][str(ent.dn).lower()] = str(ent[att])
-
- return hashAtt
-
-def int64range2str(value):
- """Display the int64 range stored in value as xxx-yyy
-
- :param value: The int64 range
- :return: A string of the representation of the range
- """
-
- lvalue = long(value)
- str = "%d-%d" % (lvalue&0xFFFFFFFF, lvalue>>32)
- return str
diff --git a/source4/scripting/python/samba/web_server/__init__.py b/source4/scripting/python/samba/web_server/__init__.py
deleted file mode 100644
index da528f42d1..0000000000
--- a/source4/scripting/python/samba/web_server/__init__.py
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-
-# Unix SMB/CIFS implementation.
-# Copyright © Jelmer Vernooij <jelmer@samba.org> 2008
-#
-# Implementation of SWAT that uses WSGI
-#
-# 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/>.
-#
-
-
-
-def render_placeholder(environ, start_response):
- status = '200 OK'
- response_headers = [('Content-type','text/html')]
- start_response(status, response_headers)
-
- yield "<!doctype html>\n"
- yield "<html>\n"
- yield " <title>The Samba web service</title>\n"
- yield "</html>\n"
-
- yield "<body>\n"
- yield "<p>Welcome to this Samba web server.</p>\n"
- yield "<p>This page is a simple placeholder. You probably want to install "
- yield "SWAT. More information can be found "
- yield "<a href='http://wiki.samba.org/index.php/SWAT'>on the wiki</a>.</p>"
- yield "</p>\n"
- yield "</body>\n"
- yield "</html>\n"
-
-
-__call__ = render_placeholder
-
-
-if __name__ == '__main__':
- from wsgiref import simple_server
- httpd = simple_server.make_server('localhost', 8090, __call__)
- print "Serving HTTP on port 8090..."
- httpd.serve_forever()
diff --git a/source4/scripting/python/samba_external/README b/source4/scripting/python/samba_external/README
deleted file mode 100644
index d6a4dec7b1..0000000000
--- a/source4/scripting/python/samba_external/README
+++ /dev/null
@@ -1,4 +0,0 @@
-This directory is for external python libraries that may not be
-installed on the local system. We always should try to use the
-system version of the library if possible, then use the Samba
-supplied copy if the system copy is unavailable
diff --git a/source4/scripting/python/uuidmodule.c b/source4/scripting/python/uuidmodule.c
index 3bfe0162ca..98ef9adaa9 100644
--- a/source4/scripting/python/uuidmodule.c
+++ b/source4/scripting/python/uuidmodule.c
@@ -17,8 +17,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#include <Python.h>
#include "includes.h"
+#include <Python.h>
#include "librpc/ndr/libndr.h"
static PyObject *uuid_random(PyObject *self, PyObject *args)
diff --git a/source4/scripting/python/wscript_build b/source4/scripting/python/wscript_build
deleted file mode 100644
index 540f3b7bb7..0000000000
--- a/source4/scripting/python/wscript_build
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/usr/bin/env python
-
-bld.SAMBA_LIBRARY('samba_python',
- source=[],
- deps='LIBPYTHON pytalloc-util pyrpc_util',
- grouping_library=True,
- private_library=True,
- pyext=True)
-
-bld.SAMBA_SUBSYSTEM('LIBPYTHON',
- source='modules.c',
- public_deps='',
- init_function_sentinal='{NULL,NULL}',
- deps='talloc',
- pyext=True,
- )
-
-
-bld.SAMBA_PYTHON('python_uuid',
- source='uuidmodule.c',
- deps='ndr',
- realname='uuid.so',
- enabled = float(bld.env.PYTHON_VERSION) <= 2.4
- )
-
-
-bld.SAMBA_PYTHON('python_glue',
- source='pyglue.c',
- deps='pyparam_util samba-util netif pytalloc-util',
- realname='samba/_glue.so'
- )
-
-
-# install out various python scripts for use by make test
-bld.SAMBA_SCRIPT('samba_python',
- pattern='samba/**/*.py',
- installdir='python')
-
-bld.INSTALL_WILDCARD('${PYTHONARCHDIR}', 'samba/**/*.py', flat=False)