[SCM] Samba Shared Repository - branch master updated

Andrew Tridgell tridge at samba.org
Thu Jun 16 21:44:03 MDT 2011


The branch, master has been updated
       via  0c3075c s4-pysamdb: fixed the normalisation of grouptype in group add
       via  a826979 samba-tool: report total error count and suggest --fix if needed
       via  08dc1aa samba-tool: added attribute normalisation checks
       via  4905725 s4-dsdb: if we don't have a remote schema, then use the local one
       via  665ef94 s4-pydsdb: added dsdb_normalise_attributes() call
      from  5961852 s3:wb_lookupsids: add some paranoia checks to wb_lookupsids_recv()

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 0c3075cb57134f6171c332158c3052e05dace595
Author: Andrew Tridgell <tridge at samba.org>
Date:   Fri Jun 17 12:02:23 2011 +1000

    s4-pysamdb: fixed the normalisation of grouptype in group add
    
    ldap integers are signed
    
    Autobuild-User: Andrew Tridgell <tridge at samba.org>
    Autobuild-Date: Fri Jun 17 05:43:18 CEST 2011 on sn-devel-104

commit a8269792aa7c75b82b5ccab0e3b819601f7a4ef4
Author: Andrew Tridgell <tridge at samba.org>
Date:   Fri Jun 17 11:34:19 2011 +1000

    samba-tool: report total error count and suggest --fix if needed

commit 08dc1aa4cc1a697dd72db6a09a32d1929421fc09
Author: Andrew Tridgell <tridge at samba.org>
Date:   Fri Jun 17 11:31:25 2011 +1000

    samba-tool: added attribute normalisation checks
    
    this checks that all attributes have the right normalisation, and
    offers to fix the ones that don't

commit 49057255999fce2e4aa93de60dc80d40a655e61a
Author: Andrew Tridgell <tridge at samba.org>
Date:   Fri Jun 17 11:30:41 2011 +1000

    s4-dsdb: if we don't have a remote schema, then use the local one
    
    this allows the use of drsuapi_to_ldb() on all attributes for the
    local database

commit 665ef94d3c15ba59811143bb3d3e395ffd306a58
Author: Andrew Tridgell <tridge at samba.org>
Date:   Fri Jun 17 11:29:44 2011 +1000

    s4-pydsdb: added dsdb_normalise_attributes() call
    
    this call converts a set of attributes to DRSUAPI format and back to
    ldb format. This has the effect of normalising the attributes using
    the schema syntax rules

-----------------------------------------------------------------------

Summary of changes:
 source4/dsdb/pydsdb.c                            |  104 ++++++++++++++++++++++
 source4/dsdb/schema/schema_syntax.c              |   10 ++-
 source4/scripting/python/samba/netcmd/dbcheck.py |   69 +++++++++++++--
 source4/scripting/python/samba/samdb.py          |   13 +++-
 4 files changed, 187 insertions(+), 9 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source4/dsdb/pydsdb.c b/source4/dsdb/pydsdb.c
index 895bd9a..62f33bb 100644
--- a/source4/dsdb/pydsdb.c
+++ b/source4/dsdb/pydsdb.c
@@ -423,6 +423,109 @@ static PyObject *py_dsdb_DsReplicaAttribute(PyObject *self, PyObject *args)
 	return ret;
 }
 
+
+/*
+  normalise a ldb attribute list
+ */
+static PyObject *py_dsdb_normalise_attributes(PyObject *self, PyObject *args)
+{
+	PyObject *py_ldb, *el_list, *ret;
+	struct ldb_context *ldb;
+	char *ldap_display_name;
+	const struct dsdb_attribute *a;
+	struct dsdb_schema *schema;
+	struct dsdb_syntax_ctx syntax_ctx;
+	struct ldb_message_element *el;
+	struct drsuapi_DsReplicaAttribute *attr;
+	TALLOC_CTX *tmp_ctx;
+	WERROR werr;
+	Py_ssize_t i;
+
+	if (!PyArg_ParseTuple(args, "OsO", &py_ldb, &ldap_display_name, &el_list)) {
+		return NULL;
+	}
+
+	PyErr_LDB_OR_RAISE(py_ldb, ldb);
+
+	if (!PyList_Check(el_list)) {
+		PyErr_Format(PyExc_TypeError, "ldif_elements must be a list");
+		return NULL;
+	}
+
+	schema = dsdb_get_schema(ldb, NULL);
+	if (!schema) {
+		PyErr_SetString(PyExc_RuntimeError, "Failed to find a schema from ldb");
+		return NULL;
+	}
+
+	a = dsdb_attribute_by_lDAPDisplayName(schema, ldap_display_name);
+	if (a == NULL) {
+		PyErr_Format(PyExc_RuntimeError, "Failed to find attribute '%s'", ldap_display_name);
+		return NULL;
+	}
+
+	dsdb_syntax_ctx_init(&syntax_ctx, ldb, schema);
+	syntax_ctx.is_schema_nc = false;
+
+	tmp_ctx = talloc_new(ldb);
+	if (tmp_ctx == NULL) {
+		PyErr_NoMemory();
+		return NULL;
+	}
+
+	el = talloc_zero(tmp_ctx, struct ldb_message_element);
+	if (el == NULL) {
+		PyErr_NoMemory();
+		talloc_free(tmp_ctx);
+		return NULL;
+	}
+
+	el->name = ldap_display_name;
+	el->num_values = PyList_Size(el_list);
+
+	el->values = talloc_array(el, struct ldb_val, el->num_values);
+	if (el->values == NULL) {
+		PyErr_NoMemory();
+		talloc_free(tmp_ctx);
+		return NULL;
+	}
+
+	for (i = 0; i < el->num_values; i++) {
+		PyObject *item = PyList_GetItem(el_list, i);
+		if (!PyString_Check(item)) {
+			PyErr_Format(PyExc_TypeError, "ldif_elements should be strings");
+			return NULL;
+		}
+		el->values[i].data = (uint8_t *)PyString_AsString(item);
+		el->values[i].length = PyString_Size(item);
+	}
+
+	/* first run ldb_to_drsuapi, then convert back again. This has
+	 * the effect of normalising the attributes
+	 */
+
+	attr = talloc_zero(tmp_ctx, struct drsuapi_DsReplicaAttribute);
+	if (attr == NULL) {
+		PyErr_NoMemory();
+		talloc_free(tmp_ctx);
+		return NULL;
+	}
+
+	werr = a->syntax->ldb_to_drsuapi(&syntax_ctx, a, el, attr, attr);
+	PyErr_WERROR_IS_ERR_RAISE(werr);
+
+	/* now convert back again */
+	werr = a->syntax->drsuapi_to_ldb(&syntax_ctx, a, attr, el, el);
+	PyErr_WERROR_IS_ERR_RAISE(werr);
+
+	ret = py_return_ndr_struct("ldb", "MessageElement", el, el);
+
+	talloc_free(tmp_ctx);
+
+	return ret;
+}
+
+
 static PyObject *py_dsdb_set_ntds_invocation_id(PyObject *self, PyObject *args)
 {
 	PyObject *py_ldb, *py_guid;
@@ -723,6 +826,7 @@ static PyMethodDef py_dsdb_methods[] = {
 		NULL },
 	{ "_dsdb_get_partitions_dn", (PyCFunction)py_dsdb_get_partitions_dn, METH_VARARGS, NULL },
 	{ "_dsdb_DsReplicaAttribute", (PyCFunction)py_dsdb_DsReplicaAttribute, METH_VARARGS, NULL },
+	{ "_dsdb_normalise_attributes", (PyCFunction)py_dsdb_normalise_attributes, METH_VARARGS, NULL },
 	{ NULL }
 };
 
diff --git a/source4/dsdb/schema/schema_syntax.c b/source4/dsdb/schema/schema_syntax.c
index ea582db..75dc162 100644
--- a/source4/dsdb/schema/schema_syntax.c
+++ b/source4/dsdb/schema/schema_syntax.c
@@ -1069,8 +1069,14 @@ static WERROR _dsdb_syntax_OID_oid_drsuapi_to_ldb(const struct dsdb_syntax_ctx *
 						  struct ldb_message_element *out)
 {
 	unsigned int i;
+	const struct dsdb_schema_prefixmap *prefixmap;
 
-	SMB_ASSERT(ctx->pfm_remote);
+	if (ctx->pfm_remote != NULL) {
+		prefixmap = ctx->pfm_remote;
+	} else {
+		prefixmap = ctx->schema->prefixmap;
+	}
+	SMB_ASSERT(prefixmap);
 
 	out->flags	= 0;
 	out->name	= talloc_strdup(mem_ctx, attr->lDAPDisplayName);
@@ -1095,7 +1101,7 @@ static WERROR _dsdb_syntax_OID_oid_drsuapi_to_ldb(const struct dsdb_syntax_ctx *
 
 		attid = IVAL(in->value_ctr.values[i].blob->data, 0);
 
-		status = dsdb_schema_pfm_oid_from_attid(ctx->pfm_remote, attid,
+		status = dsdb_schema_pfm_oid_from_attid(prefixmap, attid,
 							out->values, &oid);
 		if (!W_ERROR_IS_OK(status)) {
 			DEBUG(0,(__location__ ": Error: Unknown ATTID 0x%08X\n",
diff --git a/source4/scripting/python/samba/netcmd/dbcheck.py b/source4/scripting/python/samba/netcmd/dbcheck.py
index 7af2101..9f12136 100644
--- a/source4/scripting/python/samba/netcmd/dbcheck.py
+++ b/source4/scripting/python/samba/netcmd/dbcheck.py
@@ -58,24 +58,71 @@ def empty_attribute(self, dn, attrname):
     print("Removed empty attribute %s" % attrname)
 
 
+def normalise_mismatch(self, dn, attrname, values):
+    '''fix attribute normalisation errors'''
+    print("ERROR: Normalisation error for attribute %s in %s" % (attrname, dn))
+    mod_list = []
+    for val in values:
+        normalised = self.samdb.dsdb_normalise_attributes(self.samdb, attrname, [val])
+        if len(normalised) != 1:
+            print("Unable to normalise value '%s'" % val)
+            mod_list.append((val, ''))
+        elif (normalised[0] != val):
+            print("value '%s' should be '%s'" % (val, normalised[0]))
+            mod_list.append((val, normalised[0]))
+    if not self.fix:
+        return
+    if not confirm(self, 'Fix normalisation for %s from %s?' % (attrname, dn)):
+        print("Not fixing attribute %s" % attrname)
+        return
+
+    m = ldb.Message()
+    m.dn = dn
+    for i in range(0, len(mod_list)):
+        (val, nval) = mod_list[i]
+        m['value_%u' % i] = ldb.MessageElement(val, ldb.FLAG_MOD_DELETE, attrname)
+        if nval != '':
+            m['normv_%u' % i] = ldb.MessageElement(nval, ldb.FLAG_MOD_ADD, attrname)
+
+    try:
+        self.samdb.modify(m, controls=["relax:0"], validate=False)
+    except Exception, msg:
+        print("Failed to normalise attribute %s : %s" % (attrname, msg))
+        return
+    print("Normalised attribute %s" % attrname)
+
+
 
 def check_object(self, dn):
     '''check one object'''
     if self.verbose:
         print("Checking object %s" % dn)
-    res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE)
+    res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, controls=["extended_dn:1:1"], attrs=['*', 'ntSecurityDescriptor'])
     if len(res) != 1:
         print("Object %s disappeared during check" % dn)
-        return
+        return 1
     obj = res[0]
+    error_count = 0
     for attrname in obj:
         if attrname == 'dn':
             continue
+
+        # check for empty attributes
         for val in obj[attrname]:
             if val == '':
                 empty_attribute(self, dn, attrname)
+                error_count += 1
                 continue
 
+        # check for incorrectly normalised attributes
+        for val in obj[attrname]:
+            normalised = self.samdb.dsdb_normalise_attributes(self.samdb, attrname, [val])
+            if len(normalised) != 1 or normalised[0] != val:
+                normalise_mismatch(self, dn, attrname, obj[attrname])
+                error_count += 1
+                break
+    return error_count
+
 
 class cmd_dbcheck(Command):
     """check local AD database for errors"""
@@ -96,11 +143,13 @@ class cmd_dbcheck(Command):
                help='Fix any errors found'),
         Option("--yes", dest="yes", default=False, action='store_true',
                help="don't confirm changes, just do them all"),
+        Option("--cross-ncs", dest="cross_ncs", default=False, action='store_true',
+               help="cross naming context boundaries"),
         Option("-v", "--verbose", dest="verbose", action="store_true", default=False,
             help="Print more details of checking"),
         ]
 
-    def run(self, DN=None, verbose=False, fix=False, yes=False,
+    def run(self, DN=None, verbose=False, fix=False, yes=False, cross_ncs=False,
             scope="SUB", credopts=None, sambaopts=None, versionopts=None):
         self.lp = sambaopts.get_loadparm()
         self.creds = credopts.get_credentials(self.lp, fallback_machine=True)
@@ -117,7 +166,15 @@ class cmd_dbcheck(Command):
             raise CommandError("Unknown scope %s" % scope)
         self.search_scope = scope_map[scope]
 
-        res = self.samdb.search(base=DN, scope=self.search_scope, attrs=['dn'])
+        controls = []
+        if cross_ncs:
+            controls.append("search_options:1:2")
+
+        res = self.samdb.search(base=DN, scope=self.search_scope, attrs=['dn'], controls=controls)
+        print('Checking %u objects' % len(res))
+        error_count = 0
         for object in res:
-            check_object(self, object.dn)
-        print('Checked %u objects' % len(res))
+            error_count += check_object(self, object.dn)
+        if error_count != 0 and not self.fix:
+            print("Please use --fix to fix these errors")
+        print('Checked %u objects (%u errors)' % (len(res), error_count))
diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py
index 55f3536..53346e8 100644
--- a/source4/scripting/python/samba/samdb.py
+++ b/source4/scripting/python/samba/samdb.py
@@ -142,7 +142,7 @@ pwdLastSet: 0
             "objectClass": "group"}
 
         if grouptype is not None:
-            ldbmessage["groupType"] = "%d" % grouptype
+            ldbmessage["groupType"] = self.normalise_int32(grouptype)
 
         if description is not None:
             ldbmessage["description"] = description
@@ -507,8 +507,13 @@ accountExpires: %u
         dsdb._dsdb_set_schema_from_ldb(self, ldb_conn)
 
     def dsdb_DsReplicaAttribute(self, ldb, ldap_display_name, ldif_elements):
+        '''convert a list of attribute values to a DRSUAPI DsReplicaAttribute'''
         return dsdb._dsdb_DsReplicaAttribute(ldb, ldap_display_name, ldif_elements)
 
+    def dsdb_normalise_attributes(self, ldb, ldap_display_name, ldif_elements):
+        '''normalise a list of attribute values'''
+        return dsdb._dsdb_normalise_attributes(ldb, ldap_display_name, ldif_elements)
+
     def get_attribute_from_attid(self, attid):
         """ Get from an attid the associated attribute
 
@@ -717,3 +722,9 @@ accountExpires: %u
         if sd:
             m["nTSecurityDescriptor"] = ndr_pack(sd)
         self.add(m)
+
+    def normalise_int32(self, ivalue):
+        '''normalise a ldap integer to signed 32 bit'''
+        if int(ivalue) & 0x80000000:
+            return str(int(ivalue) - 0x100000000)
+        return str(ivalue)


-- 
Samba Shared Repository


More information about the samba-cvs mailing list