[SCM] Samba Shared Repository - branch v3-6-test updated

Volker Lendecke vlendec at samba.org
Wed Jan 19 10:22:24 MST 2011


The branch, v3-6-test has been updated
       via  fb05a07 s3: Add wbinfo --dc-info
      from  6197253 Add DELETE-LN test to show bug #7863 - Unlink may unlink wrong file when hardlinks are involved (cherry picked from commit 0ab05aabc2a9d51821b2b4238b97b7e516a2e450)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v3-6-test


- Log -----------------------------------------------------------------
commit fb05a0791de10692fd846129ef6add3c95f3c79a
Author: Volker Lendecke <vl at samba.org>
Date:   Mon Jan 10 17:25:00 2011 +0100

    s3: Add wbinfo --dc-info
    
    wbinfo --dc-info prints the current DC name and IP address. This helps
    diagnosing problems that might happen when a later wbinfo --ping-dc fails.
    
    This patch started out by using the SAF and NBT cache entires, but those are
    relatively short-lived. So I decided to invent a new gencache entry with a very
    long timeout. We need to go via the gencache because when for some reason a
    winbind child process is stuck, we can't query it for the current DC it's
    connected to. This must eventually go away again when we have a fully async
    winbind.
    
    Autobuild-User: Volker Lendecke <vlendec at samba.org>
    Autobuild-Date: Wed Jan 19 08:40:28 CET 2011 on sn-devel-104

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

Summary of changes:
 nsswitch/libwbclient/wbc_util.c    |   86 +++++++++++++++++++++++++++++++++
 nsswitch/libwbclient/wbclient.h    |   15 +++++-
 nsswitch/wbinfo.c                  |   33 +++++++++++++
 nsswitch/winbind_struct_protocol.h |    4 +-
 source3/winbindd/winbindd.c        |    1 +
 source3/winbindd/winbindd_cm.c     |   93 ++++++++++++++++++++++++++++++++++++
 source3/winbindd/winbindd_misc.c   |   50 +++++++++++++++++++
 source3/winbindd/winbindd_proto.h  |    4 ++
 8 files changed, 284 insertions(+), 2 deletions(-)


Changeset truncated at 500 lines:

diff --git a/nsswitch/libwbclient/wbc_util.c b/nsswitch/libwbclient/wbc_util.c
index e2e657a..d2783f3 100644
--- a/nsswitch/libwbclient/wbc_util.c
+++ b/nsswitch/libwbclient/wbc_util.c
@@ -203,6 +203,92 @@ wbcErr wbcDomainInfo(const char *domain, struct wbcDomainInfo **dinfo)
 	return wbc_status;
 }
 
+/* Get the list of current DCs */
+wbcErr wbcDcInfo(const char *domain, size_t *num_dcs,
+		 const char ***dc_names, const char ***dc_ips)
+{
+	struct winbindd_request request;
+	struct winbindd_response response;
+	const char **names = NULL;
+	const char **ips = NULL;
+	wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+	size_t extra_len;
+	int i;
+	char *p;
+
+	/* Initialise request */
+
+	ZERO_STRUCT(request);
+	ZERO_STRUCT(response);
+
+	if (domain != NULL) {
+		strncpy(request.domain_name, domain,
+			sizeof(request.domain_name) - 1);
+	}
+
+	wbc_status = wbcRequestResponse(WINBINDD_DC_INFO,
+					&request, &response);
+	BAIL_ON_WBC_ERROR(wbc_status);
+
+	names = wbcAllocateStringArray(response.data.num_entries);
+	BAIL_ON_PTR_ERROR(names, wbc_status);
+
+	ips = wbcAllocateStringArray(response.data.num_entries);
+	BAIL_ON_PTR_ERROR(names, wbc_status);
+
+	wbc_status = WBC_ERR_INVALID_RESPONSE;
+
+	p = (char *)response.extra_data.data;
+
+	if (response.length < (sizeof(struct winbindd_response)+1)) {
+		goto done;
+	}
+
+	extra_len = response.length - sizeof(struct winbindd_response);
+
+	if (p[extra_len-1] != '\0') {
+		goto done;
+	}
+
+	for (i=0; i<response.data.num_entries; i++) {
+		char *q;
+
+		q = strchr(p, '\n');
+		if (q == NULL) {
+			goto done;
+		}
+		names[i] = strndup(p, q-p);
+		BAIL_ON_PTR_ERROR(names[i], wbc_status);
+		p = q+1;
+
+		q = strchr(p, '\n');
+		if (q == NULL) {
+			goto done;
+		}
+		ips[i] = strndup(p, q-p);
+		BAIL_ON_PTR_ERROR(ips[i], wbc_status);
+		p = q+1;
+	}
+	if (p[0] != '\0') {
+		goto done;
+	}
+
+        wbc_status = WBC_ERR_SUCCESS;
+done:
+	if (response.extra_data.data)
+		free(response.extra_data.data);
+
+	if (WBC_ERROR_IS_OK(wbc_status)) {
+		*num_dcs = response.data.num_entries;
+		*dc_names = names;
+		names = NULL;
+		*dc_ips = ips;
+		ips = NULL;
+	}
+	wbcFreeMemory(names);
+	wbcFreeMemory(ips);
+	return wbc_status;
+}
 
 /* Resolve a NetbiosName via WINS */
 wbcErr wbcResolveWinsByName(const char *name, char **ip)
diff --git a/nsswitch/libwbclient/wbclient.h b/nsswitch/libwbclient/wbclient.h
index e2f9890..39670ab 100644
--- a/nsswitch/libwbclient/wbclient.h
+++ b/nsswitch/libwbclient/wbclient.h
@@ -192,7 +192,6 @@ struct wbcDomainInfo {
 #define WBC_DOMINFO_TRUSTTYPE_IN_FOREST  0x00000002
 #define WBC_DOMINFO_TRUSTTYPE_EXTERNAL   0x00000003
 
-
 /**
  * @brief Auth User Parameters
  **/
@@ -992,6 +991,20 @@ wbcErr wbcDomainInfo(const char *domain,
 		     struct wbcDomainInfo **dinfo);
 
 /**
+ * @brief Lookup the currently contacted DCs
+ *
+ * @param domain        The domain to query
+ *
+ * @param num_dcs       Number of DCs currently known
+ * @param dc_names      Names of the currently known DCs
+ * @param dc_ips        IP addresses of the currently known DCs
+ *
+ * @return #wbcErr
+ **/
+wbcErr wbcDcInfo(const char *domain, size_t *num_dcs,
+		 const char ***dc_names, const char ***dc_ips);
+
+/**
  * @brief Enumerate the domain trusts known by Winbind
  *
  * @param **domains     Pointer to the allocated domain list array
diff --git a/nsswitch/wbinfo.c b/nsswitch/wbinfo.c
index 6ff66f8..caa37f3 100644
--- a/nsswitch/wbinfo.c
+++ b/nsswitch/wbinfo.c
@@ -787,6 +787,31 @@ static bool wbinfo_check_secret(const char *domain)
 	return true;
 }
 
+/* Find the currently connected DCs */
+
+static bool wbinfo_dc_info(const char *domain_name)
+{
+	wbcErr wbc_status = WBC_ERR_UNKNOWN_FAILURE;
+	size_t i, num_dcs;
+	const char **dc_names, **dc_ips;
+
+	wbc_status = wbcDcInfo(domain_name, &num_dcs,
+			       &dc_names, &dc_ips);
+	if (!WBC_ERROR_IS_OK(wbc_status)) {
+		printf("Could not find dc info %s\n",
+		       domain_name ? domain_name : "our domain");
+		return false;
+	}
+
+	for (i=0; i<num_dcs; i++) {
+		printf("%s (%s)\n", dc_names[i], dc_ips[i]);
+	}
+	wbcFreeMemory(dc_names);
+	wbcFreeMemory(dc_ips);
+
+	return true;
+}
+
 /* Change trust account password */
 
 static bool wbinfo_change_secret(const char *domain)
@@ -1921,6 +1946,7 @@ enum {
 	OPT_SEQUENCE,
 	OPT_GETDCNAME,
 	OPT_DSGETDCNAME,
+	OPT_DC_INFO,
 	OPT_USERDOMGROUPS,
 	OPT_SIDALIASES,
 	OPT_USERSIDS,
@@ -2030,6 +2056,8 @@ int main(int argc, char **argv, char **envp)
 		{ "getdcname", 0, POPT_ARG_STRING, &string_arg, OPT_GETDCNAME,
 		  "Get a DC name for a foreign domain", "domainname" },
 		{ "dsgetdcname", 0, POPT_ARG_STRING, &string_arg, OPT_DSGETDCNAME, "Find a DC for a domain", "domainname" },
+		{ "dc-info", 0, POPT_ARG_STRING, &string_arg, OPT_DC_INFO,
+		  "Find the currently known DCs", "domainname" },
 		{ "get-auth-user", 0, POPT_ARG_NONE, NULL, OPT_GET_AUTH_USER, "Retrieve user and password used by winbindd (root only)", NULL },
 		{ "ping", 'p', POPT_ARG_NONE, 0, 'p', "Ping winbindd to see if it is alive" },
 		{ "domain", 0, POPT_ARG_STRING, &opt_domain_name, OPT_DOMAIN_NAME, "Define to the domain to restrict operation", "domain" },
@@ -2443,6 +2471,11 @@ int main(int argc, char **argv, char **envp)
 				goto done;
 			}
 			break;
+		case OPT_DC_INFO:
+			if (!wbinfo_dc_info(string_arg)) {
+				goto done;
+			}
+			break;
 		case OPT_SEPARATOR: {
 			const char sep = winbind_separator();
 			if ( !sep ) {
diff --git a/nsswitch/winbind_struct_protocol.h b/nsswitch/winbind_struct_protocol.h
index 537754f..9304702 100644
--- a/nsswitch/winbind_struct_protocol.h
+++ b/nsswitch/winbind_struct_protocol.h
@@ -54,8 +54,9 @@ typedef char fstring[FSTRING_LEN];
  * 25: removed WINBINDD_SET_HWM
  *     removed WINBINDD_SET_MAPPING
  *     removed WINBINDD_REMOVE_MAPPING
+ * 26: added WINBINDD_DC_INFO
  */
-#define WINBIND_INTERFACE_VERSION 25
+#define WINBIND_INTERFACE_VERSION 26
 
 /* Have to deal with time_t being 4 or 8 bytes due to structure alignment.
    On a 64bit Linux box, we have to support a constant structure size
@@ -132,6 +133,7 @@ enum winbindd_cmd {
 				   struct winbindd_domain */
 	WINBINDD_GETDCNAME,	/* Issue a GetDCName Request */
 	WINBINDD_DSGETDCNAME,	/* Issue a DsGetDCName Request */
+	WINBINDD_DC_INFO,	/* Which DC are we connected to? */
 
 	WINBINDD_SHOW_SEQUENCE, /* display sequence numbers of domains */
 
diff --git a/source3/winbindd/winbindd.c b/source3/winbindd/winbindd.c
index e5aeca6..8f4a205 100644
--- a/source3/winbindd/winbindd.c
+++ b/source3/winbindd/winbindd.c
@@ -442,6 +442,7 @@ static struct winbindd_dispatch_table {
 	  "INTERFACE_VERSION" },
 	{ WINBINDD_DOMAIN_NAME, winbindd_domain_name, "DOMAIN_NAME" },
 	{ WINBINDD_DOMAIN_INFO, winbindd_domain_info, "DOMAIN_INFO" },
+	{ WINBINDD_DC_INFO, winbindd_dc_info, "DC_INFO" },
 	{ WINBINDD_NETBIOS_NAME, winbindd_netbios_name, "NETBIOS_NAME" },
 	{ WINBINDD_PRIV_PIPE_DIR, winbindd_priv_pipe_dir,
 	  "WINBINDD_PRIV_PIPE_DIR" },
diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c
index b36f79f..8e29b7d 100644
--- a/source3/winbindd/winbindd_cm.c
+++ b/source3/winbindd/winbindd_cm.c
@@ -1419,6 +1419,88 @@ static bool find_new_dc(TALLOC_CTX *mem_ctx,
 	goto again;
 }
 
+static char *current_dc_key(TALLOC_CTX *mem_ctx, const char *domain_name)
+{
+	return talloc_asprintf_strupper_m(mem_ctx, "CURRENT_DCNAME/%s",
+					  domain_name);
+}
+
+static void store_current_dc_in_gencache(const char *domain_name,
+					 const char *dc_name,
+					 struct cli_state *cli)
+{
+	char addr[INET6_ADDRSTRLEN];
+	char *key, *value;
+
+	if (cli == NULL) {
+		return;
+	}
+	if (cli->fd == -1) {
+		return;
+	}
+	get_peer_addr(cli->fd, addr, sizeof(addr));
+
+	key = current_dc_key(talloc_tos(), domain_name);
+	if (key == NULL) {
+		goto done;
+	}
+
+	value = talloc_asprintf(talloc_tos(), "%s %s", addr, dc_name);
+	if (value == NULL) {
+		goto done;
+	}
+
+	gencache_set(key, value, 0x7ffffffff);
+done:
+	TALLOC_FREE(value);
+	TALLOC_FREE(key);
+}
+
+bool fetch_current_dc_from_gencache(TALLOC_CTX *mem_ctx,
+				    const char *domain_name,
+				    char **p_dc_name, char **p_dc_ip)
+{
+	char *key, *value, *p;
+	bool ret = false;
+	char *dc_name = NULL;
+	char *dc_ip = NULL;
+
+	key = current_dc_key(talloc_tos(), domain_name);
+	if (key == NULL) {
+		goto done;
+	}
+	if (!gencache_get(key, &value, NULL)) {
+		goto done;
+	}
+	p = strchr(value, ' ');
+	if (p == NULL) {
+		goto done;
+	}
+	dc_ip = talloc_strndup(mem_ctx, value, p - value);
+	if (dc_ip == NULL) {
+		goto done;
+	}
+	dc_name = talloc_strdup(mem_ctx, p+1);
+	if (dc_name == NULL) {
+		goto done;
+	}
+
+	if (p_dc_ip != NULL) {
+		*p_dc_ip = dc_ip;
+		dc_ip = NULL;
+	}
+	if (p_dc_name != NULL) {
+		*p_dc_name = dc_name;
+		dc_name = NULL;
+	}
+	ret = true;
+done:
+	TALLOC_FREE(dc_name);
+	TALLOC_FREE(dc_ip);
+	TALLOC_FREE(key);
+	return ret;
+}
+
 static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
 				   struct winbindd_cm_conn *new_conn)
 {
@@ -1520,6 +1602,17 @@ static NTSTATUS cm_open_connection(struct winbindd_domain *domain,
 			set_global_winbindd_state_online();
 		}
 		set_domain_online(domain);
+
+		/*
+		 * Much as I hate global state, this seems to be the point
+		 * where we can be certain that we have a proper connection to
+		 * a DC. wbinfo --dc-info needs that information, store it in
+		 * gencache with a looong timeout. This will need revisiting
+		 * once we start to connect to multiple DCs, wbcDcInfo is
+		 * already prepared for that.
+		 */
+		store_current_dc_in_gencache(domain->name, domain->dcname,
+					     new_conn->cli);
 	} else {
 		/* Ensure we setup the retry handler. */
 		set_domain_offline(domain);
diff --git a/source3/winbindd/winbindd_misc.c b/source3/winbindd/winbindd_misc.c
index caf213b..42ecea2 100644
--- a/source3/winbindd/winbindd_misc.c
+++ b/source3/winbindd/winbindd_misc.c
@@ -314,6 +314,56 @@ static void domain_info_done(struct tevent_req *req)
 	request_ok(state->cli);
 }
 
+void winbindd_dc_info(struct winbindd_cli_state *cli)
+{
+	struct winbindd_domain *domain;
+	char *dc_name, *dc_ip;
+
+	cli->request->domain_name[sizeof(cli->request->domain_name-1)] = '\0';
+
+	DEBUG(3, ("[%5lu]: domain_info [%s]\n", (unsigned long)cli->pid,
+		  cli->request->domain_name));
+
+	if (cli->request->domain_name[0] != '\0') {
+		domain = find_domain_from_name_noinit(
+			cli->request->domain_name);
+		DEBUG(10, ("Could not find domain %s\n",
+			   cli->request->domain_name));
+		if (domain == NULL) {
+			request_error(cli);
+			return;
+		}
+	} else {
+		domain = find_our_domain();
+	}
+
+	if (!fetch_current_dc_from_gencache(
+		    talloc_tos(), domain->name, &dc_name, &dc_ip)) {
+		DEBUG(10, ("fetch_current_dc_from_gencache(%s) failed\n",
+			   domain->name));
+		request_error(cli);
+		return;
+	}
+
+	cli->response->data.num_entries = 1;
+	cli->response->extra_data.data = talloc_asprintf(
+		cli->mem_ctx, "%s\n%s\n", dc_name, dc_ip);
+
+	TALLOC_FREE(dc_name);
+	TALLOC_FREE(dc_ip);
+
+	if (cli->response->extra_data.data == NULL) {
+		request_error(cli);
+		return;
+	}
+
+	/* must add one to length to copy the 0 for string termination */
+	cli->response->length +=
+		strlen((char *)cli->response->extra_data.data) + 1;
+
+	request_ok(cli);
+}
+
 /* List various tidbits of information */
 
 void winbindd_info(struct winbindd_cli_state *state)
diff --git a/source3/winbindd/winbindd_proto.h b/source3/winbindd/winbindd_proto.h
index dc563c9..5cb6c4c 100644
--- a/source3/winbindd/winbindd_proto.h
+++ b/source3/winbindd/winbindd_proto.h
@@ -170,6 +170,9 @@ NTSTATUS cm_connect_lsa_tcp(struct winbindd_domain *domain,
 			    struct rpc_pipe_client **cli);
 NTSTATUS cm_connect_netlogon(struct winbindd_domain *domain,
 			     struct rpc_pipe_client **cli);
+bool fetch_current_dc_from_gencache(TALLOC_CTX *mem_ctx,
+				    const char *domain_name,
+				    char **p_dc_name, char **p_dc_ip);
 
 /* The following definitions come from winbindd/winbindd_cred_cache.c  */
 
@@ -322,6 +325,7 @@ enum winbindd_result winbindd_dual_list_trusted_domains(struct winbindd_domain *
 							struct winbindd_cli_state *state);
 void winbindd_show_sequence(struct winbindd_cli_state *state);
 void winbindd_domain_info(struct winbindd_cli_state *state);
+void winbindd_dc_info(struct winbindd_cli_state *state);
 void winbindd_ping(struct winbindd_cli_state *state);
 void winbindd_info(struct winbindd_cli_state *state);
 void winbindd_interface_version(struct winbindd_cli_state *state);


-- 
Samba Shared Repository


More information about the samba-cvs mailing list