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