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