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