int krb5int_add_host_to_list (struct addrlist *lp, const char *hostname, int port, int secport, int socktype, int family) { struct addrinfo *addrs, *a, *anext, hint; int err; char portbuf[10], secportbuf[10]; void (*freefn)(void *); Tprintf ("adding hostname %s, ports %d,%d, family %d, socktype %d\n", hostname, ntohs (port), ntohs (secport), family, socktype); memset(&hint, 0, sizeof(hint)); hint.ai_family = family; hint.ai_socktype = socktype; #ifdef AI_NUMERICSERV hint.ai_flags = AI_NUMERICSERV; #endif sprintf(portbuf, "%d", ntohs(port)); sprintf(secportbuf, "%d", ntohs(secport)); err = getaddrinfo (hostname, portbuf, &hint, &addrs); if (err) { Tprintf ("\tgetaddrinfo(\"%s\", \"%s\", ...)\n\treturns %d: %s\n", hostname, portbuf, err, gai_strerror (err)); return translate_ai_error (err); } freefn = call_freeaddrinfo; anext = 0; for (a = addrs; a != 0 && err == 0; a = anext, freefn = 0) { anext = a->ai_next; err = add_addrinfo_to_list (lp, a, freefn, a); } if (err || secport == 0) goto egress; if (socktype == 0) socktype = SOCK_DGRAM; else if (socktype != SOCK_DGRAM) goto egress; hint.ai_family = AF_INET; err = getaddrinfo (hostname, secportbuf, &hint, &addrs); if (err) { err = translate_ai_error (err); goto egress; } freefn = call_freeaddrinfo; for (a = addrs; a != 0 && err == 0; a = anext, freefn = 0) { anext = a->ai_next; err = add_addrinfo_to_list (lp, a, freefn, a); } egress: /* Solaris Kerberos */ if (anext) freeaddrinfo (anext); return err; }
/* * Resolve the entry in servers with index ind, adding connections to the list * *conns. Connections are added for each of socktype1 and (if not zero) * socktype2. message and udpbufp are used to initialize the connections; see * add_connection above. If no addresses are available for an entry but no * internal name resolution failure occurs, return 0 without adding any new * connections. */ static krb5_error_code resolve_server(krb5_context context, const struct serverlist *servers, size_t ind, int socktype1, int socktype2, const krb5_data *message, char **udpbufp, struct conn_state **conns) { krb5_error_code retval; struct server_entry *entry = &servers->servers[ind]; struct addrinfo *addrs, *a, hint, ai; 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) return 0; if (entry->hostname == NULL) { ai.ai_socktype = entry->socktype; ai.ai_family = entry->family; ai.ai_addrlen = entry->addrlen; ai.ai_addr = (struct sockaddr *)&entry->addr; return add_connection(conns, &ai, ind, message, udpbufp); } memset(&hint, 0, sizeof(hint)); hint.ai_family = entry->family; hint.ai_socktype = (entry->socktype != 0) ? entry->socktype : socktype1; #ifdef AI_NUMERICSERV hint.ai_flags = AI_NUMERICSERV; #endif result = snprintf(portbuf, sizeof(portbuf), "%d", ntohs(entry->port)); if (SNPRINTF_OVERFLOW(result, sizeof(portbuf))) return EINVAL; TRACE_SENDTO_KDC_RESOLVING(context, entry->hostname); err = getaddrinfo(entry->hostname, portbuf, &hint, &addrs); if (err) return translate_ai_error(err); /* Add each address with the preferred socktype. */ retval = 0; for (a = addrs; a != 0 && retval == 0; a = a->ai_next) retval = add_connection(conns, a, ind, message, udpbufp); if (retval == 0 && entry->socktype == 0 && socktype2 != 0) { /* Add each address again with the non-preferred socktype. */ for (a = addrs; a != 0 && retval == 0; a = a->ai_next) { a->ai_socktype = socktype2; retval = add_connection(conns, a, ind, message, udpbufp); } } freeaddrinfo(addrs); return retval; }
/* * Resolve the entry in servers with index ind, adding connections to the list * *conns. Connections are added for each of socktype1 and (if not zero) * socktype2. message and udpbufp are used to initialize the connections; see * add_connection above. If no addresses are available for an entry but no * internal name resolution failure occurs, return 0 without adding any new * connections. */ static krb5_error_code resolve_server(krb5_context context, const krb5_data *realm, const struct serverlist *servers, 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 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) { /* 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; defer = (entry->transport != transport); return add_connection(conns, entry->transport, defer, &ai, ind, realm, NULL, entry->uri_path, 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 = socktype_for_transport(transport); hint.ai_flags = AI_ADDRCONFIG; #ifdef AI_NUMERICSERV hint.ai_flags |= AI_NUMERICSERV; #endif result = snprintf(portbuf, sizeof(portbuf), "%d", ntohs(entry->port)); if (SNPRINTF_OVERFLOW(result, sizeof(portbuf))) return EINVAL; TRACE_SENDTO_KDC_RESOLVING(context, entry->hostname); err = getaddrinfo(entry->hostname, portbuf, &hint, &addrs); if (err) return translate_ai_error(err); /* 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, transport, FALSE, a, ind, realm, entry->hostname, entry->uri_path, 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 = socktype_for_transport(transport); retval = add_connection(conns, transport, TRUE, a, ind, realm, entry->hostname, entry->uri_path, udpbufp); } } freeaddrinfo(addrs); return retval; }