1 /* $NetBSD: connect.c,v 1.1.1.2 2014/04/24 12:45:27 pettai Exp $ */ 2 3 /* 4 * Copyright (c) 1997-2005 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include "kdc_locl.h" 37 38 /* Should we enable the HTTP hack? */ 39 int enable_http = -1; 40 41 /* Log over requests to the KDC */ 42 const char *request_log; 43 44 /* A string describing on what ports to listen */ 45 const char *port_str; 46 47 krb5_addresses explicit_addresses; 48 49 size_t max_request_udp; 50 size_t max_request_tcp; 51 52 /* 53 * a tuple describing on what to listen 54 */ 55 56 struct port_desc{ 57 int family; 58 int type; 59 int port; 60 }; 61 62 /* the current ones */ 63 64 static struct port_desc *ports; 65 static size_t num_ports; 66 67 /* 68 * add `family, port, protocol' to the list with duplicate suppresion. 69 */ 70 71 static void 72 add_port(krb5_context context, 73 int family, int port, const char *protocol) 74 { 75 int type; 76 size_t i; 77 78 if(strcmp(protocol, "udp") == 0) 79 type = SOCK_DGRAM; 80 else if(strcmp(protocol, "tcp") == 0) 81 type = SOCK_STREAM; 82 else 83 return; 84 for(i = 0; i < num_ports; i++){ 85 if(ports[i].type == type 86 && ports[i].port == port 87 && ports[i].family == family) 88 return; 89 } 90 ports = realloc(ports, (num_ports + 1) * sizeof(*ports)); 91 if (ports == NULL) 92 krb5_err (context, 1, errno, "realloc"); 93 ports[num_ports].family = family; 94 ports[num_ports].type = type; 95 ports[num_ports].port = port; 96 num_ports++; 97 } 98 99 /* 100 * add a triple but with service -> port lookup 101 * (this prints warnings for stuff that does not exist) 102 */ 103 104 static void 105 add_port_service(krb5_context context, 106 int family, const char *service, int port, 107 const char *protocol) 108 { 109 port = krb5_getportbyname (context, service, protocol, port); 110 add_port (context, family, port, protocol); 111 } 112 113 /* 114 * add the port with service -> port lookup or string -> number 115 * (no warning is printed) 116 */ 117 118 static void 119 add_port_string (krb5_context context, 120 int family, const char *str, const char *protocol) 121 { 122 struct servent *sp; 123 int port; 124 125 sp = roken_getservbyname (str, protocol); 126 if (sp != NULL) { 127 port = sp->s_port; 128 } else { 129 char *end; 130 131 port = htons(strtol(str, &end, 0)); 132 if (end == str) 133 return; 134 } 135 add_port (context, family, port, protocol); 136 } 137 138 /* 139 * add the standard collection of ports for `family' 140 */ 141 142 static void 143 add_standard_ports (krb5_context context, 144 krb5_kdc_configuration *config, 145 int family) 146 { 147 add_port_service(context, family, "kerberos", 88, "udp"); 148 add_port_service(context, family, "kerberos", 88, "tcp"); 149 add_port_service(context, family, "kerberos-sec", 88, "udp"); 150 add_port_service(context, family, "kerberos-sec", 88, "tcp"); 151 if(enable_http) 152 add_port_service(context, family, "http", 80, "tcp"); 153 if(config->enable_kx509) { 154 add_port_service(context, family, "kca_service", 9878, "udp"); 155 add_port_service(context, family, "kca_service", 9878, "tcp"); 156 } 157 158 } 159 160 /* 161 * parse the set of space-delimited ports in `str' and add them. 162 * "+" => all the standard ones 163 * otherwise it's port|service[/protocol] 164 */ 165 166 static void 167 parse_ports(krb5_context context, 168 krb5_kdc_configuration *config, 169 const char *str) 170 { 171 char *pos = NULL; 172 char *p; 173 char *str_copy = strdup (str); 174 175 p = strtok_r(str_copy, " \t", &pos); 176 while(p != NULL) { 177 if(strcmp(p, "+") == 0) { 178 #ifdef HAVE_IPV6 179 add_standard_ports(context, config, AF_INET6); 180 #endif 181 add_standard_ports(context, config, AF_INET); 182 } else { 183 char *q = strchr(p, '/'); 184 if(q){ 185 *q++ = 0; 186 #ifdef HAVE_IPV6 187 add_port_string(context, AF_INET6, p, q); 188 #endif 189 add_port_string(context, AF_INET, p, q); 190 }else { 191 #ifdef HAVE_IPV6 192 add_port_string(context, AF_INET6, p, "udp"); 193 add_port_string(context, AF_INET6, p, "tcp"); 194 #endif 195 add_port_string(context, AF_INET, p, "udp"); 196 add_port_string(context, AF_INET, p, "tcp"); 197 } 198 } 199 200 p = strtok_r(NULL, " \t", &pos); 201 } 202 free (str_copy); 203 } 204 205 /* 206 * every socket we listen on 207 */ 208 209 struct descr { 210 krb5_socket_t s; 211 int type; 212 int port; 213 unsigned char *buf; 214 size_t size; 215 size_t len; 216 time_t timeout; 217 struct sockaddr_storage __ss; 218 struct sockaddr *sa; 219 socklen_t sock_len; 220 char addr_string[128]; 221 }; 222 223 static void 224 init_descr(struct descr *d) 225 { 226 memset(d, 0, sizeof(*d)); 227 d->sa = (struct sockaddr *)&d->__ss; 228 d->s = rk_INVALID_SOCKET; 229 } 230 231 /* 232 * re-initialize all `n' ->sa in `d'. 233 */ 234 235 static void 236 reinit_descrs (struct descr *d, int n) 237 { 238 int i; 239 240 for (i = 0; i < n; ++i) 241 d[i].sa = (struct sockaddr *)&d[i].__ss; 242 } 243 244 /* 245 * Create the socket (family, type, port) in `d' 246 */ 247 248 static void 249 init_socket(krb5_context context, 250 krb5_kdc_configuration *config, 251 struct descr *d, krb5_address *a, int family, int type, int port) 252 { 253 krb5_error_code ret; 254 struct sockaddr_storage __ss; 255 struct sockaddr *sa = (struct sockaddr *)&__ss; 256 krb5_socklen_t sa_size = sizeof(__ss); 257 258 init_descr (d); 259 260 ret = krb5_addr2sockaddr (context, a, sa, &sa_size, port); 261 if (ret) { 262 krb5_warn(context, ret, "krb5_addr2sockaddr"); 263 rk_closesocket(d->s); 264 d->s = rk_INVALID_SOCKET; 265 return; 266 } 267 268 if (sa->sa_family != family) 269 return; 270 271 d->s = socket(family, type, 0); 272 if(rk_IS_BAD_SOCKET(d->s)){ 273 krb5_warn(context, errno, "socket(%d, %d, 0)", family, type); 274 d->s = rk_INVALID_SOCKET; 275 return; 276 } 277 #if defined(HAVE_SETSOCKOPT) && defined(SOL_SOCKET) && defined(SO_REUSEADDR) 278 { 279 int one = 1; 280 setsockopt(d->s, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one)); 281 } 282 #endif 283 d->type = type; 284 d->port = port; 285 286 if(rk_IS_SOCKET_ERROR(bind(d->s, sa, sa_size))){ 287 char a_str[256]; 288 size_t len; 289 290 krb5_print_address (a, a_str, sizeof(a_str), &len); 291 krb5_warn(context, errno, "bind %s/%d", a_str, ntohs(port)); 292 rk_closesocket(d->s); 293 d->s = rk_INVALID_SOCKET; 294 return; 295 } 296 if(type == SOCK_STREAM && rk_IS_SOCKET_ERROR(listen(d->s, SOMAXCONN))){ 297 char a_str[256]; 298 size_t len; 299 300 krb5_print_address (a, a_str, sizeof(a_str), &len); 301 krb5_warn(context, errno, "listen %s/%d", a_str, ntohs(port)); 302 rk_closesocket(d->s); 303 d->s = rk_INVALID_SOCKET; 304 return; 305 } 306 } 307 308 /* 309 * Allocate descriptors for all the sockets that we should listen on 310 * and return the number of them. 311 */ 312 313 static int 314 init_sockets(krb5_context context, 315 krb5_kdc_configuration *config, 316 struct descr **desc) 317 { 318 krb5_error_code ret; 319 size_t i, j; 320 struct descr *d; 321 int num = 0; 322 krb5_addresses addresses; 323 324 if (explicit_addresses.len) { 325 addresses = explicit_addresses; 326 } else { 327 ret = krb5_get_all_server_addrs (context, &addresses); 328 if (ret) 329 krb5_err (context, 1, ret, "krb5_get_all_server_addrs"); 330 } 331 parse_ports(context, config, port_str); 332 d = malloc(addresses.len * num_ports * sizeof(*d)); 333 if (d == NULL) 334 krb5_errx(context, 1, "malloc(%lu) failed", 335 (unsigned long)num_ports * sizeof(*d)); 336 337 for (i = 0; i < num_ports; i++){ 338 for (j = 0; j < addresses.len; ++j) { 339 init_socket(context, config, &d[num], &addresses.val[j], 340 ports[i].family, ports[i].type, ports[i].port); 341 if(d[num].s != rk_INVALID_SOCKET){ 342 char a_str[80]; 343 size_t len; 344 345 krb5_print_address (&addresses.val[j], a_str, 346 sizeof(a_str), &len); 347 348 kdc_log(context, config, 5, "listening on %s port %u/%s", 349 a_str, 350 ntohs(ports[i].port), 351 (ports[i].type == SOCK_STREAM) ? "tcp" : "udp"); 352 /* XXX */ 353 num++; 354 } 355 } 356 } 357 krb5_free_addresses (context, &addresses); 358 d = realloc(d, num * sizeof(*d)); 359 if (d == NULL && num != 0) 360 krb5_errx(context, 1, "realloc(%lu) failed", 361 (unsigned long)num * sizeof(*d)); 362 reinit_descrs (d, num); 363 *desc = d; 364 return num; 365 } 366 367 /* 368 * 369 */ 370 371 static const char * 372 descr_type(struct descr *d) 373 { 374 if (d->type == SOCK_DGRAM) 375 return "udp"; 376 else if (d->type == SOCK_STREAM) 377 return "tcp"; 378 return "unknown"; 379 } 380 381 static void 382 addr_to_string(krb5_context context, 383 struct sockaddr *addr, size_t addr_len, char *str, size_t len) 384 { 385 krb5_address a; 386 if(krb5_sockaddr2address(context, addr, &a) == 0) { 387 if(krb5_print_address(&a, str, len, &len) == 0) { 388 krb5_free_address(context, &a); 389 return; 390 } 391 krb5_free_address(context, &a); 392 } 393 snprintf(str, len, "<family=%d>", addr->sa_family); 394 } 395 396 /* 397 * 398 */ 399 400 static void 401 send_reply(krb5_context context, 402 krb5_kdc_configuration *config, 403 krb5_boolean prependlength, 404 struct descr *d, 405 krb5_data *reply) 406 { 407 kdc_log(context, config, 5, 408 "sending %lu bytes to %s", (unsigned long)reply->length, 409 d->addr_string); 410 if(prependlength){ 411 unsigned char l[4]; 412 l[0] = (reply->length >> 24) & 0xff; 413 l[1] = (reply->length >> 16) & 0xff; 414 l[2] = (reply->length >> 8) & 0xff; 415 l[3] = reply->length & 0xff; 416 if(rk_IS_SOCKET_ERROR(sendto(d->s, l, sizeof(l), 0, d->sa, d->sock_len))) { 417 kdc_log (context, config, 418 0, "sendto(%s): %s", d->addr_string, 419 strerror(rk_SOCK_ERRNO)); 420 return; 421 } 422 } 423 if(rk_IS_SOCKET_ERROR(sendto(d->s, reply->data, reply->length, 0, d->sa, d->sock_len))) { 424 kdc_log (context, config, 0, "sendto(%s): %s", d->addr_string, 425 strerror(rk_SOCK_ERRNO)); 426 return; 427 } 428 } 429 430 /* 431 * Handle the request in `buf, len' to socket `d' 432 */ 433 434 static void 435 do_request(krb5_context context, 436 krb5_kdc_configuration *config, 437 void *buf, size_t len, krb5_boolean prependlength, 438 struct descr *d) 439 { 440 krb5_error_code ret; 441 krb5_data reply; 442 int datagram_reply = (d->type == SOCK_DGRAM); 443 444 krb5_kdc_update_time(NULL); 445 446 krb5_data_zero(&reply); 447 ret = krb5_kdc_process_request(context, config, 448 buf, len, &reply, &prependlength, 449 d->addr_string, d->sa, 450 datagram_reply); 451 if(request_log) 452 krb5_kdc_save_request(context, request_log, buf, len, &reply, d->sa); 453 if(reply.length){ 454 send_reply(context, config, prependlength, d, &reply); 455 krb5_data_free(&reply); 456 } 457 if(ret) 458 kdc_log(context, config, 0, 459 "Failed processing %lu byte request from %s", 460 (unsigned long)len, d->addr_string); 461 } 462 463 /* 464 * Handle incoming data to the UDP socket in `d' 465 */ 466 467 static void 468 handle_udp(krb5_context context, 469 krb5_kdc_configuration *config, 470 struct descr *d) 471 { 472 unsigned char *buf; 473 ssize_t n; 474 475 buf = malloc(max_request_udp); 476 if(buf == NULL){ 477 kdc_log(context, config, 0, "Failed to allocate %lu bytes", (unsigned long)max_request_udp); 478 return; 479 } 480 481 d->sock_len = sizeof(d->__ss); 482 n = recvfrom(d->s, buf, max_request_udp, 0, d->sa, &d->sock_len); 483 if(rk_IS_SOCKET_ERROR(n)) 484 krb5_warn(context, rk_SOCK_ERRNO, "recvfrom"); 485 else { 486 addr_to_string (context, d->sa, d->sock_len, 487 d->addr_string, sizeof(d->addr_string)); 488 if ((size_t)n == max_request_udp) { 489 krb5_data data; 490 krb5_warn(context, errno, 491 "recvfrom: truncated packet from %s, asking for TCP", 492 d->addr_string); 493 krb5_mk_error(context, 494 KRB5KRB_ERR_RESPONSE_TOO_BIG, 495 NULL, 496 NULL, 497 NULL, 498 NULL, 499 NULL, 500 NULL, 501 &data); 502 send_reply(context, config, FALSE, d, &data); 503 krb5_data_free(&data); 504 } else { 505 do_request(context, config, buf, n, FALSE, d); 506 } 507 } 508 free (buf); 509 } 510 511 static void 512 clear_descr(struct descr *d) 513 { 514 if(d->buf) 515 memset(d->buf, 0, d->size); 516 d->len = 0; 517 if(d->s != rk_INVALID_SOCKET) 518 rk_closesocket(d->s); 519 d->s = rk_INVALID_SOCKET; 520 } 521 522 523 /* remove HTTP %-quoting from buf */ 524 static int 525 de_http(char *buf) 526 { 527 unsigned char *p, *q; 528 for(p = q = (unsigned char *)buf; *p; p++, q++) { 529 if(*p == '%' && isxdigit(p[1]) && isxdigit(p[2])) { 530 unsigned int x; 531 if(sscanf((char *)p + 1, "%2x", &x) != 1) 532 return -1; 533 *q = x; 534 p += 2; 535 } else 536 *q = *p; 537 } 538 *q = '\0'; 539 return 0; 540 } 541 542 #define TCP_TIMEOUT 4 543 544 /* 545 * accept a new TCP connection on `d[parent]' and store it in `d[child]' 546 */ 547 548 static void 549 add_new_tcp (krb5_context context, 550 krb5_kdc_configuration *config, 551 struct descr *d, int parent, int child) 552 { 553 krb5_socket_t s; 554 555 if (child == -1) 556 return; 557 558 d[child].sock_len = sizeof(d[child].__ss); 559 s = accept(d[parent].s, d[child].sa, &d[child].sock_len); 560 if(rk_IS_BAD_SOCKET(s)) { 561 krb5_warn(context, rk_SOCK_ERRNO, "accept"); 562 return; 563 } 564 565 #ifdef FD_SETSIZE 566 if (s >= FD_SETSIZE) { 567 krb5_warnx(context, "socket FD too large"); 568 rk_closesocket (s); 569 return; 570 } 571 #endif 572 573 d[child].s = s; 574 d[child].timeout = time(NULL) + TCP_TIMEOUT; 575 d[child].type = SOCK_STREAM; 576 addr_to_string (context, 577 d[child].sa, d[child].sock_len, 578 d[child].addr_string, sizeof(d[child].addr_string)); 579 } 580 581 /* 582 * Grow `d' to handle at least `n'. 583 * Return != 0 if fails 584 */ 585 586 static int 587 grow_descr (krb5_context context, 588 krb5_kdc_configuration *config, 589 struct descr *d, size_t n) 590 { 591 if (d->size - d->len < n) { 592 unsigned char *tmp; 593 size_t grow; 594 595 grow = max(1024, d->len + n); 596 if (d->size + grow > max_request_tcp) { 597 kdc_log(context, config, 0, "Request exceeds max request size (%lu bytes).", 598 (unsigned long)d->size + grow); 599 clear_descr(d); 600 return -1; 601 } 602 tmp = realloc (d->buf, d->size + grow); 603 if (tmp == NULL) { 604 kdc_log(context, config, 0, "Failed to re-allocate %lu bytes.", 605 (unsigned long)d->size + grow); 606 clear_descr(d); 607 return -1; 608 } 609 d->size += grow; 610 d->buf = tmp; 611 } 612 return 0; 613 } 614 615 /* 616 * Try to handle the TCP data at `d->buf, d->len'. 617 * Return -1 if failed, 0 if succesful, and 1 if data is complete. 618 */ 619 620 static int 621 handle_vanilla_tcp (krb5_context context, 622 krb5_kdc_configuration *config, 623 struct descr *d) 624 { 625 krb5_storage *sp; 626 uint32_t len; 627 628 sp = krb5_storage_from_mem(d->buf, d->len); 629 if (sp == NULL) { 630 kdc_log (context, config, 0, "krb5_storage_from_mem failed"); 631 return -1; 632 } 633 krb5_ret_uint32(sp, &len); 634 krb5_storage_free(sp); 635 if(d->len - 4 >= len) { 636 memmove(d->buf, d->buf + 4, d->len - 4); 637 d->len -= 4; 638 return 1; 639 } 640 return 0; 641 } 642 643 /* 644 * Try to handle the TCP/HTTP data at `d->buf, d->len'. 645 * Return -1 if failed, 0 if succesful, and 1 if data is complete. 646 */ 647 648 static int 649 handle_http_tcp (krb5_context context, 650 krb5_kdc_configuration *config, 651 struct descr *d) 652 { 653 char *s, *p, *t; 654 void *data; 655 char *proto; 656 int len; 657 658 s = (char *)d->buf; 659 660 /* If its a multi line query, truncate off the first line */ 661 p = strstr(s, "\r\n"); 662 if (p) 663 *p = 0; 664 665 p = NULL; 666 t = strtok_r(s, " \t", &p); 667 if (t == NULL) { 668 kdc_log(context, config, 0, 669 "Missing HTTP operand (GET) request from %s", d->addr_string); 670 return -1; 671 } 672 673 t = strtok_r(NULL, " \t", &p); 674 if(t == NULL) { 675 kdc_log(context, config, 0, 676 "Missing HTTP GET data in request from %s", d->addr_string); 677 return -1; 678 } 679 680 data = malloc(strlen(t)); 681 if (data == NULL) { 682 kdc_log(context, config, 0, "Failed to allocate %lu bytes", 683 (unsigned long)strlen(t)); 684 return -1; 685 } 686 if(*t == '/') 687 t++; 688 if(de_http(t) != 0) { 689 kdc_log(context, config, 0, "Malformed HTTP request from %s", d->addr_string); 690 kdc_log(context, config, 5, "HTTP request: %s", t); 691 free(data); 692 return -1; 693 } 694 proto = strtok_r(NULL, " \t", &p); 695 if (proto == NULL) { 696 kdc_log(context, config, 0, "Malformed HTTP request from %s", d->addr_string); 697 free(data); 698 return -1; 699 } 700 len = base64_decode(t, data); 701 if(len <= 0){ 702 const char *msg = 703 " 404 Not found\r\n" 704 "Server: Heimdal/" VERSION "\r\n" 705 "Cache-Control: no-cache\r\n" 706 "Pragma: no-cache\r\n" 707 "Content-type: text/html\r\n" 708 "Content-transfer-encoding: 8bit\r\n\r\n" 709 "<TITLE>404 Not found</TITLE>\r\n" 710 "<H1>404 Not found</H1>\r\n" 711 "That page doesn't exist, maybe you are looking for " 712 "<A HREF=\"http://www.h5l.org/\">Heimdal</A>?\r\n"; 713 kdc_log(context, config, 0, "HTTP request from %s is non KDC request", d->addr_string); 714 kdc_log(context, config, 5, "HTTP request: %s", t); 715 free(data); 716 if (rk_IS_SOCKET_ERROR(send(d->s, proto, strlen(proto), 0))) { 717 kdc_log(context, config, 0, "HTTP write failed: %s: %s", 718 d->addr_string, strerror(rk_SOCK_ERRNO)); 719 return -1; 720 } 721 if (rk_IS_SOCKET_ERROR(send(d->s, msg, strlen(msg), 0))) { 722 kdc_log(context, config, 0, "HTTP write failed: %s: %s", 723 d->addr_string, strerror(rk_SOCK_ERRNO)); 724 return -1; 725 } 726 return -1; 727 } 728 { 729 const char *msg = 730 " 200 OK\r\n" 731 "Server: Heimdal/" VERSION "\r\n" 732 "Cache-Control: no-cache\r\n" 733 "Pragma: no-cache\r\n" 734 "Content-type: application/octet-stream\r\n" 735 "Content-transfer-encoding: binary\r\n\r\n"; 736 if (rk_IS_SOCKET_ERROR(send(d->s, proto, strlen(proto), 0))) { 737 free(data); 738 kdc_log(context, config, 0, "HTTP write failed: %s: %s", 739 d->addr_string, strerror(rk_SOCK_ERRNO)); 740 return -1; 741 } 742 if (rk_IS_SOCKET_ERROR(send(d->s, msg, strlen(msg), 0))) { 743 free(data); 744 kdc_log(context, config, 0, "HTTP write failed: %s: %s", 745 d->addr_string, strerror(rk_SOCK_ERRNO)); 746 return -1; 747 } 748 } 749 if ((size_t)len > d->len) 750 len = d->len; 751 memcpy(d->buf, data, len); 752 d->len = len; 753 free(data); 754 return 1; 755 } 756 757 /* 758 * Handle incoming data to the TCP socket in `d[index]' 759 */ 760 761 static void 762 handle_tcp(krb5_context context, 763 krb5_kdc_configuration *config, 764 struct descr *d, int idx, int min_free) 765 { 766 unsigned char buf[1024]; 767 int n; 768 int ret = 0; 769 770 if (d[idx].timeout == 0) { 771 add_new_tcp (context, config, d, idx, min_free); 772 return; 773 } 774 775 n = recvfrom(d[idx].s, buf, sizeof(buf), 0, NULL, NULL); 776 if(rk_IS_SOCKET_ERROR(n)){ 777 krb5_warn(context, rk_SOCK_ERRNO, "recvfrom failed from %s to %s/%d", 778 d[idx].addr_string, descr_type(d + idx), 779 ntohs(d[idx].port)); 780 return; 781 } else if (n == 0) { 782 krb5_warnx(context, "connection closed before end of data after %lu " 783 "bytes from %s to %s/%d", (unsigned long)d[idx].len, 784 d[idx].addr_string, descr_type(d + idx), 785 ntohs(d[idx].port)); 786 clear_descr (d + idx); 787 return; 788 } 789 if (grow_descr (context, config, &d[idx], n)) 790 return; 791 memcpy(d[idx].buf + d[idx].len, buf, n); 792 d[idx].len += n; 793 if(d[idx].len > 4 && d[idx].buf[0] == 0) { 794 ret = handle_vanilla_tcp (context, config, &d[idx]); 795 } else if(enable_http && 796 d[idx].len >= 4 && 797 strncmp((char *)d[idx].buf, "GET ", 4) == 0 && 798 strncmp((char *)d[idx].buf + d[idx].len - 4, 799 "\r\n\r\n", 4) == 0) { 800 801 /* remove the trailing \r\n\r\n so the string is NUL terminated */ 802 d[idx].buf[d[idx].len - 4] = '\0'; 803 804 ret = handle_http_tcp (context, config, &d[idx]); 805 if (ret < 0) 806 clear_descr (d + idx); 807 } else if (d[idx].len > 4) { 808 kdc_log (context, config, 809 0, "TCP data of strange type from %s to %s/%d", 810 d[idx].addr_string, descr_type(d + idx), 811 ntohs(d[idx].port)); 812 if (d[idx].buf[0] & 0x80) { 813 krb5_data reply; 814 815 kdc_log (context, config, 0, "TCP extension not supported"); 816 817 ret = krb5_mk_error(context, 818 KRB5KRB_ERR_FIELD_TOOLONG, 819 NULL, 820 NULL, 821 NULL, 822 NULL, 823 NULL, 824 NULL, 825 &reply); 826 if (ret == 0) { 827 send_reply(context, config, TRUE, d + idx, &reply); 828 krb5_data_free(&reply); 829 } 830 } 831 clear_descr(d + idx); 832 return; 833 } 834 if (ret < 0) 835 return; 836 else if (ret == 1) { 837 do_request(context, config, 838 d[idx].buf, d[idx].len, TRUE, &d[idx]); 839 clear_descr(d + idx); 840 } 841 } 842 843 krb5_boolean 844 realloc_descrs(struct descr **d, unsigned int *ndescr) 845 { 846 struct descr *tmp; 847 size_t i; 848 849 tmp = realloc(*d, (*ndescr + 4) * sizeof(**d)); 850 if(tmp == NULL) 851 return FALSE; 852 853 *d = tmp; 854 reinit_descrs (*d, *ndescr); 855 memset(*d + *ndescr, 0, 4 * sizeof(**d)); 856 for(i = *ndescr; i < *ndescr + 4; i++) 857 init_descr (*d + i); 858 859 *ndescr += 4; 860 861 return TRUE; 862 } 863 864 int 865 next_min_free(krb5_context context, struct descr **d, unsigned int *ndescr) 866 { 867 size_t i; 868 int min_free; 869 870 for(i = 0; i < *ndescr; i++) { 871 int s = (*d + i)->s; 872 if(rk_IS_BAD_SOCKET(s)) 873 return i; 874 } 875 876 min_free = *ndescr; 877 if(!realloc_descrs(d, ndescr)) { 878 min_free = -1; 879 krb5_warnx(context, "No memory"); 880 } 881 882 return min_free; 883 } 884 885 void 886 loop(krb5_context context, 887 krb5_kdc_configuration *config) 888 { 889 struct descr *d; 890 unsigned int ndescr; 891 892 ndescr = init_sockets(context, config, &d); 893 if(ndescr <= 0) 894 krb5_errx(context, 1, "No sockets!"); 895 kdc_log(context, config, 0, "KDC started"); 896 while(exit_flag == 0){ 897 struct timeval tmout; 898 fd_set fds; 899 int min_free = -1; 900 int max_fd = 0; 901 size_t i; 902 903 FD_ZERO(&fds); 904 for(i = 0; i < ndescr; i++) { 905 if(!rk_IS_BAD_SOCKET(d[i].s)){ 906 if(d[i].type == SOCK_STREAM && 907 d[i].timeout && d[i].timeout < time(NULL)) { 908 kdc_log(context, config, 1, 909 "TCP-connection from %s expired after %lu bytes", 910 d[i].addr_string, (unsigned long)d[i].len); 911 clear_descr(&d[i]); 912 continue; 913 } 914 #ifndef NO_LIMIT_FD_SETSIZE 915 if(max_fd < d[i].s) 916 max_fd = d[i].s; 917 #ifdef FD_SETSIZE 918 if (max_fd >= FD_SETSIZE) 919 krb5_errx(context, 1, "fd too large"); 920 #endif 921 #endif 922 FD_SET(d[i].s, &fds); 923 } 924 } 925 926 tmout.tv_sec = TCP_TIMEOUT; 927 tmout.tv_usec = 0; 928 switch(select(max_fd + 1, &fds, 0, 0, &tmout)){ 929 case 0: 930 break; 931 case -1: 932 if (errno != EINTR) 933 krb5_warn(context, rk_SOCK_ERRNO, "select"); 934 break; 935 default: 936 for(i = 0; i < ndescr; i++) 937 if(!rk_IS_BAD_SOCKET(d[i].s) && FD_ISSET(d[i].s, &fds)) { 938 min_free = next_min_free(context, &d, &ndescr); 939 940 if(d[i].type == SOCK_DGRAM) 941 handle_udp(context, config, &d[i]); 942 else if(d[i].type == SOCK_STREAM) 943 handle_tcp(context, config, d, i, min_free); 944 } 945 } 946 } 947 if (0); 948 #ifdef SIGXCPU 949 else if(exit_flag == SIGXCPU) 950 kdc_log(context, config, 0, "CPU time limit exceeded"); 951 #endif 952 else if(exit_flag == SIGINT || exit_flag == SIGTERM) 953 kdc_log(context, config, 0, "Terminated"); 954 else 955 kdc_log(context, config, 0, "Unexpected exit reason: %d", exit_flag); 956 free (d); 957 } 958