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*41785Sbostic static char sccsid[] = "@(#)rcp.c 5.24 (Berkeley) 05/12/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> 4238098Sbostic #include <strings.h> 4338098Sbostic #include <stdio.h> 4438098Sbostic #include <ctype.h> 4537037Sbostic #include "pathnames.h" 4612989Ssam 4738098Sbostic #ifdef KERBEROS 48*41785Sbostic #include <kerberosIV/krb.h> 4938879Skfall char dst_realm_buf[REALM_SZ]; 5038879Skfall char *dest_realm = NULL; 5138879Skfall int use_kerberos = 1, encrypt = 0; 5238879Skfall CREDENTIALS cred; 5338879Skfall Key_schedule schedule; 5438879Skfall extern char *krb_realmofhost(); 5538879Skfall #define OPTIONS "dfkprtx" 5638879Skfall #else 5738879Skfall #define OPTIONS "dfprt" 5836624Skfall #endif 5936624Skfall 6038098Sbostic extern int errno; 6138098Sbostic struct passwd *pwd; 6238879Skfall u_short port; 6338879Skfall uid_t userid; 6438879Skfall int errs, rem; 6538879Skfall int pflag, iamremote, iamrecursive, targetshouldbedirectory; 666440Swnj 6738879Skfall #define CMDNEEDS 64 6838100Sbostic char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ 6938098Sbostic 7038098Sbostic typedef struct _buf { 7121254Smckusick int cnt; 7221254Smckusick char *buf; 7338098Sbostic } BUF; 7421254Smckusick 756440Swnj main(argc, argv) 766440Swnj int argc; 776440Swnj char **argv; 786440Swnj { 7938098Sbostic extern int optind; 8018126Sralph struct servent *sp; 8138099Sbostic int ch, fflag, tflag; 8238098Sbostic char *targ, *colon(); 8338098Sbostic struct passwd *getpwuid(); 8438098Sbostic int lostconn(); 8518026Sralph 8638099Sbostic fflag = tflag = 0; 8738879Skfall while ((ch = getopt(argc, argv, OPTIONS)) != EOF) 8838098Sbostic switch(ch) { 8938879Skfall /* user-visible flags */ 9038098Sbostic case 'p': /* preserve access/mod times */ 9138098Sbostic ++pflag; 9223101Slepreau break; 9338098Sbostic case 'r': 9438098Sbostic ++iamrecursive; 9523101Slepreau break; 9638879Skfall #ifdef KERBEROS 9738879Skfall case 'k': 9838879Skfall strncpy(dst_realm_buf, ++argv, REALM_SZ); 9938879Skfall dest_realm = dst_realm_buf; 10038099Sbostic break; 10138098Sbostic case 'x': 10238098Sbostic encrypt = 1; 10338879Skfall /* des_set_key(cred.session, schedule); */ 10438098Sbostic break; 10538098Sbostic #endif 10638879Skfall /* rshd-invoked options (server) */ 10738879Skfall case 'd': 10838879Skfall targetshouldbedirectory = 1; 10938879Skfall break; 11038879Skfall case 'f': /* "from" */ 11138879Skfall iamremote = 1; 11238879Skfall fflag = 1; 11338879Skfall break; 11438879Skfall case 't': /* "to" */ 11538879Skfall iamremote = 1; 11638879Skfall tflag = 1; 11738879Skfall break; 11838879Skfall 11938098Sbostic case '?': 12038098Sbostic default: 12132127Sbostic usage(); 12223101Slepreau } 12338098Sbostic argc -= optind; 12438098Sbostic argv += optind; 12538098Sbostic 12638879Skfall #ifdef KERBEROS 12738879Skfall sp = getservbyname((encrypt ? "ekshell" : "kshell"), "tcp"); 12838879Skfall if (sp == NULL) { 12938879Skfall char msgbuf[64]; 13038879Skfall use_kerberos = 0; 13138879Skfall (void) sprintf(msgbuf, "can't get entry for %s/tcp service", 13238879Skfall (encrypt ? "ekshell" : "kshell")); 13338879Skfall old_warning(msgbuf); 13438879Skfall sp = getservbyname("shell", "tcp"); 13538879Skfall } 13638879Skfall #else 13738879Skfall sp = getservbyname("shell", "tcp"); 13838879Skfall #endif 13938879Skfall if (sp == NULL) { 14038879Skfall (void)fprintf(stderr, "rcp: shell/tcp: unknown service\n"); 14138879Skfall exit(1); 14238879Skfall } 14338879Skfall port = sp->s_port; 14438879Skfall 14538879Skfall if (!(pwd = getpwuid(userid = getuid()))) { 14638879Skfall (void)fprintf(stderr, "rcp: unknown user %d.\n", userid); 14738879Skfall exit(1); 14838879Skfall } 14938879Skfall 15038099Sbostic if (fflag) { 15138879Skfall /* follow "protocol", send data */ 15238099Sbostic (void)response(); 15338099Sbostic (void)setuid(userid); 15438099Sbostic source(argc, argv); 15538099Sbostic exit(errs); 15638099Sbostic } 15738099Sbostic 15838099Sbostic if (tflag) { 15938879Skfall /* receive data */ 16038099Sbostic (void)setuid(userid); 16138099Sbostic sink(argc, argv); 16238099Sbostic exit(errs); 16338099Sbostic } 16438099Sbostic 16532127Sbostic if (argc < 2) 16632127Sbostic usage(); 1676440Swnj if (argc > 2) 1686440Swnj targetshouldbedirectory = 1; 16938098Sbostic 17032127Sbostic rem = -1; 17138879Skfall /* command to be executed on remote system using "rsh" */ 17238879Skfall #ifdef KERBEROS 17338879Skfall (void)sprintf(cmd, "rcp%s%s%s%s", iamrecursive ? " -r" : "", 17438879Skfall ((encrypt && use_kerberos) ? " -x" : ""), 17538879Skfall pflag ? " -p" : "", targetshouldbedirectory ? " -d" : ""); 17638879Skfall #else 17738098Sbostic (void)sprintf(cmd, "rcp%s%s%s", iamrecursive ? " -r" : "", 17838098Sbostic pflag ? " -p" : "", targetshouldbedirectory ? " -d" : ""); 17938879Skfall #endif 18038098Sbostic 18138098Sbostic (void)signal(SIGPIPE, lostconn); 18238098Sbostic 18338098Sbostic if (targ = colon(argv[argc - 1])) 18438879Skfall toremote(targ, argc, argv); /* destination is remote host */ 18538098Sbostic else { 18638879Skfall tolocal(argc, argv); /* destination is local host */ 18738098Sbostic if (targetshouldbedirectory) 18838098Sbostic verifydir(argv[argc - 1]); 18938098Sbostic } 19038098Sbostic exit(errs); 19138098Sbostic } 19238098Sbostic 19338098Sbostic toremote(targ, argc, argv) 19438098Sbostic char *targ; 19538098Sbostic int argc; 19638098Sbostic char **argv; 19738098Sbostic { 19838098Sbostic int i; 19938100Sbostic char *bp, *host, *src, *suser, *thost, *tuser; 20038100Sbostic char *colon(), *malloc(); 20138098Sbostic 20238098Sbostic *targ++ = 0; 20338098Sbostic if (*targ == 0) 20438098Sbostic targ = "."; 20538098Sbostic 20638100Sbostic if (thost = index(argv[argc - 1], '@')) { 20738879Skfall /* user@host */ 20838098Sbostic *thost++ = 0; 20938098Sbostic tuser = argv[argc - 1]; 21038098Sbostic if (*tuser == '\0') 21124711Sbloom tuser = NULL; 21238098Sbostic else if (!okname(tuser)) 21338098Sbostic exit(1); 21438098Sbostic } else { 21538098Sbostic thost = argv[argc - 1]; 21638098Sbostic tuser = NULL; 21738098Sbostic } 21836624Skfall 21938098Sbostic for (i = 0; i < argc - 1; i++) { 22038098Sbostic src = colon(argv[i]); 22138098Sbostic if (src) { /* remote to remote */ 22238098Sbostic *src++ = 0; 22338098Sbostic if (*src == 0) 22438098Sbostic src = "."; 22538098Sbostic host = index(argv[i], '@'); 22638100Sbostic if (!(bp = malloc((u_int)(strlen(_PATH_RSH) + 22738100Sbostic strlen(argv[i]) + strlen(src) + 22838469Sbostic tuser ? strlen(tuser) : 0 + strlen(thost) + 22938100Sbostic strlen(targ)) + CMDNEEDS + 20))) 23038100Sbostic nospace(); 23138098Sbostic if (host) { 23238098Sbostic *host++ = 0; 23338098Sbostic suser = argv[i]; 23438098Sbostic if (*suser == '\0') 23538098Sbostic suser = pwd->pw_name; 23638098Sbostic else if (!okname(suser)) 23738098Sbostic continue; 23838100Sbostic (void)sprintf(bp, 23938098Sbostic "%s %s -l %s -n %s %s '%s%s%s:%s'", 24038098Sbostic _PATH_RSH, host, suser, cmd, src, 24138098Sbostic tuser ? tuser : "", tuser ? "@" : "", 24238098Sbostic thost, targ); 24338098Sbostic } else 24438100Sbostic (void)sprintf(bp, "%s %s -n %s %s '%s%s%s:%s'", 24538098Sbostic _PATH_RSH, argv[i], cmd, src, 24638098Sbostic tuser ? tuser : "", tuser ? "@" : "", 24738098Sbostic thost, targ); 24838100Sbostic (void)susystem(bp); 24938100Sbostic (void)free(bp); 25038098Sbostic } else { /* local to remote */ 25138098Sbostic if (rem == -1) { 25238100Sbostic if (!(bp = malloc((u_int)strlen(targ) + 25338100Sbostic CMDNEEDS + 20))) 25438100Sbostic nospace(); 25538100Sbostic (void)sprintf(bp, "%s -t %s", cmd, targ); 25638098Sbostic host = thost; 25738098Sbostic #ifdef KERBEROS 25838098Sbostic if (use_kerberos) 25938879Skfall rem = kerberos(&host, bp, 26038879Skfall pwd->pw_name, 26138100Sbostic tuser ? tuser : pwd->pw_name); 26238098Sbostic else 26338098Sbostic #endif 26424711Sbloom rem = rcmd(&host, port, pwd->pw_name, 26524711Sbloom tuser ? tuser : pwd->pw_name, 26638100Sbostic bp, 0); 26738098Sbostic if (rem < 0) 26838098Sbostic exit(1); 26938098Sbostic if (response() < 0) 27038098Sbostic exit(1); 27138100Sbostic (void)free(bp); 27238098Sbostic (void)setuid(userid); 2736440Swnj } 27438098Sbostic source(1, argv+i); 2756440Swnj } 27638098Sbostic } 27738098Sbostic } 27838098Sbostic 27938098Sbostic tolocal(argc, argv) 28038098Sbostic int argc; 28138098Sbostic char **argv; 28238098Sbostic { 28338098Sbostic int i; 28438100Sbostic char *bp, *host, *src, *suser; 28538100Sbostic char *colon(), *malloc(); 28638098Sbostic 28738098Sbostic for (i = 0; i < argc - 1; i++) { 28838100Sbostic if (!(src = colon(argv[i]))) { /* local to local */ 28938100Sbostic if (!(bp = malloc((u_int)(strlen(_PATH_CP) + 29038100Sbostic strlen(argv[i]) + strlen(argv[argc - 1])) + 20))) 29138100Sbostic nospace(); 29238100Sbostic (void)sprintf(bp, "%s%s%s %s %s", _PATH_CP, 29338100Sbostic iamrecursive ? " -r" : "", pflag ? " -p" : "", 29438100Sbostic argv[i], argv[argc - 1]); 29538100Sbostic (void)susystem(bp); 29638100Sbostic (void)free(bp); 29738100Sbostic continue; 29838100Sbostic } 29938100Sbostic *src++ = 0; 30038100Sbostic if (*src == 0) 30138100Sbostic src = "."; 30238100Sbostic host = index(argv[i], '@'); 30338100Sbostic if (host) { 30438100Sbostic *host++ = 0; 30538100Sbostic suser = argv[i]; 30638100Sbostic if (*suser == '\0') 30738098Sbostic suser = pwd->pw_name; 30838100Sbostic else if (!okname(suser)) 30938100Sbostic continue; 31038100Sbostic } else { 31138100Sbostic host = argv[i]; 31238100Sbostic suser = pwd->pw_name; 31338100Sbostic } 31438100Sbostic if (!(bp = malloc((u_int)(strlen(src)) + CMDNEEDS + 20))) 31538100Sbostic nospace(); 31638100Sbostic (void)sprintf(bp, "%s -f %s", cmd, src); 31738098Sbostic #ifdef KERBEROS 31838100Sbostic if (use_kerberos) 31938879Skfall rem = kerberos(&host, bp, pwd->pw_name, suser); 32038100Sbostic else 32138098Sbostic #endif 32238100Sbostic rem = rcmd(&host, port, pwd->pw_name, suser, bp, 0); 32338100Sbostic (void)free(bp); 32438100Sbostic if (rem < 0) 32538100Sbostic continue; 32638100Sbostic (void)setreuid(0, userid); 32738100Sbostic sink(1, argv + argc - 1); 32838100Sbostic (void)setreuid(userid, 0); 32938100Sbostic (void)close(rem); 33038100Sbostic rem = -1; 3316440Swnj } 3326440Swnj } 3336440Swnj 3346440Swnj verifydir(cp) 3356440Swnj char *cp; 3366440Swnj { 3376440Swnj struct stat stb; 3386440Swnj 33918126Sralph if (stat(cp, &stb) >= 0) { 34018126Sralph if ((stb.st_mode & S_IFMT) == S_IFDIR) 34118126Sralph return; 34218126Sralph errno = ENOTDIR; 34318126Sralph } 34438469Sbostic error("rcp: %s: %s.\n", cp, strerror(errno)); 3456440Swnj exit(1); 3466440Swnj } 3476440Swnj 3486440Swnj char * 3496440Swnj colon(cp) 35038098Sbostic register char *cp; 3516440Swnj { 35238098Sbostic for (; *cp; ++cp) { 3536440Swnj if (*cp == ':') 35438098Sbostic return(cp); 3556440Swnj if (*cp == '/') 35638098Sbostic return(0); 3576440Swnj } 35838098Sbostic return(0); 3596440Swnj } 3606440Swnj 3616440Swnj okname(cp0) 3626440Swnj char *cp0; 3636440Swnj { 3646440Swnj register char *cp = cp0; 3656440Swnj register int c; 3666440Swnj 3676440Swnj do { 3686440Swnj c = *cp; 3696440Swnj if (c & 0200) 3706440Swnj goto bad; 3716440Swnj if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') 3726440Swnj goto bad; 37338100Sbostic } while (*++cp); 37438098Sbostic return(1); 3756440Swnj bad: 37638100Sbostic (void)fprintf(stderr, "rcp: invalid user name %s\n", cp0); 37738098Sbostic return(0); 3786440Swnj } 3796440Swnj 38017999Sserge susystem(s) 38117999Sserge char *s; 3826440Swnj { 38317999Sserge int status, pid, w; 38438879Skfall register sig_t istat, qstat; 3856440Swnj 38617999Sserge if ((pid = vfork()) == 0) { 38738098Sbostic (void)setuid(userid); 38837037Sbostic execl(_PATH_BSHELL, "sh", "-c", s, (char *)0); 38917999Sserge _exit(127); 39017999Sserge } 39117999Sserge istat = signal(SIGINT, SIG_IGN); 39217999Sserge qstat = signal(SIGQUIT, SIG_IGN); 39317999Sserge while ((w = wait(&status)) != pid && w != -1) 39417999Sserge ; 39517999Sserge if (w == -1) 39617999Sserge status = -1; 39738098Sbostic (void)signal(SIGINT, istat); 39838098Sbostic (void)signal(SIGQUIT, qstat); 39938098Sbostic return(status); 4006440Swnj } 4016440Swnj 4026440Swnj source(argc, argv) 4036440Swnj int argc; 4046440Swnj char **argv; 4056440Swnj { 4066440Swnj struct stat stb; 40738098Sbostic static BUF buffer; 40838098Sbostic BUF *bp; 40938098Sbostic off_t i; 41032268Sbostic int x, readerr, f, amt; 41138098Sbostic char *last, *name, buf[BUFSIZ]; 41238098Sbostic BUF *allocbuf(); 4136440Swnj 4146440Swnj for (x = 0; x < argc; x++) { 4156440Swnj name = argv[x]; 41638098Sbostic if ((f = open(name, O_RDONLY, 0)) < 0) { 41738469Sbostic error("rcp: %s: %s\n", name, strerror(errno)); 4186440Swnj continue; 4196440Swnj } 4206440Swnj if (fstat(f, &stb) < 0) 4216440Swnj goto notreg; 4226440Swnj switch (stb.st_mode&S_IFMT) { 4236440Swnj 4246440Swnj case S_IFREG: 4256440Swnj break; 4266440Swnj 4276440Swnj case S_IFDIR: 4286440Swnj if (iamrecursive) { 42938098Sbostic (void)close(f); 43023101Slepreau rsource(name, &stb); 4316440Swnj continue; 4326440Swnj } 43338098Sbostic /* FALLTHROUGH */ 4346440Swnj default: 43538098Sbostic notreg: (void)close(f); 4366440Swnj error("rcp: %s: not a plain file\n", name); 4376440Swnj continue; 4386440Swnj } 4396440Swnj last = rindex(name, '/'); 4406440Swnj if (last == 0) 4416440Swnj last = name; 4426440Swnj else 4436440Swnj last++; 44423101Slepreau if (pflag) { 44523101Slepreau /* 44623101Slepreau * Make it compatible with possible future 44723101Slepreau * versions expecting microseconds. 44823101Slepreau */ 44938100Sbostic (void)sprintf(buf, "T%ld 0 %ld 0\n", stb.st_mtime, 45038100Sbostic stb.st_atime); 45138098Sbostic (void)write(rem, buf, strlen(buf)); 45223101Slepreau if (response() < 0) { 45338098Sbostic (void)close(f); 45423101Slepreau continue; 45523101Slepreau } 45623101Slepreau } 45738100Sbostic (void)sprintf(buf, "C%04o %ld %s\n", stb.st_mode&07777, 45838100Sbostic stb.st_size, last); 45938098Sbostic (void)write(rem, buf, strlen(buf)); 4606440Swnj if (response() < 0) { 46138098Sbostic (void)close(f); 4626440Swnj continue; 4636440Swnj } 46435689Sbostic if ((bp = allocbuf(&buffer, f, BUFSIZ)) == 0) { 46538098Sbostic (void)close(f); 46621254Smckusick continue; 46721254Smckusick } 46832268Sbostic readerr = 0; 46921254Smckusick for (i = 0; i < stb.st_size; i += bp->cnt) { 47021254Smckusick amt = bp->cnt; 4716440Swnj if (i + amt > stb.st_size) 4726440Swnj amt = stb.st_size - i; 47332268Sbostic if (readerr == 0 && read(f, bp->buf, amt) != amt) 47432268Sbostic readerr = errno; 47538098Sbostic (void)write(rem, bp->buf, amt); 4766440Swnj } 47738098Sbostic (void)close(f); 47832268Sbostic if (readerr == 0) 47938098Sbostic (void)write(rem, "", 1); 4806440Swnj else 48138469Sbostic error("rcp: %s: %s\n", name, strerror(readerr)); 48238098Sbostic (void)response(); 4836440Swnj } 4846440Swnj } 4856440Swnj 48623101Slepreau rsource(name, statp) 4876440Swnj char *name; 48823101Slepreau struct stat *statp; 4896440Swnj { 49038098Sbostic DIR *d; 4916440Swnj struct direct *dp; 49238100Sbostic char *last, *vect[1], path[MAXPATHLEN]; 4936440Swnj 49438098Sbostic if (!(d = opendir(name))) { 49538469Sbostic error("rcp: %s: %s\n", name, strerror(errno)); 4966440Swnj return; 4976440Swnj } 4986440Swnj last = rindex(name, '/'); 4996440Swnj if (last == 0) 5006440Swnj last = name; 5016440Swnj else 5026440Swnj last++; 50323101Slepreau if (pflag) { 50438100Sbostic (void)sprintf(path, "T%ld 0 %ld 0\n", statp->st_mtime, 50538100Sbostic statp->st_atime); 50638100Sbostic (void)write(rem, path, strlen(path)); 50723101Slepreau if (response() < 0) { 50823101Slepreau closedir(d); 50923101Slepreau return; 51023101Slepreau } 51123101Slepreau } 51238100Sbostic (void)sprintf(path, "D%04o %d %s\n", statp->st_mode&07777, 0, last); 51338100Sbostic (void)write(rem, path, strlen(path)); 5146440Swnj if (response() < 0) { 5156440Swnj closedir(d); 5166440Swnj return; 5176440Swnj } 5186440Swnj while (dp = readdir(d)) { 5196440Swnj if (dp->d_ino == 0) 5206440Swnj continue; 5216440Swnj if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 5226440Swnj continue; 52338100Sbostic if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) { 52438100Sbostic error("%s/%s: name too long.\n", name, dp->d_name); 5256440Swnj continue; 5266440Swnj } 52738100Sbostic (void)sprintf(path, "%s/%s", name, dp->d_name); 52838100Sbostic vect[0] = path; 52938100Sbostic source(1, vect); 5306440Swnj } 5316440Swnj closedir(d); 53238098Sbostic (void)write(rem, "E\n", 2); 53338098Sbostic (void)response(); 5346440Swnj } 5356440Swnj 5366440Swnj response() 5376440Swnj { 53838098Sbostic register char *cp; 53938098Sbostic char ch, resp, rbuf[BUFSIZ]; 5406440Swnj 54138098Sbostic if (read(rem, &resp, sizeof(resp)) != sizeof(resp)) 5426440Swnj lostconn(); 5436440Swnj 54438098Sbostic cp = rbuf; 54538098Sbostic switch(resp) { 54623101Slepreau case 0: /* ok */ 54738098Sbostic return(0); 5486440Swnj default: 5496440Swnj *cp++ = resp; 55038098Sbostic /* FALLTHROUGH */ 55123101Slepreau case 1: /* error, followed by err msg */ 55223101Slepreau case 2: /* fatal error, "" */ 5536440Swnj do { 55438098Sbostic if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) 5556440Swnj lostconn(); 55638098Sbostic *cp++ = ch; 55738098Sbostic } while (cp < &rbuf[BUFSIZ] && ch != '\n'); 55838098Sbostic 55938098Sbostic if (!iamremote) 56038098Sbostic (void)write(2, rbuf, cp - rbuf); 56138098Sbostic ++errs; 5626440Swnj if (resp == 1) 56338098Sbostic return(-1); 5646440Swnj exit(1); 5656440Swnj } 5666440Swnj /*NOTREACHED*/ 5676440Swnj } 5686440Swnj 5696440Swnj lostconn() 5706440Swnj { 57138098Sbostic if (!iamremote) 57238098Sbostic (void)fprintf(stderr, "rcp: lost connection\n"); 5736440Swnj exit(1); 5746440Swnj } 5756440Swnj 5766440Swnj sink(argc, argv) 5776440Swnj int argc; 5786440Swnj char **argv; 5796440Swnj { 58038100Sbostic register char *cp; 58138098Sbostic static BUF buffer; 58221254Smckusick struct stat stb; 58323101Slepreau struct timeval tv[2]; 58438469Sbostic enum { YES, NO, DISPLAYED } wrerr; 58538100Sbostic BUF *bp, *allocbuf(); 58638100Sbostic off_t i, j; 58738100Sbostic char ch, *targ, *why; 58838100Sbostic int amt, count, exists, first, mask, mode; 58938469Sbostic int ofd, setimes, size, targisdir; 59038100Sbostic char *np, *vect[1], buf[BUFSIZ], *malloc(); 5916440Swnj 59238100Sbostic #define atime tv[0] 59338100Sbostic #define mtime tv[1] 59438100Sbostic #define SCREWUP(str) { why = str; goto screwup; } 59538100Sbostic 59638100Sbostic setimes = targisdir = 0; 59738100Sbostic mask = umask(0); 59823112Slepreau if (!pflag) 59938098Sbostic (void)umask(mask); 60018126Sralph if (argc != 1) { 6016440Swnj error("rcp: ambiguous target\n"); 6026440Swnj exit(1); 6036440Swnj } 6046440Swnj targ = *argv; 6056440Swnj if (targetshouldbedirectory) 6066440Swnj verifydir(targ); 60738098Sbostic (void)write(rem, "", 1); 6086440Swnj if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR) 6096440Swnj targisdir = 1; 61038100Sbostic for (first = 1;; first = 0) { 61138100Sbostic cp = buf; 6126440Swnj if (read(rem, cp, 1) <= 0) 6136440Swnj return; 6146440Swnj if (*cp++ == '\n') 61538100Sbostic SCREWUP("unexpected <newline>"); 6166440Swnj do { 61738100Sbostic if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) 6186440Swnj SCREWUP("lost connection"); 61938100Sbostic *cp++ = ch; 62038100Sbostic } while (cp < &buf[BUFSIZ - 1] && ch != '\n'); 6216440Swnj *cp = 0; 62238100Sbostic 62338100Sbostic if (buf[0] == '\01' || buf[0] == '\02') { 6246440Swnj if (iamremote == 0) 62538100Sbostic (void)write(2, buf + 1, strlen(buf + 1)); 62638100Sbostic if (buf[0] == '\02') 6276440Swnj exit(1); 6286440Swnj errs++; 6296440Swnj continue; 6306440Swnj } 63138100Sbostic if (buf[0] == 'E') { 63238098Sbostic (void)write(rem, "", 1); 6336440Swnj return; 6346440Swnj } 63523101Slepreau 63638108Sbostic if (ch == '\n') 63738115Sbostic *--cp = 0; 63838108Sbostic 63923101Slepreau #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0'); 64038100Sbostic cp = buf; 64123101Slepreau if (*cp == 'T') { 64223101Slepreau setimes++; 64323101Slepreau cp++; 64423101Slepreau getnum(mtime.tv_sec); 64523101Slepreau if (*cp++ != ' ') 64623101Slepreau SCREWUP("mtime.sec not delimited"); 64723101Slepreau getnum(mtime.tv_usec); 64823101Slepreau if (*cp++ != ' ') 64923101Slepreau SCREWUP("mtime.usec not delimited"); 65023101Slepreau getnum(atime.tv_sec); 65123101Slepreau if (*cp++ != ' ') 65223101Slepreau SCREWUP("atime.sec not delimited"); 65323101Slepreau getnum(atime.tv_usec); 65423101Slepreau if (*cp++ != '\0') 65523101Slepreau SCREWUP("atime.usec not delimited"); 65638098Sbostic (void)write(rem, "", 1); 65723101Slepreau continue; 65823101Slepreau } 65914580Sralph if (*cp != 'C' && *cp != 'D') { 66014580Sralph /* 66114580Sralph * Check for the case "rcp remote:foo\* local:bar". 66214580Sralph * In this case, the line "No match." can be returned 66314580Sralph * by the shell before the rcp command on the remote is 66414580Sralph * executed so the ^Aerror_message convention isn't 66514580Sralph * followed. 66614580Sralph */ 66714580Sralph if (first) { 66814580Sralph error("%s\n", cp); 66914580Sralph exit(1); 67014580Sralph } 6716440Swnj SCREWUP("expected control record"); 67214580Sralph } 6736440Swnj mode = 0; 67438100Sbostic for (++cp; cp < buf + 5; cp++) { 6756440Swnj if (*cp < '0' || *cp > '7') 6766440Swnj SCREWUP("bad mode"); 6776440Swnj mode = (mode << 3) | (*cp - '0'); 6786440Swnj } 6796440Swnj if (*cp++ != ' ') 6806440Swnj SCREWUP("mode not delimited"); 6816440Swnj size = 0; 68223112Slepreau while (isdigit(*cp)) 6836440Swnj size = size * 10 + (*cp++ - '0'); 6846440Swnj if (*cp++ != ' ') 6856440Swnj SCREWUP("size not delimited"); 68638100Sbostic if (targisdir) { 68738100Sbostic static char *namebuf; 68838100Sbostic static int cursize; 68938100Sbostic int need; 69038100Sbostic 69138100Sbostic need = strlen(targ) + strlen(cp) + 250; 69238100Sbostic if (need > cursize) { 69338100Sbostic if (!(namebuf = malloc((u_int)need))) 69438108Sbostic error("out of memory\n"); 69538100Sbostic } 69638100Sbostic (void)sprintf(namebuf, "%s%s%s", targ, 6976440Swnj *targ ? "/" : "", cp); 69838100Sbostic np = namebuf; 69938100Sbostic } 7006440Swnj else 70138100Sbostic np = targ; 70238100Sbostic exists = stat(np, &stb) == 0; 70338100Sbostic if (buf[0] == 'D') { 70418126Sralph if (exists) { 7056440Swnj if ((stb.st_mode&S_IFMT) != S_IFDIR) { 7066440Swnj errno = ENOTDIR; 7076440Swnj goto bad; 7086440Swnj } 70923112Slepreau if (pflag) 71038100Sbostic (void)chmod(np, mode); 71138100Sbostic } else if (mkdir(np, mode) < 0) 7126440Swnj goto bad; 71338100Sbostic vect[0] = np; 71438100Sbostic sink(1, vect); 71523101Slepreau if (setimes) { 71623101Slepreau setimes = 0; 71738100Sbostic if (utimes(np, tv) < 0) 71838100Sbostic error("rcp: can't set times on %s: %s\n", 71938469Sbostic np, strerror(errno)); 72023101Slepreau } 7216440Swnj continue; 72218126Sralph } 72338100Sbostic if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { 72438469Sbostic bad: error("rcp: %s: %s\n", np, strerror(errno)); 7256440Swnj continue; 7266440Swnj } 72723112Slepreau if (exists && pflag) 72838100Sbostic (void)fchmod(ofd, mode); 72938098Sbostic (void)write(rem, "", 1); 73038100Sbostic if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == 0) { 73138100Sbostic (void)close(ofd); 73221254Smckusick continue; 73321254Smckusick } 73421254Smckusick cp = bp->buf; 73521254Smckusick count = 0; 73638469Sbostic wrerr = NO; 7376440Swnj for (i = 0; i < size; i += BUFSIZ) { 73821254Smckusick amt = BUFSIZ; 7396440Swnj if (i + amt > size) 7406440Swnj amt = size - i; 74121254Smckusick count += amt; 7426440Swnj do { 74321254Smckusick j = read(rem, cp, amt); 74424711Sbloom if (j <= 0) { 74538108Sbostic error("rcp: %s\n", 74638469Sbostic j ? strerror(errno) : 74738100Sbostic "dropped connection"); 7486440Swnj exit(1); 74924711Sbloom } 7506440Swnj amt -= j; 7516440Swnj cp += j; 7526440Swnj } while (amt > 0); 75321254Smckusick if (count == bp->cnt) { 75438469Sbostic if (wrerr == NO && 75538100Sbostic write(ofd, bp->buf, count) != count) 75638469Sbostic wrerr = YES; 75721254Smckusick count = 0; 75821254Smckusick cp = bp->buf; 75921254Smckusick } 7606440Swnj } 76138469Sbostic if (count != 0 && wrerr == NO && 76238100Sbostic write(ofd, bp->buf, count) != count) 76338469Sbostic wrerr = YES; 76438469Sbostic if (ftruncate(ofd, size)) { 76538100Sbostic error("rcp: can't truncate %s: %s\n", np, 76638469Sbostic strerror(errno)); 76738469Sbostic wrerr = DISPLAYED; 76838469Sbostic } 76938100Sbostic (void)close(ofd); 77038098Sbostic (void)response(); 77138469Sbostic if (setimes && wrerr == NO) { 77223101Slepreau setimes = 0; 77338469Sbostic if (utimes(np, tv) < 0) { 77423101Slepreau error("rcp: can't set times on %s: %s\n", 77538469Sbostic np, strerror(errno)); 77638469Sbostic wrerr = DISPLAYED; 77738469Sbostic } 77838469Sbostic } 77938469Sbostic switch(wrerr) { 78038469Sbostic case YES: 78138469Sbostic error("rcp: %s: %s\n", np, strerror(errno)); 78238469Sbostic break; 78338469Sbostic case NO: 78438098Sbostic (void)write(rem, "", 1); 78538469Sbostic break; 78638469Sbostic case DISPLAYED: 78738469Sbostic break; 78838469Sbostic } 7896440Swnj } 7906440Swnj screwup: 79138100Sbostic error("rcp: protocol screwup: %s\n", why); 7926440Swnj exit(1); 7936440Swnj } 7946440Swnj 79538098Sbostic BUF * 79621254Smckusick allocbuf(bp, fd, blksize) 79738098Sbostic BUF *bp; 79821254Smckusick int fd, blksize; 79921254Smckusick { 80021254Smckusick struct stat stb; 80121254Smckusick int size; 80238098Sbostic char *malloc(); 80321254Smckusick 80421254Smckusick if (fstat(fd, &stb) < 0) { 80538469Sbostic error("rcp: fstat: %s\n", strerror(errno)); 80638098Sbostic return(0); 80721254Smckusick } 80821254Smckusick size = roundup(stb.st_blksize, blksize); 80921254Smckusick if (size == 0) 81021254Smckusick size = blksize; 81121254Smckusick if (bp->cnt < size) { 81221254Smckusick if (bp->buf != 0) 81321254Smckusick free(bp->buf); 81438098Sbostic bp->buf = (char *)malloc((u_int)size); 81538100Sbostic if (!bp->buf) { 81621254Smckusick error("rcp: malloc: out of memory\n"); 81738098Sbostic return(0); 81821254Smckusick } 81921254Smckusick } 82021254Smckusick bp->cnt = size; 82138098Sbostic return(bp); 82221254Smckusick } 82321254Smckusick 82438098Sbostic /* VARARGS1 */ 82538100Sbostic error(fmt, a1, a2, a3) 8266440Swnj char *fmt; 82738100Sbostic int a1, a2, a3; 8286440Swnj { 82938108Sbostic static FILE *fp; 8306440Swnj 83138098Sbostic ++errs; 83238108Sbostic if (!fp && !(fp = fdopen(rem, "w"))) 83338108Sbostic return; 83438108Sbostic (void)fprintf(fp, "%c", 0x01); 83538108Sbostic (void)fprintf(fp, fmt, a1, a2, a3); 83638108Sbostic (void)fflush(fp); 83738098Sbostic if (!iamremote) 83838108Sbostic (void)fprintf(stderr, fmt, a1, a2, a3); 8396440Swnj } 84032127Sbostic 84138100Sbostic nospace() 84238100Sbostic { 84338100Sbostic (void)fprintf(stderr, "rcp: out of memory.\n"); 84438100Sbostic exit(1); 84538100Sbostic } 84638100Sbostic 84738100Sbostic 84832127Sbostic usage() 84932127Sbostic { 85038098Sbostic #ifdef KERBEROS 85138098Sbostic (void)fprintf(stderr, "%s\n\t%s\n", 85238098Sbostic "usage: rcp [-k realm] [-px] f1 f2", 85338098Sbostic "or: rcp [-k realm] [-rpx] f1 ... fn directory"); 85436626Skfall #else 85538098Sbostic (void)fprintf(stderr, 85638098Sbostic "usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn directory\n"); 85736626Skfall #endif 85832127Sbostic exit(1); 85932127Sbostic } 86038879Skfall 86138879Skfall #ifdef KERBEROS 86238879Skfall old_warning(str) 86338879Skfall char *str; 86438879Skfall { 86538879Skfall (void)fprintf(stderr, "rcp: warning: %s, using standard rcp\n", str); 86638879Skfall } 86738879Skfall 86838879Skfall int 86938879Skfall kerberos(host, bp, locuser, user) 87038879Skfall 87138879Skfall char **host, *bp, *locuser, *user; 87238879Skfall { 87338879Skfall struct servent *sp; 87438879Skfall 87538879Skfall again: 87638879Skfall if (use_kerberos) { 87738879Skfall rem = KSUCCESS; 87838879Skfall errno = 0; 87938879Skfall if (dest_realm == NULL) 88038879Skfall dest_realm = krb_realmofhost(*host); 88138879Skfall 88238879Skfall if (encrypt) 88338879Skfall rem = krcmd_mutual( 88438879Skfall host, port, 88538879Skfall user, bp, 0, 88638879Skfall dest_realm, 88738879Skfall &cred, schedule); 88838879Skfall else 88938879Skfall rem = krcmd( 89038879Skfall host, port, 89138879Skfall user, bp, 0, dest_realm); 89238879Skfall 89338879Skfall if (rem < 0) { 89438879Skfall use_kerberos = 0; 89538879Skfall sp = getservbyname("shell", "tcp"); 89638879Skfall if (sp == NULL) { 89738879Skfall (void)fprintf(stderr, 89838879Skfall "rcp: unknown service shell/tcp\n"); 89938879Skfall exit(1); 90038879Skfall } 90138879Skfall if (errno == ECONNREFUSED) 90238879Skfall old_warning( 90338879Skfall "remote host doesn't support Kerberos"); 90438879Skfall 90538879Skfall if (errno == ENOENT) 90638879Skfall old_warning( 90738879Skfall "Can't provide Kerberos auth data"); 90838879Skfall port = sp->s_port; 90938879Skfall goto again; 91038879Skfall } 91138879Skfall } else { 91238879Skfall if (encrypt) { 91338879Skfall fprintf(stderr, 91438879Skfall "The -x option requires Kerberos authentication\n"); 91538879Skfall exit(1); 91638879Skfall } 91738879Skfall rem = rcmd(host, sp->s_port, locuser, user, bp, 0); 91838879Skfall } 91938879Skfall return(rem); 92038879Skfall } 92138879Skfall #endif /* KERBEROS */ 922