[SCM] Samba Shared Repository - branch master updated

Michael Adam obnox at samba.org
Tue Feb 19 05:57:02 MST 2013


The branch, master has been updated
       via  5ab7725 s3:net: new implementation of "servid wipedbs" with smbXsrv_*
       via  d8dd0ec lib/util_tdb: factor out tdb_data_talloc_copy()
       via  d23f19a s3:smbXsrv_open: add smbXsrv_open_global_traverse()
       via  60721a3 s3:smbXsrv_tcon: pass record in smbXsrv_tcon_global_traverse()
       via  93e22bb s3:smbXsrv_session: pass record in smbXsrv_session_global_traverse()
      from  bdb80ae s3:smbd:smb2: fix segfault (access after free) in durable disconnect code

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


- Log -----------------------------------------------------------------
commit 5ab77259746ef3811a64f6c7880ae2263d512c16
Author: Gregor Beck <gbeck at sernet.de>
Date:   Thu Dec 13 13:00:28 2012 +0100

    s3:net: new implementation of "servid wipedbs" with smbXsrv_*
    
    Signed-off-by: Gregor Beck <gbeck at sernet.de>
    Reviewed-by: Michael Adam <obnox at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>
    
    Autobuild-User(master): Michael Adam <obnox at samba.org>
    Autobuild-Date(master): Tue Feb 19 13:56:57 CET 2013 on sn-devel-104

commit d8dd0ecc484ccc0c3450c3e96725e56e8bf1a9ef
Author: Gregor Beck <gbeck at sernet.de>
Date:   Thu Jan 10 11:09:09 2013 +0100

    lib/util_tdb: factor out tdb_data_talloc_copy()
    
    Signed-off-by: Gregor Beck <gbeck at sernet.de>
    Reviewed-by: Michael Adam <obnox at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>

commit d23f19ab00314d773edb07a45e754365db378668
Author: Gregor Beck <gbeck at sernet.de>
Date:   Wed Dec 12 16:06:50 2012 +0100

    s3:smbXsrv_open: add smbXsrv_open_global_traverse()
    
    Signed-off-by: Gregor Beck <gbeck at sernet.de>
    Reviewed-by: Michael Adam <obnox at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>

commit 60721a378240cb08e3f2ac0a1de14df5c9130010
Author: Gregor Beck <gbeck at sernet.de>
Date:   Thu Dec 13 15:27:07 2012 +0100

    s3:smbXsrv_tcon: pass record in smbXsrv_tcon_global_traverse()
    
    Signed-off-by: Gregor Beck <gbeck at sernet.de>
    Reviewed-by: Michael Adam <obnox at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>

commit 93e22bb1c401b423b0242e6923b8e7944f793b3f
Author: Gregor Beck <gbeck at sernet.de>
Date:   Thu Dec 13 15:26:49 2012 +0100

    s3:smbXsrv_session: pass record in smbXsrv_session_global_traverse()
    
    Signed-off-by: Gregor Beck <gbeck at sernet.de>
    Reviewed-by: Michael Adam <obnox at samba.org>
    Reviewed-by: Stefan Metzmacher <metze at samba.org>

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

Summary of changes:
 lib/util/util_tdb.c             |   15 +
 lib/util/util_tdb.h             |    1 +
 source3/smbd/globals.h          |    4 +
 source3/smbd/smbXsrv_open.c     |   73 +++++
 source3/smbd/smbXsrv_session.c  |    1 +
 source3/smbd/smbXsrv_tcon.c     |    1 +
 source3/utils/net_idmap_check.c |   23 +--
 source3/utils/net_serverid.c    |  566 ++++++++++++++++++++++++++++++++++++++-
 8 files changed, 663 insertions(+), 21 deletions(-)


Changeset truncated at 500 lines:

diff --git a/lib/util/util_tdb.c b/lib/util/util_tdb.c
index c005c82..93df958 100644
--- a/lib/util/util_tdb.c
+++ b/lib/util/util_tdb.c
@@ -63,6 +63,21 @@ TDB_DATA string_term_tdb_data(const char *string)
 	return make_tdb_data((const uint8_t *)string, string ? strlen(string) + 1 : 0);
 }
 
+TDB_DATA tdb_data_talloc_copy(TALLOC_CTX* mem_ctx, TDB_DATA data) {
+	TDB_DATA ret = {
+		.dptr  = (uint8_t *)talloc_size(mem_ctx, data.dsize+1),
+		.dsize = data.dsize
+	};
+	if (ret.dptr == NULL) {
+		ret.dsize = 0;
+	} else {
+		memcpy(ret.dptr, data.dptr, data.dsize);
+		ret.dptr[ret.dsize] = '\0';
+	}
+	return ret;
+}
+
+
 /****************************************************************************
  Lock a chain by string. Return non-zero if lock failed.
 ****************************************************************************/
diff --git a/lib/util/util_tdb.h b/lib/util/util_tdb.h
index d8a2333..630bdf6 100644
--- a/lib/util/util_tdb.h
+++ b/lib/util/util_tdb.h
@@ -30,6 +30,7 @@ bool tdb_data_equal(TDB_DATA t1, TDB_DATA t2);
 bool tdb_data_is_empty(TDB_DATA d);
 TDB_DATA string_tdb_data(const char *string);
 TDB_DATA string_term_tdb_data(const char *string);
+TDB_DATA tdb_data_talloc_copy(TALLOC_CTX* mem_ctx, TDB_DATA data);
 
 /****************************************************************************
  Lock a chain by string. Return non-zero if lock failed.
diff --git a/source3/smbd/globals.h b/source3/smbd/globals.h
index 6ead962..90e9ab4 100644
--- a/source3/smbd/globals.h
+++ b/source3/smbd/globals.h
@@ -457,6 +457,10 @@ NTSTATUS smb2srv_open_recreate(struct smbXsrv_connection *conn,
 			       struct GUID create_guid,
 			       NTTIME now,
 			       struct smbXsrv_open **_open);
+struct smbXsrv_open_global0;
+NTSTATUS smbXsrv_open_global_traverse(
+	int (*fn)(struct smbXsrv_open_global0 *, void *),
+	void *private_data);
 
 struct smbd_smb2_request {
 	struct smbd_smb2_request *prev, *next;
diff --git a/source3/smbd/smbXsrv_open.c b/source3/smbd/smbXsrv_open.c
index be39cbc..2c2798b 100644
--- a/source3/smbd/smbXsrv_open.c
+++ b/source3/smbd/smbXsrv_open.c
@@ -1277,3 +1277,76 @@ NTSTATUS smb2srv_open_recreate(struct smbXsrv_connection *conn,
 	*_open = op;
 	return NT_STATUS_OK;
 }
+
+
+struct smbXsrv_open_global_traverse_state {
+	int (*fn)(struct smbXsrv_open_global0 *, void *);
+	void *private_data;
+};
+
+static int smbXsrv_open_global_traverse_fn(struct db_record *rec, void *data)
+{
+	int ret = -1;
+	struct smbXsrv_open_global_traverse_state *state =
+		(struct smbXsrv_open_global_traverse_state*)data;
+	TDB_DATA key = dbwrap_record_get_key(rec);
+	TDB_DATA val = dbwrap_record_get_value(rec);
+	DATA_BLOB blob = data_blob_const(val.dptr, val.dsize);
+	struct smbXsrv_open_globalB global_blob;
+	enum ndr_err_code ndr_err;
+	TALLOC_CTX *frame = talloc_stackframe();
+
+	ndr_err = ndr_pull_struct_blob(&blob, frame, &global_blob,
+			(ndr_pull_flags_fn_t)ndr_pull_smbXsrv_open_globalB);
+	if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
+		DEBUG(1,("Invalid record in smbXsrv_open_global.tdb:"
+			 "key '%s' ndr_pull_struct_blob - %s\n",
+			 hex_encode_talloc(frame, key.dptr, key.dsize),
+			 ndr_errstr(ndr_err)));
+		goto done;
+	}
+
+	if (global_blob.version != SMBXSRV_VERSION_0) {
+		DEBUG(1,("Invalid record in smbXsrv_open_global.tdb:"
+			 "key '%s' unsuported version - %d\n",
+			 hex_encode_talloc(frame, key.dptr, key.dsize),
+			 (int)global_blob.version));
+		goto done;
+	}
+
+	global_blob.info.info0->db_rec = rec;
+	ret = state->fn(global_blob.info.info0, state->private_data);
+done:
+	TALLOC_FREE(frame);
+	return ret;
+}
+
+NTSTATUS smbXsrv_open_global_traverse(
+			int (*fn)(struct smbXsrv_open_global0 *, void *),
+			void *private_data)
+{
+
+	NTSTATUS status;
+	int count = 0;
+	struct smbXsrv_open_global_traverse_state state = {
+		.fn = fn,
+		.private_data = private_data,
+	};
+
+	become_root();
+	status = smbXsrv_open_global_init();
+	if (!NT_STATUS_IS_OK(status)) {
+		unbecome_root();
+		DEBUG(0, ("Failed to initialize open_global: %s\n",
+			  nt_errstr(status)));
+		return status;
+	}
+
+	status = dbwrap_traverse_read(smbXsrv_open_global_db_ctx,
+				      smbXsrv_open_global_traverse_fn,
+				      &state,
+				      &count);
+	unbecome_root();
+
+	return status;
+}
diff --git a/source3/smbd/smbXsrv_session.c b/source3/smbd/smbXsrv_session.c
index f3072ee..017880c 100644
--- a/source3/smbd/smbXsrv_session.c
+++ b/source3/smbd/smbXsrv_session.c
@@ -1560,6 +1560,7 @@ static int smbXsrv_session_global_traverse_fn(struct db_record *rec, void *data)
 		goto done;
 	}
 
+	global_blob.info.info0->db_rec = rec;
 	ret = state->fn(global_blob.info.info0, state->private_data);
 done:
 	TALLOC_FREE(frame);
diff --git a/source3/smbd/smbXsrv_tcon.c b/source3/smbd/smbXsrv_tcon.c
index 49da84d..b6e2058 100644
--- a/source3/smbd/smbXsrv_tcon.c
+++ b/source3/smbd/smbXsrv_tcon.c
@@ -1200,6 +1200,7 @@ static int smbXsrv_tcon_global_traverse_fn(struct db_record *rec, void *data)
 		goto done;
 	}
 
+	global_blob.info.info0->db_rec = rec;
 	ret = state->fn(global_blob.info.info0, state->private_data);
 done:
 	TALLOC_FREE(frame);
diff --git a/source3/utils/net_idmap_check.c b/source3/utils/net_idmap_check.c
index 4174238..e75c890 100644
--- a/source3/utils/net_idmap_check.c
+++ b/source3/utils/net_idmap_check.c
@@ -42,7 +42,6 @@ static int traverse_check(struct db_record *rec, void* data);
 /* TDB_DATA *******************************************************************/
 static char*    print_data(TALLOC_CTX* mem_ctx, TDB_DATA d);
 static TDB_DATA parse_data(TALLOC_CTX* mem_ctx, const char** ptr);
-static TDB_DATA talloc_copy(TALLOC_CTX* mem_ctx, TDB_DATA data);
 
 /* record *********************************************************************/
 
@@ -325,7 +324,7 @@ static int add_record(struct check_ctx* ctx, TDB_DATA key, TDB_DATA value)
 		diff = unpack_diff(recvalue);
 		talloc_free(diff.nval.dptr);
 	}
-	diff.nval = talloc_copy(ctx->diff, value);
+	diff.nval = tdb_data_talloc_copy(ctx->diff, value);
 
 	DEBUG_DIFF(2, mem, "TDB DIFF", key, diff.oval, diff.nval);
 
@@ -355,7 +354,7 @@ fetch_record(struct check_ctx* ctx, TALLOC_CTX* mem_ctx, TDB_DATA key)
 
 	if (NT_STATUS_IS_OK(status)) {
 		TDB_DATA_diff diff = unpack_diff(tmp);
-		TDB_DATA ret = talloc_copy(mem_ctx, diff.nval);
+		TDB_DATA ret = tdb_data_talloc_copy(mem_ctx, diff.nval);
 		talloc_free(tmp.dptr);
 		return ret;
 	}
@@ -548,20 +547,6 @@ void adjust_hwm(struct check_ctx* ctx, const struct record* r) {
 	}
 }
 
-TDB_DATA talloc_copy(TALLOC_CTX* mem_ctx, TDB_DATA data) {
-	TDB_DATA ret = {
-		.dptr  = (uint8_t *)talloc_size(mem_ctx, data.dsize+1),
-		.dsize = data.dsize
-	};
-	if (ret.dptr == NULL) {
-		ret.dsize = 0;
-	} else {
-		memcpy(ret.dptr, data.dptr, data.dsize);
-		ret.dptr[ret.dsize] = '\0';
-	}
-	return ret;
-}
-
 static bool is_cstr(TDB_DATA str) {
 	return !tdb_data_is_empty(str) && str.dptr[str.dsize-1] == '\0';
 }
@@ -603,8 +588,8 @@ parse_record(TALLOC_CTX* mem_ctx, TDB_DATA key, TDB_DATA val)
 		DEBUG(0, ("Out of memory.\n"));
 		return NULL;
 	}
-	ret->key = talloc_copy(ret, key);
-	ret->val = talloc_copy(ret, val);
+	ret->key = tdb_data_talloc_copy(ret, key);
+	ret->val = tdb_data_talloc_copy(ret, val);
 	if ((ret->key.dptr == NULL && key.dptr != NULL) ||
 	    (ret->val.dptr == NULL && val.dptr != NULL))
 	{
diff --git a/source3/utils/net_serverid.c b/source3/utils/net_serverid.c
index 2d25ba7..90448c1 100644
--- a/source3/utils/net_serverid.c
+++ b/source3/utils/net_serverid.c
@@ -20,9 +20,12 @@
 #include "includes.h"
 #include "utils/net.h"
 #include "dbwrap/dbwrap.h"
+#include "dbwrap/dbwrap_rbt.h"
 #include "serverid.h"
 #include "session.h"
 #include "lib/conn_tdb.h"
+#include "smbd/globals.h"
+#include "util_tdb.h"
 
 static int net_serverid_list_fn(const struct server_id *id,
 				uint32_t msg_flags, void *priv)
@@ -66,11 +69,570 @@ static int net_serverid_wipe(struct net_context *c, int argc,
 	return serverid_traverse(net_serverid_wipe_fn, NULL) ? 0 : -1;
 }
 
+
+struct wipedbs_record_marker {
+	struct wipedbs_record_marker *prev, *next;
+	TDB_DATA key, val;
+	const char *desc;
+};
+
+struct wipedbs_server_data {
+	struct server_id server_id;
+	const char *server_id_str;
+	bool exists;
+	struct wipedbs_record_marker *session_records;
+	struct wipedbs_record_marker *tcon_records;
+	struct wipedbs_record_marker *open_records;
+};
+
+struct wipedbs_state {
+	struct db_context *id2server_data;
+	struct {
+		struct {
+			int total;
+			int existing;
+			int disconnected;
+		} server;
+		struct {
+			int total;
+			int disconnected;
+			int todelete;
+			int failure;
+		} session, tcon, open;
+		int open_timed_out;
+	} stat;
+	struct server_id *server_ids;
+	bool *server_exists;
+	int idx;
+	struct db_context *session_db;
+	struct db_context *tcon_db;
+	struct db_context *open_db;
+	struct timeval now;
+	bool testmode;
+	bool verbose;
+};
+
+static struct wipedbs_server_data *get_server_data(struct wipedbs_state *state,
+						   const struct server_id *id)
+{
+	struct wipedbs_server_data *ret = NULL;
+	TDB_DATA key, val = tdb_null;
+	NTSTATUS status;
+
+	key = make_tdb_data((const void*)&id->unique_id, sizeof(id->unique_id));
+	status = dbwrap_fetch(state->id2server_data, talloc_tos(), key, &val);
+	if (NT_STATUS_IS_OK(status)) {
+		ret = *(struct wipedbs_server_data**) val.dptr;
+		TALLOC_FREE(val.dptr);
+	} else if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
+		ret = talloc_zero(state->id2server_data,
+				  struct wipedbs_server_data);
+		if (ret == NULL) {
+			DEBUG(0, ("Failed to allocate server entry for %s\n",
+				  server_id_str(talloc_tos(), id)));
+			goto done;
+		}
+		ret->server_id = *id;
+		ret->server_id_str = server_id_str(ret, id);
+		ret->exists = true;
+		val = make_tdb_data((const void*)&ret, sizeof(ret));
+		status = dbwrap_store(state->id2server_data,
+				      key, val, TDB_INSERT);
+		if (!NT_STATUS_IS_OK(status)) {
+			DEBUG(0, ("Failed to store server entry for %s: %s\n",
+				  server_id_str(talloc_tos(), id),
+				  nt_errstr(status)));
+		}
+		goto done;
+	} else {
+		DEBUG(0, ("Failed to fetch server entry for %s: %s\n",
+			  server_id_str(talloc_tos(), id), nt_errstr(status)));
+		goto done;
+	}
+	if (!server_id_equal(id, &ret->server_id)) {
+		DEBUG(0, ("uniq id collision for %s and %s\n",
+			  server_id_str(talloc_tos(), id),
+			  server_id_str(talloc_tos(), &ret->server_id)));
+		smb_panic("server_id->unique_id not unique!");
+	}
+done:
+	return ret;
+}
+
+static int wipedbs_traverse_sessions(struct smbXsrv_session_global0 *session,
+				     void *wipedbs_state)
+{
+	struct wipedbs_state *state =
+		talloc_get_type_abort(wipedbs_state,
+		struct wipedbs_state);
+	struct wipedbs_server_data *sd;
+	struct wipedbs_record_marker *rec;
+	TDB_DATA tmp;
+	int ret = -1;
+
+	assert(session->num_channels == 1);
+
+	state->stat.session.total++;
+
+	sd = get_server_data(state, &session->channels[0].server_id);
+	if (sd == NULL) {
+		goto done;
+	}
+
+	if (server_id_is_disconnected(&sd->server_id)) {
+		state->stat.session.disconnected++;
+	}
+
+	rec = talloc_zero(sd, struct wipedbs_record_marker);
+	if (rec == NULL) {
+		DEBUG(0, ("Out of memory!\n"));
+		goto done;
+	}
+
+	tmp = dbwrap_record_get_key(session->db_rec);
+	rec->key = tdb_data_talloc_copy(rec, tmp);
+	tmp = dbwrap_record_get_value(session->db_rec);
+	rec->val = tdb_data_talloc_copy(rec, tmp);
+
+	rec->desc = talloc_asprintf(
+		rec, "session[global: %u wire: %lu]",
+		session->session_global_id, session->session_wire_id);
+
+	if ((rec->key.dptr == NULL) || (rec->val.dptr == NULL) ||
+	    (rec->desc == NULL))
+	{
+		DEBUG(0, ("Out of memory!\n"));
+		goto done;
+	}
+
+	state->session_db = dbwrap_record_get_db(session->db_rec);
+
+	DLIST_ADD(sd->session_records, rec);
+	ret = 0;
+done:
+	return ret;
+}
+
+static int wipedbs_traverse_tcon(struct smbXsrv_tcon_global0 *tcon,
+				 void *wipedbs_state)
+{
+	struct wipedbs_state *state =
+		talloc_get_type_abort(wipedbs_state,
+		struct wipedbs_state);
+	struct wipedbs_server_data *sd;
+	struct wipedbs_record_marker *rec;
+	TDB_DATA tmp;
+	int ret = -1;
+
+	state->stat.tcon.total++;
+
+	sd = get_server_data(state, &tcon->server_id);
+	if (sd == NULL) {
+		goto done;
+	}
+
+	if (server_id_is_disconnected(&sd->server_id)) {
+		state->stat.tcon.disconnected++;
+	}
+
+	rec = talloc_zero(sd, struct wipedbs_record_marker);
+	if (rec == NULL) {
+		DEBUG(0, ("Out of memory!\n"));
+		goto done;
+	}
+
+	tmp = dbwrap_record_get_key(tcon->db_rec);
+	rec->key = tdb_data_talloc_copy(rec, tmp);
+	tmp = dbwrap_record_get_value(tcon->db_rec);
+	rec->val = tdb_data_talloc_copy(rec, tmp);
+
+	rec->desc = talloc_asprintf(
+		rec, "tcon[global: %u wire: %u session: %u share: %s]",
+		tcon->tcon_global_id, tcon->tcon_wire_id,
+		tcon->session_global_id, tcon->share_name);
+
+	if ((rec->key.dptr == NULL) || (rec->val.dptr == NULL) ||
+	    (rec->desc == NULL))
+	{
+		DEBUG(0, ("Out of memory!\n"));
+		goto done;
+	}
+
+	state->tcon_db = dbwrap_record_get_db(tcon->db_rec);
+
+	DLIST_ADD(sd->tcon_records, rec);
+	ret = 0;
+
+done:
+	return ret;
+}
+
+static int wipedbs_traverse_open(struct smbXsrv_open_global0 *open,
+				 void *wipedbs_state)
+{
+	struct wipedbs_state *state =
+		talloc_get_type_abort(wipedbs_state,
+		struct wipedbs_state);
+	struct wipedbs_server_data *sd;
+	struct wipedbs_record_marker *rec;
+	TDB_DATA tmp;
+	int ret = -1;
+
+	state->stat.open.total++;
+
+	sd = get_server_data(state, &open->server_id);
+	if (sd == NULL) {
+		goto done;
+	}
+
+	if (server_id_is_disconnected(&sd->server_id)) {
+		struct timeval disconnect_time;
+		int64_t tdiff;
+		bool reached;
+
+		state->stat.open.disconnected++;
+
+		nttime_to_timeval(&disconnect_time, open->disconnect_time);
+		tdiff = usec_time_diff(&state->now, &disconnect_time);
+		reached = (tdiff >= 1000*open->durable_timeout_msec);
+
+		if (state->verbose) {
+			TALLOC_CTX *mem_ctx = talloc_new(talloc_tos());
+			d_printf("open[global: %u] disconnected at "
+				 "[%s] %us ago with timeout of %us "
+				 "-%s reached\n",
+				 open->open_global_id,
+				 nt_time_string(mem_ctx, open->disconnect_time),
+				 (unsigned)(tdiff/1000000),
+				 open->durable_timeout_msec / 1000,
+				 reached ? "" : " not");
+			talloc_free(mem_ctx);
+		}
+
+		if (!reached) {
+			ret = 0;
+			goto done;
+		}
+		state->stat.open_timed_out++;
+	}
+
+	rec = talloc_zero(sd, struct wipedbs_record_marker);
+	if (rec == NULL) {
+		DEBUG(0, ("Out of memory!\n"));
+		goto done;
+	}
+
+	tmp = dbwrap_record_get_key(open->db_rec);
+	rec->key = tdb_data_talloc_copy(rec, tmp);
+	tmp = dbwrap_record_get_value(open->db_rec);
+	rec->val = tdb_data_talloc_copy(rec, tmp);
+
+	rec->desc = talloc_asprintf(


-- 
Samba Shared Repository


More information about the samba-cvs mailing list