summaryrefslogtreecommitdiff
path: root/source3/libads
diff options
context:
space:
mode:
authorVolker Lendecke <vl@samba.org>2011-10-12 19:41:45 +0200
committerStefan Metzmacher <metze@samba.org>2011-10-17 11:25:36 +0200
commit2a2dd6ff5e057b1dec37a212b0a5eeb2a8392c36 (patch)
tree4e3da46e156c33231dd22d7c770a10da51945019 /source3/libads
parent41a0e96724dc05752b1bdb86fc946c820be16632 (diff)
downloadsamba-2a2dd6ff5e057b1dec37a212b0a5eeb2a8392c36.tar.gz
samba-2a2dd6ff5e057b1dec37a212b0a5eeb2a8392c36.tar.bz2
samba-2a2dd6ff5e057b1dec37a212b0a5eeb2a8392c36.zip
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@samba.org> Autobuild-User: Stefan Metzmacher <metze@samba.org> Autobuild-Date: Mon Oct 17 11:25:37 CEST 2011 on sn-devel-104
Diffstat (limited to 'source3/libads')
-rw-r--r--source3/libads/kerberos.c148
1 files changed, 101 insertions, 47 deletions
diff --git a/source3/libads/kerberos.c b/source3/libads/kerberos.c
index 5c62ead689..d111d018e0 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. */
get_kdc_list(realm, NULL, &ip_srv_nonsite, &count_nonsite);
- for (i = 0; i < count_nonsite; i++) {
- int j;
+ dc_addrs = talloc_array(talloc_tos(), struct sockaddr_storage,
+ 1 + count_site + count_nonsite);
+ if (dc_addrs == NULL) {
+ goto fail;
+ }
- if (sockaddr_equal((struct sockaddr *)&ip_srv_nonsite[i].ss, (struct sockaddr *)pss)) {
- continue;
- }
+ dc_addrs[0] = *pss;
+ num_dcs = 1;
- /* Ensure this isn't an IP already seen (YUK! this is n*n....) */
- for (j = 0; j < count_site; j++) {
- if (sockaddr_equal((struct sockaddr *)&ip_srv_nonsite[i].ss,
- (struct sockaddr *)&ip_srv_site[j].ss)) {
- break;
- }
- /* As the lists are sorted we can break early if nonsite > site. */
- if (ip_service_compare(&ip_srv_nonsite[i], &ip_srv_site[j]) > 0) {
- break;
- }
+ for (i=0; i<count_site; i++) {
+ add_sockaddr_unique(dc_addrs, &num_dcs, &ip_srv_site[i].ss);
+ }
+
+ for (i=0; i<count_nonsite; i++) {
+ add_sockaddr_unique(dc_addrs, &num_dcs, &ip_srv_nonsite[i].ss);
+ }
+
+ dc_addrs2 = talloc_zero_array(talloc_tos(),
+ struct tsocket_address *,
+ num_dcs);
+ if (dc_addrs2 == NULL) {
+ goto fail;
+ }
+
+ for (i=0; i<num_dcs; i++) {
+ char addr[INET6_ADDRSTRLEN];
+ int ret;
+
+ print_sockaddr(addr, sizeof(addr), &dc_addrs[i]);
+
+ ret = tsocket_address_inet_from_strings(dc_addrs2, "ip",
+ addr, LDAP_PORT,
+ &dc_addrs2[i]);
+ if (ret != 0) {
+ status = map_nt_error_from_unix(errno);
+ DEBUG(2,("Failed to create tsocket_address for %s - %s\n",
+ addr, nt_errstr(status)));
+ goto fail;
}
- if (j != i) {
+ }
+
+ dc_addrs3 = (const struct tsocket_address * const *)dc_addrs2;
+
+ status = cldap_multi_netlogon(talloc_tos(),
+ dc_addrs3, num_dcs,
+ realm, lp_netbios_name(),
+ NETLOGON_NT_VERSION_5 | NETLOGON_NT_VERSION_5EX,
+ MIN(num_dcs, 3), timeval_current_ofs(3, 0), &responses);
+ TALLOC_FREE(dc_addrs2);
+ dc_addrs3 = NULL;
+
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(10,("get_kdc_ip_string: cldap_multi_netlogon failed: "
+ "%s\n", nt_errstr(status)));
+ goto fail;
+ }
+
+ kdc_str = talloc_strdup(mem_ctx, "");
+ if (kdc_str == NULL) {
+ goto fail;
+ }
+
+ for (i=0; i<num_dcs; i++) {
+ char *new_kdc_str;
+
+ if (responses[i] == NULL) {
continue;
}
/* Append to the string - inefficient but not done often. */
- kdc_str = print_kdc_line(mem_ctx,
- kdc_str,
- &ip_srv_nonsite[i].ss,
- NULL);
- if (!kdc_str) {
- SAFE_FREE(ip_srv_site);
- SAFE_FREE(ip_srv_nonsite);
- return NULL;
+ new_kdc_str = print_kdc_line(mem_ctx, kdc_str,
+ &dc_addrs[i],
+ kdc_name);
+ if (new_kdc_str == NULL) {
+ goto fail;
}
+ TALLOC_FREE(kdc_str);
+ kdc_str = new_kdc_str;
}
-
- SAFE_FREE(ip_srv_site);
- SAFE_FREE(ip_srv_nonsite);
-
DEBUG(10,("get_kdc_ip_string: Returning %s\n",
kdc_str ));
- return kdc_str;
+ result = kdc_str;
+fail:
+ SAFE_FREE(ip_srv_site);
+ SAFE_FREE(ip_srv_nonsite);
+ TALLOC_FREE(frame);
+ return result;
}
/************************************************************************