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