diff options
Diffstat (limited to 'source4/scripting/python')
-rw-r--r-- | source4/scripting/python/config.m4 | 26 | ||||
-rw-r--r-- | source4/scripting/python/config.mk | 12 | ||||
-rw-r--r-- | source4/scripting/python/misc.i | 37 | ||||
-rw-r--r-- | source4/scripting/python/misc.py | 23 | ||||
-rw-r--r-- | source4/scripting/python/misc_wrap.c | 523 | ||||
-rw-r--r-- | source4/scripting/python/parammodule.c | 181 | ||||
-rw-r--r-- | source4/scripting/python/samba/__init__.py | 161 | ||||
-rw-r--r-- | source4/scripting/python/samba/provision.py | 813 | ||||
-rw-r--r-- | source4/scripting/python/samba/samdb.py | 132 | ||||
-rw-r--r-- | source4/scripting/python/samba/tests/__init__.py | 72 | ||||
-rw-r--r-- | source4/scripting/python/samba/tests/provision.py | 71 | ||||
-rw-r--r-- | source4/scripting/python/samba/tests/upgrade.py | 28 | ||||
-rw-r--r-- | source4/scripting/python/samba/upgrade.py | 553 | ||||
-rw-r--r-- | source4/scripting/python/subunit/__init__.py | 10 |
14 files changed, 2414 insertions, 228 deletions
diff --git a/source4/scripting/python/config.m4 b/source4/scripting/python/config.m4 index 5e982556fc..96e4da9add 100644 --- a/source4/scripting/python/config.m4 +++ b/source4/scripting/python/config.m4 @@ -65,7 +65,7 @@ if test -z "$PYTHON_LDFLAGS"; then py_version=`$PYTHON -c "from distutils.sysconfig import *; \ from string import join; \ print join(get_config_vars('VERSION'))"` - if test "$py_version" == "[None]"; then + if test "$py_version" = "[None]"; then if test -n "$PYTHON_VERSION"; then py_version=$PYTHON_VERSION else @@ -119,9 +119,31 @@ AC_SUBST(PYTHON_EXTRA_LDFLAGS) SMB_EXT_LIB(LIBPYTHON, [$PYTHON_LDFLAGS], [$PYTHON_CPPFLAGS]) + +AC_MSG_CHECKING(working python module support) if test x$working_python = xyes then - SMB_ENABLE(LIBPYTHON,YES) + ac_save_LIBS="$LIBS" + ac_save_CFLAGS="$CFLAGS" + LIBS="$LIBS $PYTHON_LDFLAGS" + CFLAGS="$CFLAGS $PYTHON_CPPFLAGS" + + AC_TRY_LINK([ + #include <Python.h> + #include <stdlib.h> + ],[ + Py_InitModule(NULL, NULL); + ],[ + SMB_ENABLE(LIBPYTHON,YES) + AC_MSG_RESULT([yes]) + ],[ + SMB_ENABLE(LIBPYTHON,NO) + AC_MSG_RESULT([no]) + ]) + + LIBS="$ac_save_LIBS" + CFLAGS="$ac_save_CFLAGS" else SMB_ENABLE(LIBPYTHON,NO) + AC_MSG_RESULT([no]) fi diff --git a/source4/scripting/python/config.mk b/source4/scripting/python/config.mk index 91437e1e0b..d0d3829eef 100644 --- a/source4/scripting/python/config.mk +++ b/source4/scripting/python/config.mk @@ -1,13 +1,9 @@ -[PYTHON::python_param] -PRIVATE_DEPENDENCIES = LIBSAMBA-CONFIG -OBJ_FILES = parammodule.o - [PYTHON::python_uuid] PRIVATE_DEPENDENCIES = LIBNDR OBJ_FILES = uuidmodule.o [PYTHON::python_misc] -PRIVATE_DEPENDENCIES = LIBNDR LIBLDB +PRIVATE_DEPENDENCIES = LIBNDR LIBLDB SAMDB SWIG_FILE = misc.i # Swig extensions @@ -16,7 +12,7 @@ swig: pythonmods .SUFFIXES: _wrap.c .i .i_wrap.c: - [ "$(SWIG)" == "no" ] || $(SWIG) -Wall -I$(srcdir)/scripting/swig -python -keyword $< + [ "$(SWIG)" == "no" ] || $(SWIG) -O -Wall -I$(srcdir)/scripting/swig -python -keyword $< realdistclean:: @echo "Removing SWIG output files" @@ -29,3 +25,7 @@ PYDOCTOR_MODULES=bin/python/ldb.py bin/python/auth.py bin/python/credentials.py pydoctor:: pythonmods LD_LIBRARY_PATH=bin/shared PYTHONPATH=bin/python pydoctor --make-html --docformat=restructuredtext --add-package scripting/python/samba/ $(addprefix --add-module , $(PYDOCTOR_MODULES)) + +clean:: + @echo "Removing python modules" + @rm -f bin/python/* diff --git a/source4/scripting/python/misc.i b/source4/scripting/python/misc.i index 088522320e..3af10dfce9 100644 --- a/source4/scripting/python/misc.i +++ b/source4/scripting/python/misc.i @@ -21,12 +21,47 @@ %{ #include "includes.h" #include "ldb.h" -#include "auth/credentials/credentials.h" +#include "param/param.h" +#include "dsdb/samdb/samdb.h" +#include "lib/ldb-samba/ldif_handlers.h" %} %import "stdint.i" +%include "exception.i" %import "../../lib/talloc/talloc.i" +%import "../../lib/ldb/ldb.i" +%import "../../auth/credentials/credentials.i" +%import "../../param/param.i" +%import "../../libcli/security/security.i" +%import "../../libcli/util/errors.i" %rename(random_password) generate_random_str; char *generate_random_str(TALLOC_CTX *mem_ctx, size_t len); +%inline %{ +void ldb_set_credentials(struct ldb_context *ldb, struct cli_credentials *creds) +{ + ldb_set_opaque(ldb, "credentials", creds); +} + +void ldb_set_session_info(struct ldb_context *ldb, struct auth_session_info *session_info) +{ + ldb_set_opaque(ldb, "sessionInfo", session_info); +} + +void ldb_set_loadparm(struct ldb_context *ldb, struct loadparm_context *lp_ctx) +{ + ldb_set_opaque(ldb, "loadparm", lp_ctx); +} + +%} + +bool samdb_set_domain_sid(struct ldb_context *ldb, + const struct dom_sid *dom_sid_in); + +WERROR dsdb_attach_schema_from_ldif_file(struct ldb_context *ldb, const char *pf, const char *df); + +%rename(version) samba_version_string; +const char *samba_version_string(void); +int dsdb_set_global_schema(struct ldb_context *ldb); +int ldb_register_samba_handlers(struct ldb_context *ldb); diff --git a/source4/scripting/python/misc.py b/source4/scripting/python/misc.py index 94625be2c9..ae900a1f62 100644 --- a/source4/scripting/python/misc.py +++ b/source4/scripting/python/misc.py @@ -2,7 +2,6 @@ # Version 1.3.33 # # Don't modify this file, modify the SWIG interface instead. -# This file is compatible with both classic and new-style classes. import _misc import new @@ -48,6 +47,28 @@ except AttributeError: del types +def _swig_setattr_nondynamic_method(set): + def set_attr(self,name,value): + if (name == "thisown"): return self.this.own(value) + if hasattr(self,name) or (name == "this"): + set(self,name,value) + else: + raise AttributeError("You cannot add attributes to %s" % self) + return set_attr + + +import ldb +import credentials +import param +import security random_password = _misc.random_password +ldb_set_credentials = _misc.ldb_set_credentials +ldb_set_session_info = _misc.ldb_set_session_info +ldb_set_loadparm = _misc.ldb_set_loadparm +samdb_set_domain_sid = _misc.samdb_set_domain_sid +dsdb_attach_schema_from_ldif_file = _misc.dsdb_attach_schema_from_ldif_file +version = _misc.version +dsdb_set_global_schema = _misc.dsdb_set_global_schema +ldb_register_samba_handlers = _misc.ldb_register_samba_handlers diff --git a/source4/scripting/python/misc_wrap.c b/source4/scripting/python/misc_wrap.c index 2237f9cb03..dc1203e2f0 100644 --- a/source4/scripting/python/misc_wrap.c +++ b/source4/scripting/python/misc_wrap.c @@ -9,7 +9,7 @@ * ----------------------------------------------------------------------------- */ #define SWIGPYTHON -#define SWIG_PYTHON_DIRECTOR_NO_VTABLE +#define SWIG_PYTHON_NO_BUILD_NONE /* ----------------------------------------------------------------------------- * This section contains generic SWIG labels for method/variable * declarations/attributes, and other compiler dependent labels. @@ -2454,20 +2454,40 @@ SWIG_Python_MustGetPtr(PyObject *obj, swig_type_info *ty, int argnum, int flags) + #define SWIG_exception(code, msg) do { SWIG_Error(code, msg); SWIG_fail;; } while(0) + + /* -------- TYPES TABLE (BEGIN) -------- */ #define SWIGTYPE_p_TALLOC_CTX swig_types[0] -#define SWIGTYPE_p_char swig_types[1] -#define SWIGTYPE_p_int swig_types[2] -#define SWIGTYPE_p_long_long swig_types[3] -#define SWIGTYPE_p_short swig_types[4] -#define SWIGTYPE_p_signed_char swig_types[5] -#define SWIGTYPE_p_unsigned_char swig_types[6] -#define SWIGTYPE_p_unsigned_int swig_types[7] -#define SWIGTYPE_p_unsigned_long_long swig_types[8] -#define SWIGTYPE_p_unsigned_short swig_types[9] -static swig_type_info *swig_types[11]; -static swig_module_info swig_module = {swig_types, 10, 0, 0, 0, 0}; +#define SWIGTYPE_p_auth_session_info swig_types[1] +#define SWIGTYPE_p_char swig_types[2] +#define SWIGTYPE_p_cli_credentials swig_types[3] +#define SWIGTYPE_p_dom_sid swig_types[4] +#define SWIGTYPE_p_int swig_types[5] +#define SWIGTYPE_p_ldb_context swig_types[6] +#define SWIGTYPE_p_ldb_dn swig_types[7] +#define SWIGTYPE_p_ldb_ldif swig_types[8] +#define SWIGTYPE_p_ldb_message swig_types[9] +#define SWIGTYPE_p_ldb_message_element swig_types[10] +#define SWIGTYPE_p_ldb_result swig_types[11] +#define SWIGTYPE_p_loadparm_context swig_types[12] +#define SWIGTYPE_p_loadparm_service swig_types[13] +#define SWIGTYPE_p_long_long swig_types[14] +#define SWIGTYPE_p_param_context swig_types[15] +#define SWIGTYPE_p_param_opt swig_types[16] +#define SWIGTYPE_p_param_section swig_types[17] +#define SWIGTYPE_p_security_descriptor swig_types[18] +#define SWIGTYPE_p_security_token swig_types[19] +#define SWIGTYPE_p_short swig_types[20] +#define SWIGTYPE_p_signed_char swig_types[21] +#define SWIGTYPE_p_unsigned_char swig_types[22] +#define SWIGTYPE_p_unsigned_int swig_types[23] +#define SWIGTYPE_p_unsigned_long swig_types[24] +#define SWIGTYPE_p_unsigned_long_long swig_types[25] +#define SWIGTYPE_p_unsigned_short swig_types[26] +static swig_type_info *swig_types[28]; +static swig_module_info swig_module = {swig_types, 27, 0, 0, 0, 0}; #define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name) #define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name) @@ -2478,6 +2498,19 @@ static swig_module_info swig_module = {swig_types, 10, 0, 0, 0, 0}; # error "This python version requires swig to be run with the '-classic' option" # endif #endif +#if (PY_VERSION_HEX <= 0x02020000) +# error "This python version requires swig to be run with the '-nomodern' option" +#endif +#if (PY_VERSION_HEX <= 0x02020000) +# error "This python version requires swig to be run with the '-nomodernargs' option" +#endif +#ifndef METH_O +# error "This python version requires swig to be run with the '-nofastunpack' option" +#endif +#ifdef SWIG_TypeQuery +# undef SWIG_TypeQuery +#endif +#define SWIG_TypeQuery SWIG_Python_TypeQuery /*----------------------------------------------- @(target):= _misc.so @@ -2496,7 +2529,9 @@ static swig_module_info swig_module = {swig_types, 10, 0, 0, 0, 0}; #include "includes.h" #include "ldb.h" -#include "auth/credentials/credentials.h" +#include "param/param.h" +#include "dsdb/samdb/samdb.h" +#include "lib/ldb-samba/ldif_handlers.h" SWIGINTERN int @@ -2669,6 +2704,95 @@ SWIG_FromCharPtr(const char *cptr) return SWIG_FromCharPtrAndSize(cptr, (cptr ? strlen(cptr) : 0)); } + +void ldb_set_credentials(struct ldb_context *ldb, struct cli_credentials *creds) +{ + ldb_set_opaque(ldb, "credentials", creds); +} + +void ldb_set_session_info(struct ldb_context *ldb, struct auth_session_info *session_info) +{ + ldb_set_opaque(ldb, "sessionInfo", session_info); +} + +void ldb_set_loadparm(struct ldb_context *ldb, struct loadparm_context *lp_ctx) +{ + ldb_set_opaque(ldb, "loadparm", lp_ctx); +} + + + +SWIGINTERNINLINE PyObject* + SWIG_From_bool (bool value) +{ + return PyBool_FromLong(value ? 1 : 0); +} + + +SWIGINTERN int +SWIG_AsCharPtrAndSize(PyObject *obj, char** cptr, size_t* psize, int *alloc) +{ + if (PyString_Check(obj)) { + char *cstr; Py_ssize_t len; + PyString_AsStringAndSize(obj, &cstr, &len); + if (cptr) { + if (alloc) { + /* + In python the user should not be able to modify the inner + string representation. To warranty that, if you define + SWIG_PYTHON_SAFE_CSTRINGS, a new/copy of the python string + buffer is always returned. + + The default behavior is just to return the pointer value, + so, be careful. + */ +#if defined(SWIG_PYTHON_SAFE_CSTRINGS) + if (*alloc != SWIG_OLDOBJ) +#else + if (*alloc == SWIG_NEWOBJ) +#endif + { + *cptr = (char *)memcpy((char *)malloc((len + 1)*sizeof(char)), cstr, sizeof(char)*(len + 1)); + *alloc = SWIG_NEWOBJ; + } + else { + *cptr = cstr; + *alloc = SWIG_OLDOBJ; + } + } else { + *cptr = PyString_AsString(obj); + } + } + if (psize) *psize = len + 1; + return SWIG_OK; + } else { + swig_type_info* pchar_descriptor = SWIG_pchar_descriptor(); + if (pchar_descriptor) { + void* vptr = 0; + if (SWIG_ConvertPtr(obj, &vptr, pchar_descriptor, 0) == SWIG_OK) { + if (cptr) *cptr = (char *) vptr; + if (psize) *psize = vptr ? (strlen((char *)vptr) + 1) : 0; + if (alloc) *alloc = SWIG_OLDOBJ; + return SWIG_OK; + } + } + } + return SWIG_TypeError; +} + + + + + + #define SWIG_From_long PyInt_FromLong + + +SWIGINTERNINLINE PyObject * +SWIG_From_int (int value) +{ + return SWIG_From_long (value); +} + #ifdef __cplusplus extern "C" { #endif @@ -2701,8 +2825,313 @@ fail: } +SWIGINTERN PyObject *_wrap_ldb_set_credentials(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + struct ldb_context *arg1 = (struct ldb_context *) 0 ; + struct cli_credentials *arg2 = (struct cli_credentials *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "ldb",(char *) "creds", NULL + }; + + { + arg2 = NULL; + } + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:ldb_set_credentials",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ldb_set_credentials" "', argument " "1"" of type '" "struct ldb_context *""'"); + } + arg1 = (struct ldb_context *)(argp1); + if (obj1) { + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_cli_credentials, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ldb_set_credentials" "', argument " "2"" of type '" "struct cli_credentials *""'"); + } + arg2 = (struct cli_credentials *)(argp2); + } + { + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + } + ldb_set_credentials(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ldb_set_session_info(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + struct ldb_context *arg1 = (struct ldb_context *) 0 ; + struct auth_session_info *arg2 = (struct auth_session_info *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "ldb",(char *) "session_info", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:ldb_set_session_info",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ldb_set_session_info" "', argument " "1"" of type '" "struct ldb_context *""'"); + } + arg1 = (struct ldb_context *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_auth_session_info, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ldb_set_session_info" "', argument " "2"" of type '" "struct auth_session_info *""'"); + } + arg2 = (struct auth_session_info *)(argp2); + { + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + } + ldb_set_session_info(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ldb_set_loadparm(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + struct ldb_context *arg1 = (struct ldb_context *) 0 ; + struct loadparm_context *arg2 = (struct loadparm_context *) 0 ; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "ldb",(char *) "lp_ctx", NULL + }; + + { + arg2 = loadparm_init(NULL); + } + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O|O:ldb_set_loadparm",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ldb_set_loadparm" "', argument " "1"" of type '" "struct ldb_context *""'"); + } + arg1 = (struct ldb_context *)(argp1); + if (obj1) { + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_loadparm_context, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "ldb_set_loadparm" "', argument " "2"" of type '" "struct loadparm_context *""'"); + } + arg2 = (struct loadparm_context *)(argp2); + } + { + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + } + ldb_set_loadparm(arg1,arg2); + resultobj = SWIG_Py_Void(); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_samdb_set_domain_sid(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + struct ldb_context *arg1 = (struct ldb_context *) 0 ; + struct dom_sid *arg2 = (struct dom_sid *) 0 ; + bool result; + void *argp1 = 0 ; + int res1 = 0 ; + void *argp2 = 0 ; + int res2 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + char * kwnames[] = { + (char *) "ldb",(char *) "dom_sid_in", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OO:samdb_set_domain_sid",kwnames,&obj0,&obj1)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "samdb_set_domain_sid" "', argument " "1"" of type '" "struct ldb_context *""'"); + } + arg1 = (struct ldb_context *)(argp1); + res2 = SWIG_ConvertPtr(obj1, &argp2,SWIGTYPE_p_dom_sid, 0 | 0 ); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "samdb_set_domain_sid" "', argument " "2"" of type '" "struct dom_sid const *""'"); + } + arg2 = (struct dom_sid *)(argp2); + { + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + } + result = (bool)samdb_set_domain_sid(arg1,(struct dom_sid const *)arg2); + resultobj = SWIG_From_bool((bool)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsdb_attach_schema_from_ldif_file(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + struct ldb_context *arg1 = (struct ldb_context *) 0 ; + char *arg2 = (char *) 0 ; + char *arg3 = (char *) 0 ; + WERROR result; + void *argp1 = 0 ; + int res1 = 0 ; + int res2 ; + char *buf2 = 0 ; + int alloc2 = 0 ; + int res3 ; + char *buf3 = 0 ; + int alloc3 = 0 ; + PyObject * obj0 = 0 ; + PyObject * obj1 = 0 ; + PyObject * obj2 = 0 ; + char * kwnames[] = { + (char *) "ldb",(char *) "pf",(char *) "df", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"OOO:dsdb_attach_schema_from_ldif_file",kwnames,&obj0,&obj1,&obj2)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsdb_attach_schema_from_ldif_file" "', argument " "1"" of type '" "struct ldb_context *""'"); + } + arg1 = (struct ldb_context *)(argp1); + res2 = SWIG_AsCharPtrAndSize(obj1, &buf2, NULL, &alloc2); + if (!SWIG_IsOK(res2)) { + SWIG_exception_fail(SWIG_ArgError(res2), "in method '" "dsdb_attach_schema_from_ldif_file" "', argument " "2"" of type '" "char const *""'"); + } + arg2 = (char *)(buf2); + res3 = SWIG_AsCharPtrAndSize(obj2, &buf3, NULL, &alloc3); + if (!SWIG_IsOK(res3)) { + SWIG_exception_fail(SWIG_ArgError(res3), "in method '" "dsdb_attach_schema_from_ldif_file" "', argument " "3"" of type '" "char const *""'"); + } + arg3 = (char *)(buf3); + { + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + } + result = dsdb_attach_schema_from_ldif_file(arg1,(char const *)arg2,(char const *)arg3); + { + if (!W_ERROR_IS_OK(result)) { + PyObject *obj = Py_BuildValue("(i,s)", (&result)->v, win_errstr(result)); + PyErr_SetObject(PyExc_RuntimeError, obj); + } else if (resultobj == NULL) { + resultobj = Py_None; + } + } + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return resultobj; +fail: + if (alloc2 == SWIG_NEWOBJ) free((char*)buf2); + if (alloc3 == SWIG_NEWOBJ) free((char*)buf3); + return NULL; +} + + +SWIGINTERN PyObject *_wrap_version(PyObject *SWIGUNUSEDPARM(self), PyObject *args) { + PyObject *resultobj = 0; + char *result = 0 ; + + if (!SWIG_Python_UnpackTuple(args,"version",0,0,0)) SWIG_fail; + result = (char *)samba_version_string(); + resultobj = SWIG_FromCharPtr((const char *)result); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_dsdb_set_global_schema(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + struct ldb_context *arg1 = (struct ldb_context *) 0 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + char * kwnames[] = { + (char *) "ldb", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:dsdb_set_global_schema",kwnames,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "dsdb_set_global_schema" "', argument " "1"" of type '" "struct ldb_context *""'"); + } + arg1 = (struct ldb_context *)(argp1); + { + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + } + result = (int)dsdb_set_global_schema(arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + +SWIGINTERN PyObject *_wrap_ldb_register_samba_handlers(PyObject *SWIGUNUSEDPARM(self), PyObject *args, PyObject *kwargs) { + PyObject *resultobj = 0; + struct ldb_context *arg1 = (struct ldb_context *) 0 ; + int result; + void *argp1 = 0 ; + int res1 = 0 ; + PyObject * obj0 = 0 ; + char * kwnames[] = { + (char *) "ldb", NULL + }; + + if (!PyArg_ParseTupleAndKeywords(args,kwargs,(char *)"O:ldb_register_samba_handlers",kwnames,&obj0)) SWIG_fail; + res1 = SWIG_ConvertPtr(obj0, &argp1,SWIGTYPE_p_ldb_context, 0 | 0 ); + if (!SWIG_IsOK(res1)) { + SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ldb_register_samba_handlers" "', argument " "1"" of type '" "struct ldb_context *""'"); + } + arg1 = (struct ldb_context *)(argp1); + { + if (arg1 == NULL) + SWIG_exception(SWIG_ValueError, + "ldb context must be non-NULL"); + } + result = (int)ldb_register_samba_handlers(arg1); + resultobj = SWIG_From_int((int)(result)); + return resultobj; +fail: + return NULL; +} + + static PyMethodDef SwigMethods[] = { { (char *)"random_password", (PyCFunction) _wrap_random_password, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"ldb_set_credentials", (PyCFunction) _wrap_ldb_set_credentials, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"ldb_set_session_info", (PyCFunction) _wrap_ldb_set_session_info, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"ldb_set_loadparm", (PyCFunction) _wrap_ldb_set_loadparm, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"samdb_set_domain_sid", (PyCFunction) _wrap_samdb_set_domain_sid, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"dsdb_attach_schema_from_ldif_file", (PyCFunction) _wrap_dsdb_attach_schema_from_ldif_file, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"version", (PyCFunction)_wrap_version, METH_NOARGS, NULL}, + { (char *)"dsdb_set_global_schema", (PyCFunction) _wrap_dsdb_set_global_schema, METH_VARARGS | METH_KEYWORDS, NULL}, + { (char *)"ldb_register_samba_handlers", (PyCFunction) _wrap_ldb_register_samba_handlers, METH_VARARGS | METH_KEYWORDS, NULL}, { NULL, NULL, 0, NULL } }; @@ -2710,49 +3139,117 @@ static PyMethodDef SwigMethods[] = { /* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */ static swig_type_info _swigt__p_TALLOC_CTX = {"_p_TALLOC_CTX", "TALLOC_CTX *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_auth_session_info = {"_p_auth_session_info", "struct auth_session_info *", 0, 0, (void*)0, 0}; static swig_type_info _swigt__p_char = {"_p_char", "char *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_cli_credentials = {"_p_cli_credentials", "struct cli_credentials *|cli_credentials *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_dom_sid = {"_p_dom_sid", "struct dom_sid *|dom_sid *", 0, 0, (void*)0, 0}; static swig_type_info _swigt__p_int = {"_p_int", "intptr_t *|int *|int_least32_t *|int_fast32_t *|int32_t *|int_fast16_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ldb_context = {"_p_ldb_context", "struct ldb_context *|ldb *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ldb_dn = {"_p_ldb_dn", "struct ldb_dn *|ldb_dn *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ldb_ldif = {"_p_ldb_ldif", "struct ldb_ldif *|ldb_ldif *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ldb_message = {"_p_ldb_message", "ldb_msg *|struct ldb_message *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ldb_message_element = {"_p_ldb_message_element", "struct ldb_message_element *|ldb_msg_element *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_ldb_result = {"_p_ldb_result", "struct ldb_result *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_loadparm_context = {"_p_loadparm_context", "struct loadparm_context *|loadparm_context *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_loadparm_service = {"_p_loadparm_service", "struct loadparm_service *|loadparm_service *", 0, 0, (void*)0, 0}; static swig_type_info _swigt__p_long_long = {"_p_long_long", "int_least64_t *|int_fast64_t *|int64_t *|long long *|intmax_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_param_context = {"_p_param_context", "struct param_context *|param *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_param_opt = {"_p_param_opt", "struct param_opt *|param_opt *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_param_section = {"_p_param_section", "struct param_section *|param_section *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_security_descriptor = {"_p_security_descriptor", "struct security_descriptor *|security_descriptor *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_security_token = {"_p_security_token", "struct security_token *|security_token *", 0, 0, (void*)0, 0}; static swig_type_info _swigt__p_short = {"_p_short", "short *|int_least16_t *|int16_t *", 0, 0, (void*)0, 0}; static swig_type_info _swigt__p_signed_char = {"_p_signed_char", "signed char *|int_least8_t *|int_fast8_t *|int8_t *", 0, 0, (void*)0, 0}; static swig_type_info _swigt__p_unsigned_char = {"_p_unsigned_char", "unsigned char *|uint_least8_t *|uint_fast8_t *|uint8_t *", 0, 0, (void*)0, 0}; static swig_type_info _swigt__p_unsigned_int = {"_p_unsigned_int", "uintptr_t *|uint_least32_t *|uint_fast32_t *|uint32_t *|unsigned int *|uint_fast16_t *", 0, 0, (void*)0, 0}; +static swig_type_info _swigt__p_unsigned_long = {"_p_unsigned_long", "unsigned long *|time_t *", 0, 0, (void*)0, 0}; static swig_type_info _swigt__p_unsigned_long_long = {"_p_unsigned_long_long", "uint_least64_t *|uint_fast64_t *|uint64_t *|unsigned long long *|uintmax_t *", 0, 0, (void*)0, 0}; static swig_type_info _swigt__p_unsigned_short = {"_p_unsigned_short", "unsigned short *|uint_least16_t *|uint16_t *", 0, 0, (void*)0, 0}; static swig_type_info *swig_type_initial[] = { &_swigt__p_TALLOC_CTX, + &_swigt__p_auth_session_info, &_swigt__p_char, + &_swigt__p_cli_credentials, + &_swigt__p_dom_sid, &_swigt__p_int, + &_swigt__p_ldb_context, + &_swigt__p_ldb_dn, + &_swigt__p_ldb_ldif, + &_swigt__p_ldb_message, + &_swigt__p_ldb_message_element, + &_swigt__p_ldb_result, + &_swigt__p_loadparm_context, + &_swigt__p_loadparm_service, &_swigt__p_long_long, + &_swigt__p_param_context, + &_swigt__p_param_opt, + &_swigt__p_param_section, + &_swigt__p_security_descriptor, + &_swigt__p_security_token, &_swigt__p_short, &_swigt__p_signed_char, &_swigt__p_unsigned_char, &_swigt__p_unsigned_int, + &_swigt__p_unsigned_long, &_swigt__p_unsigned_long_long, &_swigt__p_unsigned_short, }; static swig_cast_info _swigc__p_TALLOC_CTX[] = { {&_swigt__p_TALLOC_CTX, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_auth_session_info[] = { {&_swigt__p_auth_session_info, 0, 0, 0},{0, 0, 0, 0}}; static swig_cast_info _swigc__p_char[] = { {&_swigt__p_char, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_cli_credentials[] = { {&_swigt__p_cli_credentials, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_dom_sid[] = { {&_swigt__p_dom_sid, 0, 0, 0},{0, 0, 0, 0}}; static swig_cast_info _swigc__p_int[] = { {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ldb_context[] = { {&_swigt__p_ldb_context, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ldb_dn[] = { {&_swigt__p_ldb_dn, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ldb_ldif[] = { {&_swigt__p_ldb_ldif, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ldb_message[] = { {&_swigt__p_ldb_message, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ldb_message_element[] = { {&_swigt__p_ldb_message_element, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_ldb_result[] = { {&_swigt__p_ldb_result, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_loadparm_context[] = { {&_swigt__p_loadparm_context, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_loadparm_service[] = { {&_swigt__p_loadparm_service, 0, 0, 0},{0, 0, 0, 0}}; static swig_cast_info _swigc__p_long_long[] = { {&_swigt__p_long_long, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_param_context[] = { {&_swigt__p_param_context, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_param_opt[] = { {&_swigt__p_param_opt, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_param_section[] = { {&_swigt__p_param_section, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_security_descriptor[] = { {&_swigt__p_security_descriptor, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_security_token[] = { {&_swigt__p_security_token, 0, 0, 0},{0, 0, 0, 0}}; static swig_cast_info _swigc__p_short[] = { {&_swigt__p_short, 0, 0, 0},{0, 0, 0, 0}}; static swig_cast_info _swigc__p_signed_char[] = { {&_swigt__p_signed_char, 0, 0, 0},{0, 0, 0, 0}}; static swig_cast_info _swigc__p_unsigned_char[] = { {&_swigt__p_unsigned_char, 0, 0, 0},{0, 0, 0, 0}}; static swig_cast_info _swigc__p_unsigned_int[] = { {&_swigt__p_unsigned_int, 0, 0, 0},{0, 0, 0, 0}}; +static swig_cast_info _swigc__p_unsigned_long[] = { {&_swigt__p_unsigned_long, 0, 0, 0},{0, 0, 0, 0}}; static swig_cast_info _swigc__p_unsigned_long_long[] = { {&_swigt__p_unsigned_long_long, 0, 0, 0},{0, 0, 0, 0}}; static swig_cast_info _swigc__p_unsigned_short[] = { {&_swigt__p_unsigned_short, 0, 0, 0},{0, 0, 0, 0}}; static swig_cast_info *swig_cast_initial[] = { _swigc__p_TALLOC_CTX, + _swigc__p_auth_session_info, _swigc__p_char, + _swigc__p_cli_credentials, + _swigc__p_dom_sid, _swigc__p_int, + _swigc__p_ldb_context, + _swigc__p_ldb_dn, + _swigc__p_ldb_ldif, + _swigc__p_ldb_message, + _swigc__p_ldb_message_element, + _swigc__p_ldb_result, + _swigc__p_loadparm_context, + _swigc__p_loadparm_service, _swigc__p_long_long, + _swigc__p_param_context, + _swigc__p_param_opt, + _swigc__p_param_section, + _swigc__p_security_descriptor, + _swigc__p_security_token, _swigc__p_short, _swigc__p_signed_char, _swigc__p_unsigned_char, _swigc__p_unsigned_int, + _swigc__p_unsigned_long, _swigc__p_unsigned_long_long, _swigc__p_unsigned_short, }; diff --git a/source4/scripting/python/parammodule.c b/source4/scripting/python/parammodule.c deleted file mode 100644 index bb7adab240..0000000000 --- a/source4/scripting/python/parammodule.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - Unix SMB/CIFS implementation. - - Python wrapper for reading smb.conf files - - Copyright (C) Jelmer Vernooij 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 2 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, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" -#include "Python.h" -#include "param/param.h" - -staticforward PyTypeObject param_ParamFileType; - -typedef struct { - PyObject_HEAD - struct param_context *param_ctx; -} param_ParamFileObject; - -static param_ParamFileObject *py_param_init(void) -{ - param_ParamFileObject *param; - - param = PyObject_New(param_ParamFileObject, ¶m_ParamFileType); - - param->param_ctx = param_init(NULL); - - return param; -} - -static PyObject *py_param_load(PyObject *self, PyObject *args) -{ - char *filename = NULL; - param_ParamFileObject *param; - - if (!PyArg_ParseTuple(args, "|s:new", &filename)) - return NULL; - - param = py_param_init(); - - if (filename != NULL) { - int ret = param_read(param->param_ctx, filename); - - if (ret == -1) { - PyErr_SetString(PyExc_TypeError, "reading file failed"); - return NULL; - } - } - - return (PyObject *)param; -} - -static void -param_dealloc(PyObject* self) -{ - PyObject_Del(self); -} - -static PyObject *py_param_get(PyObject *_self, PyObject *args) -{ - struct param_opt *param; - const char *section_name = NULL, *param_name = NULL; - param_ParamFileObject *self = (param_ParamFileObject *)_self; - - if (!PyArg_ParseTuple(args, (char *)"s|s", ¶m_name, §ion_name)) - return NULL; - - param = param_get(self->param_ctx, section_name, param_name); - if (param == NULL) - return Py_None; - - return PyString_FromString(param->value); -} - -static PyObject *py_param_set(PyObject *_self, PyObject *args) -{ - param_ParamFileObject *self = (param_ParamFileObject *)_self; - const char *section_name = NULL, *param_name = NULL, *param_value = NULL; - - if (!PyArg_ParseTuple(args, "ss|s", ¶m_name, ¶m_value, §ion_name)) - return NULL; - - if (section_name == NULL) - section_name = GLOBAL_NAME; - - if (param_set_string(self->param_ctx, section_name, param_name, param_value) != 0) { - PyErr_SetString(PyExc_TypeError, "setting variable failed"); - return NULL; - } - - return Py_None; -} - -static PyObject *py_param_save(PyObject *_self, PyObject *args) -{ - param_ParamFileObject *self = (param_ParamFileObject *)_self; - const char *filename = NULL; - - if (!PyArg_ParseTuple(args, "s", &filename)) - return NULL; - - if (param_write(self->param_ctx, filename) != 0) { - PyErr_SetString(PyExc_TypeError, "unable to save"); - return NULL; - } - - return Py_None; -} - -static PyObject *py_param_use(PyObject *_self, PyObject *args) -{ - param_ParamFileObject *self = (param_ParamFileObject *)_self; - - if (!PyArg_ParseTuple(args, "")) - return NULL; - - if (param_use(global_loadparm, self->param_ctx) != 0) { - PyErr_SetString(PyExc_TypeError, "unable to use"); - return NULL; - } - - return Py_None; -} - -static PyMethodDef param_methods[] = { - {"get", (PyCFunction)py_param_get, METH_VARARGS, - "Get a parameter."}, - {"set", (PyCFunction)py_param_set, METH_VARARGS, - "Set a parameter."}, - {"save", (PyCFunction)py_param_save, METH_VARARGS, - "Save file" }, - {"use", (PyCFunction)py_param_use, METH_VARARGS, - "Use param file" }, - {NULL, NULL, 0, NULL} -}; - -static PyObject * -param_getattr(PyTypeObject *obj, char *name) -{ - return Py_FindMethod(param_methods, (PyObject *)obj, name); -} - -static PyTypeObject param_ParamFileType = { - PyObject_HEAD_INIT(NULL) 0, - .tp_name = "ParamFile", - .tp_basicsize = sizeof(param_ParamFileObject), - .tp_dealloc = param_dealloc, - .tp_getattr = param_getattr, -}; - - -static PyMethodDef methods[] = { - { "ParamFile", (PyCFunction)py_param_load, METH_VARARGS, NULL}, - { NULL, NULL } -}; - -PyDoc_STRVAR(param_doc, "Simple wrappers around the smb.conf parsers"); - -PyMODINIT_FUNC initparam(void) -{ - PyObject *mod = Py_InitModule3("param", methods, param_doc); - if (mod == NULL) - return; - - PyModule_AddObject(mod, "configfile", - PyString_FromString(lp_configfile(global_loadparm))); -} diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 46d8ff7d37..2c46f72883 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -19,27 +19,140 @@ # import os -from misc import ldb_set_credentials -def Ldb(url, session_info=None, credentials=None, modules_dir=None): - """Open a Samba Ldb file. +def _in_source_tree(): + """Check whether the script is being run from the source dir. """ + return os.path.exists("%s/../../../samba4-skip" % os.path.dirname(__file__)) - 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 - can be passed through (required by some modules). + +# 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 + + +import ldb +import credentials +import misc + +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 + functions see samdb.py. """ - import ldb - ret = ldb.Ldb() - if modules_dir is None: - modules_dir = os.path.join(os.getcwd(), "bin", "modules", "ldb") - ret.set_modules_dir(modules_dir) - def samba_debug(level,text): - print "%d %s" % (level, text) - ldb_set_opaque("credentials", credentials) - ret.set_opaque("sessionInfo", session_info) - #ret.set_debug(samba_debug) - ret.connect(url) - return ret + def __init__(self, url=None, session_info=None, credentials=None, + modules_dir=None, lp=None): + """Open a Samba Ldb file. + + :param url: Optional LDB URL to open + :param session_info: Optional session information + :param credentials: Optional credentials, defaults to anonymous. + :param modules_dir: Modules directory, if not the default. + :param lp: Loadparm object, 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 + can be passed through (required by some modules). + """ + super(Ldb, self).__init__() + + 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) + + if credentials is not None: + self.set_credentials(self, credentials) + + if session_info is not None: + self.set_session_info(self, session_info) + + if lp is not None: + self.set_loadparm(self, lp) + + def msg(l,text): + print text + #self.set_debug(msg) + + if url is not None: + self.connect(url) + + + set_credentials = misc.ldb_set_credentials + set_session_info = misc.ldb_set_session_info + set_loadparm = misc.ldb_set_loadparm + + def searchone(self, basedn, attribute, expression=None, + scope=ldb.SCOPE_BASE): + """Search for one attribute as a string.""" + res = self.search(basedn, scope, expression, [attribute]) + if len(res) != 1 or res[0][attribute] is None: + return None + values = set(res[0][attribute]) + assert len(values) == 1 + return values.pop() + + def erase(self): + """Erase an ldb, removing all records.""" + # delete the specials + for attr in ["@INDEXLIST", "@ATTRIBUTES", "@SUBCLASSES", "@MODULES", + "@OPTIONS", "@PARTITION", "@KLUDGEACL"]: + try: + self.delete(ldb.Dn(self, attr)) + except ldb.LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): + # Ignore missing dn errors + pass + + basedn = ldb.Dn(self, "") + # and the rest + for msg in self.search(basedn, ldb.SCOPE_SUBTREE, + "(&(|(objectclass=*)(dn=*))(!(dn=@BASEINFO)))", + ["dn"]): + try: + self.delete(msg.dn) + except ldb.LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): + # Ignor eno such object errors + pass + + res = self.search(basedn, ldb.SCOPE_SUBTREE, "(&(|(objectclass=*)(dn=*))(!(dn=@BASEINFO)))", ["dn"]) + assert len(res) == 0 + + def erase_partitions(self): + """Erase an ldb, removing all records.""" + res = self.search(ldb.Dn(self, ""), ldb.SCOPE_BASE, "(objectClass=*)", + ["namingContexts"]) + assert len(res) == 1 + if not "namingContexts" in res[0]: + return + for basedn in res[0]["namingContexts"]: + previous_remaining = 1 + current_remaining = 0 + + k = 0 + while ++k < 10 and (previous_remaining != current_remaining): + # and the rest + res2 = self.search(ldb.Dn(self, basedn), ldb.SCOPE_SUBTREE, "(|(objectclass=*)(dn=*))", ["dn"]) + previous_remaining = current_remaining + current_remaining = len(res2) + for msg in res2: + self.delete(msg.dn) + + def load_ldif_file_add(self, ldif_path): + """Load a LDIF file. + + :param ldif_path: Path to LDIF file. + """ + self.load_ldif_add(open(ldif_path, 'r').read()) + + def load_ldif_add(self, ldif): + for changetype, msg in self.parse_ldif(ldif): + assert changetype == ldb.CHANGETYPE_NONE + self.add(msg) def substitute_var(text, values): @@ -51,7 +164,19 @@ def substitute_var(text, values): """ for (name, value) in values.items(): + assert isinstance(name, str), "%r is not a string" % name + assert isinstance(value, str), "Value %r for %s is not a string" % (value, name) text = text.replace("${%s}" % name, value) return text + +def valid_netbios_name(name): + """Check whether a name is valid as a NetBIOS name. """ + # FIXME: There are probably more constraints here. + # crh has a paragraph on this in his book (1.4.1.1) + if len(name) > 13: + return False + return True + +version = misc.version diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py new file mode 100644 index 0000000000..90f7cd0697 --- /dev/null +++ b/source4/scripting/python/samba/provision.py @@ -0,0 +1,813 @@ +# +# backend code for provisioning a Samba4 server +# Released under the GNU GPL v2 or later +# Copyright Jelmer Vernooij 2007 +# +# Based on the original in EJS: +# Copyright Andrew Tridgell 2005 +# + +from base64 import b64encode +import os +import pwd +import grp +import time +import uuid, misc +from socket import gethostname, gethostbyname +import param +import registry +import samba +from samba import Ldb, substitute_var, valid_netbios_name +from samba.samdb import SamDB +import security +from ldb import Dn, SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \ + LDB_ERR_NO_SUCH_OBJECT, timestring, CHANGETYPE_MODIFY, CHANGETYPE_NONE + + +DEFAULTSITE = "Default-First-Site-Name" + +class InvalidNetbiosName(Exception): + def __init__(self, name): + super(InvalidNetbiosName, self).__init__("The name '%r' is not a valid NetBIOS name" % name) + + +class ProvisionPaths: + def __init__(self): + self.smbconf = None + 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.secrets = None + self.keytab = None + self.dns_keytab = None + self.dns = None + self.winsdb = None + self.ldap_basedn_ldif = None + self.ldap_config_basedn_ldif = None + self.ldap_schema_basedn_ldif = None + + +def install_ok(lp, session_info, credentials): + """Check whether the current install seems ok.""" + if lp.get("realm") == "": + return False + ldb = Ldb(lp.get("sam database"), session_info=session_info, + credentials=credentials, lp=lp) + if len(ldb.search(ldb.Dn("(cn=Administrator)"))) != 1: + return False + return True + + +def findnss(nssfn, *names): + """Find a user or group from a list of possibilities.""" + for name in names: + try: + return nssfn(name) + except KeyError: + pass + raise Exception("Unable to find user/group for %s" % arguments[1]) + + +def open_ldb(session_info, credentials, lp, dbname): + assert session_info is not None + try: + return Ldb(dbname, session_info=session_info, credentials=credentials, + lp=lp) + except LdbError, e: + print e + os.unlink(dbname) + return Ldb(dbname, session_info=session_info, credentials=credentials, + lp=lp) + + +def setup_add_ldif(ldb, ldif_path, subst_vars=None): + """Setup a ldb in the private dir.""" + assert isinstance(ldif_path, str) + + data = open(ldif_path, 'r').read() + if subst_vars is not None: + data = substitute_var(data, subst_vars) + + assert "${" not in data + + ldb.load_ldif_add(data) + + +def setup_modify_ldif(ldb, ldif_path, substvars=None): + """Modify a ldb in the private dir. + + :param ldb: LDB object. + :param ldif_path: LDIF file path. + :param substvars: Optional dictionary with substitution variables. + """ + data = open(ldif_path, 'r').read() + if substvars is not None: + data = substitute_var(data, substvars) + + assert "${" not in data + + for (changetype, msg) in ldb.parse_ldif(data): + assert changetype == CHANGETYPE_MODIFY + ldb.modify(msg) + + +def setup_ldb(ldb, ldif_path, subst_vars): + 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, substvars): + """Setup a file in the private dir.""" + f = fname + + if os.path.exists(f): + os.unlink(f) + + data = open(template, 'r').read() + if substvars: + data = substitute_var(data, substvars) + assert not "${" in data + + open(f, 'w').write(data) + + +def provision_default_paths(lp, dnsdomain): + """Set the default paths for provisioning. + + :param lp: Loadparm context. + :param dnsdomain: DNS Domain name + """ + paths = ProvisionPaths() + private_dir = lp.get("private dir") + paths.shareconf = os.path.join(private_dir, "share.ldb") + paths.samdb = os.path.join(private_dir, lp.get("sam database") or "samdb.ldb") + paths.secrets = os.path.join(private_dir, lp.get("secrets database") or "secrets.ldb") + paths.templates = os.path.join(private_dir, "templates.ldb") + paths.keytab = os.path.join(private_dir, "secrets.keytab") + paths.dns_keytab = os.path.join(private_dir, "dns.keytab") + paths.dns = os.path.join(private_dir, dnsdomain + ".zone") + paths.winsdb = os.path.join(private_dir, "wins.ldb") + paths.ldap_basedn_ldif = os.path.join(private_dir, + dnsdomain + ".ldif") + paths.ldap_config_basedn_ldif = os.path.join(private_dir, + dnsdomain + "-config.ldif") + paths.ldap_schema_basedn_ldif = os.path.join(private_dir, + dnsdomain + "-schema.ldif") + paths.s4_ldapi_path = os.path.join(private_dir, "ldapi") + paths.phpldapadminconfig = os.path.join(private_dir, + "phpldapadmin-config.php") + paths.hklm = os.path.join(private_dir, "hklm.ldb") + paths.sysvol = lp.get("sysvol", "path") + if paths.sysvol is None: + paths.sysvol = os.path.join(lp.get("lock dir"), "sysvol") + + paths.netlogon = lp.get("netlogon", "path") + if paths.netlogon is None: + paths.netlogon = os.path.join(os.path.join(paths.sysvol, "scripts")) + + return paths + + +def setup_name_mappings(ldb, sid, domaindn, root, nobody, nogroup, users, + wheel, backup): + """setup reasonable name mappings for sam names to unix names.""" + # add some foreign sids if they are not present already + ldb.add_foreign(domaindn, "S-1-5-7", "Anonymous") + ldb.add_foreign(domaindn, "S-1-1-0", "World") + ldb.add_foreign(domaindn, "S-1-5-2", "Network") + ldb.add_foreign(domaindn, "S-1-5-18", "System") + ldb.add_foreign(domaindn, "S-1-5-11", "Authenticated Users") + + # some well known sids + ldb.setup_name_mapping(domaindn, "S-1-5-7", nobody) + ldb.setup_name_mapping(domaindn, "S-1-1-0", nogroup) + ldb.setup_name_mapping(domaindn, "S-1-5-2", nogroup) + ldb.setup_name_mapping(domaindn, "S-1-5-18", root) + ldb.setup_name_mapping(domaindn, "S-1-5-11", users) + ldb.setup_name_mapping(domaindn, "S-1-5-32-544", wheel) + ldb.setup_name_mapping(domaindn, "S-1-5-32-545", users) + ldb.setup_name_mapping(domaindn, "S-1-5-32-546", nogroup) + ldb.setup_name_mapping(domaindn, "S-1-5-32-551", backup) + + # and some well known domain rids + ldb.setup_name_mapping(domaindn, sid + "-500", root) + ldb.setup_name_mapping(domaindn, sid + "-518", wheel) + ldb.setup_name_mapping(domaindn, sid + "-519", wheel) + ldb.setup_name_mapping(domaindn, sid + "-512", wheel) + ldb.setup_name_mapping(domaindn, sid + "-513", users) + ldb.setup_name_mapping(domaindn, sid + "-520", wheel) + + +def provision_become_dc(setup_dir, message, paths, lp, session_info, + credentials): + assert session_info is not None + erase = False + + def setup_path(file): + return os.path.join(setup_dir, file) + os.path.unlink(paths.samdb) + + message("Setting up templates db") + setup_templatesdb(paths.templates, setup_path, session_info, + credentials, lp) + + # Also wipes the database + message("Setting up sam.ldb") + samdb = SamDB(paths.samdb, credentials=credentials, + session_info=session_info, lp=lp) + + message("Setting up sam.ldb partitions") + setup_samdb_partitions(samdb, setup_path, schemadn, + configdn, domaindn) + + samdb = SamDB(paths.samdb, credentials=credentials, + session_info=session_info, lp=lp) + + ldb.transaction_start() + try: + message("Setting up sam.ldb attributes") + samdb.load_ldif_file_add(setup_path("provision_init.ldif")) + + message("Setting up sam.ldb rootDSE") + setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, + hostname, dnsdomain, realm, rootdn, configdn, + netbiosname) + + if erase: + message("Erasing data from partitions") + samdb.erase_partitions() + + message("Setting up sam.ldb indexes") + samdb.load_ldif_file_add(setup_path("provision_index.ldif")) + except: + samdb.transaction_cancel() + raise + + samdb.transaction_commit() + + message("Setting up %s" % paths.secrets) + secrets_ldb = setup_secretsdb(paths.secrets, setup_path, session_info, credentials, lp) + setup_ldb(secrets_ldb, setup_path("secrets_dc.ldif"), + { "MACHINEPASS_B64": b64encode(machinepass) }) + + +def setup_secretsdb(path, setup_path, session_info, credentials, lp): + 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.load_ldif_file_add(setup_path("secrets.ldif")) + return secrets_ldb + + +def setup_templatesdb(path, setup_path, session_info, credentials, lp): + templates_ldb = SamDB(path, session_info=session_info, + credentials=credentials, lp=lp) + templates_ldb.erase() + templates_ldb.load_ldif_file_add(setup_path("provision_templates.ldif")) + + +def setup_registry(path, setup_path, session_info, credentials, lp): + reg = registry.Registry() + hive = registry.Hive(path, session_info=session_info, + credentials=credentials, lp_ctx=lp) + reg.mount_hive(hive, "HKEY_LOCAL_MACHINE") + provision_reg = setup_path("provision.reg") + assert os.path.exists(provision_reg) + reg.apply_patchfile(provision_reg) + + +def setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, hostname, + dnsdomain, realm, rootdn, configdn, netbiosname): + setup_add_ldif(samdb, setup_path("provision_rootdse_add.ldif"), { + "SCHEMADN": schemadn, + "NETBIOSNAME": netbiosname, + "DNSDOMAIN": dnsdomain, + "DEFAULTSITE": DEFAULTSITE, + "REALM": realm, + "DNSNAME": "%s.%s" % (hostname, dnsdomain), + "DOMAINDN": domaindn, + "ROOTDN": rootdn, + "CONFIGDN": configdn, + "VERSION": samba.version(), + }) + + +def setup_samdb_partitions(samdb, setup_path, schemadn, configdn, domaindn): + #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 = ["rootdse", + "paged_results", + "ranged_results", + "anr", + "server_sort", + "extended_dn", + "asq", + "samldb", + "rdn_name", + "objectclass", + "kludge_acl", + "operational"] + tdb_modules_list = [ + "subtree_rename", + "subtree_delete", + "linked_attributes"] + modules_list2 = ["show_deleted", + "partition"] + + setup_add_ldif(samdb, setup_path("provision_partitions.ldif"), { + "SCHEMADN": schemadn, + "SCHEMADN_LDB": "schema.ldb", + "SCHEMADN_MOD2": ",objectguid", + "CONFIGDN": configdn, + "CONFIGDN_LDB": "configuration.ldb", + "DOMAINDN": domaindn, + "DOMAINDN_LDB": "users.ldb", + "SCHEMADN_MOD": "schema_fsmo", + "CONFIGDN_MOD": "naming_fsmo", + "CONFIGDN_MOD2": ",objectguid", + "DOMAINDN_MOD": "pdc_fsmo,password_hash", + "DOMAINDN_MOD2": ",objectguid", + "MODULES_LIST": ",".join(modules_list), + "TDB_MODULES_LIST": ","+",".join(tdb_modules_list), + "MODULES_LIST2": ",".join(modules_list2), + }) + + + +def provision(lp, setup_dir, message, blank, paths, session_info, + credentials, ldapbackend, realm=None, domain=None, hostname=None, + hostip=None, domainsid=None, hostguid=None, adminpass=None, + krbtgtpass=None, domainguid=None, policyguid=None, + invocationid=None, machinepass=None, dnspass=None, root=None, + nobody=None, nogroup=None, users=None, wheel=None, backup=None, + aci=None, serverrole=None): + """Provision samba4 + + :note: caution, this wipes all existing data! + """ + + def setup_path(file): + return os.path.join(setup_dir, file) + + erase = False + + if domainsid is None: + domainsid = security.random_sid() + if policyguid is None: + policyguid = uuid.random() + if invocationid is None: + invocationid = uuid.random() + if adminpass is None: + adminpass = misc.random_password(12) + if krbtgtpass is None: + krbtgtpass = misc.random_password(12) + if machinepass is None: + machinepass = misc.random_password(12) + if dnspass is None: + dnspass = misc.random_password(12) + if root is None: + root = findnss(pwd.getpwnam, "root")[4] + if nobody is None: + nobody = findnss(pwd.getpwnam, "nobody")[4] + if nogroup is None: + nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[2] + if users is None: + users = findnss(grp.getgrnam, "users", "guest", "other", "unknown", "usr")[2] + if wheel is None: + wheel = findnss(grp.getgrnam, "wheel", "root", "staff", "adm")[2] + if backup is None: + backup = findnss(grp.getgrnam, "backup", "wheel", "root", "staff")[2] + if aci is None: + aci = "# no aci for local ldb" + if serverrole is None: + serverrole = lp.get("server role") + + if realm is None: + realm = lp.get("realm") + else: + if lp.get("realm").upper() != realm.upper(): + raise Error("realm '%s' in smb.conf must match chosen realm '%s'\n" % + (lp.get("realm"), realm)) + + assert realm is not None + realm = realm.upper() + + if domain is None: + domain = lp.get("workgroup") + else: + if lp.get("workgroup").upper() != domain.upper(): + raise Error("workgroup '%s' in smb.conf must match chosen domain '%s'\n", + lp.get("workgroup"), domain) + + assert domain is not None + domain = domain.upper() + if not valid_netbios_name(domain): + raise InvalidNetbiosName(domain) + + if hostname is None: + hostname = gethostname().split(".")[0].lower() + + if hostip is None: + hostip = gethostbyname(hostname) + + netbiosname = hostname.upper() + if not valid_netbios_name(netbiosname): + raise InvalidNetbiosName(netbiosname) + + dnsdomain = realm.lower() + domaindn = "DC=" + dnsdomain.replace(".", ",DC=") + rootdn = domaindn + configdn = "CN=Configuration," + rootdn + schemadn = "CN=Schema," + configdn + + rdn_dc = domaindn.split(",")[0][len("DC="):] + + message("set DOMAIN SID: %s" % str(domainsid)) + message("Provisioning for %s in realm %s" % (domain, realm)) + message("Using administrator password: %s" % adminpass) + + assert paths.smbconf is not None + + # only install a new smb.conf if there isn't one there already + if not os.path.exists(paths.smbconf): + message("Setting up smb.conf") + if serverrole == "domain controller": + smbconfsuffix = "dc" + elif serverrole == "member": + smbconfsuffix = "member" + else: + assert "Invalid server role setting: %s" % serverrole + setup_file(setup_path("provision.smb.conf.%s" % smbconfsuffix), paths.smbconf, { + "HOSTNAME": hostname, + "DOMAIN_CONF": domain, + "REALM_CONF": realm, + "SERVERROLE": serverrole, + "NETLOGONPATH": paths.netlogon, + "SYSVOLPATH": paths.sysvol, + }) + lp.reload() + + # 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=credentials, lp=lp) + + message("Setting up the registry") + # FIXME: Still fails for some reason + #setup_registry(paths.hklm, setup_path, session_info, + # credentials=credentials, lp=lp) + + message("Setting up templates db") + setup_templatesdb(paths.templates, setup_path, session_info=session_info, + credentials=credentials, lp=lp) + + samdb = SamDB(paths.samdb, session_info=session_info, + credentials=credentials, lp=lp) + + message("Setting up sam.ldb partitions") + setup_samdb_partitions(samdb, setup_path, schemadn, configdn, domaindn) + + samdb = SamDB(paths.samdb, session_info=session_info, + credentials=credentials, lp=lp) + + samdb.transaction_start() + try: + message("Setting up sam.ldb attributes") + samdb.load_ldif_file_add(setup_path("provision_init.ldif")) + + message("Setting up sam.ldb rootDSE") + setup_samdb_rootdse(samdb, setup_path, schemadn, domaindn, + hostname, dnsdomain, realm, rootdn, configdn, + netbiosname) + + if erase: + message("Erasing data from partitions") + samdb.erase_partitions() + except: + samdb.transaction_cancel() + raise + + samdb.transaction_commit() + + message("Pre-loading the Samba 4 and AD schema") + samdb = SamDB(paths.samdb, session_info=session_info, + credentials=credentials, lp=lp) + samdb.set_domain_sid(domainsid) + load_schema(setup_path, samdb, schemadn, netbiosname, configdn) + + samdb.transaction_start() + + try: + message("Adding DomainDN: %s (permitted to fail)" % domaindn) + setup_add_ldif(samdb, setup_path("provision_basedn.ldif"), { + "DOMAINDN": domaindn, + "ACI": aci, + "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb", + "RDN_DC": rdn_dc, + }) + + message("Modifying DomainDN: " + 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"), { + "RDN_DC": rdn_dc, + "LDAPTIME": timestring(int(time.time())), + "DOMAINSID": str(domainsid), + "SCHEMADN": schemadn, + "NETBIOSNAME": netbiosname, + "DEFAULTSITE": DEFAULTSITE, + "CONFIGDN": configdn, + "POLICYGUID": policyguid, + "DOMAINDN": domaindn, + "DOMAINGUID_MOD": domainguid_mod, + }) + + message("Adding configuration container (permitted to fail)") + setup_add_ldif(samdb, setup_path("provision_configuration_basedn.ldif"), { + "CONFIGDN": configdn, + "ACI": aci, + "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb", + }) + message("Modifying configuration container") + setup_modify_ldif(samdb, setup_path("provision_configuration_basedn_modify.ldif"), { + "CONFIGDN": configdn, + "SCHEMADN": schemadn, + }) + + message("Adding schema container (permitted to fail)") + setup_add_ldif(samdb, setup_path("provision_schema_basedn.ldif"), { + "SCHEMADN": schemadn, + "ACI": aci, + "EXTENSIBLEOBJECT": "# no objectClass: extensibleObject for local ldb" + }) + message("Modifying schema container") + setup_modify_ldif(samdb, setup_path("provision_schema_basedn_modify.ldif"), { + "SCHEMADN": schemadn, + "NETBIOSNAME": netbiosname, + "DEFAULTSITE": DEFAULTSITE, + "CONFIGDN": configdn, + }) + + message("Setting up sam.ldb Samba4 schema") + setup_add_ldif(samdb, setup_path("schema_samba4.ldif"), + {"SCHEMADN": schemadn }) + message("Setting up sam.ldb AD schema") + setup_add_ldif(samdb, setup_path("schema.ldif"), + {"SCHEMADN": schemadn}) + + message("Setting up sam.ldb configuration data") + setup_add_ldif(samdb, setup_path("provision_configuration.ldif"), { + "CONFIGDN": configdn, + "NETBIOSNAME": netbiosname, + "DEFAULTSITE": DEFAULTSITE, + "DNSDOMAIN": dnsdomain, + "DOMAIN": domain, + "SCHEMADN": schemadn, + "DOMAINDN": domaindn, + }) + + message("Setting up display specifiers") + setup_add_ldif(samdb, setup_path("display_specifiers.ldif"), + {"CONFIGDN": configdn}) + + message("Adding users container (permitted to fail)") + setup_add_ldif(samdb, setup_path("provision_users_add.ldif"), { + "DOMAINDN": domaindn}) + message("Modifying users container") + setup_modify_ldif(samdb, setup_path("provision_users_modify.ldif"), { + "DOMAINDN": domaindn}) + message("Adding computers container (permitted to fail)") + setup_add_ldif(samdb, setup_path("provision_computers_add.ldif"), { + "DOMAINDN": domaindn}) + message("Modifying computers container") + setup_modify_ldif(samdb, setup_path("provision_computers_modify.ldif"), { + "DOMAINDN": domaindn}) + message("Setting up sam.ldb data") + setup_add_ldif(samdb, setup_path("provision.ldif"), { + "DOMAINDN": domaindn, + "NETBIOSNAME": netbiosname, + "DEFAULTSITE": DEFAULTSITE, + "CONFIGDN": configdn, + }) + + if not blank: + + # message("Activate schema module") + # setup_modify_ldif("schema_activation.ldif", info, samdb, False) + # + # // (hack) Reload, now we have the schema loaded. + # commit_ok = samdb.transaction_commit() + # if (!commit_ok) { + # message("samdb commit failed: " + samdb.errstring() + "\n") + # assert(commit_ok) + # } + # samdb.close() + # + # samdb = open_ldb(info, paths.samdb, False) + # + message("Setting up sam.ldb users and groups") + setup_add_ldif(samdb, setup_path("provision_users.ldif"), { + "DOMAINDN": domaindn, + "DOMAINSID": str(domainsid), + "CONFIGDN": configdn, + "ADMINPASS_B64": b64encode(adminpass), + "KRBTGTPASS_B64": b64encode(krbtgtpass), + }) + + if lp.get("server role") == "domain controller": + message("Setting up self join") + if hostguid is not None: + hostguid_add = "objectGUID: %s" % hostguid + else: + hostguid_add = "" + + setup_add_ldif(samdb, setup_path("provision_self_join.ldif"), { + "CONFIGDN": configdn, + "SCHEMADN": schemadn, + "DOMAINDN": domaindn, + "INVOCATIONID": invocationid, + "NETBIOSNAME": netbiosname, + "DEFAULTSITE": DEFAULTSITE, + "DNSNAME": "%s.%s" % (hostname, dnsdomain), + "MACHINEPASS_B64": b64encode(machinepass), + "DNSPASS_B64": b64encode(dnspass), + "REALM": realm, + "DOMAIN": domain, + "HOSTGUID_ADD": hostguid_add, + "DNSDOMAIN": dnsdomain}) + setup_add_ldif(samdb, setup_path("provision_group_policy.ldif"), { + "POLICYGUID": policyguid, + "DNSDOMAIN": dnsdomain, + "DOMAINSID": str(domainsid), + "DOMAINDN": domaindn}) + + os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}"), 0755) + os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}", "Machine"), 0755) + os.makedirs(os.path.join(paths.sysvol, dnsdomain, "Policies", "{" + policyguid + "}", "User"), 0755) + if not os.path.isdir(paths.netlogon): + os.makedirs(paths.netlogon, 0755) + setup_ldb(secrets_ldb, setup_path("secrets_dc.ldif"), { + "MACHINEPASS_B64": b64encode(machinepass), + "DOMAIN": domain, + "REALM": realm, + "LDAPTIME": timestring(int(time.time())), + "DNSDOMAIN": dnsdomain, + "DOMAINSID": str(domainsid), + "SECRETS_KEYTAB": paths.keytab, + "NETBIOSNAME": netbiosname, + "SAM_LDB": paths.samdb, + "DNS_KEYTAB": paths.dns_keytab, + "DNSPASS_B64": b64encode(dnspass), + }) + + setup_name_mappings(samdb, str(domainsid), + domaindn, root=root, nobody=nobody, + nogroup=nogroup, wheel=wheel, users=users, + backup=backup) + + message("Setting up sam.ldb index") + samdb.load_ldif_file_add(setup_path("provision_index.ldif")) + + message("Setting up sam.ldb rootDSE marking as syncronized") + setup_modify_ldif(samdb, setup_path("provision_rootdse_modify.ldif")) + except: + samdb.transaction_cancel() + raise + + samdb.transaction_commit() + + message("Setting up phpLDAPadmin configuration") + create_phplpapdadmin_config(paths.phpldapadminconfig, setup_path, paths.s4_ldapi_path) + + message("Please install the phpLDAPadmin configuration located at %s into /etc/phpldapadmin/config.php" % paths.phpldapadminconfig) + + message("Setting up DNS zone: %s" % dnsdomain) + create_zone_file(paths.dns, setup_path, samdb, + hostname=hostname, hostip=hostip, dnsdomain=dnsdomain, + domaindn=domaindn, dnspass=dnspass, realm=realm) + message("Please install the zone located in %s into your DNS server" % paths.dns) + +def create_phplpapdadmin_config(path, setup_path, s4_ldapi_path): + setup_file(setup_path("phpldapadmin-config.php"), + path, {"S4_LDAPI_URI": "ldapi://%s" % s4_ldapi_path.replace("/", "%2F")}) + + +def create_zone_file(path, setup_path, samdb, dnsdomain, domaindn, + hostip, hostname, dnspass, realm): + """Write out a DNS zone file, from the info in the current database.""" + + # connect to the sam + # These values may have changed, due to an incoming SamSync, + # or may not have been specified, so fetch them from the database + domainguid = samdb.searchone(Dn(samdb, domaindn), "objectGUID") + hostguid = samdb.searchone(Dn(samdb, domaindn), "objectGUID" , + expression="(&(objectClass=computer)(cn=%s))" % hostname) + + setup_file(setup_path("provision.zone"), path, { + "DNSPASS_B64": b64encode(dnspass), + "HOSTNAME": hostname, + "DNSDOMAIN": dnsdomain, + "REALM": realm, + "HOSTIP": hostip, + "DOMAINGUID": domainguid, + "DATESTRING": time.strftime("%Y%m%d%H"), + "DEFAULTSITE": DEFAULTSITE, + "HOSTGUID": hostguid, + }) + + +def provision_ldapbase(setup_dir, message, paths): + """Write out a DNS zone file, from the info in the current database.""" + message("Setting up LDAP base entry: %s" % domaindn) + rdns = domaindn.split(",") + + rdn_dc = rdns[0][len("DC="):] + + def setup_path(file): + return os.path.join(setup_dir, file) + + setup_file(setup_path("provision_basedn.ldif"), + paths.ldap_basedn_ldif) + + setup_file(setup_path("provision_configuration_basedn.ldif"), + paths.ldap_config_basedn_ldif) + + setup_file(setup_path("provision_schema_basedn.ldif"), + paths.ldap_schema_basedn_ldif, { + "SCHEMADN": schemadn, + "ACI": "# no aci for local ldb", + "EXTENSIBLEOBJECT": "objectClass: extensibleObject"}) + + message("Please install the LDIF located in " + paths.ldap_basedn_ldif + ", " + paths.ldap_config_basedn_ldif + " and " + paths.ldap_schema_basedn_ldif + " into your LDAP server, and re-run with --ldap-backend=ldap://my.ldap.server") + + +def load_schema(setup_path, samdb, schemadn, netbiosname, configdn): + """Load schema.""" + schema_data = open(setup_path("schema.ldif"), 'r').read() + schema_data += open(setup_path("schema_samba4.ldif"), 'r').read() + schema_data = substitute_var(schema_data, {"SCHEMADN": schemadn}) + head_data = open(setup_path("provision_schema_basedn_modify.ldif"), 'r').read() + head_data = substitute_var(head_data, { + "SCHEMADN": schemadn, + "NETBIOSNAME": netbiosname, + "CONFIGDN": configdn, + "DEFAULTSITE": DEFAULTSITE}) + samdb.attach_schema_from_ldif(head_data, schema_data) + + +def join_domain(domain, netbios_name, join_type, creds): + ctx = NetContext(creds) + joindom = object() + joindom.domain = domain + joindom.join_type = join_type + joindom.netbios_name = netbios_name + if not ctx.JoinDomain(joindom): + raise Exception("Domain Join failed: " + joindom.error_string) + + +def vampire(domain, session_info, credentials, message): + """Vampire a remote domain. + + Session info and credentials are required for for + access to our local database (might be remote ldap) + """ + ctx = NetContext(credentials) + machine_creds = Credentials() + machine_creds.set_domain(form.domain) + if not machine_creds.set_machine_account(): + raise Exception("Failed to access domain join information!") + vampire_ctx.machine_creds = machine_creds + vampire_ctx.session_info = session_info + if not ctx.SamSyncLdb(vampire_ctx): + raise Exception("Migration of remote domain to Samba failed: %s " % vampire_ctx.error_string) + + + diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py new file mode 100644 index 0000000000..84b604dbc4 --- /dev/null +++ b/source4/scripting/python/samba/samdb.py @@ -0,0 +1,132 @@ +#!/usr/bin/python + +# Unix SMB/CIFS implementation. +# Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007 +# +# Based on the original in EJS: +# Copyright (C) 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 +import misc +import ldb + +class SamDB(samba.Ldb): + def __init__(self, url=None, session_info=None, credentials=None, + modules_dir=None, lp=None): + super(SamDB, self).__init__(session_info=session_info, credentials=credentials, + modules_dir=modules_dir, lp=lp) + assert misc.dsdb_set_global_schema(self) == 0 + assert misc.ldb_register_samba_handlers(self) == 0 + if url: + self.connect(url) + + def add_foreign(self, domaindn, sid, desc): + """Add a foreign security principle.""" + add = """ +dn: CN=%s,CN=ForeignSecurityPrincipals,%s +objectClass: top +objectClass: foreignSecurityPrincipal +description: %s + """ % (sid, domaindn, desc) + # deliberately ignore errors from this, as the records may + # already exist + for msg in self.parse_ldif(add): + self.add(msg[1]) + + def setup_name_mapping(self, domaindn, sid, unixname): + """Setup a mapping between a sam name and a unix name.""" + res = self.search(ldb.Dn(self, domaindn), ldb.SCOPE_SUBTREE, + "objectSid=%s" % sid, ["dn"]) + assert len(res) == 1, "Failed to find record for objectSid %s" % sid + + mod = """ +dn: %s +changetype: modify +replace: unixName +unixName: %s +""" % (res[0].dn, unixname) + self.modify(self.parse_ldif(mod).next()[1]) + + def enable_account(self, user_dn): + """enable the account. + + :param user_dn: Dn of the account to enable. + """ + res = self.search(user_dn, SCOPE_ONELEVEL, None, ["userAccountControl"]) + assert len(res) == 1 + userAccountControl = res[0].userAccountControl + userAccountControl = userAccountControl - 2 # remove disabled bit + mod = """ +dn: %s +changetype: modify +replace: userAccountControl +userAccountControl: %u +""" % (user_dn, userAccountControl) + self.modify(mod) + + def newuser(self, username, unixname, password, message): + """add a new user record""" + # connect to the sam + self.transaction_start() + + # find the DNs for the domain and the domain users group + res = self.search("", SCOPE_BASE, "defaultNamingContext=*", + ["defaultNamingContext"]) + assert(len(res) == 1 and res[0].defaultNamingContext is not None) + domain_dn = res[0].defaultNamingContext + assert(domain_dn is not None) + dom_users = self.searchone(domain_dn, "dn", "name=Domain Users") + assert(dom_users is not None) + + user_dn = "CN=%s,CN=Users,%s" % (username, domain_dn) + + # + # the new user record. note the reliance on the samdb module to fill + # in a sid, guid etc + # + ldif = """ +dn: %s +sAMAccountName: %s +unixName: %s +sambaPassword: %s +objectClass: user + """ % (user_dn, username, unixname, password) + # add the user to the users group as well + modgroup = """ +dn: %s +changetype: modify +add: member +member: %s +""" % (dom_users, user_dn) + + + # now the real work + message("Adding user %s" % user_dn) + self.add(ldif) + + message("Modifying group %s" % dom_users) + self.modify(modgroup) + + # modify the userAccountControl to remove the disabled bit + enable_account(self, user_dn) + self.transaction_commit() + + def set_domain_sid(self, sid): + misc.samdb_set_domain_sid(self, sid) + + def attach_schema_from_ldif(self, pf, df): + misc.dsdb_attach_schema_from_ldif_file(self, pf, df) diff --git a/source4/scripting/python/samba/tests/__init__.py b/source4/scripting/python/samba/tests/__init__.py new file mode 100644 index 0000000000..e213c1cc1f --- /dev/null +++ b/source4/scripting/python/samba/tests/__init__.py @@ -0,0 +1,72 @@ +#!/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/>. +# + +import os +import ldb +import samba +import tempfile +import unittest + +class LdbTestCase(unittest.TestCase): + def setUp(self): + self.filename = os.tempnam() + self.ldb = samba.Ldb(self.filename) + + def set_modules(self, modules=[]): + m = ldb.Message() + m.dn = ldb.Dn(self.ldb, "@MODULES") + m["@LIST"] = ",".join(modules) + self.ldb.add(m) + self.ldb = samba.Ldb(self.filename) + + +class TestCaseInTempDir(unittest.TestCase): + def setUp(self): + super(TestCaseInTempDir, self).setUp() + self.tempdir = tempfile.mkdtemp() + + def tearDown(self): + super(TestCaseInTempDir, self).tearDown() + + +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 test_unknown_var(self): + self.assertEquals("foo ${bla} gsff", + samba.substitute_var("foo ${bla} gsff", {"bar": "bla"})) + + +class LdbExtensionTests(TestCaseInTempDir): + def test_searchone(self): + l = samba.Ldb(self.tempdir + "/searchone.ldb") + l.add({"dn": "foo=dc", "bar": "bla"}) + self.assertEquals("bla", l.searchone(ldb.Dn(l, "foo=dc"), "bar")) + diff --git a/source4/scripting/python/samba/tests/provision.py b/source4/scripting/python/samba/tests/provision.py new file mode 100644 index 0000000000..bf7182dbd3 --- /dev/null +++ b/source4/scripting/python/samba/tests/provision.py @@ -0,0 +1,71 @@ +#!/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/>. +# + +import os +from samba.provision import setup_secretsdb +import samba.tests +from ldb import Dn + +setup_dir = "setup" +def setup_path(file): + return os.path.join(setup_dir, file) + + +class ProvisionTestCase(samba.tests.TestCaseInTempDir): + def test_setup_secretsdb(self): + ldb = setup_secretsdb(os.path.join(self.tempdir, "secrets.ldb"), + setup_path, None, None, None) + self.assertEquals("LSA Secrets", + ldb.searchone(Dn(ldb, "CN=LSA Secrets"), "CN")) + + +class Disabled: + def test_setup_templatesdb(self): + raise NotImplementedError(self.test_setup_templatesdb) + + def test_setup_registry(self): + raise NotImplementedError(self.test_setup_registry) + + def test_setup_samdb_rootdse(self): + raise NotImplementedError(self.test_setup_samdb_rootdse) + + def test_setup_samdb_partitions(self): + raise NotImplementedError(self.test_setup_samdb_partitions) + + def test_create_phpldapadmin_config(self): + raise NotImplementedError(self.test_create_phpldapadmin_config) + + def test_provision_dns(self): + raise NotImplementedError(self.test_provision_dns) + + def test_provision_ldapbase(self): + raise NotImplementedError(self.test_provision_ldapbase) + + def test_provision_guess(self): + raise NotImplementedError(self.test_provision_guess) + + def test_join_domain(self): + raise NotImplementedError(self.test_join_domain) + + 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/upgrade.py b/source4/scripting/python/samba/tests/upgrade.py new file mode 100644 index 0000000000..a25743425b --- /dev/null +++ b/source4/scripting/python/samba/tests/upgrade.py @@ -0,0 +1,28 @@ +#!/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/>. +# + +from samba.upgrade import regkey_to_dn +from unittest import TestCase + +class RegkeyDnTests(TestCase): + def test_empty(self): + self.assertEquals("hive=NONE", regkey_to_dn("")) + + def test_nested(self): + self.assertEquals("key=bar,key=foo,hive=NONE", regkey_to_dn("foo/bar")) diff --git a/source4/scripting/python/samba/upgrade.py b/source4/scripting/python/samba/upgrade.py new file mode 100644 index 0000000000..1c27f8ec25 --- /dev/null +++ b/source4/scripting/python/samba/upgrade.py @@ -0,0 +1,553 @@ +#!/usr/bin/python +# +# 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.""" + +from provision import findnss +import provision +import grp +import pwd +import uuid + +def regkey_to_dn(name): + """Convert a registry key to a DN. + + :name: The registry key name. + :return: A matching DN.""" + dn = "hive=NONE" + + if name == "": + return dn + + for el in name.split("/"): + dn = "key=%s," % el + dn + + return dn + +# Where prefix is any of: +# - HKLM +# HKU +# HKCR +# HKPD +# HKPT +# + +def upgrade_registry(regdb,prefix,ldb): + """Migrate registry contents.""" + assert regdb is not None + prefix_up = prefix.upper() + ldif = [] + + for rk in regdb.keys: + pts = rk.name.split("/") + + # Only handle selected hive + if pts[0].upper() != prefix_up: + continue + + keydn = regkey_to_dn(rk.name) + + pts = rk.name.split("/") + + # Convert key name to dn + ldif[rk.name] = """ +dn: %s +name: %s + +""" % (keydn, pts[0]) + + for rv in rk.values: + ldif[rk.name + " (" + rv.name + ")"] = """ +dn: %s,value=%s +value: %s +type: %d +data:: %s""" % (keydn, rv.name, rv.name, rv.type, ldb.encode(rv.data)) + + return ldif + +def upgrade_sam_policy(samba3,dn): + ldif = """ +dn: %s +changetype: modify +replace: minPwdLength +minPwdLength: %d +pwdHistoryLength: %d +minPwdAge: %d +maxPwdAge: %d +lockoutDuration: %d +samba3ResetCountMinutes: %d +samba3UserMustLogonToChangePassword: %d +samba3BadLockoutMinutes: %d +samba3DisconnectTime: %d + +""" % (dn, samba3.policy.min_password_length, + samba3.policy.password_history, samba3.policy.minimum_password_age, + samba3.policy.maximum_password_age, samba3.policy.lockout_duration, + samba3.policy.reset_count_minutes, samba3.policy.user_must_logon_to_change_password, + samba3.policy.bad_lockout_minutes, samba3.policy.disconnect_time) + + return ldif + +def upgrade_sam_account(ldb,acc,domaindn,domainsid): + """Upgrade a SAM account.""" + if acc.nt_username is None or acc.nt_username == "": + acc.nt_username = acc.username + + if acc.fullname is None: + acc.fullname = pwd.getpwnam(acc.fullname)[4] + + acc.fullname = acc.fullname.split(",")[0] + + if acc.fullname is None: + acc.fullname = acc.username + + assert acc.fullname is not None + assert acc.nt_username is not None + + ldif = """dn: cn=%s,%s +objectClass: top +objectClass: user +lastLogon: %d +lastLogoff: %d +unixName: %s +sAMAccountName: %s +cn: %s +description: %s +primaryGroupID: %d +badPwdcount: %d +logonCount: %d +samba3Domain: %s +samba3DirDrive: %s +samba3MungedDial: %s +samba3Homedir: %s +samba3LogonScript: %s +samba3ProfilePath: %s +samba3Workstations: %s +samba3KickOffTime: %d +samba3BadPwdTime: %d +samba3PassLastSetTime: %d +samba3PassCanChangeTime: %d +samba3PassMustChangeTime: %d +objectSid: %s-%d +lmPwdHash:: %s +ntPwdHash:: %s + +""" % (ldb.dn_escape(acc.fullname), domaindn, acc.logon_time, acc.logoff_time, acc.username, acc.nt_username, acc.nt_username, +acc.acct_desc, acc.group_rid, acc.bad_password_count, acc.logon_count, +acc.domain, acc.dir_drive, acc.munged_dial, acc.homedir, acc.logon_script, +acc.profile_path, acc.workstations, acc.kickoff_time, acc.bad_password_time, +acc.pass_last_set_time, acc.pass_can_change_time, acc.pass_must_change_time, domainsid, acc.user_rid, + ldb.encode(acc.lm_pw), ldb.encode(acc.nt_pw)) + + return ldif + +def upgrade_sam_group(group,domaindn): + """Upgrade a SAM group.""" + if group.sid_name_use == 5: # Well-known group + return None + + if group.nt_name in ("Domain Guests", "Domain Users", "Domain Admins"): + return None + + if group.gid == -1: + gr = grp.getgrnam(grp.nt_name) + else: + gr = grp.getgrgid(grp.gid) + + if gr is None: + group.unixname = "UNKNOWN" + else: + group.unixname = gr.gr_name + + assert group.unixname is not None + + ldif = """dn: cn=%s,%s +objectClass: top +objectClass: group +description: %s +cn: %s +objectSid: %s +unixName: %s +samba3SidNameUse: %d +""" % (group.nt_name, domaindn, +group.comment, group.nt_name, group.sid, group.unixname, group.sid_name_use) + + return ldif + +def upgrade_winbind(samba3,domaindn): + ldif = """ + +dn: dc=none +userHwm: %d +groupHwm: %d + +""" % (samba3.idmap.user_hwm, samba3.idmap.group_hwm) + + for m in samba3.idmap.mappings: + ldif += """ +dn: SID=%s,%s +SID: %s +type: %d +unixID: %d""" % (m.sid, domaindn, m.sid, m.type, m.unix_id) + + return ldif + +def upgrade_wins(samba3): + """Upgrade the WINS database.""" + ldif = "" + version_id = 0 + + for e in samba3.winsentries: + now = sys.nttime() + ttl = sys.unix2nttime(e.ttl) + + version_id+=1 + + numIPs = len(e.ips) + + if e.type == 0x1C: + rType = 0x2 + elif e.type & 0x80: + if numIPs > 1: + rType = 0x2 + else: + rType = 0x1 + else: + if numIPs > 1: + rType = 0x3 + else: + rType = 0x0 + + if ttl > now: + rState = 0x0 # active + else: + rState = 0x1 # released + + nType = ((e.nb_flags & 0x60)>>5) + + ldif += """ +dn: name=%s,type=0x%02X +type: 0x%02X +name: %s +objectClass: winsRecord +recordType: %u +recordState: %u +nodeType: %u +isStatic: 0 +expireTime: %s +versionID: %llu +""" % (e.name, e.type, e.type, e.name, + rType, rState, nType, + ldaptime(ttl), version_id) + + for ip in e.ips: + ldif += "address: %s\n" % ip + + ldif += """ +dn: CN=VERSION +objectClass: winsMaxVersion +maxVersion: %llu +""" % version_id + + return ldif + +def upgrade_provision(lp, samba3): + domainname = samba3.configuration.get("workgroup") + + if domainname is None: + domainname = samba3.secrets.domains[0].name + print "No domain specified in smb.conf file, assuming '%s'\n" % domainname + + domsec = samba3.find_domainsecrets(domainname) + hostsec = samba3.find_domainsecrets(hostname()) + realm = samba3.configuration.get("realm") + + if realm is None: + realm = domainname + print "No realm specified in smb.conf file, assuming '%s'\n" % realm + random_init(local) + + subobj.realm = realm + subobj.domain = domainname + + if domsec is not None: + subobj.DOMAINGUID = domsec.guid + subobj.DOMAINSID = domsec.sid + else: + print "Can't find domain secrets for '%s'; using random SID and GUID\n" % domainname + subobj.DOMAINGUID = uuid.random() + subobj.DOMAINSID = randsid() + + if hostsec: + hostguid = hostsec.guid + subobj.krbtgtpass = randpass(12) + subobj.machinepass = randpass(12) + subobj.adminpass = randpass(12) + subobj.datestring = datestring() + subobj.root = findnss(pwd.getpwnam, "root")[4] + subobj.nobody = findnss(pwd.getpwnam, "nobody")[4] + subobj.nogroup = findnss(grp.getgrnam, "nogroup", "nobody")[2] + subobj.wheel = findnss(grp.getgrnam, "wheel", "root")[2] + subobj.users = findnss(grp.getgrnam, "users", "guest", "other")[2] + subobj.dnsdomain = subobj.realm.lower() + subobj.dnsname = "%s.%s" % (subobj.hostname.lower(), subobj.dnsdomain) + subobj.basedn = "DC=" + ",DC=".join(subobj.realm.split(".")) + rdn_list = subobj.dnsdomain.split(".") + subobj.domaindn = "DC=" + ",DC=".join(rdn_list) + subobj.domaindn_ldb = "users.ldb" + subobj.rootdn = subobj.domaindn + + modules_list = ["rootdse", + "kludge_acl", + "paged_results", + "server_sort", + "extended_dn", + "asq", + "samldb", + "password_hash", + "operational", + "objectclass", + "rdn_name", + "show_deleted", + "partition"] + subobj.modules_list = ",".join(modules_list) + + return subobj + +smbconf_keep = [ + "dos charset", + "unix charset", + "display charset", + "comment", + "path", + "directory", + "workgroup", + "realm", + "netbios name", + "netbios aliases", + "netbios scope", + "server string", + "interfaces", + "bind interfaces only", + "security", + "auth methods", + "encrypt passwords", + "null passwords", + "obey pam restrictions", + "password server", + "smb passwd file", + "private dir", + "passwd chat", + "password level", + "lanman auth", + "ntlm auth", + "client NTLMv2 auth", + "client lanman auth", + "client plaintext auth", + "read only", + "hosts allow", + "hosts deny", + "log level", + "debuglevel", + "log file", + "smb ports", + "large readwrite", + "max protocol", + "min protocol", + "unicode", + "read raw", + "write raw", + "disable netbios", + "nt status support", + "announce version", + "announce as", + "max mux", + "max xmit", + "name resolve order", + "max wins ttl", + "min wins ttl", + "time server", + "unix extensions", + "use spnego", + "server signing", + "client signing", + "max connections", + "paranoid server security", + "socket options", + "strict sync", + "max print jobs", + "printable", + "print ok", + "printer name", + "printer", + "map system", + "map hidden", + "map archive", + "preferred master", + "prefered master", + "local master", + "browseable", + "browsable", + "wins server", + "wins support", + "csc policy", + "strict locking", + "preload", + "auto services", + "lock dir", + "lock directory", + "pid directory", + "socket address", + "copy", + "include", + "available", + "volume", + "fstype", + "panic action", + "msdfs root", + "host msdfs", + "winbind separator"] + +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 + kept in the new configuration as "samba3:<name>" + """ + data = oldconf.data() + newconf = param_init() + + for s in data: + for p in data[s]: + keep = False + for k in smbconf_keep: + if smbconf_keep[k] == p: + keep = True + break + + if keep: + newconf.set(s, p, oldconf.get(s, p)) + elif mark: + newconf.set(s, "samba3:"+p, oldconf.get(s,p)) + + if oldconf.get("domain logons") == "True": + newconf.set("server role", "domain controller") + else: + if oldconf.get("security") == "user": + newconf.set("server role", "standalone") + else: + newconf.set("server role", "member server") + + return newconf + +def upgrade(subobj, samba3, message, paths, session_info, credentials): + ret = 0 + lp = loadparm_init() + samdb = Ldb(paths.samdb, session_info=session_info, credentials=credentials) + + message("Writing configuration") + newconf = upgrade_smbconf(samba3.configuration,True) + newconf.save(paths.smbconf) + + message("Importing account policies") + ldif = upgrade_sam_policy(samba3,subobj.BASEDN) + samdb.modify(ldif) + regdb = Ldb(paths.hklm) + + regdb.modify(""" +dn: value=RefusePasswordChange,key=Parameters,key=Netlogon,key=Services,key=CurrentControlSet,key=System,HIVE=NONE +replace: type +type: 4 +replace: data +data: %d +""" % samba3.policy.refuse_machine_password_change) + + message("Importing users") + for account in samba3.samaccounts: + msg = "... " + account.username + ldif = upgrade_sam_account(samdb, accounts,subobj.BASEDN,subobj.DOMAINSID) + try: + samdb.add(ldif) + except LdbError, e: + # FIXME: Ignore 'Record exists' errors + msg += "... error: " + str(e) + ret += 1; + message(msg) + + message("Importing groups") + for mapping in samba3.groupmappings: + msg = "... " + mapping.nt_name + ldif = upgrade_sam_group(mapping, subobj.BASEDN) + if ldif is not None: + try: + samdb.add(ldif) + except LdbError, e: + # FIXME: Ignore 'Record exists' errors + msg += "... error: " + str(e) + ret += 1 + message(msg) + + message("Importing registry data") + for hive in ["hkcr","hkcu","hklm","hkpd","hku","hkpt"]: + message("... " + hive) + regdb = Ldb(paths[hive]) + ldif = upgrade_registry(samba3.registry, hive, regdb) + for j in ldif: + msg = "... ... " + j + try: + regdb.add(ldif[j]) + except LdbError, e: + # FIXME: Ignore 'Record exists' errors + msg += "... error: " + str(e) + ret += 1 + message(msg) + + message("Importing WINS data") + winsdb = Ldb(paths.winsdb) + ldb_erase(winsdb) + + ldif = upgrade_wins(samba3) + winsdb.add(ldif) + + # figure out ldapurl, if applicable + ldapurl = None + pdb = samba3.configuration.get_list("passdb backend") + if pdb is not None: + for backend in pdb: + if len(backend) >= 7 and backend[0:7] == "ldapsam": + ldapurl = backend[7:] + + # URL was not specified in passdb backend but ldap /is/ used + if ldapurl == "": + ldapurl = "ldap://%s" % samba3.configuration.get("ldap server") + + # Enable samba3sam module if original passdb backend was ldap + if ldapurl is not None: + message("Enabling Samba3 LDAP mappings for SAM database") + + samdb.modify(""" +dn: @MODULES +changetype: modify +replace: @LIST +@LIST: samldb,operational,objectguid,rdn_name,samba3sam +""") + + samdb.add({"dn": "@MAP=samba3sam", "@MAP_URL": ldapurl}) + + return ret + +def upgrade_verify(subobj, samba3, paths, message): + message("Verifying account policies") + + samldb = Ldb(paths.samdb) + + for account in samba3.samaccounts: + msg = samldb.search("(&(sAMAccountName=" + account.nt_username + ")(objectclass=user))") + assert(len(msg) >= 1) + + # FIXME diff --git a/source4/scripting/python/subunit/__init__.py b/source4/scripting/python/subunit/__init__.py index e44dd766cc..4d3434a3ea 100644 --- a/source4/scripting/python/subunit/__init__.py +++ b/source4/scripting/python/subunit/__init__.py @@ -20,7 +20,6 @@ import os from StringIO import StringIO -import subprocess import sys import unittest @@ -216,14 +215,14 @@ class TestProtocolClient(unittest.TestResult): def addError(self, test, error): """Report an error in test test.""" self._stream.write("error: %s [\n" % (test.shortDescription() or str(test))) - for line in self._exc_info_to_string(error, test).split(): + for line in self._exc_info_to_string(error, test).splitlines(): self._stream.write("%s\n" % line) self._stream.write("]\n") def addFailure(self, test, error): """Report a failure in test test.""" self._stream.write("failure: %s [\n" % (test.shortDescription() or str(test))) - for line in self._exc_info_to_string(error, test).split(): + for line in self._exc_info_to_string(error, test).splitlines(): self._stream.write("%s\n" % line) self._stream.write("]\n") @@ -315,9 +314,8 @@ class ExecTestCase(unittest.TestCase): def _run(self, result): protocol = TestProtocolServer(result) - output = subprocess.Popen([self.script], - stdout=subprocess.PIPE).communicate()[0] - protocol.readFrom(StringIO(output)) + output = os.popen(self.script, mode='r') + protocol.readFrom(output) class IsolatedTestCase(unittest.TestCase): |