diff options
Diffstat (limited to 'source4/scripting/python')
| -rw-r--r-- | source4/scripting/python/misc.i | 2 | ||||
| -rw-r--r-- | source4/scripting/python/misc.py | 1 | ||||
| -rw-r--r-- | source4/scripting/python/misc_wrap.c | 96 | ||||
| -rw-r--r-- | source4/scripting/python/samba/__init__.py | 104 | ||||
| -rw-r--r-- | source4/scripting/python/samba/provision.py | 230 | ||||
| -rw-r--r-- | source4/scripting/python/samba/samdb.py | 117 | 
6 files changed, 316 insertions, 234 deletions
diff --git a/source4/scripting/python/misc.i b/source4/scripting/python/misc.i index b2a7ad8ee8..0a94fcdc29 100644 --- a/source4/scripting/python/misc.i +++ b/source4/scripting/python/misc.i @@ -40,12 +40,10 @@ void ldb_set_credentials(struct ldb_context *ldb, struct cli_credentials *creds)      ldb_set_opaque(ldb, "credentials", creds);  } -#if 0 /* Fails to link.. */  void ldb_set_session_info(struct ldb_context *ldb, struct auth_session_info *session_info)  {      ldb_set_opaque(ldb, "sessionInfo", session_info);  } -#endif  void ldb_set_loadparm(struct ldb_context *ldb, struct loadparm_context *lp_ctx)  { diff --git a/source4/scripting/python/misc.py b/source4/scripting/python/misc.py index 8a8ff80107..7628dbcb15 100644 --- a/source4/scripting/python/misc.py +++ b/source4/scripting/python/misc.py @@ -62,6 +62,7 @@ import credentials  import param  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 diff --git a/source4/scripting/python/misc_wrap.c b/source4/scripting/python/misc_wrap.c index af0f32fcb2..f5e23d0407 100644 --- a/source4/scripting/python/misc_wrap.c +++ b/source4/scripting/python/misc_wrap.c @@ -2460,29 +2460,30 @@ SWIG_Python_MustGetPtr(PyObject *obj, swig_type_info *ty, int argnum, int flags)  /* -------- TYPES TABLE (BEGIN) -------- */  #define SWIGTYPE_p_TALLOC_CTX swig_types[0] -#define SWIGTYPE_p_char swig_types[1] -#define SWIGTYPE_p_cli_credentials swig_types[2] -#define SWIGTYPE_p_int swig_types[3] -#define SWIGTYPE_p_ldb_context swig_types[4] -#define SWIGTYPE_p_ldb_dn swig_types[5] -#define SWIGTYPE_p_ldb_ldif swig_types[6] -#define SWIGTYPE_p_ldb_message swig_types[7] -#define SWIGTYPE_p_ldb_message_element swig_types[8] -#define SWIGTYPE_p_ldb_result swig_types[9] -#define SWIGTYPE_p_loadparm_context swig_types[10] -#define SWIGTYPE_p_loadparm_service swig_types[11] -#define SWIGTYPE_p_long_long swig_types[12] -#define SWIGTYPE_p_param_context swig_types[13] -#define SWIGTYPE_p_param_section swig_types[14] -#define SWIGTYPE_p_short swig_types[15] -#define SWIGTYPE_p_signed_char swig_types[16] -#define SWIGTYPE_p_unsigned_char swig_types[17] -#define SWIGTYPE_p_unsigned_int swig_types[18] -#define SWIGTYPE_p_unsigned_long swig_types[19] -#define SWIGTYPE_p_unsigned_long_long swig_types[20] -#define SWIGTYPE_p_unsigned_short swig_types[21] -static swig_type_info *swig_types[23]; -static swig_module_info swig_module = {swig_types, 22, 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_int swig_types[4] +#define SWIGTYPE_p_ldb_context swig_types[5] +#define SWIGTYPE_p_ldb_dn swig_types[6] +#define SWIGTYPE_p_ldb_ldif swig_types[7] +#define SWIGTYPE_p_ldb_message swig_types[8] +#define SWIGTYPE_p_ldb_message_element swig_types[9] +#define SWIGTYPE_p_ldb_result swig_types[10] +#define SWIGTYPE_p_loadparm_context swig_types[11] +#define SWIGTYPE_p_loadparm_service swig_types[12] +#define SWIGTYPE_p_long_long swig_types[13] +#define SWIGTYPE_p_param_context swig_types[14] +#define SWIGTYPE_p_param_section swig_types[15] +#define SWIGTYPE_p_short swig_types[16] +#define SWIGTYPE_p_signed_char swig_types[17] +#define SWIGTYPE_p_unsigned_char swig_types[18] +#define SWIGTYPE_p_unsigned_int swig_types[19] +#define SWIGTYPE_p_unsigned_long swig_types[20] +#define SWIGTYPE_p_unsigned_long_long swig_types[21] +#define SWIGTYPE_p_unsigned_short swig_types[22] +static swig_type_info *swig_types[24]; +static swig_module_info swig_module = {swig_types, 23, 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) @@ -2703,12 +2704,10 @@ void ldb_set_credentials(struct ldb_context *ldb, struct cli_credentials *creds)      ldb_set_opaque(ldb, "credentials", creds);  } -#if 0 /* Fails to link.. */  void ldb_set_session_info(struct ldb_context *ldb, struct auth_session_info *session_info)  {      ldb_set_opaque(ldb, "sessionInfo", session_info);  } -#endif  void ldb_set_loadparm(struct ldb_context *ldb, struct loadparm_context *lp_ctx)  { @@ -2758,7 +2757,7 @@ SWIGINTERN PyObject *_wrap_ldb_set_credentials(PyObject *SWIGUNUSEDPARM(self), P    PyObject * obj0 = 0 ;    PyObject * obj1 = 0 ;    char *  kwnames[] = { -    (char *) "Ldb",(char *) "creds", NULL  +    (char *) "ldb",(char *) "creds", NULL     };    { @@ -2790,6 +2789,44 @@ fail:  } +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 ; @@ -2801,7 +2838,7 @@ SWIGINTERN PyObject *_wrap_ldb_set_loadparm(PyObject *SWIGUNUSEDPARM(self), PyOb    PyObject * obj0 = 0 ;    PyObject * obj1 = 0 ;    char *  kwnames[] = { -    (char *) "Ldb",(char *) "lp_ctx", NULL  +    (char *) "ldb",(char *) "lp_ctx", NULL     };    { @@ -2836,6 +2873,7 @@ fail:  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},  	 { NULL, NULL, 0, NULL }  }; @@ -2844,6 +2882,7 @@ 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_int = {"_p_int", "intptr_t *|int *|int_least32_t *|int_fast32_t *|int32_t *|int_fast16_t *", 0, 0, (void*)0, 0}; @@ -2868,6 +2907,7 @@ static swig_type_info _swigt__p_unsigned_short = {"_p_unsigned_short", "unsigned  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_int, @@ -2892,6 +2932,7 @@ static swig_type_info *swig_type_initial[] = {  };  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_int[] = {  {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0}}; @@ -2916,6 +2957,7 @@ static swig_cast_info _swigc__p_unsigned_short[] = {  {&_swigt__p_unsigned_short  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_int, diff --git a/source4/scripting/python/samba/__init__.py b/source4/scripting/python/samba/__init__.py index 08a262eec8..56adce4473 100644 --- a/source4/scripting/python/samba/__init__.py +++ b/source4/scripting/python/samba/__init__.py @@ -35,40 +35,78 @@ if _in_source_tree():  import misc  import ldb -ldb.ldb.set_credentials = misc.ldb_set_credentials -#FIXME: ldb.ldb.set_session_info = misc.ldb_set_session_info -ldb.ldb.set_loadparm = misc.ldb_set_loadparm - -def Ldb(url, session_info=None, credentials=None, modules_dir=None, lp=None): -    """Open a Samba Ldb file.  - -    :param url: LDB Url to open -    :param session_info: Optional session information -    :param credentials: Optional credentials, defaults to anonymous. -    :param modules_dir: Modules directory, automatically set if not specified. -    :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). +ldb.Ldb.set_credentials = misc.ldb_set_credentials +ldb.Ldb.set_session_info = misc.ldb_set_session_info +ldb.Ldb.set_loadparm = misc.ldb_set_loadparm + +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 = default_ldb_modules_dir -    if modules_dir is not None: -        ret.set_modules_dir(modules_dir) -    def samba_debug(level,text): -        print "%d %s" % (level, text) -    if credentials is not None: -        ldb.set_credentials(credentials) -    if session_info is not None: -        ldb.set_session_info(session_info) -    if lp is not None: -        ldb.set_loadparm(lp) -    #ret.set_debug(samba_debug) -    ret.connect(url) -    return ret +    def __init__(url, session_info=None, credentials=None, modules_dir=None,  +            lp=None): +        """Open a Samba Ldb file.  + +        :param url: LDB Url to open +        :param session_info: Optional session information +        :param credentials: Optional credentials, defaults to anonymous. +        :param modules_dir: Modules directory, automatically set if not specified. +        :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(self, Ldb).__init__() +        import ldb +        ret = ldb.Ldb() +        if modules_dir is None: +            modules_dir = default_ldb_modules_dir +        if modules_dir is not None: +            ret.set_modules_dir(modules_dir) +        def samba_debug(level,text): +            print "%d %s" % (level, text) +        if credentials is not None: +            ldb.set_credentials(credentials) +        if session_info is not None: +            ldb.set_session_info(session_info) +        if lp is not None: +            ldb.set_loadparm(lp) +        #ret.set_debug(samba_debug) +        ret.connect(url) +        return ret + +    def searchone(self, basedn, expression, attribute): +        """Search for one attribute as a string.""" +        res = self.search(basedn, SCOPE_SUBTREE, expression, [attribute]) +        if len(res) != 1 or res[0][attribute] is None: +            return None +        return res[0][attribute] + +    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(Dn(self, attr)) +            except LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): +                # Ignore missing dn errors +                pass + +        basedn = Dn(self, "") +        # and the rest +        for msg in self.search(basedn, SCOPE_SUBTREE,  +                "(&(|(objectclass=*)(dn=*))(!(dn=@BASEINFO)))",  +                ["dn"]): +            self.delete(msg.dn) + +        res = self.search(basedn, SCOPE_SUBTREE, "(&(|(objectclass=*)(dn=*))(!(dn=@BASEINFO)))", ["dn"]) +        assert len(res) == 0  def substitute_var(text, values): diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index ce496a8bc1..63e50897fe 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -15,6 +15,7 @@ from socket import gethostname, gethostbyname  import param  import registry  from samba import Ldb, substitute_var, valid_netbios_name +from samba.samdb import SamDB  from ldb import Dn, SCOPE_SUBTREE, SCOPE_ONELEVEL, SCOPE_BASE, LdbError, \          LDB_ERR_NO_SUCH_OBJECT, timestring @@ -164,32 +165,6 @@ def findnss(nssfn, *names):              pass      raise Exception("Unable to find user/group for %s" % arguments[1]) -def add_foreign(ldb, subobj, sid, desc): -    """Add a foreign security principle.""" -    add = """ -dn: CN=%s,CN=ForeignSecurityPrincipals,%s -objectClass: top -objectClass: foreignSecurityPrincipal -description: %s -""" % (sid, subobj.domaindn, desc) -    # deliberately ignore errors from this, as the records may -    # already exist -    for msg in ldb.parse_ldif(add): -        ldb.add(msg[1]) - -def setup_name_mapping(subobj, ldb, sid, unixname): -    """Setup a mapping between a sam name and a unix name.""" -    res = ldb.search(Dn(ldb, subobj.domaindn), 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) -    ldb.modify(ldb.parse_ldif(mod).next()[1])  def hostip(): @@ -214,57 +189,6 @@ def ldb_delete(ldb):      ldb.connect(ldb.filename) -def ldb_erase(ldb): -    """Erase an ldb, removing all records.""" -    # delete the specials -    for attr in ["@INDEXLIST", "@ATTRIBUTES", "@SUBCLASSES", "@MODULES",  -                 "@OPTIONS", "@PARTITION", "@KLUDGEACL"]: -        try: -            ldb.delete(Dn(ldb, attr)) -        except LdbError, (LDB_ERR_NO_SUCH_OBJECT, _): -            # Ignore missing dn errors -            pass - -    basedn = Dn(ldb, "") -    # and the rest -    for msg in ldb.search(basedn, SCOPE_SUBTREE,  -            "(&(|(objectclass=*)(dn=*))(!(dn=@BASEINFO)))",  -            ["dn"]): -        ldb.delete(msg.dn) - -    res = ldb.search(basedn, SCOPE_SUBTREE, "(&(|(objectclass=*)(dn=*))(!(dn=@BASEINFO)))", ["dn"]) -    assert len(res) == 0 - - -def ldb_erase_partitions(subobj, message, ldb, ldapbackend): -    """Erase an ldb, removing all records.""" -    assert ldb is not None -    res = ldb.search(Dn(ldb, ""), SCOPE_BASE, "(objectClass=*)",  -                     ["namingContexts"]) -    assert len(res) == 1 -    if not "namingContexts" in res[0]: -        return -    for basedn in res[0]["namingContexts"]: -        anything = "(|(objectclass=*)(dn=*))" -        previous_remaining = 1 -        current_remaining = 0 - -        if ldapbackend and (basedn == subobj.domaindn): -            # Only delete objects that were created by provision -            anything = "(objectcategory=*)" - -        k = 0 -        while ++k < 10 and (previous_remaining != current_remaining): -            # and the rest -            res2 = ldb.search(Dn(ldb, basedn), SCOPE_SUBTREE, anything, ["dn"]) -            previous_remaining = current_remaining -            current_remaining = len(res2) -            for msg in res2: -                try: -                    ldb.delete(msg.dn) -                except LdbError, (_, text): -                    message("Unable to delete %s: %s" % (msg.dn, text)) -  def open_ldb(session_info, credentials, dbname):      assert session_info is not None @@ -374,30 +298,30 @@ def setup_name_mappings(subobj, ldb):      sid = list(res[0]["objectSid"])[0]      # add some foreign sids if they are not present already -    add_foreign(ldb, subobj, "S-1-5-7", "Anonymous") -    add_foreign(ldb, subobj, "S-1-1-0", "World") -    add_foreign(ldb, subobj, "S-1-5-2", "Network") -    add_foreign(ldb, subobj, "S-1-5-18", "System") -    add_foreign(ldb, subobj, "S-1-5-11", "Authenticated Users") +    ldb.add_foreign(subobj.domaindn, "S-1-5-7", "Anonymous") +    ldb.add_foreign(subobj.domaindn, "S-1-1-0", "World") +    ldb.add_foreign(subobj.domaindn, "S-1-5-2", "Network") +    ldb.add_foreign(subobj.domaindn, "S-1-5-18", "System") +    ldb.add_foreign(subobj.domaindn, "S-1-5-11", "Authenticated Users")      # some well known sids -    setup_name_mapping(subobj, ldb, "S-1-5-7", subobj.nobody) -    setup_name_mapping(subobj, ldb, "S-1-1-0", subobj.nogroup) -    setup_name_mapping(subobj, ldb, "S-1-5-2", subobj.nogroup) -    setup_name_mapping(subobj, ldb, "S-1-5-18", subobj.root) -    setup_name_mapping(subobj, ldb, "S-1-5-11", subobj.users) -    setup_name_mapping(subobj, ldb, "S-1-5-32-544", subobj.wheel) -    setup_name_mapping(subobj, ldb, "S-1-5-32-545", subobj.users) -    setup_name_mapping(subobj, ldb, "S-1-5-32-546", subobj.nogroup) -    setup_name_mapping(subobj, ldb, "S-1-5-32-551", subobj.backup) +    ldb.setup_name_mapping(subobj.domaindn, "S-1-5-7", subobj.nobody) +    ldb.setup_name_mapping(subobj.domaindn, "S-1-1-0", subobj.nogroup) +    ldb.setup_name_mapping(subobj.domaindn, "S-1-5-2", subobj.nogroup) +    ldb.setup_name_mapping(subobj.domaindn, "S-1-5-18", subobj.root) +    ldb.setup_name_mapping(subobj.domaindn, "S-1-5-11", subobj.users) +    ldb.setup_name_mapping(subobj.domaindn, "S-1-5-32-544", subobj.wheel) +    ldb.setup_name_mapping(subobj.domaindn, "S-1-5-32-545", subobj.users) +    ldb.setup_name_mapping(subobj.domaindn, "S-1-5-32-546", subobj.nogroup) +    ldb.setup_name_mapping(subobj.domaindn, "S-1-5-32-551", subobj.backup)      # and some well known domain rids -    setup_name_mapping(subobj, ldb, sid + "-500", subobj.root) -    setup_name_mapping(subobj, ldb, sid + "-518", subobj.wheel) -    setup_name_mapping(subobj, ldb, sid + "-519", subobj.wheel) -    setup_name_mapping(subobj, ldb, sid + "-512", subobj.wheel) -    setup_name_mapping(subobj, ldb, sid + "-513", subobj.users) -    setup_name_mapping(subobj, ldb, sid + "-520", subobj.wheel) +    ldb.setup_name_mapping(subobj.domaindn, sid + "-500", subobj.root) +    ldb.setup_name_mapping(subobj.domaindn, sid + "-518", subobj.wheel) +    ldb.setup_name_mapping(subobj.domaindn, sid + "-519", subobj.wheel) +    ldb.setup_name_mapping(subobj.domaindn, sid + "-512", subobj.wheel) +    ldb.setup_name_mapping(subobj.domaindn, sid + "-513", subobj.users) +    ldb.setup_name_mapping(subobj.domaindn, sid + "-520", subobj.wheel)  def provision_become_dc(setup_dir, subobj, message, paths, session_info,  @@ -414,7 +338,8 @@ def provision_become_dc(setup_dir, subobj, message, paths, session_info,      setup_ldb(setup_dir, "provision_partitions.ldif", session_info,                 credentials, subobj, paths.samdb) -    samdb = open_ldb(session_info, credentials, paths.samdb) +    samdb = SamDB(paths.samdb, session_info=session_info,  +                  credentials=credentials)      ldb.transaction_start()      try:          message("Setting up %s attributes" % paths.samdb) @@ -424,7 +349,7 @@ def provision_become_dc(setup_dir, subobj, message, paths, session_info,          setup_add_ldif(setup_dir, "provision_rootdse_add.ldif", subobj, samdb)          message("Erasing data from partitions") -        ldb_erase_partitions(subobj, message, samdb, undefined) +        ldb_erase_partitions(subobj, message, samdb, None)          message("Setting up %s indexes" % paths.samdb)          setup_add_ldif(setup_dir, "provision_index.ldif", subobj, samdb) @@ -603,7 +528,7 @@ def provision_dns(setup_dir, subobj, message, paths, session_info, credentials):      """Write out a DNS zone file, from the info in the current database."""      message("Setting up DNS zone: %s" % subobj.dnsdomain)      # connect to the sam -    ldb = Ldb(paths.samdb, session_info=session_info, credentials=credentials) +    ldb = SamDB(paths.samdb, session_info=session_info, credentials=credentials)      # These values may have changed, due to an incoming SamSync,      # or may not have been specified, so fetch them from the database @@ -614,7 +539,7 @@ def provision_dns(setup_dir, subobj, message, paths, session_info, credentials):      assert(res[0]["objectGUID"] is not None)      subobj.domainguid = res[0]["objectGUID"] -    subobj.host_guid = searchone(ldb, subobj.domaindn,  +    subobj.host_guid = ldb.searchone(subobj.domaindn,                                    "(&(objectClass=computer)(cn=%s))" % subobj.netbiosname, "objectGUID")      assert subobj.host_guid is not None @@ -716,13 +641,6 @@ def provision_guess(lp):      return subobj -def searchone(ldb, basedn, expression, attribute): -    """search for one attribute as a string.""" -    res = ldb.search(basedn, SCOPE_SUBTREE, expression, [attribute]) -    if len(res) != 1 or res[0][attribute] is None: -        return None -    return res[0][attribute] -  def load_schema(setup_dir, subobj, samdb):      """Load schema.""" @@ -745,70 +663,6 @@ def load_schema(setup_dir, subobj, samdb):      samdb.attach_dsdb_schema_from_ldif(head_data, schema_data) -def enable_account(ldb, user_dn): -    """enable the account.""" -    res = ldb.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) -    ldb.modify(mod) - - -def newuser(sam, username, unixname, password, message, session_info,  -            credentials): -    """add a new user record""" -    # connect to the sam  -    ldb.transaction_start() - -    # find the DNs for the domain and the domain users group -    res = ldb.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 = searchone(ldb, domain_dn, "name=Domain Users", "dn") -    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) -    ldb.add(ldif) - -    message("Modifying group %s" % dom_users) -    ldb.modify(modgroup) - -    #  modify the userAccountControl to remove the disabled bit -    enable_account(ldb, user_dn) -    ldb.transaction_commit() - -  def join_domain(domain, netbios_name, join_type, creds, message):      ctx = NetContext(creds)      joindom = object() @@ -835,3 +689,35 @@ def vampire(domain, session_info, credentials, message):      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) + + +def ldb_erase_partitions(subobj, message, ldb, ldapbackend): +    """Erase an ldb, removing all records.""" +    assert ldb is not None +    res = ldb.search(Dn(ldb, ""), SCOPE_BASE, "(objectClass=*)",  +                     ["namingContexts"]) +    assert len(res) == 1 +    if not "namingContexts" in res[0]: +        return +    for basedn in res[0]["namingContexts"]: +        anything = "(|(objectclass=*)(dn=*))" +        previous_remaining = 1 +        current_remaining = 0 + +        if ldapbackend and (basedn == subobj.domaindn): +            # Only delete objects that were created by provision +            anything = "(objectcategory=*)" + +        k = 0 +        while ++k < 10 and (previous_remaining != current_remaining): +            # and the rest +            res2 = ldb.search(Dn(ldb, basedn), SCOPE_SUBTREE, anything, ["dn"]) +            previous_remaining = current_remaining +            current_remaining = len(res2) +            for msg in res2: +                try: +                    ldb.delete(msg.dn) +                except LdbError, (_, text): +                    message("Unable to delete %s: %s" % (msg.dn, text)) + + diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py new file mode 100644 index 0000000000..50164bf590 --- /dev/null +++ b/source4/scripting/python/samba/samdb.py @@ -0,0 +1,117 @@ +#!/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 + +class SamDB(samba.Ldb): +    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(Dn(ldb, domaindn), 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 = searchone(self, domain_dn, "name=Domain Users", "dn") +        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() + +  | 
