|
|
4be148 |
From f4b1a7e7b80ce68e57912edcd48c39ea62c73e43 Mon Sep 17 00:00:00 2001
|
|
|
4be148 |
From: Greg Hudson <ghudson@mit.edu>
|
|
|
4be148 |
Date: Sun, 6 Apr 2014 18:06:14 -0400
|
|
|
4be148 |
Subject: [PATCH 02/13] Add helper to determine if a KDC is the master
|
|
|
4be148 |
|
|
|
4be148 |
Add a new function k5_kdc_is_master in locate_kdc.c to determine
|
|
|
4be148 |
whether a KDC matches one of the masters, and use it in
|
|
|
4be148 |
krb5_sendto_kdc.
|
|
|
4be148 |
---
|
|
|
4be148 |
src/lib/krb5/os/locate_kdc.c | 110 +++++++++++++++++++++++++++++--------------
|
|
|
4be148 |
src/lib/krb5/os/os-proto.h | 3 ++
|
|
|
4be148 |
src/lib/krb5/os/sendto_kdc.c | 31 +-----------
|
|
|
4be148 |
3 files changed, 80 insertions(+), 64 deletions(-)
|
|
|
4be148 |
|
|
|
4be148 |
diff --git a/src/lib/krb5/os/locate_kdc.c b/src/lib/krb5/os/locate_kdc.c
|
|
|
4be148 |
index 88d55a8..4479465 100644
|
|
|
4be148 |
--- a/src/lib/krb5/os/locate_kdc.c
|
|
|
4be148 |
+++ b/src/lib/krb5/os/locate_kdc.c
|
|
|
4be148 |
@@ -166,6 +166,24 @@ add_host_to_list(struct serverlist *list, const char *hostname, int port,
|
|
|
4be148 |
return 0;
|
|
|
4be148 |
}
|
|
|
4be148 |
|
|
|
4be148 |
+/* Return true if server is identical to an entry in list. */
|
|
|
4be148 |
+static krb5_boolean
|
|
|
4be148 |
+server_list_contains(struct serverlist *list, struct server_entry *server)
|
|
|
4be148 |
+{
|
|
|
4be148 |
+ struct server_entry *ent;
|
|
|
4be148 |
+
|
|
|
4be148 |
+ for (ent = list->servers; ent < list->servers + list->nservers; ent++) {
|
|
|
4be148 |
+ if (server->hostname != NULL && ent->hostname != NULL &&
|
|
|
4be148 |
+ strcmp(server->hostname, ent->hostname) == 0)
|
|
|
4be148 |
+ return TRUE;
|
|
|
4be148 |
+ if (server->hostname == NULL && ent->hostname == NULL &&
|
|
|
4be148 |
+ server->addrlen == ent->addrlen &&
|
|
|
4be148 |
+ memcmp(&server->addr, &ent->addr, server->addrlen) == 0)
|
|
|
4be148 |
+ return TRUE;
|
|
|
4be148 |
+ }
|
|
|
4be148 |
+ return FALSE;
|
|
|
4be148 |
+}
|
|
|
4be148 |
+
|
|
|
4be148 |
static krb5_error_code
|
|
|
4be148 |
locate_srv_conf_1(krb5_context context, const krb5_data *realm,
|
|
|
4be148 |
const char * name, struct serverlist *serverlist,
|
|
|
4be148 |
@@ -529,6 +547,41 @@ dns_locate_server(krb5_context context, const krb5_data *realm,
|
|
|
4be148 |
}
|
|
|
4be148 |
#endif /* KRB5_DNS_LOOKUP */
|
|
|
4be148 |
|
|
|
4be148 |
+static krb5_error_code
|
|
|
4be148 |
+locate_server(krb5_context context, const krb5_data *realm,
|
|
|
4be148 |
+ struct serverlist *serverlist, enum locate_service_type svc,
|
|
|
4be148 |
+ int socktype)
|
|
|
4be148 |
+{
|
|
|
4be148 |
+ krb5_error_code ret;
|
|
|
4be148 |
+ struct serverlist list = SERVERLIST_INIT;
|
|
|
4be148 |
+
|
|
|
4be148 |
+ *serverlist = list;
|
|
|
4be148 |
+
|
|
|
4be148 |
+ /* Try modules. If a module returns 0 but leaves the list empty, return an
|
|
|
4be148 |
+ * empty list. */
|
|
|
4be148 |
+ ret = module_locate_server(context, realm, &list, svc, socktype);
|
|
|
4be148 |
+ if (ret != KRB5_PLUGIN_NO_HANDLE)
|
|
|
4be148 |
+ goto done;
|
|
|
4be148 |
+
|
|
|
4be148 |
+ /* Try the profile. Fall back to DNS if it returns an empty list. */
|
|
|
4be148 |
+ ret = prof_locate_server(context, realm, &list, svc, socktype);
|
|
|
4be148 |
+ if (ret)
|
|
|
4be148 |
+ goto done;
|
|
|
4be148 |
+
|
|
|
4be148 |
+#ifdef KRB5_DNS_LOOKUP
|
|
|
4be148 |
+ if (list.nservers == 0)
|
|
|
4be148 |
+ ret = dns_locate_server(context, realm, &list, svc, socktype);
|
|
|
4be148 |
+#endif
|
|
|
4be148 |
+
|
|
|
4be148 |
+done:
|
|
|
4be148 |
+ if (ret) {
|
|
|
4be148 |
+ k5_free_serverlist(&list);
|
|
|
4be148 |
+ return ret;
|
|
|
4be148 |
+ }
|
|
|
4be148 |
+ *serverlist = list;
|
|
|
4be148 |
+ return 0;
|
|
|
4be148 |
+}
|
|
|
4be148 |
+
|
|
|
4be148 |
/*
|
|
|
4be148 |
* Wrapper function for the various backends
|
|
|
4be148 |
*/
|
|
|
4be148 |
@@ -538,54 +591,26 @@ k5_locate_server(krb5_context context, const krb5_data *realm,
|
|
|
4be148 |
struct serverlist *serverlist, enum locate_service_type svc,
|
|
|
4be148 |
int socktype)
|
|
|
4be148 |
{
|
|
|
4be148 |
- krb5_error_code code;
|
|
|
4be148 |
- struct serverlist al = SERVERLIST_INIT;
|
|
|
4be148 |
-
|
|
|
4be148 |
- *serverlist = al;
|
|
|
4be148 |
+ krb5_error_code ret;
|
|
|
4be148 |
|
|
|
4be148 |
+ memset(serverlist, 0, sizeof(*serverlist));
|
|
|
4be148 |
if (realm == NULL || realm->data == NULL || realm->data[0] == 0) {
|
|
|
4be148 |
krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE,
|
|
|
4be148 |
"Cannot find KDC for invalid realm name \"\"");
|
|
|
4be148 |
return KRB5_REALM_CANT_RESOLVE;
|
|
|
4be148 |
}
|
|
|
4be148 |
|
|
|
4be148 |
- code = module_locate_server(context, realm, &al, svc, socktype);
|
|
|
4be148 |
- Tprintf("module_locate_server returns %d\n", code);
|
|
|
4be148 |
- if (code == KRB5_PLUGIN_NO_HANDLE) {
|
|
|
4be148 |
- /*
|
|
|
4be148 |
- * We always try the local file before DNS. Note that there
|
|
|
4be148 |
- * is no way to indicate "service not available" via the
|
|
|
4be148 |
- * config file.
|
|
|
4be148 |
- */
|
|
|
4be148 |
-
|
|
|
4be148 |
- code = prof_locate_server(context, realm, &al, svc, socktype);
|
|
|
4be148 |
-
|
|
|
4be148 |
-#ifdef KRB5_DNS_LOOKUP
|
|
|
4be148 |
- if (code == 0 && al.nservers == 0)
|
|
|
4be148 |
- code = dns_locate_server(context, realm, &al, svc, socktype);
|
|
|
4be148 |
-#endif /* KRB5_DNS_LOOKUP */
|
|
|
4be148 |
+ ret = locate_server(context, realm, serverlist, svc, socktype);
|
|
|
4be148 |
+ if (ret)
|
|
|
4be148 |
+ return ret;
|
|
|
4be148 |
|
|
|
4be148 |
- /* We could put more heuristics here, like looking up a hostname
|
|
|
4be148 |
- of "kerberos."+REALM, etc. */
|
|
|
4be148 |
- }
|
|
|
4be148 |
- if (code == 0)
|
|
|
4be148 |
- Tprintf ("krb5int_locate_server found %d addresses\n",
|
|
|
4be148 |
- al.nservers);
|
|
|
4be148 |
- else
|
|
|
4be148 |
- Tprintf ("krb5int_locate_server returning error code %d/%s\n",
|
|
|
4be148 |
- code, error_message(code));
|
|
|
4be148 |
- if (code != 0) {
|
|
|
4be148 |
- k5_free_serverlist(&al);
|
|
|
4be148 |
- return code;
|
|
|
4be148 |
- }
|
|
|
4be148 |
- if (al.nservers == 0) { /* No good servers */
|
|
|
4be148 |
- k5_free_serverlist(&al);
|
|
|
4be148 |
+ if (serverlist->nservers == 0) {
|
|
|
4be148 |
+ k5_free_serverlist(serverlist);
|
|
|
4be148 |
krb5_set_error_message(context, KRB5_REALM_UNKNOWN,
|
|
|
4be148 |
_("Cannot find KDC for realm \"%.*s\""),
|
|
|
4be148 |
realm->length, realm->data);
|
|
|
4be148 |
return KRB5_REALM_UNKNOWN;
|
|
|
4be148 |
}
|
|
|
4be148 |
- *serverlist = al;
|
|
|
4be148 |
return 0;
|
|
|
4be148 |
}
|
|
|
4be148 |
|
|
|
4be148 |
@@ -598,3 +623,18 @@ k5_locate_kdc(krb5_context context, const krb5_data *realm,
|
|
|
4be148 |
stype = get_masters ? locate_service_master_kdc : locate_service_kdc;
|
|
|
4be148 |
return k5_locate_server(context, realm, serverlist, stype, socktype);
|
|
|
4be148 |
}
|
|
|
4be148 |
+
|
|
|
4be148 |
+krb5_boolean
|
|
|
4be148 |
+k5_kdc_is_master(krb5_context context, const krb5_data *realm,
|
|
|
4be148 |
+ struct server_entry *server)
|
|
|
4be148 |
+{
|
|
|
4be148 |
+ struct serverlist list;
|
|
|
4be148 |
+ krb5_boolean found;
|
|
|
4be148 |
+
|
|
|
4be148 |
+ if (locate_server(context, realm, &list, locate_service_master_kdc,
|
|
|
4be148 |
+ server->socktype) != 0)
|
|
|
4be148 |
+ return FALSE;
|
|
|
4be148 |
+ found = server_list_contains(&list, server);
|
|
|
4be148 |
+ k5_free_serverlist(&list);
|
|
|
4be148 |
+ return found;
|
|
|
4be148 |
+}
|
|
|
4be148 |
diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h
|
|
|
4be148 |
index c6b730f..9125ba0 100644
|
|
|
4be148 |
--- a/src/lib/krb5/os/os-proto.h
|
|
|
4be148 |
+++ b/src/lib/krb5/os/os-proto.h
|
|
|
4be148 |
@@ -76,6 +76,9 @@ krb5_error_code k5_locate_kdc(krb5_context context, const krb5_data *realm,
|
|
|
4be148 |
struct serverlist *serverlist, int get_masters,
|
|
|
4be148 |
int socktype);
|
|
|
4be148 |
|
|
|
4be148 |
+krb5_boolean k5_kdc_is_master(krb5_context context, const krb5_data *realm,
|
|
|
4be148 |
+ struct server_entry *server);
|
|
|
4be148 |
+
|
|
|
4be148 |
void k5_free_serverlist(struct serverlist *);
|
|
|
4be148 |
|
|
|
4be148 |
#ifdef HAVE_NETINET_IN_H
|
|
|
4be148 |
diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c
|
|
|
4be148 |
index 5f781d3..e3855a3 100644
|
|
|
4be148 |
--- a/src/lib/krb5/os/sendto_kdc.c
|
|
|
4be148 |
+++ b/src/lib/krb5/os/sendto_kdc.c
|
|
|
4be148 |
@@ -293,25 +293,6 @@ cm_select_or_poll(const struct select_state *in, time_ms endtime,
|
|
|
4be148 |
}
|
|
|
4be148 |
|
|
|
4be148 |
static int
|
|
|
4be148 |
-in_addrlist(struct server_entry *entry, struct serverlist *list)
|
|
|
4be148 |
-{
|
|
|
4be148 |
- size_t i;
|
|
|
4be148 |
- struct server_entry *le;
|
|
|
4be148 |
-
|
|
|
4be148 |
- for (i = 0; i < list->nservers; i++) {
|
|
|
4be148 |
- le = &list->servers[i];
|
|
|
4be148 |
- if (entry->hostname != NULL && le->hostname != NULL &&
|
|
|
4be148 |
- strcmp(entry->hostname, le->hostname) == 0)
|
|
|
4be148 |
- return 1;
|
|
|
4be148 |
- if (entry->hostname == NULL && le->hostname == NULL &&
|
|
|
4be148 |
- entry->addrlen == le->addrlen &&
|
|
|
4be148 |
- memcmp(&entry->addr, &le->addr, entry->addrlen) == 0)
|
|
|
4be148 |
- return 1;
|
|
|
4be148 |
- }
|
|
|
4be148 |
- return 0;
|
|
|
4be148 |
-}
|
|
|
4be148 |
-
|
|
|
4be148 |
-static int
|
|
|
4be148 |
check_for_svc_unavailable (krb5_context context,
|
|
|
4be148 |
const krb5_data *reply,
|
|
|
4be148 |
void *msg_handler_data)
|
|
|
4be148 |
@@ -418,17 +399,9 @@ krb5_sendto_kdc(krb5_context context, const krb5_data *message,
|
|
|
4be148 |
/* Set use_master to 1 if we ended up talking to a master when we didn't
|
|
|
4be148 |
* explicitly request to. */
|
|
|
4be148 |
if (*use_master == 0) {
|
|
|
4be148 |
- struct serverlist mservers;
|
|
|
4be148 |
- struct server_entry *entry = &servers.servers[server_used];
|
|
|
4be148 |
- retval = k5_locate_kdc(context, realm, &mservers, TRUE,
|
|
|
4be148 |
- entry->socktype);
|
|
|
4be148 |
- if (retval == 0) {
|
|
|
4be148 |
- if (in_addrlist(entry, &mservers))
|
|
|
4be148 |
- *use_master = 1;
|
|
|
4be148 |
- k5_free_serverlist(&mservers);
|
|
|
4be148 |
- }
|
|
|
4be148 |
+ *use_master = k5_kdc_is_master(context, realm,
|
|
|
4be148 |
+ &servers.servers[server_used]);
|
|
|
4be148 |
TRACE_SENDTO_KDC_MASTER(context, *use_master);
|
|
|
4be148 |
- retval = 0;
|
|
|
4be148 |
}
|
|
|
4be148 |
|
|
|
4be148 |
cleanup:
|
|
|
4be148 |
--
|
|
|
4be148 |
2.1.0
|
|
|
4be148 |
|