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 <[email protected]>
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 <[email protected]>
    Autobuild-Date(master): Wed Jul 18 11:23:55 CEST 2012 on sn-devel-104

commit 02a356ea775a3ba589cb50af3c861ab86aaffa0b
Author: Andrew Bartlett <[email protected]>
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 <[email protected]>
Date:   Tue Jul 17 11:10:41 2012 +1000

    s4-dbcheck: Check for and correct incorrect instanceType values

commit e4001a78c1d0b286b37e19c733cf1bbc18166818
Author: Andrew Bartlett <[email protected]>
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 <[email protected]>
Date:   Tue Jul 17 11:10:12 2012 +1000

    s4-dsdb: Allow dbcheck to correct an incorrect instanceType

commit 96db13405bce8fa6d08b8b802439a606643e6db4
Author: Andrew Bartlett <[email protected]>
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

Reply via email to