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