172445Sassar/* 272445Sassar * Copyright (c) 1983, 1990, 1992, 1993 372445Sassar * The Regents of the University of California. All rights reserved. 472445Sassar * 572445Sassar * Redistribution and use in source and binary forms, with or without 672445Sassar * modification, are permitted provided that the following conditions 772445Sassar * are met: 872445Sassar * 1. Redistributions of source code must retain the above copyright 972445Sassar * notice, this list of conditions and the following disclaimer. 1072445Sassar * 2. Redistributions in binary form must reproduce the above copyright 1172445Sassar * notice, this list of conditions and the following disclaimer in the 1272445Sassar * documentation and/or other materials provided with the distribution. 13233294Sstas * 3. Neither the name of the University nor the names of its contributors 1472445Sassar * may be used to endorse or promote products derived from this software 1572445Sassar * without specific prior written permission. 1672445Sassar * 1772445Sassar * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1872445Sassar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1972445Sassar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2072445Sassar * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2172445Sassar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2272445Sassar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2372445Sassar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2472445Sassar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2572445Sassar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2672445Sassar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2772445Sassar * SUCH DAMAGE. 2872445Sassar */ 2972445Sassar 3072445Sassar#include "rcp_locl.h" 3178527Sassar#include <getarg.h> 3272445Sassar 3372445Sassar#define RSH_PROGRAM "rsh" 3472445Sassar 3572445Sassarstruct passwd *pwd; 3672445Sassaruid_t userid; 3772445Sassarint errs, remin, remout; 3872445Sassarint pflag, iamremote, iamrecursive, targetshouldbedirectory; 3972445Sassarint doencrypt, noencrypt; 40120945Snectarint usebroken, usekrb4, usekrb5, forwardtkt; 4172445Sassarchar *port; 42178825Sdfrint eflag = 0; 4372445Sassar 4472445Sassar#define CMDNEEDS 64 4572445Sassarchar cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ 4672445Sassar 4772445Sassarint response (void); 4872445Sassarvoid rsource (char *, struct stat *); 4972445Sassarvoid sink (int, char *[]); 5072445Sassarvoid source (int, char *[]); 5172445Sassarvoid tolocal (int, char *[]); 5272445Sassarvoid toremote (char *, int, char *[]); 5372445Sassar 5472445Sassarint do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout); 5572445Sassar 5678527Sassarstatic int fflag, tflag; 5778527Sassar 5878527Sassarstatic int version_flag, help_flag; 5978527Sassar 6078527Sassarstruct getargs args[] = { 61120945Snectar { NULL, '4', arg_flag, &usekrb4, "use Kerberos 4 authentication" }, 6278527Sassar { NULL, '5', arg_flag, &usekrb5, "use Kerberos 5 authentication" }, 6378527Sassar { NULL, 'F', arg_flag, &forwardtkt, "forward credentials" }, 6478527Sassar { NULL, 'K', arg_flag, &usebroken, "use BSD authentication" }, 6578527Sassar { NULL, 'P', arg_string, &port, "non-default port", "port" }, 6678527Sassar { NULL, 'p', arg_flag, &pflag, "preserve file permissions" }, 6778527Sassar { NULL, 'r', arg_flag, &iamrecursive, "recursive mode" }, 6878527Sassar { NULL, 'x', arg_flag, &doencrypt, "use encryption" }, 6978527Sassar { NULL, 'z', arg_flag, &noencrypt, "don't encrypt" }, 7078527Sassar { NULL, 'd', arg_flag, &targetshouldbedirectory }, 71178825Sdfr { NULL, 'e', arg_flag, &eflag, "passed to rsh" }, 7278527Sassar { NULL, 'f', arg_flag, &fflag }, 7378527Sassar { NULL, 't', arg_flag, &tflag }, 7478527Sassar { "version", 0, arg_flag, &version_flag }, 7578527Sassar { "help", 0, arg_flag, &help_flag } 7678527Sassar}; 7778527Sassar 7878527Sassarstatic void 7978527Sassarusage (int ret) 8078527Sassar{ 8178527Sassar arg_printusage (args, 8278527Sassar sizeof(args) / sizeof(args[0]), 8378527Sassar NULL, 8478527Sassar "file1 file2|file... directory"); 8578527Sassar exit (ret); 8678527Sassar} 8778527Sassar 8872445Sassarint 8978527Sassarmain(int argc, char **argv) 9072445Sassar{ 9172445Sassar char *targ; 9278527Sassar int optind = 0; 9372445Sassar 9490926Snectar setprogname(argv[0]); 9578527Sassar if (getarg (args, sizeof(args) / sizeof(args[0]), argc, argv, 9678527Sassar &optind)) 9778527Sassar usage (1); 9878527Sassar if(help_flag) 9978527Sassar usage(0); 10078527Sassar if (version_flag) { 10178527Sassar print_version (NULL); 10278527Sassar return 0; 10378527Sassar } 104233294Sstas 10578527Sassar iamremote = (fflag || tflag); 10678527Sassar 10772445Sassar argc -= optind; 10872445Sassar argv += optind; 10972445Sassar 11072445Sassar if ((pwd = getpwuid(userid = getuid())) == NULL) 11172445Sassar errx(1, "unknown user %d", (int)userid); 11272445Sassar 11372445Sassar remin = STDIN_FILENO; /* XXX */ 11472445Sassar remout = STDOUT_FILENO; 11572445Sassar 11672445Sassar if (fflag) { /* Follow "protocol", send data. */ 117233294Sstas (void)response(); 11872445Sassar source(argc, argv); 11972445Sassar exit(errs); 12072445Sassar } 12172445Sassar 12272445Sassar if (tflag) { /* Receive data. */ 12372445Sassar sink(argc, argv); 12472445Sassar exit(errs); 12572445Sassar } 12672445Sassar 12772445Sassar if (argc < 2) 12878527Sassar usage(1); 12972445Sassar if (argc > 2) 13072445Sassar targetshouldbedirectory = 1; 13172445Sassar 13272445Sassar remin = remout = -1; 13372445Sassar /* Command to be executed on remote system using "rsh". */ 13490926Snectar snprintf(cmd, sizeof(cmd), 135233294Sstas "rcp%s%s%s", iamrecursive ? " -r" : "", 13690926Snectar pflag ? " -p" : "", targetshouldbedirectory ? " -d" : ""); 13772445Sassar 13878527Sassar signal(SIGPIPE, lostconn); 13972445Sassar 14072445Sassar if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */ 14172445Sassar toremote(targ, argc, argv); 14272445Sassar else { 14372445Sassar tolocal(argc, argv); /* Dest is local host. */ 14472445Sassar if (targetshouldbedirectory) 14572445Sassar verifydir(argv[argc - 1]); 14672445Sassar } 14772445Sassar exit(errs); 14872445Sassar} 14972445Sassar 15072445Sassarvoid 15178527Sassartoremote(char *targ, int argc, char **argv) 15272445Sassar{ 15390926Snectar int i; 15472445Sassar char *bp, *host, *src, *suser, *thost, *tuser; 15572445Sassar 15672445Sassar *targ++ = 0; 15772445Sassar if (*targ == 0) 15872445Sassar targ = "."; 15972445Sassar 160233294Sstas if ((thost = strchr(argv[argc - 1], '@')) != NULL) { 16172445Sassar /* user@host */ 16272445Sassar *thost++ = 0; 16372445Sassar tuser = argv[argc - 1]; 16472445Sassar if (*tuser == '\0') 16572445Sassar tuser = NULL; 16672445Sassar else if (!okname(tuser)) 16772445Sassar exit(1); 16872445Sassar } else { 16972445Sassar thost = argv[argc - 1]; 17072445Sassar tuser = NULL; 17172445Sassar } 172233294Sstas thost = unbracket(thost); 17372445Sassar 17472445Sassar for (i = 0; i < argc - 1; i++) { 17572445Sassar src = colon(argv[i]); 17672445Sassar if (src) { /* remote to remote */ 177178825Sdfr int ret; 17872445Sassar *src++ = 0; 17972445Sassar if (*src == 0) 18072445Sassar src = "."; 18172445Sassar host = strchr(argv[i], '@'); 18272445Sassar if (host) { 18390926Snectar *host++ = '\0'; 184233294Sstas host = unbracket(host); 18572445Sassar suser = argv[i]; 18672445Sassar if (*suser == '\0') 18772445Sassar suser = pwd->pw_name; 18872445Sassar else if (!okname(suser)) 18972445Sassar continue; 190178825Sdfr ret = asprintf(&bp, 191178825Sdfr "%s%s %s -l %s -n %s %s '%s%s%s:%s'", 192233294Sstas _PATH_RSH, eflag ? " -e" : "", 193178825Sdfr host, suser, cmd, src, 19472445Sassar tuser ? tuser : "", tuser ? "@" : "", 19572445Sassar thost, targ); 19690926Snectar } else { 197233294Sstas host = unbracket(argv[i]); 198178825Sdfr ret = asprintf(&bp, 199178825Sdfr "exec %s%s %s -n %s %s '%s%s%s:%s'", 200233294Sstas _PATH_RSH, eflag ? " -e" : "", 201233294Sstas host, cmd, src, 202178825Sdfr tuser ? tuser : "", tuser ? "@" : "", 203178825Sdfr thost, targ); 20490926Snectar } 205178825Sdfr if (ret == -1) 20690926Snectar err (1, "malloc"); 207233294Sstas susystem(bp); 20878527Sassar free(bp); 20972445Sassar } else { /* local to remote */ 21072445Sassar if (remin == -1) { 211178825Sdfr if (asprintf(&bp, "%s -t %s", cmd, targ) == -1) 21290926Snectar err (1, "malloc"); 21372445Sassar host = thost; 21472445Sassar 21572445Sassar if (do_cmd(host, tuser, bp, &remin, &remout) < 0) 21672445Sassar exit(1); 21772445Sassar 21872445Sassar if (response() < 0) 21972445Sassar exit(1); 22078527Sassar free(bp); 22172445Sassar } 22272445Sassar source(1, argv+i); 22372445Sassar } 22472445Sassar } 22572445Sassar} 22672445Sassar 22772445Sassarvoid 22878527Sassartolocal(int argc, char **argv) 22972445Sassar{ 23090926Snectar int i; 23172445Sassar char *bp, *host, *src, *suser; 23272445Sassar 23372445Sassar for (i = 0; i < argc - 1; i++) { 234178825Sdfr int ret; 235178825Sdfr 23672445Sassar if (!(src = colon(argv[i]))) { /* Local to local. */ 237178825Sdfr ret = asprintf(&bp, "exec %s%s%s %s %s", _PATH_CP, 23872445Sassar iamrecursive ? " -PR" : "", pflag ? " -p" : "", 23972445Sassar argv[i], argv[argc - 1]); 240178825Sdfr if (ret == -1) 24190926Snectar err (1, "malloc"); 242233294Sstas if (susystem(bp)) 24372445Sassar ++errs; 24478527Sassar free(bp); 24572445Sassar continue; 24672445Sassar } 24772445Sassar *src++ = 0; 24872445Sassar if (*src == 0) 24972445Sassar src = "."; 25072445Sassar if ((host = strchr(argv[i], '@')) == NULL) { 25172445Sassar host = argv[i]; 25272445Sassar suser = pwd->pw_name; 25372445Sassar } else { 25472445Sassar *host++ = 0; 25572445Sassar suser = argv[i]; 25672445Sassar if (*suser == '\0') 25772445Sassar suser = pwd->pw_name; 25872445Sassar else if (!okname(suser)) 25972445Sassar continue; 26072445Sassar } 261178825Sdfr ret = asprintf(&bp, "%s -f %s", cmd, src); 262178825Sdfr if (ret == -1) 26390926Snectar err (1, "malloc"); 26472445Sassar if (do_cmd(host, suser, bp, &remin, &remout) < 0) { 26578527Sassar free(bp); 26672445Sassar ++errs; 26772445Sassar continue; 26872445Sassar } 26978527Sassar free(bp); 27072445Sassar sink(1, argv + argc - 1); 27178527Sassar close(remin); 27272445Sassar remin = remout = -1; 27372445Sassar } 27472445Sassar} 27572445Sassar 27672445Sassarvoid 27778527Sassarsource(int argc, char **argv) 27872445Sassar{ 27972445Sassar struct stat stb; 28072445Sassar static BUF buffer; 28172445Sassar BUF *bp; 28272445Sassar off_t i; 283233294Sstas off_t amt; 284233294Sstas int fd, haderr, indx, result; 28572445Sassar char *last, *name, buf[BUFSIZ]; 28672445Sassar 28772445Sassar for (indx = 0; indx < argc; ++indx) { 28872445Sassar name = argv[indx]; 28972445Sassar if ((fd = open(name, O_RDONLY, 0)) < 0) 29072445Sassar goto syserr; 29172445Sassar if (fstat(fd, &stb)) { 29272445Sassarsyserr: run_err("%s: %s", name, strerror(errno)); 29372445Sassar goto next; 29472445Sassar } 295233294Sstas if (S_ISDIR(stb.st_mode) && iamrecursive) { 296233294Sstas rsource(name, &stb); 297233294Sstas goto next; 298233294Sstas } else if (!S_ISREG(stb.st_mode)) { 29972445Sassar run_err("%s: not a regular file", name); 30072445Sassar goto next; 30172445Sassar } 30272445Sassar if ((last = strrchr(name, '/')) == NULL) 30372445Sassar last = name; 30472445Sassar else 30572445Sassar ++last; 30672445Sassar if (pflag) { 30772445Sassar /* 30872445Sassar * Make it compatible with possible future 30972445Sassar * versions expecting microseconds. 31072445Sassar */ 31178527Sassar snprintf(buf, sizeof(buf), "T%ld 0 %ld 0\n", 31272445Sassar (long)stb.st_mtime, 31372445Sassar (long)stb.st_atime); 31478527Sassar write(remout, buf, strlen(buf)); 31572445Sassar if (response() < 0) 31672445Sassar goto next; 31772445Sassar } 318178825Sdfr#undef MODEMASK 31972445Sassar#define MODEMASK (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) 32090926Snectar snprintf(buf, sizeof(buf), "C%04o %lu %s\n", 321233294Sstas (unsigned int)(stb.st_mode & MODEMASK), 32290926Snectar (unsigned long)stb.st_size, 32390926Snectar last); 32478527Sassar write(remout, buf, strlen(buf)); 32572445Sassar if (response() < 0) 32672445Sassar goto next; 32772445Sassar if ((bp = allocbuf(&buffer, fd, BUFSIZ)) == NULL) { 32878527Sassarnext: close(fd); 32972445Sassar continue; 33072445Sassar } 33172445Sassar 33272445Sassar /* Keep writing after an error so that we stay sync'd up. */ 33372445Sassar for (haderr = i = 0; i < stb.st_size; i += bp->cnt) { 33472445Sassar amt = bp->cnt; 33572445Sassar if (i + amt > stb.st_size) 33672445Sassar amt = stb.st_size - i; 33772445Sassar if (!haderr) { 338233294Sstas result = read(fd, bp->buf, (size_t)amt); 33972445Sassar if (result != amt) 34072445Sassar haderr = result >= 0 ? EIO : errno; 34172445Sassar } 34272445Sassar if (haderr) 34378527Sassar write(remout, bp->buf, amt); 34472445Sassar else { 345233294Sstas result = write(remout, bp->buf, (size_t)amt); 34672445Sassar if (result != amt) 34772445Sassar haderr = result >= 0 ? EIO : errno; 34872445Sassar } 34972445Sassar } 35072445Sassar if (close(fd) && !haderr) 35172445Sassar haderr = errno; 35272445Sassar if (!haderr) 35378527Sassar write(remout, "", 1); 35472445Sassar else 35572445Sassar run_err("%s: %s", name, strerror(haderr)); 35678527Sassar response(); 35772445Sassar } 35872445Sassar} 35972445Sassar 36072445Sassarvoid 36178527Sassarrsource(char *name, struct stat *statp) 36272445Sassar{ 36372445Sassar DIR *dirp; 36472445Sassar struct dirent *dp; 36572445Sassar char *last, *vect[1], path[MAXPATHLEN]; 36672445Sassar 36772445Sassar if (!(dirp = opendir(name))) { 36872445Sassar run_err("%s: %s", name, strerror(errno)); 36972445Sassar return; 37072445Sassar } 37172445Sassar last = strrchr(name, '/'); 37272445Sassar if (last == 0) 37372445Sassar last = name; 37472445Sassar else 37572445Sassar last++; 37672445Sassar if (pflag) { 37778527Sassar snprintf(path, sizeof(path), "T%ld 0 %ld 0\n", 37872445Sassar (long)statp->st_mtime, 37972445Sassar (long)statp->st_atime); 38078527Sassar write(remout, path, strlen(path)); 38172445Sassar if (response() < 0) { 38272445Sassar closedir(dirp); 38372445Sassar return; 38472445Sassar } 38572445Sassar } 38678527Sassar snprintf(path, sizeof(path), 387233294Sstas "D%04o %d %s\n", 388233294Sstas (unsigned int)(statp->st_mode & MODEMASK), 0, last); 38978527Sassar write(remout, path, strlen(path)); 39072445Sassar if (response() < 0) { 39172445Sassar closedir(dirp); 39272445Sassar return; 39372445Sassar } 394233294Sstas while ((dp = readdir(dirp)) != NULL) { 39572445Sassar if (dp->d_ino == 0) 39672445Sassar continue; 39772445Sassar if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 39872445Sassar continue; 39972445Sassar if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) { 40072445Sassar run_err("%s/%s: name too long", name, dp->d_name); 40172445Sassar continue; 40272445Sassar } 40378527Sassar snprintf(path, sizeof(path), "%s/%s", name, dp->d_name); 40472445Sassar vect[0] = path; 40572445Sassar source(1, vect); 40672445Sassar } 40778527Sassar closedir(dirp); 40878527Sassar write(remout, "E\n", 2); 40978527Sassar response(); 41072445Sassar} 41172445Sassar 41272445Sassarvoid 41378527Sassarsink(int argc, char **argv) 41472445Sassar{ 41572445Sassar static BUF buffer; 41672445Sassar struct stat stb; 41772445Sassar struct timeval tv[2]; 41872445Sassar enum { YES, NO, DISPLAYED } wrerr; 41972445Sassar BUF *bp; 42072445Sassar off_t i, j, size; 42172445Sassar int amt, count, exists, first, mask, mode, ofd, omode; 42272445Sassar int setimes, targisdir, wrerrno = 0; 42372445Sassar char ch, *cp, *np, *targ, *why, *vect[1], buf[BUFSIZ]; 42472445Sassar 42572445Sassar#define atime tv[0] 42672445Sassar#define mtime tv[1] 42772445Sassar#define SCREWUP(str) { why = str; goto screwup; } 42872445Sassar 42972445Sassar setimes = targisdir = 0; 43072445Sassar mask = umask(0); 43172445Sassar if (!pflag) 43278527Sassar umask(mask); 43372445Sassar if (argc != 1) { 43472445Sassar run_err("ambiguous target"); 43572445Sassar exit(1); 43672445Sassar } 43772445Sassar targ = *argv; 43872445Sassar if (targetshouldbedirectory) 43972445Sassar verifydir(targ); 44078527Sassar write(remout, "", 1); 44172445Sassar if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) 44272445Sassar targisdir = 1; 44372445Sassar for (first = 1;; first = 0) { 44472445Sassar cp = buf; 44572445Sassar if (read(remin, cp, 1) <= 0) 44672445Sassar return; 44772445Sassar if (*cp++ == '\n') 44872445Sassar SCREWUP("unexpected <newline>"); 44972445Sassar do { 45072445Sassar if (read(remin, &ch, sizeof(ch)) != sizeof(ch)) 45172445Sassar SCREWUP("lost connection"); 45272445Sassar *cp++ = ch; 45372445Sassar } while (cp < &buf[BUFSIZ - 1] && ch != '\n'); 45472445Sassar *cp = 0; 45572445Sassar 45672445Sassar if (buf[0] == '\01' || buf[0] == '\02') { 45772445Sassar if (iamremote == 0) 45878527Sassar write(STDERR_FILENO, 45972445Sassar buf + 1, strlen(buf + 1)); 46072445Sassar if (buf[0] == '\02') 46172445Sassar exit(1); 46272445Sassar ++errs; 46372445Sassar continue; 46472445Sassar } 46572445Sassar if (buf[0] == 'E') { 46678527Sassar write(remout, "", 1); 46772445Sassar return; 46872445Sassar } 46972445Sassar 47072445Sassar if (ch == '\n') 47172445Sassar *--cp = 0; 47272445Sassar 47372445Sassar cp = buf; 47472445Sassar if (*cp == 'T') { 47572445Sassar setimes++; 47672445Sassar cp++; 47772445Sassar mtime.tv_sec = strtol(cp, &cp, 10); 47872445Sassar if (!cp || *cp++ != ' ') 47972445Sassar SCREWUP("mtime.sec not delimited"); 48072445Sassar mtime.tv_usec = strtol(cp, &cp, 10); 48172445Sassar if (!cp || *cp++ != ' ') 48272445Sassar SCREWUP("mtime.usec not delimited"); 48372445Sassar atime.tv_sec = strtol(cp, &cp, 10); 48472445Sassar if (!cp || *cp++ != ' ') 48572445Sassar SCREWUP("atime.sec not delimited"); 48672445Sassar atime.tv_usec = strtol(cp, &cp, 10); 48772445Sassar if (!cp || *cp++ != '\0') 48872445Sassar SCREWUP("atime.usec not delimited"); 48978527Sassar write(remout, "", 1); 49072445Sassar continue; 49172445Sassar } 49272445Sassar if (*cp != 'C' && *cp != 'D') { 49372445Sassar /* 49472445Sassar * Check for the case "rcp remote:foo\* local:bar". 49572445Sassar * In this case, the line "No match." can be returned 49672445Sassar * by the shell before the rcp command on the remote is 49772445Sassar * executed so the ^Aerror_message convention isn't 49872445Sassar * followed. 49972445Sassar */ 50072445Sassar if (first) { 50172445Sassar run_err("%s", cp); 50272445Sassar exit(1); 50372445Sassar } 50472445Sassar SCREWUP("expected control record"); 50572445Sassar } 50672445Sassar mode = 0; 50772445Sassar for (++cp; cp < buf + 5; cp++) { 50872445Sassar if (*cp < '0' || *cp > '7') 50972445Sassar SCREWUP("bad mode"); 51072445Sassar mode = (mode << 3) | (*cp - '0'); 51172445Sassar } 51272445Sassar if (*cp++ != ' ') 51372445Sassar SCREWUP("mode not delimited"); 51472445Sassar 51590926Snectar for (size = 0; isdigit((unsigned char)*cp);) 51672445Sassar size = size * 10 + (*cp++ - '0'); 51772445Sassar if (*cp++ != ' ') 51872445Sassar SCREWUP("size not delimited"); 51972445Sassar if (targisdir) { 52072445Sassar static char *namebuf; 52172445Sassar static int cursize; 52272445Sassar size_t need; 52372445Sassar 52472445Sassar need = strlen(targ) + strlen(cp) + 250; 52572445Sassar if (need > cursize) { 52672445Sassar if (!(namebuf = malloc(need))) 52772445Sassar run_err("%s", strerror(errno)); 52872445Sassar } 52978527Sassar snprintf(namebuf, need, "%s%s%s", targ, 53072445Sassar *targ ? "/" : "", cp); 53172445Sassar np = namebuf; 53272445Sassar } else 53372445Sassar np = targ; 53472445Sassar exists = stat(np, &stb) == 0; 53572445Sassar if (buf[0] == 'D') { 53672445Sassar int mod_flag = pflag; 53772445Sassar if (exists) { 53872445Sassar if (!S_ISDIR(stb.st_mode)) { 53972445Sassar errno = ENOTDIR; 54072445Sassar goto bad; 54172445Sassar } 54272445Sassar if (pflag) 54378527Sassar chmod(np, mode); 54472445Sassar } else { 54572445Sassar /* Handle copying from a read-only directory */ 54672445Sassar mod_flag = 1; 54772445Sassar if (mkdir(np, mode | S_IRWXU) < 0) 54872445Sassar goto bad; 54972445Sassar } 55072445Sassar vect[0] = np; 55172445Sassar sink(1, vect); 55272445Sassar if (setimes) { 55372445Sassar setimes = 0; 55472445Sassar if (utimes(np, tv) < 0) 55572445Sassar run_err("%s: set times: %s", 55672445Sassar np, strerror(errno)); 55772445Sassar } 55872445Sassar if (mod_flag) 55978527Sassar chmod(np, mode); 56072445Sassar continue; 56172445Sassar } 56272445Sassar omode = mode; 56372445Sassar mode |= S_IWRITE; 56472445Sassar if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { 56572445Sassarbad: run_err("%s: %s", np, strerror(errno)); 56672445Sassar continue; 56772445Sassar } 56878527Sassar write(remout, "", 1); 56972445Sassar if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == NULL) { 57078527Sassar close(ofd); 57172445Sassar continue; 57272445Sassar } 57372445Sassar cp = bp->buf; 57472445Sassar wrerr = NO; 57572445Sassar for (count = i = 0; i < size; i += BUFSIZ) { 57672445Sassar amt = BUFSIZ; 57772445Sassar if (i + amt > size) 57872445Sassar amt = size - i; 57972445Sassar count += amt; 58078527Sassar if((j = net_read(remin, cp, amt)) != amt) { 58178527Sassar run_err("%s", j ? strerror(errno) : 58278527Sassar "dropped connection"); 58378527Sassar exit(1); 58478527Sassar } 58578527Sassar amt -= j; 58678527Sassar cp += j; 58772445Sassar if (count == bp->cnt) { 58872445Sassar /* Keep reading so we stay sync'd up. */ 58972445Sassar if (wrerr == NO) { 590233294Sstas j = write(ofd, bp->buf, (size_t)count); 59172445Sassar if (j != count) { 59272445Sassar wrerr = YES; 59372445Sassar wrerrno = j >= 0 ? EIO : errno; 59472445Sassar } 59572445Sassar } 59672445Sassar count = 0; 59772445Sassar cp = bp->buf; 59872445Sassar } 59972445Sassar } 60072445Sassar if (count != 0 && wrerr == NO && 601233294Sstas (j = write(ofd, bp->buf, (size_t)count)) != count) { 60272445Sassar wrerr = YES; 60372445Sassar wrerrno = j >= 0 ? EIO : errno; 60472445Sassar } 60572445Sassar if (ftruncate(ofd, size)) { 60672445Sassar run_err("%s: truncate: %s", np, strerror(errno)); 60772445Sassar wrerr = DISPLAYED; 60872445Sassar } 60972445Sassar if (pflag) { 61072445Sassar if (exists || omode != mode) 61172445Sassar if (fchmod(ofd, omode)) 61272445Sassar run_err("%s: set mode: %s", 61372445Sassar np, strerror(errno)); 61472445Sassar } else { 61572445Sassar if (!exists && omode != mode) 61672445Sassar if (fchmod(ofd, omode & ~mask)) 61772445Sassar run_err("%s: set mode: %s", 61872445Sassar np, strerror(errno)); 61972445Sassar } 62078527Sassar close(ofd); 62178527Sassar response(); 62272445Sassar if (setimes && wrerr == NO) { 62372445Sassar setimes = 0; 62472445Sassar if (utimes(np, tv) < 0) { 62572445Sassar run_err("%s: set times: %s", 62672445Sassar np, strerror(errno)); 62772445Sassar wrerr = DISPLAYED; 62872445Sassar } 62972445Sassar } 63072445Sassar switch(wrerr) { 63172445Sassar case YES: 63272445Sassar run_err("%s: %s", np, strerror(wrerrno)); 63372445Sassar break; 63472445Sassar case NO: 63578527Sassar write(remout, "", 1); 63672445Sassar break; 63772445Sassar case DISPLAYED: 63872445Sassar break; 63972445Sassar } 64072445Sassar } 64172445Sassarscrewup: 64272445Sassar run_err("protocol error: %s", why); 64372445Sassar exit(1); 64472445Sassar} 64572445Sassar 64672445Sassarint 64778527Sassarresponse(void) 64872445Sassar{ 64972445Sassar char ch, *cp, resp, rbuf[BUFSIZ]; 65072445Sassar 65172445Sassar if (read(remin, &resp, sizeof(resp)) != sizeof(resp)) 65272445Sassar lostconn(0); 65372445Sassar 65472445Sassar cp = rbuf; 65572445Sassar switch(resp) { 65672445Sassar case 0: /* ok */ 65772445Sassar return (0); 65872445Sassar default: 65972445Sassar *cp++ = resp; 66072445Sassar /* FALLTHROUGH */ 66172445Sassar case 1: /* error, followed by error msg */ 66272445Sassar case 2: /* fatal error, "" */ 66372445Sassar do { 66472445Sassar if (read(remin, &ch, sizeof(ch)) != sizeof(ch)) 66572445Sassar lostconn(0); 66672445Sassar *cp++ = ch; 66772445Sassar } while (cp < &rbuf[BUFSIZ] && ch != '\n'); 66872445Sassar 66972445Sassar if (!iamremote) 67078527Sassar write(STDERR_FILENO, rbuf, cp - rbuf); 67172445Sassar ++errs; 67272445Sassar if (resp == 1) 67372445Sassar return (-1); 67472445Sassar exit(1); 67572445Sassar } 67672445Sassar /* NOTREACHED */ 67772445Sassar} 67872445Sassar 67972445Sassar#include <stdarg.h> 68072445Sassar 68172445Sassarvoid 68272445Sassarrun_err(const char *fmt, ...) 68372445Sassar{ 68472445Sassar static FILE *fp; 68572445Sassar va_list ap; 68672445Sassar 68772445Sassar ++errs; 68872445Sassar if (fp == NULL && !(fp = fdopen(remout, "w"))) 68972445Sassar return; 69090926Snectar va_start(ap, fmt); 69178527Sassar fprintf(fp, "%c", 0x01); 69278527Sassar fprintf(fp, "rcp: "); 69378527Sassar vfprintf(fp, fmt, ap); 69478527Sassar fprintf(fp, "\n"); 69578527Sassar fflush(fp); 69690926Snectar va_end(ap); 69772445Sassar 69890926Snectar if (!iamremote) { 69990926Snectar va_start(ap, fmt); 70090926Snectar vwarnx(fmt, ap); 70190926Snectar va_end(ap); 70290926Snectar } 70372445Sassar} 70472445Sassar 70572445Sassar/* 70672445Sassar * This function executes the given command as the specified user on the 70772445Sassar * given host. This returns < 0 if execution fails, and >= 0 otherwise. This 70872445Sassar * assigns the input and output file descriptors on success. 70972445Sassar * 71072445Sassar * If it cannot create necessary pipes it exits with error message. 71172445Sassar */ 71272445Sassar 713233294Sstasint 71472445Sassardo_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout) 71572445Sassar{ 71672445Sassar int pin[2], pout[2], reserved[2]; 71772445Sassar 71872445Sassar /* 71972445Sassar * Reserve two descriptors so that the real pipes won't get 72072445Sassar * descriptors 0 and 1 because that will screw up dup2 below. 72172445Sassar */ 72272445Sassar pipe(reserved); 72372445Sassar 72472445Sassar /* Create a socket pair for communicating with rsh. */ 72572445Sassar if (pipe(pin) < 0) { 72672445Sassar perror("pipe"); 72772445Sassar exit(255); 72872445Sassar } 72972445Sassar if (pipe(pout) < 0) { 73072445Sassar perror("pipe"); 73172445Sassar exit(255); 73272445Sassar } 73372445Sassar 73472445Sassar /* Free the reserved descriptors. */ 73572445Sassar close(reserved[0]); 73672445Sassar close(reserved[1]); 73772445Sassar 73872445Sassar /* For a child to execute the command on the remote host using rsh. */ 73972445Sassar if (fork() == 0) { 74072445Sassar char *args[100]; 74172445Sassar unsigned int i; 74272445Sassar 74372445Sassar /* Child. */ 74472445Sassar close(pin[1]); 74572445Sassar close(pout[0]); 74672445Sassar dup2(pin[0], 0); 74772445Sassar dup2(pout[1], 1); 74872445Sassar close(pin[0]); 74972445Sassar close(pout[1]); 75072445Sassar 75172445Sassar i = 0; 75272445Sassar args[i++] = RSH_PROGRAM; 753120945Snectar if (usekrb4) 754120945Snectar args[i++] = "-4"; 75572445Sassar if (usekrb5) 75672445Sassar args[i++] = "-5"; 75772445Sassar if (usebroken) 75872445Sassar args[i++] = "-K"; 75972445Sassar if (doencrypt) 76072445Sassar args[i++] = "-x"; 76178527Sassar if (forwardtkt) 76278527Sassar args[i++] = "-F"; 76372445Sassar if (noencrypt) 76472445Sassar args[i++] = "-z"; 76572445Sassar if (port != NULL) { 76672445Sassar args[i++] = "-p"; 76772445Sassar args[i++] = port; 76872445Sassar } 769178825Sdfr if (eflag) 770178825Sdfr args[i++] = "-e"; 77172445Sassar if (remuser != NULL) { 77272445Sassar args[i++] = "-l"; 77372445Sassar args[i++] = remuser; 77472445Sassar } 77572445Sassar args[i++] = host; 77672445Sassar args[i++] = cmd; 77772445Sassar args[i++] = NULL; 77872445Sassar 77972445Sassar execvp(RSH_PROGRAM, args); 78072445Sassar perror(RSH_PROGRAM); 78172445Sassar exit(1); 78272445Sassar } 78372445Sassar /* Parent. Close the other side, and return the local side. */ 78472445Sassar close(pin[0]); 78572445Sassar *fdout = pin[1]; 78672445Sassar close(pout[1]); 78772445Sassar *fdin = pout[0]; 78872445Sassar return 0; 78972445Sassar} 790