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*42498Sbostic static char sccsid[] = "@(#)rcp.c 5.26 (Berkeley) 05/31/90"; 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> 4242011Sbostic #include <string.h> 4338098Sbostic #include <stdio.h> 4438098Sbostic #include <ctype.h> 4537037Sbostic #include "pathnames.h" 4612989Ssam 4738098Sbostic #ifdef KERBEROS 48*42498Sbostic #include <kerberosIV/des.h> 4941785Sbostic #include <kerberosIV/krb.h> 5038879Skfall char dst_realm_buf[REALM_SZ]; 5138879Skfall char *dest_realm = NULL; 5238879Skfall int use_kerberos = 1, encrypt = 0; 5338879Skfall CREDENTIALS cred; 5438879Skfall Key_schedule schedule; 5538879Skfall extern char *krb_realmofhost(); 5638879Skfall #define OPTIONS "dfkprtx" 5738879Skfall #else 5838879Skfall #define OPTIONS "dfprt" 5936624Skfall #endif 6036624Skfall 6138098Sbostic extern int errno; 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 7138098Sbostic typedef struct _buf { 7221254Smckusick int cnt; 7321254Smckusick char *buf; 7438098Sbostic } BUF; 7521254Smckusick 766440Swnj main(argc, argv) 776440Swnj int argc; 786440Swnj char **argv; 796440Swnj { 8038098Sbostic extern int optind; 8118126Sralph struct servent *sp; 8238099Sbostic int ch, fflag, tflag; 8338098Sbostic char *targ, *colon(); 8438098Sbostic struct passwd *getpwuid(); 8538098Sbostic int lostconn(); 8618026Sralph 8738099Sbostic fflag = tflag = 0; 8838879Skfall while ((ch = getopt(argc, argv, OPTIONS)) != EOF) 8938098Sbostic switch(ch) { 9038879Skfall /* user-visible flags */ 9138098Sbostic case 'p': /* preserve access/mod times */ 9238098Sbostic ++pflag; 9323101Slepreau break; 9438098Sbostic case 'r': 9538098Sbostic ++iamrecursive; 9623101Slepreau break; 9738879Skfall #ifdef KERBEROS 9838879Skfall case 'k': 9938879Skfall strncpy(dst_realm_buf, ++argv, REALM_SZ); 10038879Skfall dest_realm = dst_realm_buf; 10138099Sbostic break; 10238098Sbostic case 'x': 10338098Sbostic encrypt = 1; 10438879Skfall /* des_set_key(cred.session, schedule); */ 10538098Sbostic break; 10638098Sbostic #endif 10738879Skfall /* rshd-invoked options (server) */ 10838879Skfall case 'd': 10938879Skfall targetshouldbedirectory = 1; 11038879Skfall break; 11138879Skfall case 'f': /* "from" */ 11238879Skfall iamremote = 1; 11338879Skfall fflag = 1; 11438879Skfall break; 11538879Skfall case 't': /* "to" */ 11638879Skfall iamremote = 1; 11738879Skfall tflag = 1; 11838879Skfall break; 11938879Skfall 12038098Sbostic case '?': 12138098Sbostic default: 12232127Sbostic usage(); 12323101Slepreau } 12438098Sbostic argc -= optind; 12538098Sbostic argv += optind; 12638098Sbostic 12738879Skfall #ifdef KERBEROS 12838879Skfall sp = getservbyname((encrypt ? "ekshell" : "kshell"), "tcp"); 12938879Skfall if (sp == NULL) { 13038879Skfall char msgbuf[64]; 13138879Skfall use_kerberos = 0; 13238879Skfall (void) sprintf(msgbuf, "can't get entry for %s/tcp service", 13338879Skfall (encrypt ? "ekshell" : "kshell")); 13438879Skfall old_warning(msgbuf); 13538879Skfall sp = getservbyname("shell", "tcp"); 13638879Skfall } 13738879Skfall #else 13838879Skfall sp = getservbyname("shell", "tcp"); 13938879Skfall #endif 14038879Skfall if (sp == NULL) { 14138879Skfall (void)fprintf(stderr, "rcp: shell/tcp: unknown service\n"); 14238879Skfall exit(1); 14338879Skfall } 14438879Skfall port = sp->s_port; 14538879Skfall 14638879Skfall if (!(pwd = getpwuid(userid = getuid()))) { 14738879Skfall (void)fprintf(stderr, "rcp: unknown user %d.\n", userid); 14838879Skfall exit(1); 14938879Skfall } 15038879Skfall 15138099Sbostic if (fflag) { 15238879Skfall /* follow "protocol", send data */ 15338099Sbostic (void)response(); 15438099Sbostic (void)setuid(userid); 15538099Sbostic source(argc, argv); 15638099Sbostic exit(errs); 15738099Sbostic } 15838099Sbostic 15938099Sbostic if (tflag) { 16038879Skfall /* receive data */ 16138099Sbostic (void)setuid(userid); 16238099Sbostic sink(argc, argv); 16338099Sbostic exit(errs); 16438099Sbostic } 16538099Sbostic 16632127Sbostic if (argc < 2) 16732127Sbostic usage(); 1686440Swnj if (argc > 2) 1696440Swnj targetshouldbedirectory = 1; 17038098Sbostic 17132127Sbostic rem = -1; 17238879Skfall /* command to be executed on remote system using "rsh" */ 17338879Skfall #ifdef KERBEROS 17438879Skfall (void)sprintf(cmd, "rcp%s%s%s%s", iamrecursive ? " -r" : "", 17538879Skfall ((encrypt && use_kerberos) ? " -x" : ""), 17638879Skfall pflag ? " -p" : "", targetshouldbedirectory ? " -d" : ""); 17738879Skfall #else 17838098Sbostic (void)sprintf(cmd, "rcp%s%s%s", iamrecursive ? " -r" : "", 17938098Sbostic pflag ? " -p" : "", targetshouldbedirectory ? " -d" : ""); 18038879Skfall #endif 18138098Sbostic 18238098Sbostic (void)signal(SIGPIPE, lostconn); 18338098Sbostic 18438098Sbostic if (targ = colon(argv[argc - 1])) 18538879Skfall toremote(targ, argc, argv); /* destination is remote host */ 18638098Sbostic else { 18738879Skfall tolocal(argc, argv); /* destination is local host */ 18838098Sbostic if (targetshouldbedirectory) 18938098Sbostic verifydir(argv[argc - 1]); 19038098Sbostic } 19138098Sbostic exit(errs); 19238098Sbostic } 19338098Sbostic 19438098Sbostic toremote(targ, argc, argv) 19538098Sbostic char *targ; 19638098Sbostic int argc; 19738098Sbostic char **argv; 19838098Sbostic { 19938098Sbostic int i; 20038100Sbostic char *bp, *host, *src, *suser, *thost, *tuser; 20138100Sbostic char *colon(), *malloc(); 20238098Sbostic 20338098Sbostic *targ++ = 0; 20438098Sbostic if (*targ == 0) 20538098Sbostic targ = "."; 20638098Sbostic 20738100Sbostic if (thost = index(argv[argc - 1], '@')) { 20838879Skfall /* user@host */ 20938098Sbostic *thost++ = 0; 21038098Sbostic tuser = argv[argc - 1]; 21138098Sbostic if (*tuser == '\0') 21224711Sbloom tuser = NULL; 21338098Sbostic else if (!okname(tuser)) 21438098Sbostic exit(1); 21538098Sbostic } else { 21638098Sbostic thost = argv[argc - 1]; 21738098Sbostic tuser = NULL; 21838098Sbostic } 21936624Skfall 22038098Sbostic for (i = 0; i < argc - 1; i++) { 22138098Sbostic src = colon(argv[i]); 22238098Sbostic if (src) { /* remote to remote */ 22338098Sbostic *src++ = 0; 22438098Sbostic if (*src == 0) 22538098Sbostic src = "."; 22638098Sbostic host = index(argv[i], '@'); 22738100Sbostic if (!(bp = malloc((u_int)(strlen(_PATH_RSH) + 22838100Sbostic strlen(argv[i]) + strlen(src) + 22938469Sbostic tuser ? strlen(tuser) : 0 + strlen(thost) + 23038100Sbostic strlen(targ)) + CMDNEEDS + 20))) 23138100Sbostic nospace(); 23238098Sbostic if (host) { 23338098Sbostic *host++ = 0; 23438098Sbostic suser = argv[i]; 23538098Sbostic if (*suser == '\0') 23638098Sbostic suser = pwd->pw_name; 23738098Sbostic else if (!okname(suser)) 23838098Sbostic continue; 23938100Sbostic (void)sprintf(bp, 24038098Sbostic "%s %s -l %s -n %s %s '%s%s%s:%s'", 24138098Sbostic _PATH_RSH, host, suser, cmd, src, 24238098Sbostic tuser ? tuser : "", tuser ? "@" : "", 24338098Sbostic thost, targ); 24438098Sbostic } else 24538100Sbostic (void)sprintf(bp, "%s %s -n %s %s '%s%s%s:%s'", 24638098Sbostic _PATH_RSH, argv[i], cmd, src, 24738098Sbostic tuser ? tuser : "", tuser ? "@" : "", 24838098Sbostic thost, targ); 24938100Sbostic (void)susystem(bp); 25038100Sbostic (void)free(bp); 25138098Sbostic } else { /* local to remote */ 25238098Sbostic if (rem == -1) { 25338100Sbostic if (!(bp = malloc((u_int)strlen(targ) + 25438100Sbostic CMDNEEDS + 20))) 25538100Sbostic nospace(); 25638100Sbostic (void)sprintf(bp, "%s -t %s", cmd, targ); 25738098Sbostic host = thost; 25838098Sbostic #ifdef KERBEROS 25938098Sbostic if (use_kerberos) 26038879Skfall rem = kerberos(&host, bp, 26138879Skfall pwd->pw_name, 26238100Sbostic tuser ? tuser : pwd->pw_name); 26338098Sbostic else 26438098Sbostic #endif 26524711Sbloom rem = rcmd(&host, port, pwd->pw_name, 26624711Sbloom tuser ? tuser : pwd->pw_name, 26738100Sbostic bp, 0); 26838098Sbostic if (rem < 0) 26938098Sbostic exit(1); 27038098Sbostic if (response() < 0) 27138098Sbostic exit(1); 27238100Sbostic (void)free(bp); 27338098Sbostic (void)setuid(userid); 2746440Swnj } 27538098Sbostic source(1, argv+i); 2766440Swnj } 27738098Sbostic } 27838098Sbostic } 27938098Sbostic 28038098Sbostic tolocal(argc, argv) 28138098Sbostic int argc; 28238098Sbostic char **argv; 28338098Sbostic { 28438098Sbostic int i; 28538100Sbostic char *bp, *host, *src, *suser; 28638100Sbostic char *colon(), *malloc(); 28738098Sbostic 28838098Sbostic for (i = 0; i < argc - 1; i++) { 28938100Sbostic if (!(src = colon(argv[i]))) { /* local to local */ 29038100Sbostic if (!(bp = malloc((u_int)(strlen(_PATH_CP) + 29138100Sbostic strlen(argv[i]) + strlen(argv[argc - 1])) + 20))) 29238100Sbostic nospace(); 29338100Sbostic (void)sprintf(bp, "%s%s%s %s %s", _PATH_CP, 29438100Sbostic iamrecursive ? " -r" : "", pflag ? " -p" : "", 29538100Sbostic argv[i], argv[argc - 1]); 29638100Sbostic (void)susystem(bp); 29738100Sbostic (void)free(bp); 29838100Sbostic continue; 29938100Sbostic } 30038100Sbostic *src++ = 0; 30138100Sbostic if (*src == 0) 30238100Sbostic src = "."; 30338100Sbostic host = index(argv[i], '@'); 30438100Sbostic if (host) { 30538100Sbostic *host++ = 0; 30638100Sbostic suser = argv[i]; 30738100Sbostic if (*suser == '\0') 30838098Sbostic suser = pwd->pw_name; 30938100Sbostic else if (!okname(suser)) 31038100Sbostic continue; 31138100Sbostic } else { 31238100Sbostic host = argv[i]; 31338100Sbostic suser = pwd->pw_name; 31438100Sbostic } 31538100Sbostic if (!(bp = malloc((u_int)(strlen(src)) + CMDNEEDS + 20))) 31638100Sbostic nospace(); 31738100Sbostic (void)sprintf(bp, "%s -f %s", cmd, src); 31838098Sbostic #ifdef KERBEROS 31938100Sbostic if (use_kerberos) 32038879Skfall rem = kerberos(&host, bp, pwd->pw_name, suser); 32138100Sbostic else 32238098Sbostic #endif 32338100Sbostic rem = rcmd(&host, port, pwd->pw_name, suser, bp, 0); 32438100Sbostic (void)free(bp); 32538100Sbostic if (rem < 0) 32638100Sbostic continue; 32738100Sbostic (void)setreuid(0, userid); 32838100Sbostic sink(1, argv + argc - 1); 32938100Sbostic (void)setreuid(userid, 0); 33038100Sbostic (void)close(rem); 33138100Sbostic rem = -1; 3326440Swnj } 3336440Swnj } 3346440Swnj 3356440Swnj verifydir(cp) 3366440Swnj char *cp; 3376440Swnj { 3386440Swnj struct stat stb; 3396440Swnj 34018126Sralph if (stat(cp, &stb) >= 0) { 34118126Sralph if ((stb.st_mode & S_IFMT) == S_IFDIR) 34218126Sralph return; 34318126Sralph errno = ENOTDIR; 34418126Sralph } 34538469Sbostic error("rcp: %s: %s.\n", cp, strerror(errno)); 3466440Swnj exit(1); 3476440Swnj } 3486440Swnj 3496440Swnj char * 3506440Swnj colon(cp) 35138098Sbostic register char *cp; 3526440Swnj { 35338098Sbostic for (; *cp; ++cp) { 3546440Swnj if (*cp == ':') 35538098Sbostic return(cp); 3566440Swnj if (*cp == '/') 35738098Sbostic return(0); 3586440Swnj } 35938098Sbostic return(0); 3606440Swnj } 3616440Swnj 3626440Swnj okname(cp0) 3636440Swnj char *cp0; 3646440Swnj { 3656440Swnj register char *cp = cp0; 3666440Swnj register int c; 3676440Swnj 3686440Swnj do { 3696440Swnj c = *cp; 3706440Swnj if (c & 0200) 3716440Swnj goto bad; 3726440Swnj if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') 3736440Swnj goto bad; 37438100Sbostic } while (*++cp); 37538098Sbostic return(1); 3766440Swnj bad: 37738100Sbostic (void)fprintf(stderr, "rcp: invalid user name %s\n", cp0); 37838098Sbostic return(0); 3796440Swnj } 3806440Swnj 38117999Sserge susystem(s) 38217999Sserge char *s; 3836440Swnj { 38417999Sserge int status, pid, w; 38538879Skfall register sig_t istat, qstat; 3866440Swnj 38717999Sserge if ((pid = vfork()) == 0) { 38838098Sbostic (void)setuid(userid); 38937037Sbostic execl(_PATH_BSHELL, "sh", "-c", s, (char *)0); 39017999Sserge _exit(127); 39117999Sserge } 39217999Sserge istat = signal(SIGINT, SIG_IGN); 39317999Sserge qstat = signal(SIGQUIT, SIG_IGN); 39417999Sserge while ((w = wait(&status)) != pid && w != -1) 39517999Sserge ; 39617999Sserge if (w == -1) 39717999Sserge status = -1; 39838098Sbostic (void)signal(SIGINT, istat); 39938098Sbostic (void)signal(SIGQUIT, qstat); 40038098Sbostic return(status); 4016440Swnj } 4026440Swnj 4036440Swnj source(argc, argv) 4046440Swnj int argc; 4056440Swnj char **argv; 4066440Swnj { 4076440Swnj struct stat stb; 40838098Sbostic static BUF buffer; 40938098Sbostic BUF *bp; 41038098Sbostic off_t i; 41132268Sbostic int x, readerr, f, amt; 41238098Sbostic char *last, *name, buf[BUFSIZ]; 41338098Sbostic BUF *allocbuf(); 4146440Swnj 4156440Swnj for (x = 0; x < argc; x++) { 4166440Swnj name = argv[x]; 41738098Sbostic if ((f = open(name, O_RDONLY, 0)) < 0) { 41838469Sbostic error("rcp: %s: %s\n", name, strerror(errno)); 4196440Swnj continue; 4206440Swnj } 4216440Swnj if (fstat(f, &stb) < 0) 4226440Swnj goto notreg; 4236440Swnj switch (stb.st_mode&S_IFMT) { 4246440Swnj 4256440Swnj case S_IFREG: 4266440Swnj break; 4276440Swnj 4286440Swnj case S_IFDIR: 4296440Swnj if (iamrecursive) { 43038098Sbostic (void)close(f); 43123101Slepreau rsource(name, &stb); 4326440Swnj continue; 4336440Swnj } 43438098Sbostic /* FALLTHROUGH */ 4356440Swnj default: 43638098Sbostic notreg: (void)close(f); 4376440Swnj error("rcp: %s: not a plain file\n", name); 4386440Swnj continue; 4396440Swnj } 4406440Swnj last = rindex(name, '/'); 4416440Swnj if (last == 0) 4426440Swnj last = name; 4436440Swnj else 4446440Swnj last++; 44523101Slepreau if (pflag) { 44623101Slepreau /* 44723101Slepreau * Make it compatible with possible future 44823101Slepreau * versions expecting microseconds. 44923101Slepreau */ 45038100Sbostic (void)sprintf(buf, "T%ld 0 %ld 0\n", stb.st_mtime, 45138100Sbostic stb.st_atime); 45238098Sbostic (void)write(rem, buf, strlen(buf)); 45323101Slepreau if (response() < 0) { 45438098Sbostic (void)close(f); 45523101Slepreau continue; 45623101Slepreau } 45723101Slepreau } 45838100Sbostic (void)sprintf(buf, "C%04o %ld %s\n", stb.st_mode&07777, 45938100Sbostic stb.st_size, last); 46038098Sbostic (void)write(rem, buf, strlen(buf)); 4616440Swnj if (response() < 0) { 46238098Sbostic (void)close(f); 4636440Swnj continue; 4646440Swnj } 46535689Sbostic if ((bp = allocbuf(&buffer, f, BUFSIZ)) == 0) { 46638098Sbostic (void)close(f); 46721254Smckusick continue; 46821254Smckusick } 46932268Sbostic readerr = 0; 47021254Smckusick for (i = 0; i < stb.st_size; i += bp->cnt) { 47121254Smckusick amt = bp->cnt; 4726440Swnj if (i + amt > stb.st_size) 4736440Swnj amt = stb.st_size - i; 47432268Sbostic if (readerr == 0 && read(f, bp->buf, amt) != amt) 47532268Sbostic readerr = errno; 47638098Sbostic (void)write(rem, bp->buf, amt); 4776440Swnj } 47838098Sbostic (void)close(f); 47932268Sbostic if (readerr == 0) 48038098Sbostic (void)write(rem, "", 1); 4816440Swnj else 48238469Sbostic error("rcp: %s: %s\n", name, strerror(readerr)); 48338098Sbostic (void)response(); 4846440Swnj } 4856440Swnj } 4866440Swnj 48723101Slepreau rsource(name, statp) 4886440Swnj char *name; 48923101Slepreau struct stat *statp; 4906440Swnj { 49138098Sbostic DIR *d; 4926440Swnj struct direct *dp; 49338100Sbostic char *last, *vect[1], path[MAXPATHLEN]; 4946440Swnj 49538098Sbostic if (!(d = opendir(name))) { 49638469Sbostic error("rcp: %s: %s\n", name, strerror(errno)); 4976440Swnj return; 4986440Swnj } 4996440Swnj last = rindex(name, '/'); 5006440Swnj if (last == 0) 5016440Swnj last = name; 5026440Swnj else 5036440Swnj last++; 50423101Slepreau if (pflag) { 50538100Sbostic (void)sprintf(path, "T%ld 0 %ld 0\n", statp->st_mtime, 50638100Sbostic statp->st_atime); 50738100Sbostic (void)write(rem, path, strlen(path)); 50823101Slepreau if (response() < 0) { 50923101Slepreau closedir(d); 51023101Slepreau return; 51123101Slepreau } 51223101Slepreau } 51338100Sbostic (void)sprintf(path, "D%04o %d %s\n", statp->st_mode&07777, 0, last); 51438100Sbostic (void)write(rem, path, strlen(path)); 5156440Swnj if (response() < 0) { 5166440Swnj closedir(d); 5176440Swnj return; 5186440Swnj } 5196440Swnj while (dp = readdir(d)) { 5206440Swnj if (dp->d_ino == 0) 5216440Swnj continue; 5226440Swnj if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 5236440Swnj continue; 52438100Sbostic if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) { 52538100Sbostic error("%s/%s: name too long.\n", name, dp->d_name); 5266440Swnj continue; 5276440Swnj } 52838100Sbostic (void)sprintf(path, "%s/%s", name, dp->d_name); 52938100Sbostic vect[0] = path; 53038100Sbostic source(1, vect); 5316440Swnj } 5326440Swnj closedir(d); 53338098Sbostic (void)write(rem, "E\n", 2); 53438098Sbostic (void)response(); 5356440Swnj } 5366440Swnj 5376440Swnj response() 5386440Swnj { 53938098Sbostic register char *cp; 54038098Sbostic char ch, resp, rbuf[BUFSIZ]; 5416440Swnj 54238098Sbostic if (read(rem, &resp, sizeof(resp)) != sizeof(resp)) 5436440Swnj lostconn(); 5446440Swnj 54538098Sbostic cp = rbuf; 54638098Sbostic switch(resp) { 54723101Slepreau case 0: /* ok */ 54838098Sbostic return(0); 5496440Swnj default: 5506440Swnj *cp++ = resp; 55138098Sbostic /* FALLTHROUGH */ 55223101Slepreau case 1: /* error, followed by err msg */ 55323101Slepreau case 2: /* fatal error, "" */ 5546440Swnj do { 55538098Sbostic if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) 5566440Swnj lostconn(); 55738098Sbostic *cp++ = ch; 55838098Sbostic } while (cp < &rbuf[BUFSIZ] && ch != '\n'); 55938098Sbostic 56038098Sbostic if (!iamremote) 56138098Sbostic (void)write(2, rbuf, cp - rbuf); 56238098Sbostic ++errs; 5636440Swnj if (resp == 1) 56438098Sbostic return(-1); 5656440Swnj exit(1); 5666440Swnj } 5676440Swnj /*NOTREACHED*/ 5686440Swnj } 5696440Swnj 5706440Swnj lostconn() 5716440Swnj { 57238098Sbostic if (!iamremote) 57338098Sbostic (void)fprintf(stderr, "rcp: lost connection\n"); 5746440Swnj exit(1); 5756440Swnj } 5766440Swnj 5776440Swnj sink(argc, argv) 5786440Swnj int argc; 5796440Swnj char **argv; 5806440Swnj { 58138100Sbostic register char *cp; 58238098Sbostic static BUF buffer; 58321254Smckusick struct stat stb; 58423101Slepreau struct timeval tv[2]; 58538469Sbostic enum { YES, NO, DISPLAYED } wrerr; 58638100Sbostic BUF *bp, *allocbuf(); 58738100Sbostic off_t i, j; 58838100Sbostic char ch, *targ, *why; 58938100Sbostic int amt, count, exists, first, mask, mode; 59038469Sbostic int ofd, setimes, size, targisdir; 59138100Sbostic char *np, *vect[1], buf[BUFSIZ], *malloc(); 5926440Swnj 59338100Sbostic #define atime tv[0] 59438100Sbostic #define mtime tv[1] 59538100Sbostic #define SCREWUP(str) { why = str; goto screwup; } 59638100Sbostic 59738100Sbostic setimes = targisdir = 0; 59838100Sbostic mask = umask(0); 59923112Slepreau if (!pflag) 60038098Sbostic (void)umask(mask); 60118126Sralph if (argc != 1) { 6026440Swnj error("rcp: ambiguous target\n"); 6036440Swnj exit(1); 6046440Swnj } 6056440Swnj targ = *argv; 6066440Swnj if (targetshouldbedirectory) 6076440Swnj verifydir(targ); 60838098Sbostic (void)write(rem, "", 1); 6096440Swnj if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR) 6106440Swnj targisdir = 1; 61138100Sbostic for (first = 1;; first = 0) { 61238100Sbostic cp = buf; 6136440Swnj if (read(rem, cp, 1) <= 0) 6146440Swnj return; 6156440Swnj if (*cp++ == '\n') 61638100Sbostic SCREWUP("unexpected <newline>"); 6176440Swnj do { 61838100Sbostic if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) 6196440Swnj SCREWUP("lost connection"); 62038100Sbostic *cp++ = ch; 62138100Sbostic } while (cp < &buf[BUFSIZ - 1] && ch != '\n'); 6226440Swnj *cp = 0; 62338100Sbostic 62438100Sbostic if (buf[0] == '\01' || buf[0] == '\02') { 6256440Swnj if (iamremote == 0) 62638100Sbostic (void)write(2, buf + 1, strlen(buf + 1)); 62738100Sbostic if (buf[0] == '\02') 6286440Swnj exit(1); 6296440Swnj errs++; 6306440Swnj continue; 6316440Swnj } 63238100Sbostic if (buf[0] == 'E') { 63338098Sbostic (void)write(rem, "", 1); 6346440Swnj return; 6356440Swnj } 63623101Slepreau 63738108Sbostic if (ch == '\n') 63838115Sbostic *--cp = 0; 63938108Sbostic 64023101Slepreau #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0'); 64138100Sbostic cp = buf; 64223101Slepreau if (*cp == 'T') { 64323101Slepreau setimes++; 64423101Slepreau cp++; 64523101Slepreau getnum(mtime.tv_sec); 64623101Slepreau if (*cp++ != ' ') 64723101Slepreau SCREWUP("mtime.sec not delimited"); 64823101Slepreau getnum(mtime.tv_usec); 64923101Slepreau if (*cp++ != ' ') 65023101Slepreau SCREWUP("mtime.usec not delimited"); 65123101Slepreau getnum(atime.tv_sec); 65223101Slepreau if (*cp++ != ' ') 65323101Slepreau SCREWUP("atime.sec not delimited"); 65423101Slepreau getnum(atime.tv_usec); 65523101Slepreau if (*cp++ != '\0') 65623101Slepreau SCREWUP("atime.usec not delimited"); 65738098Sbostic (void)write(rem, "", 1); 65823101Slepreau continue; 65923101Slepreau } 66014580Sralph if (*cp != 'C' && *cp != 'D') { 66114580Sralph /* 66214580Sralph * Check for the case "rcp remote:foo\* local:bar". 66314580Sralph * In this case, the line "No match." can be returned 66414580Sralph * by the shell before the rcp command on the remote is 66514580Sralph * executed so the ^Aerror_message convention isn't 66614580Sralph * followed. 66714580Sralph */ 66814580Sralph if (first) { 66914580Sralph error("%s\n", cp); 67014580Sralph exit(1); 67114580Sralph } 6726440Swnj SCREWUP("expected control record"); 67314580Sralph } 6746440Swnj mode = 0; 67538100Sbostic for (++cp; cp < buf + 5; cp++) { 6766440Swnj if (*cp < '0' || *cp > '7') 6776440Swnj SCREWUP("bad mode"); 6786440Swnj mode = (mode << 3) | (*cp - '0'); 6796440Swnj } 6806440Swnj if (*cp++ != ' ') 6816440Swnj SCREWUP("mode not delimited"); 6826440Swnj size = 0; 68323112Slepreau while (isdigit(*cp)) 6846440Swnj size = size * 10 + (*cp++ - '0'); 6856440Swnj if (*cp++ != ' ') 6866440Swnj SCREWUP("size not delimited"); 68738100Sbostic if (targisdir) { 68838100Sbostic static char *namebuf; 68938100Sbostic static int cursize; 69038100Sbostic int need; 69138100Sbostic 69238100Sbostic need = strlen(targ) + strlen(cp) + 250; 69338100Sbostic if (need > cursize) { 69438100Sbostic if (!(namebuf = malloc((u_int)need))) 69538108Sbostic error("out of memory\n"); 69638100Sbostic } 69738100Sbostic (void)sprintf(namebuf, "%s%s%s", targ, 6986440Swnj *targ ? "/" : "", cp); 69938100Sbostic np = namebuf; 70038100Sbostic } 7016440Swnj else 70238100Sbostic np = targ; 70338100Sbostic exists = stat(np, &stb) == 0; 70438100Sbostic if (buf[0] == 'D') { 70518126Sralph if (exists) { 7066440Swnj if ((stb.st_mode&S_IFMT) != S_IFDIR) { 7076440Swnj errno = ENOTDIR; 7086440Swnj goto bad; 7096440Swnj } 71023112Slepreau if (pflag) 71138100Sbostic (void)chmod(np, mode); 71238100Sbostic } else if (mkdir(np, mode) < 0) 7136440Swnj goto bad; 71438100Sbostic vect[0] = np; 71538100Sbostic sink(1, vect); 71623101Slepreau if (setimes) { 71723101Slepreau setimes = 0; 71838100Sbostic if (utimes(np, tv) < 0) 71938100Sbostic error("rcp: can't set times on %s: %s\n", 72038469Sbostic np, strerror(errno)); 72123101Slepreau } 7226440Swnj continue; 72318126Sralph } 72438100Sbostic if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { 72538469Sbostic bad: error("rcp: %s: %s\n", np, strerror(errno)); 7266440Swnj continue; 7276440Swnj } 72823112Slepreau if (exists && pflag) 72938100Sbostic (void)fchmod(ofd, mode); 73038098Sbostic (void)write(rem, "", 1); 73138100Sbostic if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == 0) { 73238100Sbostic (void)close(ofd); 73321254Smckusick continue; 73421254Smckusick } 73521254Smckusick cp = bp->buf; 73621254Smckusick count = 0; 73738469Sbostic wrerr = NO; 7386440Swnj for (i = 0; i < size; i += BUFSIZ) { 73921254Smckusick amt = BUFSIZ; 7406440Swnj if (i + amt > size) 7416440Swnj amt = size - i; 74221254Smckusick count += amt; 7436440Swnj do { 74421254Smckusick j = read(rem, cp, amt); 74524711Sbloom if (j <= 0) { 74638108Sbostic error("rcp: %s\n", 74738469Sbostic j ? strerror(errno) : 74838100Sbostic "dropped connection"); 7496440Swnj exit(1); 75024711Sbloom } 7516440Swnj amt -= j; 7526440Swnj cp += j; 7536440Swnj } while (amt > 0); 75421254Smckusick if (count == bp->cnt) { 75538469Sbostic if (wrerr == NO && 75638100Sbostic write(ofd, bp->buf, count) != count) 75738469Sbostic wrerr = YES; 75821254Smckusick count = 0; 75921254Smckusick cp = bp->buf; 76021254Smckusick } 7616440Swnj } 76238469Sbostic if (count != 0 && wrerr == NO && 76338100Sbostic write(ofd, bp->buf, count) != count) 76438469Sbostic wrerr = YES; 76538469Sbostic if (ftruncate(ofd, size)) { 76638100Sbostic error("rcp: can't truncate %s: %s\n", np, 76738469Sbostic strerror(errno)); 76838469Sbostic wrerr = DISPLAYED; 76938469Sbostic } 77038100Sbostic (void)close(ofd); 77138098Sbostic (void)response(); 77238469Sbostic if (setimes && wrerr == NO) { 77323101Slepreau setimes = 0; 77438469Sbostic if (utimes(np, tv) < 0) { 77523101Slepreau error("rcp: can't set times on %s: %s\n", 77638469Sbostic np, strerror(errno)); 77738469Sbostic wrerr = DISPLAYED; 77838469Sbostic } 77938469Sbostic } 78038469Sbostic switch(wrerr) { 78138469Sbostic case YES: 78238469Sbostic error("rcp: %s: %s\n", np, strerror(errno)); 78338469Sbostic break; 78438469Sbostic case NO: 78538098Sbostic (void)write(rem, "", 1); 78638469Sbostic break; 78738469Sbostic case DISPLAYED: 78838469Sbostic break; 78938469Sbostic } 7906440Swnj } 7916440Swnj screwup: 79238100Sbostic error("rcp: protocol screwup: %s\n", why); 7936440Swnj exit(1); 7946440Swnj } 7956440Swnj 79638098Sbostic BUF * 79721254Smckusick allocbuf(bp, fd, blksize) 79838098Sbostic BUF *bp; 79921254Smckusick int fd, blksize; 80021254Smckusick { 80121254Smckusick struct stat stb; 80221254Smckusick int size; 80338098Sbostic char *malloc(); 80421254Smckusick 80521254Smckusick if (fstat(fd, &stb) < 0) { 80638469Sbostic error("rcp: fstat: %s\n", strerror(errno)); 80738098Sbostic return(0); 80821254Smckusick } 80921254Smckusick size = roundup(stb.st_blksize, blksize); 81021254Smckusick if (size == 0) 81121254Smckusick size = blksize; 81221254Smckusick if (bp->cnt < size) { 81321254Smckusick if (bp->buf != 0) 81421254Smckusick free(bp->buf); 81538098Sbostic bp->buf = (char *)malloc((u_int)size); 81638100Sbostic if (!bp->buf) { 81721254Smckusick error("rcp: malloc: out of memory\n"); 81838098Sbostic return(0); 81921254Smckusick } 82021254Smckusick } 82121254Smckusick bp->cnt = size; 82238098Sbostic return(bp); 82321254Smckusick } 82421254Smckusick 82538098Sbostic /* VARARGS1 */ 82638100Sbostic error(fmt, a1, a2, a3) 8276440Swnj char *fmt; 82838100Sbostic int a1, a2, a3; 8296440Swnj { 83038108Sbostic static FILE *fp; 8316440Swnj 83238098Sbostic ++errs; 83338108Sbostic if (!fp && !(fp = fdopen(rem, "w"))) 83438108Sbostic return; 83538108Sbostic (void)fprintf(fp, "%c", 0x01); 83638108Sbostic (void)fprintf(fp, fmt, a1, a2, a3); 83738108Sbostic (void)fflush(fp); 83838098Sbostic if (!iamremote) 83938108Sbostic (void)fprintf(stderr, fmt, a1, a2, a3); 8406440Swnj } 84132127Sbostic 84238100Sbostic nospace() 84338100Sbostic { 84438100Sbostic (void)fprintf(stderr, "rcp: out of memory.\n"); 84538100Sbostic exit(1); 84638100Sbostic } 84738100Sbostic 84838100Sbostic 84932127Sbostic usage() 85032127Sbostic { 85138098Sbostic #ifdef KERBEROS 85238098Sbostic (void)fprintf(stderr, "%s\n\t%s\n", 85338098Sbostic "usage: rcp [-k realm] [-px] f1 f2", 85438098Sbostic "or: rcp [-k realm] [-rpx] f1 ... fn directory"); 85536626Skfall #else 85638098Sbostic (void)fprintf(stderr, 85738098Sbostic "usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn directory\n"); 85836626Skfall #endif 85932127Sbostic exit(1); 86032127Sbostic } 86138879Skfall 86238879Skfall #ifdef KERBEROS 86338879Skfall old_warning(str) 86438879Skfall char *str; 86538879Skfall { 86638879Skfall (void)fprintf(stderr, "rcp: warning: %s, using standard rcp\n", str); 86738879Skfall } 86838879Skfall 86938879Skfall int 87038879Skfall kerberos(host, bp, locuser, user) 87138879Skfall 87238879Skfall char **host, *bp, *locuser, *user; 87338879Skfall { 87438879Skfall struct servent *sp; 87538879Skfall 87638879Skfall again: 87738879Skfall if (use_kerberos) { 87838879Skfall rem = KSUCCESS; 87938879Skfall errno = 0; 88038879Skfall if (dest_realm == NULL) 88138879Skfall dest_realm = krb_realmofhost(*host); 88238879Skfall 88338879Skfall if (encrypt) 88438879Skfall rem = krcmd_mutual( 88538879Skfall host, port, 88638879Skfall user, bp, 0, 88738879Skfall dest_realm, 88838879Skfall &cred, schedule); 88938879Skfall else 89038879Skfall rem = krcmd( 89138879Skfall host, port, 89238879Skfall user, bp, 0, dest_realm); 89338879Skfall 89438879Skfall if (rem < 0) { 89538879Skfall use_kerberos = 0; 89638879Skfall sp = getservbyname("shell", "tcp"); 89738879Skfall if (sp == NULL) { 89838879Skfall (void)fprintf(stderr, 89938879Skfall "rcp: unknown service shell/tcp\n"); 90038879Skfall exit(1); 90138879Skfall } 90238879Skfall if (errno == ECONNREFUSED) 90338879Skfall old_warning( 90438879Skfall "remote host doesn't support Kerberos"); 90538879Skfall 90638879Skfall if (errno == ENOENT) 90738879Skfall old_warning( 90838879Skfall "Can't provide Kerberos auth data"); 90938879Skfall port = sp->s_port; 91038879Skfall goto again; 91138879Skfall } 91238879Skfall } else { 91338879Skfall if (encrypt) { 91438879Skfall fprintf(stderr, 91538879Skfall "The -x option requires Kerberos authentication\n"); 91638879Skfall exit(1); 91738879Skfall } 91838879Skfall rem = rcmd(host, sp->s_port, locuser, user, bp, 0); 91938879Skfall } 92038879Skfall return(rem); 92138879Skfall } 92238879Skfall #endif /* KERBEROS */ 923