Skip to content

Commit

Permalink
Use k5_transport(_strategy) enums for k5_sendto
Browse files Browse the repository at this point in the history
In k5_sendto and k5_locate_server, replace "socktype" parameters with
a new enumerator k5_transport, so that we can add new transports which
are not in the socket type namespace.  Control the order in which we
make connections of different types using a new k5_transport_strategy
enumerator, to simplify the logic for adding new transports later.
Control the result of k5_locate_server with a no_udp boolean rather
than a socket type.

[ghudson@mit.edu: renamed type to k5_transport; k5_locate_server
 no_udp change; clarified commit message; fix for Solaris getaddrinfo]
[kaduk@mit.edu: name variables of type k5_transport 'transport']
[nalin@redhat.com: use transport rather than sock_type in more places,
 add and use k5_transport_strategy, update the test program]

ticket: 7929
  • Loading branch information
frozencemetery authored and greghudson committed Jun 2, 2014
1 parent f4b1a7e commit 9c6be00
Show file tree
Hide file tree
Showing 10 changed files with 178 additions and 122 deletions.
31 changes: 16 additions & 15 deletions src/lib/krb5/os/changepw.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,25 +59,25 @@ struct sendto_callback_context {

static krb5_error_code
locate_kpasswd(krb5_context context, const krb5_data *realm,
struct serverlist *serverlist, int socktype)
struct serverlist *serverlist, krb5_boolean no_udp)
{
krb5_error_code code;

code = k5_locate_server(context, realm, serverlist, locate_service_kpasswd,
socktype);
no_udp);

if (code == KRB5_REALM_CANT_RESOLVE || code == KRB5_REALM_UNKNOWN) {
code = k5_locate_server(context, realm, serverlist,
locate_service_kadmin, SOCK_STREAM);
locate_service_kadmin, TRUE);
if (!code) {
/* Success with admin_server but now we need to change the
port number to use DEFAULT_KPASSWD_PORT and the socktype. */
/* Success with admin_server but now we need to change the port
* number to use DEFAULT_KPASSWD_PORT and the transport. */
size_t i;
for (i = 0; i < serverlist->nservers; i++) {
struct server_entry *s = &serverlist->servers[i];
krb5_ui_2 kpasswd_port = htons(DEFAULT_KPASSWD_PORT);
if (socktype != SOCK_STREAM)
s->socktype = socktype;
if (!no_udp && s->transport == TCP)
s->transport = TCP_OR_UDP;
if (s->hostname != NULL)
s->port = kpasswd_port;
else if (s->family == AF_INET)
Expand Down Expand Up @@ -214,7 +214,7 @@ change_set_password(krb5_context context,
krb5_data *result_string)
{
krb5_data chpw_rep;
krb5_boolean use_tcp = 0;
krb5_boolean no_udp = FALSE;
GETSOCKNAME_ARG3_TYPE addrlen;
krb5_error_code code = 0;
char *code_string;
Expand Down Expand Up @@ -247,9 +247,10 @@ change_set_password(krb5_context context,
callback_ctx.local_seq_num = callback_ctx.auth_context->local_seq_number;

do {
int socktype = (use_tcp ? SOCK_STREAM : SOCK_DGRAM);
k5_transport_strategy strategy = no_udp ? NO_UDP : UDP_FIRST;

code = locate_kpasswd(callback_ctx.context, &creds->server->realm, &sl,
socktype);
no_udp);
if (code)
break;

Expand All @@ -260,7 +261,7 @@ change_set_password(krb5_context context,
callback_info.pfn_cleanup = kpasswd_sendto_msg_cleanup;
krb5_free_data_contents(callback_ctx.context, &chpw_rep);

code = k5_sendto(callback_ctx.context, NULL, &sl, socktype, 0,
code = k5_sendto(callback_ctx.context, NULL, &sl, strategy,
&callback_info, &chpw_rep, ss2sa(&remote_addr),
&addrlen, NULL, NULL, NULL);
if (code) {
Expand All @@ -277,9 +278,9 @@ change_set_password(krb5_context context,
result_string);

if (code) {
if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !use_tcp) {
if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !no_udp) {
k5_free_serverlist(&sl);
use_tcp = 1;
no_udp = 1;
continue;
}

Expand All @@ -305,9 +306,9 @@ change_set_password(krb5_context context,
strncpy(result_code_string->data, code_string, result_code_string->length);
}

if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !use_tcp) {
if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !no_udp) {
k5_free_serverlist(&sl);
use_tcp = 1;
no_udp = 1;
} else {
break;
}
Expand Down
2 changes: 1 addition & 1 deletion src/lib/krb5/os/hostrealm_domain.c
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ domain_fallback_realm(krb5_context context, krb5_hostrealm_moddata data,
suffix = uhost;
while (limit-- >= 0 && (dot = strchr(suffix, '.')) != NULL) {
drealm = string2data((char *)suffix);
if (k5_locate_kdc(context, &drealm, &slist, FALSE, SOCK_DGRAM) == 0) {
if (k5_locate_kdc(context, &drealm, &slist, FALSE, FALSE) == 0) {
k5_free_serverlist(&slist);
ret = k5_make_realmlist(suffix, realms_out);
goto cleanup;
Expand Down
75 changes: 43 additions & 32 deletions src/lib/krb5/os/locate_kdc.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,15 +129,15 @@ new_server_entry(struct serverlist *list)

/* Add an address entry to list. */
static int
add_addr_to_list(struct serverlist *list, int socktype, int family,
add_addr_to_list(struct serverlist *list, k5_transport transport, int family,
size_t addrlen, struct sockaddr *addr)
{
struct server_entry *entry;

entry = new_server_entry(list);
if (entry == NULL)
return ENOMEM;
entry->socktype = socktype;
entry->transport = transport;
entry->family = family;
entry->hostname = NULL;
entry->addrlen = addrlen;
Expand All @@ -149,14 +149,14 @@ add_addr_to_list(struct serverlist *list, int socktype, int family,
/* Add a hostname entry to list. */
static int
add_host_to_list(struct serverlist *list, const char *hostname, int port,
int socktype, int family)
k5_transport transport, int family)
{
struct server_entry *entry;

entry = new_server_entry(list);
if (entry == NULL)
return ENOMEM;
entry->socktype = socktype;
entry->transport = transport;
entry->family = family;
entry->hostname = strdup(hostname);
if (entry->hostname == NULL)
Expand Down Expand Up @@ -187,7 +187,7 @@ server_list_contains(struct serverlist *list, struct server_entry *server)
static krb5_error_code
locate_srv_conf_1(krb5_context context, const krb5_data *realm,
const char * name, struct serverlist *serverlist,
int socktype, int udpport, int sec_udpport)
k5_transport transport, int udpport, int sec_udpport)
{
const char *realm_srv_names[4];
char **hostlist, *host, *port, *cp;
Expand Down Expand Up @@ -255,12 +255,12 @@ locate_srv_conf_1(krb5_context context, const krb5_data *realm,
*cp = '\0';
}

code = add_host_to_list(serverlist, host, p1, socktype, AF_UNSPEC);
code = add_host_to_list(serverlist, host, p1, transport, AF_UNSPEC);
/* Second port is for IPv4 UDP only, and should possibly go away as
* it was originally a krb4 compatibility measure. */
if (code == 0 && p2 != 0 &&
(socktype == 0 || socktype == SOCK_DGRAM))
code = add_host_to_list(serverlist, host, p2, SOCK_DGRAM, AF_INET);
(transport == TCP_OR_UDP || transport == UDP))
code = add_host_to_list(serverlist, host, p2, UDP, AF_INET);
if (code)
goto cleanup;
}
Expand All @@ -278,7 +278,8 @@ krb5_locate_srv_conf(krb5_context context, const krb5_data *realm,
{
krb5_error_code ret;

ret = locate_srv_conf_1(context, realm, name, al, 0, udpport, sec_udpport);
ret = locate_srv_conf_1(context, realm, name, al, TCP_OR_UDP, udpport,
sec_udpport);
if (ret)
return ret;
if (al->nservers == 0) /* Couldn't resolve any KDC names */
Expand All @@ -294,7 +295,7 @@ locate_srv_dns_1(const krb5_data *realm, const char *service,
{
struct srv_dns_entry *head = NULL, *entry = NULL;
krb5_error_code code = 0;
int socktype;
k5_transport transport;

code = krb5int_make_srv_query_realm(realm, service, protocol, &head);
if (code)
Expand All @@ -310,9 +311,9 @@ locate_srv_dns_1(const krb5_data *realm, const char *service,
}

for (entry = head; entry != NULL; entry = entry->next) {
socktype = (strcmp(protocol, "_tcp") == 0) ? SOCK_STREAM : SOCK_DGRAM;
transport = (strcmp(protocol, "_tcp") == 0) ? TCP : UDP;
code = add_host_to_list(serverlist, entry->host, htons(entry->port),
socktype, AF_UNSPEC);
transport, AF_UNSPEC);
if (code)
goto cleanup;
}
Expand Down Expand Up @@ -341,6 +342,7 @@ module_callback(void *cbdata, int socktype, struct sockaddr *sa)
{
struct module_callback_data *d = cbdata;
size_t addrlen;
k5_transport transport;

if (socktype != SOCK_STREAM && socktype != SOCK_DGRAM)
return 0;
Expand All @@ -350,7 +352,8 @@ module_callback(void *cbdata, int socktype, struct sockaddr *sa)
addrlen = sizeof(struct sockaddr_in6);
else
return 0;
if (add_addr_to_list(d->list, socktype, sa->sa_family, addrlen,
transport = (socktype == SOCK_STREAM) ? TCP : UDP;
if (add_addr_to_list(d->list, transport, sa->sa_family, addrlen,
sa) != 0) {
/* Assumes only error is ENOMEM. */
d->out_of_mem = 1;
Expand All @@ -362,14 +365,14 @@ module_callback(void *cbdata, int socktype, struct sockaddr *sa)
static krb5_error_code
module_locate_server(krb5_context ctx, const krb5_data *realm,
struct serverlist *serverlist,
enum locate_service_type svc, int socktype)
enum locate_service_type svc, k5_transport transport)
{
struct krb5plugin_service_locate_result *res = NULL;
krb5_error_code code;
struct krb5plugin_service_locate_ftable *vtbl = NULL;
void **ptrs;
char *realmz; /* NUL-terminated realm */
int i;
int socktype, i;
struct module_callback_data cbdata = { 0, };
const char *msg;

Expand Down Expand Up @@ -413,11 +416,11 @@ module_locate_server(krb5_context ctx, const krb5_data *realm,
if (code)
continue;

code = vtbl->lookup(blob, svc, realmz,
(socktype != 0) ? socktype : SOCK_DGRAM, AF_UNSPEC,
socktype = (transport == TCP) ? SOCK_STREAM : SOCK_DGRAM;
code = vtbl->lookup(blob, svc, realmz, socktype, AF_UNSPEC,
module_callback, &cbdata);
/* Also ask for TCP addresses if we got UDP addresses and want both. */
if (code == 0 && socktype == 0) {
if (code == 0 && transport == TCP_OR_UDP) {
code = vtbl->lookup(blob, svc, realmz, SOCK_STREAM, AF_UNSPEC,
module_callback, &cbdata);
if (code == KRB5_PLUGIN_NO_HANDLE)
Expand Down Expand Up @@ -459,7 +462,7 @@ module_locate_server(krb5_context ctx, const krb5_data *realm,
static krb5_error_code
prof_locate_server(krb5_context context, const krb5_data *realm,
struct serverlist *serverlist, enum locate_service_type svc,
int socktype)
k5_transport transport)
{
const char *profname;
int dflport1, dflport2 = 0;
Expand Down Expand Up @@ -495,15 +498,15 @@ prof_locate_server(krb5_context context, const krb5_data *realm,
return EBUSY; /* XXX */
}

return locate_srv_conf_1(context, realm, profname, serverlist, socktype,
return locate_srv_conf_1(context, realm, profname, serverlist, transport,
dflport1, dflport2);
}

#ifdef KRB5_DNS_LOOKUP
static krb5_error_code
dns_locate_server(krb5_context context, const krb5_data *realm,
struct serverlist *serverlist, enum locate_service_type svc,
int socktype)
k5_transport transport)
{
const char *dnsname;
int use_dns = _krb5_use_dns_kdc(context);
Expand Down Expand Up @@ -533,12 +536,12 @@ dns_locate_server(krb5_context context, const krb5_data *realm,
}

code = 0;
if (socktype == SOCK_DGRAM || socktype == 0) {
if (transport == UDP || transport == TCP_OR_UDP) {
code = locate_srv_dns_1(realm, dnsname, "_udp", serverlist);
if (code)
Tprintf("dns udp lookup returned error %d\n", code);
}
if ((socktype == SOCK_STREAM || socktype == 0) && code == 0) {
if ((transport == TCP || transport == TCP_OR_UDP) && code == 0) {
code = locate_srv_dns_1(realm, dnsname, "_tcp", serverlist);
if (code)
Tprintf("dns tcp lookup returned error %d\n", code);
Expand All @@ -547,10 +550,16 @@ dns_locate_server(krb5_context context, const krb5_data *realm,
}
#endif /* KRB5_DNS_LOOKUP */

/*
* Try all of the server location methods in sequence. transport must be
* TCP_OR_UDP, TCP, or UDP. It is applied to hostname entries in the profile
* and affects whether we query modules or DNS for UDP or TCP or both, but does
* not restrict a method from returning entries of other transports.
*/
static krb5_error_code
locate_server(krb5_context context, const krb5_data *realm,
struct serverlist *serverlist, enum locate_service_type svc,
int socktype)
k5_transport transport)
{
krb5_error_code ret;
struct serverlist list = SERVERLIST_INIT;
Expand All @@ -559,18 +568,18 @@ locate_server(krb5_context context, const krb5_data *realm,

/* 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);
ret = module_locate_server(context, realm, &list, svc, transport);
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);
ret = prof_locate_server(context, realm, &list, svc, transport);
if (ret)
goto done;

#ifdef KRB5_DNS_LOOKUP
if (list.nservers == 0)
ret = dns_locate_server(context, realm, &list, svc, socktype);
ret = dns_locate_server(context, realm, &list, svc, transport);
#endif

done:
Expand All @@ -589,9 +598,10 @@ locate_server(krb5_context context, const krb5_data *realm,
krb5_error_code
k5_locate_server(krb5_context context, const krb5_data *realm,
struct serverlist *serverlist, enum locate_service_type svc,
int socktype)
krb5_boolean no_udp)
{
krb5_error_code ret;
k5_transport transport = no_udp ? TCP : TCP_OR_UDP;

memset(serverlist, 0, sizeof(*serverlist));
if (realm == NULL || realm->data == NULL || realm->data[0] == 0) {
Expand All @@ -600,7 +610,7 @@ k5_locate_server(krb5_context context, const krb5_data *realm,
return KRB5_REALM_CANT_RESOLVE;
}

ret = locate_server(context, realm, serverlist, svc, socktype);
ret = locate_server(context, realm, serverlist, svc, transport);
if (ret)
return ret;

Expand All @@ -616,12 +626,13 @@ k5_locate_server(krb5_context context, const krb5_data *realm,

krb5_error_code
k5_locate_kdc(krb5_context context, const krb5_data *realm,
struct serverlist *serverlist, int get_masters, int socktype)
struct serverlist *serverlist, krb5_boolean get_masters,
krb5_boolean no_udp)
{
enum locate_service_type stype;

stype = get_masters ? locate_service_master_kdc : locate_service_kdc;
return k5_locate_server(context, realm, serverlist, stype, socktype);
return k5_locate_server(context, realm, serverlist, stype, no_udp);
}

krb5_boolean
Expand All @@ -632,7 +643,7 @@ k5_kdc_is_master(krb5_context context, const krb5_data *realm,
krb5_boolean found;

if (locate_server(context, realm, &list, locate_service_master_kdc,
server->socktype) != 0)
server->transport) != 0)
return FALSE;
found = server_list_contains(&list, server);
k5_free_serverlist(&list);
Expand Down

0 comments on commit 9c6be00

Please sign in to comment.