121569Sdist /* 244342Skarels * Copyright (c) 1983, 1990 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[] = 1044342Skarels "@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\ 1121569Sdist All rights reserved.\n"; 1235619Sbostic #endif /* not lint */ 136440Swnj 1421569Sdist #ifndef lint 15*54151Sbostic static char sccsid[] = "@(#)rcp.c 5.33 (Berkeley) 06/20/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> 25*54151Sbostic 26*54151Sbostic #include <signal.h> 27*54151Sbostic #include <netdb.h> 2846655Sbostic #include <dirent.h> 2946655Sbostic #include <fcntl.h> 306440Swnj #include <pwd.h> 316440Swnj #include <errno.h> 3246655Sbostic #include <unistd.h> 3338098Sbostic #include <stdio.h> 3445647Storek #include <stdlib.h> 3546655Sbostic #include <string.h> 3638098Sbostic #include <ctype.h> 3737037Sbostic #include "pathnames.h" 38*54151Sbostic #include "extern.h" 3912989Ssam 4038098Sbostic #ifdef KERBEROS 4142498Sbostic #include <kerberosIV/des.h> 4241785Sbostic #include <kerberosIV/krb.h> 43*54151Sbostic 4438879Skfall char dst_realm_buf[REALM_SZ]; 4538879Skfall char *dest_realm = NULL; 4645397Smckusick int use_kerberos = 1; 4738879Skfall CREDENTIALS cred; 4838879Skfall Key_schedule schedule; 4938879Skfall extern char *krb_realmofhost(); 50*54151Sbostic #ifdef CRYPT 51*54151Sbostic int doencrypt = 0; 52*54151Sbostic #define OPTIONS "dfKk:prtx" 5345397Smckusick #else 54*54151Sbostic #define OPTIONS "dfKk:prt" 55*54151Sbostic #endif 56*54151Sbostic #else 5738879Skfall #define OPTIONS "dfprt" 5836624Skfall #endif 5936624Skfall 6038098Sbostic struct passwd *pwd; 6138879Skfall u_short port; 6238879Skfall uid_t userid; 6338879Skfall int errs, rem; 6438879Skfall int pflag, iamremote, iamrecursive, targetshouldbedirectory; 656440Swnj 6638879Skfall #define CMDNEEDS 64 6738100Sbostic char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ 6838098Sbostic 69*54151Sbostic #ifdef KERBEROS 70*54151Sbostic int kerberos __P((char **, char *, char *, char *)); 71*54151Sbostic void oldw __P((const char *, ...)); 72*54151Sbostic #endif 73*54151Sbostic int response __P((void)); 74*54151Sbostic void rsource __P((char *, struct stat *)); 75*54151Sbostic void sink __P((int, char *[])); 76*54151Sbostic void source __P((int, char *[])); 77*54151Sbostic void tolocal __P((int, char *[])); 78*54151Sbostic void toremote __P((char *, int, char *[])); 79*54151Sbostic void usage __P((void)); 8021254Smckusick 81*54151Sbostic int 826440Swnj main(argc, argv) 836440Swnj int argc; 84*54151Sbostic char *argv[]; 856440Swnj { 8618126Sralph struct servent *sp; 8738099Sbostic int ch, fflag, tflag; 88*54151Sbostic char *targ, *shell; 8918026Sralph 9038099Sbostic fflag = tflag = 0; 9138879Skfall while ((ch = getopt(argc, argv, OPTIONS)) != EOF) 92*54151Sbostic switch(ch) { /* User-visible flags. */ 93*54151Sbostic case 'K': 94*54151Sbostic #ifdef KERBEROS 95*54151Sbostic use_kerberos = 0; 96*54151Sbostic #endif 9723101Slepreau break; 9838879Skfall #ifdef KERBEROS 9938879Skfall case 'k': 10038879Skfall dest_realm = dst_realm_buf; 101*54151Sbostic (void)strncpy(dst_realm_buf, optarg, REALM_SZ); 10238099Sbostic break; 103*54151Sbostic #ifdef CRYPT 104*54151Sbostic case 'x': 105*54151Sbostic doencrypt = 1; 106*54151Sbostic /* des_set_key(cred.session, schedule); */ 107*54151Sbostic break; 10838098Sbostic #endif 109*54151Sbostic #endif 110*54151Sbostic case 'p': 111*54151Sbostic pflag = 1; 112*54151Sbostic break; 113*54151Sbostic case 'r': 114*54151Sbostic iamrecursive = 1; 115*54151Sbostic break; 116*54151Sbostic /* Server options. */ 11738879Skfall case 'd': 11838879Skfall targetshouldbedirectory = 1; 11938879Skfall break; 12038879Skfall case 'f': /* "from" */ 12138879Skfall iamremote = 1; 12238879Skfall fflag = 1; 12338879Skfall break; 12438879Skfall case 't': /* "to" */ 12538879Skfall iamremote = 1; 12638879Skfall tflag = 1; 12738879Skfall break; 12838879Skfall 12938098Sbostic case '?': 13038098Sbostic default: 13132127Sbostic usage(); 13223101Slepreau } 13338098Sbostic argc -= optind; 13438098Sbostic argv += optind; 13538098Sbostic 13638879Skfall #ifdef KERBEROS 137*54151Sbostic if (use_kerberos) { 138*54151Sbostic #ifdef CRYPT 139*54151Sbostic shell = doencrypt ? "ekshell" : "kshell"; 140*54151Sbostic #else 141*54151Sbostic shell = "kshell"; 142*54151Sbostic #endif 143*54151Sbostic if ((sp = getservbyname(shell, "tcp")) == NULL) { 144*54151Sbostic use_kerberos = 0; 145*54151Sbostic oldw("can't get entry for %s/tcp service", shell); 146*54151Sbostic sp = getservbyname(shell = "shell", "tcp"); 147*54151Sbostic } 148*54151Sbostic } else 14945647Storek sp = getservbyname(shell = "shell", "tcp"); 15038879Skfall #else 15145647Storek sp = getservbyname(shell = "shell", "tcp"); 15238879Skfall #endif 15338879Skfall if (sp == NULL) { 15445647Storek (void)fprintf(stderr, "rcp: %s/tcp: unknown service\n", shell); 15538879Skfall exit(1); 15638879Skfall } 15738879Skfall port = sp->s_port; 15838879Skfall 159*54151Sbostic if ((pwd = getpwuid(userid = getuid())) == NULL) { 16045647Storek (void)fprintf(stderr, "rcp: unknown user %d.\n", (int)userid); 16138879Skfall exit(1); 16238879Skfall } 16338879Skfall 164*54151Sbostic rem = STDIN_FILENO; /* XXX */ 165*54151Sbostic 166*54151Sbostic if (fflag) { /* Follow "protocol", send data. */ 16738099Sbostic (void)response(); 16838099Sbostic (void)setuid(userid); 16938099Sbostic source(argc, argv); 17038099Sbostic exit(errs); 17138099Sbostic } 17238099Sbostic 173*54151Sbostic if (tflag) { /* Receive data. */ 17438099Sbostic (void)setuid(userid); 17538099Sbostic sink(argc, argv); 17638099Sbostic exit(errs); 17738099Sbostic } 17838099Sbostic 17932127Sbostic if (argc < 2) 18032127Sbostic usage(); 1816440Swnj if (argc > 2) 1826440Swnj targetshouldbedirectory = 1; 18338098Sbostic 18432127Sbostic rem = -1; 185*54151Sbostic /* Command to be executed on remote system using "rsh". */ 18638879Skfall #ifdef KERBEROS 18746655Sbostic (void)snprintf(cmd, sizeof(cmd), 18846655Sbostic "rcp%s%s%s%s", iamrecursive ? " -r" : "", 189*54151Sbostic #ifdef CRYPT 190*54151Sbostic (doencrypt && use_kerberos ? " -x" : ""), 191*54151Sbostic #else 19245397Smckusick "", 193*54151Sbostic #endif 19438879Skfall pflag ? " -p" : "", targetshouldbedirectory ? " -d" : ""); 19538879Skfall #else 19646655Sbostic (void)snprintf(cmd, sizeof(cmd), "rcp%s%s%s", 19746655Sbostic iamrecursive ? " -r" : "", pflag ? " -p" : "", 19846655Sbostic targetshouldbedirectory ? " -d" : ""); 19938879Skfall #endif 20038098Sbostic 20138098Sbostic (void)signal(SIGPIPE, lostconn); 20238098Sbostic 203*54151Sbostic if (targ = colon(argv[argc - 1])) /* Dest is remote host. */ 204*54151Sbostic toremote(targ, argc, argv); 20538098Sbostic else { 206*54151Sbostic tolocal(argc, argv); /* Dest is local host. */ 20738098Sbostic if (targetshouldbedirectory) 20838098Sbostic verifydir(argv[argc - 1]); 20938098Sbostic } 21038098Sbostic exit(errs); 21138098Sbostic } 21238098Sbostic 213*54151Sbostic void 21438098Sbostic toremote(targ, argc, argv) 215*54151Sbostic char *targ, *argv[]; 21638098Sbostic int argc; 21738098Sbostic { 21846655Sbostic int i, len, tos; 21938100Sbostic char *bp, *host, *src, *suser, *thost, *tuser; 22038098Sbostic 22138098Sbostic *targ++ = 0; 22238098Sbostic if (*targ == 0) 22338098Sbostic targ = "."; 22438098Sbostic 22538100Sbostic if (thost = index(argv[argc - 1], '@')) { 22638879Skfall /* user@host */ 22738098Sbostic *thost++ = 0; 22838098Sbostic tuser = argv[argc - 1]; 22938098Sbostic if (*tuser == '\0') 23024711Sbloom tuser = NULL; 23138098Sbostic else if (!okname(tuser)) 23238098Sbostic exit(1); 23338098Sbostic } else { 23438098Sbostic thost = argv[argc - 1]; 23538098Sbostic tuser = NULL; 23638098Sbostic } 23736624Skfall 23838098Sbostic for (i = 0; i < argc - 1; i++) { 23938098Sbostic src = colon(argv[i]); 24038098Sbostic if (src) { /* remote to remote */ 24138098Sbostic *src++ = 0; 24238098Sbostic if (*src == 0) 24338098Sbostic src = "."; 24438098Sbostic host = index(argv[i], '@'); 24546655Sbostic len = strlen(_PATH_RSH) + strlen(argv[i]) + 24646655Sbostic strlen(src) + (tuser ? strlen(tuser) : 0) + 24746655Sbostic strlen(thost) + strlen(targ) + CMDNEEDS + 20; 24846655Sbostic if (!(bp = malloc(len))) 24946655Sbostic nospace(); 25038098Sbostic if (host) { 25138098Sbostic *host++ = 0; 25238098Sbostic suser = argv[i]; 25338098Sbostic if (*suser == '\0') 25438098Sbostic suser = pwd->pw_name; 25538098Sbostic else if (!okname(suser)) 25638098Sbostic continue; 25746655Sbostic (void)snprintf(bp, len, 25838098Sbostic "%s %s -l %s -n %s %s '%s%s%s:%s'", 25938098Sbostic _PATH_RSH, host, suser, cmd, src, 26038098Sbostic tuser ? tuser : "", tuser ? "@" : "", 26138098Sbostic thost, targ); 26238098Sbostic } else 26346655Sbostic (void)snprintf(bp, len, 26446655Sbostic "%s %s -n %s %s '%s%s%s:%s'", 26538098Sbostic _PATH_RSH, argv[i], cmd, src, 26638098Sbostic tuser ? tuser : "", tuser ? "@" : "", 26738098Sbostic thost, targ); 268*54151Sbostic (void)susystem(bp, userid); 26938100Sbostic (void)free(bp); 27038098Sbostic } else { /* local to remote */ 27138098Sbostic if (rem == -1) { 27246655Sbostic len = strlen(targ) + CMDNEEDS + 20; 27346655Sbostic if (!(bp = malloc(len))) 27438100Sbostic nospace(); 27546655Sbostic (void)snprintf(bp, len, "%s -t %s", cmd, targ); 27638098Sbostic host = thost; 27738098Sbostic #ifdef KERBEROS 27838098Sbostic if (use_kerberos) 27938879Skfall rem = kerberos(&host, bp, 28038879Skfall pwd->pw_name, 28138100Sbostic tuser ? tuser : pwd->pw_name); 28238098Sbostic else 28338098Sbostic #endif 28424711Sbloom rem = rcmd(&host, port, pwd->pw_name, 28524711Sbloom tuser ? tuser : pwd->pw_name, 28638100Sbostic bp, 0); 28738098Sbostic if (rem < 0) 28838098Sbostic exit(1); 28944342Skarels tos = IPTOS_THROUGHPUT; 29044342Skarels if (setsockopt(rem, IPPROTO_IP, IP_TOS, 291*54151Sbostic &tos, sizeof(int)) < 0) 292*54151Sbostic (void)fprintf(stderr, 293*54151Sbostic "rcp: TOS (ignored): %s\n", 294*54151Sbostic strerror(errno)); 29538098Sbostic if (response() < 0) 29638098Sbostic exit(1); 29738100Sbostic (void)free(bp); 29838098Sbostic (void)setuid(userid); 2996440Swnj } 30038098Sbostic source(1, argv+i); 3016440Swnj } 30238098Sbostic } 30338098Sbostic } 30438098Sbostic 305*54151Sbostic void 30638098Sbostic tolocal(argc, argv) 30738098Sbostic int argc; 308*54151Sbostic char *argv[]; 30938098Sbostic { 31046655Sbostic int i, len, tos; 31138100Sbostic char *bp, *host, *src, *suser; 31238098Sbostic 31338098Sbostic for (i = 0; i < argc - 1; i++) { 314*54151Sbostic if (!(src = colon(argv[i]))) { /* Local to local. */ 31546655Sbostic len = strlen(_PATH_CP) + strlen(argv[i]) + 31646655Sbostic strlen(argv[argc - 1]) + 20; 31746655Sbostic if (!(bp = malloc(len))) 31838100Sbostic nospace(); 31946655Sbostic (void)snprintf(bp, len, "%s%s%s %s %s", _PATH_CP, 32038100Sbostic iamrecursive ? " -r" : "", pflag ? " -p" : "", 32138100Sbostic argv[i], argv[argc - 1]); 322*54151Sbostic (void)susystem(bp, userid); 32338100Sbostic (void)free(bp); 32438100Sbostic continue; 32538100Sbostic } 32638100Sbostic *src++ = 0; 32738100Sbostic if (*src == 0) 32838100Sbostic src = "."; 329*54151Sbostic if ((host = index(argv[i], '@')) == NULL) { 330*54151Sbostic host = argv[i]; 331*54151Sbostic suser = pwd->pw_name; 332*54151Sbostic } else { 33338100Sbostic *host++ = 0; 33438100Sbostic suser = argv[i]; 33538100Sbostic if (*suser == '\0') 33638098Sbostic suser = pwd->pw_name; 33738100Sbostic else if (!okname(suser)) 33838100Sbostic continue; 33938100Sbostic } 34046655Sbostic len = strlen(src) + CMDNEEDS + 20; 341*54151Sbostic if ((bp = malloc(len)) == NULL) 34238100Sbostic nospace(); 34346655Sbostic (void)snprintf(bp, len, "%s -f %s", cmd, src); 344*54151Sbostic rem = 34538098Sbostic #ifdef KERBEROS 346*54151Sbostic use_kerberos ? 347*54151Sbostic kerberos(&host, bp, pwd->pw_name, suser) : 34838098Sbostic #endif 349*54151Sbostic rcmd(&host, port, pwd->pw_name, suser, bp, 0); 35038100Sbostic (void)free(bp); 35138100Sbostic if (rem < 0) 35238100Sbostic continue; 35344342Skarels (void)seteuid(userid); 35444342Skarels tos = IPTOS_THROUGHPUT; 355*54151Sbostic if (setsockopt(rem, IPPROTO_IP, IP_TOS, &tos, sizeof(int)) < 0) 356*54151Sbostic (void)fprintf(stderr, "rcp: TOS (ignored): %s\n", 357*54151Sbostic strerror(errno)); 35838100Sbostic sink(1, argv + argc - 1); 35944342Skarels (void)seteuid(0); 36038100Sbostic (void)close(rem); 36138100Sbostic rem = -1; 3626440Swnj } 3636440Swnj } 3646440Swnj 365*54151Sbostic void 3666440Swnj source(argc, argv) 3676440Swnj int argc; 368*54151Sbostic char *argv[]; 3696440Swnj { 3706440Swnj struct stat stb; 37138098Sbostic static BUF buffer; 37238098Sbostic BUF *bp; 37338098Sbostic off_t i; 374*54151Sbostic int fd, readerr, amt; 37538098Sbostic char *last, *name, buf[BUFSIZ]; 3766440Swnj 377*54151Sbostic while (name = *argv++) { 378*54151Sbostic if ((fd = open(name, O_RDONLY, 0)) < 0) 379*54151Sbostic goto syserr; 380*54151Sbostic if (fstat(fd, &stb)) { 381*54151Sbostic syserr: err("%s: %s", name, strerror(errno)); 382*54151Sbostic goto next; 3836440Swnj } 384*54151Sbostic switch (stb.st_mode & S_IFMT) { 3856440Swnj case S_IFREG: 3866440Swnj break; 3876440Swnj case S_IFDIR: 3886440Swnj if (iamrecursive) { 38923101Slepreau rsource(name, &stb); 390*54151Sbostic goto next; 3916440Swnj } 39238098Sbostic /* FALLTHROUGH */ 3936440Swnj default: 394*54151Sbostic err("%s: not a regular file", name); 395*54151Sbostic goto next; 3966440Swnj } 397*54151Sbostic if ((last = rindex(name, '/')) == NULL) 3986440Swnj last = name; 3996440Swnj else 400*54151Sbostic ++last; 40123101Slepreau if (pflag) { 40223101Slepreau /* 40323101Slepreau * Make it compatible with possible future 40423101Slepreau * versions expecting microseconds. 40523101Slepreau */ 406*54151Sbostic amt = snprintf(buf, sizeof(buf), "T%ld 0 %ld 0\n", 407*54151Sbostic stb.st_mtimespec.ts_sec, stb.st_atimespec.ts_sec); 408*54151Sbostic (void)write(rem, buf, amt); 409*54151Sbostic if (response() < 0) 410*54151Sbostic goto next; 41123101Slepreau } 412*54151Sbostic #define MODEMASK (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO) 413*54151Sbostic amt = snprintf(buf, sizeof(buf), "C%04o %qd %s\n", 414*54151Sbostic stb.st_mode & MODEMASK, stb.st_size, last); 415*54151Sbostic (void)write(rem, buf, amt); 416*54151Sbostic if (response() < 0) 417*54151Sbostic goto next; 418*54151Sbostic if ((bp = allocbuf(&buffer, fd, BUFSIZ)) == NULL) 419*54151Sbostic goto next; 42032268Sbostic readerr = 0; 42121254Smckusick for (i = 0; i < stb.st_size; i += bp->cnt) { 42221254Smckusick amt = bp->cnt; 4236440Swnj if (i + amt > stb.st_size) 4246440Swnj amt = stb.st_size - i; 425*54151Sbostic if (read(fd, bp->buf, amt) != amt) { 426*54151Sbostic readerr = 1; 427*54151Sbostic err("%s: %s", name, strerror(errno)); 428*54151Sbostic break; 429*54151Sbostic } 43038098Sbostic (void)write(rem, bp->buf, amt); 4316440Swnj } 432*54151Sbostic if (!readerr) 43338098Sbostic (void)write(rem, "", 1); 43438098Sbostic (void)response(); 435*54151Sbostic 436*54151Sbostic next: (void)close(fd); 4376440Swnj } 4386440Swnj } 4396440Swnj 440*54151Sbostic void 44123101Slepreau rsource(name, statp) 4426440Swnj char *name; 44323101Slepreau struct stat *statp; 4446440Swnj { 44546655Sbostic DIR *dirp; 44646655Sbostic struct dirent *dp; 447*54151Sbostic int amt; 44838100Sbostic char *last, *vect[1], path[MAXPATHLEN]; 4496440Swnj 45046655Sbostic if (!(dirp = opendir(name))) { 451*54151Sbostic err("%s: %s", name, strerror(errno)); 4526440Swnj return; 4536440Swnj } 4546440Swnj last = rindex(name, '/'); 4556440Swnj if (last == 0) 4566440Swnj last = name; 4576440Swnj else 4586440Swnj last++; 45923101Slepreau if (pflag) { 460*54151Sbostic amt = snprintf(path, sizeof(path), "T%ld 0 %ld 0\n", 461*54151Sbostic statp->st_mtimespec.ts_sec, statp->st_atimespec.ts_sec); 462*54151Sbostic (void)write(rem, path, amt); 46323101Slepreau if (response() < 0) { 46446655Sbostic closedir(dirp); 46523101Slepreau return; 46623101Slepreau } 46723101Slepreau } 468*54151Sbostic amt = snprintf(path, sizeof(path), 469*54151Sbostic "D%04o %d %s\n", statp->st_mode & MODEMASK, 0, last); 470*54151Sbostic (void)write(rem, path, amt); 4716440Swnj if (response() < 0) { 47246655Sbostic closedir(dirp); 4736440Swnj return; 4746440Swnj } 47546655Sbostic while (dp = readdir(dirp)) { 4766440Swnj if (dp->d_ino == 0) 4776440Swnj continue; 4786440Swnj if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 4796440Swnj continue; 48038100Sbostic if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) { 481*54151Sbostic err("%s/%s: name too long", name, dp->d_name); 4826440Swnj continue; 4836440Swnj } 48446655Sbostic (void)snprintf(path, sizeof(path), "%s/%s", name, dp->d_name); 48538100Sbostic vect[0] = path; 48638100Sbostic source(1, vect); 4876440Swnj } 488*54151Sbostic (void)closedir(dirp); 48938098Sbostic (void)write(rem, "E\n", 2); 49038098Sbostic (void)response(); 4916440Swnj } 4926440Swnj 49346655Sbostic void 4946440Swnj sink(argc, argv) 4956440Swnj int argc; 496*54151Sbostic char *argv[]; 4976440Swnj { 498*54151Sbostic static BUF buffer; 49938100Sbostic register char *cp; 50021254Smckusick struct stat stb; 50123101Slepreau struct timeval tv[2]; 50238469Sbostic enum { YES, NO, DISPLAYED } wrerr; 503*54151Sbostic BUF *bp; 50438100Sbostic off_t i, j; 50538100Sbostic char ch, *targ, *why; 50638100Sbostic int amt, count, exists, first, mask, mode; 50738469Sbostic int ofd, setimes, size, targisdir; 50845647Storek char *np, *vect[1], buf[BUFSIZ]; 5096440Swnj 51038100Sbostic #define atime tv[0] 51138100Sbostic #define mtime tv[1] 51238100Sbostic #define SCREWUP(str) { why = str; goto screwup; } 51338100Sbostic 51438100Sbostic setimes = targisdir = 0; 51538100Sbostic mask = umask(0); 51623112Slepreau if (!pflag) 51738098Sbostic (void)umask(mask); 51818126Sralph if (argc != 1) { 519*54151Sbostic err("ambiguous target"); 5206440Swnj exit(1); 5216440Swnj } 5226440Swnj targ = *argv; 5236440Swnj if (targetshouldbedirectory) 5246440Swnj verifydir(targ); 52538098Sbostic (void)write(rem, "", 1); 526*54151Sbostic if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) 5276440Swnj targisdir = 1; 52838100Sbostic for (first = 1;; first = 0) { 52938100Sbostic cp = buf; 5306440Swnj if (read(rem, cp, 1) <= 0) 5316440Swnj return; 5326440Swnj if (*cp++ == '\n') 53338100Sbostic SCREWUP("unexpected <newline>"); 5346440Swnj do { 53538100Sbostic if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) 5366440Swnj SCREWUP("lost connection"); 53738100Sbostic *cp++ = ch; 53838100Sbostic } while (cp < &buf[BUFSIZ - 1] && ch != '\n'); 5396440Swnj *cp = 0; 54038100Sbostic 54138100Sbostic if (buf[0] == '\01' || buf[0] == '\02') { 5426440Swnj if (iamremote == 0) 543*54151Sbostic (void)write(STDERR_FILENO, 544*54151Sbostic buf + 1, strlen(buf + 1)); 54538100Sbostic if (buf[0] == '\02') 5466440Swnj exit(1); 547*54151Sbostic ++errs; 5486440Swnj continue; 5496440Swnj } 55038100Sbostic if (buf[0] == 'E') { 55138098Sbostic (void)write(rem, "", 1); 5526440Swnj return; 5536440Swnj } 55423101Slepreau 55538108Sbostic if (ch == '\n') 55638115Sbostic *--cp = 0; 55738108Sbostic 55823101Slepreau #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0'); 55938100Sbostic cp = buf; 56023101Slepreau if (*cp == 'T') { 56123101Slepreau setimes++; 56223101Slepreau cp++; 56323101Slepreau getnum(mtime.tv_sec); 56423101Slepreau if (*cp++ != ' ') 56523101Slepreau SCREWUP("mtime.sec not delimited"); 56623101Slepreau getnum(mtime.tv_usec); 56723101Slepreau if (*cp++ != ' ') 56823101Slepreau SCREWUP("mtime.usec not delimited"); 56923101Slepreau getnum(atime.tv_sec); 57023101Slepreau if (*cp++ != ' ') 57123101Slepreau SCREWUP("atime.sec not delimited"); 57223101Slepreau getnum(atime.tv_usec); 57323101Slepreau if (*cp++ != '\0') 57423101Slepreau SCREWUP("atime.usec not delimited"); 57538098Sbostic (void)write(rem, "", 1); 57623101Slepreau continue; 57723101Slepreau } 57814580Sralph if (*cp != 'C' && *cp != 'D') { 57914580Sralph /* 58014580Sralph * Check for the case "rcp remote:foo\* local:bar". 58114580Sralph * In this case, the line "No match." can be returned 58214580Sralph * by the shell before the rcp command on the remote is 58314580Sralph * executed so the ^Aerror_message convention isn't 58414580Sralph * followed. 58514580Sralph */ 58614580Sralph if (first) { 587*54151Sbostic err("%s", cp); 58814580Sralph exit(1); 58914580Sralph } 5906440Swnj SCREWUP("expected control record"); 59114580Sralph } 5926440Swnj mode = 0; 59338100Sbostic for (++cp; cp < buf + 5; cp++) { 5946440Swnj if (*cp < '0' || *cp > '7') 5956440Swnj SCREWUP("bad mode"); 5966440Swnj mode = (mode << 3) | (*cp - '0'); 5976440Swnj } 5986440Swnj if (*cp++ != ' ') 5996440Swnj SCREWUP("mode not delimited"); 600*54151Sbostic 601*54151Sbostic for (size = 0; isdigit(*cp);) 6026440Swnj size = size * 10 + (*cp++ - '0'); 6036440Swnj if (*cp++ != ' ') 6046440Swnj SCREWUP("size not delimited"); 60538100Sbostic if (targisdir) { 60638100Sbostic static char *namebuf; 60738100Sbostic static int cursize; 60845647Storek size_t need; 60938100Sbostic 61038100Sbostic need = strlen(targ) + strlen(cp) + 250; 61138100Sbostic if (need > cursize) { 61245647Storek if (!(namebuf = malloc(need))) 613*54151Sbostic err("%s", strerror(errno)); 61438100Sbostic } 61546655Sbostic (void)snprintf(namebuf, need, "%s%s%s", targ, 6166440Swnj *targ ? "/" : "", cp); 61738100Sbostic np = namebuf; 61838100Sbostic } 6196440Swnj else 62038100Sbostic np = targ; 62138100Sbostic exists = stat(np, &stb) == 0; 62238100Sbostic if (buf[0] == 'D') { 62318126Sralph if (exists) { 624*54151Sbostic if (!S_ISDIR(stb.st_mode)) { 6256440Swnj errno = ENOTDIR; 6266440Swnj goto bad; 6276440Swnj } 62823112Slepreau if (pflag) 62938100Sbostic (void)chmod(np, mode); 63038100Sbostic } else if (mkdir(np, mode) < 0) 6316440Swnj goto bad; 63238100Sbostic vect[0] = np; 63338100Sbostic sink(1, vect); 63423101Slepreau if (setimes) { 63523101Slepreau setimes = 0; 63638100Sbostic if (utimes(np, tv) < 0) 637*54151Sbostic err("can't set times on %s: %s", 63838469Sbostic np, strerror(errno)); 63923101Slepreau } 6406440Swnj continue; 64118126Sralph } 64238100Sbostic if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { 643*54151Sbostic bad: err("%s: %s", np, strerror(errno)); 6446440Swnj continue; 6456440Swnj } 64623112Slepreau if (exists && pflag) 64738100Sbostic (void)fchmod(ofd, mode); 64838098Sbostic (void)write(rem, "", 1); 649*54151Sbostic if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == NULL) { 65038100Sbostic (void)close(ofd); 65121254Smckusick continue; 65221254Smckusick } 65321254Smckusick cp = bp->buf; 65421254Smckusick count = 0; 65538469Sbostic wrerr = NO; 6566440Swnj for (i = 0; i < size; i += BUFSIZ) { 65721254Smckusick amt = BUFSIZ; 6586440Swnj if (i + amt > size) 6596440Swnj amt = size - i; 66021254Smckusick count += amt; 6616440Swnj do { 66221254Smckusick j = read(rem, cp, amt); 66324711Sbloom if (j <= 0) { 664*54151Sbostic err("%s", j ? strerror(errno) : 66538100Sbostic "dropped connection"); 6666440Swnj exit(1); 66724711Sbloom } 6686440Swnj amt -= j; 6696440Swnj cp += j; 6706440Swnj } while (amt > 0); 67121254Smckusick if (count == bp->cnt) { 67238469Sbostic if (wrerr == NO && 67338100Sbostic write(ofd, bp->buf, count) != count) 67438469Sbostic wrerr = YES; 67521254Smckusick count = 0; 67621254Smckusick cp = bp->buf; 67721254Smckusick } 6786440Swnj } 67938469Sbostic if (count != 0 && wrerr == NO && 68038100Sbostic write(ofd, bp->buf, count) != count) 68138469Sbostic wrerr = YES; 68238469Sbostic if (ftruncate(ofd, size)) { 683*54151Sbostic err("can't truncate %s: %s", np, 68438469Sbostic strerror(errno)); 68538469Sbostic wrerr = DISPLAYED; 68638469Sbostic } 68738100Sbostic (void)close(ofd); 68838098Sbostic (void)response(); 68938469Sbostic if (setimes && wrerr == NO) { 69023101Slepreau setimes = 0; 69138469Sbostic if (utimes(np, tv) < 0) { 692*54151Sbostic err("can't set times on %s: %s", 69338469Sbostic np, strerror(errno)); 69438469Sbostic wrerr = DISPLAYED; 69538469Sbostic } 69638469Sbostic } 69738469Sbostic switch(wrerr) { 69838469Sbostic case YES: 699*54151Sbostic err("%s: %s", np, strerror(errno)); 70038469Sbostic break; 70138469Sbostic case NO: 70238098Sbostic (void)write(rem, "", 1); 70338469Sbostic break; 70438469Sbostic case DISPLAYED: 70538469Sbostic break; 70638469Sbostic } 7076440Swnj } 7086440Swnj screwup: 709*54151Sbostic err("protocol screwup: %s", why); 7106440Swnj exit(1); 7116440Swnj } 7126440Swnj 713*54151Sbostic #ifdef KERBEROS 714*54151Sbostic int 715*54151Sbostic kerberos(host, bp, locuser, user) 716*54151Sbostic char **host, *bp, *locuser, *user; 71721254Smckusick { 718*54151Sbostic struct servent *sp; 71921254Smckusick 720*54151Sbostic again: 721*54151Sbostic if (use_kerberos) { 722*54151Sbostic rem = KSUCCESS; 723*54151Sbostic errno = 0; 724*54151Sbostic if (dest_realm == NULL) 725*54151Sbostic dest_realm = krb_realmofhost(*host); 726*54151Sbostic rem = 727*54151Sbostic #ifdef CRYPT 728*54151Sbostic doencrypt ? 729*54151Sbostic krcmd_mutual(host, 730*54151Sbostic port, user, bp, 0, dest_realm, &cred, schedule) : 731*54151Sbostic #endif 732*54151Sbostic krcmd(host, port, user, bp, 0, dest_realm); 733*54151Sbostic 734*54151Sbostic if (rem < 0) { 735*54151Sbostic use_kerberos = 0; 736*54151Sbostic if ((sp = getservbyname("shell", "tcp")) == NULL) { 737*54151Sbostic (void)fprintf(stderr, 738*54151Sbostic "rcp: unknown service shell/tcp\n"); 739*54151Sbostic exit(1); 740*54151Sbostic } 741*54151Sbostic if (errno == ECONNREFUSED) 742*54151Sbostic oldw("remote host doesn't support Kerberos"); 743*54151Sbostic else if (errno == ENOENT) 744*54151Sbostic oldw("can't provide Kerberos authentication data"); 745*54151Sbostic port = sp->s_port; 746*54151Sbostic goto again; 74721254Smckusick } 748*54151Sbostic } else { 749*54151Sbostic #ifdef CRYPT 750*54151Sbostic if (doencrypt) { 751*54151Sbostic (void)fprintf(stderr, 752*54151Sbostic "the -x option requires Kerberos authentication\n"); 753*54151Sbostic exit(1); 754*54151Sbostic } 755*54151Sbostic #endif 756*54151Sbostic rem = rcmd(host, sp->s_port, locuser, user, bp, 0); 75721254Smckusick } 758*54151Sbostic return (rem); 75921254Smckusick } 760*54151Sbostic #endif /* KERBEROS */ 76121254Smckusick 762*54151Sbostic int 763*54151Sbostic response() 7646440Swnj { 765*54151Sbostic register char *cp; 766*54151Sbostic char ch, resp, rbuf[BUFSIZ]; 7676440Swnj 768*54151Sbostic if (read(rem, &resp, sizeof(resp)) != sizeof(resp)) 769*54151Sbostic lostconn(0); 77032127Sbostic 771*54151Sbostic cp = rbuf; 772*54151Sbostic switch(resp) { 773*54151Sbostic case 0: /* ok */ 774*54151Sbostic return (0); 775*54151Sbostic default: 776*54151Sbostic *cp++ = resp; 777*54151Sbostic /* FALLTHROUGH */ 778*54151Sbostic case 1: /* error, followed by error msg */ 779*54151Sbostic case 2: /* fatal error, "" */ 780*54151Sbostic do { 781*54151Sbostic if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) 782*54151Sbostic lostconn(0); 783*54151Sbostic *cp++ = ch; 784*54151Sbostic } while (cp < &rbuf[BUFSIZ] && ch != '\n'); 785*54151Sbostic 786*54151Sbostic if (!iamremote) 787*54151Sbostic (void)write(STDERR_FILENO, rbuf, cp - rbuf); 788*54151Sbostic ++errs; 789*54151Sbostic if (resp == 1) 790*54151Sbostic return (-1); 791*54151Sbostic exit(1); 792*54151Sbostic } 793*54151Sbostic /* NOTREACHED */ 79438100Sbostic } 79538100Sbostic 796*54151Sbostic void 79732127Sbostic usage() 79832127Sbostic { 79938098Sbostic #ifdef KERBEROS 800*54151Sbostic #ifdef CRYPT 80138098Sbostic (void)fprintf(stderr, "%s\n\t%s\n", 802*54151Sbostic "usage: rcp [-Kpx] [-k realm] f1 f2", 803*54151Sbostic "or: rcp [-Kprx] [-k realm] f1 ... fn directory"); 80445397Smckusick #else 805*54151Sbostic (void)fprintf(stderr, "%s\n\t%s\n", 806*54151Sbostic "usage: rcp [-Kp] [-k realm] f1 f2", 807*54151Sbostic "or: rcp [-Kpr] [-k realm] f1 ... fn directory"); 808*54151Sbostic #endif 809*54151Sbostic #else 81038098Sbostic (void)fprintf(stderr, 811*54151Sbostic "usage: rcp [-p] f1 f2; or: rcp [-pr] f1 ... fn directory\n"); 81236626Skfall #endif 81332127Sbostic exit(1); 81432127Sbostic } 81538879Skfall 816*54151Sbostic #if __STDC__ 817*54151Sbostic #include <stdarg.h> 818*54151Sbostic #else 819*54151Sbostic #include <varargs.h> 820*54151Sbostic #endif 821*54151Sbostic 82238879Skfall #ifdef KERBEROS 823*54151Sbostic void 824*54151Sbostic #if __STDC__ 825*54151Sbostic oldw(const char *fmt, ...) 826*54151Sbostic #else 827*54151Sbostic oldw(fmt, va_alist) 828*54151Sbostic char *fmt; 829*54151Sbostic va_dcl 830*54151Sbostic #endif 83138879Skfall { 832*54151Sbostic va_list ap; 833*54151Sbostic #if __STDC__ 834*54151Sbostic va_start(ap, fmt); 835*54151Sbostic #else 836*54151Sbostic va_start(ap); 837*54151Sbostic #endif 838*54151Sbostic (void)fprintf(stderr, "rcp: "); 839*54151Sbostic (void)vfprintf(stderr, fmt, ap); 840*54151Sbostic (void)fprintf(stderr, ", using standard rcp\n"); 841*54151Sbostic va_end(ap); 84238879Skfall } 843*54151Sbostic #endif 84438879Skfall 845*54151Sbostic void 846*54151Sbostic #if __STDC__ 847*54151Sbostic err(const char *fmt, ...) 848*54151Sbostic #else 849*54151Sbostic err(fmt, va_alist) 850*54151Sbostic char *fmt; 851*54151Sbostic va_dcl 852*54151Sbostic #endif 85338879Skfall { 854*54151Sbostic static FILE *fp; 855*54151Sbostic va_list ap; 856*54151Sbostic #if __STDC__ 857*54151Sbostic va_start(ap, fmt); 858*54151Sbostic #else 859*54151Sbostic va_start(ap); 860*54151Sbostic #endif 86138879Skfall 862*54151Sbostic ++errs; 863*54151Sbostic if (!fp && !(fp = fdopen(rem, "w"))) 864*54151Sbostic return; 865*54151Sbostic (void)fprintf(fp, "%c", 0x01); 866*54151Sbostic (void)fprintf(fp, "rcp: "); 867*54151Sbostic (void)vfprintf(fp, fmt, ap); 868*54151Sbostic (void)fprintf(fp, "\n"); 869*54151Sbostic if (!iamremote) { 870*54151Sbostic (void)fprintf(stderr, "rcp: "); 871*54151Sbostic (void)vfprintf(stderr, fmt, ap); 872*54151Sbostic (void)fprintf(stderr, "\n"); 87338879Skfall } 874*54151Sbostic va_end(ap); 875*54151Sbostic (void)fflush(fp); 87638879Skfall } 877