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