121569Sdist /* 235619Sbostic * Copyright (c) 1983 The Regents of the University of California. 335619Sbostic * All rights reserved. 435619Sbostic * 535619Sbostic * Redistribution and use in source and binary forms are permitted 635619Sbostic * provided that the above copyright notice and this paragraph are 735619Sbostic * duplicated in all such forms and that any documentation, 835619Sbostic * advertising materials, and other materials related to such 935619Sbostic * distribution and use acknowledge that the software was developed 1035619Sbostic * by the University of California, Berkeley. The name of the 1135619Sbostic * University may not be used to endorse or promote products derived 1235619Sbostic * from this software without specific prior written permission. 1335619Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1435619Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537038Sbostic * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1621569Sdist */ 1721569Sdist 186440Swnj #ifndef lint 1921569Sdist char copyright[] = 2035619Sbostic "@(#) Copyright (c) 1983 The Regents of the University of California.\n\ 2121569Sdist All rights reserved.\n"; 2235619Sbostic #endif /* not lint */ 236440Swnj 2421569Sdist #ifndef lint 25*38108Sbostic static char sccsid[] = "@(#)rcp.c 5.19 (Berkeley) 05/23/89"; 2635619Sbostic #endif /* not lint */ 2721569Sdist 2812989Ssam /* 2912989Ssam * rcp 3012989Ssam */ 316720Smckusick #include <sys/param.h> 3232127Sbostic #include <sys/file.h> 336440Swnj #include <sys/stat.h> 3423101Slepreau #include <sys/time.h> 356440Swnj #include <sys/ioctl.h> 3638098Sbostic #include <sys/dir.h> 3738098Sbostic #include <sys/signal.h> 389199Ssam #include <netinet/in.h> 396440Swnj #include <pwd.h> 4018026Sralph #include <netdb.h> 416440Swnj #include <errno.h> 4238098Sbostic #include <strings.h> 4338098Sbostic #include <stdio.h> 4438098Sbostic #include <ctype.h> 4537037Sbostic #include "pathnames.h" 4612989Ssam 4738098Sbostic #ifdef KERBEROS 4836624Skfall #include <kerberos/krb.h> 4938098Sbostic 5038098Sbostic char krb_realm[REALM_SZ]; 5138098Sbostic int use_kerberos = 1, encrypt = 0; 5238098Sbostic CREDENTIALS cred; 5338098Sbostic Key_schedule schedule; 5436624Skfall #endif 5536624Skfall 5638098Sbostic extern int errno; 5738098Sbostic extern char *sys_errlist[]; 5838098Sbostic struct passwd *pwd; 5938098Sbostic int errs, pflag, port, rem, userid; 6038098Sbostic int iamremote, iamrecursive, targetshouldbedirectory; 616440Swnj 6238100Sbostic #define CMDNEEDS 20 6338100Sbostic char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ 6438098Sbostic 6538098Sbostic typedef struct _buf { 6621254Smckusick int cnt; 6721254Smckusick char *buf; 6838098Sbostic } BUF; 6921254Smckusick 706440Swnj main(argc, argv) 716440Swnj int argc; 726440Swnj char **argv; 736440Swnj { 7438098Sbostic extern int optind; 7518126Sralph struct servent *sp; 7638099Sbostic int ch, fflag, tflag; 7738098Sbostic char *targ, *colon(); 7838098Sbostic struct passwd *getpwuid(); 7938098Sbostic int lostconn(); 8018026Sralph 8138098Sbostic #ifdef KERBEROS 8236626Skfall sp = getservbyname("kshell", "tcp"); 8338098Sbostic if (sp == NULL) { 8436626Skfall use_kerberos = 0; 8536626Skfall old_warning("kshell service unknown"); 8636626Skfall sp = getservbyname("kshell", "tcp"); 8736626Skfall } 8836626Skfall #else 8918026Sralph sp = getservbyname("shell", "tcp"); 9036626Skfall #endif 9138098Sbostic if (!sp) { 9238098Sbostic (void)fprintf(stderr, "rcp: shell/tcp: unknown service\n"); 9318026Sralph exit(1); 9418026Sralph } 9518126Sralph port = sp->s_port; 9638098Sbostic 9738098Sbostic if (!(pwd = getpwuid(userid = getuid()))) { 9838098Sbostic (void)fprintf(stderr, "rcp: unknown user %d.\n", userid); 996440Swnj exit(1); 1006440Swnj } 10123101Slepreau 10238099Sbostic fflag = tflag = 0; 10338098Sbostic while ((ch = getopt(argc, argv, "dfkprtx")) != EOF) 10438098Sbostic switch(ch) { 10538098Sbostic case 'd': 10638098Sbostic targetshouldbedirectory = 1; 10723101Slepreau break; 10838098Sbostic case 'f': /* "from" */ 10938099Sbostic fflag = 1; 11038099Sbostic break; 11138098Sbostic #ifdef KERBEROS 11238098Sbostic case 'k': 11336624Skfall strncpy(krb_realm, ++argv, REALM_SZ); 11436624Skfall break; 11536624Skfall #endif 11638098Sbostic case 'p': /* preserve access/mod times */ 11738098Sbostic ++pflag; 11823101Slepreau break; 11938098Sbostic case 'r': 12038098Sbostic ++iamrecursive; 12123101Slepreau break; 12238098Sbostic case 't': /* "to" */ 12338099Sbostic tflag = 1; 12438099Sbostic break; 12538098Sbostic #ifdef KERBEROS 12638098Sbostic case 'x': 12738098Sbostic encrypt = 1; 12838098Sbostic des_set_key(cred.session, schedule); 12938098Sbostic break; 13038098Sbostic #endif 13138098Sbostic case '?': 13238098Sbostic default: 13332127Sbostic usage(); 13423101Slepreau } 13538098Sbostic argc -= optind; 13638098Sbostic argv += optind; 13738098Sbostic 13838099Sbostic if (fflag) { 13938099Sbostic iamremote = 1; 14038099Sbostic (void)response(); 14138099Sbostic (void)setuid(userid); 14238099Sbostic source(argc, argv); 14338099Sbostic exit(errs); 14438099Sbostic } 14538099Sbostic 14638099Sbostic if (tflag) { 14738099Sbostic iamremote = 1; 14838099Sbostic (void)setuid(userid); 14938099Sbostic sink(argc, argv); 15038099Sbostic exit(errs); 15138099Sbostic } 15238099Sbostic 15332127Sbostic if (argc < 2) 15432127Sbostic usage(); 1556440Swnj if (argc > 2) 1566440Swnj targetshouldbedirectory = 1; 15738098Sbostic 15832127Sbostic rem = -1; 15938098Sbostic (void)sprintf(cmd, "rcp%s%s%s", iamrecursive ? " -r" : "", 16038098Sbostic pflag ? " -p" : "", targetshouldbedirectory ? " -d" : ""); 16138098Sbostic 16238098Sbostic (void)signal(SIGPIPE, lostconn); 16338098Sbostic 16438098Sbostic if (targ = colon(argv[argc - 1])) 16538098Sbostic toremote(targ, argc, argv); 16638098Sbostic else { 16738098Sbostic tolocal(argc, argv); 16838098Sbostic if (targetshouldbedirectory) 16938098Sbostic verifydir(argv[argc - 1]); 17038098Sbostic } 17138098Sbostic exit(errs); 17238098Sbostic } 17338098Sbostic 17438098Sbostic toremote(targ, argc, argv) 17538098Sbostic char *targ; 17638098Sbostic int argc; 17738098Sbostic char **argv; 17838098Sbostic { 17938098Sbostic int i; 18038100Sbostic char *bp, *host, *src, *suser, *thost, *tuser; 18138100Sbostic char *colon(), *malloc(); 18238098Sbostic 18338098Sbostic *targ++ = 0; 18438098Sbostic if (*targ == 0) 18538098Sbostic targ = "."; 18638098Sbostic 18738100Sbostic if (thost = index(argv[argc - 1], '@')) { 18838098Sbostic *thost++ = 0; 18938098Sbostic tuser = argv[argc - 1]; 19038098Sbostic if (*tuser == '\0') 19124711Sbloom tuser = NULL; 19238098Sbostic else if (!okname(tuser)) 19338098Sbostic exit(1); 19438098Sbostic } else { 19538098Sbostic thost = argv[argc - 1]; 19638098Sbostic tuser = NULL; 19738098Sbostic } 19836624Skfall 19938098Sbostic for (i = 0; i < argc - 1; i++) { 20038098Sbostic src = colon(argv[i]); 20138098Sbostic if (src) { /* remote to remote */ 20238098Sbostic *src++ = 0; 20338098Sbostic if (*src == 0) 20438098Sbostic src = "."; 20538098Sbostic host = index(argv[i], '@'); 20638100Sbostic if (!(bp = malloc((u_int)(strlen(_PATH_RSH) + 20738100Sbostic strlen(argv[i]) + strlen(src) + 20838100Sbostic strlen(tuser) + strlen(thost) + 20938100Sbostic strlen(targ)) + CMDNEEDS + 20))) 21038100Sbostic nospace(); 21138098Sbostic if (host) { 21238098Sbostic *host++ = 0; 21338098Sbostic suser = argv[i]; 21438098Sbostic if (*suser == '\0') 21538098Sbostic suser = pwd->pw_name; 21638098Sbostic else if (!okname(suser)) 21738098Sbostic continue; 21838100Sbostic (void)sprintf(bp, 21938098Sbostic "%s %s -l %s -n %s %s '%s%s%s:%s'", 22038098Sbostic _PATH_RSH, host, suser, cmd, src, 22138098Sbostic tuser ? tuser : "", tuser ? "@" : "", 22238098Sbostic thost, targ); 22338098Sbostic } else 22438100Sbostic (void)sprintf(bp, "%s %s -n %s %s '%s%s%s:%s'", 22538098Sbostic _PATH_RSH, argv[i], cmd, src, 22638098Sbostic tuser ? tuser : "", tuser ? "@" : "", 22738098Sbostic thost, targ); 22838100Sbostic (void)susystem(bp); 22938100Sbostic (void)free(bp); 23038098Sbostic } else { /* local to remote */ 23138098Sbostic if (rem == -1) { 23238100Sbostic if (!(bp = malloc((u_int)strlen(targ) + 23338100Sbostic CMDNEEDS + 20))) 23438100Sbostic nospace(); 23538100Sbostic (void)sprintf(bp, "%s -t %s", cmd, targ); 23638098Sbostic host = thost; 23738098Sbostic #ifdef KERBEROS 23838098Sbostic if (use_kerberos) 23938100Sbostic kerberos(bp, 24038100Sbostic tuser ? tuser : pwd->pw_name); 24138098Sbostic else 24238098Sbostic #endif 24324711Sbloom rem = rcmd(&host, port, pwd->pw_name, 24424711Sbloom tuser ? tuser : pwd->pw_name, 24538100Sbostic bp, 0); 24638098Sbostic if (rem < 0) 24738098Sbostic exit(1); 24838098Sbostic if (response() < 0) 24938098Sbostic exit(1); 25038100Sbostic (void)free(bp); 25138098Sbostic (void)setuid(userid); 2526440Swnj } 25338098Sbostic source(1, argv+i); 2546440Swnj } 25538098Sbostic } 25638098Sbostic } 25738098Sbostic 25838098Sbostic tolocal(argc, argv) 25938098Sbostic int argc; 26038098Sbostic char **argv; 26138098Sbostic { 26238098Sbostic int i; 26338100Sbostic char *bp, *host, *src, *suser; 26438100Sbostic char *colon(), *malloc(); 26538098Sbostic 26638098Sbostic for (i = 0; i < argc - 1; i++) { 26738100Sbostic if (!(src = colon(argv[i]))) { /* local to local */ 26838100Sbostic if (!(bp = malloc((u_int)(strlen(_PATH_CP) + 26938100Sbostic strlen(argv[i]) + strlen(argv[argc - 1])) + 20))) 27038100Sbostic nospace(); 27138100Sbostic (void)sprintf(bp, "%s%s%s %s %s", _PATH_CP, 27238100Sbostic iamrecursive ? " -r" : "", pflag ? " -p" : "", 27338100Sbostic argv[i], argv[argc - 1]); 27438100Sbostic (void)susystem(bp); 27538100Sbostic (void)free(bp); 27638100Sbostic continue; 27738100Sbostic } 27838100Sbostic *src++ = 0; 27938100Sbostic if (*src == 0) 28038100Sbostic src = "."; 28138100Sbostic host = index(argv[i], '@'); 28238100Sbostic if (host) { 28338100Sbostic *host++ = 0; 28438100Sbostic suser = argv[i]; 28538100Sbostic if (*suser == '\0') 28638098Sbostic suser = pwd->pw_name; 28738100Sbostic else if (!okname(suser)) 28838100Sbostic continue; 28938100Sbostic } else { 29038100Sbostic host = argv[i]; 29138100Sbostic suser = pwd->pw_name; 29238100Sbostic } 29338100Sbostic if (!(bp = malloc((u_int)(strlen(src)) + CMDNEEDS + 20))) 29438100Sbostic nospace(); 29538100Sbostic (void)sprintf(bp, "%s -f %s", cmd, src); 29638098Sbostic #ifdef KERBEROS 29738100Sbostic if (use_kerberos) 29838100Sbostic kerberos(bp, suser); 29938100Sbostic else 30038098Sbostic #endif 30138100Sbostic rem = rcmd(&host, port, pwd->pw_name, suser, bp, 0); 30238100Sbostic (void)free(bp); 30338100Sbostic if (rem < 0) 30438100Sbostic continue; 30538100Sbostic (void)setreuid(0, userid); 30638100Sbostic sink(1, argv + argc - 1); 30738100Sbostic (void)setreuid(userid, 0); 30838100Sbostic (void)close(rem); 30938100Sbostic rem = -1; 3106440Swnj } 3116440Swnj } 3126440Swnj 31338098Sbostic #ifdef KERBEROS 31438100Sbostic kerberos(bp, user) 31538100Sbostic char *bp, *user; 31638098Sbostic { 31738098Sbostic struct servent *sp; 31838098Sbostic char *host; 31938098Sbostic 32038098Sbostic again: rem = KSUCCESS; 32138098Sbostic if (krb_realm[0] == '\0') 32238098Sbostic rem = krb_get_lrealm(krb_realm, 1); 32338098Sbostic if (rem == KSUCCESS) { 32438098Sbostic if (encrypt) 32538100Sbostic rem = krcmd_mutual(&host, port, user, bp, 0, 32638100Sbostic krb_realm, &cred, schedule); 32738098Sbostic else 32838100Sbostic rem = krcmd(&host, port, user, bp, 0, krb_realm); 32938098Sbostic } else { 33038098Sbostic (void)fprintf(stderr, 33138098Sbostic "rcp: error getting local realm %s\n", krb_err_txt[rem]); 33238098Sbostic exit(1); 33338098Sbostic } 33438098Sbostic if (rem < 0 && errno == ECONNREFUSED) { 33538098Sbostic use_kerberos = 0; 33638098Sbostic old_warning("remote host doesn't support Kerberos"); 33738098Sbostic sp = getservbyname("shell", "tcp"); 33838098Sbostic if (sp == NULL) { 33938098Sbostic (void)fprintf(stderr, 34038098Sbostic "rcp: unknown service shell/tcp\n"); 34138098Sbostic exit(1); 34238098Sbostic } 34338098Sbostic port = sp->s_port; 34438098Sbostic goto again; 34538098Sbostic } 34638098Sbostic } 34738098Sbostic #endif /* KERBEROS */ 34838098Sbostic 3496440Swnj verifydir(cp) 3506440Swnj char *cp; 3516440Swnj { 3526440Swnj struct stat stb; 3536440Swnj 35418126Sralph if (stat(cp, &stb) >= 0) { 35518126Sralph if ((stb.st_mode & S_IFMT) == S_IFDIR) 35618126Sralph return; 35718126Sralph errno = ENOTDIR; 35818126Sralph } 3596440Swnj error("rcp: %s: %s.\n", cp, sys_errlist[errno]); 3606440Swnj exit(1); 3616440Swnj } 3626440Swnj 3636440Swnj char * 3646440Swnj colon(cp) 36538098Sbostic register char *cp; 3666440Swnj { 36738098Sbostic for (; *cp; ++cp) { 3686440Swnj if (*cp == ':') 36938098Sbostic return(cp); 3706440Swnj if (*cp == '/') 37138098Sbostic return(0); 3726440Swnj } 37338098Sbostic return(0); 3746440Swnj } 3756440Swnj 3766440Swnj okname(cp0) 3776440Swnj char *cp0; 3786440Swnj { 3796440Swnj register char *cp = cp0; 3806440Swnj register int c; 3816440Swnj 3826440Swnj do { 3836440Swnj c = *cp; 3846440Swnj if (c & 0200) 3856440Swnj goto bad; 3866440Swnj if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') 3876440Swnj goto bad; 38838100Sbostic } while (*++cp); 38938098Sbostic return(1); 3906440Swnj bad: 39138100Sbostic (void)fprintf(stderr, "rcp: invalid user name %s\n", cp0); 39238098Sbostic return(0); 3936440Swnj } 3946440Swnj 39517999Sserge susystem(s) 39617999Sserge char *s; 3976440Swnj { 39817999Sserge int status, pid, w; 39917999Sserge register int (*istat)(), (*qstat)(); 4006440Swnj 40117999Sserge if ((pid = vfork()) == 0) { 40238098Sbostic (void)setuid(userid); 40337037Sbostic execl(_PATH_BSHELL, "sh", "-c", s, (char *)0); 40417999Sserge _exit(127); 40517999Sserge } 40617999Sserge istat = signal(SIGINT, SIG_IGN); 40717999Sserge qstat = signal(SIGQUIT, SIG_IGN); 40817999Sserge while ((w = wait(&status)) != pid && w != -1) 40917999Sserge ; 41017999Sserge if (w == -1) 41117999Sserge status = -1; 41238098Sbostic (void)signal(SIGINT, istat); 41338098Sbostic (void)signal(SIGQUIT, qstat); 41438098Sbostic return(status); 4156440Swnj } 4166440Swnj 4176440Swnj source(argc, argv) 4186440Swnj int argc; 4196440Swnj char **argv; 4206440Swnj { 4216440Swnj struct stat stb; 42238098Sbostic static BUF buffer; 42338098Sbostic BUF *bp; 42438098Sbostic off_t i; 42532268Sbostic int x, readerr, f, amt; 42638098Sbostic char *last, *name, buf[BUFSIZ]; 42738098Sbostic BUF *allocbuf(); 4286440Swnj 4296440Swnj for (x = 0; x < argc; x++) { 4306440Swnj name = argv[x]; 43138098Sbostic if ((f = open(name, O_RDONLY, 0)) < 0) { 4326440Swnj error("rcp: %s: %s\n", name, sys_errlist[errno]); 4336440Swnj continue; 4346440Swnj } 4356440Swnj if (fstat(f, &stb) < 0) 4366440Swnj goto notreg; 4376440Swnj switch (stb.st_mode&S_IFMT) { 4386440Swnj 4396440Swnj case S_IFREG: 4406440Swnj break; 4416440Swnj 4426440Swnj case S_IFDIR: 4436440Swnj if (iamrecursive) { 44438098Sbostic (void)close(f); 44523101Slepreau rsource(name, &stb); 4466440Swnj continue; 4476440Swnj } 44838098Sbostic /* FALLTHROUGH */ 4496440Swnj default: 45038098Sbostic notreg: (void)close(f); 4516440Swnj error("rcp: %s: not a plain file\n", name); 4526440Swnj continue; 4536440Swnj } 4546440Swnj last = rindex(name, '/'); 4556440Swnj if (last == 0) 4566440Swnj last = name; 4576440Swnj else 4586440Swnj last++; 45923101Slepreau if (pflag) { 46023101Slepreau /* 46123101Slepreau * Make it compatible with possible future 46223101Slepreau * versions expecting microseconds. 46323101Slepreau */ 46438100Sbostic (void)sprintf(buf, "T%ld 0 %ld 0\n", stb.st_mtime, 46538100Sbostic stb.st_atime); 46638098Sbostic (void)write(rem, buf, strlen(buf)); 46723101Slepreau if (response() < 0) { 46838098Sbostic (void)close(f); 46923101Slepreau continue; 47023101Slepreau } 47123101Slepreau } 47238100Sbostic (void)sprintf(buf, "C%04o %ld %s\n", stb.st_mode&07777, 47338100Sbostic stb.st_size, last); 47438098Sbostic (void)write(rem, buf, strlen(buf)); 4756440Swnj if (response() < 0) { 47638098Sbostic (void)close(f); 4776440Swnj continue; 4786440Swnj } 47935689Sbostic if ((bp = allocbuf(&buffer, f, BUFSIZ)) == 0) { 48038098Sbostic (void)close(f); 48121254Smckusick continue; 48221254Smckusick } 48332268Sbostic readerr = 0; 48421254Smckusick for (i = 0; i < stb.st_size; i += bp->cnt) { 48521254Smckusick amt = bp->cnt; 4866440Swnj if (i + amt > stb.st_size) 4876440Swnj amt = stb.st_size - i; 48832268Sbostic if (readerr == 0 && read(f, bp->buf, amt) != amt) 48932268Sbostic readerr = errno; 49038098Sbostic (void)write(rem, bp->buf, amt); 4916440Swnj } 49238098Sbostic (void)close(f); 49332268Sbostic if (readerr == 0) 49438098Sbostic (void)write(rem, "", 1); 4956440Swnj else 49632268Sbostic error("rcp: %s: %s\n", name, sys_errlist[readerr]); 49738098Sbostic (void)response(); 4986440Swnj } 4996440Swnj } 5006440Swnj 50123101Slepreau rsource(name, statp) 5026440Swnj char *name; 50323101Slepreau struct stat *statp; 5046440Swnj { 50538098Sbostic DIR *d; 5066440Swnj struct direct *dp; 50738100Sbostic char *last, *vect[1], path[MAXPATHLEN]; 5086440Swnj 50938098Sbostic if (!(d = opendir(name))) { 51018126Sralph error("rcp: %s: %s\n", name, sys_errlist[errno]); 5116440Swnj return; 5126440Swnj } 5136440Swnj last = rindex(name, '/'); 5146440Swnj if (last == 0) 5156440Swnj last = name; 5166440Swnj else 5176440Swnj last++; 51823101Slepreau if (pflag) { 51938100Sbostic (void)sprintf(path, "T%ld 0 %ld 0\n", statp->st_mtime, 52038100Sbostic statp->st_atime); 52138100Sbostic (void)write(rem, path, strlen(path)); 52223101Slepreau if (response() < 0) { 52323101Slepreau closedir(d); 52423101Slepreau return; 52523101Slepreau } 52623101Slepreau } 52738100Sbostic (void)sprintf(path, "D%04o %d %s\n", statp->st_mode&07777, 0, last); 52838100Sbostic (void)write(rem, path, strlen(path)); 5296440Swnj if (response() < 0) { 5306440Swnj closedir(d); 5316440Swnj return; 5326440Swnj } 5336440Swnj while (dp = readdir(d)) { 5346440Swnj if (dp->d_ino == 0) 5356440Swnj continue; 5366440Swnj if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 5376440Swnj continue; 53838100Sbostic if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) { 53938100Sbostic error("%s/%s: name too long.\n", name, dp->d_name); 5406440Swnj continue; 5416440Swnj } 54238100Sbostic (void)sprintf(path, "%s/%s", name, dp->d_name); 54338100Sbostic vect[0] = path; 54438100Sbostic source(1, vect); 5456440Swnj } 5466440Swnj closedir(d); 54738098Sbostic (void)write(rem, "E\n", 2); 54838098Sbostic (void)response(); 5496440Swnj } 5506440Swnj 5516440Swnj response() 5526440Swnj { 55338098Sbostic register char *cp; 55438098Sbostic char ch, resp, rbuf[BUFSIZ]; 5556440Swnj 55638098Sbostic if (read(rem, &resp, sizeof(resp)) != sizeof(resp)) 5576440Swnj lostconn(); 5586440Swnj 55938098Sbostic cp = rbuf; 56038098Sbostic switch(resp) { 56123101Slepreau case 0: /* ok */ 56238098Sbostic return(0); 5636440Swnj default: 5646440Swnj *cp++ = resp; 56538098Sbostic /* FALLTHROUGH */ 56623101Slepreau case 1: /* error, followed by err msg */ 56723101Slepreau case 2: /* fatal error, "" */ 5686440Swnj do { 56938098Sbostic if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) 5706440Swnj lostconn(); 57138098Sbostic *cp++ = ch; 57238098Sbostic } while (cp < &rbuf[BUFSIZ] && ch != '\n'); 57338098Sbostic 57438098Sbostic if (!iamremote) 57538098Sbostic (void)write(2, rbuf, cp - rbuf); 57638098Sbostic ++errs; 5776440Swnj if (resp == 1) 57838098Sbostic return(-1); 5796440Swnj exit(1); 5806440Swnj } 5816440Swnj /*NOTREACHED*/ 5826440Swnj } 5836440Swnj 5846440Swnj lostconn() 5856440Swnj { 58638098Sbostic if (!iamremote) 58738098Sbostic (void)fprintf(stderr, "rcp: lost connection\n"); 5886440Swnj exit(1); 5896440Swnj } 5906440Swnj 5916440Swnj sink(argc, argv) 5926440Swnj int argc; 5936440Swnj char **argv; 5946440Swnj { 59538100Sbostic register char *cp; 59638098Sbostic static BUF buffer; 59721254Smckusick struct stat stb; 59823101Slepreau struct timeval tv[2]; 59938100Sbostic BUF *bp, *allocbuf(); 60038100Sbostic off_t i, j; 60138100Sbostic char ch, *targ, *why; 60238100Sbostic int amt, count, exists, first, mask, mode; 60338100Sbostic int ofd, setimes, size, targisdir, wrerr; 60438100Sbostic char *np, *vect[1], buf[BUFSIZ], *malloc(); 6056440Swnj 60638100Sbostic #define atime tv[0] 60738100Sbostic #define mtime tv[1] 60838100Sbostic #define SCREWUP(str) { why = str; goto screwup; } 60938100Sbostic 61038100Sbostic setimes = targisdir = 0; 61138100Sbostic mask = umask(0); 61223112Slepreau if (!pflag) 61338098Sbostic (void)umask(mask); 61418126Sralph if (argc != 1) { 6156440Swnj error("rcp: ambiguous target\n"); 6166440Swnj exit(1); 6176440Swnj } 6186440Swnj targ = *argv; 6196440Swnj if (targetshouldbedirectory) 6206440Swnj verifydir(targ); 62138098Sbostic (void)write(rem, "", 1); 6226440Swnj if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR) 6236440Swnj targisdir = 1; 62438100Sbostic for (first = 1;; first = 0) { 62538100Sbostic cp = buf; 6266440Swnj if (read(rem, cp, 1) <= 0) 6276440Swnj return; 6286440Swnj if (*cp++ == '\n') 62938100Sbostic SCREWUP("unexpected <newline>"); 6306440Swnj do { 63138100Sbostic if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) 6326440Swnj SCREWUP("lost connection"); 63338100Sbostic *cp++ = ch; 63438100Sbostic } while (cp < &buf[BUFSIZ - 1] && ch != '\n'); 6356440Swnj *cp = 0; 63638100Sbostic 63738100Sbostic if (buf[0] == '\01' || buf[0] == '\02') { 6386440Swnj if (iamremote == 0) 63938100Sbostic (void)write(2, buf + 1, strlen(buf + 1)); 64038100Sbostic if (buf[0] == '\02') 6416440Swnj exit(1); 6426440Swnj errs++; 6436440Swnj continue; 6446440Swnj } 64538100Sbostic if (buf[0] == 'E') { 64638098Sbostic (void)write(rem, "", 1); 6476440Swnj return; 6486440Swnj } 64923101Slepreau 650*38108Sbostic if (ch == '\n') 651*38108Sbostic --cp; 652*38108Sbostic 65323101Slepreau #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0'); 65438100Sbostic cp = buf; 65523101Slepreau if (*cp == 'T') { 65623101Slepreau setimes++; 65723101Slepreau cp++; 65823101Slepreau getnum(mtime.tv_sec); 65923101Slepreau if (*cp++ != ' ') 66023101Slepreau SCREWUP("mtime.sec not delimited"); 66123101Slepreau getnum(mtime.tv_usec); 66223101Slepreau if (*cp++ != ' ') 66323101Slepreau SCREWUP("mtime.usec not delimited"); 66423101Slepreau getnum(atime.tv_sec); 66523101Slepreau if (*cp++ != ' ') 66623101Slepreau SCREWUP("atime.sec not delimited"); 66723101Slepreau getnum(atime.tv_usec); 66823101Slepreau if (*cp++ != '\0') 66923101Slepreau SCREWUP("atime.usec not delimited"); 67038098Sbostic (void)write(rem, "", 1); 67123101Slepreau continue; 67223101Slepreau } 67314580Sralph if (*cp != 'C' && *cp != 'D') { 67414580Sralph /* 67514580Sralph * Check for the case "rcp remote:foo\* local:bar". 67614580Sralph * In this case, the line "No match." can be returned 67714580Sralph * by the shell before the rcp command on the remote is 67814580Sralph * executed so the ^Aerror_message convention isn't 67914580Sralph * followed. 68014580Sralph */ 68114580Sralph if (first) { 68214580Sralph error("%s\n", cp); 68314580Sralph exit(1); 68414580Sralph } 6856440Swnj SCREWUP("expected control record"); 68614580Sralph } 6876440Swnj mode = 0; 68838100Sbostic for (++cp; cp < buf + 5; cp++) { 6896440Swnj if (*cp < '0' || *cp > '7') 6906440Swnj SCREWUP("bad mode"); 6916440Swnj mode = (mode << 3) | (*cp - '0'); 6926440Swnj } 6936440Swnj if (*cp++ != ' ') 6946440Swnj SCREWUP("mode not delimited"); 6956440Swnj size = 0; 69623112Slepreau while (isdigit(*cp)) 6976440Swnj size = size * 10 + (*cp++ - '0'); 6986440Swnj if (*cp++ != ' ') 6996440Swnj SCREWUP("size not delimited"); 70038100Sbostic if (targisdir) { 70138100Sbostic static char *namebuf; 70238100Sbostic static int cursize; 70338100Sbostic int need; 70438100Sbostic 70538100Sbostic need = strlen(targ) + strlen(cp) + 250; 70638100Sbostic if (need > cursize) { 70738100Sbostic if (!(namebuf = malloc((u_int)need))) 708*38108Sbostic error("out of memory\n"); 70938100Sbostic } 71038100Sbostic (void)sprintf(namebuf, "%s%s%s", targ, 7116440Swnj *targ ? "/" : "", cp); 71238100Sbostic np = namebuf; 71338100Sbostic } 7146440Swnj else 71538100Sbostic np = targ; 71638100Sbostic exists = stat(np, &stb) == 0; 71738100Sbostic if (buf[0] == 'D') { 71818126Sralph if (exists) { 7196440Swnj if ((stb.st_mode&S_IFMT) != S_IFDIR) { 7206440Swnj errno = ENOTDIR; 7216440Swnj goto bad; 7226440Swnj } 72323112Slepreau if (pflag) 72438100Sbostic (void)chmod(np, mode); 72538100Sbostic } else if (mkdir(np, mode) < 0) 7266440Swnj goto bad; 72738100Sbostic vect[0] = np; 72838100Sbostic sink(1, vect); 72923101Slepreau if (setimes) { 73023101Slepreau setimes = 0; 73138100Sbostic if (utimes(np, tv) < 0) 73238100Sbostic error("rcp: can't set times on %s: %s\n", 73338100Sbostic np, sys_errlist[errno]); 73423101Slepreau } 7356440Swnj continue; 73618126Sralph } 73738100Sbostic if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { 73838100Sbostic bad: error("rcp: %s: %s\n", np, sys_errlist[errno]); 7396440Swnj continue; 7406440Swnj } 74123112Slepreau if (exists && pflag) 74238100Sbostic (void)fchmod(ofd, mode); 74338098Sbostic (void)write(rem, "", 1); 74438100Sbostic if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == 0) { 74538100Sbostic (void)close(ofd); 74621254Smckusick continue; 74721254Smckusick } 74821254Smckusick cp = bp->buf; 74921254Smckusick count = 0; 7506440Swnj wrerr = 0; 7516440Swnj for (i = 0; i < size; i += BUFSIZ) { 75221254Smckusick amt = BUFSIZ; 7536440Swnj if (i + amt > size) 7546440Swnj amt = size - i; 75521254Smckusick count += amt; 7566440Swnj do { 75721254Smckusick j = read(rem, cp, amt); 75824711Sbloom if (j <= 0) { 759*38108Sbostic error("rcp: %s\n", 76038100Sbostic j ? sys_errlist[errno] : 76138100Sbostic "dropped connection"); 7626440Swnj exit(1); 76324711Sbloom } 7646440Swnj amt -= j; 7656440Swnj cp += j; 7666440Swnj } while (amt > 0); 76721254Smckusick if (count == bp->cnt) { 76821254Smckusick if (wrerr == 0 && 76938100Sbostic write(ofd, bp->buf, count) != count) 77021254Smckusick wrerr++; 77121254Smckusick count = 0; 77221254Smckusick cp = bp->buf; 77321254Smckusick } 7746440Swnj } 77521254Smckusick if (count != 0 && wrerr == 0 && 77638100Sbostic write(ofd, bp->buf, count) != count) 77721254Smckusick wrerr++; 77838100Sbostic if (ftruncate(ofd, size)) 77938100Sbostic error("rcp: can't truncate %s: %s\n", np, 78038100Sbostic sys_errlist[errno]); 78138100Sbostic (void)close(ofd); 78238098Sbostic (void)response(); 78323101Slepreau if (setimes) { 78423101Slepreau setimes = 0; 78538100Sbostic if (utimes(np, tv) < 0) 78623101Slepreau error("rcp: can't set times on %s: %s\n", 78738100Sbostic np, sys_errlist[errno]); 78823101Slepreau } 7896440Swnj if (wrerr) 79038100Sbostic error("rcp: %s: %s\n", np, sys_errlist[errno]); 7916440Swnj else 79238098Sbostic (void)write(rem, "", 1); 7936440Swnj } 7946440Swnj screwup: 79538100Sbostic error("rcp: protocol screwup: %s\n", why); 7966440Swnj exit(1); 7976440Swnj } 7986440Swnj 79938098Sbostic BUF * 80021254Smckusick allocbuf(bp, fd, blksize) 80138098Sbostic BUF *bp; 80221254Smckusick int fd, blksize; 80321254Smckusick { 80421254Smckusick struct stat stb; 80521254Smckusick int size; 80638098Sbostic char *malloc(); 80721254Smckusick 80821254Smckusick if (fstat(fd, &stb) < 0) { 80921254Smckusick error("rcp: fstat: %s\n", sys_errlist[errno]); 81038098Sbostic return(0); 81121254Smckusick } 81221254Smckusick size = roundup(stb.st_blksize, blksize); 81321254Smckusick if (size == 0) 81421254Smckusick size = blksize; 81521254Smckusick if (bp->cnt < size) { 81621254Smckusick if (bp->buf != 0) 81721254Smckusick free(bp->buf); 81838098Sbostic bp->buf = (char *)malloc((u_int)size); 81938100Sbostic if (!bp->buf) { 82021254Smckusick error("rcp: malloc: out of memory\n"); 82138098Sbostic return(0); 82221254Smckusick } 82321254Smckusick } 82421254Smckusick bp->cnt = size; 82538098Sbostic return(bp); 82621254Smckusick } 82721254Smckusick 82838098Sbostic /* VARARGS1 */ 82938100Sbostic error(fmt, a1, a2, a3) 8306440Swnj char *fmt; 83138100Sbostic int a1, a2, a3; 8326440Swnj { 833*38108Sbostic static FILE *fp; 8346440Swnj 83538098Sbostic ++errs; 836*38108Sbostic if (!fp && !(fp = fdopen(rem, "w"))) 837*38108Sbostic return; 838*38108Sbostic (void)fprintf(fp, "%c", 0x01); 839*38108Sbostic (void)fprintf(fp, fmt, a1, a2, a3); 840*38108Sbostic (void)fflush(fp); 84138098Sbostic if (!iamremote) 842*38108Sbostic (void)fprintf(stderr, fmt, a1, a2, a3); 8436440Swnj } 84432127Sbostic 84538100Sbostic nospace() 84638100Sbostic { 84738100Sbostic (void)fprintf(stderr, "rcp: out of memory.\n"); 84838100Sbostic exit(1); 84938100Sbostic } 85038100Sbostic 85138100Sbostic #ifdef KERBEROS 85238100Sbostic old_warning(str) 85338100Sbostic char *str; 85438100Sbostic { 85538100Sbostic (void)fprintf(stderr, "rcp: warning: %s, using standard rcp\n", str); 85638100Sbostic } 85738100Sbostic #endif 85838100Sbostic 85932127Sbostic usage() 86032127Sbostic { 86138098Sbostic #ifdef KERBEROS 86238098Sbostic (void)fprintf(stderr, "%s\n\t%s\n", 86338098Sbostic "usage: rcp [-k realm] [-px] f1 f2", 86438098Sbostic "or: rcp [-k realm] [-rpx] f1 ... fn directory"); 86536626Skfall #else 86638098Sbostic (void)fprintf(stderr, 86738098Sbostic "usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn directory\n"); 86836626Skfall #endif 86932127Sbostic exit(1); 87032127Sbostic } 871