unsigned int is_udp : 1;
int (*service)(krb5_context context, struct conn_state *,
struct select_state *, int);
- struct addrinfo *addr;
+ int socktype;
+ int family;
+ size_t addrlen;
+ struct sockaddr_storage addr;
struct {
struct {
sg_buf sgbuf[2];
} out;
struct incoming_krb5_message in;
} x;
+ krb5_data callback_buffer;
+ size_t server_index;
+ struct conn_state *next;
};
struct sendto_callback_info {
#include "k5-gmt_mktime.h"
-struct addrlist;
struct sendto_callback_info;
/* libos.spec */
krb5_error_code
krb5int_get_domain_realm_mapping(krb5_context , const char *, char ***);
-/* N.B.: You need to include fake-addrinfo.h *before* k5-int.h if you're
- going to use this structure. */
-struct addrlist {
- struct {
-#ifdef FAI_DEFINED
- struct addrinfo *ai;
-#else
- struct undefined_addrinfo *ai;
-#endif
- void (*freefn)(void *);
- void *data;
- } *addrs;
- size_t naddrs;
- size_t space;
-};
-#define ADDRLIST_INIT { 0, 0, 0 }
-extern void krb5int_free_addrlist(struct addrlist *);
-extern int krb5int_grow_addrlist(struct addrlist *, int);
-extern int krb5int_add_host_to_list(struct addrlist *, const char *,
- int, int, int, int);
-
-#include <krb5/locate_plugin.h>
-krb5_error_code
-krb5int_locate_server(krb5_context, const krb5_data *realm,
- struct addrlist *, enum locate_service_type svc,
- int sockettype, int family);
-
struct derived_key {
krb5_data constant;
krb5_key dkey;
/* To keep happy libraries which are (for now) accessing internal stuff */
/* Make sure to increment by one when changing the struct */
-#define KRB5INT_ACCESS_STRUCT_VERSION 16
+#define KRB5INT_ACCESS_STRUCT_VERSION 17
#ifndef ANAME_SZ
struct ktext; /* from krb.h, for krb524 support */
krb5_error_code (*auth_con_get_subkey_enctype)(krb5_context,
krb5_auth_context,
krb5_enctype *);
- /* service location and communication */
- krb5_error_code (*sendto_udp)(krb5_context, const krb5_data *msg,
- const struct addrlist *,
- struct sendto_callback_info *,
- krb5_data *reply, struct sockaddr *,
- socklen_t *, struct sockaddr *,
- socklen_t *, int *,
- int (*msg_handler)(krb5_context,
- const krb5_data *,
- void *),
- void *msg_handler_data);
- krb5_error_code (*add_host_to_list)(struct addrlist *lp,
- const char *hostname,
- int port, int secport,
- int socktype, int family);
- void (*free_addrlist)(struct addrlist *);
-
- krb5_error_code (*make_srv_query_realm)(const krb5_data *realm,
- const char *service,
- const char *protocol,
- struct srv_dns_entry **answers);
- void (*free_srv_dns_data)(struct srv_dns_entry *);
- int (*use_dns_kdc)(krb5_context);
+
krb5_error_code (*clean_hostname)(krb5_context, const char *, char *,
size_t);
* {lenstr} size_t and const char *, as a counted string
* {hexlenstr} size_t and const char *, as hex bytes
* {hashlenstr} size_t and const char *, as four-character hex hash
- * {addrinfo} struct addrinfo *, show socket type, address, port
+ * {connstate} struct conn_state *, show socket type, address, port
* {data} krb5_data *, display as counted string
* {hexdata} krb5_data *, display as hex bytes
* {errno} int, display as number/errorstring
rlm, (master) ? " (master)" : "", (tcp) ? " (tcp only)" : ""))
#define TRACE_SENDTO_KDC_MASTER(c, master) \
TRACE(c, (c, "Response was{str} from master KDC", (master) ? "" : " not"))
-#define TRACE_SENDTO_KDC_RESPONSE(c, addr) \
- TRACE(c, (c, "Received answer from {addrinfo}", addr))
-#define TRACE_SENDTO_KDC_TCP_CONNECT(c, addr) \
- TRACE(c, (c, "Initiating TCP connection to {addrinfo}", addr))
-#define TRACE_SENDTO_KDC_TCP_DISCONNECT(c, addr) \
- TRACE(c, (c, "Terminating TCP connection to {addrinfo}", addr))
-#define TRACE_SENDTO_KDC_TCP_ERROR_CONNECT(c, addr, err) \
- TRACE(c, (c, "TCP error connecting to {addrinfo}: {errno}", addr, err))
-#define TRACE_SENDTO_KDC_TCP_ERROR_RECV(c, addr, err) \
- TRACE(c, (c, "TCP error receiving from {addrinfo}: {errno}", addr, err))
-#define TRACE_SENDTO_KDC_TCP_ERROR_RECV_LEN(c, addr, err) \
- TRACE(c, (c, "TCP error receiving from {addrinfo}: {errno}", addr, err))
-#define TRACE_SENDTO_KDC_TCP_ERROR_SEND(c, addr, err) \
- TRACE(c, (c, "TCP error sending to {addrinfo}: {errno}", addr, err))
-#define TRACE_SENDTO_KDC_TCP_SEND(c, addr) \
- TRACE(c, (c, "Sending TCP request to {addrinfo}", addr))
-#define TRACE_SENDTO_KDC_UDP_ERROR_RECV(c, addr, err) \
- TRACE(c, (c, "UDP error receiving from {addrinfo}: {errno}", addr, err))
-#define TRACE_SENDTO_KDC_UDP_ERROR_SEND_INITIAL(c, addr, err) \
- TRACE(c, (c, "UDP error sending to {addrinfo}: {errno}", addr, err))
-#define TRACE_SENDTO_KDC_UDP_ERROR_SEND_RETRY(c, addr, err) \
- TRACE(c, (c, "UDP error sending to {addrinfo}: {errno}", addr, err))
-#define TRACE_SENDTO_KDC_UDP_SEND_INITIAL(c, addr) \
- TRACE(c, (c, "Sending initial UDP request to {addrinfo}", addr))
-#define TRACE_SENDTO_KDC_UDP_SEND_RETRY(c, addr) \
- TRACE(c, (c, "Sending retry UDP request to {addrinfo}", addr))
+#define TRACE_SENDTO_KDC_RESOLVING(c, hostname) \
+ TRACE(c, (c, "Resolving hostname {str}", hostname))
+#define TRACE_SENDTO_KDC_RESPONSE(c, conn) \
+ TRACE(c, (c, "Received answer from {connstate}", conn))
+#define TRACE_SENDTO_KDC_TCP_CONNECT(c, conn) \
+ TRACE(c, (c, "Initiating TCP connection to {connstate}", conn))
+#define TRACE_SENDTO_KDC_TCP_DISCONNECT(c, conn) \
+ TRACE(c, (c, "Terminating TCP connection to {connstate}", conn))
+#define TRACE_SENDTO_KDC_TCP_ERROR_CONNECT(c, conn, err) \
+ TRACE(c, (c, "TCP error connecting to {connstate}: {errno}", conn, err))
+#define TRACE_SENDTO_KDC_TCP_ERROR_RECV(c, conn, err) \
+ TRACE(c, (c, "TCP error receiving from {connstate}: {errno}", conn, err))
+#define TRACE_SENDTO_KDC_TCP_ERROR_RECV_LEN(c, conn, err) \
+ TRACE(c, (c, "TCP error receiving from {connstate}: {errno}", conn, err))
+#define TRACE_SENDTO_KDC_TCP_ERROR_SEND(c, conn, err) \
+ TRACE(c, (c, "TCP error sending to {connstate}: {errno}", conn, err))
+#define TRACE_SENDTO_KDC_TCP_SEND(c, conn) \
+ TRACE(c, (c, "Sending TCP request to {connstate}", conn))
+#define TRACE_SENDTO_KDC_UDP_ERROR_RECV(c, conn, err) \
+ TRACE(c, (c, "UDP error receiving from {connstate}: {errno}", conn, err))
+#define TRACE_SENDTO_KDC_UDP_ERROR_SEND_INITIAL(c, conn, err) \
+ TRACE(c, (c, "UDP error sending to {connstate}: {errno}", conn, err))
+#define TRACE_SENDTO_KDC_UDP_ERROR_SEND_RETRY(c, conn, err) \
+ TRACE(c, (c, "UDP error sending to {connstate}: {errno}", conn, err))
+#define TRACE_SENDTO_KDC_UDP_SEND_INITIAL(c, conn) \
+ TRACE(c, (c, "Sending initial UDP request to {connstate}", conn))
+#define TRACE_SENDTO_KDC_UDP_SEND_RETRY(c, conn) \
+ TRACE(c, (c, "Sending retry UDP request to {connstate}", conn))
#define TRACE_SEND_TGS_ETYPES(c, etypes) \
TRACE(c, (c, "etypes requested in TGS request: {etypes}", etypes))
initialize_k5e1_error_table
initialize_kv5m_error_table
initialize_prof_error_table
+k5_free_serverlist
+k5_locate_kdc
k5_plugin_free_modules
k5_plugin_load
k5_plugin_load_all
krb5_ktf_writable_ops
krb5_kts_ops
krb5_kuserok
-krb5_locate_kdc
krb5_lock_file
krb5_make_authdata_kdc_issued
krb5_make_full_ipaddr
krb5int_find_authdata
krb5int_find_pa_data
krb5int_foreach_localaddr
-krb5int_free_addrlist
krb5int_free_data_list
krb5int_get_authdata_containee_types
krb5int_init_context_kdc
krb5int_access internals_temp;
#endif
S (arcfour_gsscrypt, krb5int_arcfour_gsscrypt),
- S (free_addrlist, krb5int_free_addrlist),
S (auth_con_get_subkey_enctype, krb5_auth_con_get_subkey_enctype),
- S (sendto_udp, &krb5int_sendto),
- S (add_host_to_list, krb5int_add_host_to_list),
-#ifdef KRB5_DNS_LOOKUP
-#define SC(FIELD, VAL) S(FIELD, VAL)
-#else /* disable */
-#define SC(FIELD, VAL) S(FIELD, 0)
-#endif
- SC (make_srv_query_realm, krb5int_make_srv_query_realm),
- SC (free_srv_dns_data, krb5int_free_srv_dns_data),
- SC (use_dns_kdc, _krb5_use_dns_kdc),
-#undef SC
S (clean_hostname, krb5int_clean_hostname),
S (mandatory_cksumtype, krb5int_c_mandatory_cksumtype),
static krb5_error_code
locate_kpasswd(krb5_context context, const krb5_data *realm,
- struct addrlist *addrlist, krb5_boolean useTcp)
+ struct serverlist *serverlist, int socktype)
{
krb5_error_code code;
- int sockType = (useTcp ? SOCK_STREAM : SOCK_DGRAM);
- code = krb5int_locate_server (context, realm, addrlist,
- locate_service_kpasswd, sockType, AF_UNSPEC);
+ code = k5_locate_server(context, realm, serverlist, locate_service_kpasswd,
+ socktype);
if (code == KRB5_REALM_CANT_RESOLVE || code == KRB5_REALM_UNKNOWN) {
- code = krb5int_locate_server (context, realm, addrlist,
- locate_service_kadmin, SOCK_STREAM,
- AF_UNSPEC);
+ code = k5_locate_server(context, realm, serverlist,
+ locate_service_kadmin, SOCK_STREAM);
if (!code) {
/* Success with admin_server but now we need to change the
port number to use DEFAULT_KPASSWD_PORT and the socktype. */
size_t i;
- for (i=0; i<addrlist->naddrs; i++) {
- struct addrinfo *a = addrlist->addrs[i].ai;
+ for (i = 0; i < serverlist->nservers; i++) {
+ struct server_entry *s = &serverlist->servers[i];
krb5_ui_2 kpasswd_port = htons(DEFAULT_KPASSWD_PORT);
- if (a->ai_family == AF_INET)
- sa2sin (a->ai_addr)->sin_port = kpasswd_port;
- if (a->ai_family == AF_INET6)
- sa2sin6 (a->ai_addr)->sin6_port = kpasswd_port;
- if (sockType != SOCK_STREAM)
- a->ai_socktype = sockType;
+ if (socktype != SOCK_STREAM)
+ s->socktype = socktype;
+ if (s->hostname != NULL)
+ s->port = kpasswd_port;
+ else if (s->family == AF_INET)
+ ss2sin(&s->addr)->sin_port = kpasswd_port;
+ else if (s->family == AF_INET6)
+ ss2sin6(&s->addr)->sin6_port = kpasswd_port;
}
}
}
{
krb5_data chpw_rep;
krb5_address remote_kaddr;
- krb5_boolean useTcp = 0;
+ krb5_boolean use_tcp = 0;
GETSOCKNAME_ARG3_TYPE addrlen;
krb5_error_code code = 0;
char *code_string;
struct sendto_callback_context callback_ctx;
struct sendto_callback_info callback_info;
struct sockaddr_storage remote_addr;
- struct addrlist al = ADDRLIST_INIT;
+ struct serverlist sl = SERVERLIST_INIT;
memset(&chpw_rep, 0, sizeof(krb5_data));
memset( &callback_ctx, 0, sizeof(struct sendto_callback_context));
callback_ctx.local_seq_num = callback_ctx.auth_context->local_seq_number;
do {
+ int socktype = (use_tcp ? SOCK_STREAM : SOCK_DGRAM);
if ((code = locate_kpasswd(callback_ctx.context,
krb5_princ_realm(callback_ctx.context,
creds->server),
- &al, useTcp)))
+ &sl, socktype)))
break;
addrlen = sizeof(remote_addr);
callback_info.pfn_cleanup = kpasswd_sendto_msg_cleanup;
krb5_free_data_contents(callback_ctx.context, &chpw_rep);
- if ((code = krb5int_sendto(callback_ctx.context,
- NULL,
- &al,
- &callback_info,
- &chpw_rep,
- NULL,
- NULL,
- ss2sa(&remote_addr),
- &addrlen,
- NULL,
- NULL,
- NULL
- ))) {
-
+ code = k5_sendto(callback_ctx.context, NULL, &sl, socktype, 0,
+ &callback_info, &chpw_rep, ss2sa(&remote_addr),
+ &addrlen, NULL, NULL, NULL);
+ if (code) {
/*
* Here we may want to switch to TCP on some errors.
* right?
result_string);
if (code) {
- if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !useTcp ) {
- krb5int_free_addrlist (&al);
- useTcp = 1;
+ if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !use_tcp) {
+ k5_free_serverlist(&sl);
+ use_tcp = 1;
continue;
}
strncpy(result_code_string->data, code_string, result_code_string->length);
}
- if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !useTcp ) {
- krb5int_free_addrlist (&al);
- useTcp = 1;
+ if (code == KRB5KRB_ERR_RESPONSE_TOO_BIG && !use_tcp) {
+ k5_free_serverlist(&sl);
+ use_tcp = 1;
} else {
break;
}
if (callback_ctx.auth_context != NULL)
krb5_auth_con_free(callback_ctx.context, callback_ctx.auth_context);
- krb5int_free_addrlist (&al);
+ k5_free_serverlist(&sl);
krb5_free_data_contents(callback_ctx.context, &callback_ctx.ap_req);
krb5_free_data_contents(callback_ctx.context, &chpw_rep);
char **realm, int limit)
{
krb5_error_code retval = 0, r;
- struct addrlist alist;
+ struct serverlist slist;
krb5_data drealm;
char *cp = NULL, *fqdn, *dot;
drealm.data = cp;
/* Find a kdc based on this part of the domain name. */
- r = krb5_locate_kdc(context, &drealm, &alist, 0, SOCK_DGRAM, 0);
+ r = k5_locate_kdc(context, &drealm, &slist, FALSE, SOCK_DGRAM);
if (!r) { /* Found a KDC! */
- krb5int_free_addrlist(&alist);
+ k5_free_serverlist(&slist);
*realm = strdup(cp);
if (!*realm) {
retval = ENOMEM;
* or implied warranty.
*
*
- * get socket addresses for KDC.
+ * Get server hostnames or addresses for KDC.
*/
#include "fake-addrinfo.h"
#endif /* KRB5_DNS_LOOKUP */
-int
-krb5int_grow_addrlist (struct addrlist *lp, int nmore)
-{
- size_t i;
- size_t newspace = lp->space + nmore;
- size_t newsize = newspace * sizeof (*lp->addrs);
- void *newaddrs;
-
- newaddrs = realloc (lp->addrs, newsize);
- if (newaddrs == NULL)
- return ENOMEM;
- lp->addrs = newaddrs;
- for (i = lp->space; i < newspace; i++) {
- lp->addrs[i].ai = NULL;
- lp->addrs[i].freefn = NULL;
- lp->addrs[i].data = NULL;
- }
- lp->space = newspace;
- return 0;
-}
-#define grow_list krb5int_grow_addrlist
-
-/* Free up everything pointed to by the addrlist structure, but don't
+/* Free up everything pointed to by the serverlist structure, but don't
free the structure itself. */
void
-krb5int_free_addrlist (struct addrlist *lp)
+k5_free_serverlist (struct serverlist *list)
{
size_t i;
- for (i = 0; i < lp->naddrs; i++)
- if (lp->addrs[i].freefn)
- (lp->addrs[i].freefn)(lp->addrs[i].data);
- free (lp->addrs);
- lp->addrs = NULL;
- lp->naddrs = lp->space = 0;
-}
-#define free_list krb5int_free_addrlist
-static int
-translate_ai_error (int err)
-{
- switch (err) {
- case 0:
- return 0;
- case EAI_BADFLAGS:
- case EAI_FAMILY:
- case EAI_SOCKTYPE:
- case EAI_SERVICE:
- /* All of these indicate bad inputs to getaddrinfo. */
- return EINVAL;
- case EAI_AGAIN:
- /* Translate to standard errno code. */
- return EAGAIN;
- case EAI_MEMORY:
- /* Translate to standard errno code. */
- return ENOMEM;
-#ifdef EAI_ADDRFAMILY
- case EAI_ADDRFAMILY:
-#endif
-#if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME
- case EAI_NODATA:
-#endif
- case EAI_NONAME:
- /* Name not known or no address data, but no error. Do
- nothing more. */
- return 0;
-#ifdef EAI_OVERFLOW
- case EAI_OVERFLOW:
- /* An argument buffer overflowed. */
- return EINVAL; /* XXX */
-#endif
-#ifdef EAI_SYSTEM
- case EAI_SYSTEM:
- /* System error, obviously. */
- return errno;
-#endif
- default:
- /* An error code we haven't handled? */
- return EINVAL;
- }
+ for (i = 0; i < list->nservers; i++)
+ free(list->servers[i].hostname);
+ free(list->servers);
+ list->servers = NULL;
+ list->nservers = 0;
}
#include <stdarg.h>
#if 0
extern void krb5int_debug_fprint(const char *, ...);
#define dprint krb5int_debug_fprint
-#define print_addrlist krb5int_print_addrlist
-extern void print_addrlist (const struct addrlist *a);
#else
static inline void dprint(const char *fmt, ...) { }
-static inline void print_addrlist(const struct addrlist *a) { }
#endif
-static int
-add_addrinfo_to_list(struct addrlist *lp, struct addrinfo *a,
- void (*freefn)(void *), void *data)
+/* Make room for a new server entry in list and return a pointer to the new
+ * entry. (Do not increment list->nservers.) */
+static struct server_entry *
+new_server_entry(struct serverlist *list)
{
- int err;
+ struct server_entry *newservers, *entry;
+ size_t newspace = (list->nservers + 1) * sizeof(struct server_entry);
+
+ newservers = realloc(list->servers, newspace);
+ if (newservers == NULL)
+ return NULL;
+ list->servers = newservers;
+ entry = &newservers[list->nservers];
+ memset(entry, 0, sizeof(*entry));
+ return entry;
+}
- dprint("\tadding %p=%A to %p (naddrs=%d space=%d)\n", a, a, lp,
- lp->naddrs, lp->space);
+/* Add an address entry to list. */
+static int
+add_addr_to_list(struct serverlist *list, int socktype, int family,
+ size_t addrlen, struct sockaddr *addr)
+{
+ struct server_entry *entry;
- if (lp->naddrs == lp->space) {
- err = grow_list (lp, 1);
- if (err) {
- Tprintf ("grow_list failed %d\n", err);
- return err;
- }
- }
- Tprintf("setting element %d\n", lp->naddrs);
- lp->addrs[lp->naddrs].ai = a;
- lp->addrs[lp->naddrs].freefn = freefn;
- lp->addrs[lp->naddrs].data = data;
- lp->naddrs++;
- Tprintf ("\tcount is now %lu: ", (unsigned long) lp->naddrs);
- print_addrlist(lp);
- Tprintf("\n");
+ entry = new_server_entry(list);
+ if (entry == NULL)
+ return ENOMEM;
+ entry->socktype = socktype;
+ entry->family = family;
+ entry->hostname = NULL;
+ entry->addrlen = addrlen;
+ memcpy(&entry->addr, addr, addrlen);
+ list->nservers++;
return 0;
}
-#define add_host_to_list krb5int_add_host_to_list
-
-static void
-call_freeaddrinfo(void *data)
+/* Add a hostname entry to list. */
+static int
+add_host_to_list(struct serverlist *list, const char *hostname, int port,
+ int socktype, int family)
{
- /* Strict interpretation of the C standard says we can't assume
- that the ABI for f(void*) and f(struct foo *) will be
- compatible. Use this stub just to be paranoid. */
- freeaddrinfo(data);
-}
+ struct server_entry *entry;
-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, result;
- 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
- result = snprintf(portbuf, sizeof(portbuf), "%d", ntohs(port));
- if (SNPRINTF_OVERFLOW(result, sizeof(portbuf)))
- /* XXX */
- return EINVAL;
- result = snprintf(secportbuf, sizeof(secportbuf), "%d", ntohs(secport));
- if (SNPRINTF_OVERFLOW(result, sizeof(secportbuf)))
- return EINVAL;
- 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:
- /* XXX Memory leaks possible here if add_addrinfo_to_list fails. */
- return err;
+ entry = new_server_entry(list);
+ if (entry == NULL)
+ return ENOMEM;
+ entry->socktype = socktype;
+ entry->family = family;
+ entry->hostname = strdup(hostname);
+ if (entry->hostname == NULL)
+ return ENOMEM;
+ entry->port = port;
+ list->nservers++;
+ return 0;
}
-/*
- * returns count of number of addresses found
- */
-
static krb5_error_code
locate_srv_conf_1(krb5_context context, const krb5_data *realm,
- const char * name, struct addrlist *addrlist,
- int socktype, int udpport, int sec_udpport, int family)
+ const char * name, struct serverlist *serverlist,
+ int socktype, int udpport, int sec_udpport)
{
const char *realm_srv_names[4];
char **hostlist, *host, *port, *cp;
if (count == 0) {
profile_free_list(hostlist);
- addrlist->naddrs = 0;
+ serverlist->nservers = 0;
return 0;
}
-#ifdef HAVE_NETINET_IN_H
- if (sec_udpport)
- count = count * 2;
-#endif
-
for (i=0; hostlist[i]; i++) {
int p1, p2;
*cp = '\0';
}
- if (socktype != 0)
- code = add_host_to_list(addrlist, host, p1, p2, socktype, family);
- else {
- code = add_host_to_list(addrlist, host, p1, p2, SOCK_DGRAM,
- family);
- if (code == 0)
- code = add_host_to_list(addrlist, host, p1, p2, SOCK_STREAM,
- family);
- }
- if (code) {
- Tprintf ("error %d (%s) returned from add_host_to_list\n", code,
- error_message (code));
- if (hostlist)
- profile_free_list (hostlist);
- return code;
- }
+ code = add_host_to_list(serverlist, host, p1, socktype, 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);
+ if (code)
+ goto cleanup;
}
- if (hostlist)
- profile_free_list(hostlist);
-
- return 0;
+cleanup:
+ profile_free_list(hostlist);
+ return code;
}
#ifdef TEST
static krb5_error_code
krb5_locate_srv_conf(krb5_context context, const krb5_data *realm,
- const char *name, struct addrlist *al, int udpport,
+ const char *name, struct serverlist *al, int udpport,
int sec_udpport)
{
krb5_error_code ret;
- ret = locate_srv_conf_1(context, realm, name, al, 0, udpport,
- sec_udpport, 0);
+ ret = locate_srv_conf_1(context, realm, name, al, 0, udpport, sec_udpport);
if (ret)
return ret;
- if (al->naddrs == 0) /* Couldn't resolve any KDC names */
+ if (al->nservers == 0) /* Couldn't resolve any KDC names */
return KRB5_REALM_CANT_RESOLVE;
return 0;
}
#ifdef KRB5_DNS_LOOKUP
static krb5_error_code
-locate_srv_dns_1 (const krb5_data *realm,
- const char *service,
- const char *protocol,
- struct addrlist *addrlist,
- int family)
+locate_srv_dns_1(const krb5_data *realm, const char *service,
+ const char *protocol, struct serverlist *serverlist)
{
- struct srv_dns_entry *head = NULL;
- struct srv_dns_entry *entry = NULL, *next;
+ struct srv_dns_entry *head = NULL, *entry = NULL;
krb5_error_code code = 0;
+ int socktype;
code = krb5int_make_srv_query_realm(realm, service, protocol, &head);
if (code)
return 0;
- /*
- * Okay! Now we've got a linked list of entries sorted by
- * priority. Start looking up A records and returning
- * addresses.
- */
-
if (head == NULL)
return 0;
/* Check for the "." case indicating no support. */
- if (head->next == 0 && head->host[0] == 0) {
- free(head->host);
- free(head);
- return KRB5_ERR_NO_SERVICE;
+ if (head->next == NULL && head->host[0] == '\0') {
+ code = KRB5_ERR_NO_SERVICE;
+ goto cleanup;
}
- Tprintf ("walking answer list:\n");
- for (entry = head; entry != NULL; entry = next) {
- Tprintf ("\tport=%d host=%s\n", entry->port, entry->host);
- next = entry->next;
- code = add_host_to_list (addrlist, entry->host, htons (entry->port), 0,
- (strcmp("_tcp", protocol)
- ? SOCK_DGRAM
- : SOCK_STREAM), family);
- if (code) {
- break;
- }
- if (entry == head) {
- free(entry->host);
- free(entry);
- head = next;
- entry = 0;
- }
+ for (entry = head; entry != NULL; entry = entry->next) {
+ socktype = (strcmp(protocol, "_tcp") == 0) ? SOCK_STREAM : SOCK_DGRAM;
+ code = add_host_to_list(serverlist, entry->host, htons(entry->port),
+ socktype, AF_UNSPEC);
+ if (code)
+ goto cleanup;
}
- Tprintf ("[end]\n");
+cleanup:
krb5int_free_srv_dns_data(head);
return code;
}
struct module_callback_data {
int out_of_mem;
- struct addrlist *lp;
+ struct serverlist *list;
};
static int
-module_callback (void *cbdata, int socktype, struct sockaddr *sa)
+module_callback(void *cbdata, int socktype, struct sockaddr *sa)
{
struct module_callback_data *d = cbdata;
- struct {
- struct addrinfo ai;
- union {
- struct sockaddr_in sin;
-#ifdef KRB5_USE_INET6
- struct sockaddr_in6 sin6;
-#endif
- } u;
- } *x;
+ size_t addrlen;
if (socktype != SOCK_STREAM && socktype != SOCK_DGRAM)
return 0;
- if (sa->sa_family != AF_INET
+ if (sa->sa_family == AF_INET)
+ addrlen = sizeof(struct sockaddr_in);
#ifdef KRB5_USE_INET6
- && sa->sa_family != AF_INET6
+ else if (sa->sa_family == AF_INET6)
+ addrlen = sizeof(struct sockaddr_in6);
#endif
- )
+ else
return 0;
- x = calloc (1, sizeof (*x));
- if (x == 0) {
- d->out_of_mem = 1;
- return 1;
- }
- x->ai.ai_addr = (struct sockaddr *) &x->u;
- x->ai.ai_socktype = socktype;
- x->ai.ai_family = sa->sa_family;
- if (sa->sa_family == AF_INET) {
- x->u.sin = *(struct sockaddr_in *)sa;
- x->ai.ai_addrlen = sizeof(struct sockaddr_in);
- }
-#ifdef KRB5_USE_INET6
- if (sa->sa_family == AF_INET6) {
- x->u.sin6 = *(struct sockaddr_in6 *)sa;
- x->ai.ai_addrlen = sizeof(struct sockaddr_in6);
- }
-#endif
- if (add_addrinfo_to_list (d->lp, &x->ai, free, x) != 0) {
+ if (add_addr_to_list(d->list, socktype, sa->sa_family, addrlen,
+ sa) != 0) {
/* Assumes only error is ENOMEM. */
d->out_of_mem = 1;
return 1;
}
static krb5_error_code
-module_locate_server (krb5_context ctx, const krb5_data *realm,
- struct addrlist *addrlist,
- enum locate_service_type svc, int socktype, int family)
+module_locate_server(krb5_context ctx, const krb5_data *realm,
+ struct serverlist *serverlist,
+ enum locate_service_type svc, int socktype)
{
struct krb5plugin_service_locate_result *res = NULL;
krb5_error_code code;
const char *msg;
Tprintf("in module_locate_server\n");
- cbdata.lp = addrlist;
+ cbdata.list = serverlist;
if (!PLUGIN_DIR_OPEN (&ctx->libkrb5_plugins)) {
code = krb5int_open_plugin_dirs (objdirs, NULL, &ctx->libkrb5_plugins,
if (code)
continue;
- code = vtbl->lookup(blob, svc, realmz, socktype, family,
+ code = vtbl->lookup(blob, svc, realmz,
+ (socktype != 0) ? socktype : SOCK_DGRAM, AF_UNSPEC,
module_callback, &cbdata);
+ /* Also ask for TCP addresses if we got UDP addresses and want both. */
+ if (code == 0 && socktype == 0) {
+ code = vtbl->lookup(blob, svc, realmz, SOCK_STREAM, AF_UNSPEC,
+ module_callback, &cbdata);
+ if (code == KRB5_PLUGIN_NO_HANDLE)
+ code = 0;
+ }
vtbl->fini(blob);
if (code == KRB5_PLUGIN_NO_HANDLE) {
/* Module passes, keep going. */
/* Got something back, yippee. */
Tprintf("now have %lu addrs in list %p\n",
- (unsigned long) addrlist->naddrs, addrlist);
- print_addrlist(addrlist);
+ (unsigned long) serverlist->nservers, serverlist);
free(realmz);
krb5int_free_plugin_dir_data (ptrs);
return 0;
}
static krb5_error_code
-prof_locate_server (krb5_context context, const krb5_data *realm,
- struct addrlist *addrlist,
- enum locate_service_type svc, int socktype, int family)
+prof_locate_server(krb5_context context, const krb5_data *realm,
+ struct serverlist *serverlist, enum locate_service_type svc,
+ int socktype)
{
const char *profname;
int dflport1, dflport2 = 0;
return EBUSY; /* XXX */
}
- return locate_srv_conf_1(context, realm, profname, addrlist, socktype,
- dflport1, dflport2, family);
+ return locate_srv_conf_1(context, realm, profname, serverlist, socktype,
+ dflport1, dflport2);
}
static krb5_error_code
-dns_locate_server (krb5_context context, const krb5_data *realm,
- struct addrlist *addrlist,
- enum locate_service_type svc, int socktype, int family)
+dns_locate_server(krb5_context context, const krb5_data *realm,
+ struct serverlist *serverlist, enum locate_service_type svc,
+ int socktype)
{
const char *dnsname;
int use_dns = _krb5_use_dns_kdc(context);
code = 0;
if (socktype == SOCK_DGRAM || socktype == 0) {
- code = locate_srv_dns_1(realm, dnsname, "_udp", addrlist, family);
+ 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) {
- code = locate_srv_dns_1(realm, dnsname, "_tcp", addrlist, family);
+ code = locate_srv_dns_1(realm, dnsname, "_tcp", serverlist);
if (code)
Tprintf("dns tcp lookup returned error %d\n", code);
}
*/
krb5_error_code
-krb5int_locate_server (krb5_context context, const krb5_data *realm,
- struct addrlist *addrlist,
- enum locate_service_type svc,
- int socktype, int family)
+k5_locate_server(krb5_context context, const krb5_data *realm,
+ struct serverlist *serverlist, enum locate_service_type svc,
+ int socktype)
{
krb5_error_code code;
- struct addrlist al = ADDRLIST_INIT;
+ struct serverlist al = SERVERLIST_INIT;
- *addrlist = al;
+ *serverlist = al;
if (realm == NULL || realm->data == NULL || realm->data[0] == 0) {
krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE,
return KRB5_REALM_CANT_RESOLVE;
}
- code = module_locate_server(context, realm, &al, svc, socktype, family);
+ code = module_locate_server(context, realm, &al, svc, socktype);
Tprintf("module_locate_server returns %d\n", code);
if (code == KRB5_PLUGIN_NO_HANDLE) {
/*
* config file.
*/
- code = prof_locate_server(context, realm, &al, svc, socktype, family);
+ code = prof_locate_server(context, realm, &al, svc, socktype);
#ifdef KRB5_DNS_LOOKUP
if (code) { /* Try DNS for all profile errors? */
krb5_error_code code2;
- code2 = dns_locate_server(context, realm, &al, svc, socktype,
- family);
+ code2 = dns_locate_server(context, realm, &al, svc, socktype);
if (code2 != KRB5_PLUGIN_NO_HANDLE)
code = code2;
}
}
if (code == 0)
Tprintf ("krb5int_locate_server found %d addresses\n",
- al.naddrs);
+ al.nservers);
else
Tprintf ("krb5int_locate_server returning error code %d/%s\n",
code, error_message(code));
if (code != 0) {
- if (al.space)
- free_list (&al);
+ k5_free_serverlist(&al);
return code;
}
- if (al.naddrs == 0) { /* No good servers */
- if (al.space)
- free_list (&al);
+ if (al.nservers == 0) { /* No good servers */
+ k5_free_serverlist(&al);
krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE,
- "Cannot resolve network address for KDC in realm \"%.*s\"",
- realm->length, realm->data);
-
+ "Cannot resolve servers for KDC in "
+ "realm \"%.*s\"", realm->length, realm->data);
return KRB5_REALM_CANT_RESOLVE;
}
- *addrlist = al;
+ *serverlist = al;
return 0;
}
krb5_error_code
-krb5_locate_kdc(krb5_context context, const krb5_data *realm,
- struct addrlist *addrlist,
- int get_masters, int socktype, int family)
+k5_locate_kdc(krb5_context context, const krb5_data *realm,
+ struct serverlist *serverlist, int get_masters, int socktype)
{
- return krb5int_locate_server(context, realm, addrlist,
- (get_masters
- ? locate_service_master_kdc
- : locate_service_kdc),
- socktype, family);
+ enum locate_service_type stype;
+
+ stype = get_masters ? locate_service_master_kdc : locate_service_kdc;
+ return k5_locate_server(context, realm, serverlist, stype, socktype);
}
#ifndef KRB5_LIBOS_INT_PROTO__
#define KRB5_LIBOS_INT_PROTO__
-struct addrlist;
-krb5_error_code krb5_locate_kdc(krb5_context, const krb5_data *,
- struct addrlist *, int, int, int);
+#include <krb5/locate_plugin.h>
+
+/* 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 */
+ int family; /* May be 0 (aka AF_UNSPEC) if hostname set */
+ size_t addrlen;
+ struct sockaddr_storage addr;
+};
+
+/* A list of server hostnames/addresses. */
+struct serverlist {
+ struct server_entry *servers;
+ size_t nservers;
+};
+#define SERVERLIST_INIT { NULL, 0 }
+
+krb5_error_code k5_locate_server(krb5_context, const krb5_data *realm,
+ struct serverlist *,
+ enum locate_service_type svc, int socktype);
+
+krb5_error_code k5_locate_kdc(krb5_context context, const krb5_data *realm,
+ struct serverlist *serverlist, int get_masters,
+ int socktype);
+
+void k5_free_serverlist(struct serverlist *);
#ifdef HAVE_NETINET_IN_H
krb5_error_code krb5_unpack_full_ipaddr(krb5_context,
int _krb5_use_dns_kdc (krb5_context);
int _krb5_conf_boolean (const char *);
-krb5_error_code krb5int_sendto(krb5_context context, const krb5_data *message,
- const struct addrlist *addrs,
- struct sendto_callback_info* callback_info,
- krb5_data *reply, struct sockaddr *localaddr,
- socklen_t *localaddrlen,
- struct sockaddr *remoteaddr, socklen_t *remoteaddrlen,
- int *addr_used,
- int (*msg_handler)(krb5_context, const krb5_data *, void *),
- void *msg_handler_data);
+krb5_error_code k5_sendto(krb5_context context, const krb5_data *message,
+ const struct serverlist *addrs,
+ int socktype1, int socktype2,
+ struct sendto_callback_info *callback_info,
+ krb5_data *reply, struct sockaddr *remoteaddr,
+ socklen_t *remoteaddrlen, int *server_used,
+ int (*msg_handler)(krb5_context, const krb5_data *,
+ void *),
+ void *msg_handler_data);
krb5_error_code krb5int_get_fq_local_hostname(char *, size_t);
#endif
}
-#define print_addrlist krb5int_print_addrlist
-static void
-print_addrlist (const struct addrlist *a)
-{
- size_t i;
- dprint("%d{", a->naddrs);
- for (i = 0; i < a->naddrs; i++)
- dprint("%s%p=%A", i ? "," : "", (void*)a->addrs[i].ai, a->addrs[i].ai);
- dprint("}");
-}
-
static int
-merge_addrlists (struct addrlist *dest, struct addrlist *src)
+in_addrlist(struct server_entry *entry, struct serverlist *list)
{
- /* Wouldn't it be nice if we could filter out duplicates? The
- alloc/free handling makes that pretty difficult though. */
- int err;
size_t i;
+ struct server_entry *le;
- dprint("merging addrlists:\n\tlist1: ");
- for (i = 0; i < dest->naddrs; i++)
- dprint(" %A", dest->addrs[i].ai);
- dprint("\n\tlist2: ");
- for (i = 0; i < src->naddrs; i++)
- dprint(" %A", src->addrs[i].ai);
- dprint("\n");
-
- err = krb5int_grow_addrlist (dest, src->naddrs);
- if (err)
- return err;
- for (i = 0; i < src->naddrs; i++) {
- dest->addrs[dest->naddrs + i] = src->addrs[i];
- src->addrs[i].ai = 0;
- src->addrs[i].freefn = 0;
- }
- dest->naddrs += i;
- src->naddrs = 0;
-
- dprint("\tout: ");
- for (i = 0; i < dest->naddrs; i++)
- dprint(" %A", dest->addrs[i].ai);
- dprint("\n");
-
- return 0;
-}
-
-static int
-in_addrlist (struct addrinfo *thisaddr, struct addrlist *list)
-{
- size_t i;
- for (i = 0; i < list->naddrs; i++) {
- if (thisaddr->ai_addrlen == list->addrs[i].ai->ai_addrlen
- && !memcmp(thisaddr->ai_addr, list->addrs[i].ai->ai_addr,
- thisaddr->ai_addrlen))
+ for (i = 0; i < list->nservers; i++) {
+ le = &list->servers[i];
+ if (entry->hostname != NULL && le->hostname != NULL &&
+ strcmp(entry->hostname, le->hostname) == 0)
+ return 1;
+ if (entry->hostname == NULL && le->hostname == NULL &&
+ entry->addrlen == le->addrlen &&
+ memcmp(&entry->addr, &le->addr, entry->addrlen) == 0)
return 1;
}
return 0;
*/
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)
+krb5_sendto_kdc(krb5_context context, const krb5_data *message,
+ const krb5_data *realm, krb5_data *reply, int *use_master,
+ int tcp_only)
{
- krb5_error_code retval, retval2;
- struct addrlist addrs;
- int socktype1 = 0, socktype2 = 0, addr_used;
+ krb5_error_code retval, err;
+ struct serverlist servers;
+ int socktype1 = 0, socktype2 = 0, server_used;
/*
* find KDC location(s) for realm
context->udp_pref_limit = tmp;
}
- retval = (*use_master ? KRB5_KDC_UNREACH : KRB5_REALM_UNKNOWN);
-
if (tcp_only)
socktype1 = SOCK_STREAM, socktype2 = 0;
else if (message->length <= (unsigned int) context->udp_pref_limit)
else
socktype1 = SOCK_STREAM, socktype2 = SOCK_DGRAM;
- retval = krb5_locate_kdc(context, realm, &addrs, *use_master, socktype1, 0);
- if (socktype2) {
- struct addrlist addrs2;
-
- retval2 = krb5_locate_kdc(context, realm, &addrs2, *use_master,
- socktype2, 0);
-#if 0
- if (retval2 == 0) {
- (void) merge_addrlists(&addrs, &addrs2);
- krb5int_free_addrlist(&addrs2);
- retval = 0;
- } else if (retval == KRB5_REALM_CANT_RESOLVE) {
- retval = retval2;
+ retval = k5_locate_kdc(context, realm, &servers, *use_master,
+ tcp_only ? SOCK_STREAM : 0);
+ if (retval)
+ return retval;
+
+ retval = k5_sendto(context, message, &servers, socktype1, socktype2,
+ 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;
+ } else {
+ krb5_set_error_message(context, retval,
+ "Cannot contact any KDC for realm '%.*s'",
+ realm->length, realm->data);
}
-#else
- retval = retval2;
+ }
+ if (retval)
+ goto cleanup;
+
+ /* Set use_master to 1 if we ended up talking to a master when we didn't
+ * explicitly request to. */
+ if (*use_master == 0) {
+ struct serverlist mservers;
+ struct server_entry *entry = &servers.servers[server_used];
+ retval = k5_locate_kdc(context, realm, &mservers, TRUE,
+ entry->socktype);
if (retval == 0) {
- (void) merge_addrlists(&addrs, &addrs2);
- krb5int_free_addrlist(&addrs2);
+ if (in_addrlist(entry, &mservers))
+ *use_master = 1;
+ k5_free_serverlist(&mservers);
}
-#endif
+ TRACE_SENDTO_KDC_MASTER(context, *use_master);
+ retval = 0;
}
- if (addrs.naddrs > 0) {
- krb5_error_code err = 0;
-
- retval = krb5int_sendto (context, message, &addrs, 0, reply, 0, 0,
- 0, 0, &addr_used, check_for_svc_unavailable, &err);
- switch (retval) {
- case 0:
- /*
- * Set use_master to 1 if we ended up talking to a master when
- * we didn't explicitly request to
- */
- if (*use_master == 0) {
- struct addrlist addrs3;
- retval = krb5_locate_kdc(context, realm, &addrs3, 1,
- addrs.addrs[addr_used].ai->ai_socktype,
- addrs.addrs[addr_used].ai->ai_family);
- if (retval == 0) {
- if (in_addrlist(addrs.addrs[addr_used].ai, &addrs3))
- *use_master = 1;
- krb5int_free_addrlist (&addrs3);
- }
- TRACE_SENDTO_KDC_MASTER(context, *use_master);
- }
- krb5int_free_addrlist (&addrs);
- return 0;
- default:
- break;
- /* Cases here are for constructing useful error messages. */
- case KRB5_KDC_UNREACH:
- if (err == KDC_ERR_SVC_UNAVAILABLE) {
- retval = KRB5KDC_ERR_SVC_UNAVAILABLE;
- } else {
- krb5_set_error_message(context, retval,
- "Cannot contact any KDC for realm '%.*s'",
- realm->length, realm->data);
- }
- break;
- }
- krb5int_free_addrlist (&addrs);
- }
+cleanup:
+ k5_free_serverlist(&servers);
return retval;
}
}
}
-
-
-static void
-setup_connection (struct conn_state *state, struct addrinfo *ai,
- const krb5_data *message, char **udpbufp)
+static krb5_error_code
+add_connection(struct conn_state **conns, struct addrinfo *ai,
+ size_t server_index, const krb5_data *message, char **udpbufp)
{
+ struct conn_state *state, **tailptr;
+
+ state = calloc(1, sizeof(*state));
+ if (state == NULL)
+ return ENOMEM;
state->state = INITIALIZING;
state->err = 0;
state->x.out.sgp = state->x.out.sgbuf;
- state->addr = ai;
+ state->socktype = ai->ai_socktype;
+ state->family = ai->ai_family;
+ state->addrlen = ai->ai_addrlen;
+ memcpy(&state->addr, ai->ai_addr, ai->ai_addrlen);
state->fd = INVALID_SOCKET;
+ state->server_index = server_index;
SG_SET(&state->x.out.sgbuf[1], 0, 0);
if (ai->ai_socktype == SOCK_STREAM) {
/*
state->service = service_udp_fd;
set_conn_state_msg_length (state, message);
- if (*udpbufp == 0) {
+ if (*udpbufp == NULL) {
*udpbufp = malloc(krb5_max_dgram_size);
- if (*udpbufp == 0) {
- dperror("malloc(krb5_max_dgram_size)");
- state->state = FAILED;
- return;
- }
+ if (*udpbufp == 0)
+ return ENOMEM;
}
state->x.in.buf = *udpbufp;
state->x.in.bufsize = krb5_max_dgram_size;
}
+
+ /* Chain the new state onto the tail of the list. */
+ for (tailptr = conns; *tailptr != NULL; tailptr = &(*tailptr)->next);
+ *tailptr = state;
+
+ return 0;
+}
+
+static int
+translate_ai_error (int err)
+{
+ switch (err) {
+ case 0:
+ return 0;
+ case EAI_BADFLAGS:
+ case EAI_FAMILY:
+ case EAI_SOCKTYPE:
+ case EAI_SERVICE:
+ /* All of these indicate bad inputs to getaddrinfo. */
+ return EINVAL;
+ case EAI_AGAIN:
+ /* Translate to standard errno code. */
+ return EAGAIN;
+ case EAI_MEMORY:
+ /* Translate to standard errno code. */
+ return ENOMEM;
+#ifdef EAI_ADDRFAMILY
+ case EAI_ADDRFAMILY:
+#endif
+#if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME
+ case EAI_NODATA:
+#endif
+ case EAI_NONAME:
+ /* Name not known or no address data, but no error. Do
+ nothing more. */
+ return 0;
+#ifdef EAI_OVERFLOW
+ case EAI_OVERFLOW:
+ /* An argument buffer overflowed. */
+ return EINVAL; /* XXX */
+#endif
+#ifdef EAI_SYSTEM
+ case EAI_SYSTEM:
+ /* System error, obviously. */
+ return errno;
+#endif
+ default:
+ /* An error code we haven't handled? */
+ return EINVAL;
+ }
+}
+
+/*
+ * 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);
+ }
+ }
+ return retval;
}
static int
start_connection(krb5_context context, struct conn_state *state,
struct select_state *selstate,
- struct sendto_callback_info *callback_info,
- krb5_data *callback_buffer)
+ struct sendto_callback_info *callback_info)
{
int fd, e;
- struct addrinfo *ai = state->addr;
dprint("start_connection(@%p)\ngetting %s socket in family %d...", state,
- ai->ai_socktype == SOCK_STREAM ? "stream" : "dgram", ai->ai_family);
- fd = socket(ai->ai_family, ai->ai_socktype, 0);
+ state->socktype == SOCK_STREAM ? "stream" : "dgram", state->family);
+ fd = socket(state->family, state->socktype, 0);
if (fd == INVALID_SOCKET) {
state->err = SOCKET_ERRNO;
- dprint("socket: %m creating with af %d\n", state->err, ai->ai_family);
+ dprint("socket: %m creating with af %d\n", state->err, state->family);
return -1; /* try other hosts */
}
#ifndef _WIN32 /* On Windows FD_SETSIZE is a count, not a max value. */
#endif
set_cloexec_fd(fd);
/* Make it non-blocking. */
- if (ai->ai_socktype == SOCK_STREAM) {
+ if (state->socktype == SOCK_STREAM) {
static const int one = 1;
static const struct linger lopt = { 0, 0 };
dperror("sendto_kdc: ioctl(FIONBIO)");
if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &lopt, sizeof(lopt)))
dperror("sendto_kdc: setsockopt(SO_LINGER)");
- TRACE_SENDTO_KDC_TCP_CONNECT(context, ai);
+ TRACE_SENDTO_KDC_TCP_CONNECT(context, state);
}
/* Start connecting to KDC. */
- dprint(" fd %d; connecting to %A...\n", fd, ai);
- e = connect(fd, ai->ai_addr, ai->ai_addrlen);
+ e = connect(fd, (struct sockaddr *)&state->addr, state->addrlen);
if (e != 0) {
/*
* This is the path that should be followed for non-blocking
*/
if (callback_info) {
- e = callback_info->pfn_callback(state,
- callback_info->context,
- callback_buffer);
+ e = callback_info->pfn_callback(state, callback_info->context,
+ &state->callback_buffer);
if (e != 0) {
dprint("callback failed: %m\n", e);
(void) closesocket(fd);
return -3;
}
- dprint("callback %p (message=%d@%p)\n",
- state,
- callback_buffer->length,
- callback_buffer->data);
-
- set_conn_state_msg_length( state, callback_buffer );
+ set_conn_state_msg_length(state, &state->callback_buffer);
}
- if (ai->ai_socktype == SOCK_DGRAM) {
+ if (state->socktype == SOCK_DGRAM) {
/* Send it now. */
ssize_t ret;
sg_buf *sg = &state->x.out.sgbuf[0];
- TRACE_SENDTO_KDC_UDP_SEND_INITIAL(context, ai);
+ TRACE_SENDTO_KDC_UDP_SEND_INITIAL(context, state);
dprint("sending %d bytes on fd %d\n", SG_LEN(sg), state->fd);
ret = send(state->fd, SG_BUF(sg), SG_LEN(sg), 0);
if (ret < 0 || (size_t) ret != SG_LEN(sg)) {
- TRACE_SENDTO_KDC_UDP_ERROR_SEND_INITIAL(context, ai, SOCKET_ERRNO);
+ TRACE_SENDTO_KDC_UDP_ERROR_SEND_INITIAL(context, state,
+ SOCKET_ERRNO);
dperror("sendto");
(void) closesocket(state->fd);
state->fd = INVALID_SOCKET;
state->state = READING;
}
}
-#ifdef DEBUG
- if (debug) {
- struct sockaddr_storage ss;
- socklen_t sslen = sizeof(ss);
- if (getsockname(state->fd, (struct sockaddr *)&ss, &sslen) == 0) {
- struct addrinfo hack_ai;
- memset(&hack_ai, 0, sizeof(hack_ai));
- hack_ai.ai_addr = (struct sockaddr *) &ss;
- hack_ai.ai_addrlen = sslen;
- hack_ai.ai_socktype = SOCK_DGRAM;
- hack_ai.ai_family = ai->ai_family;
- dprint("local socket address is %A\n", &hack_ai);
- }
- }
-#endif
FD_SET(state->fd, &selstate->rfds);
if (state->state == CONNECTING || state->state == WRITING)
FD_SET(state->fd, &selstate->wfds);
static int
maybe_send(krb5_context context, struct conn_state *conn,
struct select_state *selstate,
- struct sendto_callback_info *callback_info,
- krb5_data *callback_buffer)
+ struct sendto_callback_info *callback_info)
{
sg_buf *sg;
ssize_t ret;
dprint("maybe_send(@%p) state=%s type=%s\n", conn,
state_strings[conn->state],
conn->is_udp ? "udp" : "tcp");
- if (conn->state == INITIALIZING) {
- return start_connection(context, conn, selstate, callback_info,
- callback_buffer);
- }
+ if (conn->state == INITIALIZING)
+ return start_connection(context, conn, selstate, callback_info);
/* Did we already shut down this channel? */
if (conn->state == FAILED) {
return -1;
}
- if (conn->addr->ai_socktype == SOCK_STREAM) {
+ if (conn->socktype == SOCK_STREAM) {
dprint("skipping stream socket\n");
/* The select callback will handle flushing any data we
haven't written yet, and we only write it once. */
/* UDP - retransmit after a previous attempt timed out. */
sg = &conn->x.out.sgbuf[0];
- TRACE_SENDTO_KDC_UDP_SEND_RETRY(context, conn->addr);
+ TRACE_SENDTO_KDC_UDP_SEND_RETRY(context, conn);
dprint("sending %d bytes on fd %d\n", SG_LEN(sg), conn->fd);
ret = send(conn->fd, SG_BUF(sg), SG_LEN(sg), 0);
if (ret < 0 || (size_t) ret != SG_LEN(sg)) {
- TRACE_SENDTO_KDC_UDP_ERROR_SEND_INITIAL(context, conn->addr,
- SOCKET_ERRNO);
+ TRACE_SENDTO_KDC_UDP_ERROR_SEND_RETRY(context, conn, SOCKET_ERRNO);
dperror("send");
/* Keep connection alive, we'll try again next pass.
/* Bad -- the KDC shouldn't be sending to us first. */
e = EINVAL /* ?? */;
kill_conn:
- TRACE_SENDTO_KDC_TCP_DISCONNECT(context, conn->addr);
+ TRACE_SENDTO_KDC_TCP_DISCONNECT(context, conn);
kill_conn(conn, selstate, e);
if (e == EINVAL) {
closesocket(conn->fd);
*/
e = get_so_error(conn->fd);
if (e) {
- TRACE_SENDTO_KDC_TCP_ERROR_CONNECT(context, conn->addr, e);
+ TRACE_SENDTO_KDC_TCP_ERROR_CONNECT(context, conn, e);
dprint("socket error on write fd: %m", e);
goto kill_conn;
}
((conn->x.out.sg_count == 2 ? SG_LEN(&conn->x.out.sgp[1]) : 0)
+ SG_LEN(&conn->x.out.sgp[0])),
conn->fd);
- TRACE_SENDTO_KDC_TCP_SEND(context, conn->addr);
+ TRACE_SENDTO_KDC_TCP_SEND(context, conn);
nwritten = SOCKET_WRITEV(conn->fd, conn->x.out.sgp,
conn->x.out.sg_count, tmp);
if (nwritten < 0) {
e = SOCKET_ERRNO;
- TRACE_SENDTO_KDC_TCP_ERROR_SEND(context, conn->addr, e);
+ TRACE_SENDTO_KDC_TCP_ERROR_SEND(context, conn, e);
dprint("failed: %m\n", e);
goto kill_conn;
}
e = nread ? SOCKET_ERRNO : ECONNRESET;
free(conn->x.in.buf);
conn->x.in.buf = 0;
- TRACE_SENDTO_KDC_TCP_ERROR_RECV(context, conn->addr, e);
+ TRACE_SENDTO_KDC_TCP_ERROR_RECV(context, conn, e);
goto kill_conn;
}
conn->x.in.n_left -= nread;
conn->x.in.bufsizebytes + conn->x.in.bufsizebytes_read,
4 - conn->x.in.bufsizebytes_read);
if (nread < 0) {
- TRACE_SENDTO_KDC_TCP_ERROR_RECV_LEN(context, conn->addr, e);
+ TRACE_SENDTO_KDC_TCP_ERROR_RECV_LEN(context, conn, e);
e = SOCKET_ERRNO;
goto kill_conn;
}
nread = recv(conn->fd, conn->x.in.buf, conn->x.in.bufsize, 0);
if (nread < 0) {
- TRACE_SENDTO_KDC_UDP_ERROR_RECV(context, conn->addr, SOCKET_ERRNO);
+ TRACE_SENDTO_KDC_UDP_ERROR_RECV(context, conn, SOCKET_ERRNO);
kill_conn(conn, selstate, SOCKET_ERRNO);
return 0;
}
return 1;
}
-static int
-service_fds (krb5_context context,
- struct select_state *selstate,
- struct conn_state *conns, size_t n_conns, int *winning_conn,
- struct select_state *seltemp,
- int (*msg_handler)(krb5_context, const krb5_data *, void *),
- void *msg_handler_data)
+static krb5_boolean
+service_fds(krb5_context context, struct select_state *selstate, int interval,
+ struct conn_state *conns, struct select_state *seltemp,
+ int (*msg_handler)(krb5_context, const krb5_data *, void *),
+ void *msg_handler_data, struct conn_state **winner_out)
{
int e, selret;
+ struct timeval now;
+ struct conn_state *state;
+
+ *winner_out = NULL;
+
+ e = getcurtime(&now);
+ if (e)
+ return 1;
+ selstate->end_time = now;
+ selstate->end_time.tv_sec += interval;
e = 0;
while (selstate->nfds > 0) {
return 0;
/* Got something on a socket, process it. */
- for (i = 0; i <= (unsigned int)selstate->max && selret > 0 && i < n_conns; i++) {
+ for (state = conns; state != NULL; state = state->next) {
int ssflags;
- if (conns[i].fd == INVALID_SOCKET)
+ if (state->fd == INVALID_SOCKET)
continue;
ssflags = 0;
- if (FD_ISSET(conns[i].fd, &seltemp->rfds))
- ssflags |= SSF_READ, selret--;
- if (FD_ISSET(conns[i].fd, &seltemp->wfds))
- ssflags |= SSF_WRITE, selret--;
- if (FD_ISSET(conns[i].fd, &seltemp->xfds))
- ssflags |= SSF_EXCEPTION, selret--;
+ if (FD_ISSET(state->fd, &seltemp->rfds))
+ ssflags |= SSF_READ;
+ if (FD_ISSET(state->fd, &seltemp->wfds))
+ ssflags |= SSF_WRITE;
+ if (FD_ISSET(state->fd, &seltemp->xfds))
+ ssflags |= SSF_EXCEPTION;
if (!ssflags)
continue;
- dprint("handling flags '%s%s%s' on fd %d (%A) in state %s\n",
- (ssflags & SSF_READ) ? "r" : "",
- (ssflags & SSF_WRITE) ? "w" : "",
- (ssflags & SSF_EXCEPTION) ? "x" : "",
- conns[i].fd, conns[i].addr,
- state_strings[(int) conns[i].state]);
-
- if (conns[i].service(context, &conns[i], selstate, ssflags)) {
+ if (state->service(context, state, selstate, ssflags)) {
int stop = 1;
if (msg_handler != NULL) {
krb5_data reply;
- reply.data = conns[i].x.in.buf;
- reply.length = conns[i].x.in.pos - conns[i].x.in.buf;
+ reply.data = state->x.in.buf;
+ reply.length = state->x.in.pos - state->x.in.buf;
stop = (msg_handler(context, &reply, msg_handler_data) != 0);
}
if (stop) {
dprint("fd service routine says we're done\n");
- *winning_conn = i;
+ *winner_out = state;
return 1;
}
}
}
}
- if (e != 0) {
- dprint("select returned %m\n", e);
- *winning_conn = -1;
+ if (e != 0)
return 1;
- }
return 0;
}
*/
krb5_error_code
-krb5int_sendto (krb5_context context, const krb5_data *message,
- const struct addrlist *addrs,
- struct sendto_callback_info* callback_info, krb5_data *reply,
- struct sockaddr *localaddr, socklen_t *localaddrlen,
- struct sockaddr *remoteaddr, socklen_t *remoteaddrlen,
- int *addr_used,
- /* return 0 -> keep going, 1 -> quit */
- int (*msg_handler)(krb5_context, const krb5_data *, void *),
- void *msg_handler_data)
+k5_sendto(krb5_context context, const krb5_data *message,
+ const struct serverlist *servers, int socktype1, int socktype2,
+ struct sendto_callback_info* callback_info, krb5_data *reply,
+ struct sockaddr *remoteaddr, socklen_t *remoteaddrlen,
+ int *server_used,
+ /* return 0 -> keep going, 1 -> quit */
+ int (*msg_handler)(krb5_context, const krb5_data *, void *),
+ void *msg_handler_data)
{
- int pass;
- int delay_this_pass = 2;
+ int pass, delay;
krb5_error_code retval;
- struct conn_state *conns = NULL;
- krb5_data *callback_data = NULL;
- size_t i, n_conns = 0, host;
- struct select_state *sel_state = NULL;
- struct timeval now;
- int winning_conn = -1, e = 0;
+ struct conn_state *conns = NULL, *state, **tailptr, *next, *winner;
+ size_t s;
+ struct select_state *sel_state = NULL, *seltemp;
char *udpbuf = NULL;
-
- if (message)
- dprint("krb5int_sendto(message=%d@%p, addrlist=", message->length, message->data);
- else
- dprint("krb5int_sendto(callback=%p, addrlist=", callback_info);
- print_addrlist(addrs);
- dprint(")\n");
+ krb5_boolean done = FALSE;
reply->data = 0;
reply->length = 0;
- conns = calloc(addrs->naddrs, sizeof(struct conn_state));
- if (conns == NULL)
- return ENOMEM;
-
- if (callback_info) {
- callback_data = calloc(addrs->naddrs, sizeof(krb5_data));
- if (callback_data == NULL) {
- retval = ENOMEM;
- goto egress;
- }
- }
-
- for (i = 0; i < addrs->naddrs; i++)
- conns[i].fd = INVALID_SOCKET;
-
/* One for use here, listing all our fds in use, and one for
- temporary use in service_fds, for the fds of interest. */
+ * temporary use in service_fds, for the fds of interest. */
sel_state = malloc(2 * sizeof(*sel_state));
if (sel_state == NULL) {
retval = ENOMEM;
- goto egress;
+ goto cleanup;
}
+ seltemp = &sel_state[1];
sel_state->max = 0;
sel_state->nfds = 0;
sel_state->end_time.tv_sec = sel_state->end_time.tv_usec = 0;
FD_ZERO(&sel_state->wfds);
FD_ZERO(&sel_state->xfds);
+ /* First pass: resolve server hosts, communicate with resulting addresses
+ * of the preferred socktype, 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);
+ if (retval)
+ goto cleanup;
+ for (state = *tailptr; state != NULL && !done; state = state->next) {
+ /* Contact each new connection whose socktype matches socktype1. */
+ if (state->socktype != socktype1)
+ continue;
+ if (maybe_send(context, state, sel_state, callback_info))
+ continue;
+ done = service_fds(context, sel_state, 1, conns, seltemp,
+ msg_handler, msg_handler_data, &winner);
+ }
+ }
+
+ /* Complete the first pass by contacting servers of the non-preferred
+ * socktype (if given), waiting 1s for an answer from each. */
+ for (state = conns; state != NULL && !done; state = state->next) {
+ if (state->socktype != socktype2)
+ continue;
+ if (maybe_send(context, state, sel_state, callback_info))
+ continue;
+ done = service_fds(context, sel_state, 1, state, seltemp, msg_handler,
+ msg_handler_data, &winner);
+ }
- /* Set up connections. */
- for (host = 0; host < addrs->naddrs; host++) {
- setup_connection(&conns[host], addrs->addrs[host].ai, message,
- &udpbuf);
+ /* Wait for two seconds at the end of the first pass. */
+ if (!done) {
+ done = service_fds(context, sel_state, 2, conns, seltemp, msg_handler,
+ msg_handler_data, &winner);
}
- n_conns = addrs->naddrs;
- for (pass = 0; pass < MAX_PASS; pass++) {
- /* Possible optimization: Make only one pass if TCP only.
- Stop making passes if all UDP ports are closed down. */
- dprint("pass %d delay=%d\n", pass, delay_this_pass);
- for (host = 0; host < n_conns; host++) {
- dprint("host %d\n", host);
-
- /* Send to the host, wait for a response, then move on. */
- if (maybe_send(context, &conns[host], sel_state, callback_info,
- (callback_info ? &callback_data[host] : NULL)))
- continue;
- retval = getcurtime(&now);
- if (retval)
- goto egress;
- sel_state->end_time = now;
- sel_state->end_time.tv_sec += 1;
- e = service_fds(context, sel_state, conns, host+1, &winning_conn,
- sel_state+1, msg_handler, msg_handler_data);
- if (e)
- break;
- if (pass > 0 && sel_state->nfds == 0)
- /*
- * After the first pass, if we close all fds, break
- * out right away. During the first pass, it's okay,
- * we're probably about to open another connection.
- */
+ /* Make remaining passes over all of the connections. */
+ delay = 4;
+ for (pass = 1; pass < MAX_PASS && !done; pass++) {
+ for (state = conns; state != NULL && !done; state = state->next) {
+ if (maybe_send(context, state, sel_state, callback_info))
+ continue;
+ done = service_fds(context, sel_state, 1, conns, seltemp,
+ msg_handler, msg_handler_data, &winner);
+ if (sel_state->nfds == 0)
break;
}
- if (e)
- break;
- retval = getcurtime(&now);
- if (retval)
- goto egress;
- /* Possible optimization: Find a way to integrate this select
- call with the last one from the above loop, if the loop
- actually calls select. */
- sel_state->end_time.tv_sec += delay_this_pass;
- e = service_fds(context, sel_state, conns, host+1, &winning_conn,
- sel_state+1, msg_handler, msg_handler_data);
- if (e)
- break;
+ /* Wait for the delay backoff at the end of this pass. */
+ if (!done) {
+ done = service_fds(context, sel_state, delay, conns, seltemp,
+ msg_handler, msg_handler_data, &winner);
+ }
if (sel_state->nfds == 0)
break;
- delay_this_pass *= 2;
+ delay *= 2;
}
- if (sel_state->nfds == 0) {
- /* No addresses? */
- retval = KRB5_KDC_UNREACH;
- goto egress;
- }
- if (e == 0 || winning_conn < 0) {
+ if (sel_state->nfds == 0 || !done || winner == NULL) {
retval = KRB5_KDC_UNREACH;
- goto egress;
+ goto cleanup;
}
/* Success! */
- TRACE_SENDTO_KDC_RESPONSE(context, conns[winning_conn].addr);
- reply->data = conns[winning_conn].x.in.buf;
- reply->length = (conns[winning_conn].x.in.pos
- - conns[winning_conn].x.in.buf);
- dprint("returning %d bytes in buffer %p\n",
- (int) reply->length, reply->data);
+ TRACE_SENDTO_KDC_RESPONSE(context, winner);
+ reply->data = winner->x.in.buf;
+ reply->length = winner->x.in.pos - winner->x.in.buf;
retval = 0;
- conns[winning_conn].x.in.buf = 0;
- if (addr_used)
- *addr_used = winning_conn;
- if (localaddr != 0 && localaddrlen != 0 && *localaddrlen > 0)
- (void) getsockname(conns[winning_conn].fd, localaddr, localaddrlen);
-
- if (remoteaddr != 0 && remoteaddrlen != 0 && *remoteaddrlen > 0)
- (void) getpeername(conns[winning_conn].fd, remoteaddr, remoteaddrlen);
-
-egress:
- for (i = 0; i < n_conns; i++) {
- if (conns[i].fd != INVALID_SOCKET)
- closesocket(conns[i].fd);
- if (conns[i].state == READING && conns[i].x.in.buf != udpbuf)
- free(conns[i].x.in.buf);
+ winner->x.in.buf = NULL;
+ if (server_used != NULL)
+ *server_used = winner->server_index;
+ if (remoteaddr != NULL && remoteaddrlen != 0 && *remoteaddrlen > 0)
+ (void)getpeername(winner->fd, remoteaddr, remoteaddrlen);
+
+cleanup:
+ for (state = conns; state != NULL; state = next) {
+ next = state->next;
+ if (state->fd != INVALID_SOCKET)
+ closesocket(state->fd);
+ if (state->state == READING && state->x.in.buf != udpbuf)
+ free(state->x.in.buf);
if (callback_info) {
callback_info->pfn_cleanup(callback_info->context,
- &callback_data[i]);
+ &state->callback_buffer);
}
+ free(state);
}
- free(callback_data);
- free(conns);
if (reply->data != udpbuf)
free(udpbuf);
free(sel_state);
const char *prog;
-struct addrlist al;
+struct serverlist sl;
static void
kfatal (krb5_error_code err)
static void
print_addrs (void)
{
- int i;
+ size_t i;
+ int err;
- int naddrs = al.naddrs;
-
- printf ("%d addresses:\n", naddrs);
- for (i = 0; i < naddrs; i++) {
- int err;
- struct addrinfo *ai = al.addrs[i].ai;
+ printf("%d servers:\n", (int)sl.nservers);
+ for (i = 0; i < sl.nservers; i++) {
+ struct server_entry *entry = &sl.servers[i];
char hostbuf[NI_MAXHOST], srvbuf[NI_MAXSERV];
- err = getnameinfo (ai->ai_addr, ai->ai_addrlen,
- hostbuf, sizeof (hostbuf),
- srvbuf, sizeof (srvbuf),
- NI_NUMERICHOST | NI_NUMERICSERV);
- if (err)
- printf ("%2d: getnameinfo returns error %d=%s\n",
- i, err, gai_strerror (err));
- else
- printf ("%2d: address %s\t%s\tport %s\n", i, hostbuf,
- stypename (ai->ai_socktype), srvbuf);
+
+ if (entry->hostname != NULL) {
+ printf("%2d: host %s\t%s\tport %d\n", (int)i, entry->hostname,
+ stypename(entry->socktype), ntohs(entry->port));
+ continue;
+ }
+ err = getnameinfo((struct sockaddr *)&entry->addr, entry->addrlen,
+ hostbuf, sizeof(hostbuf), srvbuf, sizeof(srvbuf),
+ NI_NUMERICHOST | NI_NUMERICSERV);
+ if (err) {
+ printf("%2d: getnameinfo returns error %d=%s\n", (int)i, err,
+ gai_strerror(err));
+ } else {
+ printf("%2d: address %s\t%s\tport %s\n", (int)i, hostbuf,
+ stypename(entry->socktype), srvbuf);
+ }
}
}
switch (how) {
case LOOKUP_CONF:
- err = krb5_locate_srv_conf (ctx, &realm, "kdc", &al,
- htons (88), htons (750));
+ err = krb5_locate_srv_conf(ctx, &realm, "kdc", &sl,
+ htons(88), htons(750));
break;
case LOOKUP_DNS:
- err = locate_srv_dns_1 (&realm, "_kerberos", "_udp", &al, 0);
+ err = locate_srv_dns_1(&realm, "_kerberos", "_udp", &sl);
break;
case LOOKUP_WHATEVER:
- err = krb5_locate_kdc (ctx, &realm, &al, master, 0, 0);
+ err = k5_locate_kdc(ctx, &realm, &sl, master, 0);
break;
}
if (err) kfatal (err);
- print_addrs ();
+ print_addrs();
- krb5int_free_addrlist (&al);
- krb5_free_context (ctx);
+ k5_free_serverlist(&sl);
+ krb5_free_context(ctx);
return 0;
}
static void
test_locate_kdc(krb5_context ctx, char *realm)
{
- struct addrlist addrs;
- int i;
- int get_masters=0;
+ struct serverlist servers;
+ size_t i;
+ int get_masters = FALSE;
krb5_data rlm;
krb5_error_code retval;
rlm.data = realm;
rlm.length = strlen(realm);
- retval = krb5_locate_kdc(ctx, &rlm, &addrs, get_masters, 0, 0);
+ retval = k5_locate_kdc(ctx, &rlm, &servers, get_masters, 0);
if (retval) {
com_err("krb5_locate_kdc", retval, 0);
return;
}
printf("krb_locate_kdc(%s) returned:", realm);
- for (i=0; i < addrs.naddrs; i++) {
- struct addrinfo *ai = addrs.addrs[i].ai;
- switch (ai->ai_family) {
+ for (i = 0; i < servers.nservers; i++) {
+ struct server_entry *entry = &servers.servers[i];
+ if (entry->hostname) {
+ printf(" host:%s/%d", entry->hostname, ntohs(entry->port));
+ continue;
+ }
+ switch (entry->family) {
case AF_INET:
{
- struct sockaddr_in *s_sin;
- s_sin = (struct sockaddr_in *) ai->ai_addr;
+ struct sockaddr_in *s_sin = (struct sockaddr_in *)&entry->addr;
printf(" inet:%s/%d", inet_ntoa(s_sin->sin_addr),
ntohs(s_sin->sin_port));
}
#ifdef KRB5_USE_INET6
case AF_INET6:
{
- struct sockaddr_in6 *s_sin6;
+ struct sockaddr_in6 *s_sin6 = (struct sockaddr_in6 *)&entry->addr;
int j;
- s_sin6 = (struct sockaddr_in6 *) ai->ai_addr;
printf(" inet6");
for (j = 0; j < 8; j++)
printf(":%x",
}
#endif
default:
- printf(" unknown-af-%d", ai->ai_family);
+ printf(" unknown-af-%d", entry->family);
break;
}
}
- krb5int_free_addrlist(&addrs);
+ k5_free_serverlist(&servers);
printf("\n");
}
*/
#include "k5-int.h"
+#include "cm.h"
#ifndef DISABLE_TRACING
krb5_error_code kerr;
size_t len, i;
int err;
- struct addrinfo *ai;
+ struct conn_state *cs;
const krb5_data *d;
krb5_data data;
char addrbuf[NI_MAXHOST], portbuf[NI_MAXSERV], tmpbuf[200], *str;
krb5int_buf_add(&buf, str);
free(str);
}
- } else if (strcmp(tmpbuf, "addrinfo") == 0) {
- ai = va_arg(ap, struct addrinfo *);
- if (ai->ai_socktype == SOCK_DGRAM)
- krb5int_buf_add(&buf, "dgram");
- else if (ai->ai_socktype == SOCK_STREAM)
- krb5int_buf_add(&buf, "stream");
- else
- krb5int_buf_add_fmt(&buf, "socktype%d", ai->ai_socktype);
+ } else if (strcmp(tmpbuf, "connstate") == 0) {
+ cs = va_arg(ap, struct conn_state *);
+ if (cs->socktype == SOCK_DGRAM)
+ krb5int_buf_add(&buf, "dgram");
+ else if (cs->socktype == SOCK_STREAM)
+ krb5int_buf_add(&buf, "stream");
+ else
+ krb5int_buf_add_fmt(&buf, "socktype%d", cs->socktype);
- if (getnameinfo(ai->ai_addr, ai->ai_addrlen,
+ if (getnameinfo((struct sockaddr *)&cs->addr, cs->addrlen,
addrbuf, sizeof(addrbuf), portbuf, sizeof(portbuf),
NI_NUMERICHOST|NI_NUMERICSERV) != 0) {
- if (ai->ai_addr->sa_family == AF_UNSPEC)
- krb5int_buf_add(&buf, " AF_UNSPEC");
- else
- krb5int_buf_add_fmt(&buf, " af%d", ai->ai_addr->sa_family);
- } else
- krb5int_buf_add_fmt(&buf, " %s:%s", addrbuf, portbuf);
+ if (cs->family == AF_UNSPEC)
+ krb5int_buf_add(&buf, " AF_UNSPEC");
+ else
+ krb5int_buf_add_fmt(&buf, " af%d", cs->family);
+ } else
+ krb5int_buf_add_fmt(&buf, " %s:%s", addrbuf, portbuf);
} else if (strcmp(tmpbuf, "data") == 0) {
d = va_arg(ap, krb5_data *);
if (d == NULL || (d->length != 0 && d->data == NULL))