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 1535619Sbostic * WARRANTIES OF MERCHANTIBILITY 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 2536624Skfall static char sccsid[] = "@(#)rcp.c 5.11 (Berkeley) 9/22/88"; 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> 369199Ssam 379199Ssam #include <netinet/in.h> 389199Ssam 399199Ssam #include <stdio.h> 409199Ssam #include <signal.h> 416440Swnj #include <pwd.h> 426440Swnj #include <ctype.h> 4318026Sralph #include <netdb.h> 446440Swnj #include <errno.h> 45*37037Sbostic #include "pathnames.h" 4612989Ssam 4736624Skfall #ifdef KERBEROS 4836624Skfall #include <kerberos/krb.h> 4936624Skfall char krb_realm[REALM_SZ]; 5036624Skfall int use_kerberos = 1, encrypt = 0; 5136624Skfall CREDENTIALS cred; 5236624Skfall Key_schedule schedule; 5336624Skfall #endif 5436624Skfall 556440Swnj int rem; 5632419Sbostic char *colon(), *index(), *rindex(), *malloc(), *strcpy(); 576440Swnj int errs; 586440Swnj int lostconn(); 596440Swnj int errno; 606440Swnj char *sys_errlist[]; 616440Swnj int iamremote, targetshouldbedirectory; 626440Swnj int iamrecursive; 6323101Slepreau int pflag; 646440Swnj struct passwd *pwd; 656440Swnj struct passwd *getpwuid(); 6618126Sralph int userid; 6718126Sralph int port; 686440Swnj 6921254Smckusick struct buffer { 7021254Smckusick int cnt; 7121254Smckusick char *buf; 7221254Smckusick } *allocbuf(); 7321254Smckusick 746440Swnj /*VARARGS*/ 756440Swnj int error(); 766440Swnj 776440Swnj #define ga() (void) write(rem, "", 1) 786440Swnj 796440Swnj main(argc, argv) 806440Swnj int argc; 816440Swnj char **argv; 826440Swnj { 836440Swnj char *targ, *host, *src; 8418259Sralph char *suser, *tuser, *thost; 856440Swnj int i; 866440Swnj char buf[BUFSIZ], cmd[16]; 8718126Sralph struct servent *sp; 8818026Sralph 8936626Skfall #ifdef KERBEROS 9036626Skfall sp = getservbyname("kshell", "tcp"); 9136626Skfall if(sp == NULL) { 9236626Skfall use_kerberos = 0; 9336626Skfall old_warning("kshell service unknown"); 9436626Skfall sp = getservbyname("kshell", "tcp"); 9536626Skfall } 9636626Skfall #else 9718026Sralph sp = getservbyname("shell", "tcp"); 9836626Skfall #endif 9936626Skfall 10018026Sralph if (sp == NULL) { 10118026Sralph fprintf(stderr, "rcp: shell/tcp: unknown service\n"); 10218026Sralph exit(1); 10318026Sralph } 10418126Sralph port = sp->s_port; 10518126Sralph pwd = getpwuid(userid = getuid()); 1066440Swnj if (pwd == 0) { 1076440Swnj fprintf(stderr, "who are you?\n"); 1086440Swnj exit(1); 1096440Swnj } 11023101Slepreau 11123101Slepreau for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++) { 11223101Slepreau (*argv)++; 11323101Slepreau while (**argv) switch (*(*argv)++) { 11423101Slepreau 11523101Slepreau case 'r': 11623101Slepreau iamrecursive++; 11723101Slepreau break; 11823101Slepreau 11936624Skfall #ifdef KERBEROS 12036624Skfall case 'x': 12136624Skfall encrypt = 1; 12236624Skfall des_set_key(cred.session, schedule); 12336624Skfall break; 12436624Skfall 12536624Skfall case 'k': 12636624Skfall strncpy(krb_realm, ++argv, REALM_SZ); 12736624Skfall break; 12836624Skfall #endif 12936624Skfall 13023101Slepreau case 'p': /* preserve mtimes and atimes */ 13123101Slepreau pflag++; 13223101Slepreau break; 13323101Slepreau 13423101Slepreau /* The rest of these are not for users. */ 13523101Slepreau case 'd': 13623101Slepreau targetshouldbedirectory = 1; 13723101Slepreau break; 13823101Slepreau 13923101Slepreau case 'f': /* "from" */ 14023101Slepreau iamremote = 1; 14123101Slepreau (void) response(); 14223101Slepreau (void) setuid(userid); 14323101Slepreau source(--argc, ++argv); 14423101Slepreau exit(errs); 14523101Slepreau 14623101Slepreau case 't': /* "to" */ 14723101Slepreau iamremote = 1; 14823101Slepreau (void) setuid(userid); 14923101Slepreau sink(--argc, ++argv); 15023101Slepreau exit(errs); 15123101Slepreau 15223101Slepreau default: 15332127Sbostic usage(); 15423101Slepreau } 1556440Swnj } 15632127Sbostic if (argc < 2) 15732127Sbostic usage(); 1586440Swnj if (argc > 2) 1596440Swnj targetshouldbedirectory = 1; 16032127Sbostic rem = -1; 16123101Slepreau (void) sprintf(cmd, "rcp%s%s%s", 16223101Slepreau iamrecursive ? " -r" : "", pflag ? " -p" : "", 16323101Slepreau targetshouldbedirectory ? " -d" : ""); 16423101Slepreau (void) signal(SIGPIPE, lostconn); 1656440Swnj targ = colon(argv[argc - 1]); 16623101Slepreau if (targ) { /* ... to remote */ 1676440Swnj *targ++ = 0; 16813542Ssam if (*targ == 0) 16913542Ssam targ = "."; 17018259Sralph thost = index(argv[argc - 1], '@'); 17118259Sralph if (thost) { 17218259Sralph *thost++ = 0; 17318259Sralph tuser = argv[argc - 1]; 17418259Sralph if (*tuser == '\0') 17524711Sbloom tuser = NULL; 17618259Sralph else if (!okname(tuser)) 1776440Swnj exit(1); 17818259Sralph } else { 17918259Sralph thost = argv[argc - 1]; 18024711Sbloom tuser = NULL; 18118259Sralph } 1826440Swnj for (i = 0; i < argc - 1; i++) { 1836440Swnj src = colon(argv[i]); 18423101Slepreau if (src) { /* remote to remote */ 1856440Swnj *src++ = 0; 18613542Ssam if (*src == 0) 18713738Ssam src = "."; 18818259Sralph host = index(argv[i], '@'); 18918259Sralph if (host) { 19018259Sralph *host++ = 0; 19118259Sralph suser = argv[i]; 19218259Sralph if (*suser == '\0') 19318259Sralph suser = pwd->pw_name; 19418259Sralph else if (!okname(suser)) 1956440Swnj continue; 196*37037Sbostic (void) sprintf(buf, "%s %s -l %s -n %s %s '%s%s%s:%s'", 197*37037Sbostic _PATH_RSH, host, suser, cmd, src, 19831945Sbostic tuser ? tuser : "", 19924711Sbloom tuser ? "@" : "", 20024711Sbloom thost, targ); 20118631Sralph } else 202*37037Sbostic (void) sprintf(buf, "%s %s -n %s %s '%s%s%s:%s'", 203*37037Sbostic _PATH_RSH, argv[i], cmd, src, 20431945Sbostic tuser ? tuser : "", 20524711Sbloom tuser ? "@" : "", 20624711Sbloom thost, targ); 2076440Swnj (void) susystem(buf); 20823101Slepreau } else { /* local to remote */ 2096440Swnj if (rem == -1) { 2106440Swnj (void) sprintf(buf, "%s -t %s", 2116440Swnj cmd, targ); 21218259Sralph host = thost; 21336624Skfall #ifdef KERBEROS 21436624Skfall try_again: 21536624Skfall if(use_kerberos) { 21636624Skfall rem = KSUCCESS; 21736624Skfall if(krb_realm[0] == '\0') 21836624Skfall rem = krb_get_lrealm(krb_realm,1); 21936624Skfall if(rem == KSUCCESS) { 22036624Skfall if(encrypt) { 22136624Skfall rem = krcmd_mutual( 22236624Skfall &host, port, 22336624Skfall tuser ? tuser 22436624Skfall : pwd->pw_name, 22536624Skfall buf, 0, krb_realm, 22636624Skfall &cred, schedule); 22736624Skfall } else { 22836624Skfall 22936624Skfall rem = krcmd( 23036624Skfall &host, 23136624Skfall port, 23236624Skfall tuser ? tuser 23336624Skfall : pwd->pw_name, 23436624Skfall buf, 0, 23536624Skfall krb_realm 23636624Skfall ); 23736624Skfall } 23836624Skfall } else { 23936624Skfall fprintf(stderr, 24036624Skfall "rcp: error getting local realm %s\n", 24136624Skfall krb_err_txt[rem]); 24236624Skfall exit(1); 24336624Skfall } 24436624Skfall if((rem < 0) && errno == ECONNREFUSED) { 24536624Skfall use_kerberos = 0; 24636624Skfall old_warning("remote host doesn't support Kerberos"); 24736626Skfall sp = getservbyname("shell", "tcp"); 24836626Skfall if(sp == NULL) { 24936626Skfall fprintf(stderr, "unknown service shell/tcp\n"); 25036626Skfall exit(1); 25136626Skfall } 25236626Skfall port = sp->s_port; 25336624Skfall goto try_again; 25436624Skfall } 25536624Skfall } else { 25636624Skfall rem = rcmd(&host, port, pwd->pw_name, 25736624Skfall tuser ? tuser : pwd->pw_name, 25836624Skfall buf, 0); 25936624Skfall } 26036624Skfall #else 26136624Skfall 26224711Sbloom rem = rcmd(&host, port, pwd->pw_name, 26324711Sbloom tuser ? tuser : pwd->pw_name, 2646440Swnj buf, 0); 26536624Skfall #endif 2666440Swnj if (rem < 0) 2676440Swnj exit(1); 2686440Swnj if (response() < 0) 2696440Swnj exit(1); 27018126Sralph (void) setuid(userid); 2716440Swnj } 2726440Swnj source(1, argv+i); 2736440Swnj } 2746440Swnj } 27523101Slepreau } else { /* ... to local */ 2766440Swnj if (targetshouldbedirectory) 2776440Swnj verifydir(argv[argc - 1]); 2786440Swnj for (i = 0; i < argc - 1; i++) { 2796440Swnj src = colon(argv[i]); 28023101Slepreau if (src == 0) { /* local to local */ 281*37037Sbostic (void) sprintf(buf, "%s%s%s %s %s", 282*37037Sbostic _PATH_CP, iamrecursive ? " -r" : "", 28323101Slepreau pflag ? " -p" : "", 2846440Swnj argv[i], argv[argc - 1]); 2856440Swnj (void) susystem(buf); 28623101Slepreau } else { /* remote to local */ 2876440Swnj *src++ = 0; 28813542Ssam if (*src == 0) 28913542Ssam src = "."; 29018259Sralph host = index(argv[i], '@'); 29118259Sralph if (host) { 29218259Sralph *host++ = 0; 29318259Sralph suser = argv[i]; 29418259Sralph if (*suser == '\0') 29518259Sralph suser = pwd->pw_name; 29618259Sralph else if (!okname(suser)) 2976440Swnj continue; 29818259Sralph } else { 29918259Sralph host = argv[i]; 3006440Swnj suser = pwd->pw_name; 30118259Sralph } 3026440Swnj (void) sprintf(buf, "%s -f %s", cmd, src); 30336624Skfall #ifdef KERBEROS 30436624Skfall one_more_time: 30536624Skfall if(use_kerberos) { 30636624Skfall rem = KSUCCESS; 30736624Skfall if(krb_realm[0] == '\0') 30836624Skfall rem = krb_get_lrealm(krb_realm,1); 30936624Skfall if(rem == KSUCCESS) { 31036624Skfall if(encrypt) { 31136624Skfall rem = krcmd_mutual( 31236624Skfall &host, 31336624Skfall port, 31436624Skfall suser, 31536624Skfall buf, 0, 31636624Skfall krb_realm, 31736624Skfall &cred, schedule 31836624Skfall ); 31936624Skfall } else { 32036624Skfall rem = krcmd( 32136624Skfall &host, 32236624Skfall port, 32336624Skfall suser, 32436624Skfall buf, 0, 32536624Skfall krb_realm 32636624Skfall ); 32736624Skfall } 32836624Skfall } else { 32936624Skfall fprintf(stderr, 33036624Skfall "rcp: error getting local realm %s\n", 33136624Skfall krb_err_txt[rem]); 33236624Skfall exit(1); 33336624Skfall } 33436624Skfall if((rem < 0) && errno == ECONNREFUSED) { 33536624Skfall use_kerberos = 0; 33636624Skfall old_warning("remote host doesn't suport Kerberos"); 33736626Skfall sp = getservbyname("shell", "tcp"); 33836626Skfall if(sp == NULL) { 33936626Skfall fprintf(stderr, "unknown service shell/tcp\n"); 34036626Skfall exit(1); 34136626Skfall } 34236626Skfall port = sp->s_port; 34336624Skfall goto one_more_time; 34436624Skfall } 34536624Skfall } else { 34636624Skfall rem = rcmd(&host, port, pwd->pw_name, suser, 34736624Skfall buf, 0); 34836624Skfall } 34936624Skfall #else 35018126Sralph rem = rcmd(&host, port, pwd->pw_name, suser, 35136624Skfall buf, 0); 35236624Skfall #endif 3536440Swnj if (rem < 0) 35418259Sralph continue; 35518126Sralph (void) setreuid(0, userid); 3566440Swnj sink(1, argv+argc-1); 35718126Sralph (void) setreuid(userid, 0); 3586440Swnj (void) close(rem); 3596440Swnj rem = -1; 3606440Swnj } 3616440Swnj } 3626440Swnj } 3636440Swnj exit(errs); 3646440Swnj } 3656440Swnj 3666440Swnj verifydir(cp) 3676440Swnj char *cp; 3686440Swnj { 3696440Swnj struct stat stb; 3706440Swnj 37118126Sralph if (stat(cp, &stb) >= 0) { 37218126Sralph if ((stb.st_mode & S_IFMT) == S_IFDIR) 37318126Sralph return; 37418126Sralph errno = ENOTDIR; 37518126Sralph } 3766440Swnj error("rcp: %s: %s.\n", cp, sys_errlist[errno]); 3776440Swnj exit(1); 3786440Swnj } 3796440Swnj 3806440Swnj char * 3816440Swnj colon(cp) 3826440Swnj char *cp; 3836440Swnj { 3846440Swnj 3856440Swnj while (*cp) { 3866440Swnj if (*cp == ':') 3876440Swnj return (cp); 3886440Swnj if (*cp == '/') 3896440Swnj return (0); 3906440Swnj cp++; 3916440Swnj } 3926440Swnj return (0); 3936440Swnj } 3946440Swnj 3956440Swnj okname(cp0) 3966440Swnj char *cp0; 3976440Swnj { 3986440Swnj register char *cp = cp0; 3996440Swnj register int c; 4006440Swnj 4016440Swnj do { 4026440Swnj c = *cp; 4036440Swnj if (c & 0200) 4046440Swnj goto bad; 4056440Swnj if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') 4066440Swnj goto bad; 4076440Swnj cp++; 4086440Swnj } while (*cp); 4096440Swnj return (1); 4106440Swnj bad: 4116440Swnj fprintf(stderr, "rcp: invalid user name %s\n", cp0); 4126440Swnj return (0); 4136440Swnj } 4146440Swnj 41517999Sserge susystem(s) 41617999Sserge char *s; 4176440Swnj { 41817999Sserge int status, pid, w; 41917999Sserge register int (*istat)(), (*qstat)(); 4206440Swnj 42117999Sserge if ((pid = vfork()) == 0) { 42223101Slepreau (void) setuid(userid); 423*37037Sbostic execl(_PATH_BSHELL, "sh", "-c", s, (char *)0); 42417999Sserge _exit(127); 42517999Sserge } 42617999Sserge istat = signal(SIGINT, SIG_IGN); 42717999Sserge qstat = signal(SIGQUIT, SIG_IGN); 42817999Sserge while ((w = wait(&status)) != pid && w != -1) 42917999Sserge ; 43017999Sserge if (w == -1) 43117999Sserge status = -1; 43223101Slepreau (void) signal(SIGINT, istat); 43323101Slepreau (void) signal(SIGQUIT, qstat); 43417999Sserge return (status); 4356440Swnj } 4366440Swnj 4376440Swnj source(argc, argv) 4386440Swnj int argc; 4396440Swnj char **argv; 4406440Swnj { 4416440Swnj char *last, *name; 4426440Swnj struct stat stb; 44321254Smckusick static struct buffer buffer; 44421254Smckusick struct buffer *bp; 44532268Sbostic int x, readerr, f, amt; 44621254Smckusick off_t i; 4476440Swnj char buf[BUFSIZ]; 4486440Swnj 4496440Swnj for (x = 0; x < argc; x++) { 4506440Swnj name = argv[x]; 45118126Sralph if ((f = open(name, 0)) < 0) { 4526440Swnj error("rcp: %s: %s\n", name, sys_errlist[errno]); 4536440Swnj continue; 4546440Swnj } 4556440Swnj if (fstat(f, &stb) < 0) 4566440Swnj goto notreg; 4576440Swnj switch (stb.st_mode&S_IFMT) { 4586440Swnj 4596440Swnj case S_IFREG: 4606440Swnj break; 4616440Swnj 4626440Swnj case S_IFDIR: 4636440Swnj if (iamrecursive) { 4646440Swnj (void) close(f); 46523101Slepreau rsource(name, &stb); 4666440Swnj continue; 4676440Swnj } 4686440Swnj /* fall into ... */ 4696440Swnj default: 4706440Swnj notreg: 4716440Swnj (void) close(f); 4726440Swnj error("rcp: %s: not a plain file\n", name); 4736440Swnj continue; 4746440Swnj } 4756440Swnj last = rindex(name, '/'); 4766440Swnj if (last == 0) 4776440Swnj last = name; 4786440Swnj else 4796440Swnj last++; 48023101Slepreau if (pflag) { 48123101Slepreau /* 48223101Slepreau * Make it compatible with possible future 48323101Slepreau * versions expecting microseconds. 48423101Slepreau */ 48523101Slepreau (void) sprintf(buf, "T%ld 0 %ld 0\n", 48623101Slepreau stb.st_mtime, stb.st_atime); 48723101Slepreau (void) write(rem, buf, strlen(buf)); 48823101Slepreau if (response() < 0) { 48923101Slepreau (void) close(f); 49023101Slepreau continue; 49123101Slepreau } 49223101Slepreau } 49323101Slepreau (void) sprintf(buf, "C%04o %ld %s\n", 4946440Swnj stb.st_mode&07777, stb.st_size, last); 4956440Swnj (void) write(rem, buf, strlen(buf)); 4966440Swnj if (response() < 0) { 4976440Swnj (void) close(f); 4986440Swnj continue; 4996440Swnj } 50035689Sbostic if ((bp = allocbuf(&buffer, f, BUFSIZ)) == 0) { 50121254Smckusick (void) close(f); 50221254Smckusick continue; 50321254Smckusick } 50432268Sbostic readerr = 0; 50521254Smckusick for (i = 0; i < stb.st_size; i += bp->cnt) { 50621254Smckusick amt = bp->cnt; 5076440Swnj if (i + amt > stb.st_size) 5086440Swnj amt = stb.st_size - i; 50932268Sbostic if (readerr == 0 && read(f, bp->buf, amt) != amt) 51032268Sbostic readerr = errno; 51121254Smckusick (void) write(rem, bp->buf, amt); 5126440Swnj } 5136440Swnj (void) close(f); 51432268Sbostic if (readerr == 0) 5156440Swnj ga(); 5166440Swnj else 51732268Sbostic error("rcp: %s: %s\n", name, sys_errlist[readerr]); 5186440Swnj (void) response(); 5196440Swnj } 5206440Swnj } 5216440Swnj 52213542Ssam #include <sys/dir.h> 5236440Swnj 52423101Slepreau rsource(name, statp) 5256440Swnj char *name; 52623101Slepreau struct stat *statp; 5276440Swnj { 5286440Swnj DIR *d = opendir(name); 5296440Swnj char *last; 5306440Swnj struct direct *dp; 5316440Swnj char buf[BUFSIZ]; 5326440Swnj char *bufv[1]; 5336440Swnj 5346440Swnj if (d == 0) { 53518126Sralph error("rcp: %s: %s\n", name, sys_errlist[errno]); 5366440Swnj return; 5376440Swnj } 5386440Swnj last = rindex(name, '/'); 5396440Swnj if (last == 0) 5406440Swnj last = name; 5416440Swnj else 5426440Swnj last++; 54323101Slepreau if (pflag) { 54423101Slepreau (void) sprintf(buf, "T%ld 0 %ld 0\n", 54523101Slepreau statp->st_mtime, statp->st_atime); 54623101Slepreau (void) write(rem, buf, strlen(buf)); 54723101Slepreau if (response() < 0) { 54823101Slepreau closedir(d); 54923101Slepreau return; 55023101Slepreau } 55123101Slepreau } 55223101Slepreau (void) sprintf(buf, "D%04o %d %s\n", statp->st_mode&07777, 0, last); 5536440Swnj (void) write(rem, buf, strlen(buf)); 5546440Swnj if (response() < 0) { 5556440Swnj closedir(d); 5566440Swnj return; 5576440Swnj } 5586440Swnj while (dp = readdir(d)) { 5596440Swnj if (dp->d_ino == 0) 5606440Swnj continue; 5616440Swnj if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 5626440Swnj continue; 5636440Swnj if (strlen(name) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) { 5646440Swnj error("%s/%s: Name too long.\n", name, dp->d_name); 5656440Swnj continue; 5666440Swnj } 5676440Swnj (void) sprintf(buf, "%s/%s", name, dp->d_name); 5686440Swnj bufv[0] = buf; 5696440Swnj source(1, bufv); 5706440Swnj } 5716440Swnj closedir(d); 5726440Swnj (void) write(rem, "E\n", 2); 5736440Swnj (void) response(); 5746440Swnj } 5756440Swnj 5766440Swnj response() 5776440Swnj { 5786440Swnj char resp, c, rbuf[BUFSIZ], *cp = rbuf; 5796440Swnj 5806440Swnj if (read(rem, &resp, 1) != 1) 5816440Swnj lostconn(); 5826440Swnj switch (resp) { 5836440Swnj 58423101Slepreau case 0: /* ok */ 5856440Swnj return (0); 5866440Swnj 5876440Swnj default: 5886440Swnj *cp++ = resp; 5896440Swnj /* fall into... */ 59023101Slepreau case 1: /* error, followed by err msg */ 59123101Slepreau case 2: /* fatal error, "" */ 5926440Swnj do { 5936440Swnj if (read(rem, &c, 1) != 1) 5946440Swnj lostconn(); 5956440Swnj *cp++ = c; 5966440Swnj } while (cp < &rbuf[BUFSIZ] && c != '\n'); 5976440Swnj if (iamremote == 0) 5986440Swnj (void) write(2, rbuf, cp - rbuf); 5996440Swnj errs++; 6006440Swnj if (resp == 1) 6016440Swnj return (-1); 6026440Swnj exit(1); 6036440Swnj } 6046440Swnj /*NOTREACHED*/ 6056440Swnj } 6066440Swnj 6076440Swnj lostconn() 6086440Swnj { 6096440Swnj 6106440Swnj if (iamremote == 0) 6116440Swnj fprintf(stderr, "rcp: lost connection\n"); 6126440Swnj exit(1); 6136440Swnj } 6146440Swnj 6156440Swnj sink(argc, argv) 6166440Swnj int argc; 6176440Swnj char **argv; 6186440Swnj { 61921254Smckusick off_t i, j; 62021254Smckusick char *targ, *whopp, *cp; 62121254Smckusick int of, mode, wrerr, exists, first, count, amt, size; 62221254Smckusick struct buffer *bp; 62321254Smckusick static struct buffer buffer; 62421254Smckusick struct stat stb; 62521254Smckusick int targisdir = 0; 6266440Swnj int mask = umask(0); 6276440Swnj char *myargv[1]; 62823101Slepreau char cmdbuf[BUFSIZ], nambuf[BUFSIZ]; 62923101Slepreau int setimes = 0; 63023101Slepreau struct timeval tv[2]; 63123101Slepreau #define atime tv[0] 63223101Slepreau #define mtime tv[1] 63321254Smckusick #define SCREWUP(str) { whopp = str; goto screwup; } 6346440Swnj 63523112Slepreau if (!pflag) 63623112Slepreau (void) umask(mask); 63718126Sralph if (argc != 1) { 6386440Swnj error("rcp: ambiguous target\n"); 6396440Swnj exit(1); 6406440Swnj } 6416440Swnj targ = *argv; 6426440Swnj if (targetshouldbedirectory) 6436440Swnj verifydir(targ); 6446440Swnj ga(); 6456440Swnj if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR) 6466440Swnj targisdir = 1; 64714580Sralph for (first = 1; ; first = 0) { 6486440Swnj cp = cmdbuf; 6496440Swnj if (read(rem, cp, 1) <= 0) 6506440Swnj return; 6516440Swnj if (*cp++ == '\n') 6526440Swnj SCREWUP("unexpected '\\n'"); 6536440Swnj do { 6546440Swnj if (read(rem, cp, 1) != 1) 6556440Swnj SCREWUP("lost connection"); 6566440Swnj } while (*cp++ != '\n'); 6576440Swnj *cp = 0; 6586440Swnj if (cmdbuf[0] == '\01' || cmdbuf[0] == '\02') { 6596440Swnj if (iamremote == 0) 66013542Ssam (void) write(2, cmdbuf+1, strlen(cmdbuf+1)); 6616440Swnj if (cmdbuf[0] == '\02') 6626440Swnj exit(1); 6636440Swnj errs++; 6646440Swnj continue; 6656440Swnj } 6666440Swnj *--cp = 0; 6676440Swnj cp = cmdbuf; 6686440Swnj if (*cp == 'E') { 6696440Swnj ga(); 6706440Swnj return; 6716440Swnj } 67223101Slepreau 67323101Slepreau #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0'); 67423101Slepreau if (*cp == 'T') { 67523101Slepreau setimes++; 67623101Slepreau cp++; 67723101Slepreau getnum(mtime.tv_sec); 67823101Slepreau if (*cp++ != ' ') 67923101Slepreau SCREWUP("mtime.sec not delimited"); 68023101Slepreau getnum(mtime.tv_usec); 68123101Slepreau if (*cp++ != ' ') 68223101Slepreau SCREWUP("mtime.usec not delimited"); 68323101Slepreau getnum(atime.tv_sec); 68423101Slepreau if (*cp++ != ' ') 68523101Slepreau SCREWUP("atime.sec not delimited"); 68623101Slepreau getnum(atime.tv_usec); 68723101Slepreau if (*cp++ != '\0') 68823101Slepreau SCREWUP("atime.usec not delimited"); 68923101Slepreau ga(); 69023101Slepreau continue; 69123101Slepreau } 69214580Sralph if (*cp != 'C' && *cp != 'D') { 69314580Sralph /* 69414580Sralph * Check for the case "rcp remote:foo\* local:bar". 69514580Sralph * In this case, the line "No match." can be returned 69614580Sralph * by the shell before the rcp command on the remote is 69714580Sralph * executed so the ^Aerror_message convention isn't 69814580Sralph * followed. 69914580Sralph */ 70014580Sralph if (first) { 70114580Sralph error("%s\n", cp); 70214580Sralph exit(1); 70314580Sralph } 7046440Swnj SCREWUP("expected control record"); 70514580Sralph } 7066440Swnj cp++; 7076440Swnj mode = 0; 7086440Swnj for (; cp < cmdbuf+5; cp++) { 7096440Swnj if (*cp < '0' || *cp > '7') 7106440Swnj SCREWUP("bad mode"); 7116440Swnj mode = (mode << 3) | (*cp - '0'); 7126440Swnj } 7136440Swnj if (*cp++ != ' ') 7146440Swnj SCREWUP("mode not delimited"); 7156440Swnj size = 0; 71623112Slepreau while (isdigit(*cp)) 7176440Swnj size = size * 10 + (*cp++ - '0'); 7186440Swnj if (*cp++ != ' ') 7196440Swnj SCREWUP("size not delimited"); 7206440Swnj if (targisdir) 7216440Swnj (void) sprintf(nambuf, "%s%s%s", targ, 7226440Swnj *targ ? "/" : "", cp); 7236440Swnj else 7246440Swnj (void) strcpy(nambuf, targ); 7256440Swnj exists = stat(nambuf, &stb) == 0; 72618126Sralph if (cmdbuf[0] == 'D') { 72718126Sralph if (exists) { 7286440Swnj if ((stb.st_mode&S_IFMT) != S_IFDIR) { 7296440Swnj errno = ENOTDIR; 7306440Swnj goto bad; 7316440Swnj } 73223112Slepreau if (pflag) 73323112Slepreau (void) chmod(nambuf, mode); 73418126Sralph } else if (mkdir(nambuf, mode) < 0) 7356440Swnj goto bad; 7366440Swnj myargv[0] = nambuf; 7376440Swnj sink(1, myargv); 73823101Slepreau if (setimes) { 73923101Slepreau setimes = 0; 74023101Slepreau if (utimes(nambuf, tv) < 0) 74123101Slepreau error("rcp: can't set times on %s: %s\n", 74223101Slepreau nambuf, sys_errlist[errno]); 74323101Slepreau } 7446440Swnj continue; 74518126Sralph } 74632127Sbostic if ((of = open(nambuf, O_WRONLY|O_CREAT, mode)) < 0) { 7476440Swnj bad: 7486440Swnj error("rcp: %s: %s\n", nambuf, sys_errlist[errno]); 7496440Swnj continue; 7506440Swnj } 75123112Slepreau if (exists && pflag) 75223112Slepreau (void) fchmod(of, mode); 7536440Swnj ga(); 75435689Sbostic if ((bp = allocbuf(&buffer, of, BUFSIZ)) == 0) { 75523101Slepreau (void) close(of); 75621254Smckusick continue; 75721254Smckusick } 75821254Smckusick cp = bp->buf; 75921254Smckusick count = 0; 7606440Swnj wrerr = 0; 7616440Swnj for (i = 0; i < size; i += BUFSIZ) { 76221254Smckusick amt = BUFSIZ; 7636440Swnj if (i + amt > size) 7646440Swnj amt = size - i; 76521254Smckusick count += amt; 7666440Swnj do { 76721254Smckusick j = read(rem, cp, amt); 76824711Sbloom if (j <= 0) { 76924711Sbloom if (j == 0) 77024711Sbloom error("rcp: dropped connection"); 77124711Sbloom else 77224711Sbloom error("rcp: %s\n", 77324711Sbloom sys_errlist[errno]); 7746440Swnj exit(1); 77524711Sbloom } 7766440Swnj amt -= j; 7776440Swnj cp += j; 7786440Swnj } while (amt > 0); 77921254Smckusick if (count == bp->cnt) { 78021254Smckusick if (wrerr == 0 && 78121254Smckusick write(of, bp->buf, count) != count) 78221254Smckusick wrerr++; 78321254Smckusick count = 0; 78421254Smckusick cp = bp->buf; 78521254Smckusick } 7866440Swnj } 78721254Smckusick if (count != 0 && wrerr == 0 && 78821254Smckusick write(of, bp->buf, count) != count) 78921254Smckusick wrerr++; 79032127Sbostic if (ftruncate(of, size)) 79132127Sbostic error("rcp: can't truncate %s: %s\n", 79232127Sbostic nambuf, sys_errlist[errno]); 7936440Swnj (void) close(of); 7946440Swnj (void) response(); 79523101Slepreau if (setimes) { 79623101Slepreau setimes = 0; 79723101Slepreau if (utimes(nambuf, tv) < 0) 79823101Slepreau error("rcp: can't set times on %s: %s\n", 79923101Slepreau nambuf, sys_errlist[errno]); 80023101Slepreau } 8016440Swnj if (wrerr) 80223101Slepreau error("rcp: %s: %s\n", nambuf, sys_errlist[errno]); 8036440Swnj else 8046440Swnj ga(); 8056440Swnj } 8066440Swnj screwup: 8076440Swnj error("rcp: protocol screwup: %s\n", whopp); 8086440Swnj exit(1); 8096440Swnj } 8106440Swnj 81121254Smckusick struct buffer * 81221254Smckusick allocbuf(bp, fd, blksize) 81321254Smckusick struct buffer *bp; 81421254Smckusick int fd, blksize; 81521254Smckusick { 81621254Smckusick struct stat stb; 81721254Smckusick int size; 81821254Smckusick 81921254Smckusick if (fstat(fd, &stb) < 0) { 82021254Smckusick error("rcp: fstat: %s\n", sys_errlist[errno]); 82135689Sbostic return ((struct buffer *)0); 82221254Smckusick } 82321254Smckusick size = roundup(stb.st_blksize, blksize); 82421254Smckusick if (size == 0) 82521254Smckusick size = blksize; 82621254Smckusick if (bp->cnt < size) { 82721254Smckusick if (bp->buf != 0) 82821254Smckusick free(bp->buf); 82923101Slepreau bp->buf = (char *)malloc((unsigned) size); 83021254Smckusick if (bp->buf == 0) { 83121254Smckusick error("rcp: malloc: out of memory\n"); 83235689Sbostic return ((struct buffer *)0); 83321254Smckusick } 83421254Smckusick } 83521254Smckusick bp->cnt = size; 83621254Smckusick return (bp); 83721254Smckusick } 83821254Smckusick 83923101Slepreau /*VARARGS1*/ 8406440Swnj error(fmt, a1, a2, a3, a4, a5) 8416440Swnj char *fmt; 8426440Swnj int a1, a2, a3, a4, a5; 8436440Swnj { 8446440Swnj char buf[BUFSIZ], *cp = buf; 8456440Swnj 8466440Swnj errs++; 8476440Swnj *cp++ = 1; 8486440Swnj (void) sprintf(cp, fmt, a1, a2, a3, a4, a5); 8496440Swnj (void) write(rem, buf, strlen(buf)); 8506440Swnj if (iamremote == 0) 8516440Swnj (void) write(2, buf+1, strlen(buf+1)); 8526440Swnj } 85332127Sbostic 85432127Sbostic usage() 85532127Sbostic { 85636626Skfall #ifdef KERBEROS 85736626Skfall fputs("usage: rcp [-k realm] [-x] [-p] f1 f2;\n", stderr); 85836626Skfall fputs(" or: rcp [-k realm] [-x] [-rp] f1 ... fn d2\n", stderr); 85936626Skfall #else 86032127Sbostic fputs("usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn d2\n", stderr); 86136626Skfall #endif 86232127Sbostic exit(1); 86332127Sbostic } 86436624Skfall 86536624Skfall #ifdef KERBEROS 86636624Skfall old_warning(str) 86736624Skfall char *str; 86836624Skfall { 86936626Skfall fprintf(stderr,"Warning: %s, using standard rcp\n", str); 87036624Skfall } 87136624Skfall #endif 872