1 /* 2 * Copyright (c) 1983, 1990, 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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 "rcp_locl.h" 35 36 #define RSH_PROGRAM "rsh" 37 #define OPTIONS "5dfKpP:rtxz" 38 39 struct passwd *pwd; 40 uid_t userid; 41 int errs, remin, remout; 42 int pflag, iamremote, iamrecursive, targetshouldbedirectory; 43 int doencrypt, noencrypt; 44 int usebroken, usekrb5; 45 char *port; 46 47 #define CMDNEEDS 64 48 char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ 49 50 int response (void); 51 void rsource (char *, struct stat *); 52 void sink (int, char *[]); 53 void source (int, char *[]); 54 void tolocal (int, char *[]); 55 void toremote (char *, int, char *[]); 56 void usage (void); 57 58 int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout); 59 60 int 61 main(argc, argv) 62 int argc; 63 char *argv[]; 64 { 65 int ch, fflag, tflag; 66 char *targ; 67 68 fflag = tflag = 0; 69 while ((ch = getopt(argc, argv, OPTIONS)) != -1) 70 switch(ch) { /* User-visible flags. */ 71 case '5': 72 usekrb5 = 1; 73 break; 74 case 'K': 75 usebroken = 1; 76 break; 77 case 'P': 78 port = optarg; 79 break; 80 case 'p': 81 pflag = 1; 82 break; 83 case 'r': 84 iamrecursive = 1; 85 break; 86 case 'x': 87 doencrypt = 1; 88 break; 89 case 'z': 90 noencrypt = 1; 91 break; 92 /* Server options. */ 93 case 'd': 94 targetshouldbedirectory = 1; 95 break; 96 case 'f': /* "from" */ 97 iamremote = 1; 98 fflag = 1; 99 break; 100 case 't': /* "to" */ 101 iamremote = 1; 102 tflag = 1; 103 break; 104 case '?': 105 default: 106 usage(); 107 } 108 argc -= optind; 109 argv += optind; 110 111 if ((pwd = getpwuid(userid = getuid())) == NULL) 112 errx(1, "unknown user %d", (int)userid); 113 114 remin = STDIN_FILENO; /* XXX */ 115 remout = STDOUT_FILENO; 116 117 if (fflag) { /* Follow "protocol", send data. */ 118 (void)response(); 119 (void)setuid(userid); 120 source(argc, argv); 121 exit(errs); 122 } 123 124 if (tflag) { /* Receive data. */ 125 (void)setuid(userid); 126 sink(argc, argv); 127 exit(errs); 128 } 129 130 if (argc < 2) 131 usage(); 132 if (argc > 2) 133 targetshouldbedirectory = 1; 134 135 remin = remout = -1; 136 /* Command to be executed on remote system using "rsh". */ 137 (void) sprintf(cmd, "rcp%s%s%s", iamrecursive ? " -r" : "", 138 pflag ? " -p" : "", targetshouldbedirectory ? " -d" : ""); 139 140 (void)signal(SIGPIPE, lostconn); 141 142 if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */ 143 toremote(targ, argc, argv); 144 else { 145 tolocal(argc, argv); /* Dest is local host. */ 146 if (targetshouldbedirectory) 147 verifydir(argv[argc - 1]); 148 } 149 exit(errs); 150 } 151 152 void 153 toremote(targ, argc, argv) 154 char *targ, *argv[]; 155 int argc; 156 { 157 int i, len; 158 char *bp, *host, *src, *suser, *thost, *tuser; 159 160 *targ++ = 0; 161 if (*targ == 0) 162 targ = "."; 163 164 if ((thost = strchr(argv[argc - 1], '@'))) { 165 /* user@host */ 166 *thost++ = 0; 167 tuser = argv[argc - 1]; 168 if (*tuser == '\0') 169 tuser = NULL; 170 else if (!okname(tuser)) 171 exit(1); 172 } else { 173 thost = argv[argc - 1]; 174 tuser = NULL; 175 } 176 177 for (i = 0; i < argc - 1; i++) { 178 src = colon(argv[i]); 179 if (src) { /* remote to remote */ 180 *src++ = 0; 181 if (*src == 0) 182 src = "."; 183 host = strchr(argv[i], '@'); 184 len = strlen(_PATH_RSH) + strlen(argv[i]) + 185 strlen(src) + (tuser ? strlen(tuser) : 0) + 186 strlen(thost) + strlen(targ) + CMDNEEDS + 20; 187 if (!(bp = malloc(len))) 188 err(1, "malloc"); 189 if (host) { 190 *host++ = 0; 191 suser = argv[i]; 192 if (*suser == '\0') 193 suser = pwd->pw_name; 194 else if (!okname(suser)) 195 continue; 196 (void)snprintf(bp, len, 197 "%s %s -l %s -n %s %s '%s%s%s:%s'", 198 _PATH_RSH, host, suser, cmd, src, 199 tuser ? tuser : "", tuser ? "@" : "", 200 thost, targ); 201 } else 202 (void)snprintf(bp, len, 203 "exec %s %s -n %s %s '%s%s%s:%s'", 204 _PATH_RSH, argv[i], cmd, src, 205 tuser ? tuser : "", tuser ? "@" : "", 206 thost, targ); 207 (void)susystem(bp, userid); 208 (void)free(bp); 209 } else { /* local to remote */ 210 if (remin == -1) { 211 len = strlen(targ) + CMDNEEDS + 20; 212 if (!(bp = malloc(len))) 213 err(1, "malloc"); 214 (void)snprintf(bp, len, "%s -t %s", cmd, targ); 215 host = thost; 216 217 if (do_cmd(host, tuser, bp, &remin, &remout) < 0) 218 exit(1); 219 220 if (response() < 0) 221 exit(1); 222 (void)free(bp); 223 (void)setuid(userid); 224 } 225 source(1, argv+i); 226 } 227 } 228 } 229 230 void 231 tolocal(argc, argv) 232 int argc; 233 char *argv[]; 234 { 235 int i, len; 236 char *bp, *host, *src, *suser; 237 238 for (i = 0; i < argc - 1; i++) { 239 if (!(src = colon(argv[i]))) { /* Local to local. */ 240 len = strlen(_PATH_CP) + strlen(argv[i]) + 241 strlen(argv[argc - 1]) + 20; 242 if (!(bp = malloc(len))) 243 err(1, "malloc"); 244 (void)snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP, 245 iamrecursive ? " -PR" : "", pflag ? " -p" : "", 246 argv[i], argv[argc - 1]); 247 if (susystem(bp, userid)) 248 ++errs; 249 (void)free(bp); 250 continue; 251 } 252 *src++ = 0; 253 if (*src == 0) 254 src = "."; 255 if ((host = strchr(argv[i], '@')) == NULL) { 256 host = argv[i]; 257 suser = pwd->pw_name; 258 } else { 259 *host++ = 0; 260 suser = argv[i]; 261 if (*suser == '\0') 262 suser = pwd->pw_name; 263 else if (!okname(suser)) 264 continue; 265 } 266 len = strlen(src) + CMDNEEDS + 20; 267 if ((bp = malloc(len)) == NULL) 268 err(1, "malloc"); 269 (void)snprintf(bp, len, "%s -f %s", cmd, src); 270 if (do_cmd(host, suser, bp, &remin, &remout) < 0) { 271 (void)free(bp); 272 ++errs; 273 continue; 274 } 275 (void)free(bp); 276 sink(1, argv + argc - 1); 277 (void)seteuid(0); 278 (void)close(remin); 279 remin = remout = -1; 280 } 281 } 282 283 void 284 source(argc, argv) 285 int argc; 286 char *argv[]; 287 { 288 struct stat stb; 289 static BUF buffer; 290 BUF *bp; 291 off_t i; 292 int amt, fd, haderr, indx, result; 293 char *last, *name, buf[BUFSIZ]; 294 295 for (indx = 0; indx < argc; ++indx) { 296 name = argv[indx]; 297 if ((fd = open(name, O_RDONLY, 0)) < 0) 298 goto syserr; 299 if (fstat(fd, &stb)) { 300 syserr: run_err("%s: %s", name, strerror(errno)); 301 goto next; 302 } 303 switch (stb.st_mode & S_IFMT) { 304 case S_IFREG: 305 break; 306 case S_IFDIR: 307 if (iamrecursive) { 308 rsource(name, &stb); 309 goto next; 310 } 311 /* FALLTHROUGH */ 312 default: 313 run_err("%s: not a regular file", name); 314 goto next; 315 } 316 if ((last = strrchr(name, '/')) == NULL) 317 last = name; 318 else 319 ++last; 320 if (pflag) { 321 /* 322 * Make it compatible with possible future 323 * versions expecting microseconds. 324 */ 325 (void)snprintf(buf, sizeof(buf), "T%ld 0 %ld 0\n", 326 (long)stb.st_mtime, 327 (long)stb.st_atime); 328 (void)write(remout, buf, strlen(buf)); 329 if (response() < 0) 330 goto next; 331 } 332 #define MODEMASK (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) 333 (void)snprintf(buf, sizeof(buf), "C%04o %lu %s\n", 334 stb.st_mode & MODEMASK, (unsigned long)stb.st_size, last); 335 (void)write(remout, buf, strlen(buf)); 336 if (response() < 0) 337 goto next; 338 if ((bp = allocbuf(&buffer, fd, BUFSIZ)) == NULL) { 339 next: (void)close(fd); 340 continue; 341 } 342 343 /* Keep writing after an error so that we stay sync'd up. */ 344 for (haderr = i = 0; i < stb.st_size; i += bp->cnt) { 345 amt = bp->cnt; 346 if (i + amt > stb.st_size) 347 amt = stb.st_size - i; 348 if (!haderr) { 349 result = read(fd, bp->buf, amt); 350 if (result != amt) 351 haderr = result >= 0 ? EIO : errno; 352 } 353 if (haderr) 354 (void)write(remout, bp->buf, amt); 355 else { 356 result = write(remout, bp->buf, amt); 357 if (result != amt) 358 haderr = result >= 0 ? EIO : errno; 359 } 360 } 361 if (close(fd) && !haderr) 362 haderr = errno; 363 if (!haderr) 364 (void)write(remout, "", 1); 365 else 366 run_err("%s: %s", name, strerror(haderr)); 367 (void)response(); 368 } 369 } 370 371 void 372 rsource(name, statp) 373 char *name; 374 struct stat *statp; 375 { 376 DIR *dirp; 377 struct dirent *dp; 378 char *last, *vect[1], path[MAXPATHLEN]; 379 380 if (!(dirp = opendir(name))) { 381 run_err("%s: %s", name, strerror(errno)); 382 return; 383 } 384 last = strrchr(name, '/'); 385 if (last == 0) 386 last = name; 387 else 388 last++; 389 if (pflag) { 390 (void)snprintf(path, sizeof(path), "T%ld 0 %ld 0\n", 391 (long)statp->st_mtime, 392 (long)statp->st_atime); 393 (void)write(remout, path, strlen(path)); 394 if (response() < 0) { 395 closedir(dirp); 396 return; 397 } 398 } 399 (void)snprintf(path, sizeof(path), 400 "D%04o %d %s\n", statp->st_mode & MODEMASK, 0, last); 401 (void)write(remout, path, strlen(path)); 402 if (response() < 0) { 403 closedir(dirp); 404 return; 405 } 406 while ((dp = readdir(dirp))) { 407 if (dp->d_ino == 0) 408 continue; 409 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 410 continue; 411 if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) { 412 run_err("%s/%s: name too long", name, dp->d_name); 413 continue; 414 } 415 (void)snprintf(path, sizeof(path), "%s/%s", name, dp->d_name); 416 vect[0] = path; 417 source(1, vect); 418 } 419 (void)closedir(dirp); 420 (void)write(remout, "E\n", 2); 421 (void)response(); 422 } 423 424 void 425 sink(argc, argv) 426 int argc; 427 char *argv[]; 428 { 429 static BUF buffer; 430 struct stat stb; 431 struct timeval tv[2]; 432 enum { YES, NO, DISPLAYED } wrerr; 433 BUF *bp; 434 off_t i, j, size; 435 int amt, count, exists, first, mask, mode, ofd, omode; 436 int setimes, targisdir, wrerrno = 0; 437 char ch, *cp, *np, *targ, *why, *vect[1], buf[BUFSIZ]; 438 439 #define atime tv[0] 440 #define mtime tv[1] 441 #define SCREWUP(str) { why = str; goto screwup; } 442 443 setimes = targisdir = 0; 444 mask = umask(0); 445 if (!pflag) 446 (void)umask(mask); 447 if (argc != 1) { 448 run_err("ambiguous target"); 449 exit(1); 450 } 451 targ = *argv; 452 if (targetshouldbedirectory) 453 verifydir(targ); 454 (void)write(remout, "", 1); 455 if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) 456 targisdir = 1; 457 for (first = 1;; first = 0) { 458 cp = buf; 459 if (read(remin, cp, 1) <= 0) 460 return; 461 if (*cp++ == '\n') 462 SCREWUP("unexpected <newline>"); 463 do { 464 if (read(remin, &ch, sizeof(ch)) != sizeof(ch)) 465 SCREWUP("lost connection"); 466 *cp++ = ch; 467 } while (cp < &buf[BUFSIZ - 1] && ch != '\n'); 468 *cp = 0; 469 470 if (buf[0] == '\01' || buf[0] == '\02') { 471 if (iamremote == 0) 472 (void)write(STDERR_FILENO, 473 buf + 1, strlen(buf + 1)); 474 if (buf[0] == '\02') 475 exit(1); 476 ++errs; 477 continue; 478 } 479 if (buf[0] == 'E') { 480 (void)write(remout, "", 1); 481 return; 482 } 483 484 if (ch == '\n') 485 *--cp = 0; 486 487 cp = buf; 488 if (*cp == 'T') { 489 setimes++; 490 cp++; 491 mtime.tv_sec = strtol(cp, &cp, 10); 492 if (!cp || *cp++ != ' ') 493 SCREWUP("mtime.sec not delimited"); 494 mtime.tv_usec = strtol(cp, &cp, 10); 495 if (!cp || *cp++ != ' ') 496 SCREWUP("mtime.usec not delimited"); 497 atime.tv_sec = strtol(cp, &cp, 10); 498 if (!cp || *cp++ != ' ') 499 SCREWUP("atime.sec not delimited"); 500 atime.tv_usec = strtol(cp, &cp, 10); 501 if (!cp || *cp++ != '\0') 502 SCREWUP("atime.usec not delimited"); 503 (void)write(remout, "", 1); 504 continue; 505 } 506 if (*cp != 'C' && *cp != 'D') { 507 /* 508 * Check for the case "rcp remote:foo\* local:bar". 509 * In this case, the line "No match." can be returned 510 * by the shell before the rcp command on the remote is 511 * executed so the ^Aerror_message convention isn't 512 * followed. 513 */ 514 if (first) { 515 run_err("%s", cp); 516 exit(1); 517 } 518 SCREWUP("expected control record"); 519 } 520 mode = 0; 521 for (++cp; cp < buf + 5; cp++) { 522 if (*cp < '0' || *cp > '7') 523 SCREWUP("bad mode"); 524 mode = (mode << 3) | (*cp - '0'); 525 } 526 if (*cp++ != ' ') 527 SCREWUP("mode not delimited"); 528 529 for (size = 0; isdigit(*cp);) 530 size = size * 10 + (*cp++ - '0'); 531 if (*cp++ != ' ') 532 SCREWUP("size not delimited"); 533 if (targisdir) { 534 static char *namebuf; 535 static int cursize; 536 size_t need; 537 538 need = strlen(targ) + strlen(cp) + 250; 539 if (need > cursize) { 540 if (!(namebuf = malloc(need))) 541 run_err("%s", strerror(errno)); 542 } 543 (void)snprintf(namebuf, need, "%s%s%s", targ, 544 *targ ? "/" : "", cp); 545 np = namebuf; 546 } else 547 np = targ; 548 exists = stat(np, &stb) == 0; 549 if (buf[0] == 'D') { 550 int mod_flag = pflag; 551 if (exists) { 552 if (!S_ISDIR(stb.st_mode)) { 553 errno = ENOTDIR; 554 goto bad; 555 } 556 if (pflag) 557 (void)chmod(np, mode); 558 } else { 559 /* Handle copying from a read-only directory */ 560 mod_flag = 1; 561 if (mkdir(np, mode | S_IRWXU) < 0) 562 goto bad; 563 } 564 vect[0] = np; 565 sink(1, vect); 566 if (setimes) { 567 setimes = 0; 568 if (utimes(np, tv) < 0) 569 run_err("%s: set times: %s", 570 np, strerror(errno)); 571 } 572 if (mod_flag) 573 (void)chmod(np, mode); 574 continue; 575 } 576 omode = mode; 577 mode |= S_IWRITE; 578 if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { 579 bad: run_err("%s: %s", np, strerror(errno)); 580 continue; 581 } 582 (void)write(remout, "", 1); 583 if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == NULL) { 584 (void)close(ofd); 585 continue; 586 } 587 cp = bp->buf; 588 wrerr = NO; 589 for (count = i = 0; i < size; i += BUFSIZ) { 590 amt = BUFSIZ; 591 if (i + amt > size) 592 amt = size - i; 593 count += amt; 594 do { 595 j = read(remin, cp, amt); 596 if (j <= 0) { 597 run_err("%s", j ? strerror(errno) : 598 "dropped connection"); 599 exit(1); 600 } 601 amt -= j; 602 cp += j; 603 } while (amt > 0); 604 if (count == bp->cnt) { 605 /* Keep reading so we stay sync'd up. */ 606 if (wrerr == NO) { 607 j = write(ofd, bp->buf, count); 608 if (j != count) { 609 wrerr = YES; 610 wrerrno = j >= 0 ? EIO : errno; 611 } 612 } 613 count = 0; 614 cp = bp->buf; 615 } 616 } 617 if (count != 0 && wrerr == NO && 618 (j = write(ofd, bp->buf, count)) != count) { 619 wrerr = YES; 620 wrerrno = j >= 0 ? EIO : errno; 621 } 622 if (ftruncate(ofd, size)) { 623 run_err("%s: truncate: %s", np, strerror(errno)); 624 wrerr = DISPLAYED; 625 } 626 if (pflag) { 627 if (exists || omode != mode) 628 if (fchmod(ofd, omode)) 629 run_err("%s: set mode: %s", 630 np, strerror(errno)); 631 } else { 632 if (!exists && omode != mode) 633 if (fchmod(ofd, omode & ~mask)) 634 run_err("%s: set mode: %s", 635 np, strerror(errno)); 636 } 637 (void)close(ofd); 638 (void)response(); 639 if (setimes && wrerr == NO) { 640 setimes = 0; 641 if (utimes(np, tv) < 0) { 642 run_err("%s: set times: %s", 643 np, strerror(errno)); 644 wrerr = DISPLAYED; 645 } 646 } 647 switch(wrerr) { 648 case YES: 649 run_err("%s: %s", np, strerror(wrerrno)); 650 break; 651 case NO: 652 (void)write(remout, "", 1); 653 break; 654 case DISPLAYED: 655 break; 656 } 657 } 658 screwup: 659 run_err("protocol error: %s", why); 660 exit(1); 661 } 662 663 int 664 response() 665 { 666 char ch, *cp, resp, rbuf[BUFSIZ]; 667 668 if (read(remin, &resp, sizeof(resp)) != sizeof(resp)) 669 lostconn(0); 670 671 cp = rbuf; 672 switch(resp) { 673 case 0: /* ok */ 674 return (0); 675 default: 676 *cp++ = resp; 677 /* FALLTHROUGH */ 678 case 1: /* error, followed by error msg */ 679 case 2: /* fatal error, "" */ 680 do { 681 if (read(remin, &ch, sizeof(ch)) != sizeof(ch)) 682 lostconn(0); 683 *cp++ = ch; 684 } while (cp < &rbuf[BUFSIZ] && ch != '\n'); 685 686 if (!iamremote) 687 (void)write(STDERR_FILENO, rbuf, cp - rbuf); 688 ++errs; 689 if (resp == 1) 690 return (-1); 691 exit(1); 692 } 693 /* NOTREACHED */ 694 } 695 696 void 697 usage() 698 { 699 (void)fprintf(stderr, "%s\n%s\n", 700 "usage: rcp [-5FKpx] [-P port] f1 f2", 701 " rcp [-5FKprx] [-P port] f1 ... fn directory"); 702 exit(1); 703 } 704 705 #include <stdarg.h> 706 707 void 708 run_err(const char *fmt, ...) 709 { 710 static FILE *fp; 711 va_list ap; 712 va_start(ap, fmt); 713 714 ++errs; 715 if (fp == NULL && !(fp = fdopen(remout, "w"))) 716 return; 717 (void)fprintf(fp, "%c", 0x01); 718 (void)fprintf(fp, "rcp: "); 719 (void)vfprintf(fp, fmt, ap); 720 (void)fprintf(fp, "\n"); 721 (void)fflush(fp); 722 723 if (!iamremote) 724 vwarnx(fmt, ap); 725 726 va_end(ap); 727 } 728 729 /* 730 * This function executes the given command as the specified user on the 731 * given host. This returns < 0 if execution fails, and >= 0 otherwise. This 732 * assigns the input and output file descriptors on success. 733 * 734 * If it cannot create necessary pipes it exits with error message. 735 */ 736 737 int 738 do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout) 739 { 740 int pin[2], pout[2], reserved[2]; 741 742 /* 743 * Reserve two descriptors so that the real pipes won't get 744 * descriptors 0 and 1 because that will screw up dup2 below. 745 */ 746 pipe(reserved); 747 748 /* Create a socket pair for communicating with rsh. */ 749 if (pipe(pin) < 0) { 750 perror("pipe"); 751 exit(255); 752 } 753 if (pipe(pout) < 0) { 754 perror("pipe"); 755 exit(255); 756 } 757 758 /* Free the reserved descriptors. */ 759 close(reserved[0]); 760 close(reserved[1]); 761 762 /* For a child to execute the command on the remote host using rsh. */ 763 if (fork() == 0) { 764 char *args[100]; 765 unsigned int i; 766 767 /* Child. */ 768 close(pin[1]); 769 close(pout[0]); 770 dup2(pin[0], 0); 771 dup2(pout[1], 1); 772 close(pin[0]); 773 close(pout[1]); 774 775 i = 0; 776 args[i++] = RSH_PROGRAM; 777 if (usekrb5) 778 args[i++] = "-5"; 779 if (usebroken) 780 args[i++] = "-K"; 781 if (doencrypt) 782 args[i++] = "-x"; 783 if (noencrypt) 784 args[i++] = "-z"; 785 if (port != NULL) { 786 args[i++] = "-p"; 787 args[i++] = port; 788 } 789 if (remuser != NULL) { 790 args[i++] = "-l"; 791 args[i++] = remuser; 792 } 793 args[i++] = host; 794 args[i++] = cmd; 795 args[i++] = NULL; 796 797 execvp(RSH_PROGRAM, args); 798 perror(RSH_PROGRAM); 799 exit(1); 800 } 801 /* Parent. Close the other side, and return the local side. */ 802 close(pin[0]); 803 *fdout = pin[1]; 804 close(pout[1]); 805 *fdin = pout[0]; 806 return 0; 807 } 808