rcp.c revision 72445
1217309Snwhitehorn/* 2217309Snwhitehorn * Copyright (c) 1983, 1990, 1992, 1993 3217309Snwhitehorn * The Regents of the University of California. All rights reserved. 4217309Snwhitehorn * 5217309Snwhitehorn * Redistribution and use in source and binary forms, with or without 6217309Snwhitehorn * modification, are permitted provided that the following conditions 7217309Snwhitehorn * are met: 8217309Snwhitehorn * 1. Redistributions of source code must retain the above copyright 9217309Snwhitehorn * notice, this list of conditions and the following disclaimer. 10217309Snwhitehorn * 2. Redistributions in binary form must reproduce the above copyright 11217309Snwhitehorn * notice, this list of conditions and the following disclaimer in the 12217309Snwhitehorn * documentation and/or other materials provided with the distribution. 13217309Snwhitehorn * 3. All advertising materials mentioning features or use of this software 14217309Snwhitehorn * must display the following acknowledgement: 15217309Snwhitehorn * This product includes software developed by the University of 16217309Snwhitehorn * California, Berkeley and its contributors. 17217309Snwhitehorn * 4. Neither the name of the University nor the names of its contributors 18217309Snwhitehorn * may be used to endorse or promote products derived from this software 19217309Snwhitehorn * without specific prior written permission. 20217309Snwhitehorn * 21217309Snwhitehorn * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22217309Snwhitehorn * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23217309Snwhitehorn * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24217309Snwhitehorn * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25217309Snwhitehorn * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26217309Snwhitehorn * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27217309Snwhitehorn * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28217309Snwhitehorn * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29217309Snwhitehorn * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30217309Snwhitehorn * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31217309Snwhitehorn * SUCH DAMAGE. 32217309Snwhitehorn */ 33217309Snwhitehorn 34217309Snwhitehorn#include "rcp_locl.h" 35217309Snwhitehorn 36217309Snwhitehorn#define RSH_PROGRAM "rsh" 37217309Snwhitehorn#define OPTIONS "5dfKpP:rtxz" 38217309Snwhitehorn 39217309Snwhitehornstruct passwd *pwd; 40217309Snwhitehornuid_t userid; 41217309Snwhitehornint errs, remin, remout; 42217309Snwhitehornint pflag, iamremote, iamrecursive, targetshouldbedirectory; 43217309Snwhitehornint doencrypt, noencrypt; 44217309Snwhitehornint usebroken, usekrb5; 45217309Snwhitehornchar *port; 46217309Snwhitehorn 47217309Snwhitehorn#define CMDNEEDS 64 48217309Snwhitehornchar cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ 49217309Snwhitehorn 50217309Snwhitehornint response (void); 51217309Snwhitehornvoid rsource (char *, struct stat *); 52217309Snwhitehornvoid sink (int, char *[]); 53217309Snwhitehornvoid source (int, char *[]); 54217309Snwhitehornvoid tolocal (int, char *[]); 55217309Snwhitehornvoid toremote (char *, int, char *[]); 56217309Snwhitehornvoid usage (void); 57217309Snwhitehorn 58217309Snwhitehornint do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout); 59217309Snwhitehorn 60217309Snwhitehornint 61217309Snwhitehornmain(argc, argv) 62217309Snwhitehorn int argc; 63217309Snwhitehorn char *argv[]; 64217309Snwhitehorn{ 65217309Snwhitehorn int ch, fflag, tflag; 66217309Snwhitehorn char *targ; 67217309Snwhitehorn 68217309Snwhitehorn fflag = tflag = 0; 69217309Snwhitehorn while ((ch = getopt(argc, argv, OPTIONS)) != -1) 70217309Snwhitehorn switch(ch) { /* User-visible flags. */ 71217309Snwhitehorn case '5': 72217309Snwhitehorn usekrb5 = 1; 73217309Snwhitehorn break; 74217309Snwhitehorn case 'K': 75217309Snwhitehorn usebroken = 1; 76217309Snwhitehorn break; 77217309Snwhitehorn case 'P': 78217309Snwhitehorn port = optarg; 79217309Snwhitehorn break; 80217309Snwhitehorn case 'p': 81217309Snwhitehorn pflag = 1; 82217309Snwhitehorn break; 83217309Snwhitehorn case 'r': 84217309Snwhitehorn iamrecursive = 1; 85217309Snwhitehorn break; 86217309Snwhitehorn case 'x': 87217309Snwhitehorn doencrypt = 1; 88217309Snwhitehorn break; 89217309Snwhitehorn case 'z': 90217309Snwhitehorn noencrypt = 1; 91217309Snwhitehorn break; 92217309Snwhitehorn /* Server options. */ 93217309Snwhitehorn case 'd': 94217309Snwhitehorn targetshouldbedirectory = 1; 95217309Snwhitehorn break; 96217309Snwhitehorn case 'f': /* "from" */ 97217309Snwhitehorn iamremote = 1; 98217309Snwhitehorn fflag = 1; 99217309Snwhitehorn break; 100217309Snwhitehorn case 't': /* "to" */ 101217309Snwhitehorn iamremote = 1; 102217309Snwhitehorn tflag = 1; 103217309Snwhitehorn break; 104217309Snwhitehorn case '?': 105217309Snwhitehorn default: 106217309Snwhitehorn usage(); 107217309Snwhitehorn } 108217309Snwhitehorn argc -= optind; 109217309Snwhitehorn argv += optind; 110217309Snwhitehorn 111217309Snwhitehorn if ((pwd = getpwuid(userid = getuid())) == NULL) 112217309Snwhitehorn errx(1, "unknown user %d", (int)userid); 113217309Snwhitehorn 114217309Snwhitehorn remin = STDIN_FILENO; /* XXX */ 115217309Snwhitehorn remout = STDOUT_FILENO; 116217309Snwhitehorn 117217309Snwhitehorn if (fflag) { /* Follow "protocol", send data. */ 118217309Snwhitehorn (void)response(); 119217309Snwhitehorn (void)setuid(userid); 120217309Snwhitehorn source(argc, argv); 121217309Snwhitehorn exit(errs); 122217309Snwhitehorn } 123217309Snwhitehorn 124217309Snwhitehorn if (tflag) { /* Receive data. */ 125217309Snwhitehorn (void)setuid(userid); 126217309Snwhitehorn sink(argc, argv); 127217309Snwhitehorn exit(errs); 128217309Snwhitehorn } 129217309Snwhitehorn 130217309Snwhitehorn if (argc < 2) 131217309Snwhitehorn usage(); 132217309Snwhitehorn if (argc > 2) 133217309Snwhitehorn targetshouldbedirectory = 1; 134217309Snwhitehorn 135217309Snwhitehorn remin = remout = -1; 136217309Snwhitehorn /* Command to be executed on remote system using "rsh". */ 137217309Snwhitehorn (void) sprintf(cmd, "rcp%s%s%s", iamrecursive ? " -r" : "", 138217309Snwhitehorn pflag ? " -p" : "", targetshouldbedirectory ? " -d" : ""); 139217309Snwhitehorn 140217309Snwhitehorn (void)signal(SIGPIPE, lostconn); 141217309Snwhitehorn 142217309Snwhitehorn if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */ 143217309Snwhitehorn toremote(targ, argc, argv); 144217309Snwhitehorn else { 145217309Snwhitehorn tolocal(argc, argv); /* Dest is local host. */ 146217309Snwhitehorn if (targetshouldbedirectory) 147217309Snwhitehorn verifydir(argv[argc - 1]); 148217309Snwhitehorn } 149217309Snwhitehorn exit(errs); 150217309Snwhitehorn} 151217309Snwhitehorn 152217309Snwhitehornvoid 153217309Snwhitehorntoremote(targ, argc, argv) 154217309Snwhitehorn char *targ, *argv[]; 155217309Snwhitehorn int argc; 156217309Snwhitehorn{ 157217309Snwhitehorn int i, len; 158217309Snwhitehorn char *bp, *host, *src, *suser, *thost, *tuser; 159217309Snwhitehorn 160217309Snwhitehorn *targ++ = 0; 161217309Snwhitehorn if (*targ == 0) 162217309Snwhitehorn targ = "."; 163217309Snwhitehorn 164217309Snwhitehorn if ((thost = strchr(argv[argc - 1], '@'))) { 165217309Snwhitehorn /* user@host */ 166217309Snwhitehorn *thost++ = 0; 167217309Snwhitehorn tuser = argv[argc - 1]; 168217309Snwhitehorn if (*tuser == '\0') 169217309Snwhitehorn tuser = NULL; 170217309Snwhitehorn else if (!okname(tuser)) 171217309Snwhitehorn exit(1); 172217309Snwhitehorn } else { 173217309Snwhitehorn thost = argv[argc - 1]; 174217309Snwhitehorn tuser = NULL; 175217309Snwhitehorn } 176217309Snwhitehorn 177217309Snwhitehorn for (i = 0; i < argc - 1; i++) { 178217309Snwhitehorn src = colon(argv[i]); 179217309Snwhitehorn if (src) { /* remote to remote */ 180217309Snwhitehorn *src++ = 0; 181217309Snwhitehorn if (*src == 0) 182217309Snwhitehorn src = "."; 183217309Snwhitehorn host = strchr(argv[i], '@'); 184217309Snwhitehorn len = strlen(_PATH_RSH) + strlen(argv[i]) + 185217309Snwhitehorn strlen(src) + (tuser ? strlen(tuser) : 0) + 186217309Snwhitehorn strlen(thost) + strlen(targ) + CMDNEEDS + 20; 187217309Snwhitehorn if (!(bp = malloc(len))) 188217309Snwhitehorn err(1, "malloc"); 189217309Snwhitehorn if (host) { 190217309Snwhitehorn *host++ = 0; 191217309Snwhitehorn suser = argv[i]; 192217309Snwhitehorn if (*suser == '\0') 193217309Snwhitehorn suser = pwd->pw_name; 194217309Snwhitehorn else if (!okname(suser)) 195217309Snwhitehorn continue; 196217309Snwhitehorn (void)snprintf(bp, len, 197217309Snwhitehorn "%s %s -l %s -n %s %s '%s%s%s:%s'", 198217309Snwhitehorn _PATH_RSH, host, suser, cmd, src, 199217309Snwhitehorn tuser ? tuser : "", tuser ? "@" : "", 200217309Snwhitehorn thost, targ); 201217309Snwhitehorn } else 202217309Snwhitehorn (void)snprintf(bp, len, 203217309Snwhitehorn "exec %s %s -n %s %s '%s%s%s:%s'", 204217309Snwhitehorn _PATH_RSH, argv[i], cmd, src, 205217309Snwhitehorn tuser ? tuser : "", tuser ? "@" : "", 206217309Snwhitehorn thost, targ); 207217309Snwhitehorn (void)susystem(bp, userid); 208217309Snwhitehorn (void)free(bp); 209217309Snwhitehorn } else { /* local to remote */ 210217309Snwhitehorn if (remin == -1) { 211217309Snwhitehorn len = strlen(targ) + CMDNEEDS + 20; 212217309Snwhitehorn if (!(bp = malloc(len))) 213217309Snwhitehorn err(1, "malloc"); 214217309Snwhitehorn (void)snprintf(bp, len, "%s -t %s", cmd, targ); 215217309Snwhitehorn host = thost; 216217309Snwhitehorn 217217309Snwhitehorn if (do_cmd(host, tuser, bp, &remin, &remout) < 0) 218217309Snwhitehorn exit(1); 219217309Snwhitehorn 220217309Snwhitehorn if (response() < 0) 221217309Snwhitehorn exit(1); 222217309Snwhitehorn (void)free(bp); 223217309Snwhitehorn (void)setuid(userid); 224217309Snwhitehorn } 225217309Snwhitehorn source(1, argv+i); 226217309Snwhitehorn } 227217309Snwhitehorn } 228217309Snwhitehorn} 229217309Snwhitehorn 230217309Snwhitehornvoid 231217309Snwhitehorntolocal(argc, argv) 232217309Snwhitehorn int argc; 233217309Snwhitehorn char *argv[]; 234217309Snwhitehorn{ 235217309Snwhitehorn int i, len; 236217309Snwhitehorn char *bp, *host, *src, *suser; 237217309Snwhitehorn 238217309Snwhitehorn for (i = 0; i < argc - 1; i++) { 239217309Snwhitehorn if (!(src = colon(argv[i]))) { /* Local to local. */ 240217309Snwhitehorn len = strlen(_PATH_CP) + strlen(argv[i]) + 241217309Snwhitehorn strlen(argv[argc - 1]) + 20; 242217309Snwhitehorn if (!(bp = malloc(len))) 243217309Snwhitehorn err(1, "malloc"); 244217309Snwhitehorn (void)snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP, 245217309Snwhitehorn iamrecursive ? " -PR" : "", pflag ? " -p" : "", 246217309Snwhitehorn argv[i], argv[argc - 1]); 247217309Snwhitehorn if (susystem(bp, userid)) 248217309Snwhitehorn ++errs; 249217309Snwhitehorn (void)free(bp); 250217309Snwhitehorn continue; 251217309Snwhitehorn } 252217309Snwhitehorn *src++ = 0; 253217309Snwhitehorn if (*src == 0) 254217309Snwhitehorn src = "."; 255217309Snwhitehorn if ((host = strchr(argv[i], '@')) == NULL) { 256217309Snwhitehorn host = argv[i]; 257217309Snwhitehorn suser = pwd->pw_name; 258217309Snwhitehorn } else { 259217309Snwhitehorn *host++ = 0; 260217309Snwhitehorn suser = argv[i]; 261217309Snwhitehorn if (*suser == '\0') 262217309Snwhitehorn suser = pwd->pw_name; 263217309Snwhitehorn else if (!okname(suser)) 264217309Snwhitehorn continue; 265217309Snwhitehorn } 266217309Snwhitehorn len = strlen(src) + CMDNEEDS + 20; 267217309Snwhitehorn if ((bp = malloc(len)) == NULL) 268217309Snwhitehorn err(1, "malloc"); 269217309Snwhitehorn (void)snprintf(bp, len, "%s -f %s", cmd, src); 270217309Snwhitehorn if (do_cmd(host, suser, bp, &remin, &remout) < 0) { 271217309Snwhitehorn (void)free(bp); 272217309Snwhitehorn ++errs; 273217309Snwhitehorn continue; 274217309Snwhitehorn } 275217309Snwhitehorn (void)free(bp); 276217309Snwhitehorn sink(1, argv + argc - 1); 277217309Snwhitehorn (void)seteuid(0); 278217309Snwhitehorn (void)close(remin); 279217309Snwhitehorn remin = remout = -1; 280217309Snwhitehorn } 281217309Snwhitehorn} 282217309Snwhitehorn 283217309Snwhitehornvoid 284217309Snwhitehornsource(argc, argv) 285217309Snwhitehorn int argc; 286217309Snwhitehorn char *argv[]; 287217309Snwhitehorn{ 288217309Snwhitehorn struct stat stb; 289217309Snwhitehorn static BUF buffer; 290217309Snwhitehorn BUF *bp; 291217309Snwhitehorn off_t i; 292217309Snwhitehorn int amt, fd, haderr, indx, result; 293217309Snwhitehorn char *last, *name, buf[BUFSIZ]; 294217309Snwhitehorn 295217309Snwhitehorn for (indx = 0; indx < argc; ++indx) { 296217309Snwhitehorn name = argv[indx]; 297217309Snwhitehorn if ((fd = open(name, O_RDONLY, 0)) < 0) 298217309Snwhitehorn goto syserr; 299217309Snwhitehorn if (fstat(fd, &stb)) { 300217309Snwhitehornsyserr: run_err("%s: %s", name, strerror(errno)); 301217309Snwhitehorn goto next; 302217309Snwhitehorn } 303217309Snwhitehorn switch (stb.st_mode & S_IFMT) { 304217309Snwhitehorn case S_IFREG: 305217309Snwhitehorn break; 306217309Snwhitehorn case S_IFDIR: 307217309Snwhitehorn if (iamrecursive) { 308217309Snwhitehorn rsource(name, &stb); 309217309Snwhitehorn goto next; 310217309Snwhitehorn } 311217309Snwhitehorn /* FALLTHROUGH */ 312217309Snwhitehorn default: 313217309Snwhitehorn run_err("%s: not a regular file", name); 314217309Snwhitehorn goto next; 315217309Snwhitehorn } 316217309Snwhitehorn if ((last = strrchr(name, '/')) == NULL) 317217309Snwhitehorn last = name; 318217309Snwhitehorn else 319217309Snwhitehorn ++last; 320217309Snwhitehorn if (pflag) { 321217309Snwhitehorn /* 322217309Snwhitehorn * Make it compatible with possible future 323217309Snwhitehorn * versions expecting microseconds. 324217309Snwhitehorn */ 325217309Snwhitehorn (void)snprintf(buf, sizeof(buf), "T%ld 0 %ld 0\n", 326217309Snwhitehorn (long)stb.st_mtime, 327217309Snwhitehorn (long)stb.st_atime); 328217309Snwhitehorn (void)write(remout, buf, strlen(buf)); 329217309Snwhitehorn if (response() < 0) 330217309Snwhitehorn goto next; 331217309Snwhitehorn } 332217309Snwhitehorn#define MODEMASK (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) 333217309Snwhitehorn (void)snprintf(buf, sizeof(buf), "C%04o %lu %s\n", 334217309Snwhitehorn stb.st_mode & MODEMASK, (unsigned long)stb.st_size, last); 335217309Snwhitehorn (void)write(remout, buf, strlen(buf)); 336217309Snwhitehorn if (response() < 0) 337217309Snwhitehorn goto next; 338217309Snwhitehorn if ((bp = allocbuf(&buffer, fd, BUFSIZ)) == NULL) { 339217309Snwhitehornnext: (void)close(fd); 340217309Snwhitehorn continue; 341217309Snwhitehorn } 342217309Snwhitehorn 343217309Snwhitehorn /* Keep writing after an error so that we stay sync'd up. */ 344217309Snwhitehorn for (haderr = i = 0; i < stb.st_size; i += bp->cnt) { 345217309Snwhitehorn amt = bp->cnt; 346217309Snwhitehorn if (i + amt > stb.st_size) 347217309Snwhitehorn amt = stb.st_size - i; 348217309Snwhitehorn if (!haderr) { 349217309Snwhitehorn result = read(fd, bp->buf, amt); 350217309Snwhitehorn if (result != amt) 351217309Snwhitehorn haderr = result >= 0 ? EIO : errno; 352217309Snwhitehorn } 353217309Snwhitehorn if (haderr) 354217309Snwhitehorn (void)write(remout, bp->buf, amt); 355217309Snwhitehorn else { 356217309Snwhitehorn result = write(remout, bp->buf, amt); 357217309Snwhitehorn if (result != amt) 358217309Snwhitehorn haderr = result >= 0 ? EIO : errno; 359217309Snwhitehorn } 360217309Snwhitehorn } 361217309Snwhitehorn if (close(fd) && !haderr) 362217309Snwhitehorn haderr = errno; 363217309Snwhitehorn if (!haderr) 364217309Snwhitehorn (void)write(remout, "", 1); 365217309Snwhitehorn else 366217309Snwhitehorn run_err("%s: %s", name, strerror(haderr)); 367217309Snwhitehorn (void)response(); 368217309Snwhitehorn } 369217309Snwhitehorn} 370217309Snwhitehorn 371217309Snwhitehornvoid 372217309Snwhitehornrsource(name, statp) 373217309Snwhitehorn char *name; 374217309Snwhitehorn struct stat *statp; 375217309Snwhitehorn{ 376217309Snwhitehorn DIR *dirp; 377217309Snwhitehorn struct dirent *dp; 378217309Snwhitehorn char *last, *vect[1], path[MAXPATHLEN]; 379217309Snwhitehorn 380217309Snwhitehorn if (!(dirp = opendir(name))) { 381217309Snwhitehorn run_err("%s: %s", name, strerror(errno)); 382217309Snwhitehorn return; 383217309Snwhitehorn } 384217309Snwhitehorn last = strrchr(name, '/'); 385217309Snwhitehorn if (last == 0) 386217309Snwhitehorn last = name; 387217309Snwhitehorn else 388217309Snwhitehorn last++; 389217309Snwhitehorn if (pflag) { 390217309Snwhitehorn (void)snprintf(path, sizeof(path), "T%ld 0 %ld 0\n", 391217309Snwhitehorn (long)statp->st_mtime, 392217309Snwhitehorn (long)statp->st_atime); 393217309Snwhitehorn (void)write(remout, path, strlen(path)); 394217309Snwhitehorn if (response() < 0) { 395217309Snwhitehorn closedir(dirp); 396217309Snwhitehorn return; 397217309Snwhitehorn } 398217309Snwhitehorn } 399217309Snwhitehorn (void)snprintf(path, sizeof(path), 400217309Snwhitehorn "D%04o %d %s\n", statp->st_mode & MODEMASK, 0, last); 401217309Snwhitehorn (void)write(remout, path, strlen(path)); 402217309Snwhitehorn if (response() < 0) { 403217309Snwhitehorn closedir(dirp); 404217309Snwhitehorn return; 405217309Snwhitehorn } 406217309Snwhitehorn while ((dp = readdir(dirp))) { 407217309Snwhitehorn if (dp->d_ino == 0) 408217309Snwhitehorn continue; 409217309Snwhitehorn if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 410217309Snwhitehorn continue; 411217309Snwhitehorn if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) { 412217309Snwhitehorn run_err("%s/%s: name too long", name, dp->d_name); 413217309Snwhitehorn continue; 414217309Snwhitehorn } 415217309Snwhitehorn (void)snprintf(path, sizeof(path), "%s/%s", name, dp->d_name); 416217309Snwhitehorn vect[0] = path; 417217309Snwhitehorn source(1, vect); 418217309Snwhitehorn } 419217309Snwhitehorn (void)closedir(dirp); 420217309Snwhitehorn (void)write(remout, "E\n", 2); 421217309Snwhitehorn (void)response(); 422217309Snwhitehorn} 423217309Snwhitehorn 424217309Snwhitehornvoid 425217309Snwhitehornsink(argc, argv) 426217309Snwhitehorn int argc; 427217309Snwhitehorn char *argv[]; 428217309Snwhitehorn{ 429217309Snwhitehorn static BUF buffer; 430217309Snwhitehorn struct stat stb; 431217309Snwhitehorn struct timeval tv[2]; 432217309Snwhitehorn enum { YES, NO, DISPLAYED } wrerr; 433217309Snwhitehorn BUF *bp; 434217309Snwhitehorn off_t i, j, size; 435217309Snwhitehorn int amt, count, exists, first, mask, mode, ofd, omode; 436217309Snwhitehorn int setimes, targisdir, wrerrno = 0; 437217309Snwhitehorn char ch, *cp, *np, *targ, *why, *vect[1], buf[BUFSIZ]; 438217309Snwhitehorn 439217309Snwhitehorn#define atime tv[0] 440217309Snwhitehorn#define mtime tv[1] 441217309Snwhitehorn#define SCREWUP(str) { why = str; goto screwup; } 442217309Snwhitehorn 443217309Snwhitehorn setimes = targisdir = 0; 444217309Snwhitehorn mask = umask(0); 445217309Snwhitehorn if (!pflag) 446217309Snwhitehorn (void)umask(mask); 447217309Snwhitehorn if (argc != 1) { 448217309Snwhitehorn run_err("ambiguous target"); 449217309Snwhitehorn exit(1); 450217309Snwhitehorn } 451217309Snwhitehorn targ = *argv; 452217309Snwhitehorn if (targetshouldbedirectory) 453217309Snwhitehorn verifydir(targ); 454217309Snwhitehorn (void)write(remout, "", 1); 455217309Snwhitehorn if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) 456217309Snwhitehorn targisdir = 1; 457217309Snwhitehorn for (first = 1;; first = 0) { 458217309Snwhitehorn cp = buf; 459217309Snwhitehorn if (read(remin, cp, 1) <= 0) 460217309Snwhitehorn return; 461217309Snwhitehorn if (*cp++ == '\n') 462217309Snwhitehorn SCREWUP("unexpected <newline>"); 463217309Snwhitehorn do { 464217309Snwhitehorn if (read(remin, &ch, sizeof(ch)) != sizeof(ch)) 465217309Snwhitehorn SCREWUP("lost connection"); 466217309Snwhitehorn *cp++ = ch; 467217309Snwhitehorn } while (cp < &buf[BUFSIZ - 1] && ch != '\n'); 468217309Snwhitehorn *cp = 0; 469217309Snwhitehorn 470217309Snwhitehorn if (buf[0] == '\01' || buf[0] == '\02') { 471217309Snwhitehorn if (iamremote == 0) 472217309Snwhitehorn (void)write(STDERR_FILENO, 473217309Snwhitehorn buf + 1, strlen(buf + 1)); 474217309Snwhitehorn if (buf[0] == '\02') 475217309Snwhitehorn exit(1); 476217309Snwhitehorn ++errs; 477217309Snwhitehorn continue; 478217309Snwhitehorn } 479217309Snwhitehorn if (buf[0] == 'E') { 480217309Snwhitehorn (void)write(remout, "", 1); 481217309Snwhitehorn return; 482217309Snwhitehorn } 483217309Snwhitehorn 484217309Snwhitehorn if (ch == '\n') 485217309Snwhitehorn *--cp = 0; 486217309Snwhitehorn 487217309Snwhitehorn cp = buf; 488217309Snwhitehorn if (*cp == 'T') { 489217309Snwhitehorn setimes++; 490217309Snwhitehorn cp++; 491217309Snwhitehorn mtime.tv_sec = strtol(cp, &cp, 10); 492217309Snwhitehorn if (!cp || *cp++ != ' ') 493217309Snwhitehorn SCREWUP("mtime.sec not delimited"); 494217309Snwhitehorn mtime.tv_usec = strtol(cp, &cp, 10); 495217309Snwhitehorn if (!cp || *cp++ != ' ') 496217309Snwhitehorn SCREWUP("mtime.usec not delimited"); 497217309Snwhitehorn atime.tv_sec = strtol(cp, &cp, 10); 498217309Snwhitehorn if (!cp || *cp++ != ' ') 499217309Snwhitehorn SCREWUP("atime.sec not delimited"); 500217309Snwhitehorn atime.tv_usec = strtol(cp, &cp, 10); 501217309Snwhitehorn if (!cp || *cp++ != '\0') 502217309Snwhitehorn SCREWUP("atime.usec not delimited"); 503217309Snwhitehorn (void)write(remout, "", 1); 504217309Snwhitehorn 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) { 579bad: 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 } 658screwup: 659 run_err("protocol error: %s", why); 660 exit(1); 661} 662 663int 664response() 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 696void 697usage() 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 707void 708run_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 737int 738do_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