1/*
2 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
3 */
4/*
5 * lib/krb5/os/sendto_kdc.c
6 *
7 * Copyright 1990,1991,2001,2002,2004,2005,2007 by the Massachusetts Institute of Technology.
8 * All Rights Reserved.
9 *
10 * Export of this software from the United States of America may
11 *   require a specific license from the United States Government.
12 *   It is the responsibility of any person or organization contemplating
13 *   export to obtain such a license before exporting.
14 *
15 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
16 * distribute this software and its documentation for any purpose and
17 * without fee is hereby granted, provided that the above copyright
18 * notice appear in all copies and that both that copyright notice and
19 * this permission notice appear in supporting documentation, and that
20 * the name of M.I.T. not be used in advertising or publicity pertaining
21 * to distribution of the software without specific, written prior
22 * permission.  Furthermore if you modify this software you must label
23 * your software as modified software and not distribute it in such a
24 * fashion that it might be confused with the original M.I.T. software.
25 * M.I.T. makes no representations about the suitability of
26 * this software for any purpose.  It is provided "as is" without express
27 * or implied warranty.
28 *
29 *
30 * Send packet to KDC for realm; wait for response, retransmitting
31 * as necessary.
32 */
33
34#include "fake-addrinfo.h"
35#include "k5-int.h"
36
37/* Solaris Kerberos */
38#include <syslog.h>
39#include <locale.h>
40
41#ifdef HAVE_SYS_TIME_H
42#include <sys/time.h>
43#else
44#include <time.h>
45#endif
46#include "os-proto.h"
47#ifdef _WIN32
48#include <sys/timeb.h>
49#endif
50
51#ifdef _AIX
52#include <sys/select.h>
53#endif
54
55#ifndef _WIN32
56/* For FIONBIO.  */
57#include <sys/ioctl.h>
58#ifdef HAVE_SYS_FILIO_H
59#include <sys/filio.h>
60#endif
61#endif
62
63#define MAX_PASS		    3
64/* Solaris Kerberos: moved to k5-int.h */
65/* #define DEFAULT_UDP_PREF_LIMIT	 1465 */
66#define HARD_UDP_LIMIT		32700 /* could probably do 64K-epsilon ? */
67
68#undef DEBUG
69
70#ifdef DEBUG
71int krb5int_debug_sendto_kdc = 0;
72#define debug krb5int_debug_sendto_kdc
73
74static void default_debug_handler (const void *data, size_t len)
75{
76#if 0
77    FILE *logfile;
78    logfile = fopen("/tmp/sendto_kdc.log", "a");
79    if (logfile == NULL)
80	return;
81    fwrite(data, 1, len, logfile);
82    fclose(logfile);
83#else
84    fwrite(data, 1, len, stderr);
85    /* stderr is unbuffered */
86#endif
87}
88
89void (*krb5int_sendtokdc_debug_handler) (const void *, size_t) = default_debug_handler;
90
91/*
92 * Solaris Kerberos: only including the debug stuff if DEBUG defined outside
93 * this file.
94 */
95static char global_err_str[NI_MAXHOST + NI_MAXSERV + 1024];
96
97/* Solaris kerberos: removed put() since it isn't needed. */
98#if 0
99static void put(const void *ptr, size_t len)
100{
101    (*krb5int_sendtokdc_debug_handler)(ptr, len);
102}
103#endif
104
105static void putstr(const char *str)
106{
107    /* Solaris kerberos: build the string which will be passed to syslog later */
108    strlcat(global_err_str, str, sizeof (global_err_str));
109}
110#else
111void (*krb5int_sendtokdc_debug_handler) (const void *, size_t) = 0;
112#endif
113
114#define dprint krb5int_debug_fprint
115 void
116krb5int_debug_fprint (const char *fmt, ...)
117{
118#ifdef DEBUG
119    va_list args;
120
121    /* Temporaries for variable arguments, etc.  */
122    krb5_error_code kerr;
123    int err;
124    fd_set *rfds, *wfds, *xfds;
125    int i;
126    int maxfd;
127    struct timeval *tv;
128    struct addrinfo *ai;
129    const krb5_data *d;
130    char addrbuf[NI_MAXHOST], portbuf[NI_MAXSERV];
131    const char *p;
132#ifndef max
133#define max(a,b) ((a) > (b) ? (a) : (b))
134#endif
135    char tmpbuf[max(NI_MAXHOST + NI_MAXSERV + 30, 200)];
136
137    /*
138     * Solaris kerberos: modified this function to create a string to pass to
139     * syslog()
140     */
141    global_err_str[0] = NULL;
142
143    va_start(args, fmt);
144
145#define putf(FMT,X)	(sprintf(tmpbuf,FMT,X),putstr(tmpbuf))
146
147    for (; *fmt; fmt++) {
148	if (*fmt != '%') {
149	    /* Possible optimization: Look for % and print all chars
150	       up to it in one call.  */
151	    putf("%c", *fmt);
152	    continue;
153	}
154	/* After this, always processing a '%' sequence.  */
155	fmt++;
156	switch (*fmt) {
157	case 0:
158	default:
159	    abort();
160	case 'E':
161	    /* %E => krb5_error_code */
162	    kerr = va_arg(args, krb5_error_code);
163	    sprintf(tmpbuf, "%lu/", (unsigned long) kerr);
164	    putstr(tmpbuf);
165	    p = error_message(kerr);
166	    putstr(p);
167	    break;
168	case 'm':
169	    /* %m => errno value (int) */
170	    /* Like syslog's %m except the errno value is passed in
171	       rather than the current value.  */
172	    err = va_arg(args, int);
173	    putf("%d/", err);
174	    p = NULL;
175#ifdef HAVE_STRERROR_R
176	    if (strerror_r(err, tmpbuf, sizeof(tmpbuf)) == 0)
177		p = tmpbuf;
178#endif
179	    if (p == NULL)
180		p = strerror(err);
181	    putstr(p);
182	    break;
183	case 'F':
184	    /* %F => fd_set *, fd_set *, fd_set *, int */
185	    rfds = va_arg(args, fd_set *);
186	    wfds = va_arg(args, fd_set *);
187	    xfds = va_arg(args, fd_set *);
188	    maxfd = va_arg(args, int);
189
190	    for (i = 0; i < maxfd; i++) {
191		int r = FD_ISSET(i, rfds);
192		int w = wfds && FD_ISSET(i, wfds);
193		int x = xfds && FD_ISSET(i, xfds);
194		if (r || w || x) {
195		    putf(" %d", i);
196		    if (r)
197			putstr("r");
198		    if (w)
199			putstr("w");
200		    if (x)
201			putstr("x");
202		}
203	    }
204	    putstr(" ");
205	    break;
206	case 's':
207	    /* %s => char * */
208	    p = va_arg(args, const char *);
209	    putstr(p);
210	    break;
211	case 't':
212	    /* %t => struct timeval * */
213	    tv = va_arg(args, struct timeval *);
214	    if (tv) {
215		sprintf(tmpbuf, "%ld.%06ld",
216			(long) tv->tv_sec, (long) tv->tv_usec);
217		putstr(tmpbuf);
218	    } else
219		putstr("never");
220	    break;
221	case 'd':
222	    /* %d => int */
223	    putf("%d", va_arg(args, int));
224	    break;
225	case 'p':
226	    /* %p => pointer */
227	    putf("%p", va_arg(args, void*));
228	    break;
229	case 'A':
230	    /* %A => addrinfo */
231	    ai = va_arg(args, struct addrinfo *);
232	    if (ai->ai_socktype == SOCK_DGRAM)
233		strcpy(tmpbuf, "dgram");
234	    else if (ai->ai_socktype == SOCK_STREAM)
235		strcpy(tmpbuf, "stream");
236	    else
237		sprintf(tmpbuf, "socktype%d", ai->ai_socktype);
238	    if (0 != getnameinfo (ai->ai_addr, ai->ai_addrlen,
239				  addrbuf, sizeof (addrbuf),
240				  portbuf, sizeof (portbuf),
241				  NI_NUMERICHOST | NI_NUMERICSERV)) {
242		if (ai->ai_addr->sa_family == AF_UNSPEC)
243		    strcpy(tmpbuf + strlen(tmpbuf), " AF_UNSPEC");
244		else
245		    sprintf(tmpbuf + strlen(tmpbuf), " af%d", ai->ai_addr->sa_family);
246	    } else
247		sprintf(tmpbuf + strlen(tmpbuf), " %s.%s", addrbuf, portbuf);
248	    putstr(tmpbuf);
249	    break;
250	case 'D':
251	    /* %D => krb5_data * */
252	    d = va_arg(args, krb5_data *);
253	    /* Solaris Kerberos */
254	    p = d->data;
255	    putstr("0x");
256	    for (i = 0; i < d->length; i++) {
257		putf("%.2x", *p++);
258	    }
259	    break;
260	}
261    }
262    va_end(args);
263
264    /* Solaris kerberos: use syslog() for debug output */
265    syslog(LOG_DEBUG, global_err_str);
266#endif
267}
268
269#define print_addrlist krb5int_print_addrlist
270static void
271print_addrlist (const struct addrlist *a)
272{
273    int i;
274    dprint("%d{", a->naddrs);
275    for (i = 0; i < a->naddrs; i++)
276	dprint("%s%p=%A", i ? "," : "", (void*)a->addrs[i].ai, a->addrs[i].ai);
277    dprint("}");
278}
279
280static int
281merge_addrlists (struct addrlist *dest, struct addrlist *src)
282{
283    /* Wouldn't it be nice if we could filter out duplicates?  The
284       alloc/free handling makes that pretty difficult though.  */
285    int err, i;
286
287/* Solaris Kerberos */
288#ifdef DEBUG
289    /*LINTED*/
290    dprint("merging addrlists:\n\tlist1: ");
291    for (i = 0; i < dest->naddrs; i++)
292	/*LINTED*/
293	dprint(" %A", dest->addrs[i].ai);
294    /*LINTED*/
295    dprint("\n\tlist2: ");
296    for (i = 0; i < src->naddrs; i++)
297	/*LINTED*/
298	dprint(" %A", src->addrs[i].ai);
299    /*LINTED*/
300    dprint("\n");
301#endif
302
303    err = krb5int_grow_addrlist (dest, src->naddrs);
304    if (err)
305	return err;
306    for (i = 0; i < src->naddrs; i++) {
307	dest->addrs[dest->naddrs + i] = src->addrs[i];
308	src->addrs[i].ai = 0;
309	src->addrs[i].freefn = 0;
310    }
311    dest->naddrs += i;
312    src->naddrs = 0;
313
314/* Solaris Kerberos */
315#ifdef DEBUG
316    /*LINTED*/
317    dprint("\tout:   ");
318    for (i = 0; i < dest->naddrs; i++)
319	/*LINTED*/
320	dprint(" %A", dest->addrs[i].ai);
321    /*LINTED*/
322    dprint("\n");
323#endif
324
325    return 0;
326}
327
328static int
329in_addrlist (struct addrinfo *thisaddr, struct addrlist *list)
330{
331    int i;
332    for (i = 0; i < list->naddrs; i++) {
333	if (thisaddr->ai_addrlen == list->addrs[i].ai->ai_addrlen
334	    && !memcmp(thisaddr->ai_addr, list->addrs[i].ai->ai_addr,
335		       thisaddr->ai_addrlen))
336	    return 1;
337    }
338    return 0;
339}
340
341static int
342check_for_svc_unavailable (krb5_context context,
343			   const krb5_data *reply,
344			   void *msg_handler_data)
345{
346    krb5_error_code *retval = (krb5_error_code *)msg_handler_data;
347
348    *retval = 0;
349
350    if (krb5_is_krb_error(reply)) {
351	krb5_error *err_reply;
352
353	if (decode_krb5_error(reply, &err_reply) == 0) {
354	    *retval = err_reply->error;
355	    krb5_free_error(context, err_reply);
356
357	    /* Returning 0 means continue to next KDC */
358	    return (*retval != KDC_ERR_SVC_UNAVAILABLE);
359	}
360    }
361
362    return 1;
363}
364
365/*
366 * send the formatted request 'message' to a KDC for realm 'realm' and
367 * return the response (if any) in 'reply'.
368 *
369 * If the message is sent and a response is received, 0 is returned,
370 * otherwise an error code is returned.
371 *
372 * The storage for 'reply' is allocated and should be freed by the caller
373 * when finished.
374 */
375
376krb5_error_code
377krb5_sendto_kdc (krb5_context context, const krb5_data *message,
378		 const krb5_data *realm, krb5_data *reply,
379		 int *use_master, int tcp_only)
380{
381	return (krb5_sendto_kdc2(context, message, realm, reply, use_master,
382				tcp_only, NULL));
383}
384
385/*
386 * Solaris Kerberos
387 * Same as krb5_sendto_kdc plus an extra arg to return the FQDN
388 * of the KDC sent the request.
389 * Caller (at top of stack) needs to free hostname_used.
390 */
391krb5_error_code
392krb5_sendto_kdc2 (krb5_context context, const krb5_data *message,
393		 const krb5_data *realm, krb5_data *reply,
394		int *use_master, int tcp_only, char **hostname_used)
395{
396    krb5_error_code retval, retval2;
397    struct addrlist addrs = ADDRLIST_INIT;	/* Solaris Kerberos */
398    int socktype1 = 0, socktype2 = 0, addr_used;
399
400    /*
401     * find KDC location(s) for realm
402     */
403
404    /*
405     * BUG: This code won't return "interesting" errors (e.g., out of mem,
406     * bad config file) from locate_kdc.  KRB5_REALM_CANT_RESOLVE can be
407     * ignored from one query of two, but if only one query is done, or
408     * both return that error, it should be returned to the caller.  Also,
409     * "interesting" errors (not KRB5_KDC_UNREACH) from sendto_{udp,tcp}
410     * should probably be returned as well.
411     */
412
413    /*LINTED*/
414    dprint("krb5_sendto_kdc(%d@%p, \"%D\", use_master=%d, tcp_only=%d)\n",
415    /*LINTED*/
416	   message->length, message->data, realm, *use_master, tcp_only);
417
418    if (!tcp_only && context->udp_pref_limit < 0) {
419	int tmp;
420	retval = profile_get_integer(context->profile,
421				     "libdefaults", "udp_preference_limit", 0,
422				     DEFAULT_UDP_PREF_LIMIT, &tmp);
423	if (retval)
424	    return retval;
425	if (tmp < 0)
426	    tmp = DEFAULT_UDP_PREF_LIMIT;
427	else if (tmp > HARD_UDP_LIMIT)
428	    /* In the unlikely case that a *really* big value is
429	       given, let 'em use as big as we think we can
430	       support.  */
431	    tmp = HARD_UDP_LIMIT;
432	context->udp_pref_limit = tmp;
433    }
434
435    retval = (*use_master ? KRB5_KDC_UNREACH : KRB5_REALM_UNKNOWN);
436
437    if (tcp_only)
438	socktype1 = SOCK_STREAM, socktype2 = 0;
439    else if (message->length <= context->udp_pref_limit)
440	socktype1 = SOCK_DGRAM, socktype2 = SOCK_STREAM;
441    else
442	socktype1 = SOCK_STREAM, socktype2 = SOCK_DGRAM;
443
444    retval = krb5_locate_kdc(context, realm, &addrs, *use_master, socktype1, 0);
445    if (socktype2) {
446	struct addrlist addrs2;
447
448	retval2 = krb5_locate_kdc(context, realm, &addrs2, *use_master,
449				  socktype2, 0);
450#if 0
451	if (retval2 == 0) {
452	    (void) merge_addrlists(&addrs, &addrs2);
453	    krb5int_free_addrlist(&addrs2);
454	    retval = 0;
455	} else if (retval == KRB5_REALM_CANT_RESOLVE) {
456	    retval = retval2;
457	}
458#else
459	retval = retval2;
460	if (retval == 0) {
461	    (void) merge_addrlists(&addrs, &addrs2);
462	    krb5int_free_addrlist(&addrs2);
463	}
464#endif
465    }
466
467    if (addrs.naddrs > 0) {
468	krb5_error_code err = 0;
469
470        retval = krb5int_sendto (context, message, &addrs, 0, reply, 0, 0,
471				 0, 0, &addr_used, check_for_svc_unavailable, &err);
472	switch (retval) {
473	case 0:
474            /*
475             * Set use_master to 1 if we ended up talking to a master when
476             * we didn't explicitly request to
477             */
478            if (*use_master == 0) {
479                struct addrlist addrs3;
480                retval = krb5_locate_kdc(context, realm, &addrs3, 1,
481                                         addrs.addrs[addr_used].ai->ai_socktype,
482                                         addrs.addrs[addr_used].ai->ai_family);
483                if (retval == 0) {
484		    if (in_addrlist(addrs.addrs[addr_used].ai, &addrs3))
485			*use_master = 1;
486                    krb5int_free_addrlist (&addrs3);
487                }
488            }
489
490	    if (hostname_used) {
491		struct sockaddr *sa;
492		char buf[NI_MAXHOST];
493		int err;
494
495		*hostname_used = NULL;
496		sa = addrs.addrs[addr_used].ai->ai_addr;
497		err = getnameinfo (sa, socklen (sa), buf, sizeof (buf), 0, 0,
498				AI_CANONNAME);
499		if (err)
500		    err = getnameinfo (sa, socklen (sa), buf,
501				    sizeof (buf), 0, 0,
502				    NI_NUMERICHOST);
503		if (!err)
504		    *hostname_used = strdup(buf);
505	            /* don't sweat strdup fail */
506	    }
507            krb5int_free_addrlist (&addrs);
508            return 0;
509	default:
510	    break;
511	    /* Cases here are for constructing useful error messages.  */
512	case KRB5_KDC_UNREACH:
513	    if (err == KDC_ERR_SVC_UNAVAILABLE) {
514		retval = KRB5KDC_ERR_SVC_UNAVAILABLE;
515	    } else {
516		krb5_set_error_message(context, retval,
517				    dgettext(TEXT_DOMAIN,
518				    "Cannot contact any KDC for realm '%.*s'"),
519				    realm->length, realm->data);
520	    }
521	    break;
522	}
523        krb5int_free_addrlist (&addrs);
524    }
525    return retval;
526}
527
528#ifdef DEBUG
529
530#ifdef _WIN32
531#define dperror(MSG) \
532	 dprint("%s: an error occurred ... "			\
533		"\tline=%d errno=%m socketerrno=%m\n",		\
534		(MSG), __LINE__, errno, SOCKET_ERRNO)
535#else
536#define dperror(MSG) dprint("%s: %m\n", MSG, errno)
537#endif
538#define dfprintf(ARGLIST) (debug ? fprintf ARGLIST : 0)
539
540#else /* ! DEBUG */
541
542#define dperror(MSG) ((void)(MSG))
543#define dfprintf(ARGLIST) ((void)0)
544
545#endif
546
547/*
548 * Notes:
549 *
550 * Getting "connection refused" on a connected UDP socket causes
551 * select to indicate write capability on UNIX, but only shows up
552 * as an exception on Windows.  (I don't think any UNIX system flags
553 * the error as an exception.)  So we check for both, or make it
554 * system-specific.
555 *
556 * Always watch for responses from *any* of the servers.  Eventually
557 * fix the UDP code to do the same.
558 *
559 * To do:
560 * - TCP NOPUSH/CORK socket options?
561 * - error codes that don't suck
562 * - getsockopt(SO_ERROR) to check connect status
563 * - handle error RESPONSE_TOO_BIG from UDP server and use TCP
564 *   connections already in progress
565 */
566
567#include "cm.h"
568
569static int getcurtime (struct timeval *tvp)
570{
571#ifdef _WIN32
572    struct _timeb tb;
573    _ftime(&tb);
574    tvp->tv_sec = tb.time;
575    tvp->tv_usec = tb.millitm * 1000;
576    /* Can _ftime fail?  */
577    return 0;
578#else
579    if (gettimeofday(tvp, 0)) {
580	dperror("gettimeofday");
581	return errno;
582    }
583    return 0;
584#endif
585}
586
587/*
588 * Call select and return results.
589 * Input: interesting file descriptors and absolute timeout
590 * Output: select return value (-1 or num fds ready) and fd_sets
591 * Return: 0 (for i/o available or timeout) or error code.
592 */
593krb5_error_code
594krb5int_cm_call_select (const struct select_state *in,
595			struct select_state *out, int *sret)
596{
597    struct timeval now, *timo;
598    krb5_error_code e;
599
600    *out = *in;
601    e = getcurtime(&now);
602    if (e)
603	return e;
604    if (out->end_time.tv_sec == 0)
605	timo = 0;
606    else {
607	timo = &out->end_time;
608	out->end_time.tv_sec -= now.tv_sec;
609	out->end_time.tv_usec -= now.tv_usec;
610	if (out->end_time.tv_usec < 0) {
611	    out->end_time.tv_usec += 1000000;
612	    out->end_time.tv_sec--;
613	}
614	if (out->end_time.tv_sec < 0) {
615	    *sret = 0;
616	    return 0;
617	}
618    }
619    /*LINTED*/
620    dprint("selecting on max=%d sockets [%F] timeout %t\n",
621	    /*LINTED*/
622	   out->max,
623	   &out->rfds, &out->wfds, &out->xfds, out->max,
624	   timo);
625    *sret = select(out->max, &out->rfds, &out->wfds, &out->xfds, timo);
626    e = SOCKET_ERRNO;
627
628/* Solaris Kerberos */
629#ifdef DEBUG
630    /*LINTED*/
631    dprint("select returns %d", *sret);
632    if (*sret < 0)
633	/*LINTED*/
634	dprint(", error = %E\n", e);
635    else if (*sret == 0)
636	/*LINTED*/
637	dprint(" (timeout)\n");
638    else
639	/*LINTED*/
640	dprint(":%F\n", &out->rfds, &out->wfds, &out->xfds, out->max);
641#endif
642
643    if (*sret < 0)
644	return e;
645    return 0;
646}
647
648static int service_tcp_fd (struct conn_state *conn,
649			   struct select_state *selstate, int ssflags);
650static int service_udp_fd (struct conn_state *conn,
651			   struct select_state *selstate, int ssflags);
652
653static void
654set_conn_state_msg_length (struct conn_state *state, const krb5_data *message)
655{
656    if (!message || message->length == 0)
657	return;
658
659    if (!state->is_udp) {
660
661	state->x.out.msg_len_buf[0] = (message->length >> 24) & 0xff;
662	state->x.out.msg_len_buf[1] = (message->length >> 16) & 0xff;
663	state->x.out.msg_len_buf[2] = (message->length >>  8) & 0xff;
664	state->x.out.msg_len_buf[3] =  message->length        & 0xff;
665
666	SG_SET(&state->x.out.sgbuf[0], state->x.out.msg_len_buf, 4);
667	SG_SET(&state->x.out.sgbuf[1], message->data, message->length);
668   	state->x.out.sg_count = 2;
669
670    } else {
671
672	SG_SET(&state->x.out.sgbuf[0], message->data, message->length);
673	SG_SET(&state->x.out.sgbuf[1], 0, 0);
674	state->x.out.sg_count = 1;
675
676    }
677}
678
679
680
681static int
682setup_connection (struct conn_state *state, struct addrinfo *ai,
683		  const krb5_data *message, char **udpbufp)
684{
685    state->state = INITIALIZING;
686    state->err = 0;
687    state->x.out.sgp = state->x.out.sgbuf;
688    state->addr = ai;
689    state->fd = INVALID_SOCKET;
690    SG_SET(&state->x.out.sgbuf[1], 0, 0);
691    if (ai->ai_socktype == SOCK_STREAM) {
692	/*
693	SG_SET(&state->x.out.sgbuf[0], message_len_buf, 4);
694	SG_SET(&state->x.out.sgbuf[1], message->data, message->length);
695	state->x.out.sg_count = 2;
696	*/
697
698	state->is_udp = 0;
699	state->service = service_tcp_fd;
700	set_conn_state_msg_length (state, message);
701    } else {
702	/*
703	SG_SET(&state->x.out.sgbuf[0], message->data, message->length);
704	SG_SET(&state->x.out.sgbuf[1], 0, 0);
705	state->x.out.sg_count = 1;
706	*/
707
708	state->is_udp = 1;
709	state->service = service_udp_fd;
710	set_conn_state_msg_length (state, message);
711
712	if (*udpbufp == 0) {
713	    *udpbufp = malloc(krb5_max_dgram_size);
714	    if (*udpbufp == 0) {
715		dperror("malloc(krb5_max_dgram_size)");
716		(void) closesocket(state->fd);
717		state->fd = INVALID_SOCKET;
718		state->state = FAILED;
719		return 1;
720	    }
721	}
722	state->x.in.buf = *udpbufp;
723	state->x.in.bufsize = krb5_max_dgram_size;
724    }
725    return 0;
726}
727
728static int
729start_connection (struct conn_state *state,
730		  struct select_state *selstate,
731		  struct sendto_callback_info* callback_info,
732                  krb5_data* callback_buffer)
733{
734    int fd, e;
735    struct addrinfo *ai = state->addr;
736
737    /*LINTED*/
738    dprint("start_connection(@%p)\ngetting %s socket in family %d...", state,
739	   /*LINTED*/
740	   ai->ai_socktype == SOCK_STREAM ? "stream" : "dgram", ai->ai_family);
741    fd = socket(ai->ai_family, ai->ai_socktype, 0);
742    if (fd == INVALID_SOCKET) {
743	state->err = SOCKET_ERRNO;
744	/*LINTED*/
745	dprint("socket: %m creating with af %d\n", state->err, ai->ai_family);
746	return -1;		/* try other hosts */
747    }
748    /* Make it non-blocking.  */
749    if (ai->ai_socktype == SOCK_STREAM) {
750	static const int one = 1;
751	static const struct linger lopt = { 0, 0 };
752
753	if (ioctlsocket(fd, FIONBIO, (const void *) &one))
754	    dperror("sendto_kdc: ioctl(FIONBIO)");
755	if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &lopt, sizeof(lopt)))
756	    dperror("sendto_kdc: setsockopt(SO_LINGER)");
757    }
758
759    /* Start connecting to KDC.  */
760    /*LINTED*/
761    dprint(" fd %d; connecting to %A...\n", fd, ai);
762    e = connect(fd, ai->ai_addr, ai->ai_addrlen);
763    if (e != 0) {
764	/*
765	 * This is the path that should be followed for non-blocking
766	 * connections.
767	 */
768	if (SOCKET_ERRNO == EINPROGRESS || SOCKET_ERRNO == EWOULDBLOCK) {
769	    state->state = CONNECTING;
770	    state->fd = fd;
771	} else {
772	    /*LINTED*/
773	    dprint("connect failed: %m\n", SOCKET_ERRNO);
774	    (void) closesocket(fd);
775	    state->err = SOCKET_ERRNO;
776	    state->state = FAILED;
777	    return -2;
778	}
779    } else {
780	/*
781	 * Connect returned zero even though we tried to make it
782	 * non-blocking, which should have caused it to return before
783	 * finishing the connection.  Oh well.  Someone's network
784	 * stack is broken, but if they gave us a connection, use it.
785	 */
786	state->state = WRITING;
787	state->fd = fd;
788    }
789    /*LINTED*/
790    dprint("new state = %s\n", state_strings[state->state]);
791
792
793    /*
794     * Here's where KPASSWD callback gets the socket information it needs for
795     * a kpasswd request
796     */
797    if (callback_info) {
798
799	e = callback_info->pfn_callback(state,
800					callback_info->context,
801					callback_buffer);
802	if (e != 0) {
803	    dprint("callback failed: %m\n", e);
804	    (void) closesocket(fd);
805	    state->err = e;
806	    state->fd = INVALID_SOCKET;
807	    state->state = FAILED;
808	    return -3;
809	}
810
811	dprint("callback %p (message=%d@%p)\n",
812	       state,
813	       callback_buffer->length,
814	       callback_buffer->data);
815
816	set_conn_state_msg_length( state, callback_buffer );
817    }
818
819    if (ai->ai_socktype == SOCK_DGRAM) {
820	/* Send it now.  */
821	int ret;
822	sg_buf *sg = &state->x.out.sgbuf[0];
823
824	/*LINTED*/
825	dprint("sending %d bytes on fd %d\n", SG_LEN(sg), state->fd);
826	ret = send(state->fd, SG_BUF(sg), SG_LEN(sg), 0);
827	if (ret != SG_LEN(sg)) {
828	    dperror("sendto");
829	    (void) closesocket(state->fd);
830	    state->fd = INVALID_SOCKET;
831	    state->state = FAILED;
832	    return -4;
833	} else {
834	    state->state = READING;
835	}
836    }
837#ifdef DEBUG
838    if (debug) {
839	struct sockaddr_storage ss;
840	socklen_t sslen = sizeof(ss);
841	if (getsockname(state->fd, (struct sockaddr *)&ss, &sslen) == 0) {
842	    struct addrinfo hack_ai;
843	    memset(&hack_ai, 0, sizeof(hack_ai));
844	    hack_ai.ai_addr = (struct sockaddr *) &ss;
845	    hack_ai.ai_addrlen = sslen;
846	    hack_ai.ai_socktype = SOCK_DGRAM;
847	    hack_ai.ai_family = ai->ai_family;
848	    dprint("local socket address is %A\n", &hack_ai);
849	}
850    }
851#endif
852    FD_SET(state->fd, &selstate->rfds);
853    if (state->state == CONNECTING || state->state == WRITING)
854	FD_SET(state->fd, &selstate->wfds);
855    FD_SET(state->fd, &selstate->xfds);
856    if (selstate->max <= state->fd)
857	selstate->max = state->fd + 1;
858    selstate->nfds++;
859
860    /*LINTED*/
861    dprint("new select vectors: %F\n",
862	   /*LINTED*/
863	   &selstate->rfds, &selstate->wfds, &selstate->xfds, selstate->max);
864
865    return 0;
866}
867
868/* Return 0 if we sent something, non-0 otherwise.
869   If 0 is returned, the caller should delay waiting for a response.
870   Otherwise, the caller should immediately move on to process the
871   next connection.  */
872static int
873maybe_send (struct conn_state *conn,
874	    struct select_state *selstate,
875	    struct sendto_callback_info* callback_info,
876	    krb5_data* callback_buffer)
877{
878    sg_buf *sg;
879
880    /*LINTED*/
881    dprint("maybe_send(@%p) state=%s type=%s\n", conn,
882	   /*LINTED*/
883	   state_strings[conn->state],
884	   conn->is_udp ? "udp" : "tcp");
885    if (conn->state == INITIALIZING)
886	return start_connection(conn, selstate, callback_info, callback_buffer);
887
888    /* Did we already shut down this channel?  */
889    if (conn->state == FAILED) {
890	dprint("connection already closed\n");
891	return -1;
892    }
893
894    if (conn->addr->ai_socktype == SOCK_STREAM) {
895	dprint("skipping stream socket\n");
896	/* The select callback will handle flushing any data we
897	   haven't written yet, and we only write it once.  */
898	return -1;
899    }
900
901    /* UDP - Send message, possibly for the first time, possibly a
902       retransmit if a previous attempt timed out.  */
903    sg = &conn->x.out.sgbuf[0];
904    /*LINTED*/
905    dprint("sending %d bytes on fd %d\n", SG_LEN(sg), conn->fd);
906    if (send(conn->fd, SG_BUF(sg), SG_LEN(sg), 0) != SG_LEN(sg)) {
907	dperror("send");
908	/* Keep connection alive, we'll try again next pass.
909
910	   Is this likely to catch any errors we didn't get from the
911	   select callbacks?  */
912	return -1;
913    }
914    /* Yay, it worked.  */
915    return 0;
916}
917
918static void
919kill_conn(struct conn_state *conn, struct select_state *selstate, int err)
920{
921    conn->state = FAILED;
922    shutdown(conn->fd, SHUTDOWN_BOTH);
923    FD_CLR(conn->fd, &selstate->rfds);
924    FD_CLR(conn->fd, &selstate->wfds);
925    FD_CLR(conn->fd, &selstate->xfds);
926    conn->err = err;
927    /*LINTED*/
928    dprint("abandoning connection %d: %m\n", conn->fd, err);
929    /* Fix up max fd for next select call.  */
930    if (selstate->max == 1 + conn->fd) {
931	while (selstate->max > 0
932	       && ! FD_ISSET(selstate->max-1, &selstate->rfds)
933	       && ! FD_ISSET(selstate->max-1, &selstate->wfds)
934	       && ! FD_ISSET(selstate->max-1, &selstate->xfds))
935	    selstate->max--;
936	/*LINTED*/
937	dprint("new max_fd + 1 is %d\n", selstate->max);
938    }
939    selstate->nfds--;
940}
941
942/* Check socket for error.  */
943static int
944get_so_error(int fd)
945{
946    int e, sockerr;
947    socklen_t sockerrlen;
948
949    sockerr = 0;
950    sockerrlen = sizeof(sockerr);
951    e = getsockopt(fd, SOL_SOCKET, SO_ERROR, &sockerr, &sockerrlen);
952    if (e != 0) {
953	/* What to do now?  */
954	e = SOCKET_ERRNO;
955	dprint("getsockopt(SO_ERROR) on fd failed: %m\n", e);
956	return e;
957    }
958    return sockerr;
959}
960
961/* Return nonzero only if we're finished and the caller should exit
962   its loop.  This happens in two cases: We have a complete message,
963   or the socket has closed and no others are open.  */
964
965static int
966service_tcp_fd (struct conn_state *conn, struct select_state *selstate,
967		int ssflags)
968{
969    krb5_error_code e = 0;
970    int nwritten, nread;
971
972    if (!(ssflags & (SSF_READ|SSF_WRITE|SSF_EXCEPTION)))
973	abort();
974    switch (conn->state) {
975	SOCKET_WRITEV_TEMP tmp;
976
977    case CONNECTING:
978	if (ssflags & SSF_READ) {
979	    /* Bad -- the KDC shouldn't be sending to us first.  */
980	    e = EINVAL /* ?? */;
981	kill_conn:
982	    kill_conn(conn, selstate, e);
983	    if (e == EINVAL) {
984		closesocket(conn->fd);
985		conn->fd = INVALID_SOCKET;
986	    }
987	    return e == 0;
988	}
989	if (ssflags & SSF_EXCEPTION) {
990	handle_exception:
991	    e = get_so_error(conn->fd);
992	    if (e)
993		dprint("socket error on exception fd: %m", e);
994	    else
995		dprint("no socket error info available on exception fd");
996	    goto kill_conn;
997	}
998
999	/*
1000	 * Connect finished -- but did it succeed or fail?
1001	 * UNIX sets can_write if failed.
1002	 * Call getsockopt to see if error pending.
1003	 *
1004	 * (For most UNIX systems it works to just try writing the
1005	 * first time and detect an error.  But Bill Dodd at IBM
1006	 * reports that some version of AIX, SIGPIPE can result.)
1007	 */
1008	e = get_so_error(conn->fd);
1009	if (e) {
1010	    dprint("socket error on write fd: %m", e);
1011	    goto kill_conn;
1012	}
1013	conn->state = WRITING;
1014	goto try_writing;
1015
1016    case WRITING:
1017	if (ssflags & SSF_READ) {
1018	    e = E2BIG;
1019	    /* Bad -- the KDC shouldn't be sending anything yet.  */
1020	    goto kill_conn;
1021	}
1022	if (ssflags & SSF_EXCEPTION)
1023	    goto handle_exception;
1024
1025    try_writing:
1026	/*LINTED*/
1027	dprint("trying to writev %d (%d bytes) to fd %d\n",
1028		/*LINTED*/
1029	       conn->x.out.sg_count,
1030	       ((conn->x.out.sg_count == 2 ? SG_LEN(&conn->x.out.sgp[1]) : 0)
1031		/*LINTED*/
1032		+ SG_LEN(&conn->x.out.sgp[0])),
1033	       conn->fd);
1034	nwritten = SOCKET_WRITEV(conn->fd, conn->x.out.sgp,
1035				 conn->x.out.sg_count, tmp);
1036	if (nwritten < 0) {
1037	    e = SOCKET_ERRNO;
1038	    /*LINTED*/
1039	    dprint("failed: %m\n", e);
1040	    goto kill_conn;
1041	}
1042	/*LINTED*/
1043	dprint("wrote %d bytes\n", nwritten);
1044	while (nwritten) {
1045	    sg_buf *sgp = conn->x.out.sgp;
1046	    if (nwritten < SG_LEN(sgp)) {
1047		/*LINTED*/
1048		SG_ADVANCE(sgp, nwritten);
1049		nwritten = 0;
1050	    } else {
1051		nwritten -= SG_LEN(conn->x.out.sgp);
1052		conn->x.out.sgp++;
1053		conn->x.out.sg_count--;
1054		if (conn->x.out.sg_count == 0 && nwritten != 0)
1055		    /* Wrote more than we wanted to?  */
1056		    abort();
1057	    }
1058	}
1059	if (conn->x.out.sg_count == 0) {
1060	    /* Done writing, switch to reading.  */
1061	    /* Don't call shutdown at this point because
1062	     * some implementations cannot deal with half-closed connections.*/
1063	    FD_CLR(conn->fd, &selstate->wfds);
1064	    /* Q: How do we detect failures to send the remaining data
1065	       to the remote side, since we're in non-blocking mode?
1066	       Will we always get errors on the reading side?  */
1067	    /*LINTED*/
1068	    dprint("switching fd %d to READING\n", conn->fd);
1069	    conn->state = READING;
1070	    conn->x.in.bufsizebytes_read = 0;
1071	    conn->x.in.bufsize = 0;
1072	    conn->x.in.buf = 0;
1073	    conn->x.in.pos = 0;
1074	    conn->x.in.n_left = 0;
1075	}
1076	return 0;
1077
1078    case READING:
1079	if (ssflags & SSF_EXCEPTION) {
1080	    if (conn->x.in.buf) {
1081		free(conn->x.in.buf);
1082		conn->x.in.buf = 0;
1083	    }
1084	    goto handle_exception;
1085	}
1086
1087	if (conn->x.in.bufsizebytes_read == 4) {
1088	    /* Reading data.  */
1089	    /*LINTED*/
1090	    dprint("reading %d bytes of data from fd %d\n",
1091		   (int) conn->x.in.n_left, conn->fd);
1092	    nread = SOCKET_READ(conn->fd, conn->x.in.pos, conn->x.in.n_left);
1093	    if (nread <= 0) {
1094		e = nread ? SOCKET_ERRNO : ECONNRESET;
1095		free(conn->x.in.buf);
1096		conn->x.in.buf = 0;
1097		goto kill_conn;
1098	    }
1099	    conn->x.in.n_left -= nread;
1100	    conn->x.in.pos += nread;
1101	    /* Solaris Kerberos */
1102	    if ((long)conn->x.in.n_left <= 0) {
1103		/* We win!  */
1104		return 1;
1105	    }
1106	} else {
1107	    /* Reading length.  */
1108	    nread = SOCKET_READ(conn->fd,
1109				conn->x.in.bufsizebytes + conn->x.in.bufsizebytes_read,
1110				4 - conn->x.in.bufsizebytes_read);
1111	    if (nread < 0) {
1112		e = SOCKET_ERRNO;
1113		goto kill_conn;
1114	    }
1115	    conn->x.in.bufsizebytes_read += nread;
1116	    if (conn->x.in.bufsizebytes_read == 4) {
1117		unsigned long len;
1118		len = conn->x.in.bufsizebytes[0];
1119		len = (len << 8) + conn->x.in.bufsizebytes[1];
1120		len = (len << 8) + conn->x.in.bufsizebytes[2];
1121		len = (len << 8) + conn->x.in.bufsizebytes[3];
1122		/*LINTED*/
1123		dprint("received length on fd %d is %d\n", conn->fd, (int)len);
1124		/* Arbitrary 1M cap.  */
1125		if (len > 1 * 1024 * 1024) {
1126		    e = E2BIG;
1127		    goto kill_conn;
1128		}
1129		conn->x.in.bufsize = conn->x.in.n_left = len;
1130		conn->x.in.buf = conn->x.in.pos = malloc(len);
1131		/*LINTED*/
1132		dprint("allocated %d byte buffer at %p\n", (int) len,
1133		       conn->x.in.buf);
1134		if (conn->x.in.buf == 0) {
1135		    /* allocation failure */
1136		    e = errno;
1137		    goto kill_conn;
1138		}
1139	    }
1140	}
1141	break;
1142
1143    default:
1144	abort();
1145    }
1146    return 0;
1147}
1148
1149static int
1150service_udp_fd(struct conn_state *conn, struct select_state *selstate,
1151	       int ssflags)
1152{
1153    int nread;
1154
1155    if (!(ssflags & (SSF_READ|SSF_EXCEPTION)))
1156	abort();
1157    if (conn->state != READING)
1158	abort();
1159
1160    nread = recv(conn->fd, conn->x.in.buf, conn->x.in.bufsize, 0);
1161    if (nread < 0) {
1162	kill_conn(conn, selstate, SOCKET_ERRNO);
1163	return 0;
1164    }
1165    conn->x.in.pos = conn->x.in.buf + nread;
1166    return 1;
1167}
1168
1169static int
1170service_fds (krb5_context context,
1171	     struct select_state *selstate,
1172	     struct conn_state *conns, size_t n_conns, int *winning_conn,
1173	     struct select_state *seltemp,
1174	     int (*msg_handler)(krb5_context, const krb5_data *, void *),
1175	     void *msg_handler_data)
1176{
1177    int e, selret;
1178
1179    e = 0;
1180    while (selstate->nfds > 0
1181	   && (e = krb5int_cm_call_select(selstate, seltemp, &selret)) == 0) {
1182	int i;
1183
1184	/*LINTED*/
1185	dprint("service_fds examining results, selret=%d\n", selret);
1186
1187	if (selret == 0)
1188	    /* Timeout, return to caller.  */
1189	    return 0;
1190
1191	/* Got something on a socket, process it.  */
1192	for (i = 0; i <= selstate->max && selret > 0 && i < n_conns; i++) {
1193	    int ssflags;
1194
1195	    if (conns[i].fd == INVALID_SOCKET)
1196		continue;
1197	    ssflags = 0;
1198	    if (FD_ISSET(conns[i].fd, &seltemp->rfds))
1199		ssflags |= SSF_READ, selret--;
1200	    if (FD_ISSET(conns[i].fd, &seltemp->wfds))
1201		ssflags |= SSF_WRITE, selret--;
1202	    if (FD_ISSET(conns[i].fd, &seltemp->xfds))
1203		ssflags |= SSF_EXCEPTION, selret--;
1204	    if (!ssflags)
1205		continue;
1206
1207	    /*LINTED*/
1208	    dprint("handling flags '%s%s%s' on fd %d (%A) in state %s\n",
1209		    /*LINTED*/
1210		   (ssflags & SSF_READ) ? "r" : "",
1211		    /*LINTED*/
1212		   (ssflags & SSF_WRITE) ? "w" : "",
1213		    /*LINTED*/
1214		   (ssflags & SSF_EXCEPTION) ? "x" : "",
1215		    /*LINTED*/
1216		   conns[i].fd, conns[i].addr,
1217		   state_strings[(int) conns[i].state]);
1218
1219	    if (conns[i].service (&conns[i], selstate, ssflags)) {
1220		int stop = 1;
1221
1222		if (msg_handler != NULL) {
1223		    krb5_data reply;
1224
1225		    reply.data = conns[i].x.in.buf;
1226		    reply.length = conns[i].x.in.pos - conns[i].x.in.buf;
1227
1228		    stop = (msg_handler(context, &reply, msg_handler_data) != 0);
1229		}
1230
1231		if (stop) {
1232		    dprint("fd service routine says we're done\n");
1233		    *winning_conn = i;
1234		    return 1;
1235		}
1236	    }
1237	}
1238    }
1239    if (e != 0) {
1240	/*LINTED*/
1241	dprint("select returned %m\n", e);
1242	*winning_conn = -1;
1243	return 1;
1244    }
1245    return 0;
1246}
1247
1248/*
1249 * Current worst-case timeout behavior:
1250 *
1251 * First pass, 1s per udp or tcp server, plus 2s at end.
1252 * Second pass, 1s per udp server, plus 4s.
1253 * Third pass, 1s per udp server, plus 8s.
1254 * Fourth => 16s, etc.
1255 *
1256 * Restated:
1257 * Per UDP server, 1s per pass.
1258 * Per TCP server, 1s.
1259 * Backoff delay, 2**(P+1) - 2, where P is total number of passes.
1260 *
1261 * Total = 2**(P+1) + U*P + T - 2.
1262 *
1263 * If P=3, Total = 3*U + T + 14.
1264 * If P=4, Total = 4*U + T + 30.
1265 *
1266 * Note that if you try to reach two ports (e.g., both 88 and 750) on
1267 * one server, it counts as two.
1268 */
1269
1270krb5_error_code
1271/*ARGSUSED*/
1272krb5int_sendto (krb5_context context, const krb5_data *message,
1273                const struct addrlist *addrs,
1274		struct sendto_callback_info* callback_info, krb5_data *reply,
1275		struct sockaddr *localaddr, socklen_t *localaddrlen,
1276                struct sockaddr *remoteaddr, socklen_t *remoteaddrlen,
1277		int *addr_used,
1278		/* return 0 -> keep going, 1 -> quit */
1279		int (*msg_handler)(krb5_context, const krb5_data *, void *),
1280		void *msg_handler_data)
1281{
1282    int i, pass;
1283    int delay_this_pass = 2;
1284    krb5_error_code retval;
1285    struct conn_state *conns;
1286    krb5_data *callback_data = 0;
1287    size_t n_conns, host;
1288    struct select_state *sel_state;
1289    struct timeval now;
1290    int winning_conn = -1, e = 0;
1291    char *udpbuf = 0;
1292
1293    if (message)
1294	dprint("krb5int_sendto(message=%d@%p, addrlist=", message->length, message->data);
1295    else
1296	dprint("krb5int_sendto(callback=%p, addrlist=", callback_info);
1297    print_addrlist(addrs);
1298    dprint(")\n");
1299
1300    reply->data = 0;
1301    reply->length = 0;
1302
1303    n_conns = addrs->naddrs;
1304    conns = malloc(n_conns * sizeof(struct conn_state));
1305    if (conns == NULL) {
1306	return ENOMEM;
1307    }
1308
1309    memset(conns, 0, n_conns * sizeof(struct conn_state));
1310
1311    if (callback_info) {
1312	callback_data = malloc(n_conns * sizeof(krb5_data));
1313	if (callback_data == NULL) {
1314	    return ENOMEM;
1315	}
1316
1317	memset(callback_data, 0, n_conns * sizeof(krb5_data));
1318    }
1319
1320    for (i = 0; i < n_conns; i++) {
1321	conns[i].fd = INVALID_SOCKET;
1322    }
1323
1324    /* One for use here, listing all our fds in use, and one for
1325       temporary use in service_fds, for the fds of interest.  */
1326    sel_state = malloc(2 * sizeof(*sel_state));
1327    if (sel_state == NULL) {
1328	free(conns);
1329	return ENOMEM;
1330    }
1331    sel_state->max = 0;
1332    sel_state->nfds = 0;
1333    sel_state->end_time.tv_sec = sel_state->end_time.tv_usec = 0;
1334    FD_ZERO(&sel_state->rfds);
1335    FD_ZERO(&sel_state->wfds);
1336    FD_ZERO(&sel_state->xfds);
1337
1338
1339    /* Set up connections.  */
1340    for (host = 0; host < n_conns; host++) {
1341	retval = setup_connection(&conns[host],
1342				  addrs->addrs[host].ai,
1343				  message,
1344				  &udpbuf);
1345	if (retval)
1346	    continue;
1347    }
1348    for (pass = 0; pass < MAX_PASS; pass++) {
1349	/* Possible optimization: Make only one pass if TCP only.
1350	   Stop making passes if all UDP ports are closed down.  */
1351	/*LINTED*/
1352	dprint("pass %d delay=%d\n", pass, delay_this_pass);
1353	for (host = 0; host < n_conns; host++) {
1354	    /*LINTED*/
1355	    dprint("host %d\n", host);
1356
1357	    /* Send to the host, wait for a response, then move on. */
1358	    if (maybe_send(&conns[host],
1359			   sel_state,
1360			   callback_info,
1361			   (callback_info ? &callback_data[host] : NULL)))
1362		continue;
1363
1364	    retval = getcurtime(&now);
1365	    if (retval)
1366		goto egress;
1367	    sel_state->end_time = now;
1368	    sel_state->end_time.tv_sec += 1;
1369	    e = service_fds(context, sel_state, conns, host+1, &winning_conn,
1370			    sel_state+1, msg_handler, msg_handler_data);
1371	    if (e)
1372		break;
1373	    if (pass > 0 && sel_state->nfds == 0)
1374		/*
1375		 * After the first pass, if we close all fds, break
1376		 * out right away.  During the first pass, it's okay,
1377		 * we're probably about to open another connection.
1378		 */
1379		break;
1380	}
1381	if (e)
1382	    break;
1383	retval = getcurtime(&now);
1384	if (retval)
1385	    goto egress;
1386	/* Possible optimization: Find a way to integrate this select
1387	   call with the last one from the above loop, if the loop
1388	   actually calls select.  */
1389	sel_state->end_time.tv_sec += delay_this_pass;
1390	e = service_fds(context, sel_state, conns, host+1, &winning_conn,
1391		        sel_state+1, msg_handler, msg_handler_data);
1392	if (e)
1393	    break;
1394	if (sel_state->nfds == 0)
1395	    break;
1396	delay_this_pass *= 2;
1397    }
1398
1399    if (sel_state->nfds == 0) {
1400	/* No addresses?  */
1401	retval = KRB5_KDC_UNREACH;
1402	goto egress;
1403    }
1404    if (e == 0 || winning_conn < 0) {
1405	retval = KRB5_KDC_UNREACH;
1406	goto egress;
1407    }
1408    /* Success!  */
1409    reply->data = conns[winning_conn].x.in.buf;
1410    reply->length = (conns[winning_conn].x.in.pos
1411		     - conns[winning_conn].x.in.buf);
1412    /*LINTED*/
1413    dprint("returning %d bytes in buffer %p\n",
1414	   (int) reply->length, reply->data);
1415    retval = 0;
1416    conns[winning_conn].x.in.buf = 0;
1417    if (addr_used)
1418        *addr_used = winning_conn;
1419    if (localaddr != 0 && localaddrlen != 0 && *localaddrlen > 0)
1420	(void) getsockname(conns[winning_conn].fd, localaddr, localaddrlen);
1421
1422     if (remoteaddr != 0 && remoteaddrlen != 0 && *remoteaddrlen > 0)
1423	(void) getpeername(conns[winning_conn].fd, remoteaddr, remoteaddrlen);
1424
1425egress:
1426    for (i = 0; i < n_conns; i++) {
1427	if (conns[i].fd != INVALID_SOCKET)
1428	    closesocket(conns[i].fd);
1429	if (conns[i].state == READING
1430	    && conns[i].x.in.buf != 0
1431	    && conns[i].x.in.buf != udpbuf)
1432	    free(conns[i].x.in.buf);
1433	if (callback_info) {
1434	    callback_info->pfn_cleanup( callback_info->context, &callback_data[i]);
1435	}
1436    }
1437
1438    if (callback_data)
1439	free(callback_data);
1440
1441    free(conns);
1442    if (reply->data != udpbuf)
1443	free(udpbuf);
1444    free(sel_state);
1445    return retval;
1446}
1447