121569Sdist /* 254570Sandrew * Copyright (c) 1983, 1990, 1992 The Regents of the University of California. 335619Sbostic * All rights reserved. 435619Sbostic * 542539Sbostic * %sccs.include.redist.c% 621569Sdist */ 721569Sdist 86440Swnj #ifndef lint 921569Sdist char copyright[] = 1054570Sandrew "@(#) Copyright (c) 1983, 1990, 1992 The Regents of the University of California.\n\ 1121569Sdist All rights reserved.\n"; 1235619Sbostic #endif /* not lint */ 136440Swnj 1421569Sdist #ifndef lint 15*56587Sbostic static char sccsid[] = "@(#)rcp.c 5.35 (Berkeley) 10/17/92"; 1635619Sbostic #endif /* not lint */ 1721569Sdist 186720Smckusick #include <sys/param.h> 196440Swnj #include <sys/stat.h> 2023101Slepreau #include <sys/time.h> 2146655Sbostic #include <sys/socket.h> 229199Ssam #include <netinet/in.h> 2344342Skarels #include <netinet/in_systm.h> 2444342Skarels #include <netinet/ip.h> 2554151Sbostic 26*56587Sbostic #include <ctype.h> 2746655Sbostic #include <dirent.h> 28*56587Sbostic #include <errno.h> 2946655Sbostic #include <fcntl.h> 30*56587Sbostic #include <netdb.h> 316440Swnj #include <pwd.h> 32*56587Sbostic #include <signal.h> 3338098Sbostic #include <stdio.h> 3445647Storek #include <stdlib.h> 3546655Sbostic #include <string.h> 36*56587Sbostic #include <string.h> 37*56587Sbostic #include <unistd.h> 38*56587Sbostic 3937037Sbostic #include "pathnames.h" 4054151Sbostic #include "extern.h" 4112989Ssam 4238098Sbostic #ifdef KERBEROS 4342498Sbostic #include <kerberosIV/des.h> 4441785Sbostic #include <kerberosIV/krb.h> 4554151Sbostic 4638879Skfall char dst_realm_buf[REALM_SZ]; 4738879Skfall char *dest_realm = NULL; 4845397Smckusick int use_kerberos = 1; 4938879Skfall CREDENTIALS cred; 5038879Skfall Key_schedule schedule; 5138879Skfall extern char *krb_realmofhost(); 5254151Sbostic #ifdef CRYPT 5354151Sbostic int doencrypt = 0; 5454151Sbostic #define OPTIONS "dfKk:prtx" 5545397Smckusick #else 5654151Sbostic #define OPTIONS "dfKk:prt" 5754151Sbostic #endif 5854151Sbostic #else 5938879Skfall #define OPTIONS "dfprt" 6036624Skfall #endif 6136624Skfall 6238098Sbostic struct passwd *pwd; 6338879Skfall u_short port; 6438879Skfall uid_t userid; 6538879Skfall int errs, rem; 6638879Skfall int pflag, iamremote, iamrecursive, targetshouldbedirectory; 676440Swnj 6838879Skfall #define CMDNEEDS 64 6938100Sbostic char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ 7038098Sbostic 7154151Sbostic #ifdef KERBEROS 7254151Sbostic int kerberos __P((char **, char *, char *, char *)); 7354151Sbostic void oldw __P((const char *, ...)); 7454151Sbostic #endif 7554151Sbostic int response __P((void)); 7654151Sbostic void rsource __P((char *, struct stat *)); 7754151Sbostic void sink __P((int, char *[])); 7854151Sbostic void source __P((int, char *[])); 7954151Sbostic void tolocal __P((int, char *[])); 8054151Sbostic void toremote __P((char *, int, char *[])); 8154151Sbostic void usage __P((void)); 8221254Smckusick 8354151Sbostic int 846440Swnj main(argc, argv) 856440Swnj int argc; 8654151Sbostic char *argv[]; 876440Swnj { 8818126Sralph struct servent *sp; 8938099Sbostic int ch, fflag, tflag; 9054151Sbostic char *targ, *shell; 9118026Sralph 9238099Sbostic fflag = tflag = 0; 9338879Skfall while ((ch = getopt(argc, argv, OPTIONS)) != EOF) 9454151Sbostic switch(ch) { /* User-visible flags. */ 9554151Sbostic case 'K': 9654151Sbostic #ifdef KERBEROS 9754151Sbostic use_kerberos = 0; 9854151Sbostic #endif 9923101Slepreau break; 10038879Skfall #ifdef KERBEROS 10138879Skfall case 'k': 10238879Skfall dest_realm = dst_realm_buf; 10354151Sbostic (void)strncpy(dst_realm_buf, optarg, REALM_SZ); 10438099Sbostic break; 10554151Sbostic #ifdef CRYPT 10654151Sbostic case 'x': 10754151Sbostic doencrypt = 1; 10854151Sbostic /* des_set_key(cred.session, schedule); */ 10954151Sbostic break; 11038098Sbostic #endif 11154151Sbostic #endif 11254151Sbostic case 'p': 11354151Sbostic pflag = 1; 11454151Sbostic break; 11554151Sbostic case 'r': 11654151Sbostic iamrecursive = 1; 11754151Sbostic break; 11854151Sbostic /* Server options. */ 11938879Skfall case 'd': 12038879Skfall targetshouldbedirectory = 1; 12138879Skfall break; 12238879Skfall case 'f': /* "from" */ 12338879Skfall iamremote = 1; 12438879Skfall fflag = 1; 12538879Skfall break; 12638879Skfall case 't': /* "to" */ 12738879Skfall iamremote = 1; 12838879Skfall tflag = 1; 12938879Skfall break; 13038098Sbostic case '?': 13138098Sbostic default: 13232127Sbostic usage(); 13323101Slepreau } 13438098Sbostic argc -= optind; 13538098Sbostic argv += optind; 13638098Sbostic 13738879Skfall #ifdef KERBEROS 13854151Sbostic if (use_kerberos) { 13954151Sbostic #ifdef CRYPT 14054151Sbostic shell = doencrypt ? "ekshell" : "kshell"; 14154151Sbostic #else 14254151Sbostic shell = "kshell"; 14354151Sbostic #endif 14454151Sbostic if ((sp = getservbyname(shell, "tcp")) == NULL) { 14554151Sbostic use_kerberos = 0; 14654151Sbostic oldw("can't get entry for %s/tcp service", shell); 14754151Sbostic sp = getservbyname(shell = "shell", "tcp"); 14854151Sbostic } 14954151Sbostic } else 15045647Storek sp = getservbyname(shell = "shell", "tcp"); 15138879Skfall #else 15245647Storek sp = getservbyname(shell = "shell", "tcp"); 15338879Skfall #endif 15438879Skfall if (sp == NULL) { 15545647Storek (void)fprintf(stderr, "rcp: %s/tcp: unknown service\n", shell); 15638879Skfall exit(1); 15738879Skfall } 15838879Skfall port = sp->s_port; 15938879Skfall 16054151Sbostic if ((pwd = getpwuid(userid = getuid())) == NULL) { 16145647Storek (void)fprintf(stderr, "rcp: unknown user %d.\n", (int)userid); 16238879Skfall exit(1); 16338879Skfall } 16438879Skfall 16554151Sbostic rem = STDIN_FILENO; /* XXX */ 16654151Sbostic 16754151Sbostic if (fflag) { /* Follow "protocol", send data. */ 16838099Sbostic (void)response(); 16938099Sbostic (void)setuid(userid); 17038099Sbostic source(argc, argv); 17138099Sbostic exit(errs); 17238099Sbostic } 17338099Sbostic 17454151Sbostic if (tflag) { /* Receive data. */ 17538099Sbostic (void)setuid(userid); 17638099Sbostic sink(argc, argv); 17738099Sbostic exit(errs); 17838099Sbostic } 17938099Sbostic 18032127Sbostic if (argc < 2) 18132127Sbostic usage(); 1826440Swnj if (argc > 2) 1836440Swnj targetshouldbedirectory = 1; 18438098Sbostic 18532127Sbostic rem = -1; 18654151Sbostic /* Command to be executed on remote system using "rsh". */ 18738879Skfall #ifdef KERBEROS 18846655Sbostic (void)snprintf(cmd, sizeof(cmd), 18946655Sbostic "rcp%s%s%s%s", iamrecursive ? " -r" : "", 19054151Sbostic #ifdef CRYPT 19154151Sbostic (doencrypt && use_kerberos ? " -x" : ""), 19254151Sbostic #else 19345397Smckusick "", 19454151Sbostic #endif 19538879Skfall pflag ? " -p" : "", targetshouldbedirectory ? " -d" : ""); 19638879Skfall #else 19746655Sbostic (void)snprintf(cmd, sizeof(cmd), "rcp%s%s%s", 19846655Sbostic iamrecursive ? " -r" : "", pflag ? " -p" : "", 19946655Sbostic targetshouldbedirectory ? " -d" : ""); 20038879Skfall #endif 20138098Sbostic 20238098Sbostic (void)signal(SIGPIPE, lostconn); 20338098Sbostic 20454151Sbostic if (targ = colon(argv[argc - 1])) /* Dest is remote host. */ 20554151Sbostic toremote(targ, argc, argv); 20638098Sbostic else { 20754151Sbostic tolocal(argc, argv); /* Dest is local host. */ 20838098Sbostic if (targetshouldbedirectory) 20938098Sbostic verifydir(argv[argc - 1]); 21038098Sbostic } 21138098Sbostic exit(errs); 21238098Sbostic } 21338098Sbostic 21454151Sbostic void 21538098Sbostic toremote(targ, argc, argv) 21654151Sbostic char *targ, *argv[]; 21738098Sbostic int argc; 21838098Sbostic { 21946655Sbostic int i, len, tos; 22038100Sbostic char *bp, *host, *src, *suser, *thost, *tuser; 22138098Sbostic 22238098Sbostic *targ++ = 0; 22338098Sbostic if (*targ == 0) 22438098Sbostic targ = "."; 22538098Sbostic 22638100Sbostic if (thost = index(argv[argc - 1], '@')) { 22738879Skfall /* user@host */ 22838098Sbostic *thost++ = 0; 22938098Sbostic tuser = argv[argc - 1]; 23038098Sbostic if (*tuser == '\0') 23124711Sbloom tuser = NULL; 23238098Sbostic else if (!okname(tuser)) 23338098Sbostic exit(1); 23438098Sbostic } else { 23538098Sbostic thost = argv[argc - 1]; 23638098Sbostic tuser = NULL; 23738098Sbostic } 23836624Skfall 23938098Sbostic for (i = 0; i < argc - 1; i++) { 24038098Sbostic src = colon(argv[i]); 24138098Sbostic if (src) { /* remote to remote */ 24238098Sbostic *src++ = 0; 24338098Sbostic if (*src == 0) 24438098Sbostic src = "."; 24538098Sbostic host = index(argv[i], '@'); 24646655Sbostic len = strlen(_PATH_RSH) + strlen(argv[i]) + 24746655Sbostic strlen(src) + (tuser ? strlen(tuser) : 0) + 24846655Sbostic strlen(thost) + strlen(targ) + CMDNEEDS + 20; 24946655Sbostic if (!(bp = malloc(len))) 25046655Sbostic nospace(); 25138098Sbostic if (host) { 25238098Sbostic *host++ = 0; 25338098Sbostic suser = argv[i]; 25438098Sbostic if (*suser == '\0') 25538098Sbostic suser = pwd->pw_name; 25638098Sbostic else if (!okname(suser)) 25738098Sbostic continue; 25846655Sbostic (void)snprintf(bp, len, 25938098Sbostic "%s %s -l %s -n %s %s '%s%s%s:%s'", 26038098Sbostic _PATH_RSH, host, suser, cmd, src, 26138098Sbostic tuser ? tuser : "", tuser ? "@" : "", 26238098Sbostic thost, targ); 26338098Sbostic } else 26446655Sbostic (void)snprintf(bp, len, 26546655Sbostic "%s %s -n %s %s '%s%s%s:%s'", 26638098Sbostic _PATH_RSH, argv[i], cmd, src, 26738098Sbostic tuser ? tuser : "", tuser ? "@" : "", 26838098Sbostic thost, targ); 26954151Sbostic (void)susystem(bp, userid); 27038100Sbostic (void)free(bp); 27138098Sbostic } else { /* local to remote */ 27238098Sbostic if (rem == -1) { 27346655Sbostic len = strlen(targ) + CMDNEEDS + 20; 27446655Sbostic if (!(bp = malloc(len))) 27538100Sbostic nospace(); 27646655Sbostic (void)snprintf(bp, len, "%s -t %s", cmd, targ); 27738098Sbostic host = thost; 27838098Sbostic #ifdef KERBEROS 27938098Sbostic if (use_kerberos) 28038879Skfall rem = kerberos(&host, bp, 28138879Skfall pwd->pw_name, 28238100Sbostic tuser ? tuser : pwd->pw_name); 28338098Sbostic else 28438098Sbostic #endif 28524711Sbloom rem = rcmd(&host, port, pwd->pw_name, 28624711Sbloom tuser ? tuser : pwd->pw_name, 28738100Sbostic bp, 0); 28838098Sbostic if (rem < 0) 28938098Sbostic exit(1); 29044342Skarels tos = IPTOS_THROUGHPUT; 29144342Skarels if (setsockopt(rem, IPPROTO_IP, IP_TOS, 29254151Sbostic &tos, sizeof(int)) < 0) 29354151Sbostic (void)fprintf(stderr, 29454151Sbostic "rcp: TOS (ignored): %s\n", 29554151Sbostic strerror(errno)); 29638098Sbostic if (response() < 0) 29738098Sbostic exit(1); 29838100Sbostic (void)free(bp); 29938098Sbostic (void)setuid(userid); 3006440Swnj } 30138098Sbostic source(1, argv+i); 3026440Swnj } 30338098Sbostic } 30438098Sbostic } 30538098Sbostic 30654151Sbostic void 30738098Sbostic tolocal(argc, argv) 30838098Sbostic int argc; 30954151Sbostic char *argv[]; 31038098Sbostic { 31146655Sbostic int i, len, tos; 31238100Sbostic char *bp, *host, *src, *suser; 31338098Sbostic 31438098Sbostic for (i = 0; i < argc - 1; i++) { 31554151Sbostic if (!(src = colon(argv[i]))) { /* Local to local. */ 31646655Sbostic len = strlen(_PATH_CP) + strlen(argv[i]) + 31746655Sbostic strlen(argv[argc - 1]) + 20; 31846655Sbostic if (!(bp = malloc(len))) 31938100Sbostic nospace(); 32046655Sbostic (void)snprintf(bp, len, "%s%s%s %s %s", _PATH_CP, 32138100Sbostic iamrecursive ? " -r" : "", pflag ? " -p" : "", 32238100Sbostic argv[i], argv[argc - 1]); 32354570Sandrew if (susystem(bp, userid)) 32454570Sandrew ++errs; 32538100Sbostic (void)free(bp); 32638100Sbostic continue; 32738100Sbostic } 32838100Sbostic *src++ = 0; 32938100Sbostic if (*src == 0) 33038100Sbostic src = "."; 33154151Sbostic if ((host = index(argv[i], '@')) == NULL) { 33254151Sbostic host = argv[i]; 33354151Sbostic suser = pwd->pw_name; 33454151Sbostic } else { 33538100Sbostic *host++ = 0; 33638100Sbostic suser = argv[i]; 33738100Sbostic if (*suser == '\0') 33838098Sbostic suser = pwd->pw_name; 33938100Sbostic else if (!okname(suser)) 34038100Sbostic continue; 34138100Sbostic } 34246655Sbostic len = strlen(src) + CMDNEEDS + 20; 34354151Sbostic if ((bp = malloc(len)) == NULL) 34438100Sbostic nospace(); 34546655Sbostic (void)snprintf(bp, len, "%s -f %s", cmd, src); 34654151Sbostic rem = 34738098Sbostic #ifdef KERBEROS 34854151Sbostic use_kerberos ? 34954151Sbostic kerberos(&host, bp, pwd->pw_name, suser) : 35038098Sbostic #endif 35154151Sbostic rcmd(&host, port, pwd->pw_name, suser, bp, 0); 35238100Sbostic (void)free(bp); 35354570Sandrew if (rem < 0) { 35454570Sandrew ++errs; 35538100Sbostic continue; 35654570Sandrew } 35744342Skarels (void)seteuid(userid); 35844342Skarels tos = IPTOS_THROUGHPUT; 35954151Sbostic if (setsockopt(rem, IPPROTO_IP, IP_TOS, &tos, sizeof(int)) < 0) 36054151Sbostic (void)fprintf(stderr, "rcp: TOS (ignored): %s\n", 36154151Sbostic strerror(errno)); 36238100Sbostic sink(1, argv + argc - 1); 36344342Skarels (void)seteuid(0); 36438100Sbostic (void)close(rem); 36538100Sbostic rem = -1; 3666440Swnj } 3676440Swnj } 3686440Swnj 36954151Sbostic void 3706440Swnj source(argc, argv) 3716440Swnj int argc; 37254151Sbostic char *argv[]; 3736440Swnj { 3746440Swnj struct stat stb; 37538098Sbostic static BUF buffer; 37638098Sbostic BUF *bp; 37738098Sbostic off_t i; 37854570Sandrew int amt, fd, haderr, indx, result; 37938098Sbostic char *last, *name, buf[BUFSIZ]; 3806440Swnj 38154570Sandrew for (indx = 0; indx < argc; ++indx) { 38254570Sandrew name = argv[indx]; 38354151Sbostic if ((fd = open(name, O_RDONLY, 0)) < 0) 38454151Sbostic goto syserr; 38554151Sbostic if (fstat(fd, &stb)) { 38654151Sbostic syserr: err("%s: %s", name, strerror(errno)); 38754151Sbostic goto next; 3886440Swnj } 38954151Sbostic switch (stb.st_mode & S_IFMT) { 3906440Swnj case S_IFREG: 3916440Swnj break; 3926440Swnj case S_IFDIR: 3936440Swnj if (iamrecursive) { 39423101Slepreau rsource(name, &stb); 39554151Sbostic goto next; 3966440Swnj } 39738098Sbostic /* FALLTHROUGH */ 3986440Swnj default: 39954151Sbostic err("%s: not a regular file", name); 40054151Sbostic goto next; 4016440Swnj } 40254151Sbostic if ((last = rindex(name, '/')) == NULL) 4036440Swnj last = name; 4046440Swnj else 40554151Sbostic ++last; 40623101Slepreau if (pflag) { 40723101Slepreau /* 40823101Slepreau * Make it compatible with possible future 40923101Slepreau * versions expecting microseconds. 41023101Slepreau */ 411*56587Sbostic (void)snprintf(buf, sizeof(buf), "T%ld 0 %ld 0\n", 41254151Sbostic stb.st_mtimespec.ts_sec, stb.st_atimespec.ts_sec); 413*56587Sbostic (void)write(rem, buf, strlen(buf)); 41454151Sbostic if (response() < 0) 41554151Sbostic goto next; 41623101Slepreau } 41754151Sbostic #define MODEMASK (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO) 418*56587Sbostic (void)snprintf(buf, sizeof(buf), "C%04o %qd %s\n", 41954151Sbostic stb.st_mode & MODEMASK, stb.st_size, last); 420*56587Sbostic (void)write(rem, buf, strlen(buf)); 42154151Sbostic if (response() < 0) 42254151Sbostic goto next; 42354570Sandrew if ((bp = allocbuf(&buffer, fd, BUFSIZ)) == NULL) { 42454570Sandrew next: (void)close(fd); 42554570Sandrew continue; 42654570Sandrew } 42754570Sandrew 42854570Sandrew /* Keep writing after an error so that we stay sync'd up. */ 42954570Sandrew for (haderr = i = 0; i < stb.st_size; i += bp->cnt) { 43021254Smckusick amt = bp->cnt; 4316440Swnj if (i + amt > stb.st_size) 4326440Swnj amt = stb.st_size - i; 43354570Sandrew if (!haderr) { 43454570Sandrew result = read(fd, bp->buf, amt); 43554570Sandrew if (result != amt) 43654570Sandrew haderr = result >= 0 ? EIO : errno; 43754151Sbostic } 43854570Sandrew if (haderr) 43954570Sandrew (void)write(rem, bp->buf, amt); 44054570Sandrew else { 44154570Sandrew result = write(rem, bp->buf, amt); 44254570Sandrew if (result != amt) 44354570Sandrew haderr = result >= 0 ? EIO : errno; 44454570Sandrew } 4456440Swnj } 44654570Sandrew if (close(fd) && !haderr) 44754570Sandrew haderr = errno; 44854570Sandrew if (!haderr) 44938098Sbostic (void)write(rem, "", 1); 45054570Sandrew else 45154570Sandrew err("%s: %s", name, strerror(haderr)); 45238098Sbostic (void)response(); 4536440Swnj } 4546440Swnj } 4556440Swnj 45654151Sbostic void 45723101Slepreau rsource(name, statp) 4586440Swnj char *name; 45923101Slepreau struct stat *statp; 4606440Swnj { 46146655Sbostic DIR *dirp; 46246655Sbostic struct dirent *dp; 46338100Sbostic char *last, *vect[1], path[MAXPATHLEN]; 4646440Swnj 46546655Sbostic if (!(dirp = opendir(name))) { 46654151Sbostic err("%s: %s", name, strerror(errno)); 4676440Swnj return; 4686440Swnj } 4696440Swnj last = rindex(name, '/'); 4706440Swnj if (last == 0) 4716440Swnj last = name; 4726440Swnj else 4736440Swnj last++; 47423101Slepreau if (pflag) { 475*56587Sbostic (void)snprintf(path, sizeof(path), "T%ld 0 %ld 0\n", 47654151Sbostic statp->st_mtimespec.ts_sec, statp->st_atimespec.ts_sec); 477*56587Sbostic (void)write(rem, path, strlen(path)); 47823101Slepreau if (response() < 0) { 47946655Sbostic closedir(dirp); 48023101Slepreau return; 48123101Slepreau } 48223101Slepreau } 483*56587Sbostic (void)snprintf(path, sizeof(path), 48454151Sbostic "D%04o %d %s\n", statp->st_mode & MODEMASK, 0, last); 485*56587Sbostic (void)write(rem, path, strlen(path)); 4866440Swnj if (response() < 0) { 48746655Sbostic closedir(dirp); 4886440Swnj return; 4896440Swnj } 49046655Sbostic while (dp = readdir(dirp)) { 4916440Swnj if (dp->d_ino == 0) 4926440Swnj continue; 4936440Swnj if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 4946440Swnj continue; 49538100Sbostic if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) { 49654151Sbostic err("%s/%s: name too long", name, dp->d_name); 4976440Swnj continue; 4986440Swnj } 49946655Sbostic (void)snprintf(path, sizeof(path), "%s/%s", name, dp->d_name); 50038100Sbostic vect[0] = path; 50138100Sbostic source(1, vect); 5026440Swnj } 50354151Sbostic (void)closedir(dirp); 50438098Sbostic (void)write(rem, "E\n", 2); 50538098Sbostic (void)response(); 5066440Swnj } 5076440Swnj 50846655Sbostic void 5096440Swnj sink(argc, argv) 5106440Swnj int argc; 51154151Sbostic char *argv[]; 5126440Swnj { 51354151Sbostic static BUF buffer; 51438100Sbostic register char *cp; 51521254Smckusick struct stat stb; 51623101Slepreau struct timeval tv[2]; 51738469Sbostic enum { YES, NO, DISPLAYED } wrerr; 51854151Sbostic BUF *bp; 51938100Sbostic off_t i, j; 52054570Sandrew int amt, count, exists, first, mask, mode, ofd, omode; 52154570Sandrew int setimes, size, targisdir, wrerrno; 52254570Sandrew char ch, *np, *targ, *why, *vect[1], buf[BUFSIZ]; 5236440Swnj 52438100Sbostic #define atime tv[0] 52538100Sbostic #define mtime tv[1] 52638100Sbostic #define SCREWUP(str) { why = str; goto screwup; } 52738100Sbostic 52838100Sbostic setimes = targisdir = 0; 52938100Sbostic mask = umask(0); 53023112Slepreau if (!pflag) 53138098Sbostic (void)umask(mask); 53218126Sralph if (argc != 1) { 53354151Sbostic err("ambiguous target"); 5346440Swnj exit(1); 5356440Swnj } 5366440Swnj targ = *argv; 5376440Swnj if (targetshouldbedirectory) 5386440Swnj verifydir(targ); 53938098Sbostic (void)write(rem, "", 1); 54054151Sbostic if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) 5416440Swnj targisdir = 1; 54238100Sbostic for (first = 1;; first = 0) { 54338100Sbostic cp = buf; 5446440Swnj if (read(rem, cp, 1) <= 0) 5456440Swnj return; 5466440Swnj if (*cp++ == '\n') 54738100Sbostic SCREWUP("unexpected <newline>"); 5486440Swnj do { 54938100Sbostic if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) 5506440Swnj SCREWUP("lost connection"); 55138100Sbostic *cp++ = ch; 55238100Sbostic } while (cp < &buf[BUFSIZ - 1] && ch != '\n'); 5536440Swnj *cp = 0; 55438100Sbostic 55538100Sbostic if (buf[0] == '\01' || buf[0] == '\02') { 5566440Swnj if (iamremote == 0) 55754151Sbostic (void)write(STDERR_FILENO, 55854151Sbostic buf + 1, strlen(buf + 1)); 55938100Sbostic if (buf[0] == '\02') 5606440Swnj exit(1); 56154151Sbostic ++errs; 5626440Swnj continue; 5636440Swnj } 56438100Sbostic if (buf[0] == 'E') { 56538098Sbostic (void)write(rem, "", 1); 5666440Swnj return; 5676440Swnj } 56823101Slepreau 56938108Sbostic if (ch == '\n') 57038115Sbostic *--cp = 0; 57138108Sbostic 57223101Slepreau #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0'); 57338100Sbostic cp = buf; 57423101Slepreau if (*cp == 'T') { 57523101Slepreau setimes++; 57623101Slepreau cp++; 57723101Slepreau getnum(mtime.tv_sec); 57823101Slepreau if (*cp++ != ' ') 57923101Slepreau SCREWUP("mtime.sec not delimited"); 58023101Slepreau getnum(mtime.tv_usec); 58123101Slepreau if (*cp++ != ' ') 58223101Slepreau SCREWUP("mtime.usec not delimited"); 58323101Slepreau getnum(atime.tv_sec); 58423101Slepreau if (*cp++ != ' ') 58523101Slepreau SCREWUP("atime.sec not delimited"); 58623101Slepreau getnum(atime.tv_usec); 58723101Slepreau if (*cp++ != '\0') 58823101Slepreau SCREWUP("atime.usec not delimited"); 58938098Sbostic (void)write(rem, "", 1); 59023101Slepreau continue; 59123101Slepreau } 59214580Sralph if (*cp != 'C' && *cp != 'D') { 59314580Sralph /* 59414580Sralph * Check for the case "rcp remote:foo\* local:bar". 59514580Sralph * In this case, the line "No match." can be returned 59614580Sralph * by the shell before the rcp command on the remote is 59714580Sralph * executed so the ^Aerror_message convention isn't 59814580Sralph * followed. 59914580Sralph */ 60014580Sralph if (first) { 60154151Sbostic err("%s", cp); 60214580Sralph exit(1); 60314580Sralph } 6046440Swnj SCREWUP("expected control record"); 60514580Sralph } 6066440Swnj mode = 0; 60738100Sbostic for (++cp; cp < buf + 5; cp++) { 6086440Swnj if (*cp < '0' || *cp > '7') 6096440Swnj SCREWUP("bad mode"); 6106440Swnj mode = (mode << 3) | (*cp - '0'); 6116440Swnj } 6126440Swnj if (*cp++ != ' ') 6136440Swnj SCREWUP("mode not delimited"); 61454151Sbostic 61554151Sbostic for (size = 0; isdigit(*cp);) 6166440Swnj size = size * 10 + (*cp++ - '0'); 6176440Swnj if (*cp++ != ' ') 6186440Swnj SCREWUP("size not delimited"); 61938100Sbostic if (targisdir) { 62038100Sbostic static char *namebuf; 62138100Sbostic static int cursize; 62245647Storek size_t need; 62338100Sbostic 62438100Sbostic need = strlen(targ) + strlen(cp) + 250; 62538100Sbostic if (need > cursize) { 62645647Storek if (!(namebuf = malloc(need))) 62754151Sbostic err("%s", strerror(errno)); 62838100Sbostic } 62946655Sbostic (void)snprintf(namebuf, need, "%s%s%s", targ, 6306440Swnj *targ ? "/" : "", cp); 63138100Sbostic np = namebuf; 63254570Sandrew } else 63338100Sbostic np = targ; 63438100Sbostic exists = stat(np, &stb) == 0; 63538100Sbostic if (buf[0] == 'D') { 63654570Sandrew int mod_flag = pflag; 63718126Sralph if (exists) { 63854151Sbostic if (!S_ISDIR(stb.st_mode)) { 6396440Swnj errno = ENOTDIR; 6406440Swnj goto bad; 6416440Swnj } 64223112Slepreau if (pflag) 64338100Sbostic (void)chmod(np, mode); 64454570Sandrew } else { 64554570Sandrew /* Handle copying from a read-only directory */ 64654570Sandrew mod_flag = 1; 64754570Sandrew if (mkdir(np, mode | S_IRWXU) < 0) 64854570Sandrew goto bad; 64954570Sandrew } 65038100Sbostic vect[0] = np; 65138100Sbostic sink(1, vect); 65223101Slepreau if (setimes) { 65323101Slepreau setimes = 0; 65438100Sbostic if (utimes(np, tv) < 0) 65554151Sbostic err("can't set times on %s: %s", 65638469Sbostic np, strerror(errno)); 65723101Slepreau } 65854570Sandrew if (mod_flag) 65954570Sandrew (void)chmod(np, mode); 6606440Swnj continue; 66118126Sralph } 66254570Sandrew omode = mode; 66354570Sandrew mode |= S_IWRITE; 66438100Sbostic if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { 66554151Sbostic bad: err("%s: %s", np, strerror(errno)); 6666440Swnj continue; 6676440Swnj } 66838098Sbostic (void)write(rem, "", 1); 66954151Sbostic if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == NULL) { 67038100Sbostic (void)close(ofd); 67121254Smckusick continue; 67221254Smckusick } 67321254Smckusick cp = bp->buf; 67438469Sbostic wrerr = NO; 67554570Sandrew for (count = i = 0; i < size; i += BUFSIZ) { 67621254Smckusick amt = BUFSIZ; 6776440Swnj if (i + amt > size) 6786440Swnj amt = size - i; 67921254Smckusick count += amt; 6806440Swnj do { 68121254Smckusick j = read(rem, cp, amt); 68224711Sbloom if (j <= 0) { 68354151Sbostic err("%s", j ? strerror(errno) : 68438100Sbostic "dropped connection"); 6856440Swnj exit(1); 68624711Sbloom } 6876440Swnj amt -= j; 6886440Swnj cp += j; 6896440Swnj } while (amt > 0); 69021254Smckusick if (count == bp->cnt) { 69154570Sandrew /* Keep reading so we stay sync'd up. */ 69254570Sandrew if (wrerr == NO) { 69354570Sandrew j = write(ofd, bp->buf, count); 69454570Sandrew if (j != count) { 69554570Sandrew wrerr = YES; 69654570Sandrew wrerrno = j >= 0 ? EIO : errno; 69754570Sandrew } 69854570Sandrew } 69921254Smckusick count = 0; 70021254Smckusick cp = bp->buf; 70121254Smckusick } 7026440Swnj } 70338469Sbostic if (count != 0 && wrerr == NO && 704*56587Sbostic (j = write(ofd, bp->buf, count)) != count) { 70538469Sbostic wrerr = YES; 706*56587Sbostic wrerrno = j >= 0 ? EIO : errno; 707*56587Sbostic } 70838469Sbostic if (ftruncate(ofd, size)) { 70954570Sandrew err("can't truncate %s: %s", np, strerror(errno)); 71038469Sbostic wrerr = DISPLAYED; 71138469Sbostic } 71254570Sandrew if (pflag) { 71354570Sandrew if (exists || omode != mode) 71454570Sandrew (void)fchmod(ofd, omode); 71554570Sandrew } else { 71654570Sandrew if (!exists && omode != mode) 71754570Sandrew (void)fchmod(ofd, omode & ~mask); 71854570Sandrew } 71938100Sbostic (void)close(ofd); 72038098Sbostic (void)response(); 72138469Sbostic if (setimes && wrerr == NO) { 72223101Slepreau setimes = 0; 72338469Sbostic if (utimes(np, tv) < 0) { 72454151Sbostic err("can't set times on %s: %s", 72538469Sbostic np, strerror(errno)); 72638469Sbostic wrerr = DISPLAYED; 72738469Sbostic } 72838469Sbostic } 72938469Sbostic switch(wrerr) { 73038469Sbostic case YES: 73154570Sandrew err("%s: %s", np, strerror(wrerrno)); 73238469Sbostic break; 73338469Sbostic case NO: 73438098Sbostic (void)write(rem, "", 1); 73538469Sbostic break; 73638469Sbostic case DISPLAYED: 73738469Sbostic break; 73838469Sbostic } 7396440Swnj } 7406440Swnj screwup: 74154570Sandrew err("protocol error: %s", why); 7426440Swnj exit(1); 7436440Swnj } 7446440Swnj 74554151Sbostic #ifdef KERBEROS 74654151Sbostic int 74754151Sbostic kerberos(host, bp, locuser, user) 74854151Sbostic char **host, *bp, *locuser, *user; 74921254Smckusick { 75054151Sbostic struct servent *sp; 75121254Smckusick 75254151Sbostic again: 75354151Sbostic if (use_kerberos) { 75454151Sbostic rem = KSUCCESS; 75554151Sbostic errno = 0; 75654151Sbostic if (dest_realm == NULL) 75754151Sbostic dest_realm = krb_realmofhost(*host); 75854151Sbostic rem = 75954151Sbostic #ifdef CRYPT 76054151Sbostic doencrypt ? 76154151Sbostic krcmd_mutual(host, 76254151Sbostic port, user, bp, 0, dest_realm, &cred, schedule) : 76354151Sbostic #endif 76454151Sbostic krcmd(host, port, user, bp, 0, dest_realm); 76554151Sbostic 76654151Sbostic if (rem < 0) { 76754151Sbostic use_kerberos = 0; 76854151Sbostic if ((sp = getservbyname("shell", "tcp")) == NULL) { 76954151Sbostic (void)fprintf(stderr, 77054151Sbostic "rcp: unknown service shell/tcp\n"); 77154151Sbostic exit(1); 77254151Sbostic } 77354151Sbostic if (errno == ECONNREFUSED) 77454151Sbostic oldw("remote host doesn't support Kerberos"); 77554151Sbostic else if (errno == ENOENT) 77654151Sbostic oldw("can't provide Kerberos authentication data"); 77754151Sbostic port = sp->s_port; 77854151Sbostic goto again; 77921254Smckusick } 78054151Sbostic } else { 78154151Sbostic #ifdef CRYPT 78254151Sbostic if (doencrypt) { 78354151Sbostic (void)fprintf(stderr, 78454151Sbostic "the -x option requires Kerberos authentication\n"); 78554151Sbostic exit(1); 78654151Sbostic } 78754151Sbostic #endif 788*56587Sbostic rem = rcmd(host, port, locuser, user, bp, 0); 78921254Smckusick } 79054151Sbostic return (rem); 79121254Smckusick } 79254151Sbostic #endif /* KERBEROS */ 79321254Smckusick 79454151Sbostic int 79554151Sbostic response() 7966440Swnj { 79754151Sbostic register char *cp; 79854151Sbostic char ch, resp, rbuf[BUFSIZ]; 7996440Swnj 80054151Sbostic if (read(rem, &resp, sizeof(resp)) != sizeof(resp)) 80154151Sbostic lostconn(0); 80232127Sbostic 80354151Sbostic cp = rbuf; 80454151Sbostic switch(resp) { 80554151Sbostic case 0: /* ok */ 80654151Sbostic return (0); 80754151Sbostic default: 80854151Sbostic *cp++ = resp; 80954151Sbostic /* FALLTHROUGH */ 81054151Sbostic case 1: /* error, followed by error msg */ 81154151Sbostic case 2: /* fatal error, "" */ 81254151Sbostic do { 81354151Sbostic if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) 81454151Sbostic lostconn(0); 81554151Sbostic *cp++ = ch; 81654151Sbostic } while (cp < &rbuf[BUFSIZ] && ch != '\n'); 81754151Sbostic 81854151Sbostic if (!iamremote) 81954151Sbostic (void)write(STDERR_FILENO, rbuf, cp - rbuf); 82054151Sbostic ++errs; 82154151Sbostic if (resp == 1) 82254151Sbostic return (-1); 82354151Sbostic exit(1); 82454151Sbostic } 82554151Sbostic /* NOTREACHED */ 82638100Sbostic } 82738100Sbostic 82854151Sbostic void 82932127Sbostic usage() 83032127Sbostic { 83138098Sbostic #ifdef KERBEROS 83254151Sbostic #ifdef CRYPT 83338098Sbostic (void)fprintf(stderr, "%s\n\t%s\n", 83454151Sbostic "usage: rcp [-Kpx] [-k realm] f1 f2", 83554151Sbostic "or: rcp [-Kprx] [-k realm] f1 ... fn directory"); 83645397Smckusick #else 83754151Sbostic (void)fprintf(stderr, "%s\n\t%s\n", 83854151Sbostic "usage: rcp [-Kp] [-k realm] f1 f2", 83954151Sbostic "or: rcp [-Kpr] [-k realm] f1 ... fn directory"); 84054151Sbostic #endif 84154151Sbostic #else 84238098Sbostic (void)fprintf(stderr, 84354151Sbostic "usage: rcp [-p] f1 f2; or: rcp [-pr] f1 ... fn directory\n"); 84436626Skfall #endif 84532127Sbostic exit(1); 84632127Sbostic } 84738879Skfall 84854151Sbostic #if __STDC__ 84954151Sbostic #include <stdarg.h> 85054151Sbostic #else 85154151Sbostic #include <varargs.h> 85254151Sbostic #endif 85354151Sbostic 85438879Skfall #ifdef KERBEROS 85554151Sbostic void 85654151Sbostic #if __STDC__ 85754151Sbostic oldw(const char *fmt, ...) 85854151Sbostic #else 85954151Sbostic oldw(fmt, va_alist) 86054151Sbostic char *fmt; 86154151Sbostic va_dcl 86254151Sbostic #endif 86338879Skfall { 86454151Sbostic va_list ap; 86554151Sbostic #if __STDC__ 86654151Sbostic va_start(ap, fmt); 86754151Sbostic #else 86854151Sbostic va_start(ap); 86954151Sbostic #endif 87054151Sbostic (void)fprintf(stderr, "rcp: "); 87154151Sbostic (void)vfprintf(stderr, fmt, ap); 87254151Sbostic (void)fprintf(stderr, ", using standard rcp\n"); 87354151Sbostic va_end(ap); 87438879Skfall } 87554151Sbostic #endif 87638879Skfall 87754151Sbostic void 87854151Sbostic #if __STDC__ 87954151Sbostic err(const char *fmt, ...) 88054151Sbostic #else 88154151Sbostic err(fmt, va_alist) 88254151Sbostic char *fmt; 88354151Sbostic va_dcl 88454151Sbostic #endif 88538879Skfall { 88654151Sbostic static FILE *fp; 88754151Sbostic va_list ap; 88854151Sbostic #if __STDC__ 88954151Sbostic va_start(ap, fmt); 89054151Sbostic #else 89154151Sbostic va_start(ap); 89254151Sbostic #endif 89338879Skfall 89454151Sbostic ++errs; 89554151Sbostic if (!fp && !(fp = fdopen(rem, "w"))) 89654151Sbostic return; 89754151Sbostic (void)fprintf(fp, "%c", 0x01); 89854151Sbostic (void)fprintf(fp, "rcp: "); 89954151Sbostic (void)vfprintf(fp, fmt, ap); 90054151Sbostic (void)fprintf(fp, "\n"); 90154151Sbostic if (!iamremote) { 90254151Sbostic (void)fprintf(stderr, "rcp: "); 90354151Sbostic (void)vfprintf(stderr, fmt, ap); 90454151Sbostic (void)fprintf(stderr, "\n"); 90538879Skfall } 90654151Sbostic va_end(ap); 90754151Sbostic (void)fflush(fp); 90838879Skfall } 909