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