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