diff options
Diffstat (limited to '0003-Use-k5_transport-_strategy-enums-for-k5_sendto.patch')
-rw-r--r-- | 0003-Use-k5_transport-_strategy-enums-for-k5_sendto.patch | 913 |
1 files changed, 913 insertions, 0 deletions
diff --git a/0003-Use-k5_transport-_strategy-enums-for-k5_sendto.patch b/0003-Use-k5_transport-_strategy-enums-for-k5_sendto.patch new file mode 100644 index 0000000..ba3f91c --- /dev/null +++ b/0003-Use-k5_transport-_strategy-enums-for-k5_sendto.patch @@ -0,0 +1,913 @@ +From 9c6be00daca0b80aed94ec9680724f95e6be92e1 Mon Sep 17 00:00:00 2001 +From: "Robbie Harwood (frozencemetery)" <rharwood@club.cc.cmu.edu> +Date: Thu, 15 Aug 2013 15:55:52 -0400 +Subject: [PATCH 03/13] 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@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 +--- + 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), +-- +2.1.0 + |