rcp.c revision 78527
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. 1372445Sassar * 3. All advertising materials mentioning features or use of this software 1472445Sassar * must display the following acknowledgement: 1572445Sassar * This product includes software developed by the University of 1672445Sassar * California, Berkeley and its contributors. 1772445Sassar * 4. Neither the name of the University nor the names of its contributors 1872445Sassar * may be used to endorse or promote products derived from this software 1972445Sassar * without specific prior written permission. 2072445Sassar * 2172445Sassar * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2272445Sassar * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2372445Sassar * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2472445Sassar * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2572445Sassar * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2672445Sassar * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2772445Sassar * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2872445Sassar * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2972445Sassar * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3072445Sassar * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3172445Sassar * SUCH DAMAGE. 3272445Sassar */ 3372445Sassar 3472445Sassar#include "rcp_locl.h" 3578527Sassar#include <getarg.h> 3672445Sassar 3772445Sassar#define RSH_PROGRAM "rsh" 3872445Sassar 3972445Sassarstruct passwd *pwd; 4072445Sassaruid_t userid; 4172445Sassarint errs, remin, remout; 4272445Sassarint pflag, iamremote, iamrecursive, targetshouldbedirectory; 4372445Sassarint doencrypt, noencrypt; 4478527Sassarint usebroken, usekrb5, forwardtkt; 4572445Sassarchar *port; 4672445Sassar 4772445Sassar#define CMDNEEDS 64 4872445Sassarchar cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ 4972445Sassar 5072445Sassarint response (void); 5172445Sassarvoid rsource (char *, struct stat *); 5272445Sassarvoid sink (int, char *[]); 5372445Sassarvoid source (int, char *[]); 5472445Sassarvoid tolocal (int, char *[]); 5572445Sassarvoid toremote (char *, int, char *[]); 5672445Sassar 5772445Sassarint do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout); 5872445Sassar 5978527Sassarstatic int fflag, tflag; 6078527Sassar 6178527Sassarstatic int version_flag, help_flag; 6278527Sassar 6378527Sassarstruct getargs args[] = { 6478527Sassar { NULL, '5', arg_flag, &usekrb5, "use Kerberos 5 authentication" }, 6578527Sassar { NULL, 'F', arg_flag, &forwardtkt, "forward credentials" }, 6678527Sassar { NULL, 'K', arg_flag, &usebroken, "use BSD authentication" }, 6778527Sassar { NULL, 'P', arg_string, &port, "non-default port", "port" }, 6878527Sassar { NULL, 'p', arg_flag, &pflag, "preserve file permissions" }, 6978527Sassar { NULL, 'r', arg_flag, &iamrecursive, "recursive mode" }, 7078527Sassar { NULL, 'x', arg_flag, &doencrypt, "use encryption" }, 7178527Sassar { NULL, 'z', arg_flag, &noencrypt, "don't encrypt" }, 7278527Sassar { NULL, 'd', arg_flag, &targetshouldbedirectory }, 7378527Sassar { NULL, 'f', arg_flag, &fflag }, 7478527Sassar { NULL, 't', arg_flag, &tflag }, 7578527Sassar { "version", 0, arg_flag, &version_flag }, 7678527Sassar { "help", 0, arg_flag, &help_flag } 7778527Sassar}; 7878527Sassar 7978527Sassarstatic void 8078527Sassarusage (int ret) 8178527Sassar{ 8278527Sassar arg_printusage (args, 8378527Sassar sizeof(args) / sizeof(args[0]), 8478527Sassar NULL, 8578527Sassar "file1 file2|file... directory"); 8678527Sassar exit (ret); 8778527Sassar} 8878527Sassar 8972445Sassarint 9078527Sassarmain(int argc, char **argv) 9172445Sassar{ 9272445Sassar char *targ; 9378527Sassar int optind = 0; 9472445Sassar 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 } 10478527Sassar 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. */ 11778527Sassar response(); 11878527Sassar setuid(userid); 11972445Sassar source(argc, argv); 12072445Sassar exit(errs); 12172445Sassar } 12272445Sassar 12372445Sassar if (tflag) { /* Receive data. */ 12478527Sassar setuid(userid); 12572445Sassar sink(argc, argv); 12672445Sassar exit(errs); 12772445Sassar } 12872445Sassar 12972445Sassar if (argc < 2) 13078527Sassar usage(1); 13172445Sassar if (argc > 2) 13272445Sassar targetshouldbedirectory = 1; 13372445Sassar 13472445Sassar remin = remout = -1; 13572445Sassar /* Command to be executed on remote system using "rsh". */ 13678527Sassar sprintf(cmd, "rcp%s%s%s", iamrecursive ? " -r" : "", 13772445Sassar pflag ? " -p" : "", targetshouldbedirectory ? " -d" : ""); 13872445Sassar 13978527Sassar signal(SIGPIPE, lostconn); 14072445Sassar 14172445Sassar if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */ 14272445Sassar toremote(targ, argc, argv); 14372445Sassar else { 14472445Sassar tolocal(argc, argv); /* Dest is local host. */ 14572445Sassar if (targetshouldbedirectory) 14672445Sassar verifydir(argv[argc - 1]); 14772445Sassar } 14872445Sassar exit(errs); 14972445Sassar} 15072445Sassar 15172445Sassarvoid 15278527Sassartoremote(char *targ, int argc, char **argv) 15372445Sassar{ 15472445Sassar int i, len; 15572445Sassar char *bp, *host, *src, *suser, *thost, *tuser; 15672445Sassar 15772445Sassar *targ++ = 0; 15872445Sassar if (*targ == 0) 15972445Sassar targ = "."; 16072445Sassar 16172445Sassar if ((thost = strchr(argv[argc - 1], '@'))) { 16272445Sassar /* user@host */ 16372445Sassar *thost++ = 0; 16472445Sassar tuser = argv[argc - 1]; 16572445Sassar if (*tuser == '\0') 16672445Sassar tuser = NULL; 16772445Sassar else if (!okname(tuser)) 16872445Sassar exit(1); 16972445Sassar } else { 17072445Sassar thost = argv[argc - 1]; 17172445Sassar tuser = NULL; 17272445Sassar } 17372445Sassar 17472445Sassar for (i = 0; i < argc - 1; i++) { 17572445Sassar src = colon(argv[i]); 17672445Sassar if (src) { /* remote to remote */ 17772445Sassar *src++ = 0; 17872445Sassar if (*src == 0) 17972445Sassar src = "."; 18072445Sassar host = strchr(argv[i], '@'); 18172445Sassar len = strlen(_PATH_RSH) + strlen(argv[i]) + 18272445Sassar strlen(src) + (tuser ? strlen(tuser) : 0) + 18372445Sassar strlen(thost) + strlen(targ) + CMDNEEDS + 20; 18472445Sassar if (!(bp = malloc(len))) 18572445Sassar err(1, "malloc"); 18672445Sassar if (host) { 18772445Sassar *host++ = 0; 18872445Sassar suser = argv[i]; 18972445Sassar if (*suser == '\0') 19072445Sassar suser = pwd->pw_name; 19172445Sassar else if (!okname(suser)) 19272445Sassar continue; 19378527Sassar snprintf(bp, len, 19472445Sassar "%s %s -l %s -n %s %s '%s%s%s:%s'", 19572445Sassar _PATH_RSH, host, suser, cmd, src, 19672445Sassar tuser ? tuser : "", tuser ? "@" : "", 19772445Sassar thost, targ); 19872445Sassar } else 19978527Sassar snprintf(bp, len, 20072445Sassar "exec %s %s -n %s %s '%s%s%s:%s'", 20172445Sassar _PATH_RSH, argv[i], cmd, src, 20272445Sassar tuser ? tuser : "", tuser ? "@" : "", 20372445Sassar thost, targ); 20478527Sassar susystem(bp, userid); 20578527Sassar free(bp); 20672445Sassar } else { /* local to remote */ 20772445Sassar if (remin == -1) { 20872445Sassar len = strlen(targ) + CMDNEEDS + 20; 20972445Sassar if (!(bp = malloc(len))) 21072445Sassar err(1, "malloc"); 21178527Sassar snprintf(bp, len, "%s -t %s", cmd, targ); 21272445Sassar host = thost; 21372445Sassar 21472445Sassar if (do_cmd(host, tuser, bp, &remin, &remout) < 0) 21572445Sassar exit(1); 21672445Sassar 21772445Sassar if (response() < 0) 21872445Sassar exit(1); 21978527Sassar free(bp); 22078527Sassar setuid(userid); 22172445Sassar } 22272445Sassar source(1, argv+i); 22372445Sassar } 22472445Sassar } 22572445Sassar} 22672445Sassar 22772445Sassarvoid 22878527Sassartolocal(int argc, char **argv) 22972445Sassar{ 23072445Sassar int i, len; 23172445Sassar char *bp, *host, *src, *suser; 23272445Sassar 23372445Sassar for (i = 0; i < argc - 1; i++) { 23472445Sassar if (!(src = colon(argv[i]))) { /* Local to local. */ 23572445Sassar len = strlen(_PATH_CP) + strlen(argv[i]) + 23672445Sassar strlen(argv[argc - 1]) + 20; 23772445Sassar if (!(bp = malloc(len))) 23872445Sassar err(1, "malloc"); 23978527Sassar snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP, 24072445Sassar iamrecursive ? " -PR" : "", pflag ? " -p" : "", 24172445Sassar argv[i], argv[argc - 1]); 24272445Sassar if (susystem(bp, userid)) 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 } 26172445Sassar len = strlen(src) + CMDNEEDS + 20; 26272445Sassar if ((bp = malloc(len)) == NULL) 26372445Sassar err(1, "malloc"); 26478527Sassar snprintf(bp, len, "%s -f %s", cmd, src); 26572445Sassar if (do_cmd(host, suser, bp, &remin, &remout) < 0) { 26678527Sassar free(bp); 26772445Sassar ++errs; 26872445Sassar continue; 26972445Sassar } 27078527Sassar free(bp); 27172445Sassar sink(1, argv + argc - 1); 27278527Sassar seteuid(0); 27378527Sassar close(remin); 27472445Sassar remin = remout = -1; 27572445Sassar } 27672445Sassar} 27772445Sassar 27878527Sassarstatic char * 27978527Sassarsizestr(off_t size) 28078527Sassar{ 28178527Sassar static char ss[32]; 28278527Sassar char *p; 28378527Sassar ss[sizeof(ss) - 1] = '\0'; 28478527Sassar for(p = ss + sizeof(ss) - 2; p >= ss; p--) { 28578527Sassar *p = '0' + size % 10; 28678527Sassar size /= 10; 28778527Sassar if(size == 0) 28878527Sassar break; 28978527Sassar } 29078527Sassar return ss; 29178527Sassar} 29278527Sassar 29378527Sassar 29472445Sassarvoid 29578527Sassarsource(int argc, char **argv) 29672445Sassar{ 29772445Sassar struct stat stb; 29872445Sassar static BUF buffer; 29972445Sassar BUF *bp; 30072445Sassar off_t i; 30172445Sassar int amt, fd, haderr, indx, result; 30272445Sassar char *last, *name, buf[BUFSIZ]; 30372445Sassar 30472445Sassar for (indx = 0; indx < argc; ++indx) { 30572445Sassar name = argv[indx]; 30672445Sassar if ((fd = open(name, O_RDONLY, 0)) < 0) 30772445Sassar goto syserr; 30872445Sassar if (fstat(fd, &stb)) { 30972445Sassarsyserr: run_err("%s: %s", name, strerror(errno)); 31072445Sassar goto next; 31172445Sassar } 31272445Sassar switch (stb.st_mode & S_IFMT) { 31372445Sassar case S_IFREG: 31472445Sassar break; 31572445Sassar case S_IFDIR: 31672445Sassar if (iamrecursive) { 31772445Sassar rsource(name, &stb); 31872445Sassar goto next; 31972445Sassar } 32072445Sassar /* FALLTHROUGH */ 32172445Sassar default: 32272445Sassar run_err("%s: not a regular file", name); 32372445Sassar goto next; 32472445Sassar } 32572445Sassar if ((last = strrchr(name, '/')) == NULL) 32672445Sassar last = name; 32772445Sassar else 32872445Sassar ++last; 32972445Sassar if (pflag) { 33072445Sassar /* 33172445Sassar * Make it compatible with possible future 33272445Sassar * versions expecting microseconds. 33372445Sassar */ 33478527Sassar snprintf(buf, sizeof(buf), "T%ld 0 %ld 0\n", 33572445Sassar (long)stb.st_mtime, 33672445Sassar (long)stb.st_atime); 33778527Sassar write(remout, buf, strlen(buf)); 33872445Sassar if (response() < 0) 33972445Sassar goto next; 34072445Sassar } 34172445Sassar#define MODEMASK (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO) 34278527Sassar snprintf(buf, sizeof(buf), "C%04o %s %s\n", 34378527Sassar stb.st_mode & MODEMASK, sizestr(stb.st_size), last); 34478527Sassar write(remout, buf, strlen(buf)); 34572445Sassar if (response() < 0) 34672445Sassar goto next; 34772445Sassar if ((bp = allocbuf(&buffer, fd, BUFSIZ)) == NULL) { 34878527Sassarnext: close(fd); 34972445Sassar continue; 35072445Sassar } 35172445Sassar 35272445Sassar /* Keep writing after an error so that we stay sync'd up. */ 35372445Sassar for (haderr = i = 0; i < stb.st_size; i += bp->cnt) { 35472445Sassar amt = bp->cnt; 35572445Sassar if (i + amt > stb.st_size) 35672445Sassar amt = stb.st_size - i; 35772445Sassar if (!haderr) { 35872445Sassar result = read(fd, bp->buf, amt); 35972445Sassar if (result != amt) 36072445Sassar haderr = result >= 0 ? EIO : errno; 36172445Sassar } 36272445Sassar if (haderr) 36378527Sassar write(remout, bp->buf, amt); 36472445Sassar else { 36572445Sassar result = write(remout, bp->buf, amt); 36672445Sassar if (result != amt) 36772445Sassar haderr = result >= 0 ? EIO : errno; 36872445Sassar } 36972445Sassar } 37072445Sassar if (close(fd) && !haderr) 37172445Sassar haderr = errno; 37272445Sassar if (!haderr) 37378527Sassar write(remout, "", 1); 37472445Sassar else 37572445Sassar run_err("%s: %s", name, strerror(haderr)); 37678527Sassar response(); 37772445Sassar } 37872445Sassar} 37972445Sassar 38072445Sassarvoid 38178527Sassarrsource(char *name, struct stat *statp) 38272445Sassar{ 38372445Sassar DIR *dirp; 38472445Sassar struct dirent *dp; 38572445Sassar char *last, *vect[1], path[MAXPATHLEN]; 38672445Sassar 38772445Sassar if (!(dirp = opendir(name))) { 38872445Sassar run_err("%s: %s", name, strerror(errno)); 38972445Sassar return; 39072445Sassar } 39172445Sassar last = strrchr(name, '/'); 39272445Sassar if (last == 0) 39372445Sassar last = name; 39472445Sassar else 39572445Sassar last++; 39672445Sassar if (pflag) { 39778527Sassar snprintf(path, sizeof(path), "T%ld 0 %ld 0\n", 39872445Sassar (long)statp->st_mtime, 39972445Sassar (long)statp->st_atime); 40078527Sassar write(remout, path, strlen(path)); 40172445Sassar if (response() < 0) { 40272445Sassar closedir(dirp); 40372445Sassar return; 40472445Sassar } 40572445Sassar } 40678527Sassar snprintf(path, sizeof(path), 40772445Sassar "D%04o %d %s\n", statp->st_mode & MODEMASK, 0, last); 40878527Sassar write(remout, path, strlen(path)); 40972445Sassar if (response() < 0) { 41072445Sassar closedir(dirp); 41172445Sassar return; 41272445Sassar } 41372445Sassar while ((dp = readdir(dirp))) { 41472445Sassar if (dp->d_ino == 0) 41572445Sassar continue; 41672445Sassar if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 41772445Sassar continue; 41872445Sassar if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) { 41972445Sassar run_err("%s/%s: name too long", name, dp->d_name); 42072445Sassar continue; 42172445Sassar } 42278527Sassar snprintf(path, sizeof(path), "%s/%s", name, dp->d_name); 42372445Sassar vect[0] = path; 42472445Sassar source(1, vect); 42572445Sassar } 42678527Sassar closedir(dirp); 42778527Sassar write(remout, "E\n", 2); 42878527Sassar response(); 42972445Sassar} 43072445Sassar 43172445Sassarvoid 43278527Sassarsink(int argc, char **argv) 43372445Sassar{ 43472445Sassar static BUF buffer; 43572445Sassar struct stat stb; 43672445Sassar struct timeval tv[2]; 43772445Sassar enum { YES, NO, DISPLAYED } wrerr; 43872445Sassar BUF *bp; 43972445Sassar off_t i, j, size; 44072445Sassar int amt, count, exists, first, mask, mode, ofd, omode; 44172445Sassar int setimes, targisdir, wrerrno = 0; 44272445Sassar char ch, *cp, *np, *targ, *why, *vect[1], buf[BUFSIZ]; 44372445Sassar 44472445Sassar#define atime tv[0] 44572445Sassar#define mtime tv[1] 44672445Sassar#define SCREWUP(str) { why = str; goto screwup; } 44772445Sassar 44872445Sassar setimes = targisdir = 0; 44972445Sassar mask = umask(0); 45072445Sassar if (!pflag) 45178527Sassar umask(mask); 45272445Sassar if (argc != 1) { 45372445Sassar run_err("ambiguous target"); 45472445Sassar exit(1); 45572445Sassar } 45672445Sassar targ = *argv; 45772445Sassar if (targetshouldbedirectory) 45872445Sassar verifydir(targ); 45978527Sassar write(remout, "", 1); 46072445Sassar if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) 46172445Sassar targisdir = 1; 46272445Sassar for (first = 1;; first = 0) { 46372445Sassar cp = buf; 46472445Sassar if (read(remin, cp, 1) <= 0) 46572445Sassar return; 46672445Sassar if (*cp++ == '\n') 46772445Sassar SCREWUP("unexpected <newline>"); 46872445Sassar do { 46972445Sassar if (read(remin, &ch, sizeof(ch)) != sizeof(ch)) 47072445Sassar SCREWUP("lost connection"); 47172445Sassar *cp++ = ch; 47272445Sassar } while (cp < &buf[BUFSIZ - 1] && ch != '\n'); 47372445Sassar *cp = 0; 47472445Sassar 47572445Sassar if (buf[0] == '\01' || buf[0] == '\02') { 47672445Sassar if (iamremote == 0) 47778527Sassar write(STDERR_FILENO, 47872445Sassar buf + 1, strlen(buf + 1)); 47972445Sassar if (buf[0] == '\02') 48072445Sassar exit(1); 48172445Sassar ++errs; 48272445Sassar continue; 48372445Sassar } 48472445Sassar if (buf[0] == 'E') { 48578527Sassar write(remout, "", 1); 48672445Sassar return; 48772445Sassar } 48872445Sassar 48972445Sassar if (ch == '\n') 49072445Sassar *--cp = 0; 49172445Sassar 49272445Sassar cp = buf; 49372445Sassar if (*cp == 'T') { 49472445Sassar setimes++; 49572445Sassar cp++; 49672445Sassar mtime.tv_sec = strtol(cp, &cp, 10); 49772445Sassar if (!cp || *cp++ != ' ') 49872445Sassar SCREWUP("mtime.sec not delimited"); 49972445Sassar mtime.tv_usec = strtol(cp, &cp, 10); 50072445Sassar if (!cp || *cp++ != ' ') 50172445Sassar SCREWUP("mtime.usec not delimited"); 50272445Sassar atime.tv_sec = strtol(cp, &cp, 10); 50372445Sassar if (!cp || *cp++ != ' ') 50472445Sassar SCREWUP("atime.sec not delimited"); 50572445Sassar atime.tv_usec = strtol(cp, &cp, 10); 50672445Sassar if (!cp || *cp++ != '\0') 50772445Sassar SCREWUP("atime.usec not delimited"); 50878527Sassar write(remout, "", 1); 50972445Sassar continue; 51072445Sassar } 51172445Sassar if (*cp != 'C' && *cp != 'D') { 51272445Sassar /* 51372445Sassar * Check for the case "rcp remote:foo\* local:bar". 51472445Sassar * In this case, the line "No match." can be returned 51572445Sassar * by the shell before the rcp command on the remote is 51672445Sassar * executed so the ^Aerror_message convention isn't 51772445Sassar * followed. 51872445Sassar */ 51972445Sassar if (first) { 52072445Sassar run_err("%s", cp); 52172445Sassar exit(1); 52272445Sassar } 52372445Sassar SCREWUP("expected control record"); 52472445Sassar } 52572445Sassar mode = 0; 52672445Sassar for (++cp; cp < buf + 5; cp++) { 52772445Sassar if (*cp < '0' || *cp > '7') 52872445Sassar SCREWUP("bad mode"); 52972445Sassar mode = (mode << 3) | (*cp - '0'); 53072445Sassar } 53172445Sassar if (*cp++ != ' ') 53272445Sassar SCREWUP("mode not delimited"); 53372445Sassar 53472445Sassar for (size = 0; isdigit(*cp);) 53572445Sassar size = size * 10 + (*cp++ - '0'); 53672445Sassar if (*cp++ != ' ') 53772445Sassar SCREWUP("size not delimited"); 53872445Sassar if (targisdir) { 53972445Sassar static char *namebuf; 54072445Sassar static int cursize; 54172445Sassar size_t need; 54272445Sassar 54372445Sassar need = strlen(targ) + strlen(cp) + 250; 54472445Sassar if (need > cursize) { 54572445Sassar if (!(namebuf = malloc(need))) 54672445Sassar run_err("%s", strerror(errno)); 54772445Sassar } 54878527Sassar snprintf(namebuf, need, "%s%s%s", targ, 54972445Sassar *targ ? "/" : "", cp); 55072445Sassar np = namebuf; 55172445Sassar } else 55272445Sassar np = targ; 55372445Sassar exists = stat(np, &stb) == 0; 55472445Sassar if (buf[0] == 'D') { 55572445Sassar int mod_flag = pflag; 55672445Sassar if (exists) { 55772445Sassar if (!S_ISDIR(stb.st_mode)) { 55872445Sassar errno = ENOTDIR; 55972445Sassar goto bad; 56072445Sassar } 56172445Sassar if (pflag) 56278527Sassar chmod(np, mode); 56372445Sassar } else { 56472445Sassar /* Handle copying from a read-only directory */ 56572445Sassar mod_flag = 1; 56672445Sassar if (mkdir(np, mode | S_IRWXU) < 0) 56772445Sassar goto bad; 56872445Sassar } 56972445Sassar vect[0] = np; 57072445Sassar sink(1, vect); 57172445Sassar if (setimes) { 57272445Sassar setimes = 0; 57372445Sassar if (utimes(np, tv) < 0) 57472445Sassar run_err("%s: set times: %s", 57572445Sassar np, strerror(errno)); 57672445Sassar } 57772445Sassar if (mod_flag) 57878527Sassar chmod(np, mode); 57972445Sassar continue; 58072445Sassar } 58172445Sassar omode = mode; 58272445Sassar mode |= S_IWRITE; 58372445Sassar if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { 58472445Sassarbad: run_err("%s: %s", np, strerror(errno)); 58572445Sassar continue; 58672445Sassar } 58778527Sassar write(remout, "", 1); 58872445Sassar if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == NULL) { 58978527Sassar close(ofd); 59072445Sassar continue; 59172445Sassar } 59272445Sassar cp = bp->buf; 59372445Sassar wrerr = NO; 59472445Sassar for (count = i = 0; i < size; i += BUFSIZ) { 59572445Sassar amt = BUFSIZ; 59672445Sassar if (i + amt > size) 59772445Sassar amt = size - i; 59872445Sassar count += amt; 59978527Sassar if((j = net_read(remin, cp, amt)) != amt) { 60078527Sassar run_err("%s", j ? strerror(errno) : 60178527Sassar "dropped connection"); 60278527Sassar exit(1); 60378527Sassar } 60478527Sassar amt -= j; 60578527Sassar cp += j; 60672445Sassar if (count == bp->cnt) { 60772445Sassar /* Keep reading so we stay sync'd up. */ 60872445Sassar if (wrerr == NO) { 60972445Sassar j = write(ofd, bp->buf, count); 61072445Sassar if (j != count) { 61172445Sassar wrerr = YES; 61272445Sassar wrerrno = j >= 0 ? EIO : errno; 61372445Sassar } 61472445Sassar } 61572445Sassar count = 0; 61672445Sassar cp = bp->buf; 61772445Sassar } 61872445Sassar } 61972445Sassar if (count != 0 && wrerr == NO && 62072445Sassar (j = write(ofd, bp->buf, count)) != count) { 62172445Sassar wrerr = YES; 62272445Sassar wrerrno = j >= 0 ? EIO : errno; 62372445Sassar } 62472445Sassar if (ftruncate(ofd, size)) { 62572445Sassar run_err("%s: truncate: %s", np, strerror(errno)); 62672445Sassar wrerr = DISPLAYED; 62772445Sassar } 62872445Sassar if (pflag) { 62972445Sassar if (exists || omode != mode) 63072445Sassar if (fchmod(ofd, omode)) 63172445Sassar run_err("%s: set mode: %s", 63272445Sassar np, strerror(errno)); 63372445Sassar } else { 63472445Sassar if (!exists && omode != mode) 63572445Sassar if (fchmod(ofd, omode & ~mask)) 63672445Sassar run_err("%s: set mode: %s", 63772445Sassar np, strerror(errno)); 63872445Sassar } 63978527Sassar close(ofd); 64078527Sassar response(); 64172445Sassar if (setimes && wrerr == NO) { 64272445Sassar setimes = 0; 64372445Sassar if (utimes(np, tv) < 0) { 64472445Sassar run_err("%s: set times: %s", 64572445Sassar np, strerror(errno)); 64672445Sassar wrerr = DISPLAYED; 64772445Sassar } 64872445Sassar } 64972445Sassar switch(wrerr) { 65072445Sassar case YES: 65172445Sassar run_err("%s: %s", np, strerror(wrerrno)); 65272445Sassar break; 65372445Sassar case NO: 65478527Sassar write(remout, "", 1); 65572445Sassar break; 65672445Sassar case DISPLAYED: 65772445Sassar break; 65872445Sassar } 65972445Sassar } 66072445Sassarscrewup: 66172445Sassar run_err("protocol error: %s", why); 66272445Sassar exit(1); 66372445Sassar} 66472445Sassar 66572445Sassarint 66678527Sassarresponse(void) 66772445Sassar{ 66872445Sassar char ch, *cp, resp, rbuf[BUFSIZ]; 66972445Sassar 67072445Sassar if (read(remin, &resp, sizeof(resp)) != sizeof(resp)) 67172445Sassar lostconn(0); 67272445Sassar 67372445Sassar cp = rbuf; 67472445Sassar switch(resp) { 67572445Sassar case 0: /* ok */ 67672445Sassar return (0); 67772445Sassar default: 67872445Sassar *cp++ = resp; 67972445Sassar /* FALLTHROUGH */ 68072445Sassar case 1: /* error, followed by error msg */ 68172445Sassar case 2: /* fatal error, "" */ 68272445Sassar do { 68372445Sassar if (read(remin, &ch, sizeof(ch)) != sizeof(ch)) 68472445Sassar lostconn(0); 68572445Sassar *cp++ = ch; 68672445Sassar } while (cp < &rbuf[BUFSIZ] && ch != '\n'); 68772445Sassar 68872445Sassar if (!iamremote) 68978527Sassar write(STDERR_FILENO, rbuf, cp - rbuf); 69072445Sassar ++errs; 69172445Sassar if (resp == 1) 69272445Sassar return (-1); 69372445Sassar exit(1); 69472445Sassar } 69572445Sassar /* NOTREACHED */ 69672445Sassar} 69772445Sassar 69872445Sassar#include <stdarg.h> 69972445Sassar 70072445Sassarvoid 70172445Sassarrun_err(const char *fmt, ...) 70272445Sassar{ 70372445Sassar static FILE *fp; 70472445Sassar va_list ap; 70572445Sassar va_start(ap, fmt); 70672445Sassar 70772445Sassar ++errs; 70872445Sassar if (fp == NULL && !(fp = fdopen(remout, "w"))) 70972445Sassar return; 71078527Sassar fprintf(fp, "%c", 0x01); 71178527Sassar fprintf(fp, "rcp: "); 71278527Sassar vfprintf(fp, fmt, ap); 71378527Sassar fprintf(fp, "\n"); 71478527Sassar fflush(fp); 71572445Sassar 71672445Sassar if (!iamremote) 71772445Sassar vwarnx(fmt, ap); 71872445Sassar 71972445Sassar va_end(ap); 72072445Sassar} 72172445Sassar 72272445Sassar/* 72372445Sassar * This function executes the given command as the specified user on the 72472445Sassar * given host. This returns < 0 if execution fails, and >= 0 otherwise. This 72572445Sassar * assigns the input and output file descriptors on success. 72672445Sassar * 72772445Sassar * If it cannot create necessary pipes it exits with error message. 72872445Sassar */ 72972445Sassar 73072445Sassarint 73172445Sassardo_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout) 73272445Sassar{ 73372445Sassar int pin[2], pout[2], reserved[2]; 73472445Sassar 73572445Sassar /* 73672445Sassar * Reserve two descriptors so that the real pipes won't get 73772445Sassar * descriptors 0 and 1 because that will screw up dup2 below. 73872445Sassar */ 73972445Sassar pipe(reserved); 74072445Sassar 74172445Sassar /* Create a socket pair for communicating with rsh. */ 74272445Sassar if (pipe(pin) < 0) { 74372445Sassar perror("pipe"); 74472445Sassar exit(255); 74572445Sassar } 74672445Sassar if (pipe(pout) < 0) { 74772445Sassar perror("pipe"); 74872445Sassar exit(255); 74972445Sassar } 75072445Sassar 75172445Sassar /* Free the reserved descriptors. */ 75272445Sassar close(reserved[0]); 75372445Sassar close(reserved[1]); 75472445Sassar 75572445Sassar /* For a child to execute the command on the remote host using rsh. */ 75672445Sassar if (fork() == 0) { 75772445Sassar char *args[100]; 75872445Sassar unsigned int i; 75972445Sassar 76072445Sassar /* Child. */ 76172445Sassar close(pin[1]); 76272445Sassar close(pout[0]); 76372445Sassar dup2(pin[0], 0); 76472445Sassar dup2(pout[1], 1); 76572445Sassar close(pin[0]); 76672445Sassar close(pout[1]); 76772445Sassar 76872445Sassar i = 0; 76972445Sassar args[i++] = RSH_PROGRAM; 77072445Sassar if (usekrb5) 77172445Sassar args[i++] = "-5"; 77272445Sassar if (usebroken) 77372445Sassar args[i++] = "-K"; 77472445Sassar if (doencrypt) 77572445Sassar args[i++] = "-x"; 77678527Sassar if (forwardtkt) 77778527Sassar args[i++] = "-F"; 77872445Sassar if (noencrypt) 77972445Sassar args[i++] = "-z"; 78072445Sassar if (port != NULL) { 78172445Sassar args[i++] = "-p"; 78272445Sassar args[i++] = port; 78372445Sassar } 78472445Sassar if (remuser != NULL) { 78572445Sassar args[i++] = "-l"; 78672445Sassar args[i++] = remuser; 78772445Sassar } 78872445Sassar args[i++] = host; 78972445Sassar args[i++] = cmd; 79072445Sassar args[i++] = NULL; 79172445Sassar 79272445Sassar execvp(RSH_PROGRAM, args); 79372445Sassar perror(RSH_PROGRAM); 79472445Sassar exit(1); 79572445Sassar } 79672445Sassar /* Parent. Close the other side, and return the local side. */ 79772445Sassar close(pin[0]); 79872445Sassar *fdout = pin[1]; 79972445Sassar close(pout[1]); 80072445Sassar *fdin = pout[0]; 80172445Sassar return 0; 80272445Sassar} 803