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