From 9c6be00daca0b80aed94ec9680724f95e6be92e1 Mon Sep 17 00:00:00 2001 From: "Robbie Harwood (frozencemetery)" 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 +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