1 /* 2 * Copyright (c) 1997 - 2003 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "rsh_locl.h" 35 RCSID("$Id: rsh.c,v 1.71 2003/04/16 20:37:20 joda Exp $"); 36 37 enum auth_method auth_method; 38 #if defined(KRB4) || defined(KRB5) 39 int do_encrypt = -1; 40 #endif 41 #ifdef KRB5 42 int do_unique_tkfile = 0; 43 char *unique_tkfile = NULL; 44 char tkfile[MAXPATHLEN]; 45 int do_forward = -1; 46 int do_forwardable = -1; 47 krb5_context context; 48 krb5_keyblock *keyblock; 49 krb5_crypto crypto; 50 #endif 51 #ifdef KRB4 52 des_key_schedule schedule; 53 des_cblock iv; 54 #endif 55 int sock_debug = 0; 56 57 #ifdef KRB4 58 static int use_v4 = -1; 59 #endif 60 #ifdef KRB5 61 static int use_v5 = -1; 62 #endif 63 static int use_only_broken = 0; 64 static int use_broken = 1; 65 static char *port_str; 66 static const char *user; 67 static int do_version; 68 static int do_help; 69 static int do_errsock = 1; 70 static char *protocol_version_str; 71 static int protocol_version = 2; 72 73 /* 74 * 75 */ 76 77 static int input = 1; /* Read from stdin */ 78 79 static int 80 loop (int s, int errsock) 81 { 82 fd_set real_readset; 83 int count = 1; 84 85 #ifdef KRB5 86 if(auth_method == AUTH_KRB5 && protocol_version == 2) 87 init_ivecs(1); 88 #endif 89 90 if (s >= FD_SETSIZE || (errsock != -1 && errsock >= FD_SETSIZE)) 91 errx (1, "fd too large"); 92 93 FD_ZERO(&real_readset); 94 FD_SET(s, &real_readset); 95 if (errsock != -1) { 96 FD_SET(errsock, &real_readset); 97 ++count; 98 } 99 if(input) 100 FD_SET(STDIN_FILENO, &real_readset); 101 102 for (;;) { 103 int ret; 104 fd_set readset; 105 char buf[RSH_BUFSIZ]; 106 107 readset = real_readset; 108 ret = select (max(s, errsock) + 1, &readset, NULL, NULL, NULL); 109 if (ret < 0) { 110 if (errno == EINTR) 111 continue; 112 else 113 err (1, "select"); 114 } 115 if (FD_ISSET(s, &readset)) { 116 ret = do_read (s, buf, sizeof(buf), ivec_in[0]); 117 if (ret < 0) 118 err (1, "read"); 119 else if (ret == 0) { 120 close (s); 121 FD_CLR(s, &real_readset); 122 if (--count == 0) 123 return 0; 124 } else 125 net_write (STDOUT_FILENO, buf, ret); 126 } 127 if (errsock != -1 && FD_ISSET(errsock, &readset)) { 128 ret = do_read (errsock, buf, sizeof(buf), ivec_in[1]); 129 if (ret < 0) 130 err (1, "read"); 131 else if (ret == 0) { 132 close (errsock); 133 FD_CLR(errsock, &real_readset); 134 if (--count == 0) 135 return 0; 136 } else 137 net_write (STDERR_FILENO, buf, ret); 138 } 139 if (FD_ISSET(STDIN_FILENO, &readset)) { 140 ret = read (STDIN_FILENO, buf, sizeof(buf)); 141 if (ret < 0) 142 err (1, "read"); 143 else if (ret == 0) { 144 close (STDIN_FILENO); 145 FD_CLR(STDIN_FILENO, &real_readset); 146 shutdown (s, SHUT_WR); 147 } else 148 do_write (s, buf, ret, ivec_out[0]); 149 } 150 } 151 } 152 153 #ifdef KRB4 154 static int 155 send_krb4_auth(int s, 156 struct sockaddr *thisaddr, 157 struct sockaddr *thataddr, 158 const char *hostname, 159 const char *remote_user, 160 const char *local_user, 161 size_t cmd_len, 162 const char *cmd) 163 { 164 KTEXT_ST text; 165 CREDENTIALS cred; 166 MSG_DAT msg; 167 int status; 168 size_t len; 169 170 /* the normal default for krb4 should be to disable encryption */ 171 status = krb_sendauth ((do_encrypt == 1) ? KOPT_DO_MUTUAL : 0, 172 s, &text, "rcmd", 173 (char *)hostname, krb_realmofhost (hostname), 174 getpid(), &msg, &cred, schedule, 175 (struct sockaddr_in *)thisaddr, 176 (struct sockaddr_in *)thataddr, 177 KCMD_OLD_VERSION); 178 if (status != KSUCCESS) { 179 warnx("%s: %s", hostname, krb_get_err_text(status)); 180 return 1; 181 } 182 memcpy (iv, cred.session, sizeof(iv)); 183 184 len = strlen(remote_user) + 1; 185 if (net_write (s, remote_user, len) != len) { 186 warn("write"); 187 return 1; 188 } 189 if (net_write (s, cmd, cmd_len) != cmd_len) { 190 warn("write"); 191 return 1; 192 } 193 return 0; 194 } 195 #endif /* KRB4 */ 196 197 #ifdef KRB5 198 /* 199 * Send forward information on `s' for host `hostname', them being 200 * forwardable themselves if `forwardable' 201 */ 202 203 static int 204 krb5_forward_cred (krb5_auth_context auth_context, 205 int s, 206 const char *hostname, 207 int forwardable) 208 { 209 krb5_error_code ret; 210 krb5_ccache ccache; 211 krb5_creds creds; 212 krb5_kdc_flags flags; 213 krb5_data out_data; 214 krb5_principal principal; 215 216 memset (&creds, 0, sizeof(creds)); 217 218 ret = krb5_cc_default (context, &ccache); 219 if (ret) { 220 warnx ("could not forward creds: krb5_cc_default: %s", 221 krb5_get_err_text (context, ret)); 222 return 1; 223 } 224 225 ret = krb5_cc_get_principal (context, ccache, &principal); 226 if (ret) { 227 warnx ("could not forward creds: krb5_cc_get_principal: %s", 228 krb5_get_err_text (context, ret)); 229 return 1; 230 } 231 232 creds.client = principal; 233 234 ret = krb5_build_principal (context, 235 &creds.server, 236 strlen(principal->realm), 237 principal->realm, 238 "krbtgt", 239 principal->realm, 240 NULL); 241 242 if (ret) { 243 warnx ("could not forward creds: krb5_build_principal: %s", 244 krb5_get_err_text (context, ret)); 245 return 1; 246 } 247 248 creds.times.endtime = 0; 249 250 flags.i = 0; 251 flags.b.forwarded = 1; 252 flags.b.forwardable = forwardable; 253 254 ret = krb5_get_forwarded_creds (context, 255 auth_context, 256 ccache, 257 flags.i, 258 hostname, 259 &creds, 260 &out_data); 261 if (ret) { 262 warnx ("could not forward creds: krb5_get_forwarded_creds: %s", 263 krb5_get_err_text (context, ret)); 264 return 1; 265 } 266 267 ret = krb5_write_message (context, 268 (void *)&s, 269 &out_data); 270 krb5_data_free (&out_data); 271 272 if (ret) 273 warnx ("could not forward creds: krb5_write_message: %s", 274 krb5_get_err_text (context, ret)); 275 return 0; 276 } 277 278 static int sendauth_version_error; 279 280 static int 281 send_krb5_auth(int s, 282 struct sockaddr *thisaddr, 283 struct sockaddr *thataddr, 284 const char *hostname, 285 const char *remote_user, 286 const char *local_user, 287 size_t cmd_len, 288 const char *cmd) 289 { 290 krb5_principal server; 291 krb5_data cksum_data; 292 int status; 293 size_t len; 294 krb5_auth_context auth_context = NULL; 295 const char *protocol_string = NULL; 296 krb5_flags ap_opts; 297 298 status = krb5_sname_to_principal(context, 299 hostname, 300 "host", 301 KRB5_NT_SRV_HST, 302 &server); 303 if (status) { 304 warnx ("%s: %s", hostname, krb5_get_err_text(context, status)); 305 return 1; 306 } 307 308 if(do_encrypt == -1) { 309 krb5_appdefault_boolean(context, NULL, 310 krb5_principal_get_realm(context, server), 311 "encrypt", 312 FALSE, 313 &do_encrypt); 314 } 315 316 cksum_data.length = asprintf ((char **)&cksum_data.data, 317 "%u:%s%s%s", 318 ntohs(socket_get_port(thataddr)), 319 do_encrypt ? "-x " : "", 320 cmd, 321 remote_user); 322 323 ap_opts = 0; 324 325 if(do_encrypt) 326 ap_opts |= AP_OPTS_MUTUAL_REQUIRED; 327 328 switch(protocol_version) { 329 case 2: 330 ap_opts |= AP_OPTS_USE_SUBKEY; 331 protocol_string = KCMD_NEW_VERSION; 332 break; 333 case 1: 334 protocol_string = KCMD_OLD_VERSION; 335 key_usage = KRB5_KU_OTHER_ENCRYPTED; 336 break; 337 default: 338 abort(); 339 } 340 341 status = krb5_sendauth (context, 342 &auth_context, 343 &s, 344 protocol_string, 345 NULL, 346 server, 347 ap_opts, 348 &cksum_data, 349 NULL, 350 NULL, 351 NULL, 352 NULL, 353 NULL); 354 355 /* do this while we have a principal */ 356 if(do_forward == -1 || do_forwardable == -1) { 357 krb5_const_realm realm = krb5_principal_get_realm(context, server); 358 if (do_forwardable == -1) 359 krb5_appdefault_boolean(context, NULL, realm, 360 "forwardable", FALSE, 361 &do_forwardable); 362 if (do_forward == -1) 363 krb5_appdefault_boolean(context, NULL, realm, 364 "forward", FALSE, 365 &do_forward); 366 } 367 368 krb5_free_principal(context, server); 369 krb5_data_free(&cksum_data); 370 371 if (status) { 372 if(status == KRB5_SENDAUTH_REJECTED && 373 protocol_version == 2 && protocol_version_str == NULL) 374 sendauth_version_error = 1; 375 else 376 krb5_warn(context, status, "%s", hostname); 377 return 1; 378 } 379 380 status = krb5_auth_con_getlocalsubkey (context, auth_context, &keyblock); 381 if(keyblock == NULL) 382 status = krb5_auth_con_getkey (context, auth_context, &keyblock); 383 if (status) { 384 warnx ("krb5_auth_con_getkey: %s", krb5_get_err_text(context, status)); 385 return 1; 386 } 387 388 status = krb5_auth_con_setaddrs_from_fd (context, 389 auth_context, 390 &s); 391 if (status) { 392 warnx("krb5_auth_con_setaddrs_from_fd: %s", 393 krb5_get_err_text(context, status)); 394 return(1); 395 } 396 397 status = krb5_crypto_init(context, keyblock, 0, &crypto); 398 if(status) { 399 warnx ("krb5_crypto_init: %s", krb5_get_err_text(context, status)); 400 return 1; 401 } 402 403 len = strlen(remote_user) + 1; 404 if (net_write (s, remote_user, len) != len) { 405 warn ("write"); 406 return 1; 407 } 408 if (do_encrypt && net_write (s, "-x ", 3) != 3) { 409 warn ("write"); 410 return 1; 411 } 412 if (net_write (s, cmd, cmd_len) != cmd_len) { 413 warn ("write"); 414 return 1; 415 } 416 417 if (do_unique_tkfile) { 418 if (net_write (s, tkfile, strlen(tkfile)) != strlen(tkfile)) { 419 warn ("write"); 420 return 1; 421 } 422 } 423 len = strlen(local_user) + 1; 424 if (net_write (s, local_user, len) != len) { 425 warn ("write"); 426 return 1; 427 } 428 429 if (!do_forward 430 || krb5_forward_cred (auth_context, s, hostname, do_forwardable)) { 431 /* Empty forwarding info */ 432 433 u_char zero[4] = {0, 0, 0, 0}; 434 write (s, &zero, 4); 435 } 436 krb5_auth_con_free (context, auth_context); 437 return 0; 438 } 439 440 #endif /* KRB5 */ 441 442 static int 443 send_broken_auth(int s, 444 struct sockaddr *thisaddr, 445 struct sockaddr *thataddr, 446 const char *hostname, 447 const char *remote_user, 448 const char *local_user, 449 size_t cmd_len, 450 const char *cmd) 451 { 452 size_t len; 453 454 len = strlen(local_user) + 1; 455 if (net_write (s, local_user, len) != len) { 456 warn ("write"); 457 return 1; 458 } 459 len = strlen(remote_user) + 1; 460 if (net_write (s, remote_user, len) != len) { 461 warn ("write"); 462 return 1; 463 } 464 if (net_write (s, cmd, cmd_len) != cmd_len) { 465 warn ("write"); 466 return 1; 467 } 468 return 0; 469 } 470 471 static int 472 proto (int s, int errsock, 473 const char *hostname, const char *local_user, const char *remote_user, 474 const char *cmd, size_t cmd_len, 475 int (*auth_func)(int s, 476 struct sockaddr *this, struct sockaddr *that, 477 const char *hostname, const char *remote_user, 478 const char *local_user, size_t cmd_len, 479 const char *cmd)) 480 { 481 int errsock2; 482 char buf[BUFSIZ]; 483 char *p; 484 size_t len; 485 char reply; 486 struct sockaddr_storage thisaddr_ss; 487 struct sockaddr *thisaddr = (struct sockaddr *)&thisaddr_ss; 488 struct sockaddr_storage thataddr_ss; 489 struct sockaddr *thataddr = (struct sockaddr *)&thataddr_ss; 490 struct sockaddr_storage erraddr_ss; 491 struct sockaddr *erraddr = (struct sockaddr *)&erraddr_ss; 492 socklen_t addrlen; 493 int ret; 494 495 addrlen = sizeof(thisaddr_ss); 496 if (getsockname (s, thisaddr, &addrlen) < 0) { 497 warn ("getsockname(%s)", hostname); 498 return 1; 499 } 500 addrlen = sizeof(thataddr_ss); 501 if (getpeername (s, thataddr, &addrlen) < 0) { 502 warn ("getpeername(%s)", hostname); 503 return 1; 504 } 505 506 if (errsock != -1) { 507 508 addrlen = sizeof(erraddr_ss); 509 if (getsockname (errsock, erraddr, &addrlen) < 0) { 510 warn ("getsockname"); 511 return 1; 512 } 513 514 if (listen (errsock, 1) < 0) { 515 warn ("listen"); 516 return 1; 517 } 518 519 p = buf; 520 snprintf (p, sizeof(buf), "%u", 521 ntohs(socket_get_port(erraddr))); 522 len = strlen(buf) + 1; 523 if(net_write (s, buf, len) != len) { 524 warn ("write"); 525 close (errsock); 526 return 1; 527 } 528 529 530 for (;;) { 531 fd_set fdset; 532 533 if (errsock >= FD_SETSIZE || s >= FD_SETSIZE) 534 errx (1, "fd too large"); 535 536 FD_ZERO(&fdset); 537 FD_SET(errsock, &fdset); 538 FD_SET(s, &fdset); 539 540 ret = select (max(errsock, s) + 1, &fdset, NULL, NULL, NULL); 541 if (ret < 0) { 542 if (errno == EINTR) 543 continue; 544 warn ("select"); 545 close (errsock); 546 return 1; 547 } 548 if (FD_ISSET(errsock, &fdset)) { 549 errsock2 = accept (errsock, NULL, NULL); 550 close (errsock); 551 if (errsock2 < 0) { 552 warn ("accept"); 553 return 1; 554 } 555 break; 556 } 557 558 /* 559 * there should not arrive any data on this fd so if it's 560 * readable it probably indicates that the other side when 561 * away. 562 */ 563 564 if (FD_ISSET(s, &fdset)) { 565 warnx ("socket closed"); 566 close (errsock); 567 errsock2 = -1; 568 break; 569 } 570 } 571 } else { 572 if (net_write (s, "0", 2) != 2) { 573 warn ("write"); 574 return 1; 575 } 576 errsock2 = -1; 577 } 578 579 if ((*auth_func)(s, thisaddr, thataddr, hostname, 580 remote_user, local_user, 581 cmd_len, cmd)) { 582 close (errsock2); 583 return 1; 584 } 585 586 ret = net_read (s, &reply, 1); 587 if (ret < 0) { 588 warn ("read"); 589 close (errsock2); 590 return 1; 591 } else if (ret == 0) { 592 warnx ("unexpected EOF from %s", hostname); 593 close (errsock2); 594 return 1; 595 } 596 if (reply != 0) { 597 598 warnx ("Error from rshd at %s:", hostname); 599 600 while ((ret = read (s, buf, sizeof(buf))) > 0) 601 write (STDOUT_FILENO, buf, ret); 602 write (STDOUT_FILENO,"\n",1); 603 close (errsock2); 604 return 1; 605 } 606 607 if (sock_debug) { 608 int one = 1; 609 if (setsockopt(s, SOL_SOCKET, SO_DEBUG, (void *)&one, sizeof(one)) < 0) 610 warn("setsockopt remote"); 611 if (errsock2 != -1 && 612 setsockopt(errsock2, SOL_SOCKET, SO_DEBUG, 613 (void *)&one, sizeof(one)) < 0) 614 warn("setsockopt stderr"); 615 } 616 617 return loop (s, errsock2); 618 } 619 620 /* 621 * Return in `res' a copy of the concatenation of `argc, argv' into 622 * malloced space. */ 623 624 static size_t 625 construct_command (char **res, int argc, char **argv) 626 { 627 int i; 628 size_t len = 0; 629 char *tmp; 630 631 for (i = 0; i < argc; ++i) 632 len += strlen(argv[i]) + 1; 633 len = max (1, len); 634 tmp = malloc (len); 635 if (tmp == NULL) 636 errx (1, "malloc %u failed", len); 637 638 *tmp = '\0'; 639 for (i = 0; i < argc - 1; ++i) { 640 strcat (tmp, argv[i]); 641 strcat (tmp, " "); 642 } 643 if (argc > 0) 644 strcat (tmp, argv[argc-1]); 645 *res = tmp; 646 return len; 647 } 648 649 static char * 650 print_addr (const struct sockaddr *sa) 651 { 652 char addr_str[256]; 653 char *res; 654 const char *as = NULL; 655 656 if(sa->sa_family == AF_INET) 657 as = inet_ntop (sa->sa_family, &((struct sockaddr_in*)sa)->sin_addr, 658 addr_str, sizeof(addr_str)); 659 #ifdef HAVE_INET6 660 else if(sa->sa_family == AF_INET6) 661 as = inet_ntop (sa->sa_family, &((struct sockaddr_in6*)sa)->sin6_addr, 662 addr_str, sizeof(addr_str)); 663 #endif 664 if(as == NULL) 665 return NULL; 666 res = strdup(as); 667 if (res == NULL) 668 errx (1, "malloc: out of memory"); 669 return res; 670 } 671 672 static int 673 doit_broken (int argc, 674 char **argv, 675 int hostindex, 676 struct addrinfo *ai, 677 const char *remote_user, 678 const char *local_user, 679 int priv_socket1, 680 int priv_socket2, 681 const char *cmd, 682 size_t cmd_len) 683 { 684 struct addrinfo *a; 685 686 if (connect (priv_socket1, ai->ai_addr, ai->ai_addrlen) < 0) { 687 int save_errno = errno; 688 689 close(priv_socket1); 690 close(priv_socket2); 691 692 for (a = ai->ai_next; a != NULL; a = a->ai_next) { 693 pid_t pid; 694 char *adr = print_addr(a->ai_addr); 695 if(adr == NULL) 696 continue; 697 698 pid = fork(); 699 if (pid < 0) 700 err (1, "fork"); 701 else if(pid == 0) { 702 char **new_argv; 703 int i = 0; 704 705 new_argv = malloc((argc + 2) * sizeof(*new_argv)); 706 if (new_argv == NULL) 707 errx (1, "malloc: out of memory"); 708 new_argv[i] = argv[i]; 709 ++i; 710 if (hostindex == i) 711 new_argv[i++] = adr; 712 new_argv[i++] = "-K"; 713 for(; i <= argc; ++i) 714 new_argv[i] = argv[i - 1]; 715 if (hostindex > 1) 716 new_argv[hostindex + 1] = adr; 717 new_argv[argc + 1] = NULL; 718 execv(PATH_RSH, new_argv); 719 err(1, "execv(%s)", PATH_RSH); 720 } else { 721 int status; 722 free(adr); 723 724 while(waitpid(pid, &status, 0) < 0) 725 ; 726 if(WIFEXITED(status) && WEXITSTATUS(status) == 0) 727 return 0; 728 } 729 } 730 errno = save_errno; 731 warn("%s", argv[hostindex]); 732 return 1; 733 } else { 734 int ret; 735 736 ret = proto (priv_socket1, priv_socket2, 737 argv[hostindex], 738 local_user, remote_user, 739 cmd, cmd_len, 740 send_broken_auth); 741 return ret; 742 } 743 } 744 745 #if defined(KRB4) || defined(KRB5) 746 static int 747 doit (const char *hostname, 748 struct addrinfo *ai, 749 const char *remote_user, 750 const char *local_user, 751 const char *cmd, 752 size_t cmd_len, 753 int do_errsock, 754 int (*auth_func)(int s, 755 struct sockaddr *this, struct sockaddr *that, 756 const char *hostname, const char *remote_user, 757 const char *local_user, size_t cmd_len, 758 const char *cmd)) 759 { 760 int error; 761 struct addrinfo *a; 762 int socketfailed = 1; 763 int ret; 764 765 for (a = ai; a != NULL; a = a->ai_next) { 766 int s; 767 int errsock; 768 769 s = socket (a->ai_family, a->ai_socktype, a->ai_protocol); 770 if (s < 0) 771 continue; 772 socketfailed = 0; 773 if (connect (s, a->ai_addr, a->ai_addrlen) < 0) { 774 char addr[128]; 775 if(getnameinfo(a->ai_addr, a->ai_addrlen, 776 addr, sizeof(addr), NULL, 0, NI_NUMERICHOST) == 0) 777 warn ("connect(%s [%s])", hostname, addr); 778 else 779 warn ("connect(%s)", hostname); 780 close (s); 781 continue; 782 } 783 if (do_errsock) { 784 struct addrinfo *ea, *eai; 785 struct addrinfo hints; 786 787 memset (&hints, 0, sizeof(hints)); 788 hints.ai_socktype = a->ai_socktype; 789 hints.ai_protocol = a->ai_protocol; 790 hints.ai_family = a->ai_family; 791 hints.ai_flags = AI_PASSIVE; 792 793 errsock = -1; 794 795 error = getaddrinfo (NULL, "0", &hints, &eai); 796 if (error) 797 errx (1, "getaddrinfo: %s", gai_strerror(error)); 798 for (ea = eai; ea != NULL; ea = ea->ai_next) { 799 errsock = socket (ea->ai_family, ea->ai_socktype, 800 ea->ai_protocol); 801 if (errsock < 0) 802 continue; 803 if (bind (errsock, ea->ai_addr, ea->ai_addrlen) < 0) 804 err (1, "bind"); 805 break; 806 } 807 if (errsock < 0) 808 err (1, "socket"); 809 freeaddrinfo (eai); 810 } else 811 errsock = -1; 812 813 ret = proto (s, errsock, 814 hostname, 815 local_user, remote_user, 816 cmd, cmd_len, auth_func); 817 close (s); 818 return ret; 819 } 820 if(socketfailed) 821 warnx ("failed to contact %s", hostname); 822 return -1; 823 } 824 #endif /* KRB4 || KRB5 */ 825 826 struct getargs args[] = { 827 #ifdef KRB4 828 { "krb4", '4', arg_flag, &use_v4, "Use Kerberos V4" }, 829 #endif 830 #ifdef KRB5 831 { "krb5", '5', arg_flag, &use_v5, "Use Kerberos V5" }, 832 { "forward", 'f', arg_flag, &do_forward, "Forward credentials (krb5)"}, 833 { NULL, 'G', arg_negative_flag,&do_forward, "Don't forward credentials" }, 834 { "forwardable", 'F', arg_flag, &do_forwardable, 835 "Forward forwardable credentials" }, 836 #endif 837 #if defined(KRB4) || defined(KRB5) 838 { "broken", 'K', arg_flag, &use_only_broken, "Use only priv port" }, 839 { "encrypt", 'x', arg_flag, &do_encrypt, "Encrypt connection" }, 840 { NULL, 'z', arg_negative_flag, &do_encrypt, 841 "Don't encrypt connection", NULL }, 842 #endif 843 #ifdef KRB5 844 { "unique", 'u', arg_flag, &do_unique_tkfile, 845 "Use unique remote tkfile (krb5)" }, 846 { "tkfile", 'U', arg_string, &unique_tkfile, 847 "Use that remote tkfile (krb5)" }, 848 #endif 849 { NULL, 'd', arg_flag, &sock_debug, "Enable socket debugging" }, 850 { "input", 'n', arg_negative_flag, &input, "Close stdin" }, 851 { "port", 'p', arg_string, &port_str, "Use this port", 852 "port" }, 853 { "user", 'l', arg_string, &user, "Run as this user", "login" }, 854 { "stderr", 'e', arg_negative_flag, &do_errsock, "Don't open stderr"}, 855 { "protocol", 'P', arg_string, &protocol_version_str, 856 "Protocol version", "protocol" }, 857 { "version", 0, arg_flag, &do_version, NULL }, 858 { "help", 0, arg_flag, &do_help, NULL } 859 }; 860 861 static void 862 usage (int ret) 863 { 864 arg_printusage (args, 865 sizeof(args) / sizeof(args[0]), 866 NULL, 867 "[login@]host [command]"); 868 exit (ret); 869 } 870 871 /* 872 * 873 */ 874 875 int 876 main(int argc, char **argv) 877 { 878 int priv_port1, priv_port2; 879 int priv_socket1, priv_socket2; 880 int argindex = 0; 881 int error; 882 struct addrinfo hints, *ai; 883 int ret = 1; 884 char *cmd; 885 char *tmp; 886 size_t cmd_len; 887 const char *local_user; 888 char *host = NULL; 889 int host_index = -1; 890 #ifdef KRB5 891 int status; 892 #endif 893 uid_t uid; 894 895 priv_port1 = priv_port2 = IPPORT_RESERVED-1; 896 priv_socket1 = rresvport(&priv_port1); 897 priv_socket2 = rresvport(&priv_port2); 898 uid = getuid (); 899 if (setuid (uid) || (uid != 0 && setuid(0) == 0)) 900 err (1, "setuid"); 901 902 setprogname (argv[0]); 903 904 if (argc >= 2 && argv[1][0] != '-') { 905 host = argv[host_index = 1]; 906 argindex = 1; 907 } 908 909 if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, 910 &argindex)) 911 usage (1); 912 913 if (do_help) 914 usage (0); 915 916 if (do_version) { 917 print_version (NULL); 918 return 0; 919 } 920 921 if(protocol_version_str != NULL) { 922 if(strcasecmp(protocol_version_str, "N") == 0) 923 protocol_version = 2; 924 else if(strcasecmp(protocol_version_str, "O") == 0) 925 protocol_version = 1; 926 else { 927 char *end; 928 int v; 929 v = strtol(protocol_version_str, &end, 0); 930 if(*end != '\0' || (v != 1 && v != 2)) { 931 errx(1, "unknown protocol version \"%s\"", 932 protocol_version_str); 933 } 934 protocol_version = v; 935 } 936 } 937 938 #ifdef KRB5 939 status = krb5_init_context (&context); 940 if (status) { 941 if(use_v5 == 1) 942 errx(1, "krb5_init_context failed: %d", status); 943 else 944 use_v5 = 0; 945 } 946 947 /* request for forwardable on the command line means we should 948 also forward */ 949 if (do_forwardable == 1) 950 do_forward = 1; 951 952 #endif 953 954 #if defined(KRB4) && defined(KRB5) 955 if(use_v4 == -1 && use_v5 == 1) 956 use_v4 = 0; 957 if(use_v5 == -1 && use_v4 == 1) 958 use_v5 = 0; 959 #endif 960 961 if (use_only_broken) { 962 #ifdef KRB4 963 use_v4 = 0; 964 #endif 965 #ifdef KRB5 966 use_v5 = 0; 967 #endif 968 } 969 970 if(priv_socket1 < 0) { 971 if (use_only_broken) 972 errx (1, "unable to bind reserved port: is rsh setuid root?"); 973 use_broken = 0; 974 } 975 976 #if defined(KRB4) || defined(KRB5) 977 if (do_encrypt == 1 && use_only_broken) 978 errx (1, "encryption not supported with old style authentication"); 979 #endif 980 981 982 983 #ifdef KRB5 984 if (do_unique_tkfile && unique_tkfile != NULL) 985 errx (1, "Only one of -u and -U allowed."); 986 987 if (do_unique_tkfile) 988 strcpy(tkfile,"-u "); 989 else if (unique_tkfile != NULL) { 990 if (strchr(unique_tkfile,' ') != NULL) { 991 warnx("Space is not allowed in tkfilename"); 992 usage(1); 993 } 994 do_unique_tkfile = 1; 995 snprintf (tkfile, sizeof(tkfile), "-U %s ", unique_tkfile); 996 } 997 #endif 998 999 if (host == NULL) { 1000 if (argc - argindex < 1) 1001 usage (1); 1002 else 1003 host = argv[host_index = argindex++]; 1004 } 1005 1006 if((tmp = strchr(host, '@')) != NULL) { 1007 *tmp++ = '\0'; 1008 user = host; 1009 host = tmp; 1010 } 1011 1012 if (argindex == argc) { 1013 close (priv_socket1); 1014 close (priv_socket2); 1015 argv[0] = "rlogin"; 1016 execvp ("rlogin", argv); 1017 err (1, "execvp rlogin"); 1018 } 1019 1020 local_user = get_default_username (); 1021 if (local_user == NULL) 1022 errx (1, "who are you?"); 1023 1024 if (user == NULL) 1025 user = local_user; 1026 1027 cmd_len = construct_command(&cmd, argc - argindex, argv + argindex); 1028 1029 /* 1030 * Try all different authentication methods 1031 */ 1032 1033 #ifdef KRB5 1034 if (ret && use_v5) { 1035 memset (&hints, 0, sizeof(hints)); 1036 hints.ai_socktype = SOCK_STREAM; 1037 hints.ai_protocol = IPPROTO_TCP; 1038 1039 if(port_str == NULL) { 1040 error = getaddrinfo(host, "kshell", &hints, &ai); 1041 if(error == EAI_NONAME) 1042 error = getaddrinfo(host, "544", &hints, &ai); 1043 } else 1044 error = getaddrinfo(host, port_str, &hints, &ai); 1045 1046 if(error) 1047 errx (1, "getaddrinfo: %s", gai_strerror(error)); 1048 1049 auth_method = AUTH_KRB5; 1050 again: 1051 ret = doit (host, ai, user, local_user, cmd, cmd_len, 1052 do_errsock, 1053 send_krb5_auth); 1054 if(ret != 0 && sendauth_version_error && 1055 protocol_version == 2) { 1056 protocol_version = 1; 1057 goto again; 1058 } 1059 freeaddrinfo(ai); 1060 } 1061 #endif 1062 #ifdef KRB4 1063 if (ret && use_v4) { 1064 memset (&hints, 0, sizeof(hints)); 1065 hints.ai_socktype = SOCK_STREAM; 1066 hints.ai_protocol = IPPROTO_TCP; 1067 1068 if(port_str == NULL) { 1069 if(do_encrypt) { 1070 error = getaddrinfo(host, "ekshell", &hints, &ai); 1071 if(error == EAI_NONAME) 1072 error = getaddrinfo(host, "545", &hints, &ai); 1073 } else { 1074 error = getaddrinfo(host, "kshell", &hints, &ai); 1075 if(error == EAI_NONAME) 1076 error = getaddrinfo(host, "544", &hints, &ai); 1077 } 1078 } else 1079 error = getaddrinfo(host, port_str, &hints, &ai); 1080 1081 if(error) 1082 errx (1, "getaddrinfo: %s", gai_strerror(error)); 1083 auth_method = AUTH_KRB4; 1084 ret = doit (host, ai, user, local_user, cmd, cmd_len, 1085 do_errsock, 1086 send_krb4_auth); 1087 freeaddrinfo(ai); 1088 } 1089 #endif 1090 if (ret && use_broken) { 1091 memset (&hints, 0, sizeof(hints)); 1092 hints.ai_socktype = SOCK_STREAM; 1093 hints.ai_protocol = IPPROTO_TCP; 1094 1095 if(port_str == NULL) { 1096 error = getaddrinfo(host, "shell", &hints, &ai); 1097 if(error == EAI_NONAME) 1098 error = getaddrinfo(host, "514", &hints, &ai); 1099 } else 1100 error = getaddrinfo(host, port_str, &hints, &ai); 1101 1102 if(error) 1103 errx (1, "getaddrinfo: %s", gai_strerror(error)); 1104 1105 auth_method = AUTH_BROKEN; 1106 ret = doit_broken (argc, argv, host_index, ai, 1107 user, local_user, 1108 priv_socket1, 1109 do_errsock ? priv_socket2 : -1, 1110 cmd, cmd_len); 1111 freeaddrinfo(ai); 1112 } 1113 free(cmd); 1114 return ret; 1115 } 1116