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