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*38098Sbostic static char sccsid[] = "@(#)rcp.c 5.16 (Berkeley) 05/21/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> 36*38098Sbostic #include <sys/dir.h> 37*38098Sbostic #include <sys/signal.h> 389199Ssam #include <netinet/in.h> 396440Swnj #include <pwd.h> 4018026Sralph #include <netdb.h> 416440Swnj #include <errno.h> 42*38098Sbostic #include <strings.h> 43*38098Sbostic #include <stdio.h> 44*38098Sbostic #include <ctype.h> 4537037Sbostic #include "pathnames.h" 4612989Ssam 47*38098Sbostic #ifdef KERBEROS 4836624Skfall #include <kerberos/krb.h> 49*38098Sbostic 50*38098Sbostic char krb_realm[REALM_SZ]; 51*38098Sbostic int use_kerberos = 1, encrypt = 0; 52*38098Sbostic CREDENTIALS cred; 53*38098Sbostic Key_schedule schedule; 5436624Skfall #endif 5536624Skfall 56*38098Sbostic extern int errno; 57*38098Sbostic extern char *sys_errlist[]; 58*38098Sbostic struct passwd *pwd; 59*38098Sbostic int errs, pflag, port, rem, userid; 60*38098Sbostic int iamremote, iamrecursive, targetshouldbedirectory; 616440Swnj 62*38098Sbostic char cmd[20]; /* must hold "rcp -r -p -d\0" */ 63*38098Sbostic 64*38098Sbostic typedef struct _buf { 6521254Smckusick int cnt; 6621254Smckusick char *buf; 67*38098Sbostic } BUF; 6821254Smckusick 696440Swnj main(argc, argv) 706440Swnj int argc; 716440Swnj char **argv; 726440Swnj { 73*38098Sbostic extern int optind; 7418126Sralph struct servent *sp; 75*38098Sbostic int ch; 76*38098Sbostic char *targ, *colon(); 77*38098Sbostic struct passwd *getpwuid(); 78*38098Sbostic int lostconn(); 7918026Sralph 80*38098Sbostic #ifdef KERBEROS 8136626Skfall sp = getservbyname("kshell", "tcp"); 82*38098Sbostic if (sp == NULL) { 8336626Skfall use_kerberos = 0; 8436626Skfall old_warning("kshell service unknown"); 8536626Skfall sp = getservbyname("kshell", "tcp"); 8636626Skfall } 8736626Skfall #else 8818026Sralph sp = getservbyname("shell", "tcp"); 8936626Skfall #endif 90*38098Sbostic if (!sp) { 91*38098Sbostic (void)fprintf(stderr, "rcp: shell/tcp: unknown service\n"); 9218026Sralph exit(1); 9318026Sralph } 9418126Sralph port = sp->s_port; 95*38098Sbostic 96*38098Sbostic if (!(pwd = getpwuid(userid = getuid()))) { 97*38098Sbostic (void)fprintf(stderr, "rcp: unknown user %d.\n", userid); 986440Swnj exit(1); 996440Swnj } 10023101Slepreau 101*38098Sbostic while ((ch = getopt(argc, argv, "dfkprtx")) != EOF) 102*38098Sbostic switch(ch) { 103*38098Sbostic case 'd': 104*38098Sbostic targetshouldbedirectory = 1; 10523101Slepreau break; 106*38098Sbostic case 'f': /* "from" */ 107*38098Sbostic iamremote = 1; 108*38098Sbostic (void)response(); 109*38098Sbostic (void)setuid(userid); 110*38098Sbostic source(--argc, ++argv); 111*38098Sbostic exit(errs); 112*38098Sbostic #ifdef KERBEROS 113*38098Sbostic case 'k': 11436624Skfall strncpy(krb_realm, ++argv, REALM_SZ); 11536624Skfall break; 11636624Skfall #endif 117*38098Sbostic case 'p': /* preserve access/mod times */ 118*38098Sbostic ++pflag; 11923101Slepreau break; 120*38098Sbostic case 'r': 121*38098Sbostic ++iamrecursive; 12223101Slepreau break; 123*38098Sbostic case 't': /* "to" */ 12423101Slepreau iamremote = 1; 125*38098Sbostic (void)setuid(userid); 12623101Slepreau sink(--argc, ++argv); 12723101Slepreau exit(errs); 128*38098Sbostic #ifdef KERBEROS 129*38098Sbostic case 'x': 130*38098Sbostic encrypt = 1; 131*38098Sbostic des_set_key(cred.session, schedule); 132*38098Sbostic break; 133*38098Sbostic #endif 134*38098Sbostic case '?': 135*38098Sbostic default: 13632127Sbostic usage(); 13723101Slepreau } 138*38098Sbostic argc -= optind; 139*38098Sbostic argv += optind; 140*38098Sbostic 14132127Sbostic if (argc < 2) 14232127Sbostic usage(); 1436440Swnj if (argc > 2) 1446440Swnj targetshouldbedirectory = 1; 145*38098Sbostic 14632127Sbostic rem = -1; 147*38098Sbostic (void)sprintf(cmd, "rcp%s%s%s", iamrecursive ? " -r" : "", 148*38098Sbostic pflag ? " -p" : "", targetshouldbedirectory ? " -d" : ""); 149*38098Sbostic 150*38098Sbostic (void)signal(SIGPIPE, lostconn); 151*38098Sbostic 152*38098Sbostic if (targ = colon(argv[argc - 1])) 153*38098Sbostic toremote(targ, argc, argv); 154*38098Sbostic else { 155*38098Sbostic tolocal(argc, argv); 156*38098Sbostic if (targetshouldbedirectory) 157*38098Sbostic verifydir(argv[argc - 1]); 158*38098Sbostic } 159*38098Sbostic exit(errs); 160*38098Sbostic } 161*38098Sbostic 162*38098Sbostic toremote(targ, argc, argv) 163*38098Sbostic char *targ; 164*38098Sbostic int argc; 165*38098Sbostic char **argv; 166*38098Sbostic { 167*38098Sbostic int i; 168*38098Sbostic char *host, *src, *suser, *thost, *tuser; 169*38098Sbostic char buf[1024], *colon(); 170*38098Sbostic 171*38098Sbostic *targ++ = 0; 172*38098Sbostic if (*targ == 0) 173*38098Sbostic targ = "."; 174*38098Sbostic 175*38098Sbostic thost = index(argv[argc - 1], '@'); 176*38098Sbostic if (thost) { 177*38098Sbostic *thost++ = 0; 178*38098Sbostic tuser = argv[argc - 1]; 179*38098Sbostic if (*tuser == '\0') 18024711Sbloom tuser = NULL; 181*38098Sbostic else if (!okname(tuser)) 182*38098Sbostic exit(1); 183*38098Sbostic } else { 184*38098Sbostic thost = argv[argc - 1]; 185*38098Sbostic tuser = NULL; 186*38098Sbostic } 18736624Skfall 188*38098Sbostic for (i = 0; i < argc - 1; i++) { 189*38098Sbostic src = colon(argv[i]); 190*38098Sbostic if (src) { /* remote to remote */ 191*38098Sbostic *src++ = 0; 192*38098Sbostic if (*src == 0) 193*38098Sbostic src = "."; 194*38098Sbostic host = index(argv[i], '@'); 195*38098Sbostic if (host) { 196*38098Sbostic *host++ = 0; 197*38098Sbostic suser = argv[i]; 198*38098Sbostic if (*suser == '\0') 199*38098Sbostic suser = pwd->pw_name; 200*38098Sbostic else if (!okname(suser)) 201*38098Sbostic continue; 202*38098Sbostic (void)sprintf(buf, 203*38098Sbostic "%s %s -l %s -n %s %s '%s%s%s:%s'", 204*38098Sbostic _PATH_RSH, host, suser, cmd, src, 205*38098Sbostic tuser ? tuser : "", tuser ? "@" : "", 206*38098Sbostic thost, targ); 207*38098Sbostic } else 208*38098Sbostic (void)sprintf(buf, 209*38098Sbostic "%s %s -n %s %s '%s%s%s:%s'", 210*38098Sbostic _PATH_RSH, argv[i], cmd, src, 211*38098Sbostic tuser ? tuser : "", tuser ? "@" : "", 212*38098Sbostic thost, targ); 213*38098Sbostic (void)susystem(buf); 214*38098Sbostic } else { /* local to remote */ 215*38098Sbostic if (rem == -1) { 216*38098Sbostic (void)sprintf(buf, "%s -t %s", cmd, targ); 217*38098Sbostic host = thost; 218*38098Sbostic #ifdef KERBEROS 219*38098Sbostic if (use_kerberos) 220*38098Sbostic kerberos(buf, tuser ? 221*38098Sbostic tuser : pwd->pw_name); 222*38098Sbostic else 223*38098Sbostic #endif 22424711Sbloom rem = rcmd(&host, port, pwd->pw_name, 22524711Sbloom tuser ? tuser : pwd->pw_name, 2266440Swnj buf, 0); 227*38098Sbostic if (rem < 0) 228*38098Sbostic exit(1); 229*38098Sbostic if (response() < 0) 230*38098Sbostic exit(1); 231*38098Sbostic (void)setuid(userid); 2326440Swnj } 233*38098Sbostic source(1, argv+i); 2346440Swnj } 235*38098Sbostic } 236*38098Sbostic } 237*38098Sbostic 238*38098Sbostic tolocal(argc, argv) 239*38098Sbostic int argc; 240*38098Sbostic char **argv; 241*38098Sbostic { 242*38098Sbostic int i; 243*38098Sbostic char *host, *src, *suser; 244*38098Sbostic char buf[1024], *colon(); 245*38098Sbostic 246*38098Sbostic for (i = 0; i < argc - 1; i++) { 247*38098Sbostic src = colon(argv[i]); 248*38098Sbostic if (src == 0) { /* local to local */ 249*38098Sbostic (void)sprintf(buf, "%s%s%s %s %s", 250*38098Sbostic _PATH_CP, iamrecursive ? " -r" : "", 251*38098Sbostic pflag ? " -p" : "", argv[i], argv[argc - 1]); 252*38098Sbostic (void)susystem(buf); 253*38098Sbostic } else { /* remote to local */ 254*38098Sbostic *src++ = 0; 255*38098Sbostic if (*src == 0) 256*38098Sbostic src = "."; 257*38098Sbostic host = index(argv[i], '@'); 258*38098Sbostic if (host) { 259*38098Sbostic *host++ = 0; 260*38098Sbostic suser = argv[i]; 261*38098Sbostic if (*suser == '\0') 2626440Swnj suser = pwd->pw_name; 263*38098Sbostic else if (!okname(suser)) 26418259Sralph continue; 265*38098Sbostic } else { 266*38098Sbostic host = argv[i]; 267*38098Sbostic suser = pwd->pw_name; 2686440Swnj } 269*38098Sbostic (void)sprintf(buf, "%s -f %s", cmd, src); 270*38098Sbostic #ifdef KERBEROS 271*38098Sbostic if (use_kerberos) 272*38098Sbostic kerberos(buf, suser); 273*38098Sbostic else 274*38098Sbostic #endif 275*38098Sbostic rem = rcmd(&host, port, pwd->pw_name, suser, 276*38098Sbostic buf, 0); 277*38098Sbostic if (rem < 0) 278*38098Sbostic continue; 279*38098Sbostic (void)setreuid(0, userid); 280*38098Sbostic sink(1, argv + argc - 1); 281*38098Sbostic (void)setreuid(userid, 0); 282*38098Sbostic (void)close(rem); 283*38098Sbostic rem = -1; 2846440Swnj } 2856440Swnj } 2866440Swnj } 2876440Swnj 288*38098Sbostic #ifdef KERBEROS 289*38098Sbostic kerberos(buf, user) 290*38098Sbostic char *buf, *user; 291*38098Sbostic { 292*38098Sbostic struct servent *sp; 293*38098Sbostic char *host; 294*38098Sbostic 295*38098Sbostic again: rem = KSUCCESS; 296*38098Sbostic if (krb_realm[0] == '\0') 297*38098Sbostic rem = krb_get_lrealm(krb_realm, 1); 298*38098Sbostic if (rem == KSUCCESS) { 299*38098Sbostic if (encrypt) 300*38098Sbostic rem = krcmd_mutual(&host, port, user, buf, 301*38098Sbostic 0, krb_realm, &cred, schedule); 302*38098Sbostic else 303*38098Sbostic rem = krcmd(&host, port, user, buf, 0, krb_realm); 304*38098Sbostic } else { 305*38098Sbostic (void)fprintf(stderr, 306*38098Sbostic "rcp: error getting local realm %s\n", krb_err_txt[rem]); 307*38098Sbostic exit(1); 308*38098Sbostic } 309*38098Sbostic if (rem < 0 && errno == ECONNREFUSED) { 310*38098Sbostic use_kerberos = 0; 311*38098Sbostic old_warning("remote host doesn't support Kerberos"); 312*38098Sbostic sp = getservbyname("shell", "tcp"); 313*38098Sbostic if (sp == NULL) { 314*38098Sbostic (void)fprintf(stderr, 315*38098Sbostic "rcp: unknown service shell/tcp\n"); 316*38098Sbostic exit(1); 317*38098Sbostic } 318*38098Sbostic port = sp->s_port; 319*38098Sbostic goto again; 320*38098Sbostic } 321*38098Sbostic } 322*38098Sbostic #endif /* KERBEROS */ 323*38098Sbostic 3246440Swnj verifydir(cp) 3256440Swnj char *cp; 3266440Swnj { 3276440Swnj struct stat stb; 3286440Swnj 32918126Sralph if (stat(cp, &stb) >= 0) { 33018126Sralph if ((stb.st_mode & S_IFMT) == S_IFDIR) 33118126Sralph return; 33218126Sralph errno = ENOTDIR; 33318126Sralph } 3346440Swnj error("rcp: %s: %s.\n", cp, sys_errlist[errno]); 3356440Swnj exit(1); 3366440Swnj } 3376440Swnj 3386440Swnj char * 3396440Swnj colon(cp) 340*38098Sbostic register char *cp; 3416440Swnj { 342*38098Sbostic for (; *cp; ++cp) { 3436440Swnj if (*cp == ':') 344*38098Sbostic return(cp); 3456440Swnj if (*cp == '/') 346*38098Sbostic return(0); 3476440Swnj } 348*38098Sbostic return(0); 3496440Swnj } 3506440Swnj 3516440Swnj okname(cp0) 3526440Swnj char *cp0; 3536440Swnj { 3546440Swnj register char *cp = cp0; 3556440Swnj register int c; 3566440Swnj 3576440Swnj do { 3586440Swnj c = *cp; 3596440Swnj if (c & 0200) 3606440Swnj goto bad; 3616440Swnj if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') 3626440Swnj goto bad; 3636440Swnj cp++; 3646440Swnj } while (*cp); 365*38098Sbostic return(1); 3666440Swnj bad: 3676440Swnj fprintf(stderr, "rcp: invalid user name %s\n", cp0); 368*38098Sbostic return(0); 3696440Swnj } 3706440Swnj 37117999Sserge susystem(s) 37217999Sserge char *s; 3736440Swnj { 37417999Sserge int status, pid, w; 37517999Sserge register int (*istat)(), (*qstat)(); 3766440Swnj 37717999Sserge if ((pid = vfork()) == 0) { 378*38098Sbostic (void)setuid(userid); 37937037Sbostic execl(_PATH_BSHELL, "sh", "-c", s, (char *)0); 38017999Sserge _exit(127); 38117999Sserge } 38217999Sserge istat = signal(SIGINT, SIG_IGN); 38317999Sserge qstat = signal(SIGQUIT, SIG_IGN); 38417999Sserge while ((w = wait(&status)) != pid && w != -1) 38517999Sserge ; 38617999Sserge if (w == -1) 38717999Sserge status = -1; 388*38098Sbostic (void)signal(SIGINT, istat); 389*38098Sbostic (void)signal(SIGQUIT, qstat); 390*38098Sbostic return(status); 3916440Swnj } 3926440Swnj 3936440Swnj source(argc, argv) 3946440Swnj int argc; 3956440Swnj char **argv; 3966440Swnj { 3976440Swnj struct stat stb; 398*38098Sbostic static BUF buffer; 399*38098Sbostic BUF *bp; 400*38098Sbostic off_t i; 40132268Sbostic int x, readerr, f, amt; 402*38098Sbostic char *last, *name, buf[BUFSIZ]; 403*38098Sbostic BUF *allocbuf(); 4046440Swnj 4056440Swnj for (x = 0; x < argc; x++) { 4066440Swnj name = argv[x]; 407*38098Sbostic if ((f = open(name, O_RDONLY, 0)) < 0) { 4086440Swnj error("rcp: %s: %s\n", name, sys_errlist[errno]); 4096440Swnj continue; 4106440Swnj } 4116440Swnj if (fstat(f, &stb) < 0) 4126440Swnj goto notreg; 4136440Swnj switch (stb.st_mode&S_IFMT) { 4146440Swnj 4156440Swnj case S_IFREG: 4166440Swnj break; 4176440Swnj 4186440Swnj case S_IFDIR: 4196440Swnj if (iamrecursive) { 420*38098Sbostic (void)close(f); 42123101Slepreau rsource(name, &stb); 4226440Swnj continue; 4236440Swnj } 424*38098Sbostic /* FALLTHROUGH */ 4256440Swnj default: 426*38098Sbostic notreg: (void)close(f); 4276440Swnj error("rcp: %s: not a plain file\n", name); 4286440Swnj continue; 4296440Swnj } 4306440Swnj last = rindex(name, '/'); 4316440Swnj if (last == 0) 4326440Swnj last = name; 4336440Swnj else 4346440Swnj last++; 43523101Slepreau if (pflag) { 43623101Slepreau /* 43723101Slepreau * Make it compatible with possible future 43823101Slepreau * versions expecting microseconds. 43923101Slepreau */ 440*38098Sbostic (void)sprintf(buf, "T%ld 0 %ld 0\n", 44123101Slepreau stb.st_mtime, stb.st_atime); 442*38098Sbostic (void)write(rem, buf, strlen(buf)); 44323101Slepreau if (response() < 0) { 444*38098Sbostic (void)close(f); 44523101Slepreau continue; 44623101Slepreau } 44723101Slepreau } 448*38098Sbostic (void)sprintf(buf, "C%04o %ld %s\n", 4496440Swnj stb.st_mode&07777, stb.st_size, last); 450*38098Sbostic (void)write(rem, buf, strlen(buf)); 4516440Swnj if (response() < 0) { 452*38098Sbostic (void)close(f); 4536440Swnj continue; 4546440Swnj } 45535689Sbostic if ((bp = allocbuf(&buffer, f, BUFSIZ)) == 0) { 456*38098Sbostic (void)close(f); 45721254Smckusick continue; 45821254Smckusick } 45932268Sbostic readerr = 0; 46021254Smckusick for (i = 0; i < stb.st_size; i += bp->cnt) { 46121254Smckusick amt = bp->cnt; 4626440Swnj if (i + amt > stb.st_size) 4636440Swnj amt = stb.st_size - i; 46432268Sbostic if (readerr == 0 && read(f, bp->buf, amt) != amt) 46532268Sbostic readerr = errno; 466*38098Sbostic (void)write(rem, bp->buf, amt); 4676440Swnj } 468*38098Sbostic (void)close(f); 46932268Sbostic if (readerr == 0) 470*38098Sbostic (void)write(rem, "", 1); 4716440Swnj else 47232268Sbostic error("rcp: %s: %s\n", name, sys_errlist[readerr]); 473*38098Sbostic (void)response(); 4746440Swnj } 4756440Swnj } 4766440Swnj 47723101Slepreau rsource(name, statp) 4786440Swnj char *name; 47923101Slepreau struct stat *statp; 4806440Swnj { 481*38098Sbostic DIR *d; 4826440Swnj struct direct *dp; 483*38098Sbostic char *last, *bufv[1], buf[BUFSIZ]; 4846440Swnj 485*38098Sbostic if (!(d = opendir(name))) { 48618126Sralph error("rcp: %s: %s\n", name, sys_errlist[errno]); 4876440Swnj return; 4886440Swnj } 4896440Swnj last = rindex(name, '/'); 4906440Swnj if (last == 0) 4916440Swnj last = name; 4926440Swnj else 4936440Swnj last++; 49423101Slepreau if (pflag) { 495*38098Sbostic (void)sprintf(buf, "T%ld 0 %ld 0\n", 49623101Slepreau statp->st_mtime, statp->st_atime); 497*38098Sbostic (void)write(rem, buf, strlen(buf)); 49823101Slepreau if (response() < 0) { 49923101Slepreau closedir(d); 50023101Slepreau return; 50123101Slepreau } 50223101Slepreau } 503*38098Sbostic (void)sprintf(buf, "D%04o %d %s\n", statp->st_mode&07777, 0, last); 504*38098Sbostic (void)write(rem, buf, strlen(buf)); 5056440Swnj if (response() < 0) { 5066440Swnj closedir(d); 5076440Swnj return; 5086440Swnj } 5096440Swnj while (dp = readdir(d)) { 5106440Swnj if (dp->d_ino == 0) 5116440Swnj continue; 5126440Swnj if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 5136440Swnj continue; 5146440Swnj if (strlen(name) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { 5156440Swnj error("%s/%s: Name too long.\n", name, dp->d_name); 5166440Swnj continue; 5176440Swnj } 518*38098Sbostic (void)sprintf(buf, "%s/%s", name, dp->d_name); 5196440Swnj bufv[0] = buf; 5206440Swnj source(1, bufv); 5216440Swnj } 5226440Swnj closedir(d); 523*38098Sbostic (void)write(rem, "E\n", 2); 524*38098Sbostic (void)response(); 5256440Swnj } 5266440Swnj 5276440Swnj response() 5286440Swnj { 529*38098Sbostic register char *cp; 530*38098Sbostic char ch, resp, rbuf[BUFSIZ]; 5316440Swnj 532*38098Sbostic if (read(rem, &resp, sizeof(resp)) != sizeof(resp)) 5336440Swnj lostconn(); 5346440Swnj 535*38098Sbostic cp = rbuf; 536*38098Sbostic switch(resp) { 53723101Slepreau case 0: /* ok */ 538*38098Sbostic return(0); 5396440Swnj default: 5406440Swnj *cp++ = resp; 541*38098Sbostic /* FALLTHROUGH */ 54223101Slepreau case 1: /* error, followed by err msg */ 54323101Slepreau case 2: /* fatal error, "" */ 5446440Swnj do { 545*38098Sbostic if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) 5466440Swnj lostconn(); 547*38098Sbostic *cp++ = ch; 548*38098Sbostic } while (cp < &rbuf[BUFSIZ] && ch != '\n'); 549*38098Sbostic 550*38098Sbostic if (!iamremote) 551*38098Sbostic (void)write(2, rbuf, cp - rbuf); 552*38098Sbostic ++errs; 5536440Swnj if (resp == 1) 554*38098Sbostic return(-1); 5556440Swnj exit(1); 5566440Swnj } 5576440Swnj /*NOTREACHED*/ 5586440Swnj } 5596440Swnj 5606440Swnj lostconn() 5616440Swnj { 562*38098Sbostic if (!iamremote) 563*38098Sbostic (void)fprintf(stderr, "rcp: lost connection\n"); 5646440Swnj exit(1); 5656440Swnj } 5666440Swnj 5676440Swnj sink(argc, argv) 5686440Swnj int argc; 5696440Swnj char **argv; 5706440Swnj { 57121254Smckusick off_t i, j; 57221254Smckusick char *targ, *whopp, *cp; 57321254Smckusick int of, mode, wrerr, exists, first, count, amt, size; 574*38098Sbostic BUF *bp; 575*38098Sbostic static BUF buffer; 57621254Smckusick struct stat stb; 57721254Smckusick int targisdir = 0; 5786440Swnj int mask = umask(0); 5796440Swnj char *myargv[1]; 58023101Slepreau char cmdbuf[BUFSIZ], nambuf[BUFSIZ]; 58123101Slepreau int setimes = 0; 58223101Slepreau struct timeval tv[2]; 583*38098Sbostic BUF *allocbuf(); 58423101Slepreau #define atime tv[0] 58523101Slepreau #define mtime tv[1] 58621254Smckusick #define SCREWUP(str) { whopp = str; goto screwup; } 5876440Swnj 58823112Slepreau if (!pflag) 589*38098Sbostic (void)umask(mask); 59018126Sralph if (argc != 1) { 5916440Swnj error("rcp: ambiguous target\n"); 5926440Swnj exit(1); 5936440Swnj } 5946440Swnj targ = *argv; 5956440Swnj if (targetshouldbedirectory) 5966440Swnj verifydir(targ); 597*38098Sbostic (void)write(rem, "", 1); 5986440Swnj if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR) 5996440Swnj targisdir = 1; 60014580Sralph for (first = 1; ; first = 0) { 6016440Swnj cp = cmdbuf; 6026440Swnj if (read(rem, cp, 1) <= 0) 6036440Swnj return; 6046440Swnj if (*cp++ == '\n') 6056440Swnj SCREWUP("unexpected '\\n'"); 6066440Swnj do { 6076440Swnj if (read(rem, cp, 1) != 1) 6086440Swnj SCREWUP("lost connection"); 6096440Swnj } while (*cp++ != '\n'); 6106440Swnj *cp = 0; 6116440Swnj if (cmdbuf[0] == '\01' || cmdbuf[0] == '\02') { 6126440Swnj if (iamremote == 0) 613*38098Sbostic (void)write(2, cmdbuf+1, strlen(cmdbuf+1)); 6146440Swnj if (cmdbuf[0] == '\02') 6156440Swnj exit(1); 6166440Swnj errs++; 6176440Swnj continue; 6186440Swnj } 6196440Swnj *--cp = 0; 6206440Swnj cp = cmdbuf; 6216440Swnj if (*cp == 'E') { 622*38098Sbostic (void)write(rem, "", 1); 6236440Swnj return; 6246440Swnj } 62523101Slepreau 62623101Slepreau #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0'); 62723101Slepreau if (*cp == 'T') { 62823101Slepreau setimes++; 62923101Slepreau cp++; 63023101Slepreau getnum(mtime.tv_sec); 63123101Slepreau if (*cp++ != ' ') 63223101Slepreau SCREWUP("mtime.sec not delimited"); 63323101Slepreau getnum(mtime.tv_usec); 63423101Slepreau if (*cp++ != ' ') 63523101Slepreau SCREWUP("mtime.usec not delimited"); 63623101Slepreau getnum(atime.tv_sec); 63723101Slepreau if (*cp++ != ' ') 63823101Slepreau SCREWUP("atime.sec not delimited"); 63923101Slepreau getnum(atime.tv_usec); 64023101Slepreau if (*cp++ != '\0') 64123101Slepreau SCREWUP("atime.usec not delimited"); 642*38098Sbostic (void)write(rem, "", 1); 64323101Slepreau continue; 64423101Slepreau } 64514580Sralph if (*cp != 'C' && *cp != 'D') { 64614580Sralph /* 64714580Sralph * Check for the case "rcp remote:foo\* local:bar". 64814580Sralph * In this case, the line "No match." can be returned 64914580Sralph * by the shell before the rcp command on the remote is 65014580Sralph * executed so the ^Aerror_message convention isn't 65114580Sralph * followed. 65214580Sralph */ 65314580Sralph if (first) { 65414580Sralph error("%s\n", cp); 65514580Sralph exit(1); 65614580Sralph } 6576440Swnj SCREWUP("expected control record"); 65814580Sralph } 6596440Swnj cp++; 6606440Swnj mode = 0; 6616440Swnj for (; cp < cmdbuf+5; cp++) { 6626440Swnj if (*cp < '0' || *cp > '7') 6636440Swnj SCREWUP("bad mode"); 6646440Swnj mode = (mode << 3) | (*cp - '0'); 6656440Swnj } 6666440Swnj if (*cp++ != ' ') 6676440Swnj SCREWUP("mode not delimited"); 6686440Swnj size = 0; 66923112Slepreau while (isdigit(*cp)) 6706440Swnj size = size * 10 + (*cp++ - '0'); 6716440Swnj if (*cp++ != ' ') 6726440Swnj SCREWUP("size not delimited"); 6736440Swnj if (targisdir) 674*38098Sbostic (void)sprintf(nambuf, "%s%s%s", targ, 6756440Swnj *targ ? "/" : "", cp); 6766440Swnj else 677*38098Sbostic (void)strcpy(nambuf, targ); 6786440Swnj exists = stat(nambuf, &stb) == 0; 67918126Sralph if (cmdbuf[0] == 'D') { 68018126Sralph if (exists) { 6816440Swnj if ((stb.st_mode&S_IFMT) != S_IFDIR) { 6826440Swnj errno = ENOTDIR; 6836440Swnj goto bad; 6846440Swnj } 68523112Slepreau if (pflag) 686*38098Sbostic (void)chmod(nambuf, mode); 68718126Sralph } else if (mkdir(nambuf, mode) < 0) 6886440Swnj goto bad; 6896440Swnj myargv[0] = nambuf; 6906440Swnj sink(1, myargv); 69123101Slepreau if (setimes) { 69223101Slepreau setimes = 0; 69323101Slepreau if (utimes(nambuf, tv) < 0) 69423101Slepreau error("rcp: can't set times on %s: %s\n", 69523101Slepreau nambuf, sys_errlist[errno]); 69623101Slepreau } 6976440Swnj continue; 69818126Sralph } 69932127Sbostic if ((of = open(nambuf, O_WRONLY|O_CREAT, mode)) < 0) { 7006440Swnj bad: 7016440Swnj error("rcp: %s: %s\n", nambuf, sys_errlist[errno]); 7026440Swnj continue; 7036440Swnj } 70423112Slepreau if (exists && pflag) 705*38098Sbostic (void)fchmod(of, mode); 706*38098Sbostic (void)write(rem, "", 1); 70735689Sbostic if ((bp = allocbuf(&buffer, of, BUFSIZ)) == 0) { 708*38098Sbostic (void)close(of); 70921254Smckusick continue; 71021254Smckusick } 71121254Smckusick cp = bp->buf; 71221254Smckusick count = 0; 7136440Swnj wrerr = 0; 7146440Swnj for (i = 0; i < size; i += BUFSIZ) { 71521254Smckusick amt = BUFSIZ; 7166440Swnj if (i + amt > size) 7176440Swnj amt = size - i; 71821254Smckusick count += amt; 7196440Swnj do { 72021254Smckusick j = read(rem, cp, amt); 72124711Sbloom if (j <= 0) { 72224711Sbloom if (j == 0) 72324711Sbloom error("rcp: dropped connection"); 72424711Sbloom else 72524711Sbloom error("rcp: %s\n", 72624711Sbloom sys_errlist[errno]); 7276440Swnj exit(1); 72824711Sbloom } 7296440Swnj amt -= j; 7306440Swnj cp += j; 7316440Swnj } while (amt > 0); 73221254Smckusick if (count == bp->cnt) { 73321254Smckusick if (wrerr == 0 && 73421254Smckusick write(of, bp->buf, count) != count) 73521254Smckusick wrerr++; 73621254Smckusick count = 0; 73721254Smckusick cp = bp->buf; 73821254Smckusick } 7396440Swnj } 74021254Smckusick if (count != 0 && wrerr == 0 && 74121254Smckusick write(of, bp->buf, count) != count) 74221254Smckusick wrerr++; 74332127Sbostic if (ftruncate(of, size)) 74432127Sbostic error("rcp: can't truncate %s: %s\n", 74532127Sbostic nambuf, sys_errlist[errno]); 746*38098Sbostic (void)close(of); 747*38098Sbostic (void)response(); 74823101Slepreau if (setimes) { 74923101Slepreau setimes = 0; 75023101Slepreau if (utimes(nambuf, tv) < 0) 75123101Slepreau error("rcp: can't set times on %s: %s\n", 75223101Slepreau nambuf, sys_errlist[errno]); 75323101Slepreau } 7546440Swnj if (wrerr) 75523101Slepreau error("rcp: %s: %s\n", nambuf, sys_errlist[errno]); 7566440Swnj else 757*38098Sbostic (void)write(rem, "", 1); 7586440Swnj } 7596440Swnj screwup: 7606440Swnj error("rcp: protocol screwup: %s\n", whopp); 7616440Swnj exit(1); 7626440Swnj } 7636440Swnj 764*38098Sbostic BUF * 76521254Smckusick allocbuf(bp, fd, blksize) 766*38098Sbostic BUF *bp; 76721254Smckusick int fd, blksize; 76821254Smckusick { 76921254Smckusick struct stat stb; 77021254Smckusick int size; 771*38098Sbostic char *malloc(); 77221254Smckusick 77321254Smckusick if (fstat(fd, &stb) < 0) { 77421254Smckusick error("rcp: fstat: %s\n", sys_errlist[errno]); 775*38098Sbostic return(0); 77621254Smckusick } 77721254Smckusick size = roundup(stb.st_blksize, blksize); 77821254Smckusick if (size == 0) 77921254Smckusick size = blksize; 78021254Smckusick if (bp->cnt < size) { 78121254Smckusick if (bp->buf != 0) 78221254Smckusick free(bp->buf); 783*38098Sbostic bp->buf = (char *)malloc((u_int)size); 78421254Smckusick if (bp->buf == 0) { 78521254Smckusick error("rcp: malloc: out of memory\n"); 786*38098Sbostic return(0); 78721254Smckusick } 78821254Smckusick } 78921254Smckusick bp->cnt = size; 790*38098Sbostic return(bp); 79121254Smckusick } 79221254Smckusick 793*38098Sbostic /* VARARGS1 */ 7946440Swnj error(fmt, a1, a2, a3, a4, a5) 7956440Swnj char *fmt; 7966440Swnj int a1, a2, a3, a4, a5; 7976440Swnj { 798*38098Sbostic int len; 799*38098Sbostic char buf[BUFSIZ]; 8006440Swnj 801*38098Sbostic ++errs; 802*38098Sbostic buf[0] = 0x01; 803*38098Sbostic (void)sprintf(buf + 1, fmt, a1, a2, a3, a4, a5); 804*38098Sbostic len = strlen(buf); 805*38098Sbostic (void)write(rem, buf, len); 806*38098Sbostic if (!iamremote) 807*38098Sbostic (void)write(2, buf + 1, len - 1); 8086440Swnj } 80932127Sbostic 81032127Sbostic usage() 81132127Sbostic { 812*38098Sbostic #ifdef KERBEROS 813*38098Sbostic (void)fprintf(stderr, "%s\n\t%s\n", 814*38098Sbostic "usage: rcp [-k realm] [-px] f1 f2", 815*38098Sbostic "or: rcp [-k realm] [-rpx] f1 ... fn directory"); 81636626Skfall #else 817*38098Sbostic (void)fprintf(stderr, 818*38098Sbostic "usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn directory\n"); 81936626Skfall #endif 82032127Sbostic exit(1); 82132127Sbostic } 82236624Skfall 823*38098Sbostic #ifdef KERBEROS 82436624Skfall old_warning(str) 825*38098Sbostic char *str; 82636624Skfall { 827*38098Sbostic (void)fprintf(stderr, "rcp: warning: %s, using standard rcp\n", str); 82836624Skfall } 82936624Skfall #endif 830