rcp.c revision 46057
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#ifndef lint 35static char const copyright[] = 36"@(#) Copyright (c) 1983, 1990, 1992, 1993\n\ 37 The Regents of the University of California. All rights reserved.\n"; 38#endif /* not lint */ 39 40#ifndef lint 41#if 0 42static char sccsid[] = "@(#)rcp.c 8.2 (Berkeley) 4/2/94"; 43#endif 44static const char rcsid[] = 45 "$Id: rcp.c,v 1.21 1998/10/09 06:31:45 markm Exp $"; 46#endif /* not lint */ 47 48#include <sys/param.h> 49#include <sys/stat.h> 50#include <sys/time.h> 51#include <sys/socket.h> 52#include <netinet/in.h> 53#include <netinet/in_systm.h> 54#include <netinet/ip.h> 55 56#include <ctype.h> 57#include <dirent.h> 58#include <err.h> 59#include <errno.h> 60#include <fcntl.h> 61#include <netdb.h> 62#include <pwd.h> 63#include <signal.h> 64#include <stdio.h> 65#include <stdlib.h> 66#include <string.h> 67#include <string.h> 68#include <unistd.h> 69#include <libutil.h> 70 71#include "pathnames.h" 72#include "extern.h" 73 74#ifdef KERBEROS 75#include <des.h> 76#include <krb.h> 77 78char dst_realm_buf[REALM_SZ]; 79char *dest_realm = NULL; 80int use_kerberos = 1; 81CREDENTIALS cred; 82Key_schedule schedule; 83extern char *krb_realmofhost(); 84#ifdef CRYPT 85int doencrypt = 0; 86#define OPTIONS "dfKk:prtx" 87#else 88#define OPTIONS "dfKk:prt" 89#endif 90#else 91#define OPTIONS "dfprt" 92#endif 93 94struct passwd *pwd; 95u_short port; 96uid_t userid; 97int errs, rem; 98int pflag, iamremote, iamrecursive, targetshouldbedirectory; 99 100static int argc_copy; 101static char **argv_copy; 102 103#define CMDNEEDS 64 104char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ 105 106#ifdef KERBEROS 107int kerberos __P((char **, char *, char *, char *)); 108void oldw __P((const char *, ...)); 109#endif 110int response __P((void)); 111void rsource __P((char *, struct stat *)); 112void sink __P((int, char *[])); 113void source __P((int, char *[])); 114void tolocal __P((int, char *[])); 115void toremote __P((char *, int, char *[])); 116void usage __P((void)); 117 118int 119main(argc, argv) 120 int argc; 121 char *argv[]; 122{ 123 struct servent *sp; 124 int ch, fflag, tflag; 125 char *targ, *shell; 126 int i; 127#ifdef KERBEROS 128 char *k; 129#endif 130 131 /* 132 * Prepare for execing ourselves. 133 */ 134 135 argc_copy = argc + 1; 136 argv_copy = malloc((argc_copy + 1) * sizeof(*argv_copy)); 137 if (argv_copy == NULL) 138 err(1, "malloc"); 139 argv_copy[0] = argv[0]; 140 argv_copy[1] = "-K"; 141 for(i = 1; i < argc; ++i) { 142 argv_copy[i + 1] = strdup(argv[i]); 143 if (argv_copy[i + 1] == NULL) 144 errx(1, "strdup: out of memory"); 145 } 146 argv_copy[argc + 1] = NULL; 147 148 fflag = tflag = 0; 149 while ((ch = getopt(argc, argv, OPTIONS)) != -1) 150 switch(ch) { /* User-visible flags. */ 151 case 'K': 152#ifdef KERBEROS 153 use_kerberos = 0; 154#endif 155 break; 156#ifdef KERBEROS 157 case 'k': 158 dest_realm = dst_realm_buf; 159 (void)strncpy(dst_realm_buf, optarg, REALM_SZ - 1); 160 dst_realm_buf[REALM_SZ - 1] = '\0'; 161 break; 162#ifdef CRYPT 163 case 'x': 164 doencrypt = 1; 165 /* des_set_key(cred.session, schedule); */ 166 break; 167#endif 168#endif 169 case 'p': 170 pflag = 1; 171 break; 172 case 'r': 173 iamrecursive = 1; 174 break; 175 /* Server options. */ 176 case 'd': 177 targetshouldbedirectory = 1; 178 break; 179 case 'f': /* "from" */ 180 iamremote = 1; 181 fflag = 1; 182 break; 183 case 't': /* "to" */ 184 iamremote = 1; 185 tflag = 1; 186 break; 187 case '?': 188 default: 189 usage(); 190 } 191 argc -= optind; 192 argv += optind; 193 194#ifdef KERBEROS 195 k = auth_getval("auth_list"); 196 if (k && !strstr(k, "kerberos")) 197 use_kerberos = 0; 198 if (use_kerberos) { 199#ifdef CRYPT 200 shell = doencrypt ? "ekshell" : "kshell"; 201#else 202 shell = "kshell"; 203#endif 204 if ((sp = getservbyname(shell, "tcp")) == NULL) { 205 use_kerberos = 0; 206 oldw("can't get entry for %s/tcp service", shell); 207 sp = getservbyname(shell = "shell", "tcp"); 208 } 209 } else 210 sp = getservbyname(shell = "shell", "tcp"); 211#else 212 sp = getservbyname(shell = "shell", "tcp"); 213#endif 214 if (sp == NULL) 215 errx(1, "%s/tcp: unknown service", shell); 216 port = sp->s_port; 217 218 if ((pwd = getpwuid(userid = getuid())) == NULL) 219 errx(1, "unknown user %d", (int)userid); 220 221 rem = STDIN_FILENO; /* XXX */ 222 223 if (fflag) { /* Follow "protocol", send data. */ 224 (void)response(); 225 (void)setuid(userid); 226 source(argc, argv); 227 exit(errs); 228 } 229 230 if (tflag) { /* Receive data. */ 231 (void)setuid(userid); 232 sink(argc, argv); 233 exit(errs); 234 } 235 236 if (argc < 2) 237 usage(); 238 if (argc > 2) 239 targetshouldbedirectory = 1; 240 241 rem = -1; 242 /* Command to be executed on remote system using "rsh". */ 243#ifdef KERBEROS 244 (void)snprintf(cmd, sizeof(cmd), 245 "rcp%s%s%s%s", iamrecursive ? " -r" : "", 246#ifdef CRYPT 247 (doencrypt && use_kerberos ? " -x" : ""), 248#else 249 "", 250#endif 251 pflag ? " -p" : "", targetshouldbedirectory ? " -d" : ""); 252#else 253 (void)snprintf(cmd, sizeof(cmd), "rcp%s%s%s", 254 iamrecursive ? " -r" : "", pflag ? " -p" : "", 255 targetshouldbedirectory ? " -d" : ""); 256#endif 257 258 (void)signal(SIGPIPE, lostconn); 259 260 if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */ 261 toremote(targ, argc, argv); 262 else { 263 tolocal(argc, argv); /* Dest is local host. */ 264 if (targetshouldbedirectory) 265 verifydir(argv[argc - 1]); 266 } 267 exit(errs); 268} 269 270void 271toremote(targ, argc, argv) 272 char *targ, *argv[]; 273 int argc; 274{ 275 int i, len, tos; 276 char *bp, *host, *src, *suser, *thost, *tuser; 277 278 *targ++ = 0; 279 if (*targ == 0) 280 targ = "."; 281 282 if ((thost = strchr(argv[argc - 1], '@'))) { 283 /* user@host */ 284 *thost++ = 0; 285 tuser = argv[argc - 1]; 286 if (*tuser == '\0') 287 tuser = NULL; 288 else if (!okname(tuser)) 289 exit(1); 290 } else { 291 thost = argv[argc - 1]; 292 tuser = NULL; 293 } 294 295 for (i = 0; i < argc - 1; i++) { 296 src = colon(argv[i]); 297 if (src) { /* remote to remote */ 298 *src++ = 0; 299 if (*src == 0) 300 src = "."; 301 host = strchr(argv[i], '@'); 302 len = strlen(_PATH_RSH) + strlen(argv[i]) + 303 strlen(src) + (tuser ? strlen(tuser) : 0) + 304 strlen(thost) + strlen(targ) + CMDNEEDS + 20; 305 if (!(bp = malloc(len))) 306 err(1, NULL); 307 if (host) { 308 *host++ = 0; 309 suser = argv[i]; 310 if (*suser == '\0') 311 suser = pwd->pw_name; 312 else if (!okname(suser)) 313 continue; 314 (void)snprintf(bp, len, 315 "%s %s -l %s -n %s %s '%s%s%s:%s'", 316 _PATH_RSH, host, suser, cmd, src, 317 tuser ? tuser : "", tuser ? "@" : "", 318 thost, targ); 319 } else 320 (void)snprintf(bp, len, 321 "exec %s %s -n %s %s '%s%s%s:%s'", 322 _PATH_RSH, argv[i], cmd, src, 323 tuser ? tuser : "", tuser ? "@" : "", 324 thost, targ); 325 (void)susystem(bp, userid); 326 (void)free(bp); 327 } else { /* local to remote */ 328 if (rem == -1) { 329 len = strlen(targ) + CMDNEEDS + 20; 330 if (!(bp = malloc(len))) 331 err(1, NULL); 332 (void)snprintf(bp, len, "%s -t %s", cmd, targ); 333 host = thost; 334#ifdef KERBEROS 335 if (use_kerberos) 336 rem = kerberos(&host, bp, 337 pwd->pw_name, 338 tuser ? tuser : pwd->pw_name); 339 else 340#endif 341 rem = rcmd(&host, port, pwd->pw_name, 342 tuser ? tuser : pwd->pw_name, 343 bp, 0); 344 if (rem < 0) 345 exit(1); 346 tos = IPTOS_THROUGHPUT; 347 if (setsockopt(rem, IPPROTO_IP, IP_TOS, 348 &tos, sizeof(int)) < 0) 349 warn("TOS (ignored)"); 350 if (response() < 0) 351 exit(1); 352 (void)free(bp); 353 (void)setuid(userid); 354 } 355 source(1, argv+i); 356 } 357 } 358} 359 360void 361tolocal(argc, argv) 362 int argc; 363 char *argv[]; 364{ 365 int i, len, tos; 366 char *bp, *host, *src, *suser; 367 368 for (i = 0; i < argc - 1; i++) { 369 if (!(src = colon(argv[i]))) { /* Local to local. */ 370 len = strlen(_PATH_CP) + strlen(argv[i]) + 371 strlen(argv[argc - 1]) + 20; 372 if (!(bp = malloc(len))) 373 err(1, NULL); 374 (void)snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP, 375 iamrecursive ? " -PR" : "", pflag ? " -p" : "", 376 argv[i], argv[argc - 1]); 377 if (susystem(bp, userid)) 378 ++errs; 379 (void)free(bp); 380 continue; 381 } 382 *src++ = 0; 383 if (*src == 0) 384 src = "."; 385 if ((host = strchr(argv[i], '@')) == NULL) { 386 host = argv[i]; 387 suser = pwd->pw_name; 388 } else { 389 *host++ = 0; 390 suser = argv[i]; 391 if (*suser == '\0') 392 suser = pwd->pw_name; 393 else if (!okname(suser)) 394 continue; 395 } 396 len = strlen(src) + CMDNEEDS + 20; 397 if ((bp = malloc(len)) == NULL) 398 err(1, NULL); 399 (void)snprintf(bp, len, "%s -f %s", cmd, src); 400 rem = 401#ifdef KERBEROS 402 use_kerberos ? 403 kerberos(&host, bp, pwd->pw_name, suser) : 404#endif 405 rcmd(&host, port, pwd->pw_name, suser, bp, 0); 406 (void)free(bp); 407 if (rem < 0) { 408 ++errs; 409 continue; 410 } 411 (void)seteuid(userid); 412 tos = IPTOS_THROUGHPUT; 413 if (setsockopt(rem, IPPROTO_IP, IP_TOS, &tos, sizeof(int)) < 0) 414 warn("TOS (ignored)"); 415 sink(1, argv + argc - 1); 416 (void)seteuid(0); 417 (void)close(rem); 418 rem = -1; 419 } 420} 421 422void 423source(argc, argv) 424 int argc; 425 char *argv[]; 426{ 427 struct stat stb; 428 static BUF buffer; 429 BUF *bp; 430 off_t i; 431 int amt, fd, haderr, indx, result; 432 char *last, *name, buf[BUFSIZ]; 433 434 for (indx = 0; indx < argc; ++indx) { 435 name = argv[indx]; 436 if ((fd = open(name, O_RDONLY, 0)) < 0) 437 goto syserr; 438 if (fstat(fd, &stb)) { 439syserr: run_err("%s: %s", name, strerror(errno)); 440 goto next; 441 } 442 switch (stb.st_mode & S_IFMT) { 443 case S_IFREG: 444 break; 445 case S_IFDIR: 446 if (iamrecursive) { 447 rsource(name, &stb); 448 goto next; 449 } 450 /* FALLTHROUGH */ 451 default: 452 run_err("%s: not a regular file", name); 453 goto next; 454 } 455 if ((last = strrchr(name, '/')) == NULL) 456 last = name; 457 else 458 ++last; 459 if (pflag) { 460 /* 461 * Make it compatible with possible future 462 * versions expecting microseconds. 463 */ 464 (void)snprintf(buf, sizeof(buf), "T%ld 0 %ld 0\n", 465 (long)stb.st_mtimespec.tv_sec, 466 (long)stb.st_atimespec.tv_sec); 467 (void)write(rem, buf, strlen(buf)); 468 if (response() < 0) 469 goto next; 470 } 471#define MODEMASK (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO) 472 (void)snprintf(buf, sizeof(buf), "C%04o %qd %s\n", 473 stb.st_mode & MODEMASK, stb.st_size, last); 474 (void)write(rem, buf, strlen(buf)); 475 if (response() < 0) 476 goto next; 477 if ((bp = allocbuf(&buffer, fd, BUFSIZ)) == NULL) { 478next: (void)close(fd); 479 continue; 480 } 481 482 /* Keep writing after an error so that we stay sync'd up. */ 483 for (haderr = i = 0; i < stb.st_size; i += bp->cnt) { 484 amt = bp->cnt; 485 if (i + amt > stb.st_size) 486 amt = stb.st_size - i; 487 if (!haderr) { 488 result = read(fd, bp->buf, amt); 489 if (result != amt) 490 haderr = result >= 0 ? EIO : errno; 491 } 492 if (haderr) 493 (void)write(rem, bp->buf, amt); 494 else { 495 result = write(rem, bp->buf, amt); 496 if (result != amt) 497 haderr = result >= 0 ? EIO : errno; 498 } 499 } 500 if (close(fd) && !haderr) 501 haderr = errno; 502 if (!haderr) 503 (void)write(rem, "", 1); 504 else 505 run_err("%s: %s", name, strerror(haderr)); 506 (void)response(); 507 } 508} 509 510void 511rsource(name, statp) 512 char *name; 513 struct stat *statp; 514{ 515 DIR *dirp; 516 struct dirent *dp; 517 char *last, *vect[1], path[MAXPATHLEN]; 518 519 if (!(dirp = opendir(name))) { 520 run_err("%s: %s", name, strerror(errno)); 521 return; 522 } 523 last = strrchr(name, '/'); 524 if (last == 0) 525 last = name; 526 else 527 last++; 528 if (pflag) { 529 (void)snprintf(path, sizeof(path), "T%ld 0 %ld 0\n", 530 (long)statp->st_mtimespec.tv_sec, 531 (long)statp->st_atimespec.tv_sec); 532 (void)write(rem, path, strlen(path)); 533 if (response() < 0) { 534 closedir(dirp); 535 return; 536 } 537 } 538 (void)snprintf(path, sizeof(path), 539 "D%04o %d %s\n", statp->st_mode & MODEMASK, 0, last); 540 (void)write(rem, path, strlen(path)); 541 if (response() < 0) { 542 closedir(dirp); 543 return; 544 } 545 while ((dp = readdir(dirp))) { 546 if (dp->d_ino == 0) 547 continue; 548 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 549 continue; 550 if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) { 551 run_err("%s/%s: name too long", name, dp->d_name); 552 continue; 553 } 554 (void)snprintf(path, sizeof(path), "%s/%s", name, dp->d_name); 555 vect[0] = path; 556 source(1, vect); 557 } 558 (void)closedir(dirp); 559 (void)write(rem, "E\n", 2); 560 (void)response(); 561} 562 563void 564sink(argc, argv) 565 int argc; 566 char *argv[]; 567{ 568 static BUF buffer; 569 struct stat stb; 570 struct timeval tv[2]; 571 enum { YES, NO, DISPLAYED } wrerr; 572 BUF *bp; 573 off_t i, j, size; 574 int amt, count, exists, first, mask, mode, ofd, omode; 575 int setimes, targisdir, wrerrno = 0; 576 char ch, *cp, *np, *targ, *why, *vect[1], buf[BUFSIZ]; 577 578#define atime tv[0] 579#define mtime tv[1] 580#define SCREWUP(str) { why = str; goto screwup; } 581 582 setimes = targisdir = 0; 583 mask = umask(0); 584 if (!pflag) 585 (void)umask(mask); 586 if (argc != 1) { 587 run_err("ambiguous target"); 588 exit(1); 589 } 590 targ = *argv; 591 if (targetshouldbedirectory) 592 verifydir(targ); 593 (void)write(rem, "", 1); 594 if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) 595 targisdir = 1; 596 for (first = 1;; first = 0) { 597 cp = buf; 598 if (read(rem, cp, 1) <= 0) 599 return; 600 if (*cp++ == '\n') 601 SCREWUP("unexpected <newline>"); 602 do { 603 if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) 604 SCREWUP("lost connection"); 605 *cp++ = ch; 606 } while (cp < &buf[BUFSIZ - 1] && ch != '\n'); 607 *cp = 0; 608 609 if (buf[0] == '\01' || buf[0] == '\02') { 610 if (iamremote == 0) 611 (void)write(STDERR_FILENO, 612 buf + 1, strlen(buf + 1)); 613 if (buf[0] == '\02') 614 exit(1); 615 ++errs; 616 continue; 617 } 618 if (buf[0] == 'E') { 619 (void)write(rem, "", 1); 620 return; 621 } 622 623 if (ch == '\n') 624 *--cp = 0; 625 626 cp = buf; 627 if (*cp == 'T') { 628 setimes++; 629 cp++; 630 mtime.tv_sec = strtol(cp, &cp, 10); 631 if (!cp || *cp++ != ' ') 632 SCREWUP("mtime.sec not delimited"); 633 mtime.tv_usec = strtol(cp, &cp, 10); 634 if (!cp || *cp++ != ' ') 635 SCREWUP("mtime.usec not delimited"); 636 atime.tv_sec = strtol(cp, &cp, 10); 637 if (!cp || *cp++ != ' ') 638 SCREWUP("atime.sec not delimited"); 639 atime.tv_usec = strtol(cp, &cp, 10); 640 if (!cp || *cp++ != '\0') 641 SCREWUP("atime.usec not delimited"); 642 (void)write(rem, "", 1); 643 continue; 644 } 645 if (*cp != 'C' && *cp != 'D') { 646 /* 647 * Check for the case "rcp remote:foo\* local:bar". 648 * In this case, the line "No match." can be returned 649 * by the shell before the rcp command on the remote is 650 * executed so the ^Aerror_message convention isn't 651 * followed. 652 */ 653 if (first) { 654 run_err("%s", cp); 655 exit(1); 656 } 657 SCREWUP("expected control record"); 658 } 659 mode = 0; 660 for (++cp; cp < buf + 5; cp++) { 661 if (*cp < '0' || *cp > '7') 662 SCREWUP("bad mode"); 663 mode = (mode << 3) | (*cp - '0'); 664 } 665 if (*cp++ != ' ') 666 SCREWUP("mode not delimited"); 667 668 for (size = 0; isdigit(*cp);) 669 size = size * 10 + (*cp++ - '0'); 670 if (*cp++ != ' ') 671 SCREWUP("size not delimited"); 672 if (targisdir) { 673 static char *namebuf; 674 static int cursize; 675 size_t need; 676 677 need = strlen(targ) + strlen(cp) + 250; 678 if (need > cursize) { 679 if (!(namebuf = malloc(need))) 680 run_err("%s", strerror(errno)); 681 } 682 (void)snprintf(namebuf, need, "%s%s%s", targ, 683 *targ ? "/" : "", cp); 684 np = namebuf; 685 } else 686 np = targ; 687 exists = stat(np, &stb) == 0; 688 if (buf[0] == 'D') { 689 int mod_flag = pflag; 690 if (exists) { 691 if (!S_ISDIR(stb.st_mode)) { 692 errno = ENOTDIR; 693 goto bad; 694 } 695 if (pflag) 696 (void)chmod(np, mode); 697 } else { 698 /* Handle copying from a read-only directory */ 699 mod_flag = 1; 700 if (mkdir(np, mode | S_IRWXU) < 0) 701 goto bad; 702 } 703 vect[0] = np; 704 sink(1, vect); 705 if (setimes) { 706 setimes = 0; 707 if (utimes(np, tv) < 0) 708 run_err("%s: set times: %s", 709 np, strerror(errno)); 710 } 711 if (mod_flag) 712 (void)chmod(np, mode); 713 continue; 714 } 715 omode = mode; 716 mode |= S_IWRITE; 717 if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { 718bad: run_err("%s: %s", np, strerror(errno)); 719 continue; 720 } 721 (void)write(rem, "", 1); 722 if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == NULL) { 723 (void)close(ofd); 724 continue; 725 } 726 cp = bp->buf; 727 wrerr = NO; 728 for (count = i = 0; i < size; i += BUFSIZ) { 729 amt = BUFSIZ; 730 if (i + amt > size) 731 amt = size - i; 732 count += amt; 733 do { 734 j = read(rem, cp, amt); 735 if (j <= 0) { 736 run_err("%s", j ? strerror(errno) : 737 "dropped connection"); 738 exit(1); 739 } 740 amt -= j; 741 cp += j; 742 } while (amt > 0); 743 if (count == bp->cnt) { 744 /* Keep reading so we stay sync'd up. */ 745 if (wrerr == NO) { 746 j = write(ofd, bp->buf, count); 747 if (j != count) { 748 wrerr = YES; 749 wrerrno = j >= 0 ? EIO : errno; 750 } 751 } 752 count = 0; 753 cp = bp->buf; 754 } 755 } 756 if (count != 0 && wrerr == NO && 757 (j = write(ofd, bp->buf, count)) != count) { 758 wrerr = YES; 759 wrerrno = j >= 0 ? EIO : errno; 760 } 761 if (ftruncate(ofd, size)) { 762 run_err("%s: truncate: %s", np, strerror(errno)); 763 wrerr = DISPLAYED; 764 } 765 if (pflag) { 766 if (exists || omode != mode) 767 if (fchmod(ofd, omode)) 768 run_err("%s: set mode: %s", 769 np, strerror(errno)); 770 } else { 771 if (!exists && omode != mode) 772 if (fchmod(ofd, omode & ~mask)) 773 run_err("%s: set mode: %s", 774 np, strerror(errno)); 775 } 776 (void)close(ofd); 777 (void)response(); 778 if (setimes && wrerr == NO) { 779 setimes = 0; 780 if (utimes(np, tv) < 0) { 781 run_err("%s: set times: %s", 782 np, strerror(errno)); 783 wrerr = DISPLAYED; 784 } 785 } 786 switch(wrerr) { 787 case YES: 788 run_err("%s: %s", np, strerror(wrerrno)); 789 break; 790 case NO: 791 (void)write(rem, "", 1); 792 break; 793 case DISPLAYED: 794 break; 795 } 796 } 797screwup: 798 run_err("protocol error: %s", why); 799 exit(1); 800} 801 802#ifdef KERBEROS 803int 804kerberos(host, bp, locuser, user) 805 char **host, *bp, *locuser, *user; 806{ 807 if (use_kerberos) { 808 setuid(getuid()); 809 rem = KSUCCESS; 810 errno = 0; 811 if (dest_realm == NULL) 812 dest_realm = krb_realmofhost(*host); 813 rem = 814#ifdef CRYPT 815 doencrypt ? 816 krcmd_mutual(host, 817 port, user, bp, 0, dest_realm, &cred, schedule) : 818#endif 819 krcmd(host, port, user, bp, 0, dest_realm); 820 821 if (rem < 0) { 822 if (errno == ECONNREFUSED) 823 oldw("remote host doesn't support Kerberos"); 824 else if (errno == ENOENT) 825 oldw("can't provide Kerberos authentication data"); 826 execv(_PATH_RCP, argv_copy); 827 } 828 } else { 829#ifdef CRYPT 830 if (doencrypt) 831 errx(1, 832 "the -x option requires Kerberos authentication"); 833#endif 834 rem = rcmd(host, port, locuser, user, bp, 0); 835 } 836 return (rem); 837} 838#endif /* KERBEROS */ 839 840int 841response() 842{ 843 char ch, *cp, resp, rbuf[BUFSIZ]; 844 845 if (read(rem, &resp, sizeof(resp)) != sizeof(resp)) 846 lostconn(0); 847 848 cp = rbuf; 849 switch(resp) { 850 case 0: /* ok */ 851 return (0); 852 default: 853 *cp++ = resp; 854 /* FALLTHROUGH */ 855 case 1: /* error, followed by error msg */ 856 case 2: /* fatal error, "" */ 857 do { 858 if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) 859 lostconn(0); 860 *cp++ = ch; 861 } while (cp < &rbuf[BUFSIZ] && ch != '\n'); 862 863 if (!iamremote) 864 (void)write(STDERR_FILENO, rbuf, cp - rbuf); 865 ++errs; 866 if (resp == 1) 867 return (-1); 868 exit(1); 869 } 870 /* NOTREACHED */ 871} 872 873void 874usage() 875{ 876#ifdef KERBEROS 877#ifdef CRYPT 878 (void)fprintf(stderr, "%s\n%s\n", 879 "usage: rcp [-Kpx] [-k realm] f1 f2", 880 " rcp [-Kprx] [-k realm] f1 ... fn directory"); 881#else 882 (void)fprintf(stderr, "%s\n%s\n", 883 "usage: rcp [-Kp] [-k realm] f1 f2", 884 " rcp [-Kpr] [-k realm] f1 ... fn directory"); 885#endif 886#else 887 (void)fprintf(stderr, "%s\n%s\n", 888 "usage: rcp [-p] f1 f2", 889 " rcp [-pr] f1 ... fn directory"); 890#endif 891 exit(1); 892} 893 894#if __STDC__ 895#include <stdarg.h> 896#else 897#include <varargs.h> 898#endif 899 900#ifdef KERBEROS 901void 902#if __STDC__ 903oldw(const char *fmt, ...) 904#else 905oldw(fmt, va_alist) 906 char *fmt; 907 va_dcl 908#endif 909{ 910 va_list ap; 911#if __STDC__ 912 va_start(ap, fmt); 913#else 914 va_start(ap); 915#endif 916 (void)fprintf(stderr, "rcp: "); 917 (void)vfprintf(stderr, fmt, ap); 918 (void)fprintf(stderr, ", using standard rcp\n"); 919 va_end(ap); 920} 921#endif 922 923void 924#if __STDC__ 925run_err(const char *fmt, ...) 926#else 927run_err(fmt, va_alist) 928 char *fmt; 929 va_dcl 930#endif 931{ 932 static FILE *fp; 933 va_list ap; 934#if __STDC__ 935 va_start(ap, fmt); 936#else 937 va_start(ap); 938#endif 939 940 ++errs; 941 if (fp == NULL && !(fp = fdopen(rem, "w"))) 942 return; 943 (void)fprintf(fp, "%c", 0x01); 944 (void)fprintf(fp, "rcp: "); 945 (void)vfprintf(fp, fmt, ap); 946 (void)fprintf(fp, "\n"); 947 (void)fflush(fp); 948 949 if (!iamremote) 950 vwarnx(fmt, ap); 951 952 va_end(ap); 953} 954