[SCM] Samba Shared Repository - branch master updated

Stefan Metzmacher metze at samba.org
Mon Oct 17 03:26:04 MDT 2011


The branch, master has been updated
       via  2a2dd6f s3: Before adding KDC's to the krb5.conf, cldap ping them
       via  41a0e96 Add cldap_multi_netlogon_send/recv
      from  8c07686 s4 provision: DNS backend should be set by caller

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


- Log -----------------------------------------------------------------
commit 2a2dd6ff5e057b1dec37a212b0a5eeb2a8392c36
Author: Volker Lendecke <vl at samba.org>
Date:   Wed Oct 12 19:41:45 2011 +0200

    s3: Before adding KDC's to the krb5.conf, cldap ping them
    
    Some Kerberos libraries don't do proper failover. This fixes the situation
    where a KDC exists in DNS but is not reachable for some reason.
    
    Ported to master by Stefan Metzmacher <metze at samba.org>
    
    Autobuild-User: Stefan Metzmacher <metze at samba.org>
    Autobuild-Date: Mon Oct 17 11:25:37 CEST 2011 on sn-devel-104

commit 41a0e96724dc05752b1bdb86fc946c820be16632
Author: Volker Lendecke <vl at samba.org>
Date:   Thu Sep 29 13:30:30 2011 +0200

    Add cldap_multi_netlogon_send/recv
    
    Make ads_cldap_netlogon use it. It does not need the fancy multi stuff, but
    excercising that code more often is better. And because we have to ask over the
    network, the additional load should be neglectable.
    
    Ported to master by Stefan Metzmacher <metze at samba.org>

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

Summary of changes:
 source3/Makefile.in       |    3 +-
 source3/libads/cldap.c    |  338 +++++++++++++++++++++++++++++++++++++++------
 source3/libads/cldap.h    |   18 +++
 source3/libads/kerberos.c |  148 ++++++++++++++-------
 source3/wscript_build     |    2 +-
 5 files changed, 418 insertions(+), 91 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/Makefile.in b/source3/Makefile.in
index 6b979d4..f2bab71 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -1532,7 +1532,8 @@ NTLM_AUTH_OBJ = ${NTLM_AUTH_OBJ1} $(LIBSAMBA_OBJ) $(POPT_LIB_OBJ) \
 		$(PASSDB_OBJ) $(GROUPDB_OBJ) \
 		$(SMBLDAP_OBJ) $(LIBNMB_OBJ) \
 		$(WBCOMMON_OBJ) \
-		$(LIBCLI_LDAP_NDR_OBJ) \
+		$(LIBNBT_OBJ) \
+		$(CLDAP_OBJ) \
 		$(DRSUAPI_OBJ) \
 		$(LIBNDR_GEN_OBJ0) $(LIBNDR_NETLOGON_OBJ) @BUILD_INIPARSER@
 
diff --git a/source3/libads/cldap.c b/source3/libads/cldap.c
index 4f725a0..0241236 100644
--- a/source3/libads/cldap.c
+++ b/source3/libads/cldap.c
@@ -23,8 +23,286 @@
 #include "includes.h"
 #include "../libcli/cldap/cldap.h"
 #include "../lib/tsocket/tsocket.h"
+#include "../lib/util/tevent_ntstatus.h"
 #include "libads/cldap.h"
 
+struct cldap_multi_netlogon_state {
+	struct tevent_context *ev;
+	const struct tsocket_address * const *servers;
+	int num_servers;
+	const char *domain;
+	const char *hostname;
+	unsigned ntversion;
+	int min_servers;
+
+	struct cldap_socket **cldap;
+	struct tevent_req **subreqs;
+	int num_sent;
+	int num_received;
+	int num_good_received;
+	struct cldap_netlogon *ios;
+	struct netlogon_samlogon_response **responses;
+};
+
+static void cldap_multi_netlogon_done(struct tevent_req *subreq);
+static void cldap_multi_netlogon_next(struct tevent_req *subreq);
+
+/*
+ * Do a parallel cldap ping to the servers. The first "min_servers"
+ * are fired directly, the remaining ones in 100msec intervals. If
+ * "min_servers" responses came in successfully, we immediately reply,
+ * not waiting for the remaining ones.
+ */
+
+struct tevent_req *cldap_multi_netlogon_send(
+	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+	const struct tsocket_address * const *servers, int num_servers,
+	const char *domain, const char *hostname, unsigned ntversion,
+	int min_servers)
+{
+	struct tevent_req *req, *subreq;
+	struct cldap_multi_netlogon_state *state;
+	int i;
+
+	req = tevent_req_create(mem_ctx, &state,
+				struct cldap_multi_netlogon_state);
+	if (req == NULL) {
+		return NULL;
+	}
+	state->ev = ev;
+	state->servers = servers;
+	state->num_servers = num_servers;
+	state->domain = domain;
+	state->hostname = hostname;
+	state->ntversion = ntversion;
+	state->min_servers = min_servers;
+
+	if (min_servers > num_servers) {
+		tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+		return tevent_req_post(req, ev);
+	}
+
+	state->subreqs = talloc_zero_array(state,
+					   struct tevent_req *,
+					   num_servers);
+	if (tevent_req_nomem(state->subreqs, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	state->cldap = talloc_zero_array(state,
+					 struct cldap_socket *,
+					 num_servers);
+	if (tevent_req_nomem(state->cldap, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	state->responses = talloc_zero_array(state,
+				struct netlogon_samlogon_response *,
+				num_servers);
+	if (tevent_req_nomem(state->responses, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	state->ios = talloc_zero_array(state->responses,
+				       struct cldap_netlogon,
+				       num_servers);
+	if (tevent_req_nomem(state->ios, req)) {
+		return tevent_req_post(req, ev);
+	}
+
+	for (i=0; i<num_servers; i++) {
+		NTSTATUS status;
+
+		status = cldap_socket_init(state->cldap,
+					   NULL, /* local_addr */
+					   state->servers[i],
+					   &state->cldap[i]);
+		if (tevent_req_nterror(req, status)) {
+			return tevent_req_post(req, ev);
+		}
+
+		state->ios[i].in.dest_address	= NULL;
+		state->ios[i].in.dest_port	= 0;
+		state->ios[i].in.realm		= domain;
+		state->ios[i].in.host		= NULL;
+		state->ios[i].in.user		= NULL;
+		state->ios[i].in.domain_guid	= NULL;
+		state->ios[i].in.domain_sid	= NULL;
+		state->ios[i].in.acct_control	= 0;
+		state->ios[i].in.version	= ntversion;
+		state->ios[i].in.map_response	= false;
+	}
+
+	for (i=0; i<min_servers; i++) {
+		state->subreqs[i] = cldap_netlogon_send(state->subreqs,
+							state->ev,
+							state->cldap[i],
+							&state->ios[i]);
+		if (tevent_req_nomem(state->subreqs[i], req)) {
+			return tevent_req_post(req, ev);
+		}
+		tevent_req_set_callback(
+			state->subreqs[i], cldap_multi_netlogon_done, req);
+	}
+	state->num_sent = min_servers;
+
+	if (state->num_sent < state->num_servers) {
+		/*
+		 * After 100 milliseconds fire the next one
+		 */
+		subreq = tevent_wakeup_send(state, state->ev,
+					    timeval_current_ofs(0, 100000));
+		if (tevent_req_nomem(subreq, req)) {
+			return tevent_req_post(req, ev);
+		}
+		tevent_req_set_callback(subreq, cldap_multi_netlogon_next,
+					req);
+	}
+
+	return req;
+}
+
+static void cldap_multi_netlogon_done(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct cldap_multi_netlogon_state *state = tevent_req_data(
+		req, struct cldap_multi_netlogon_state);
+	NTSTATUS status;
+	struct netlogon_samlogon_response *response;
+	int i;
+
+	for (i=0; i<state->num_sent; i++) {
+		if (state->subreqs[i] == subreq) {
+			break;
+		}
+	}
+	if (i == state->num_sent) {
+		/*
+		 * Got a response we did not fire...
+		 */
+		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+		return;
+	}
+	state->subreqs[i] = NULL;
+
+	response = talloc_zero(state, struct netlogon_samlogon_response);
+	if (tevent_req_nomem(response, req)) {
+		return;
+	}
+
+	status = cldap_netlogon_recv(subreq, response,
+				     &state->ios[i]);
+	TALLOC_FREE(subreq);
+	state->num_received += 1;
+
+	if (NT_STATUS_IS_OK(status)) {
+		*response = state->ios[i].out.netlogon;
+		state->responses[i] = talloc_move(state->responses,
+						  &response);
+		state->num_good_received += 1;
+	}
+
+	if ((state->num_received == state->num_servers) ||
+	    (state->num_good_received >= state->min_servers)) {
+		tevent_req_done(req);
+		return;
+	}
+}
+
+static void cldap_multi_netlogon_next(struct tevent_req *subreq)
+{
+	struct tevent_req *req = tevent_req_callback_data(
+		subreq, struct tevent_req);
+	struct cldap_multi_netlogon_state *state = tevent_req_data(
+		req, struct cldap_multi_netlogon_state);
+	bool ret;
+
+	ret = tevent_wakeup_recv(subreq);
+	TALLOC_FREE(subreq);
+	if (!ret) {
+		tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
+		return;
+	}
+
+	subreq = cldap_netlogon_send(state->subreqs,
+				     state->ev,
+				     state->cldap[state->num_sent],
+				     &state->ios[state->num_sent]);
+	if (tevent_req_nomem(subreq, req)) {
+		return;
+	}
+	tevent_req_set_callback(subreq, cldap_multi_netlogon_done, req);
+	state->subreqs[state->num_sent] = subreq;
+	state->num_sent += 1;
+
+	if (state->num_sent < state->num_servers) {
+		/*
+		 * After 100 milliseconds fire the next one
+		 */
+		subreq = tevent_wakeup_send(state, state->ev,
+					    timeval_current_ofs(0, 100000));
+		if (tevent_req_nomem(subreq, req)) {
+			return;
+		}
+		tevent_req_set_callback(subreq, cldap_multi_netlogon_next,
+					req);
+	}
+}
+
+NTSTATUS cldap_multi_netlogon_recv(
+	struct tevent_req *req, TALLOC_CTX *mem_ctx,
+	struct netlogon_samlogon_response ***responses)
+{
+	struct cldap_multi_netlogon_state *state = tevent_req_data(
+		req, struct cldap_multi_netlogon_state);
+	NTSTATUS status;
+
+	if (tevent_req_is_nterror(req, &status) &&
+	    !NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
+		return status;
+	}
+	/*
+	 * If we timeout, give back what we have so far
+	 */
+	*responses = talloc_move(mem_ctx, &state->responses);
+	return NT_STATUS_OK;
+}
+
+NTSTATUS cldap_multi_netlogon(
+	TALLOC_CTX *mem_ctx,
+	const struct tsocket_address * const *servers,
+	int num_servers,
+	const char *domain, const char *hostname, unsigned ntversion,
+	int min_servers, struct timeval timeout,
+	struct netlogon_samlogon_response ***responses)
+{
+	struct tevent_context *ev;
+	struct tevent_req *req;
+	NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+	ev = tevent_context_init(talloc_tos());
+	if (ev == NULL) {
+		goto fail;
+	}
+	req = cldap_multi_netlogon_send(
+		ev, ev, servers, num_servers, domain, hostname, ntversion,
+		min_servers);
+	if (req == NULL) {
+		goto fail;
+	}
+	if (!tevent_req_set_endtime(req, ev, timeout)) {
+		goto fail;
+	}
+	if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+		goto fail;
+	}
+	status = cldap_multi_netlogon_recv(req, mem_ctx, responses);
+fail:
+	TALLOC_FREE(ev);
+	return status;
+}
+
 /*******************************************************************
   do a cldap netlogon query.  Always 389/udp
 *******************************************************************/
@@ -35,14 +313,13 @@ bool ads_cldap_netlogon(TALLOC_CTX *mem_ctx,
 			uint32_t nt_version,
 			struct netlogon_samlogon_response **_reply)
 {
-	struct cldap_socket *cldap;
-	struct cldap_netlogon io;
-	struct netlogon_samlogon_response *reply;
 	NTSTATUS status;
 	char addrstr[INET6_ADDRSTRLEN];
 	const char *dest_str;
-	int ret;
 	struct tsocket_address *dest_addr;
+	const struct tsocket_address * const *dest_addrs;
+	struct netlogon_samlogon_response **responses = NULL;
+	int ret;
 
 	dest_str = print_sockaddr(addrstr, sizeof(addrstr), ss);
 
@@ -56,50 +333,27 @@ bool ads_cldap_netlogon(TALLOC_CTX *mem_ctx,
 		return false;
 	}
 
-	/*
-	 * as we use a connected udp socket
-	 */
-	status = cldap_socket_init(mem_ctx, NULL, dest_addr, &cldap);
-	TALLOC_FREE(dest_addr);
+	dest_addrs = (const struct tsocket_address * const *)&dest_addr;
+
+	status = cldap_multi_netlogon(talloc_tos(),
+				dest_addrs, 1,
+				realm, NULL,
+				nt_version, 1,
+				timeval_current_ofs(MAX(3,lp_ldap_timeout()/2), 0),
+				&responses);
 	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(2,("Failed to create cldap socket to %s: %s\n",
-			 dest_str, nt_errstr(status)));
+		DEBUG(2, ("ads_cldap_netlogon: cldap_multi_netlogon "
+			  "failed: %s\n", nt_errstr(status)));
 		return false;
 	}
-
-	reply = talloc(cldap, struct netlogon_samlogon_response);
-	if (!reply) {
-		goto failed;
-	}
-
-	/*
-	 * as we use a connected socket, so we don't need to specify the
-	 * destination
-	 */
-	io.in.dest_address	= NULL;
-	io.in.dest_port		= 0;
-	io.in.realm		= realm;
-	io.in.host		= NULL;
-	io.in.user		= NULL;
-	io.in.domain_guid	= NULL;
-	io.in.domain_sid	= NULL;
-	io.in.acct_control	= 0;
-	io.in.version		= nt_version;
-	io.in.map_response	= false;
-
-	status = cldap_netlogon(cldap, reply, &io);
-	if (!NT_STATUS_IS_OK(status)) {
-		DEBUG(2,("cldap_netlogon() failed: %s\n", nt_errstr(status)));
-		goto failed;
+	if (responses[0] == NULL) {
+		DEBUG(2, ("ads_cldap_netlogon: did not get a reply\n"));
+		TALLOC_FREE(responses);
+		return false;
 	}
+	*_reply = talloc_move(mem_ctx, &responses[0]);
 
-	*reply = io.out.netlogon;
-	*_reply = talloc_move(mem_ctx, &reply);
-	TALLOC_FREE(cldap);
 	return true;
-failed:
-	TALLOC_FREE(cldap);
-	return false;
 }
 
 /*******************************************************************
diff --git a/source3/libads/cldap.h b/source3/libads/cldap.h
index 60e1c56..9e42782 100644
--- a/source3/libads/cldap.h
+++ b/source3/libads/cldap.h
@@ -26,6 +26,24 @@
 #include "../libcli/netlogon/netlogon.h"
 
 /* The following definitions come from libads/cldap.c  */
+
+struct tevent_req *cldap_multi_netlogon_send(
+	TALLOC_CTX *mem_ctx, struct tevent_context *ev,
+	const struct tsocket_address * const *servers,
+	int num_servers,
+	const char *domain, const char *hostname, unsigned ntversion,
+	int min_servers);
+NTSTATUS cldap_multi_netlogon_recv(
+	struct tevent_req *req, TALLOC_CTX *mem_ctx,
+	struct netlogon_samlogon_response ***responses);
+NTSTATUS cldap_multi_netlogon(
+	TALLOC_CTX *mem_ctx,
+	const struct tsocket_address * const *servers,
+	int num_servers,
+	const char *domain, const char *hostname, unsigned ntversion,
+	int min_servers, struct timeval timeout,
+	struct netlogon_samlogon_response ***responses);
+
 bool ads_cldap_netlogon(TALLOC_CTX *mem_ctx,
 			struct sockaddr_storage *ss,
 			const char *realm,
diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c
index 5c62ead..d111d01 100644
--- a/source3/libads/kerberos.c
+++ b/source3/libads/kerberos.c
@@ -26,7 +26,9 @@
 #include "smb_krb5.h"
 #include "../librpc/gen_ndr/ndr_misc.h"
 #include "libads/kerberos_proto.h"
+#include "libads/cldap.h"
 #include "secrets.h"
+#include "../lib/tsocket/tsocket.h"
 
 #ifdef HAVE_KRB5
 
@@ -735,17 +737,40 @@ static char *print_kdc_line(char *mem_ctx,
 
 ************************************************************************/
 
+static void add_sockaddr_unique(struct sockaddr_storage *addrs, int *num_addrs,
+				const struct sockaddr_storage *addr)
+{
+	int i;
+
+	for (i=0; i<*num_addrs; i++) {
+		if (sockaddr_equal((const struct sockaddr *)&addrs[i],
+				   (const struct sockaddr *)addr)) {
+			return;
+		}
+	}
+	addrs[i] = *addr;
+	*num_addrs += 1;
+}
+
 static char *get_kdc_ip_string(char *mem_ctx,
 		const char *realm,
 		const char *sitename,
 		const struct sockaddr_storage *pss,
 		const char *kdc_name)
 {
+	TALLOC_CTX *frame = talloc_stackframe();
 	int i;
 	struct ip_service *ip_srv_site = NULL;
 	struct ip_service *ip_srv_nonsite = NULL;
 	int count_site = 0;
 	int count_nonsite;
+	int num_dcs;
+	struct sockaddr_storage *dc_addrs;
+	struct tsocket_address **dc_addrs2 = NULL;
+	const struct tsocket_address * const *dc_addrs3 = NULL;
+	char *result = NULL;
+	struct netlogon_samlogon_response **responses = NULL;
+	NTSTATUS status;
 	char *kdc_str = print_kdc_line(mem_ctx, "", pss, kdc_name);
 
 	if (kdc_str == NULL) {
@@ -758,73 +783,102 @@ static char *get_kdc_ip_string(char *mem_ctx,
 	 */
 
 	if (sitename) {
-
 		get_kdc_list(realm, sitename, &ip_srv_site, &count_site);
-
-		for (i = 0; i < count_site; i++) {
-			if (sockaddr_equal((struct sockaddr *)&ip_srv_site[i].ss,
-						   (struct sockaddr *)pss)) {
-				continue;
-			}
-			/* Append to the string - inefficient
-			 * but not done often. */
-			kdc_str = print_kdc_line(mem_ctx,
-						kdc_str,
-						&ip_srv_site[i].ss,
-						NULL);
-			if (!kdc_str) {
-				SAFE_FREE(ip_srv_site);
-				return NULL;
-			}
-		}
 	}
 
 	/* Get all KDC's. */
 


-- 
Samba Shared Repository


More information about the samba-cvs mailing list