krb5 commit: Use k5_transport(_strategy) enums for k5_sendto
Greg Hudson
ghudson at MIT.EDU
Mon Jun 2 18:53:27 EDT 2014
https://github.com/krb5/krb5/commit/9c6be00daca0b80aed94ec9680724f95e6be92e1
commit 9c6be00daca0b80aed94ec9680724f95e6be92e1
Author: Robbie Harwood (frozencemetery) <rharwood at club.cc.cmu.edu>
Date: Thu Aug 15 15:55:52 2013 -0400
Use k5_transport(_strategy) enums for k5_sendto
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 at mit.edu: renamed type to k5_transport; k5_locate_server
no_udp change; clarified commit message; fix for Solaris getaddrinfo]
[kaduk at mit.edu: name variables of type k5_transport 'transport']
[nalin at redhat.com: use transport rather than sock_type in more places,
add and use k5_transport_strategy, update the test program]
ticket: 7929
src/lib/krb5/os/changepw.c | 31 +++++-----
src/lib/krb5/os/hostrealm_domain.c | 2 +-
src/lib/krb5/os/locate_kdc.c | 75 +++++++++++++---------
src/lib/krb5/os/os-proto.h | 27 ++++++--
src/lib/krb5/os/sendto_kdc.c | 123 ++++++++++++++++++++++-------------
src/lib/krb5/os/t_locate_kdc.c | 24 ++++----
src/lib/krb5/os/t_std_conf.c | 2 +-
src/lib/krb5/os/t_trace.c | 6 +-
src/lib/krb5/os/t_trace.ref | 4 +-
src/lib/krb5/os/trace.c | 6 +-
10 files changed, 178 insertions(+), 122 deletions(-)
diff --git a/src/lib/krb5/os/changepw.c b/src/lib/krb5/os/changepw.c
index 4d8abd9..a1c9885 100644
--- a/src/lib/krb5/os/changepw.c
+++ b/src/lib/krb5/os/changepw.c
@@ -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)
@@ -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;
@@ -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;
@@ -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) {
@@ -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;
}
@@ -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;
}
diff --git a/src/lib/krb5/os/hostrealm_domain.c b/src/lib/krb5/os/hostrealm_domain.c
index dc9cc59..2228df0 100644
--- a/src/lib/krb5/os/hostrealm_domain.c
+++ b/src/lib/krb5/os/hostrealm_domain.c
@@ -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;
diff --git a/src/lib/krb5/os/locate_kdc.c b/src/lib/krb5/os/locate_kdc.c
index 4479465..4c8aead 100644
--- a/src/lib/krb5/os/locate_kdc.c
+++ b/src/lib/krb5/os/locate_kdc.c
@@ -129,7 +129,7 @@ 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;
@@ -137,7 +137,7 @@ add_addr_to_list(struct serverlist *list, int socktype, int family,
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;
@@ -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)
@@ -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;
@@ -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;
}
@@ -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 */
@@ -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)
@@ -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;
}
@@ -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;
@@ -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;
@@ -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;
@@ -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)
@@ -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;
@@ -495,7 +498,7 @@ 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);
}
@@ -503,7 +506,7 @@ prof_locate_server(krb5_context context, const krb5_data *realm,
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);
@@ -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);
@@ -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;
@@ -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:
@@ -589,9 +598,10 @@ done:
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) {
@@ -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;
@@ -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
@@ -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);
diff --git a/src/lib/krb5/os/os-proto.h b/src/lib/krb5/os/os-proto.h
index 9125ba0..3196bca 100644
--- a/src/lib/krb5/os/os-proto.h
+++ b/src/lib/krb5/os/os-proto.h
@@ -38,11 +38,23 @@
#include <krb5/locate_plugin.h>
+typedef enum {
+ TCP_OR_UDP = 0,
+ TCP,
+ UDP,
+} k5_transport;
+
+typedef enum {
+ UDP_FIRST = 0,
+ UDP_LAST,
+ NO_UDP,
+} k5_transport_strategy;
+
/* A single server hostname or address. */
struct server_entry {
char *hostname; /* NULL -> use addrlen/addr instead */
int port; /* Used only if hostname set */
- int socktype; /* May be 0 for UDP/TCP if hostname set */
+ k5_transport transport; /* May be 0 for UDP/TCP if hostname set */
int family; /* May be 0 (aka AF_UNSPEC) if hostname set */
size_t addrlen;
struct sockaddr_storage addr;
@@ -56,8 +68,8 @@ struct serverlist {
#define SERVERLIST_INIT { NULL, 0 }
struct remote_address {
+ k5_transport transport;
int family;
- int type;
socklen_t len;
struct sockaddr_storage saddr;
};
@@ -69,12 +81,13 @@ struct sendto_callback_info {
};
krb5_error_code k5_locate_server(krb5_context, const krb5_data *realm,
- struct serverlist *,
- enum locate_service_type svc, int socktype);
+ struct serverlist *serverlist,
+ enum locate_service_type svc,
+ krb5_boolean no_udp);
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);
krb5_boolean k5_kdc_is_master(krb5_context context, const krb5_data *realm,
struct server_entry *server);
@@ -103,7 +116,7 @@ int _krb5_conf_boolean (const char *);
krb5_error_code k5_sendto(krb5_context context, const krb5_data *message,
const struct serverlist *addrs,
- int socktype1, int socktype2,
+ k5_transport_strategy strategy,
struct sendto_callback_info *callback_info,
krb5_data *reply, struct sockaddr *remoteaddr,
socklen_t *remoteaddrlen, int *server_used,
diff --git a/src/lib/krb5/os/sendto_kdc.c b/src/lib/krb5/os/sendto_kdc.c
index e3855a3..3f99ce8 100644
--- a/src/lib/krb5/os/sendto_kdc.c
+++ b/src/lib/krb5/os/sendto_kdc.c
@@ -104,6 +104,7 @@ struct conn_state {
size_t server_index;
struct conn_state *next;
time_ms endtime;
+ krb5_boolean defer;
};
/* Get current time in milliseconds. */
@@ -293,6 +294,19 @@ cm_select_or_poll(const struct select_state *in, time_ms endtime,
}
static int
+socktype_for_transport(k5_transport transport)
+{
+ switch (transport) {
+ case UDP:
+ return SOCK_DGRAM;
+ case TCP:
+ return SOCK_STREAM;
+ default:
+ return 0;
+ }
+}
+
+static int
check_for_svc_unavailable (krb5_context context,
const krb5_data *reply,
void *msg_handler_data)
@@ -330,11 +344,12 @@ check_for_svc_unavailable (krb5_context context,
krb5_error_code
krb5_sendto_kdc(krb5_context context, const krb5_data *message,
const krb5_data *realm, krb5_data *reply, int *use_master,
- int tcp_only)
+ int no_udp)
{
krb5_error_code retval, err;
struct serverlist servers;
- int socktype1 = 0, socktype2 = 0, server_used;
+ int server_used;
+ k5_transport_strategy strategy;
/*
* find KDC location(s) for realm
@@ -349,9 +364,9 @@ krb5_sendto_kdc(krb5_context context, const krb5_data *message,
* should probably be returned as well.
*/
- TRACE_SENDTO_KDC(context, message->length, realm, *use_master, tcp_only);
+ TRACE_SENDTO_KDC(context, message->length, realm, *use_master, no_udp);
- if (!tcp_only && context->udp_pref_limit < 0) {
+ if (!no_udp && context->udp_pref_limit < 0) {
int tmp;
retval = profile_get_integer(context->profile,
KRB5_CONF_LIBDEFAULTS, KRB5_CONF_UDP_PREFERENCE_LIMIT, 0,
@@ -368,22 +383,21 @@ krb5_sendto_kdc(krb5_context context, const krb5_data *message,
context->udp_pref_limit = tmp;
}
- if (tcp_only)
- socktype1 = SOCK_STREAM, socktype2 = 0;
+ if (no_udp)
+ strategy = NO_UDP;
else if (message->length <= (unsigned int) context->udp_pref_limit)
- socktype1 = SOCK_DGRAM, socktype2 = SOCK_STREAM;
+ strategy = UDP_FIRST;
else
- socktype1 = SOCK_STREAM, socktype2 = SOCK_DGRAM;
+ strategy = UDP_LAST;
- retval = k5_locate_kdc(context, realm, &servers, *use_master,
- tcp_only ? SOCK_STREAM : 0);
+ retval = k5_locate_kdc(context, realm, &servers, *use_master, no_udp);
if (retval)
return retval;
err = 0;
- retval = k5_sendto(context, message, &servers, socktype1, socktype2,
- NULL, reply, NULL, NULL, &server_used,
- check_for_svc_unavailable, &err);
+ retval = k5_sendto(context, message, &servers, strategy, NULL, reply,
+ NULL, NULL, &server_used, check_for_svc_unavailable,
+ &err);
if (retval == KRB5_KDC_UNREACH) {
if (err == KDC_ERR_SVC_UNAVAILABLE) {
retval = KRB5KDC_ERR_SVC_UNAVAILABLE;
@@ -444,7 +458,7 @@ set_transport_message(struct conn_state *state, const krb5_data *message)
if (message == NULL || message->length == 0)
return;
- if (state->addr.type == SOCK_STREAM) {
+ if (state->addr.transport == TCP) {
store_32_be(message->length, out->msg_len_buf);
SG_SET(&out->sgbuf[0], out->msg_len_buf, 4);
SG_SET(&out->sgbuf[1], message->data, message->length);
@@ -457,8 +471,9 @@ set_transport_message(struct conn_state *state, const krb5_data *message)
}
static krb5_error_code
-add_connection(struct conn_state **conns, struct addrinfo *ai,
- size_t server_index, char **udpbufp)
+add_connection(struct conn_state **conns, k5_transport transport,
+ krb5_boolean defer, struct addrinfo *ai, size_t server_index,
+ char **udpbufp)
{
struct conn_state *state, **tailptr;
@@ -467,14 +482,15 @@ add_connection(struct conn_state **conns, struct addrinfo *ai,
return ENOMEM;
state->state = INITIALIZING;
state->out.sgp = state->out.sgbuf;
- state->addr.type = ai->ai_socktype;
+ state->addr.transport = transport;
state->addr.family = ai->ai_family;
state->addr.len = ai->ai_addrlen;
memcpy(&state->addr.saddr, ai->ai_addr, ai->ai_addrlen);
+ state->defer = defer;
state->fd = INVALID_SOCKET;
state->server_index = server_index;
SG_SET(&state->out.sgbuf[1], NULL, 0);
- if (ai->ai_socktype == SOCK_STREAM) {
+ if (transport == TCP) {
state->service = service_tcp_fd;
} else {
state->service = service_udp_fd;
@@ -549,32 +565,41 @@ translate_ai_error (int err)
*/
static krb5_error_code
resolve_server(krb5_context context, const struct serverlist *servers,
- size_t ind, int socktype1, int socktype2,
+ size_t ind, k5_transport_strategy strategy,
const krb5_data *message, char **udpbufp,
struct conn_state **conns)
{
krb5_error_code retval;
struct server_entry *entry = &servers->servers[ind];
+ k5_transport transport;
struct addrinfo *addrs, *a, hint, ai;
+ krb5_boolean defer;
int err, result;
char portbuf[64];
- /* Skip any stray entries of socktypes we don't want. */
- if (entry->socktype != 0 && entry->socktype != socktype1 &&
- entry->socktype != socktype2)
+ /* Skip UDP entries if we don't want UDP. */
+ if (strategy == NO_UDP && entry->transport == UDP)
return 0;
+ transport = (strategy == UDP_FIRST) ? UDP : TCP;
if (entry->hostname == NULL) {
- ai.ai_socktype = entry->socktype;
+ /* Added by a module, so transport is either TCP or UDP. */
+ ai.ai_socktype = socktype_for_transport(entry->transport);
ai.ai_family = entry->family;
ai.ai_addrlen = entry->addrlen;
ai.ai_addr = (struct sockaddr *)&entry->addr;
- return add_connection(conns, &ai, ind, udpbufp);
+ defer = (entry->transport != transport);
+ return add_connection(conns, entry->transport, defer, &ai, ind,
+ udpbufp);
}
+ /* If the entry has a specified transport, use it. */
+ if (entry->transport != TCP_OR_UDP)
+ transport = entry->transport;
+
memset(&hint, 0, sizeof(hint));
hint.ai_family = entry->family;
- hint.ai_socktype = (entry->socktype != 0) ? entry->socktype : socktype1;
+ hint.ai_socktype = socktype_for_transport(transport);
hint.ai_flags = AI_ADDRCONFIG;
#ifdef AI_NUMERICSERV
hint.ai_flags |= AI_NUMERICSERV;
@@ -586,15 +611,19 @@ resolve_server(krb5_context context, const struct serverlist *servers,
err = getaddrinfo(entry->hostname, portbuf, &hint, &addrs);
if (err)
return translate_ai_error(err);
- /* Add each address with the preferred socktype. */
+
+ /* Add each address with the specified or preferred transport. */
retval = 0;
for (a = addrs; a != 0 && retval == 0; a = a->ai_next)
- retval = add_connection(conns, a, ind, udpbufp);
- if (retval == 0 && entry->socktype == 0 && socktype2 != 0) {
- /* Add each address again with the non-preferred socktype. */
+ retval = add_connection(conns, transport, FALSE, a, ind, udpbufp);
+
+ /* For TCP_OR_UDP entries, add each address again with the non-preferred
+ * transport, unless we are avoiding UDP. Flag these as deferred. */
+ if (retval == 0 && entry->transport == TCP_OR_UDP && strategy != NO_UDP) {
+ transport = (strategy == UDP_FIRST) ? TCP : UDP;
for (a = addrs; a != 0 && retval == 0; a = a->ai_next) {
- a->ai_socktype = socktype2;
- retval = add_connection(conns, a, ind, udpbufp);
+ a->ai_socktype = socktype_for_transport(transport);
+ retval = add_connection(conns, transport, TRUE, a, ind, udpbufp);
}
}
freeaddrinfo(addrs);
@@ -606,17 +635,18 @@ start_connection(krb5_context context, struct conn_state *state,
const krb5_data *message, struct select_state *selstate,
struct sendto_callback_info *callback_info)
{
- int fd, e;
+ int fd, e, type;
static const int one = 1;
static const struct linger lopt = { 0, 0 };
- fd = socket(state->addr.family, state->addr.type, 0);
+ type = socktype_for_transport(state->addr.transport);
+ fd = socket(state->addr.family, type, 0);
if (fd == INVALID_SOCKET)
return -1; /* try other hosts */
set_cloexec_fd(fd);
/* Make it non-blocking. */
ioctlsocket(fd, FIONBIO, (const void *) &one);
- if (state->addr.type == SOCK_STREAM) {
+ if (state->addr.transport == TCP) {
setsockopt(fd, SOL_SOCKET, SO_LINGER, &lopt, sizeof(lopt));
TRACE_SENDTO_KDC_TCP_CONNECT(context, &state->addr);
}
@@ -665,7 +695,7 @@ start_connection(krb5_context context, struct conn_state *state,
}
set_transport_message(state, message);
- if (state->addr.type == SOCK_DGRAM) {
+ if (state->addr.transport == UDP) {
/* Send it now. */
ssize_t ret;
sg_buf *sg = &state->out.sgbuf[0];
@@ -720,7 +750,7 @@ maybe_send(krb5_context context, struct conn_state *conn,
return -1;
}
- if (conn->addr.type == SOCK_STREAM) {
+ if (conn->addr.transport != UDP) {
/* The select callback will handle flushing any data we
haven't written yet, and we only write it once. */
return -1;
@@ -910,7 +940,7 @@ get_endtime(time_ms endtime, struct conn_state *conns)
struct conn_state *state;
for (state = conns; state != NULL; state = state->next) {
- if (state->addr.type == SOCK_STREAM &&
+ if (state->addr.transport == TCP &&
(state->state == READING || state->state == WRITING) &&
state->endtime > endtime)
endtime = state->endtime;
@@ -1008,7 +1038,7 @@ service_fds(krb5_context context, struct select_state *selstate,
krb5_error_code
k5_sendto(krb5_context context, const krb5_data *message,
- const struct serverlist *servers, int socktype1, int socktype2,
+ const struct serverlist *servers, k5_transport_strategy strategy,
struct sendto_callback_info* callback_info, krb5_data *reply,
struct sockaddr *remoteaddr, socklen_t *remoteaddrlen,
int *server_used,
@@ -1038,17 +1068,18 @@ k5_sendto(krb5_context context, const krb5_data *message,
cm_init_selstate(sel_state);
/* First pass: resolve server hosts, communicate with resulting addresses
- * of the preferred socktype, and wait 1s for an answer from each. */
+ * of the preferred transport, and wait 1s for an answer from each. */
for (s = 0; s < servers->nservers && !done; s++) {
/* Find the current tail pointer. */
for (tailptr = &conns; *tailptr != NULL; tailptr = &(*tailptr)->next);
- retval = resolve_server(context, servers, s, socktype1, socktype2,
- message, &udpbuf, &conns);
+ retval = resolve_server(context, servers, s, strategy, message,
+ &udpbuf, &conns);
if (retval)
goto cleanup;
for (state = *tailptr; state != NULL && !done; state = state->next) {
- /* Contact each new connection whose socktype matches socktype1. */
- if (state->addr.type != socktype1)
+ /* Contact each new connection, deferring those which use the
+ * non-preferred RFC 4120 transport. */
+ if (state->defer)
continue;
if (maybe_send(context, state, message, sel_state, callback_info))
continue;
@@ -1057,10 +1088,10 @@ k5_sendto(krb5_context context, const krb5_data *message,
}
}
- /* Complete the first pass by contacting servers of the non-preferred
- * socktype (if given), waiting 1s for an answer from each. */
+ /* Complete the first pass by contacting servers of the non-preferred RFC
+ * 4120 transport (if given), waiting 1s for an answer from each. */
for (state = conns; state != NULL && !done; state = state->next) {
- if (state->addr.type != socktype2)
+ if (!state->defer)
continue;
if (maybe_send(context, state, message, sel_state, callback_info))
continue;
diff --git a/src/lib/krb5/os/t_locate_kdc.c b/src/lib/krb5/os/t_locate_kdc.c
index 5453a4c..300aa71 100644
--- a/src/lib/krb5/os/t_locate_kdc.c
+++ b/src/lib/krb5/os/t_locate_kdc.c
@@ -29,18 +29,18 @@ kfatal (krb5_error_code err)
}
static const char *
-stypename (int stype)
+ttypename (k5_transport ttype)
{
static char buf[20];
- switch (stype) {
- case SOCK_STREAM:
- return "stream";
- case SOCK_DGRAM:
- return "dgram";
- case SOCK_RAW:
- return "raw";
+ switch (ttype) {
+ case TCP_OR_UDP:
+ return "tcp or udp";
+ case TCP:
+ return "tcp";
+ case UDP:
+ return "udp";
default:
- snprintf(buf, sizeof(buf), "?%d", stype);
+ snprintf(buf, sizeof(buf), "?%d", ttype);
return buf;
}
}
@@ -58,7 +58,7 @@ print_addrs (void)
if (entry->hostname != NULL) {
printf("%2d: host %s\t%s\tport %d\n", (int)i, entry->hostname,
- stypename(entry->socktype), ntohs(entry->port));
+ ttypename(entry->transport), ntohs(entry->port));
continue;
}
err = getnameinfo((struct sockaddr *)&entry->addr, entry->addrlen,
@@ -69,7 +69,7 @@ print_addrs (void)
gai_strerror(err));
} else {
printf("%2d: address %s\t%s\tport %s\n", (int)i, hostbuf,
- stypename(entry->socktype), srvbuf);
+ ttypename(entry->transport), srvbuf);
}
}
}
@@ -129,7 +129,7 @@ main (int argc, char *argv[])
break;
case LOOKUP_WHATEVER:
- err = k5_locate_kdc(ctx, &realm, &sl, master, 0);
+ err = k5_locate_kdc(ctx, &realm, &sl, master, FALSE);
break;
}
if (err) kfatal (err);
diff --git a/src/lib/krb5/os/t_std_conf.c b/src/lib/krb5/os/t_std_conf.c
index e2ff572..6ee54d5 100644
--- a/src/lib/krb5/os/t_std_conf.c
+++ b/src/lib/krb5/os/t_std_conf.c
@@ -82,7 +82,7 @@ test_locate_kdc(krb5_context ctx, char *realm)
rlm.data = realm;
rlm.length = strlen(realm);
- retval = k5_locate_kdc(ctx, &rlm, &servers, get_masters, 0);
+ retval = k5_locate_kdc(ctx, &rlm, &servers, get_masters, FALSE);
if (retval) {
com_err("krb5_locate_kdc", retval, 0);
return;
diff --git a/src/lib/krb5/os/t_trace.c b/src/lib/krb5/os/t_trace.c
index 36044f5..4cb2bd0 100644
--- a/src/lib/krb5/os/t_trace.c
+++ b/src/lib/krb5/os/t_trace.c
@@ -112,7 +112,7 @@ main (int argc, char *argv[])
TRACE(ctx, "size_t and const char *, as four-character hex hash: "
"{hashlenstr}", 1, NULL);
- ra.type = SOCK_STREAM;
+ ra.transport = TCP;
addr_in = (struct sockaddr_in *)&ra.saddr;
addr_in->sin_family = AF_INET;
addr_in->sin_addr.s_addr = INADDR_ANY;
@@ -121,10 +121,10 @@ main (int argc, char *argv[])
ra.family = AF_INET;
TRACE(ctx, "struct remote_address *, show socket type, address, port: "
"{raddr}", &ra);
- ra.type = SOCK_DGRAM;
+ ra.transport = UDP;
TRACE(ctx, "struct remote_address *, show socket type, address, port: "
"{raddr}", &ra);
- ra.type = 1234;
+ ra.transport = 1234;
addr_in->sin_family = AF_UNSPEC;
ra.family = AF_UNSPEC;
TRACE(ctx, "struct remote_address *, show socket type, address, port: "
diff --git a/src/lib/krb5/os/t_trace.ref b/src/lib/krb5/os/t_trace.ref
index 749d9c9..ca5818a 100644
--- a/src/lib/krb5/os/t_trace.ref
+++ b/src/lib/krb5/os/t_trace.ref
@@ -10,8 +10,8 @@ size_t and const char *, as four-character hex hash: 7B9A
size_t and const char *, as four-character hex hash: (null)
struct remote_address *, show socket type, address, port: stream 0.0.0.0:88
struct remote_address *, show socket type, address, port: dgram 0.0.0.0:88
-struct remote_address *, show socket type, address, port: socktype1234 AF_UNSPEC
-struct remote_address *, show socket type, address, port: socktype1234 af5678
+struct remote_address *, show socket type, address, port: transport1234 AF_UNSPEC
+struct remote_address *, show socket type, address, port: transport1234 af5678
krb5_data *, display as counted string: example.data
krb5_data *, display as counted string: (null)
krb5_data *, display as hex bytes: 6578616D706C652E64617461
diff --git a/src/lib/krb5/os/trace.c b/src/lib/krb5/os/trace.c
index 525742c..8319a86 100644
--- a/src/lib/krb5/os/trace.c
+++ b/src/lib/krb5/os/trace.c
@@ -197,12 +197,12 @@ trace_format(krb5_context context, const char *fmt, va_list ap)
}
} else if (strcmp(tmpbuf, "raddr") == 0) {
ra = va_arg(ap, struct remote_address *);
- if (ra->type == SOCK_DGRAM)
+ if (ra->transport == UDP)
k5_buf_add(&buf, "dgram");
- else if (ra->type == SOCK_STREAM)
+ else if (ra->transport == TCP)
k5_buf_add(&buf, "stream");
else
- k5_buf_add_fmt(&buf, "socktype%d", ra->type);
+ k5_buf_add_fmt(&buf, "transport%d", ra->transport);
if (getnameinfo((struct sockaddr *)&ra->saddr, ra->len,
addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf),
More information about the cvs-krb5
mailing list