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 #if defined(HAVE_POLL_H)
38 #define MAX_POLLFDS 1024
39 #elif defined(HAVE_SYS_SELECT_H)
40 #include <sys/select.h>
45 #include <sys/ioctl.h>
46 #ifdef HAVE_SYS_FILIO_H
47 #include <sys/filio.h>
52 #define DEFAULT_UDP_PREF_LIMIT 1465
53 #define HARD_UDP_LIMIT 32700 /* could probably do 64K-epsilon ? */
55 /* Select state flags. */
57 #define SSF_WRITE 0x02
58 #define SSF_EXCEPTION 0x04
60 typedef int64_t time_ms;
62 /* This can be pretty large, so should not be stack-allocated. */
65 struct pollfd fds[MAX_POLLFDS];
68 fd_set rfds, wfds, xfds;
73 static const char *const state_strings[] = {
74 "INITIALIZING", "CONNECTING", "WRITING", "READING", "FAILED"
77 /* connection states */
78 enum conn_states { INITIALIZING, CONNECTING, WRITING, READING, FAILED };
79 struct incoming_krb5_message {
80 size_t bufsizebytes_read;
84 unsigned char bufsizebytes[4];
90 enum conn_states state;
91 int (*service)(krb5_context context, struct conn_state *,
92 struct select_state *, int);
93 struct remote_address addr;
99 unsigned char msg_len_buf[4];
101 struct incoming_krb5_message in;
103 krb5_data callback_buffer;
105 struct conn_state *next;
109 /* Get current time in milliseconds. */
110 static krb5_error_code
111 get_curtime_ms(time_ms *time_out)
115 if (gettimeofday(&tv, 0))
117 *time_out = (time_ms)tv.tv_sec * 1000 + tv.tv_usec / 1000;
123 /* Find a pollfd in selstate by fd, or abort if we can't find it. */
124 static inline struct pollfd *
125 find_pollfd(struct select_state *selstate, int fd)
129 for (i = 0; i < selstate->nfds; i++) {
130 if (selstate->fds[i].fd == fd)
131 return &selstate->fds[i];
137 cm_init_selstate(struct select_state *selstate)
143 cm_add_fd(struct select_state *selstate, int fd)
145 if (selstate->nfds >= MAX_POLLFDS)
147 selstate->fds[selstate->nfds].fd = fd;
148 selstate->fds[selstate->nfds].events = 0;
154 cm_remove_fd(struct select_state *selstate, int fd)
156 struct pollfd *pfd = find_pollfd(selstate, fd);
158 *pfd = selstate->fds[selstate->nfds - 1];
162 /* Poll for reading (and not writing) on fd the next time we poll. */
164 cm_read(struct select_state *selstate, int fd)
166 find_pollfd(selstate, fd)->events = POLLIN;
169 /* Poll for writing (and not reading) on fd the next time we poll. */
171 cm_write(struct select_state *selstate, int fd)
173 find_pollfd(selstate, fd)->events = POLLOUT;
176 /* Get the output events for fd in the form of ssflags. */
178 cm_get_ssflags(struct select_state *selstate, int fd)
180 struct pollfd *pfd = find_pollfd(selstate, fd);
183 * OS X sets POLLHUP without POLLOUT on connection error. Catch this as
184 * well as other error events such as POLLNVAL, but only if POLLIN and
185 * POLLOUT aren't set, as we can get POLLHUP along with POLLIN with TCP
186 * data still to be read.
188 if (pfd->revents != 0 && !(pfd->revents & (POLLIN | POLLOUT)))
189 return SSF_EXCEPTION;
191 return ((pfd->revents & POLLIN) ? SSF_READ : 0) |
192 ((pfd->revents & POLLOUT) ? SSF_WRITE : 0) |
193 ((pfd->revents & POLLERR) ? SSF_EXCEPTION : 0);
196 #else /* not USE_POLL */
199 cm_init_selstate(struct select_state *selstate)
203 FD_ZERO(&selstate->rfds);
204 FD_ZERO(&selstate->wfds);
205 FD_ZERO(&selstate->xfds);
209 cm_add_fd(struct select_state *selstate, int fd)
211 #ifndef _WIN32 /* On Windows FD_SETSIZE is a count, not a max value. */
212 if (fd >= FD_SETSIZE)
215 FD_SET(fd, &selstate->xfds);
216 if (selstate->max <= fd)
217 selstate->max = fd + 1;
223 cm_remove_fd(struct select_state *selstate, int fd)
225 FD_CLR(fd, &selstate->rfds);
226 FD_CLR(fd, &selstate->wfds);
227 FD_CLR(fd, &selstate->xfds);
228 if (selstate->max == fd + 1) {
229 while (selstate->max > 0 &&
230 !FD_ISSET(selstate->max - 1, &selstate->rfds) &&
231 !FD_ISSET(selstate->max - 1, &selstate->wfds) &&
232 !FD_ISSET(selstate->max - 1, &selstate->xfds))
238 /* Select for reading (and not writing) on fd the next time we select. */
240 cm_read(struct select_state *selstate, int fd)
242 FD_SET(fd, &selstate->rfds);
243 FD_CLR(fd, &selstate->wfds);
246 /* Select for writing (and not reading) on fd the next time we select. */
248 cm_write(struct select_state *selstate, int fd)
250 FD_CLR(fd, &selstate->rfds);
251 FD_SET(fd, &selstate->wfds);
254 /* Get the events for fd from selstate after a select. */
256 cm_get_ssflags(struct select_state *selstate, int fd)
258 return (FD_ISSET(fd, &selstate->rfds) ? SSF_READ : 0) |
259 (FD_ISSET(fd, &selstate->wfds) ? SSF_WRITE : 0) |
260 (FD_ISSET(fd, &selstate->xfds) ? SSF_EXCEPTION : 0);
263 #endif /* not USE_POLL */
265 static krb5_error_code
266 cm_select_or_poll(const struct select_state *in, time_ms endtime,
267 struct select_state *out, int *sret)
272 krb5_error_code retval;
273 time_ms curtime, interval;
275 retval = get_curtime_ms(&curtime);
278 interval = (curtime < endtime) ? endtime - curtime : 0;
280 /* We don't need a separate copy of the selstate for poll, but use one for
281 * consistency with how we use select. */
285 *sret = poll(out->fds, out->nfds, interval);
287 tv.tv_sec = interval / 1000;
288 tv.tv_usec = interval % 1000 * 1000;
289 *sret = select(out->max, &out->rfds, &out->wfds, &out->xfds, &tv);
292 return (*sret < 0) ? SOCKET_ERRNO : 0;
296 in_addrlist(struct server_entry *entry, struct serverlist *list)
299 struct server_entry *le;
301 for (i = 0; i < list->nservers; i++) {
302 le = &list->servers[i];
303 if (entry->hostname != NULL && le->hostname != NULL &&
304 strcmp(entry->hostname, le->hostname) == 0)
306 if (entry->hostname == NULL && le->hostname == NULL &&
307 entry->addrlen == le->addrlen &&
308 memcmp(&entry->addr, &le->addr, entry->addrlen) == 0)
315 check_for_svc_unavailable (krb5_context context,
316 const krb5_data *reply,
317 void *msg_handler_data)
319 krb5_error_code *retval = (krb5_error_code *)msg_handler_data;
323 if (krb5_is_krb_error(reply)) {
324 krb5_error *err_reply;
326 if (decode_krb5_error(reply, &err_reply) == 0) {
327 *retval = err_reply->error;
328 krb5_free_error(context, err_reply);
330 /* Returning 0 means continue to next KDC */
331 return (*retval != KDC_ERR_SVC_UNAVAILABLE);
339 * send the formatted request 'message' to a KDC for realm 'realm' and
340 * return the response (if any) in 'reply'.
342 * If the message is sent and a response is received, 0 is returned,
343 * otherwise an error code is returned.
345 * The storage for 'reply' is allocated and should be freed by the caller
350 krb5_sendto_kdc(krb5_context context, const krb5_data *message,
351 const krb5_data *realm, krb5_data *reply, int *use_master,
354 krb5_error_code retval, err;
355 struct serverlist servers;
356 int socktype1 = 0, socktype2 = 0, server_used;
359 * find KDC location(s) for realm
363 * BUG: This code won't return "interesting" errors (e.g., out of mem,
364 * bad config file) from locate_kdc. KRB5_REALM_CANT_RESOLVE can be
365 * ignored from one query of two, but if only one query is done, or
366 * both return that error, it should be returned to the caller. Also,
367 * "interesting" errors (not KRB5_KDC_UNREACH) from sendto_{udp,tcp}
368 * should probably be returned as well.
371 TRACE_SENDTO_KDC(context, message->length, realm, *use_master, tcp_only);
373 if (!tcp_only && context->udp_pref_limit < 0) {
375 retval = profile_get_integer(context->profile,
376 KRB5_CONF_LIBDEFAULTS, KRB5_CONF_UDP_PREFERENCE_LIMIT, 0,
377 DEFAULT_UDP_PREF_LIMIT, &tmp);
381 tmp = DEFAULT_UDP_PREF_LIMIT;
382 else if (tmp > HARD_UDP_LIMIT)
383 /* In the unlikely case that a *really* big value is
384 given, let 'em use as big as we think we can
386 tmp = HARD_UDP_LIMIT;
387 context->udp_pref_limit = tmp;
391 socktype1 = SOCK_STREAM, socktype2 = 0;
392 else if (message->length <= (unsigned int) context->udp_pref_limit)
393 socktype1 = SOCK_DGRAM, socktype2 = SOCK_STREAM;
395 socktype1 = SOCK_STREAM, socktype2 = SOCK_DGRAM;
397 retval = k5_locate_kdc(context, realm, &servers, *use_master,
398 tcp_only ? SOCK_STREAM : 0);
403 retval = k5_sendto(context, message, &servers, socktype1, socktype2,
404 NULL, reply, NULL, NULL, &server_used,
405 check_for_svc_unavailable, &err);
406 if (retval == KRB5_KDC_UNREACH) {
407 if (err == KDC_ERR_SVC_UNAVAILABLE) {
408 retval = KRB5KDC_ERR_SVC_UNAVAILABLE;
410 krb5_set_error_message(context, retval,
411 _("Cannot contact any KDC for realm "
412 "'%.*s'"), realm->length, realm->data);
418 /* Set use_master to 1 if we ended up talking to a master when we didn't
419 * explicitly request to. */
420 if (*use_master == 0) {
421 struct serverlist mservers;
422 struct server_entry *entry = &servers.servers[server_used];
423 retval = k5_locate_kdc(context, realm, &mservers, TRUE,
426 if (in_addrlist(entry, &mservers))
428 k5_free_serverlist(&mservers);
430 TRACE_SENDTO_KDC_MASTER(context, *use_master);
435 k5_free_serverlist(&servers);
442 * Getting "connection refused" on a connected UDP socket causes
443 * select to indicate write capability on UNIX, but only shows up
444 * as an exception on Windows. (I don't think any UNIX system flags
445 * the error as an exception.) So we check for both, or make it
448 * Always watch for responses from *any* of the servers. Eventually
449 * fix the UDP code to do the same.
452 * - TCP NOPUSH/CORK socket options?
453 * - error codes that don't suck
454 * - getsockopt(SO_ERROR) to check connect status
455 * - handle error RESPONSE_TOO_BIG from UDP server and use TCP
456 * connections already in progress
459 static int service_tcp_fd(krb5_context context, struct conn_state *conn,
460 struct select_state *selstate, int ssflags);
461 static int service_udp_fd(krb5_context context, struct conn_state *conn,
462 struct select_state *selstate, int ssflags);
465 set_conn_state_msg_length (struct conn_state *state, const krb5_data *message)
467 if (!message || message->length == 0)
470 if (state->addr.type == SOCK_STREAM) {
471 store_32_be(message->length, state->x.out.msg_len_buf);
472 SG_SET(&state->x.out.sgbuf[0], state->x.out.msg_len_buf, 4);
473 SG_SET(&state->x.out.sgbuf[1], message->data, message->length);
474 state->x.out.sg_count = 2;
478 SG_SET(&state->x.out.sgbuf[0], message->data, message->length);
479 SG_SET(&state->x.out.sgbuf[1], 0, 0);
480 state->x.out.sg_count = 1;
485 static krb5_error_code
486 add_connection(struct conn_state **conns, struct addrinfo *ai,
487 size_t server_index, const krb5_data *message, char **udpbufp)
489 struct conn_state *state, **tailptr;
491 state = calloc(1, sizeof(*state));
494 state->state = INITIALIZING;
495 state->x.out.sgp = state->x.out.sgbuf;
496 state->addr.type = ai->ai_socktype;
497 state->addr.family = ai->ai_family;
498 state->addr.len = ai->ai_addrlen;
499 memcpy(&state->addr.saddr, ai->ai_addr, ai->ai_addrlen);
500 state->fd = INVALID_SOCKET;
501 state->server_index = server_index;
502 SG_SET(&state->x.out.sgbuf[1], 0, 0);
503 if (ai->ai_socktype == SOCK_STREAM) {
504 state->service = service_tcp_fd;
505 set_conn_state_msg_length (state, message);
507 state->service = service_udp_fd;
508 set_conn_state_msg_length (state, message);
510 if (*udpbufp == NULL) {
511 *udpbufp = malloc(MAX_DGRAM_SIZE);
515 state->x.in.buf = *udpbufp;
516 state->x.in.bufsize = MAX_DGRAM_SIZE;
519 /* Chain the new state onto the tail of the list. */
520 for (tailptr = conns; *tailptr != NULL; tailptr = &(*tailptr)->next);
527 translate_ai_error (int err)
536 /* All of these indicate bad inputs to getaddrinfo. */
539 /* Translate to standard errno code. */
542 /* Translate to standard errno code. */
544 #ifdef EAI_ADDRFAMILY
547 #if defined(EAI_NODATA) && EAI_NODATA != EAI_NONAME
551 /* Name not known or no address data, but no error. Do
556 /* An argument buffer overflowed. */
557 return EINVAL; /* XXX */
561 /* System error, obviously. */
565 /* An error code we haven't handled? */
571 * Resolve the entry in servers with index ind, adding connections to the list
572 * *conns. Connections are added for each of socktype1 and (if not zero)
573 * socktype2. message and udpbufp are used to initialize the connections; see
574 * add_connection above. If no addresses are available for an entry but no
575 * internal name resolution failure occurs, return 0 without adding any new
578 static krb5_error_code
579 resolve_server(krb5_context context, const struct serverlist *servers,
580 size_t ind, int socktype1, int socktype2,
581 const krb5_data *message, char **udpbufp,
582 struct conn_state **conns)
584 krb5_error_code retval;
585 struct server_entry *entry = &servers->servers[ind];
586 struct addrinfo *addrs, *a, hint, ai;
590 /* Skip any stray entries of socktypes we don't want. */
591 if (entry->socktype != 0 && entry->socktype != socktype1 &&
592 entry->socktype != socktype2)
595 if (entry->hostname == NULL) {
596 ai.ai_socktype = entry->socktype;
597 ai.ai_family = entry->family;
598 ai.ai_addrlen = entry->addrlen;
599 ai.ai_addr = (struct sockaddr *)&entry->addr;
600 return add_connection(conns, &ai, ind, message, udpbufp);
603 memset(&hint, 0, sizeof(hint));
604 hint.ai_family = entry->family;
605 hint.ai_socktype = (entry->socktype != 0) ? entry->socktype : socktype1;
606 hint.ai_flags = AI_ADDRCONFIG;
607 #ifdef AI_NUMERICSERV
608 hint.ai_flags |= AI_NUMERICSERV;
610 result = snprintf(portbuf, sizeof(portbuf), "%d", ntohs(entry->port));
611 if (SNPRINTF_OVERFLOW(result, sizeof(portbuf)))
613 TRACE_SENDTO_KDC_RESOLVING(context, entry->hostname);
614 err = getaddrinfo(entry->hostname, portbuf, &hint, &addrs);
616 return translate_ai_error(err);
617 /* Add each address with the preferred socktype. */
619 for (a = addrs; a != 0 && retval == 0; a = a->ai_next)
620 retval = add_connection(conns, a, ind, message, udpbufp);
621 if (retval == 0 && entry->socktype == 0 && socktype2 != 0) {
622 /* Add each address again with the non-preferred socktype. */
623 for (a = addrs; a != 0 && retval == 0; a = a->ai_next) {
624 a->ai_socktype = socktype2;
625 retval = add_connection(conns, a, ind, message, udpbufp);
633 start_connection(krb5_context context, struct conn_state *state,
634 struct select_state *selstate,
635 struct sendto_callback_info *callback_info)
638 static const int one = 1;
639 static const struct linger lopt = { 0, 0 };
641 fd = socket(state->addr.family, state->addr.type, 0);
642 if (fd == INVALID_SOCKET)
643 return -1; /* try other hosts */
645 /* Make it non-blocking. */
646 ioctlsocket(fd, FIONBIO, (const void *) &one);
647 if (state->addr.type == SOCK_STREAM) {
648 setsockopt(fd, SOL_SOCKET, SO_LINGER, &lopt, sizeof(lopt));
649 TRACE_SENDTO_KDC_TCP_CONNECT(context, &state->addr);
652 /* Start connecting to KDC. */
653 e = connect(fd, (struct sockaddr *)&state->addr.saddr, state->addr.len);
656 * This is the path that should be followed for non-blocking
659 if (SOCKET_ERRNO == EINPROGRESS || SOCKET_ERRNO == EWOULDBLOCK) {
660 state->state = CONNECTING;
663 (void) closesocket(fd);
664 state->state = FAILED;
669 * Connect returned zero even though we made it non-blocking. This
670 * happens normally for UDP sockets, and can perhaps also happen for
671 * TCP sockets connecting to localhost.
673 state->state = WRITING;
678 * Here's where KPASSWD callback gets the socket information it needs for
683 e = callback_info->pfn_callback(state->fd, callback_info->data,
684 &state->callback_buffer);
686 (void) closesocket(fd);
687 state->fd = INVALID_SOCKET;
688 state->state = FAILED;
692 set_conn_state_msg_length(state, &state->callback_buffer);
695 if (state->addr.type == SOCK_DGRAM) {
698 sg_buf *sg = &state->x.out.sgbuf[0];
700 TRACE_SENDTO_KDC_UDP_SEND_INITIAL(context, &state->addr);
701 ret = send(state->fd, SG_BUF(sg), SG_LEN(sg), 0);
702 if (ret < 0 || (size_t) ret != SG_LEN(sg)) {
703 TRACE_SENDTO_KDC_UDP_ERROR_SEND_INITIAL(context, &state->addr,
705 (void) closesocket(state->fd);
706 state->fd = INVALID_SOCKET;
707 state->state = FAILED;
710 state->state = READING;
714 if (!cm_add_fd(selstate, state->fd)) {
715 (void) closesocket(state->fd);
716 state->fd = INVALID_SOCKET;
717 state->state = FAILED;
720 if (state->state == CONNECTING || state->state == WRITING)
721 cm_write(selstate, state->fd);
723 cm_read(selstate, state->fd);
728 /* Return 0 if we sent something, non-0 otherwise.
729 If 0 is returned, the caller should delay waiting for a response.
730 Otherwise, the caller should immediately move on to process the
733 maybe_send(krb5_context context, struct conn_state *conn,
734 struct select_state *selstate,
735 struct sendto_callback_info *callback_info)
740 if (conn->state == INITIALIZING)
741 return start_connection(context, conn, selstate, callback_info);
743 /* Did we already shut down this channel? */
744 if (conn->state == FAILED) {
748 if (conn->addr.type == SOCK_STREAM) {
749 /* The select callback will handle flushing any data we
750 haven't written yet, and we only write it once. */
754 /* UDP - retransmit after a previous attempt timed out. */
755 sg = &conn->x.out.sgbuf[0];
756 TRACE_SENDTO_KDC_UDP_SEND_RETRY(context, &conn->addr);
757 ret = send(conn->fd, SG_BUF(sg), SG_LEN(sg), 0);
758 if (ret < 0 || (size_t) ret != SG_LEN(sg)) {
759 TRACE_SENDTO_KDC_UDP_ERROR_SEND_RETRY(context, &conn->addr,
761 /* Keep connection alive, we'll try again next pass.
763 Is this likely to catch any errors we didn't get from the
767 /* Yay, it worked. */
772 kill_conn(struct conn_state *conn, struct select_state *selstate)
774 cm_remove_fd(selstate, conn->fd);
775 closesocket(conn->fd);
776 conn->fd = INVALID_SOCKET;
777 conn->state = FAILED;
780 /* Check socket for error. */
785 socklen_t sockerrlen;
788 sockerrlen = sizeof(sockerr);
789 e = getsockopt(fd, SOL_SOCKET, SO_ERROR, &sockerr, &sockerrlen);
791 /* What to do now? */
798 /* Process events on a TCP socket. Return 1 if we get a complete reply. */
800 service_tcp_fd(krb5_context context, struct conn_state *conn,
801 struct select_state *selstate, int ssflags)
804 ssize_t nwritten, nread;
805 SOCKET_WRITEV_TEMP tmp;
807 /* Check for a socket exception. */
808 if (ssflags & SSF_EXCEPTION)
811 switch (conn->state) {
813 /* Check whether the connection succeeded. */
814 e = get_so_error(conn->fd);
816 TRACE_SENDTO_KDC_TCP_ERROR_CONNECT(context, &conn->addr, e);
819 conn->state = WRITING;
821 /* Record this connection's timeout for service_fds. */
822 if (get_curtime_ms(&conn->endtime) == 0)
823 conn->endtime += 10000;
827 TRACE_SENDTO_KDC_TCP_SEND(context, &conn->addr);
828 nwritten = SOCKET_WRITEV(conn->fd, conn->x.out.sgp,
829 conn->x.out.sg_count, tmp);
831 TRACE_SENDTO_KDC_TCP_ERROR_SEND(context, &conn->addr,
836 sg_buf *sgp = conn->x.out.sgp;
837 if ((size_t) nwritten < SG_LEN(sgp)) {
838 SG_ADVANCE(sgp, (size_t) nwritten);
841 nwritten -= SG_LEN(sgp);
843 conn->x.out.sg_count--;
846 if (conn->x.out.sg_count == 0) {
847 /* Done writing, switch to reading. */
848 cm_read(selstate, conn->fd);
849 conn->state = READING;
850 conn->x.in.bufsizebytes_read = 0;
851 conn->x.in.bufsize = 0;
854 conn->x.in.n_left = 0;
859 if (conn->x.in.bufsizebytes_read == 4) {
861 nread = SOCKET_READ(conn->fd, conn->x.in.pos, conn->x.in.n_left);
863 e = nread ? SOCKET_ERRNO : ECONNRESET;
864 TRACE_SENDTO_KDC_TCP_ERROR_RECV(context, &conn->addr, e);
867 conn->x.in.n_left -= nread;
868 conn->x.in.pos += nread;
869 if (conn->x.in.n_left <= 0)
872 /* Reading length. */
873 nread = SOCKET_READ(conn->fd,
874 conn->x.in.bufsizebytes + conn->x.in.bufsizebytes_read,
875 4 - conn->x.in.bufsizebytes_read);
877 e = nread ? SOCKET_ERRNO : ECONNRESET;
878 TRACE_SENDTO_KDC_TCP_ERROR_RECV_LEN(context, &conn->addr, e);
881 conn->x.in.bufsizebytes_read += nread;
882 if (conn->x.in.bufsizebytes_read == 4) {
883 unsigned long len = load_32_be (conn->x.in.bufsizebytes);
884 /* Arbitrary 1M cap. */
885 if (len > 1 * 1024 * 1024)
887 conn->x.in.bufsize = conn->x.in.n_left = len;
888 conn->x.in.buf = conn->x.in.pos = malloc(len);
889 if (conn->x.in.buf == 0)
901 TRACE_SENDTO_KDC_TCP_DISCONNECT(context, &conn->addr);
902 kill_conn(conn, selstate);
906 /* Process events on a UDP socket. Return 1 if we get a reply. */
908 service_udp_fd(krb5_context context, struct conn_state *conn,
909 struct select_state *selstate, int ssflags)
913 if (!(ssflags & (SSF_READ|SSF_EXCEPTION)))
915 if (conn->state != READING)
918 nread = recv(conn->fd, conn->x.in.buf, conn->x.in.bufsize, 0);
920 TRACE_SENDTO_KDC_UDP_ERROR_RECV(context, &conn->addr, SOCKET_ERRNO);
921 kill_conn(conn, selstate);
924 conn->x.in.pos = conn->x.in.buf + nread;
928 /* Return the maximum of endtime and the endtime fields of all currently active
929 * TCP connections. */
931 get_endtime(time_ms endtime, struct conn_state *conns)
933 struct conn_state *state;
935 for (state = conns; state != NULL; state = state->next) {
936 if (state->addr.type == SOCK_STREAM &&
937 (state->state == READING || state->state == WRITING) &&
938 state->endtime > endtime)
939 endtime = state->endtime;
945 service_fds(krb5_context context, struct select_state *selstate,
946 time_ms interval, struct conn_state *conns,
947 struct select_state *seltemp,
948 int (*msg_handler)(krb5_context, const krb5_data *, void *),
949 void *msg_handler_data, struct conn_state **winner_out)
953 struct conn_state *state;
957 e = get_curtime_ms(&endtime);
963 while (selstate->nfds > 0) {
964 e = cm_select_or_poll(selstate, get_endtime(endtime, conns),
972 /* Timeout, return to caller. */
975 /* Got something on a socket, process it. */
976 for (state = conns; state != NULL; state = state->next) {
979 if (state->fd == INVALID_SOCKET)
981 ssflags = cm_get_ssflags(seltemp, state->fd);
985 if (state->service(context, state, selstate, ssflags)) {
988 if (msg_handler != NULL) {
991 reply.data = state->x.in.buf;
992 reply.length = state->x.in.pos - state->x.in.buf;
994 stop = (msg_handler(context, &reply, msg_handler_data) != 0);
1010 * Current worst-case timeout behavior:
1012 * First pass, 1s per udp or tcp server, plus 2s at end.
1013 * Second pass, 1s per udp server, plus 4s.
1014 * Third pass, 1s per udp server, plus 8s.
1015 * Fourth => 16s, etc.
1018 * Per UDP server, 1s per pass.
1019 * Per TCP server, 1s.
1020 * Backoff delay, 2**(P+1) - 2, where P is total number of passes.
1022 * Total = 2**(P+1) + U*P + T - 2.
1024 * If P=3, Total = 3*U + T + 14.
1025 * If P=4, Total = 4*U + T + 30.
1027 * Note that if you try to reach two ports (e.g., both 88 and 750) on
1028 * one server, it counts as two.
1030 * There is one exception to the above rules. Whenever a TCP connection is
1031 * established, we wait up to ten seconds for it to finish or fail before
1032 * moving on. This reduces network traffic significantly in a TCP environment.
1036 k5_sendto(krb5_context context, const krb5_data *message,
1037 const struct serverlist *servers, int socktype1, int socktype2,
1038 struct sendto_callback_info* callback_info, krb5_data *reply,
1039 struct sockaddr *remoteaddr, socklen_t *remoteaddrlen,
1041 /* return 0 -> keep going, 1 -> quit */
1042 int (*msg_handler)(krb5_context, const krb5_data *, void *),
1043 void *msg_handler_data)
1047 krb5_error_code retval;
1048 struct conn_state *conns = NULL, *state, **tailptr, *next, *winner;
1050 struct select_state *sel_state = NULL, *seltemp;
1051 char *udpbuf = NULL;
1052 krb5_boolean done = FALSE;
1057 /* One for use here, listing all our fds in use, and one for
1058 * temporary use in service_fds, for the fds of interest. */
1059 sel_state = malloc(2 * sizeof(*sel_state));
1060 if (sel_state == NULL) {
1064 seltemp = &sel_state[1];
1065 cm_init_selstate(sel_state);
1067 /* First pass: resolve server hosts, communicate with resulting addresses
1068 * of the preferred socktype, and wait 1s for an answer from each. */
1069 for (s = 0; s < servers->nservers && !done; s++) {
1070 /* Find the current tail pointer. */
1071 for (tailptr = &conns; *tailptr != NULL; tailptr = &(*tailptr)->next);
1072 retval = resolve_server(context, servers, s, socktype1, socktype2,
1073 message, &udpbuf, &conns);
1076 for (state = *tailptr; state != NULL && !done; state = state->next) {
1077 /* Contact each new connection whose socktype matches socktype1. */
1078 if (state->addr.type != socktype1)
1080 if (maybe_send(context, state, sel_state, callback_info))
1082 done = service_fds(context, sel_state, 1000, conns, seltemp,
1083 msg_handler, msg_handler_data, &winner);
1087 /* Complete the first pass by contacting servers of the non-preferred
1088 * socktype (if given), waiting 1s for an answer from each. */
1089 for (state = conns; state != NULL && !done; state = state->next) {
1090 if (state->addr.type != socktype2)
1092 if (maybe_send(context, state, sel_state, callback_info))
1094 done = service_fds(context, sel_state, 1000, conns, seltemp,
1095 msg_handler, msg_handler_data, &winner);
1098 /* Wait for two seconds at the end of the first pass. */
1100 done = service_fds(context, sel_state, 2000, conns, seltemp,
1101 msg_handler, msg_handler_data, &winner);
1104 /* Make remaining passes over all of the connections. */
1106 for (pass = 1; pass < MAX_PASS && !done; pass++) {
1107 for (state = conns; state != NULL && !done; state = state->next) {
1108 if (maybe_send(context, state, sel_state, callback_info))
1110 done = service_fds(context, sel_state, 1000, conns, seltemp,
1111 msg_handler, msg_handler_data, &winner);
1112 if (sel_state->nfds == 0)
1115 /* Wait for the delay backoff at the end of this pass. */
1117 done = service_fds(context, sel_state, delay, conns, seltemp,
1118 msg_handler, msg_handler_data, &winner);
1120 if (sel_state->nfds == 0)
1125 if (sel_state->nfds == 0 || !done || winner == NULL) {
1126 retval = KRB5_KDC_UNREACH;
1130 reply->data = winner->x.in.buf;
1131 reply->length = winner->x.in.pos - winner->x.in.buf;
1133 winner->x.in.buf = NULL;
1134 if (server_used != NULL)
1135 *server_used = winner->server_index;
1136 if (remoteaddr != NULL && remoteaddrlen != 0 && *remoteaddrlen > 0)
1137 (void)getpeername(winner->fd, remoteaddr, remoteaddrlen);
1138 TRACE_SENDTO_KDC_RESPONSE(context, reply->length, &winner->addr);
1141 for (state = conns; state != NULL; state = next) {
1143 if (state->fd != INVALID_SOCKET)
1144 closesocket(state->fd);
1145 if (state->state == READING && state->x.in.buf != udpbuf)
1146 free(state->x.in.buf);
1147 if (callback_info) {
1148 callback_info->pfn_cleanup(callback_info->data,
1149 &state->callback_buffer);
1154 if (reply->data != udpbuf)