[SCM] Samba Shared Repository - branch master updated

Andrew Bartlett abartlet at samba.org
Wed Jul 18 03:24:02 MDT 2012


The branch, master has been updated
       via  d0d05f8 s4-lib/tls: Try socket_send() multiple times to send partial packets
       via  02a356e s4-librpc: Ensure we do not call call the decrpc timeout handler during gensec_update()
       via  fc36ebf s4-dbcheck: Check for and correct incorrect instanceType values
       via  e4001a7 dsdb: Allocate new OID to allow updates of a read-only replica
       via  5630e25 s4-dsdb: Allow dbcheck to correct an incorrect instanceType
       via  96db134 s4-dsdb: Ensure we never write read-only objects onto a read-write replica
      from  127352c source4/torture: add talloc_stackframe()

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


- Log -----------------------------------------------------------------
commit d0d05f8474ed1882d373f042aba2c0209247678a
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Wed Jul 18 15:28:50 2012 +1000

    s4-lib/tls: Try socket_send() multiple times to send partial packets
    
    This works around an artificial limitation in socket_wrapper that breaks
    some versions of GnuTLS when we return a short write.
    
    Instead, keep pushing until the OS will not take it.
    
    The correct solution will be to use tls_tstream, but the client code
    for this is not yet tested and needs the ldap client layer changed
    to use it.
    
    Andrew Bartlett
    
    Autobuild-User(master): Andrew Bartlett <abartlet at samba.org>
    Autobuild-Date(master): Wed Jul 18 11:23:55 CEST 2012 on sn-devel-104

commit 02a356ea775a3ba589cb50af3c861ab86aaffa0b
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Mon Jul 9 14:37:28 2012 +1000

    s4-librpc: Ensure we do not call call the decrpc timeout handler during gensec_update()
    
    This avoids a situation where we could destroy pointers on the stack due to
    a nested event loop.
    
    This is certainly not a final, generic solution, but it is a minimal change
    while we work to make gensec and gensec_gssapi async.
    
    Andrew Bartlett

commit fc36ebfa7861cf7e86aa3c2110a6ab213424e8c1
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Jul 17 11:10:41 2012 +1000

    s4-dbcheck: Check for and correct incorrect instanceType values

commit e4001a78c1d0b286b37e19c733cf1bbc18166818
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Wed Jul 18 17:13:30 2012 +1000

    dsdb: Allocate new OID to allow updates of a read-only replica
    
    Normally this would be a very bad idea, but the specific case of fixing the instanceType
    is the only case where this makes sense.
    
    Andrew Bartlett

commit 5630e25a35ea95ca848281933a5a3a96306986a4
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Jul 17 11:10:12 2012 +1000

    s4-dsdb: Allow dbcheck to correct an incorrect instanceType

commit 96db13405bce8fa6d08b8b802439a606643e6db4
Author: Andrew Bartlett <abartlet at samba.org>
Date:   Tue Jul 17 15:48:15 2012 +1000

    s4-dsdb: Ensure we never write read-only objects onto a read-write replica
    
    We should prevent this much further up the stack, but at least add a choke
    at this point for now.
    
    Additionally, this avoids administrator-forced replications causing
    considerable damange to the directory.
    
    Andrew Bartlett

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

Summary of changes:
 source4/dsdb/pydsdb.c                              |    1 +
 source4/dsdb/repl/replicated_objects.c             |    9 ++++-
 source4/dsdb/samdb/ldb_modules/instancetype.c      |    8 ++-
 source4/dsdb/samdb/ldb_modules/objectclass_attrs.c |   12 ++++--
 source4/dsdb/samdb/ldb_modules/repl_meta_data.c    |    3 +-
 source4/dsdb/samdb/samdb.h                         |    3 +
 source4/lib/tls/tls.c                              |   39 +++++++++++------
 source4/librpc/rpc/dcerpc.h                        |    8 ++++
 source4/librpc/rpc/dcerpc_auth.c                   |   17 +++++++
 source4/librpc/rpc/dcerpc_connect.c                |   19 ++++++--
 source4/scripting/python/samba/dbchecker.py        |   45 ++++++++++++++++++++
 source4/setup/schema_samba4.ldif                   |    1 +
 12 files changed, 138 insertions(+), 27 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source4/dsdb/pydsdb.c b/source4/dsdb/pydsdb.c
index f63d71e..b9e1dd7 100644
--- a/source4/dsdb/pydsdb.c
+++ b/source4/dsdb/pydsdb.c
@@ -1269,6 +1269,7 @@ void initdsdb(void)
 	ADD_DSDB_STRING(DSDB_SYNTAX_STRING_DN);
 	ADD_DSDB_STRING(DSDB_SYNTAX_OR_NAME);
 	ADD_DSDB_STRING(DSDB_CONTROL_DBCHECK);
+	ADD_DSDB_STRING(DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA);
 
 	ADD_DSDB_STRING(DS_GUID_COMPUTERS_CONTAINER);
 	ADD_DSDB_STRING(DS_GUID_DELETED_OBJECTS_CONTAINER);
diff --git a/source4/dsdb/repl/replicated_objects.c b/source4/dsdb/repl/replicated_objects.c
index ec4dffe..67999df 100644
--- a/source4/dsdb/repl/replicated_objects.c
+++ b/source4/dsdb/repl/replicated_objects.c
@@ -202,6 +202,7 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
 	uint32_t i;
 	struct ldb_message *msg;
 	struct replPropertyMetaDataBlob *md;
+	int instanceType;
 	struct ldb_val guid_value;
 	struct ldb_val parent_guid_value;
 	NTTIME whenChanged = 0;
@@ -352,12 +353,12 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
 
 	}
 
+	instanceType = ldb_msg_find_attr_as_int(msg, "instanceType", 0);
 	if (dsdb_repl_flags & DSDB_REPL_FLAG_PARTIAL_REPLICA) {
 		/* the instanceType type for partial_replica
 		   replication is sent via DRS with TYPE_WRITE set, but
 		   must be used on the client with TYPE_WRITE removed
 		*/
-		int instanceType = ldb_msg_find_attr_as_int(msg, "instanceType", 0);
 		if (instanceType & INSTANCE_TYPE_WRITE) {
 			instanceType &= ~INSTANCE_TYPE_WRITE;
 			ldb_msg_remove_attr(msg, "instanceType");
@@ -365,6 +366,12 @@ WERROR dsdb_convert_object_ex(struct ldb_context *ldb,
 				return WERR_INTERNAL_ERROR;
 			}
 		}
+	} else {
+		if (!(instanceType & INSTANCE_TYPE_WRITE)) {
+			DEBUG(0, ("Refusing to replicate %s from a read-only repilca into a read-write replica!\n",
+				  ldb_dn_get_linearized(msg->dn)));
+			return WERR_DS_DRA_SOURCE_IS_PARTIAL_REPLICA;
+		}
 	}
 
 	whenChanged_t = nt_time_to_unix(whenChanged);
diff --git a/source4/dsdb/samdb/ldb_modules/instancetype.c b/source4/dsdb/samdb/ldb_modules/instancetype.c
index d743d4f..7bf95f3 100644
--- a/source4/dsdb/samdb/ldb_modules/instancetype.c
+++ b/source4/dsdb/samdb/ldb_modules/instancetype.c
@@ -136,10 +136,12 @@ static int instancetype_mod(struct ldb_module *module, struct ldb_request *req)
 
 	el = ldb_msg_find_element(req->op.mod.message, "instanceType");
 	if (el != NULL) {
-		ldb_set_errstring(ldb, "instancetype: the 'instanceType' attribute can never be changed!");
-		return LDB_ERR_CONSTRAINT_VIOLATION;
+		/* Except to allow dbcheck to fix things, this must never be modified */
+		if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
+			ldb_set_errstring(ldb, "instancetype: the 'instanceType' attribute can never be changed!");
+			return LDB_ERR_CONSTRAINT_VIOLATION;
+		}
 	}
-
 	return ldb_next_request(module, req);
 }
 
diff --git a/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c b/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c
index e50c8e2..c521f33 100644
--- a/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c
+++ b/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c
@@ -408,10 +408,14 @@ static int attr_handler2(struct oc_context *ac)
 			found = str_list_check(harmless_attrs, attr->lDAPDisplayName);
 		}
 		if (!found) {
-			ldb_asprintf_errstring(ldb, "objectclass_attrs: attribute '%s' on entry '%s' does not exist in the specified objectclasses!",
-					       msg->elements[i].name,
-					       ldb_dn_get_linearized(msg->dn));
-			return LDB_ERR_OBJECT_CLASS_VIOLATION;
+			/* we allow this for dbcheck to fix the rest of this broken entry */
+			if (!ldb_request_get_control(ac->req, DSDB_CONTROL_DBCHECK) || 
+			    ac->req->operation == LDB_ADD) {
+				ldb_asprintf_errstring(ldb, "objectclass_attrs: attribute '%s' on entry '%s' does not exist in the specified objectclasses!",
+						       msg->elements[i].name,
+						       ldb_dn_get_linearized(msg->dn));
+				return LDB_ERR_OBJECT_CLASS_VIOLATION;
+			}
 		}
 	}
 
diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
index 1dc7ea0..6f26299 100644
--- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
+++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c
@@ -1391,7 +1391,8 @@ static int replmd_update_rpmd(struct ldb_module *module,
 		struct ldb_message_element *el;
 
 		/*if we are RODC and this is a DRSR update then its ok*/
-		if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
+		if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)
+		    && !ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) {
 			unsigned instanceType;
 
 			ret = samdb_rodc(ldb, rodc);
diff --git a/source4/dsdb/samdb/samdb.h b/source4/dsdb/samdb/samdb.h
index 5422218..c4cb3bd 100644
--- a/source4/dsdb/samdb/samdb.h
+++ b/source4/dsdb/samdb/samdb.h
@@ -122,6 +122,9 @@ struct dsdb_control_password_change {
 /* passed when we want special behaviour for dbcheck */
 #define DSDB_CONTROL_DBCHECK "1.3.6.1.4.1.7165.4.3.19"
 
+/* passed when dbcheck wants to modify a read only replica (very special case) */
+#define DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA "1.3.6.1.4.1.7165.4.3.19.1"
+
 /* passed when importing plain text password on upgrades */
 #define DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID "1.3.6.1.4.1.7165.4.3.20"
 
diff --git a/source4/lib/tls/tls.c b/source4/lib/tls/tls.c
index 7bf2ff8..db6d1eb 100644
--- a/source4/lib/tls/tls.c
+++ b/source4/lib/tls/tls.c
@@ -152,7 +152,7 @@ static ssize_t tls_push(gnutls_transport_ptr ptr, const void *buf, size_t size)
 {
 	struct tls_context *tls = talloc_get_type(ptr, struct tls_context);
 	NTSTATUS status;
-	size_t nwritten;
+	size_t nwritten, total_nwritten = 0;
 	DATA_BLOB b;
 
 	if (!tls->tls_enabled) {
@@ -162,19 +162,32 @@ static ssize_t tls_push(gnutls_transport_ptr ptr, const void *buf, size_t size)
 	b.data = discard_const(buf);
 	b.length = size;
 
-	status = socket_send(tls->socket, &b, &nwritten);
-	if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
-		errno = EAGAIN;
-		return -1;
-	}
-	if (!NT_STATUS_IS_OK(status)) {
-		TEVENT_FD_WRITEABLE(tls->fde);
-		return -1;
-	}
-	if (size != nwritten) {
+	/* Cope with socket_wrapper 1500 byte chunking for PCAP */
+	do {
+		status = socket_send(tls->socket, &b, &nwritten);
+		
+		if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {
+			errno = EAGAIN;
+			return -1;
+		}
+		if (!NT_STATUS_IS_OK(status)) {
+			TEVENT_FD_WRITEABLE(tls->fde);
+			return -1;
+		}
+
+		total_nwritten += nwritten;
+
+		if (size == nwritten) {
+			break;
+		}
+
+		b.data += nwritten;
+		b.length -= nwritten;
+
 		TEVENT_FD_WRITEABLE(tls->fde);
-	}
-	return nwritten;
+	} while (b.length);
+
+	return total_nwritten;
 }
 
 /*
diff --git a/source4/librpc/rpc/dcerpc.h b/source4/librpc/rpc/dcerpc.h
index 359efda..ef83086 100644
--- a/source4/librpc/rpc/dcerpc.h
+++ b/source4/librpc/rpc/dcerpc.h
@@ -124,6 +124,14 @@ struct dcerpc_pipe {
 
 	/** timeout for individual rpc requests, in seconds */
 	uint32_t request_timeout;
+
+	/*
+	 * Set for the timeout in dcerpc_pipe_connect_b_send(), to
+	 * allow the timeout not to destory the stack during a nested
+	 * event loop caused by gensec_update()
+	 */
+	bool inhibit_timeout_processing;
+	bool timed_out;
 };
 
 /* default timeout for all rpc requests, in seconds */
diff --git a/source4/librpc/rpc/dcerpc_auth.c b/source4/librpc/rpc/dcerpc_auth.c
index cedcdd1..d5e5620 100644
--- a/source4/librpc/rpc/dcerpc_auth.c
+++ b/source4/librpc/rpc/dcerpc_auth.c
@@ -151,10 +151,19 @@ static void bind_auth_next_step(struct composite_context *c)
 	 * it doesn't like that either
 	 */
 
+	state->pipe->inhibit_timeout_processing = true;
+	state->pipe->timed_out = false;
+
 	c->status = gensec_update(sec->generic_state, state,
 				  state->pipe->conn->event_ctx,
 				  sec->auth_info->credentials,
 				  &state->credentials);
+	if (state->pipe->timed_out) {
+		composite_error(c, NT_STATUS_IO_TIMEOUT);
+		return;
+	}
+	state->pipe->inhibit_timeout_processing = false;
+
 	data_blob_free(&sec->auth_info->credentials);
 
 	if (NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
@@ -358,10 +367,18 @@ struct composite_context *dcerpc_bind_auth_send(TALLOC_CTX *mem_ctx,
 	 * it doesn't like that either
 	 */
 
+	state->pipe->inhibit_timeout_processing = true;
+	state->pipe->timed_out = false;
 	c->status = gensec_update(sec->generic_state, state,
 				  p->conn->event_ctx,
 				  sec->auth_info->credentials,
 				  &state->credentials);
+	if (state->pipe->timed_out) {
+		composite_error(c, NT_STATUS_IO_TIMEOUT);
+		return c;
+	}
+	state->pipe->inhibit_timeout_processing = false;
+
 	if (!NT_STATUS_IS_OK(c->status) &&
 	    !NT_STATUS_EQUAL(c->status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
 		composite_error(c, c->status);
diff --git a/source4/librpc/rpc/dcerpc_connect.c b/source4/librpc/rpc/dcerpc_connect.c
index 8cf60e6..821499e 100644
--- a/source4/librpc/rpc/dcerpc_connect.c
+++ b/source4/librpc/rpc/dcerpc_connect.c
@@ -716,8 +716,14 @@ static void continue_pipe_auth(struct composite_context *ctx)
 static void dcerpc_connect_timeout_handler(struct tevent_context *ev, struct tevent_timer *te, 
 					   struct timeval t, void *private_data)
 {
-	struct composite_context *c = talloc_get_type(private_data, struct composite_context);
-	composite_error(c, NT_STATUS_IO_TIMEOUT);
+	struct composite_context *c = talloc_get_type(private_data,
+						      struct composite_context);
+	struct pipe_connect_state *s = talloc_get_type(c->private_data, struct pipe_connect_state);
+	if (!s->pipe->inhibit_timeout_processing) {
+		composite_error(c, NT_STATUS_IO_TIMEOUT);
+	} else {
+		s->pipe->timed_out = true;
+	}
 }
 
 /*
@@ -757,9 +763,12 @@ _PUBLIC_ struct composite_context* dcerpc_pipe_connect_b_send(TALLOC_CTX *parent
 	s->credentials  = credentials;
 	s->lp_ctx 	= lp_ctx;
 
-	tevent_add_timer(c->event_ctx, c,
-			timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
-			dcerpc_connect_timeout_handler, c);
+	s->pipe->timed_out = false;
+	s->pipe->inhibit_timeout_processing = false;
+
+	tevent_add_timer(c->event_ctx, s,
+			 timeval_current_ofs(DCERPC_REQUEST_TIMEOUT, 0),
+			 dcerpc_connect_timeout_handler, s);
 	
 	switch (s->binding->transport) {
 	case NCA_UNKNOWN: {
diff --git a/source4/scripting/python/samba/dbchecker.py b/source4/scripting/python/samba/dbchecker.py
index 284c529..03ec7ab 100644
--- a/source4/scripting/python/samba/dbchecker.py
+++ b/source4/scripting/python/samba/dbchecker.py
@@ -51,11 +51,19 @@ class dbcheck(object):
         self.fix_rmd_flags = False
         self.seize_fsmo_role = False
         self.move_to_lost_and_found = False
+        self.fix_instancetype = False
         self.in_transaction = in_transaction
         self.infrastructure_dn = ldb.Dn(samdb, "CN=Infrastructure," + samdb.domain_dn())
         self.naming_dn = ldb.Dn(samdb, "CN=Partitions,%s" % samdb.get_config_basedn())
         self.schema_dn = samdb.get_schema_basedn()
         self.rid_dn = ldb.Dn(samdb, "CN=RID Manager$,CN=System," + samdb.domain_dn())
+        self.ntds_dsa = samdb.get_dsServiceName()
+
+        res = self.samdb.search(base=self.ntds_dsa, scope=ldb.SCOPE_BASE, attrs=['msDS-hasMasterNCs'])
+        if "msDS-hasMasterNCs" in res[0]:
+            self.write_ncs = res[0]["msDS-hasMasterNCs"]
+        else:
+            self.write_ncs = None
 
     def check_database(self, DN=None, scope=ldb.SCOPE_SUBTREE, controls=[], attrs=['*']):
         '''perform a database check, returning the number of errors found'''
@@ -366,6 +374,20 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
                           "Failed to rename object %s into lostAndFound at %s" % (obj.dn, new_dn + lost_and_found)):
             self.report("Renamed object %s into lostAndFound at %s" % (obj.dn, new_dn + lost_and_found))
 
+    def err_wrong_instancetype(self, obj, calculated_instancetype):
+        '''handle a wrong instanceType'''
+        self.report("ERROR: wrong instanceType %s on %s, should be %d" % (obj["instanceType"], obj.dn, calculated_instancetype))
+        if not self.confirm_all('Change instanceType from %s to %d on %s?' % (obj["instanceType"], calculated_instancetype, obj.dn), 'fix_instancetype'):
+            self.report('Not changing instanceType from %s to %d on %s' % (obj["instanceType"], calculated_instancetype, obj.dn))
+            return
+
+        m = ldb.Message()
+        m.dn = obj.dn
+        m['value'] = ldb.MessageElement(str(calculated_instancetype), ldb.FLAG_MOD_REPLACE, 'instanceType')
+        if self.do_modify(m, ["local_oid:%s:0" % dsdb.DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA],
+                          "Failed to correct missing instanceType on %s by setting instanceType=%d" % (obj.dn, calculated_instancetype)):
+            self.report("Corrected instancetype on %s by setting instanceType=%d" % (obj.dn, calculated_instancetype))
+
     def find_revealed_link(self, dn, attrname, guid):
         '''return a revealed link in an object'''
         res = self.samdb.search(base=dn, scope=ldb.SCOPE_BASE, attrs=[attrname],
@@ -511,6 +533,24 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
         
         return False
 
+    def calculate_instancetype(self, dn):
+        instancetype = 0
+        nc_root = self.samdb.get_nc_root(dn)
+        if dn == nc_root:
+            instancetype |= dsdb.INSTANCE_TYPE_IS_NC_HEAD
+            try:
+                self.samdb.search(base=dn.parent(), scope=ldb.SCOPE_BASE, attrs=[], controls=["show_recycled:1"])
+            except ldb.LdbError, (enum, estr):
+                if enum != ldb.ERR_NO_SUCH_OBJECT:
+                    raise
+            else:
+                instancetype |= dsdb.INSTANCE_TYPE_NC_ABOVE
+
+        if self.write_ncs is not None and str(nc_root) in self.write_ncs:
+            instancetype |= dsdb.INSTANCE_TYPE_WRITE
+
+        return instancetype
+
     def check_object(self, dn, attrs=['*']):
         '''check one object'''
         if self.verbose:
@@ -589,6 +629,11 @@ newSuperior: %s""" % (str(from_dn), str(to_rdn), str(to_base)))
                     error_count += 1
                     break
 
+            if str(attrname).lower() == "instancetype":
+                calculated_instancetype = self.calculate_instancetype(dn)
+                if len(obj["instanceType"]) != 1 or obj["instanceType"][0] != str(calculated_instancetype):
+                    self.err_wrong_instancetype(obj, calculated_instancetype)
+
         show_dn = True
         if got_repl_property_meta_data:
             rdn = (str(dn).split(","))[0]
diff --git a/source4/setup/schema_samba4.ldif b/source4/setup/schema_samba4.ldif
index 3d004c5..0c5c787 100644
--- a/source4/setup/schema_samba4.ldif
+++ b/source4/setup/schema_samba4.ldif
@@ -194,6 +194,7 @@
 #Allocated: DSDB_CONTROL_NO_GLOBAL_CATALOG 1.3.6.1.4.1.7165.4.3.17
 #Allocated: DSDB_CONTROL_PARTIAL_REPLICA 1.3.6.1.4.1.7165.4.3.18
 #Allocated: DSDB_CONTROL_DBCHECK 1.3.6.1.4.1.7165.4.3.19
+#Allocated: DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA 1.3.6.1.4.1.7165.4.3.19.1
 #Allocated: DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID 1.3.6.1.4.1.7165.4.3.20
 
 # Extended 1.3.6.1.4.1.7165.4.4.x


-- 
Samba Shared Repository


More information about the samba-cvs mailing list