1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/krb5/os/sendto_kdc.c */
4 * Copyright 1990,1991,2001,2002,2004,2005,2007,2008 by the Massachusetts Institute of Technology.
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
27 /* Send packet to KDC for realm; wait for response, retransmitting
30 #include "fake-addrinfo.h"
35 #include <sys/timeb.h>
38 #if defined(HAVE_POLL_H)
41 #define MAX_POLLFDS 1024
42 #elif defined(HAVE_SYS_SELECT_H)
43 #include <sys/select.h>
48 #include <sys/ioctl.h>
49 #ifdef HAVE_SYS_FILIO_H
50 #include <sys/filio.h>
55 #define DEFAULT_UDP_PREF_LIMIT 1465
56 #define HARD_UDP_LIMIT 32700 /* could probably do 64K-epsilon ? */
61 int krb5int_debug_sendto_kdc = 0;
62 #define debug krb5int_debug_sendto_kdc
65 default_debug_handler (const void *data, size_t len)
69 if (logfile == NULL) {
70 logfile = fopen("/tmp/sendto_kdc.log", "a");
73 setbuf(logfile, NULL);
75 fwrite(data, 1, len, logfile);
77 fwrite(data, 1, len, stderr);
78 /* stderr is unbuffered */
82 void (*krb5int_sendtokdc_debug_handler) (const void *, size_t) = default_debug_handler;
85 put(const void *ptr, size_t len)
87 (*krb5int_sendtokdc_debug_handler)(ptr, len);
90 putstr(const char *str)
92 put(str, strlen(str));
95 void (*krb5int_sendtokdc_debug_handler) (const void *, size_t) = 0;
98 #define dprint krb5int_debug_fprint
100 krb5int_debug_fprint (const char *fmt, ...)
105 /* Temporaries for variable arguments, etc. */
106 krb5_error_code kerr;
108 fd_set *rfds, *wfds, *xfds;
114 char addrbuf[NI_MAXHOST], portbuf[NI_MAXSERV];
117 #define max(a,b) ((a) > (b) ? (a) : (b))
119 char tmpbuf[max(NI_MAXHOST + NI_MAXSERV + 30, 200)];
122 if (!krb5int_debug_sendto_kdc)
127 #define putf(FMT,X) (snprintf(tmpbuf,sizeof(tmpbuf),FMT,X),putstr(tmpbuf))
129 for (; *fmt; fmt++) {
133 for (fmt2 = fmt+1; *fmt2; fmt2++)
138 fmt += len - 1; /* then fmt++ in loop header */
141 /* After this, always processing a '%' sequence. */
148 /* %E => krb5_error_code */
149 kerr = va_arg(args, krb5_error_code);
150 snprintf(tmpbuf, sizeof(tmpbuf), "%lu/", (unsigned long) kerr);
152 p = error_message(kerr);
156 /* %m => errno value (int) */
157 /* Like syslog's %m except the errno value is passed in
158 rather than the current value. */
159 err = va_arg(args, int);
162 #ifdef HAVE_STRERROR_R
163 if (strerror_r(err, tmpbuf, sizeof(tmpbuf)) == 0)
172 p = va_arg(args, const char *);
176 /* %t => struct timeval * */
177 tv = va_arg(args, struct timeval *);
179 snprintf(tmpbuf, sizeof(tmpbuf), "%ld.%06ld",
180 (long) tv->tv_sec, (long) tv->tv_usec);
187 putf("%d", va_arg(args, int));
191 putf("%p", va_arg(args, void*));
195 ai = va_arg(args, struct addrinfo *);
196 krb5int_buf_init_dynamic(&buf);
197 if (ai->ai_socktype == SOCK_DGRAM)
198 krb5int_buf_add(&buf, "dgram");
199 else if (ai->ai_socktype == SOCK_STREAM)
200 krb5int_buf_add(&buf, "stream");
202 krb5int_buf_add_fmt(&buf, "socktype%d", ai->ai_socktype);
204 if (0 != getnameinfo (ai->ai_addr, ai->ai_addrlen,
205 addrbuf, sizeof (addrbuf),
206 portbuf, sizeof (portbuf),
207 NI_NUMERICHOST | NI_NUMERICSERV)) {
208 if (ai->ai_addr->sa_family == AF_UNSPEC)
209 krb5int_buf_add(&buf, " AF_UNSPEC");
211 krb5int_buf_add_fmt(&buf, " af%d", ai->ai_addr->sa_family);
213 krb5int_buf_add_fmt(&buf, " %s.%s", addrbuf, portbuf);
214 if (krb5int_buf_data(&buf))
215 putstr(krb5int_buf_data(&buf));
216 krb5int_free_buf(&buf);
219 /* %D => krb5_data * */
220 d = va_arg(args, krb5_data *);
221 /* may not be nul-terminated */
222 put(d->data, d->length);
231 in_addrlist(struct server_entry *entry, struct serverlist *list)
234 struct server_entry *le;
236 for (i = 0; i < list->nservers; i++) {
237 le = &list->servers[i];
238 if (entry->hostname != NULL && le->hostname != NULL &&
239 strcmp(entry->hostname, le->hostname) == 0)
241 if (entry->hostname == NULL && le->hostname == NULL &&
242 entry->addrlen == le->addrlen &&
243 memcmp(&entry->addr, &le->addr, entry->addrlen) == 0)
250 check_for_svc_unavailable (krb5_context context,
251 const krb5_data *reply,
252 void *msg_handler_data)
254 krb5_error_code *retval = (krb5_error_code *)msg_handler_data;
258 if (krb5_is_krb_error(reply)) {
259 krb5_error *err_reply;
261 if (decode_krb5_error(reply, &err_reply) == 0) {
262 *retval = err_reply->error;
263 krb5_free_error(context, err_reply);
265 /* Returning 0 means continue to next KDC */
266 return (*retval != KDC_ERR_SVC_UNAVAILABLE);
274 * send the formatted request 'message' to a KDC for realm 'realm' and
275 * return the response (if any) in 'reply'.
277 * If the message is sent and a response is received, 0 is returned,
278 * otherwise an error code is returned.
280 * The storage for 'reply' is allocated and should be freed by the caller
285 krb5_sendto_kdc(krb5_context context, const krb5_data *message,
286 const krb5_data *realm, krb5_data *reply, int *use_master,
289 krb5_error_code retval, err;
290 struct serverlist servers;
291 int socktype1 = 0, socktype2 = 0, server_used;
294 * find KDC location(s) for realm
298 * BUG: This code won't return "interesting" errors (e.g., out of mem,
299 * bad config file) from locate_kdc. KRB5_REALM_CANT_RESOLVE can be
300 * ignored from one query of two, but if only one query is done, or
301 * both return that error, it should be returned to the caller. Also,
302 * "interesting" errors (not KRB5_KDC_UNREACH) from sendto_{udp,tcp}
303 * should probably be returned as well.
306 dprint("krb5_sendto_kdc(%d@%p, \"%D\", use_master=%d, tcp_only=%d)\n",
307 message->length, message->data, realm, *use_master, tcp_only);
308 TRACE_SENDTO_KDC(context, message->length, realm, *use_master, tcp_only);
310 if (!tcp_only && context->udp_pref_limit < 0) {
312 retval = profile_get_integer(context->profile,
313 KRB5_CONF_LIBDEFAULTS, KRB5_CONF_UDP_PREFERENCE_LIMIT, 0,
314 DEFAULT_UDP_PREF_LIMIT, &tmp);
318 tmp = DEFAULT_UDP_PREF_LIMIT;
319 else if (tmp > HARD_UDP_LIMIT)
320 /* In the unlikely case that a *really* big value is
321 given, let 'em use as big as we think we can
323 tmp = HARD_UDP_LIMIT;
324 context->udp_pref_limit = tmp;
328 socktype1 = SOCK_STREAM, socktype2 = 0;
329 else if (message->length <= (unsigned int) context->udp_pref_limit)
330 socktype1 = SOCK_DGRAM, socktype2 = SOCK_STREAM;
332 socktype1 = SOCK_STREAM, socktype2 = SOCK_DGRAM;
334 retval = k5_locate_kdc(context, realm, &servers, *use_master,
335 tcp_only ? SOCK_STREAM : 0);
339 retval = k5_sendto(context, message, &servers, socktype1, socktype2,
340 NULL, reply, NULL, NULL, &server_used,
341 check_for_svc_unavailable, &err);
342 if (retval == KRB5_KDC_UNREACH) {
343 if (err == KDC_ERR_SVC_UNAVAILABLE) {
344 retval = KRB5KDC_ERR_SVC_UNAVAILABLE;
346 krb5_set_error_message(context, retval,
347 _("Cannot contact any KDC for realm "
348 "'%.*s'"), realm->length, realm->data);
354 /* Set use_master to 1 if we ended up talking to a master when we didn't
355 * explicitly request to. */
356 if (*use_master == 0) {
357 struct serverlist mservers;
358 struct server_entry *entry = &servers.servers[server_used];
359 retval = k5_locate_kdc(context, realm, &mservers, TRUE,
362 if (in_addrlist(entry, &mservers))
364 k5_free_serverlist(&mservers);
366 TRACE_SENDTO_KDC_MASTER(context, *use_master);
371 k5_free_serverlist(&servers);
378 #define dperror(MSG) \
379 dprint("%s: an error occurred ... " \
380 "\tline=%d errno=%m socketerrno=%m\n", \
381 (MSG), __LINE__, errno, SOCKET_ERRNO)
383 #define dperror(MSG) dprint("%s: %m\n", MSG, errno)
385 #define dfprintf(ARGLIST) (debug ? fprintf ARGLIST : 0)
389 #define dperror(MSG) ((void)(MSG))
390 #define dfprintf(ARGLIST) ((void)0)
397 * Getting "connection refused" on a connected UDP socket causes
398 * select to indicate write capability on UNIX, but only shows up
399 * as an exception on Windows. (I don't think any UNIX system flags
400 * the error as an exception.) So we check for both, or make it
403 * Always watch for responses from *any* of the servers. Eventually
404 * fix the UDP code to do the same.
407 * - TCP NOPUSH/CORK socket options?
408 * - error codes that don't suck
409 * - getsockopt(SO_ERROR) to check connect status
410 * - handle error RESPONSE_TOO_BIG from UDP server and use TCP
411 * connections already in progress
417 * Currently only sendto_kdc.c knows how to use poll(); the other candidate
418 * user, lib/apputils/net-server.c, is stuck using select() for the moment
419 * since it is entangled with the RPC library. The following cm_* functions
420 * are not fully generic, are O(n^2) in the poll case, and are limited to
421 * handling 1024 connections (in order to maintain a constant-sized selstate).
422 * More rearchitecting would be appropriate before extending this support to
423 * the KDC and kadmind.
427 cm_init_selstate(struct select_state *selstate)
430 selstate->end_time.tv_sec = selstate->end_time.tv_usec = 0;
433 FD_ZERO(&selstate->rfds);
434 FD_ZERO(&selstate->wfds);
435 FD_ZERO(&selstate->xfds);
440 cm_add_fd(struct select_state *selstate, int fd, unsigned int ssflags)
443 if (selstate->nfds >= MAX_POLLFDS)
445 selstate->fds[selstate->nfds].fd = fd;
446 selstate->fds[selstate->nfds].events = 0;
447 if (ssflags & SSF_READ)
448 selstate->fds[selstate->nfds].events |= POLLIN;
449 if (ssflags & SSF_WRITE)
450 selstate->fds[selstate->nfds].events |= POLLOUT;
452 #ifndef _WIN32 /* On Windows FD_SETSIZE is a count, not a max value. */
453 if (fd >= FD_SETSIZE)
456 if (ssflags & SSF_READ)
457 FD_SET(fd, &selstate->rfds);
458 if (ssflags & SSF_WRITE)
459 FD_SET(fd, &selstate->wfds);
460 if (ssflags & SSF_EXCEPTION)
461 FD_SET(fd, &selstate->xfds);
462 if (selstate->max <= fd)
463 selstate->max = fd + 1;
470 cm_remove_fd(struct select_state *selstate, int fd)
475 /* Find the FD in the array and move the last entry to its place. */
476 assert(selstate->nfds > 0);
477 for (i = 0; i < selstate->nfds && selstate->fds[i].fd != fd; i++);
478 assert(i < selstate->nfds);
479 selstate->fds[i] = selstate->fds[selstate->nfds - 1];
481 FD_CLR(fd, &selstate->rfds);
482 FD_CLR(fd, &selstate->wfds);
483 FD_CLR(fd, &selstate->xfds);
484 if (selstate->max == 1 + fd) {
485 while (selstate->max > 0
486 && ! FD_ISSET(selstate->max-1, &selstate->rfds)
487 && ! FD_ISSET(selstate->max-1, &selstate->wfds)
488 && ! FD_ISSET(selstate->max-1, &selstate->xfds))
490 dprint("new max_fd + 1 is %d\n", selstate->max);
497 cm_unset_write(struct select_state *selstate, int fd)
502 for (i = 0; i < selstate->nfds && selstate->fds[i].fd != fd; i++);
503 assert(i < selstate->nfds);
504 selstate->fds[i].events &= ~POLLOUT;
506 FD_CLR(fd, &selstate->wfds);
510 static krb5_error_code
511 cm_select_or_poll(const struct select_state *in, struct select_state *out,
518 if (in->end_time.tv_sec == 0)
521 e = k5_getcurtime(&now);
524 timeout = (in->end_time.tv_sec - now.tv_sec) * 1000 +
525 (in->end_time.tv_usec - now.tv_usec) / 1000;
527 /* We don't need a separate copy of the selstate for poll, but use one
528 * anyone for consistency with the select wrapper. */
530 *sret = poll(out->fds, out->nfds, timeout);
532 return (*sret < 0) ? e : 0;
534 /* Use the select wrapper from cm.c. */
535 return krb5int_cm_call_select(in, out, sret);
540 cm_get_ssflags(struct select_state *selstate, int fd)
542 unsigned int ssflags = 0;
546 for (i = 0; i < selstate->nfds && selstate->fds[i].fd != fd; i++);
547 assert(i < selstate->nfds);
548 if (selstate->fds[i].revents & POLLIN)
550 if (selstate->fds[i].revents & POLLOUT)
551 ssflags |= SSF_WRITE;
552 if (selstate->fds[i].revents & POLLERR)
553 ssflags |= SSF_EXCEPTION;
555 if (FD_ISSET(fd, &selstate->rfds))
557 if (FD_ISSET(fd, &selstate->wfds))
558 ssflags |= SSF_WRITE;
559 if (FD_ISSET(fd, &selstate->xfds))
560 ssflags |= SSF_EXCEPTION;
565 static int service_tcp_fd(krb5_context context, struct conn_state *conn,
566 struct select_state *selstate, int ssflags);
567 static int service_udp_fd(krb5_context context, struct conn_state *conn,
568 struct select_state *selstate, int ssflags);
571 set_conn_state_msg_length (struct conn_state *state, const krb5_data *message)
573 if (!message || message->length == 0)
576 if (!state->is_udp) {
578 store_32_be(message->length, state->x.out.msg_len_buf);
579 SG_SET(&state->x.out.sgbuf[0], state->x.out.msg_len_buf, 4);
580 SG_SET(&state->x.out.sgbuf[1], message->data, message->length);
581 state->x.out.sg_count = 2;
585 SG_SET(&state->x.out.sgbuf[0], message->data, message->length);
586 SG_SET(&state->x.out.sgbuf[1], 0, 0);
587 state->x.out.sg_count = 1;
592 static krb5_error_code
593 add_connection(struct conn_state **conns, struct addrinfo *ai,
594 size_t server_index, const krb5_data *message, char **udpbufp)
596 struct conn_state *state, **tailptr;
598 state = calloc(1, sizeof(*state));
601 state->state = INITIALIZING;
603 state->x.out.sgp = state->x.out.sgbuf;
604 state->socktype = ai->ai_socktype;
605 state->family = ai->ai_family;
606 state->addrlen = ai->ai_addrlen;
607 memcpy(&state->addr, ai->ai_addr, ai->ai_addrlen);
608 state->fd = INVALID_SOCKET;
609 state->server_index = server_index;
610 SG_SET(&state->x.out.sgbuf[1], 0, 0);
611 if (ai->ai_socktype == SOCK_STREAM) {
613 SG_SET(&state->x.out.sgbuf[0], message_len_buf, 4);
614 SG_SET(&state->x.out.sgbuf[1], message->data, message->length);
615 state->x.out.sg_count = 2;
619 state->service = service_tcp_fd;
620 set_conn_state_msg_length (state, message);
623 SG_SET(&state->x.out.sgbuf[0], message->data, message->length);
624 SG_SET(&state->x.out.sgbuf[1], 0, 0);
625 state->x.out.sg_count = 1;
629 state->service = service_udp_fd;
630 set_conn_state_msg_length (state, message);
632 if (*udpbufp == NULL) {
633 *udpbufp = malloc(krb5_max_dgram_size);
637 state->x.in.buf = *udpbufp;
638 state->x.in.bufsize = krb5_max_dgram_size;
641 /* Chain the new state onto the tail of the list. */
642 for (tailptr = conns; *tailptr != NULL; tailptr = &(*tailptr)->next);
649 translate_ai_error (int err)
658 /* All of these indicate bad inputs to getaddrinfo. */
661 /* Translate to standard errno code. */
664 /* Translate to standard errno code. */
666 #ifdef EAI_ADDRFAMILY
669 #if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME
673 /* Name not known or no address data, but no error. Do
678 /* An argument buffer overflowed. */
679 return EINVAL; /* XXX */
683 /* System error, obviously. */
687 /* An error code we haven't handled? */
693 * Resolve the entry in servers with index ind, adding connections to the list
694 * *conns. Connections are added for each of socktype1 and (if not zero)
695 * socktype2. message and udpbufp are used to initialize the connections; see
696 * add_connection above. If no addresses are available for an entry but no
697 * internal name resolution failure occurs, return 0 without adding any new
700 static krb5_error_code
701 resolve_server(krb5_context context, const struct serverlist *servers,
702 size_t ind, int socktype1, int socktype2,
703 const krb5_data *message, char **udpbufp,
704 struct conn_state **conns)
706 krb5_error_code retval;
707 struct server_entry *entry = &servers->servers[ind];
708 struct addrinfo *addrs, *a, hint, ai;
712 /* Skip any stray entries of socktypes we don't want. */
713 if (entry->socktype != 0 && entry->socktype != socktype1 &&
714 entry->socktype != socktype2)
717 if (entry->hostname == NULL) {
718 ai.ai_socktype = entry->socktype;
719 ai.ai_family = entry->family;
720 ai.ai_addrlen = entry->addrlen;
721 ai.ai_addr = (struct sockaddr *)&entry->addr;
722 return add_connection(conns, &ai, ind, message, udpbufp);
725 memset(&hint, 0, sizeof(hint));
726 hint.ai_family = entry->family;
727 hint.ai_socktype = (entry->socktype != 0) ? entry->socktype : socktype1;
728 hint.ai_flags = AI_ADDRCONFIG;
729 #ifdef AI_NUMERICSERV
730 hint.ai_flags |= AI_NUMERICSERV;
732 result = snprintf(portbuf, sizeof(portbuf), "%d", ntohs(entry->port));
733 if (SNPRINTF_OVERFLOW(result, sizeof(portbuf)))
735 TRACE_SENDTO_KDC_RESOLVING(context, entry->hostname);
736 err = getaddrinfo(entry->hostname, portbuf, &hint, &addrs);
738 return translate_ai_error(err);
739 /* Add each address with the preferred socktype. */
741 for (a = addrs; a != 0 && retval == 0; a = a->ai_next)
742 retval = add_connection(conns, a, ind, message, udpbufp);
743 if (retval == 0 && entry->socktype == 0 && socktype2 != 0) {
744 /* Add each address again with the non-preferred socktype. */
745 for (a = addrs; a != 0 && retval == 0; a = a->ai_next) {
746 a->ai_socktype = socktype2;
747 retval = add_connection(conns, a, ind, message, udpbufp);
755 start_connection(krb5_context context, struct conn_state *state,
756 struct select_state *selstate,
757 struct sendto_callback_info *callback_info)
760 unsigned int ssflags;
761 static const int one = 1;
762 static const struct linger lopt = { 0, 0 };
764 dprint("start_connection(@%p)\ngetting %s socket in family %d...", state,
765 state->socktype == SOCK_STREAM ? "stream" : "dgram", state->family);
766 fd = socket(state->family, state->socktype, 0);
767 if (fd == INVALID_SOCKET) {
768 state->err = SOCKET_ERRNO;
769 dprint("socket: %m creating with af %d\n", state->err, state->family);
770 return -1; /* try other hosts */
773 /* Make it non-blocking. */
774 if (ioctlsocket(fd, FIONBIO, (const void *) &one))
775 dperror("sendto_kdc: ioctl(FIONBIO)");
776 if (state->socktype == SOCK_STREAM) {
777 if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &lopt, sizeof(lopt)))
778 dperror("sendto_kdc: setsockopt(SO_LINGER)");
779 TRACE_SENDTO_KDC_TCP_CONNECT(context, state);
782 /* Start connecting to KDC. */
783 e = connect(fd, (struct sockaddr *)&state->addr, state->addrlen);
786 * This is the path that should be followed for non-blocking
789 if (SOCKET_ERRNO == EINPROGRESS || SOCKET_ERRNO == EWOULDBLOCK) {
790 state->state = CONNECTING;
793 dprint("connect failed: %m\n", SOCKET_ERRNO);
794 (void) closesocket(fd);
795 state->err = SOCKET_ERRNO;
796 state->state = FAILED;
801 * Connect returned zero even though we made it non-blocking. This
802 * happens normally for UDP sockets, and can perhaps also happen for
803 * TCP sockets connecting to localhost.
805 state->state = WRITING;
808 dprint("new state = %s\n", state_strings[state->state]);
812 * Here's where KPASSWD callback gets the socket information it needs for
817 e = callback_info->pfn_callback(state, callback_info->context,
818 &state->callback_buffer);
820 dprint("callback failed: %m\n", e);
821 (void) closesocket(fd);
823 state->fd = INVALID_SOCKET;
824 state->state = FAILED;
828 set_conn_state_msg_length(state, &state->callback_buffer);
831 if (state->socktype == SOCK_DGRAM) {
834 sg_buf *sg = &state->x.out.sgbuf[0];
836 TRACE_SENDTO_KDC_UDP_SEND_INITIAL(context, state);
837 dprint("sending %d bytes on fd %d\n", SG_LEN(sg), state->fd);
838 ret = send(state->fd, SG_BUF(sg), SG_LEN(sg), 0);
839 if (ret < 0 || (size_t) ret != SG_LEN(sg)) {
840 TRACE_SENDTO_KDC_UDP_ERROR_SEND_INITIAL(context, state,
843 (void) closesocket(state->fd);
844 state->fd = INVALID_SOCKET;
845 state->state = FAILED;
848 state->state = READING;
851 ssflags = SSF_READ | SSF_EXCEPTION;
852 if (state->state == CONNECTING || state->state == WRITING)
853 ssflags |= SSF_WRITE;
854 if (!cm_add_fd(selstate, state->fd, ssflags)) {
855 (void) closesocket(state->fd);
856 state->fd = INVALID_SOCKET;
857 state->state = FAILED;
864 /* Return 0 if we sent something, non-0 otherwise.
865 If 0 is returned, the caller should delay waiting for a response.
866 Otherwise, the caller should immediately move on to process the
869 maybe_send(krb5_context context, struct conn_state *conn,
870 struct select_state *selstate,
871 struct sendto_callback_info *callback_info)
876 dprint("maybe_send(@%p) state=%s type=%s\n", conn,
877 state_strings[conn->state],
878 conn->is_udp ? "udp" : "tcp");
879 if (conn->state == INITIALIZING)
880 return start_connection(context, conn, selstate, callback_info);
882 /* Did we already shut down this channel? */
883 if (conn->state == FAILED) {
884 dprint("connection already closed\n");
888 if (conn->socktype == SOCK_STREAM) {
889 dprint("skipping stream socket\n");
890 /* The select callback will handle flushing any data we
891 haven't written yet, and we only write it once. */
895 /* UDP - retransmit after a previous attempt timed out. */
896 sg = &conn->x.out.sgbuf[0];
897 TRACE_SENDTO_KDC_UDP_SEND_RETRY(context, conn);
898 dprint("sending %d bytes on fd %d\n", SG_LEN(sg), conn->fd);
899 ret = send(conn->fd, SG_BUF(sg), SG_LEN(sg), 0);
900 if (ret < 0 || (size_t) ret != SG_LEN(sg)) {
901 TRACE_SENDTO_KDC_UDP_ERROR_SEND_RETRY(context, conn, SOCKET_ERRNO);
903 /* Keep connection alive, we'll try again next pass.
905 Is this likely to catch any errors we didn't get from the
909 /* Yay, it worked. */
914 kill_conn(struct conn_state *conn, struct select_state *selstate, int err)
916 dprint("abandoning connection %d: %m\n", conn->fd, err);
917 cm_remove_fd(selstate, conn->fd);
918 closesocket(conn->fd);
919 conn->fd = INVALID_SOCKET;
920 conn->state = FAILED;
924 /* Check socket for error. */
929 socklen_t sockerrlen;
932 sockerrlen = sizeof(sockerr);
933 e = getsockopt(fd, SOL_SOCKET, SO_ERROR, &sockerr, &sockerrlen);
935 /* What to do now? */
937 dprint("getsockopt(SO_ERROR) on fd failed: %m\n", e);
943 /* Return nonzero only if we're finished and the caller should exit
944 its loop. This happens in two cases: We have a complete message,
945 or the socket has closed and no others are open. */
948 service_tcp_fd(krb5_context context, struct conn_state *conn,
949 struct select_state *selstate, int ssflags)
952 ssize_t nwritten, nread;
954 if (!(ssflags & (SSF_READ|SSF_WRITE|SSF_EXCEPTION)))
956 switch (conn->state) {
957 SOCKET_WRITEV_TEMP tmp;
960 if (ssflags & SSF_READ) {
961 /* Bad -- the KDC shouldn't be sending to us first. */
964 TRACE_SENDTO_KDC_TCP_DISCONNECT(context, conn);
965 kill_conn(conn, selstate, e);
967 closesocket(conn->fd);
968 conn->fd = INVALID_SOCKET;
972 if (ssflags & SSF_EXCEPTION) {
974 e = get_so_error(conn->fd);
976 dprint("socket error on exception fd: %m", e);
978 dprint("no socket error info available on exception fd");
983 * Connect finished -- but did it succeed or fail?
984 * UNIX sets can_write if failed.
985 * Call getsockopt to see if error pending.
987 * (For most UNIX systems it works to just try writing the
988 * first time and detect an error. But Bill Dodd at IBM
989 * reports that some version of AIX, SIGPIPE can result.)
991 e = get_so_error(conn->fd);
993 TRACE_SENDTO_KDC_TCP_ERROR_CONNECT(context, conn, e);
994 dprint("socket error on write fd: %m", e);
997 conn->state = WRITING;
1001 if (ssflags & SSF_READ) {
1003 /* Bad -- the KDC shouldn't be sending anything yet. */
1006 if (ssflags & SSF_EXCEPTION)
1007 goto handle_exception;
1010 dprint("trying to writev %d (%d bytes) to fd %d\n",
1011 conn->x.out.sg_count,
1012 ((conn->x.out.sg_count == 2 ? SG_LEN(&conn->x.out.sgp[1]) : 0)
1013 + SG_LEN(&conn->x.out.sgp[0])),
1015 TRACE_SENDTO_KDC_TCP_SEND(context, conn);
1016 nwritten = SOCKET_WRITEV(conn->fd, conn->x.out.sgp,
1017 conn->x.out.sg_count, tmp);
1020 TRACE_SENDTO_KDC_TCP_ERROR_SEND(context, conn, e);
1021 dprint("failed: %m\n", e);
1024 dprint("wrote %d bytes\n", nwritten);
1026 sg_buf *sgp = conn->x.out.sgp;
1027 if ((size_t) nwritten < SG_LEN(sgp)) {
1028 SG_ADVANCE(sgp, (size_t) nwritten);
1031 nwritten -= SG_LEN(sgp);
1033 conn->x.out.sg_count--;
1034 if (conn->x.out.sg_count == 0 && nwritten != 0)
1035 /* Wrote more than we wanted to? */
1039 if (conn->x.out.sg_count == 0) {
1040 /* Done writing, switch to reading. */
1041 /* Don't call shutdown at this point because
1042 * some implementations cannot deal with half-closed connections.*/
1043 cm_unset_write(selstate, conn->fd);
1044 /* Q: How do we detect failures to send the remaining data
1045 to the remote side, since we're in non-blocking mode?
1046 Will we always get errors on the reading side? */
1047 dprint("switching fd %d to READING\n", conn->fd);
1048 conn->state = READING;
1049 conn->x.in.bufsizebytes_read = 0;
1050 conn->x.in.bufsize = 0;
1053 conn->x.in.n_left = 0;
1058 if (ssflags & SSF_EXCEPTION) {
1059 if (conn->x.in.buf) {
1060 free(conn->x.in.buf);
1063 goto handle_exception;
1066 if (conn->x.in.bufsizebytes_read == 4) {
1068 dprint("reading %d bytes of data from fd %d\n",
1069 (int) conn->x.in.n_left, conn->fd);
1070 nread = SOCKET_READ(conn->fd, conn->x.in.pos, conn->x.in.n_left);
1072 e = nread ? SOCKET_ERRNO : ECONNRESET;
1073 free(conn->x.in.buf);
1075 TRACE_SENDTO_KDC_TCP_ERROR_RECV(context, conn, e);
1078 conn->x.in.n_left -= nread;
1079 conn->x.in.pos += nread;
1080 if (conn->x.in.n_left <= 0) {
1085 /* Reading length. */
1086 nread = SOCKET_READ(conn->fd,
1087 conn->x.in.bufsizebytes + conn->x.in.bufsizebytes_read,
1088 4 - conn->x.in.bufsizebytes_read);
1090 TRACE_SENDTO_KDC_TCP_ERROR_RECV_LEN(context, conn, e);
1094 conn->x.in.bufsizebytes_read += nread;
1095 if (conn->x.in.bufsizebytes_read == 4) {
1096 unsigned long len = load_32_be (conn->x.in.bufsizebytes);
1097 dprint("received length on fd %d is %d\n", conn->fd, (int)len);
1098 /* Arbitrary 1M cap. */
1099 if (len > 1 * 1024 * 1024) {
1103 conn->x.in.bufsize = conn->x.in.n_left = len;
1104 conn->x.in.buf = conn->x.in.pos = malloc(len);
1105 dprint("allocated %d byte buffer at %p\n", (int) len,
1107 if (conn->x.in.buf == 0) {
1108 /* allocation failure */
1123 service_udp_fd(krb5_context context, struct conn_state *conn,
1124 struct select_state *selstate, int ssflags)
1128 if (!(ssflags & (SSF_READ|SSF_EXCEPTION)))
1130 if (conn->state != READING)
1133 nread = recv(conn->fd, conn->x.in.buf, conn->x.in.bufsize, 0);
1135 TRACE_SENDTO_KDC_UDP_ERROR_RECV(context, conn, SOCKET_ERRNO);
1136 kill_conn(conn, selstate, SOCKET_ERRNO);
1139 conn->x.in.pos = conn->x.in.buf + nread;
1144 service_fds(krb5_context context, struct select_state *selstate, int interval,
1145 struct conn_state *conns, struct select_state *seltemp,
1146 int (*msg_handler)(krb5_context, const krb5_data *, void *),
1147 void *msg_handler_data, struct conn_state **winner_out)
1151 struct conn_state *state;
1155 e = k5_getcurtime(&now);
1158 selstate->end_time = now;
1159 selstate->end_time.tv_sec += interval;
1162 while (selstate->nfds > 0) {
1163 e = cm_select_or_poll(selstate, seltemp, &selret);
1169 dprint("service_fds examining results, selret=%d\n", selret);
1172 /* Timeout, return to caller. */
1175 /* Got something on a socket, process it. */
1176 for (state = conns; state != NULL; state = state->next) {
1179 if (state->fd == INVALID_SOCKET)
1181 ssflags = cm_get_ssflags(seltemp, state->fd);
1185 if (state->service(context, state, selstate, ssflags)) {
1188 if (msg_handler != NULL) {
1191 reply.data = state->x.in.buf;
1192 reply.length = state->x.in.pos - state->x.in.buf;
1194 stop = (msg_handler(context, &reply, msg_handler_data) != 0);
1198 dprint("fd service routine says we're done\n");
1199 *winner_out = state;
1211 * Current worst-case timeout behavior:
1213 * First pass, 1s per udp or tcp server, plus 2s at end.
1214 * Second pass, 1s per udp server, plus 4s.
1215 * Third pass, 1s per udp server, plus 8s.
1216 * Fourth => 16s, etc.
1219 * Per UDP server, 1s per pass.
1220 * Per TCP server, 1s.
1221 * Backoff delay, 2**(P+1) - 2, where P is total number of passes.
1223 * Total = 2**(P+1) + U*P + T - 2.
1225 * If P=3, Total = 3*U + T + 14.
1226 * If P=4, Total = 4*U + T + 30.
1228 * Note that if you try to reach two ports (e.g., both 88 and 750) on
1229 * one server, it counts as two.
1233 k5_sendto(krb5_context context, const krb5_data *message,
1234 const struct serverlist *servers, int socktype1, int socktype2,
1235 struct sendto_callback_info* callback_info, krb5_data *reply,
1236 struct sockaddr *remoteaddr, socklen_t *remoteaddrlen,
1238 /* return 0 -> keep going, 1 -> quit */
1239 int (*msg_handler)(krb5_context, const krb5_data *, void *),
1240 void *msg_handler_data)
1243 krb5_error_code retval;
1244 struct conn_state *conns = NULL, *state, **tailptr, *next, *winner;
1246 struct select_state *sel_state = NULL, *seltemp;
1247 char *udpbuf = NULL;
1248 krb5_boolean done = FALSE;
1253 /* One for use here, listing all our fds in use, and one for
1254 * temporary use in service_fds, for the fds of interest. */
1255 sel_state = malloc(2 * sizeof(*sel_state));
1256 if (sel_state == NULL) {
1260 seltemp = &sel_state[1];
1261 cm_init_selstate(sel_state);
1263 /* First pass: resolve server hosts, communicate with resulting addresses
1264 * of the preferred socktype, and wait 1s for an answer from each. */
1265 for (s = 0; s < servers->nservers && !done; s++) {
1266 /* Find the current tail pointer. */
1267 for (tailptr = &conns; *tailptr != NULL; tailptr = &(*tailptr)->next);
1268 retval = resolve_server(context, servers, s, socktype1, socktype2,
1269 message, &udpbuf, &conns);
1272 for (state = *tailptr; state != NULL && !done; state = state->next) {
1273 /* Contact each new connection whose socktype matches socktype1. */
1274 if (state->socktype != socktype1)
1276 if (maybe_send(context, state, sel_state, callback_info))
1278 done = service_fds(context, sel_state, 1, conns, seltemp,
1279 msg_handler, msg_handler_data, &winner);
1283 /* Complete the first pass by contacting servers of the non-preferred
1284 * socktype (if given), waiting 1s for an answer from each. */
1285 for (state = conns; state != NULL && !done; state = state->next) {
1286 if (state->socktype != socktype2)
1288 if (maybe_send(context, state, sel_state, callback_info))
1290 done = service_fds(context, sel_state, 1, state, seltemp, msg_handler,
1291 msg_handler_data, &winner);
1294 /* Wait for two seconds at the end of the first pass. */
1296 done = service_fds(context, sel_state, 2, conns, seltemp, msg_handler,
1297 msg_handler_data, &winner);
1300 /* Make remaining passes over all of the connections. */
1302 for (pass = 1; pass < MAX_PASS && !done; pass++) {
1303 for (state = conns; state != NULL && !done; state = state->next) {
1304 if (maybe_send(context, state, sel_state, callback_info))
1306 done = service_fds(context, sel_state, 1, conns, seltemp,
1307 msg_handler, msg_handler_data, &winner);
1308 if (sel_state->nfds == 0)
1311 /* Wait for the delay backoff at the end of this pass. */
1313 done = service_fds(context, sel_state, delay, conns, seltemp,
1314 msg_handler, msg_handler_data, &winner);
1316 if (sel_state->nfds == 0)
1321 if (sel_state->nfds == 0 || !done || winner == NULL) {
1322 retval = KRB5_KDC_UNREACH;
1326 TRACE_SENDTO_KDC_RESPONSE(context, winner);
1327 reply->data = winner->x.in.buf;
1328 reply->length = winner->x.in.pos - winner->x.in.buf;
1330 winner->x.in.buf = NULL;
1331 if (server_used != NULL)
1332 *server_used = winner->server_index;
1333 if (remoteaddr != NULL && remoteaddrlen != 0 && *remoteaddrlen > 0)
1334 (void)getpeername(winner->fd, remoteaddr, remoteaddrlen);
1337 for (state = conns; state != NULL; state = next) {
1339 if (state->fd != INVALID_SOCKET)
1340 closesocket(state->fd);
1341 if (state->state == READING && state->x.in.buf != udpbuf)
1342 free(state->x.in.buf);
1343 if (callback_info) {
1344 callback_info->pfn_cleanup(callback_info->context,
1345 &state->callback_buffer);
1350 if (reply->data != udpbuf)