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