121569Sdist /*
260688Sbostic * Copyright (c) 1983, 1990, 1992, 1993
360688Sbostic * The Regents of the University of California. All rights reserved.
435619Sbostic *
542539Sbostic * %sccs.include.redist.c%
621569Sdist */
721569Sdist
86440Swnj #ifndef lint
960688Sbostic static char copyright[] =
1060688Sbostic "@(#) Copyright (c) 1983, 1990, 1992, 1993\n\
1160688Sbostic The Regents of the University of California. All rights reserved.\n";
1235619Sbostic #endif /* not lint */
136440Swnj
1421569Sdist #ifndef lint
15*66619Spendry static char sccsid[] = "@(#)rcp.c 8.2 (Berkeley) 04/02/94";
1635619Sbostic #endif /* not lint */
1721569Sdist
186720Smckusick #include <sys/param.h>
196440Swnj #include <sys/stat.h>
2023101Slepreau #include <sys/time.h>
2146655Sbostic #include <sys/socket.h>
229199Ssam #include <netinet/in.h>
2344342Skarels #include <netinet/in_systm.h>
2444342Skarels #include <netinet/ip.h>
2554151Sbostic
2656587Sbostic #include <ctype.h>
2746655Sbostic #include <dirent.h>
2859512Sbostic #include <err.h>
2956587Sbostic #include <errno.h>
3046655Sbostic #include <fcntl.h>
3156587Sbostic #include <netdb.h>
326440Swnj #include <pwd.h>
3356587Sbostic #include <signal.h>
3438098Sbostic #include <stdio.h>
3545647Storek #include <stdlib.h>
3646655Sbostic #include <string.h>
3756587Sbostic #include <string.h>
3856587Sbostic #include <unistd.h>
3956587Sbostic
4037037Sbostic #include "pathnames.h"
4154151Sbostic #include "extern.h"
4212989Ssam
4338098Sbostic #ifdef KERBEROS
4442498Sbostic #include <kerberosIV/des.h>
4541785Sbostic #include <kerberosIV/krb.h>
4654151Sbostic
4738879Skfall char dst_realm_buf[REALM_SZ];
4838879Skfall char *dest_realm = NULL;
4945397Smckusick int use_kerberos = 1;
5038879Skfall CREDENTIALS cred;
5138879Skfall Key_schedule schedule;
5238879Skfall extern char *krb_realmofhost();
5359512Sbostic #ifdef CRYPT
5459512Sbostic int doencrypt = 0;
5559512Sbostic #define OPTIONS "dfKk:prtx"
5659512Sbostic #else
5754151Sbostic #define OPTIONS "dfKk:prt"
5859512Sbostic #endif
5954151Sbostic #else
6038879Skfall #define OPTIONS "dfprt"
6136624Skfall #endif
6236624Skfall
6338098Sbostic struct passwd *pwd;
6438879Skfall u_short port;
6538879Skfall uid_t userid;
6638879Skfall int errs, rem;
6738879Skfall int pflag, iamremote, iamrecursive, targetshouldbedirectory;
686440Swnj
6938879Skfall #define CMDNEEDS 64
7038100Sbostic char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */
7138098Sbostic
7254151Sbostic #ifdef KERBEROS
7354151Sbostic int kerberos __P((char **, char *, char *, char *));
7454151Sbostic void oldw __P((const char *, ...));
7554151Sbostic #endif
7654151Sbostic int response __P((void));
7754151Sbostic void rsource __P((char *, struct stat *));
7854151Sbostic void sink __P((int, char *[]));
7954151Sbostic void source __P((int, char *[]));
8054151Sbostic void tolocal __P((int, char *[]));
8154151Sbostic void toremote __P((char *, int, char *[]));
8254151Sbostic void usage __P((void));
8321254Smckusick
8454151Sbostic int
main(argc,argv)856440Swnj main(argc, argv)
866440Swnj int argc;
8754151Sbostic char *argv[];
886440Swnj {
8918126Sralph struct servent *sp;
9038099Sbostic int ch, fflag, tflag;
9154151Sbostic char *targ, *shell;
9218026Sralph
9338099Sbostic fflag = tflag = 0;
9438879Skfall while ((ch = getopt(argc, argv, OPTIONS)) != EOF)
9554151Sbostic switch(ch) { /* User-visible flags. */
9654151Sbostic case 'K':
9754151Sbostic #ifdef KERBEROS
9854151Sbostic use_kerberos = 0;
9954151Sbostic #endif
10023101Slepreau break;
10138879Skfall #ifdef KERBEROS
10238879Skfall case 'k':
10338879Skfall dest_realm = dst_realm_buf;
10454151Sbostic (void)strncpy(dst_realm_buf, optarg, REALM_SZ);
10538099Sbostic break;
10659512Sbostic #ifdef CRYPT
10759512Sbostic case 'x':
10859512Sbostic doencrypt = 1;
10959512Sbostic /* des_set_key(cred.session, schedule); */
11059512Sbostic break;
11138098Sbostic #endif
11259512Sbostic #endif
11354151Sbostic case 'p':
11454151Sbostic pflag = 1;
11554151Sbostic break;
11654151Sbostic case 'r':
11754151Sbostic iamrecursive = 1;
11854151Sbostic break;
11954151Sbostic /* Server options. */
12038879Skfall case 'd':
12138879Skfall targetshouldbedirectory = 1;
12238879Skfall break;
12338879Skfall case 'f': /* "from" */
12438879Skfall iamremote = 1;
12538879Skfall fflag = 1;
12638879Skfall break;
12738879Skfall case 't': /* "to" */
12838879Skfall iamremote = 1;
12938879Skfall tflag = 1;
13038879Skfall break;
13138098Sbostic case '?':
13238098Sbostic default:
13332127Sbostic usage();
13423101Slepreau }
13538098Sbostic argc -= optind;
13638098Sbostic argv += optind;
13738098Sbostic
13838879Skfall #ifdef KERBEROS
13954151Sbostic if (use_kerberos) {
14059512Sbostic #ifdef CRYPT
14159512Sbostic shell = doencrypt ? "ekshell" : "kshell";
14259512Sbostic #else
14354151Sbostic shell = "kshell";
14459512Sbostic #endif
14554151Sbostic if ((sp = getservbyname(shell, "tcp")) == NULL) {
14654151Sbostic use_kerberos = 0;
14754151Sbostic oldw("can't get entry for %s/tcp service", shell);
14854151Sbostic sp = getservbyname(shell = "shell", "tcp");
14954151Sbostic }
15054151Sbostic } else
15145647Storek sp = getservbyname(shell = "shell", "tcp");
15238879Skfall #else
15345647Storek sp = getservbyname(shell = "shell", "tcp");
15438879Skfall #endif
15559512Sbostic if (sp == NULL)
15659512Sbostic errx(1, "%s/tcp: unknown service", shell);
15738879Skfall port = sp->s_port;
15838879Skfall
15959512Sbostic if ((pwd = getpwuid(userid = getuid())) == NULL)
16059512Sbostic errx(1, "unknown user %d", (int)userid);
16138879Skfall
16254151Sbostic rem = STDIN_FILENO; /* XXX */
16354151Sbostic
16454151Sbostic if (fflag) { /* Follow "protocol", send data. */
16538099Sbostic (void)response();
16638099Sbostic (void)setuid(userid);
16738099Sbostic source(argc, argv);
16838099Sbostic exit(errs);
16938099Sbostic }
17038099Sbostic
17154151Sbostic if (tflag) { /* Receive data. */
17238099Sbostic (void)setuid(userid);
17338099Sbostic sink(argc, argv);
17438099Sbostic exit(errs);
17538099Sbostic }
17638099Sbostic
17732127Sbostic if (argc < 2)
17832127Sbostic usage();
1796440Swnj if (argc > 2)
1806440Swnj targetshouldbedirectory = 1;
18138098Sbostic
18232127Sbostic rem = -1;
18354151Sbostic /* Command to be executed on remote system using "rsh". */
18438879Skfall #ifdef KERBEROS
18546655Sbostic (void)snprintf(cmd, sizeof(cmd),
18646655Sbostic "rcp%s%s%s%s", iamrecursive ? " -r" : "",
18759512Sbostic #ifdef CRYPT
18859512Sbostic (doencrypt && use_kerberos ? " -x" : ""),
18959512Sbostic #else
19045397Smckusick "",
19159512Sbostic #endif
19238879Skfall pflag ? " -p" : "", targetshouldbedirectory ? " -d" : "");
19338879Skfall #else
19446655Sbostic (void)snprintf(cmd, sizeof(cmd), "rcp%s%s%s",
19546655Sbostic iamrecursive ? " -r" : "", pflag ? " -p" : "",
19646655Sbostic targetshouldbedirectory ? " -d" : "");
19738879Skfall #endif
19838098Sbostic
19938098Sbostic (void)signal(SIGPIPE, lostconn);
20038098Sbostic
20154151Sbostic if (targ = colon(argv[argc - 1])) /* Dest is remote host. */
20254151Sbostic toremote(targ, argc, argv);
20338098Sbostic else {
20454151Sbostic tolocal(argc, argv); /* Dest is local host. */
20538098Sbostic if (targetshouldbedirectory)
20638098Sbostic verifydir(argv[argc - 1]);
20738098Sbostic }
20838098Sbostic exit(errs);
20938098Sbostic }
21038098Sbostic
21154151Sbostic void
toremote(targ,argc,argv)21238098Sbostic toremote(targ, argc, argv)
21354151Sbostic char *targ, *argv[];
21438098Sbostic int argc;
21538098Sbostic {
21646655Sbostic int i, len, tos;
21738100Sbostic char *bp, *host, *src, *suser, *thost, *tuser;
21838098Sbostic
21938098Sbostic *targ++ = 0;
22038098Sbostic if (*targ == 0)
22138098Sbostic targ = ".";
22238098Sbostic
22359512Sbostic if (thost = strchr(argv[argc - 1], '@')) {
22438879Skfall /* user@host */
22538098Sbostic *thost++ = 0;
22638098Sbostic tuser = argv[argc - 1];
22738098Sbostic if (*tuser == '\0')
22824711Sbloom tuser = NULL;
22938098Sbostic else if (!okname(tuser))
23038098Sbostic exit(1);
23138098Sbostic } else {
23238098Sbostic thost = argv[argc - 1];
23338098Sbostic tuser = NULL;
23438098Sbostic }
23536624Skfall
23638098Sbostic for (i = 0; i < argc - 1; i++) {
23738098Sbostic src = colon(argv[i]);
23838098Sbostic if (src) { /* remote to remote */
23938098Sbostic *src++ = 0;
24038098Sbostic if (*src == 0)
24138098Sbostic src = ".";
24259512Sbostic host = strchr(argv[i], '@');
24346655Sbostic len = strlen(_PATH_RSH) + strlen(argv[i]) +
24446655Sbostic strlen(src) + (tuser ? strlen(tuser) : 0) +
24546655Sbostic strlen(thost) + strlen(targ) + CMDNEEDS + 20;
24646655Sbostic if (!(bp = malloc(len)))
24759512Sbostic err(1, NULL);
24838098Sbostic if (host) {
24938098Sbostic *host++ = 0;
25038098Sbostic suser = argv[i];
25138098Sbostic if (*suser == '\0')
25238098Sbostic suser = pwd->pw_name;
25338098Sbostic else if (!okname(suser))
25438098Sbostic continue;
25546655Sbostic (void)snprintf(bp, len,
25638098Sbostic "%s %s -l %s -n %s %s '%s%s%s:%s'",
25738098Sbostic _PATH_RSH, host, suser, cmd, src,
25838098Sbostic tuser ? tuser : "", tuser ? "@" : "",
25938098Sbostic thost, targ);
26038098Sbostic } else
26146655Sbostic (void)snprintf(bp, len,
262*66619Spendry "exec %s %s -n %s %s '%s%s%s:%s'",
26338098Sbostic _PATH_RSH, argv[i], cmd, src,
26438098Sbostic tuser ? tuser : "", tuser ? "@" : "",
26538098Sbostic thost, targ);
26654151Sbostic (void)susystem(bp, userid);
26738100Sbostic (void)free(bp);
26838098Sbostic } else { /* local to remote */
26938098Sbostic if (rem == -1) {
27046655Sbostic len = strlen(targ) + CMDNEEDS + 20;
27146655Sbostic if (!(bp = malloc(len)))
27259512Sbostic err(1, NULL);
27346655Sbostic (void)snprintf(bp, len, "%s -t %s", cmd, targ);
27438098Sbostic host = thost;
27538098Sbostic #ifdef KERBEROS
27638098Sbostic if (use_kerberos)
27738879Skfall rem = kerberos(&host, bp,
27838879Skfall pwd->pw_name,
27938100Sbostic tuser ? tuser : pwd->pw_name);
28038098Sbostic else
28138098Sbostic #endif
28224711Sbloom rem = rcmd(&host, port, pwd->pw_name,
28324711Sbloom tuser ? tuser : pwd->pw_name,
28438100Sbostic bp, 0);
28538098Sbostic if (rem < 0)
28638098Sbostic exit(1);
28744342Skarels tos = IPTOS_THROUGHPUT;
28844342Skarels if (setsockopt(rem, IPPROTO_IP, IP_TOS,
28954151Sbostic &tos, sizeof(int)) < 0)
29059512Sbostic warn("TOS (ignored)");
29138098Sbostic if (response() < 0)
29238098Sbostic exit(1);
29338100Sbostic (void)free(bp);
29438098Sbostic (void)setuid(userid);
2956440Swnj }
29638098Sbostic source(1, argv+i);
2976440Swnj }
29838098Sbostic }
29938098Sbostic }
30038098Sbostic
30154151Sbostic void
tolocal(argc,argv)30238098Sbostic tolocal(argc, argv)
30338098Sbostic int argc;
30454151Sbostic char *argv[];
30538098Sbostic {
30646655Sbostic int i, len, tos;
30738100Sbostic char *bp, *host, *src, *suser;
30838098Sbostic
30938098Sbostic for (i = 0; i < argc - 1; i++) {
31054151Sbostic if (!(src = colon(argv[i]))) { /* Local to local. */
31146655Sbostic len = strlen(_PATH_CP) + strlen(argv[i]) +
31246655Sbostic strlen(argv[argc - 1]) + 20;
31346655Sbostic if (!(bp = malloc(len)))
31459512Sbostic err(1, NULL);
315*66619Spendry (void)snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP,
31638100Sbostic iamrecursive ? " -r" : "", pflag ? " -p" : "",
31738100Sbostic argv[i], argv[argc - 1]);
31854570Sandrew if (susystem(bp, userid))
31954570Sandrew ++errs;
32038100Sbostic (void)free(bp);
32138100Sbostic continue;
32238100Sbostic }
32338100Sbostic *src++ = 0;
32438100Sbostic if (*src == 0)
32538100Sbostic src = ".";
32659512Sbostic if ((host = strchr(argv[i], '@')) == NULL) {
32754151Sbostic host = argv[i];
32854151Sbostic suser = pwd->pw_name;
32954151Sbostic } else {
33038100Sbostic *host++ = 0;
33138100Sbostic suser = argv[i];
33238100Sbostic if (*suser == '\0')
33338098Sbostic suser = pwd->pw_name;
33438100Sbostic else if (!okname(suser))
33538100Sbostic continue;
33638100Sbostic }
33746655Sbostic len = strlen(src) + CMDNEEDS + 20;
33854151Sbostic if ((bp = malloc(len)) == NULL)
33959512Sbostic err(1, NULL);
34046655Sbostic (void)snprintf(bp, len, "%s -f %s", cmd, src);
34154151Sbostic rem =
34238098Sbostic #ifdef KERBEROS
34354151Sbostic use_kerberos ?
34454151Sbostic kerberos(&host, bp, pwd->pw_name, suser) :
34538098Sbostic #endif
34654151Sbostic rcmd(&host, port, pwd->pw_name, suser, bp, 0);
34738100Sbostic (void)free(bp);
34854570Sandrew if (rem < 0) {
34954570Sandrew ++errs;
35038100Sbostic continue;
35154570Sandrew }
35244342Skarels (void)seteuid(userid);
35344342Skarels tos = IPTOS_THROUGHPUT;
35454151Sbostic if (setsockopt(rem, IPPROTO_IP, IP_TOS, &tos, sizeof(int)) < 0)
35559512Sbostic warn("TOS (ignored)");
35638100Sbostic sink(1, argv + argc - 1);
35744342Skarels (void)seteuid(0);
35838100Sbostic (void)close(rem);
35938100Sbostic rem = -1;
3606440Swnj }
3616440Swnj }
3626440Swnj
36354151Sbostic void
source(argc,argv)3646440Swnj source(argc, argv)
3656440Swnj int argc;
36654151Sbostic char *argv[];
3676440Swnj {
3686440Swnj struct stat stb;
36938098Sbostic static BUF buffer;
37038098Sbostic BUF *bp;
37138098Sbostic off_t i;
37254570Sandrew int amt, fd, haderr, indx, result;
37338098Sbostic char *last, *name, buf[BUFSIZ];
3746440Swnj
37554570Sandrew for (indx = 0; indx < argc; ++indx) {
37654570Sandrew name = argv[indx];
37754151Sbostic if ((fd = open(name, O_RDONLY, 0)) < 0)
37854151Sbostic goto syserr;
37954151Sbostic if (fstat(fd, &stb)) {
38059512Sbostic syserr: run_err("%s: %s", name, strerror(errno));
38154151Sbostic goto next;
3826440Swnj }
38354151Sbostic switch (stb.st_mode & S_IFMT) {
3846440Swnj case S_IFREG:
3856440Swnj break;
3866440Swnj case S_IFDIR:
3876440Swnj if (iamrecursive) {
38823101Slepreau rsource(name, &stb);
38954151Sbostic goto next;
3906440Swnj }
39138098Sbostic /* FALLTHROUGH */
3926440Swnj default:
39359512Sbostic run_err("%s: not a regular file", name);
39454151Sbostic goto next;
3956440Swnj }
39659512Sbostic if ((last = strrchr(name, '/')) == NULL)
3976440Swnj last = name;
3986440Swnj else
39954151Sbostic ++last;
40023101Slepreau if (pflag) {
40123101Slepreau /*
40223101Slepreau * Make it compatible with possible future
40323101Slepreau * versions expecting microseconds.
40423101Slepreau */
40556587Sbostic (void)snprintf(buf, sizeof(buf), "T%ld 0 %ld 0\n",
40654151Sbostic stb.st_mtimespec.ts_sec, stb.st_atimespec.ts_sec);
40756587Sbostic (void)write(rem, buf, strlen(buf));
40854151Sbostic if (response() < 0)
40954151Sbostic goto next;
41023101Slepreau }
41154151Sbostic #define MODEMASK (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO)
41256587Sbostic (void)snprintf(buf, sizeof(buf), "C%04o %qd %s\n",
41354151Sbostic stb.st_mode & MODEMASK, stb.st_size, last);
41456587Sbostic (void)write(rem, buf, strlen(buf));
41554151Sbostic if (response() < 0)
41654151Sbostic goto next;
41754570Sandrew if ((bp = allocbuf(&buffer, fd, BUFSIZ)) == NULL) {
41854570Sandrew next: (void)close(fd);
41954570Sandrew continue;
42054570Sandrew }
42154570Sandrew
42254570Sandrew /* Keep writing after an error so that we stay sync'd up. */
42354570Sandrew for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
42421254Smckusick amt = bp->cnt;
4256440Swnj if (i + amt > stb.st_size)
4266440Swnj amt = stb.st_size - i;
42754570Sandrew if (!haderr) {
42854570Sandrew result = read(fd, bp->buf, amt);
42954570Sandrew if (result != amt)
43054570Sandrew haderr = result >= 0 ? EIO : errno;
43154151Sbostic }
43254570Sandrew if (haderr)
43354570Sandrew (void)write(rem, bp->buf, amt);
43454570Sandrew else {
43554570Sandrew result = write(rem, bp->buf, amt);
43654570Sandrew if (result != amt)
43754570Sandrew haderr = result >= 0 ? EIO : errno;
43854570Sandrew }
4396440Swnj }
44054570Sandrew if (close(fd) && !haderr)
44154570Sandrew haderr = errno;
44254570Sandrew if (!haderr)
44338098Sbostic (void)write(rem, "", 1);
44454570Sandrew else
44559512Sbostic run_err("%s: %s", name, strerror(haderr));
44638098Sbostic (void)response();
4476440Swnj }
4486440Swnj }
4496440Swnj
45054151Sbostic void
rsource(name,statp)45123101Slepreau rsource(name, statp)
4526440Swnj char *name;
45323101Slepreau struct stat *statp;
4546440Swnj {
45546655Sbostic DIR *dirp;
45646655Sbostic struct dirent *dp;
45738100Sbostic char *last, *vect[1], path[MAXPATHLEN];
4586440Swnj
45946655Sbostic if (!(dirp = opendir(name))) {
46059512Sbostic run_err("%s: %s", name, strerror(errno));
4616440Swnj return;
4626440Swnj }
46359512Sbostic last = strrchr(name, '/');
4646440Swnj if (last == 0)
4656440Swnj last = name;
4666440Swnj else
4676440Swnj last++;
46823101Slepreau if (pflag) {
46956587Sbostic (void)snprintf(path, sizeof(path), "T%ld 0 %ld 0\n",
47054151Sbostic statp->st_mtimespec.ts_sec, statp->st_atimespec.ts_sec);
47156587Sbostic (void)write(rem, path, strlen(path));
47223101Slepreau if (response() < 0) {
47346655Sbostic closedir(dirp);
47423101Slepreau return;
47523101Slepreau }
47623101Slepreau }
47756587Sbostic (void)snprintf(path, sizeof(path),
47854151Sbostic "D%04o %d %s\n", statp->st_mode & MODEMASK, 0, last);
47956587Sbostic (void)write(rem, path, strlen(path));
4806440Swnj if (response() < 0) {
48146655Sbostic closedir(dirp);
4826440Swnj return;
4836440Swnj }
48446655Sbostic while (dp = readdir(dirp)) {
4856440Swnj if (dp->d_ino == 0)
4866440Swnj continue;
4876440Swnj if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
4886440Swnj continue;
48938100Sbostic if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) {
49059512Sbostic run_err("%s/%s: name too long", name, dp->d_name);
4916440Swnj continue;
4926440Swnj }
49346655Sbostic (void)snprintf(path, sizeof(path), "%s/%s", name, dp->d_name);
49438100Sbostic vect[0] = path;
49538100Sbostic source(1, vect);
4966440Swnj }
49754151Sbostic (void)closedir(dirp);
49838098Sbostic (void)write(rem, "E\n", 2);
49938098Sbostic (void)response();
5006440Swnj }
5016440Swnj
50246655Sbostic void
sink(argc,argv)5036440Swnj sink(argc, argv)
5046440Swnj int argc;
50554151Sbostic char *argv[];
5066440Swnj {
50754151Sbostic static BUF buffer;
50821254Smckusick struct stat stb;
50923101Slepreau struct timeval tv[2];
51038469Sbostic enum { YES, NO, DISPLAYED } wrerr;
51154151Sbostic BUF *bp;
51238100Sbostic off_t i, j;
51354570Sandrew int amt, count, exists, first, mask, mode, ofd, omode;
51454570Sandrew int setimes, size, targisdir, wrerrno;
515*66619Spendry char ch, *cp, *np, *targ, *why, *vect[1], buf[BUFSIZ];
5166440Swnj
51738100Sbostic #define atime tv[0]
51838100Sbostic #define mtime tv[1]
51938100Sbostic #define SCREWUP(str) { why = str; goto screwup; }
52038100Sbostic
52138100Sbostic setimes = targisdir = 0;
52238100Sbostic mask = umask(0);
52323112Slepreau if (!pflag)
52438098Sbostic (void)umask(mask);
52518126Sralph if (argc != 1) {
52659512Sbostic run_err("ambiguous target");
5276440Swnj exit(1);
5286440Swnj }
5296440Swnj targ = *argv;
5306440Swnj if (targetshouldbedirectory)
5316440Swnj verifydir(targ);
53238098Sbostic (void)write(rem, "", 1);
53354151Sbostic if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
5346440Swnj targisdir = 1;
53538100Sbostic for (first = 1;; first = 0) {
53638100Sbostic cp = buf;
5376440Swnj if (read(rem, cp, 1) <= 0)
5386440Swnj return;
5396440Swnj if (*cp++ == '\n')
54038100Sbostic SCREWUP("unexpected <newline>");
5416440Swnj do {
54238100Sbostic if (read(rem, &ch, sizeof(ch)) != sizeof(ch))
5436440Swnj SCREWUP("lost connection");
54438100Sbostic *cp++ = ch;
54538100Sbostic } while (cp < &buf[BUFSIZ - 1] && ch != '\n');
5466440Swnj *cp = 0;
54738100Sbostic
54838100Sbostic if (buf[0] == '\01' || buf[0] == '\02') {
5496440Swnj if (iamremote == 0)
55054151Sbostic (void)write(STDERR_FILENO,
55154151Sbostic buf + 1, strlen(buf + 1));
55238100Sbostic if (buf[0] == '\02')
5536440Swnj exit(1);
55454151Sbostic ++errs;
5556440Swnj continue;
5566440Swnj }
55738100Sbostic if (buf[0] == 'E') {
55838098Sbostic (void)write(rem, "", 1);
5596440Swnj return;
5606440Swnj }
56123101Slepreau
56238108Sbostic if (ch == '\n')
56338115Sbostic *--cp = 0;
56438108Sbostic
56523101Slepreau #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0');
56638100Sbostic cp = buf;
56723101Slepreau if (*cp == 'T') {
56823101Slepreau setimes++;
56923101Slepreau cp++;
57023101Slepreau getnum(mtime.tv_sec);
57123101Slepreau if (*cp++ != ' ')
57223101Slepreau SCREWUP("mtime.sec not delimited");
57323101Slepreau getnum(mtime.tv_usec);
57423101Slepreau if (*cp++ != ' ')
57523101Slepreau SCREWUP("mtime.usec not delimited");
57623101Slepreau getnum(atime.tv_sec);
57723101Slepreau if (*cp++ != ' ')
57823101Slepreau SCREWUP("atime.sec not delimited");
57923101Slepreau getnum(atime.tv_usec);
58023101Slepreau if (*cp++ != '\0')
58123101Slepreau SCREWUP("atime.usec not delimited");
58238098Sbostic (void)write(rem, "", 1);
58323101Slepreau continue;
58423101Slepreau }
58514580Sralph if (*cp != 'C' && *cp != 'D') {
58614580Sralph /*
58714580Sralph * Check for the case "rcp remote:foo\* local:bar".
58814580Sralph * In this case, the line "No match." can be returned
58914580Sralph * by the shell before the rcp command on the remote is
59014580Sralph * executed so the ^Aerror_message convention isn't
59114580Sralph * followed.
59214580Sralph */
59314580Sralph if (first) {
59459512Sbostic run_err("%s", cp);
59514580Sralph exit(1);
59614580Sralph }
5976440Swnj SCREWUP("expected control record");
59814580Sralph }
5996440Swnj mode = 0;
60038100Sbostic for (++cp; cp < buf + 5; cp++) {
6016440Swnj if (*cp < '0' || *cp > '7')
6026440Swnj SCREWUP("bad mode");
6036440Swnj mode = (mode << 3) | (*cp - '0');
6046440Swnj }
6056440Swnj if (*cp++ != ' ')
6066440Swnj SCREWUP("mode not delimited");
60754151Sbostic
60854151Sbostic for (size = 0; isdigit(*cp);)
6096440Swnj size = size * 10 + (*cp++ - '0');
6106440Swnj if (*cp++ != ' ')
6116440Swnj SCREWUP("size not delimited");
61238100Sbostic if (targisdir) {
61338100Sbostic static char *namebuf;
61438100Sbostic static int cursize;
61545647Storek size_t need;
61638100Sbostic
61738100Sbostic need = strlen(targ) + strlen(cp) + 250;
61838100Sbostic if (need > cursize) {
61945647Storek if (!(namebuf = malloc(need)))
62059512Sbostic run_err("%s", strerror(errno));
62138100Sbostic }
62246655Sbostic (void)snprintf(namebuf, need, "%s%s%s", targ,
6236440Swnj *targ ? "/" : "", cp);
62438100Sbostic np = namebuf;
62554570Sandrew } else
62638100Sbostic np = targ;
62738100Sbostic exists = stat(np, &stb) == 0;
62838100Sbostic if (buf[0] == 'D') {
62954570Sandrew int mod_flag = pflag;
63018126Sralph if (exists) {
63154151Sbostic if (!S_ISDIR(stb.st_mode)) {
6326440Swnj errno = ENOTDIR;
6336440Swnj goto bad;
6346440Swnj }
63523112Slepreau if (pflag)
63638100Sbostic (void)chmod(np, mode);
63754570Sandrew } else {
63854570Sandrew /* Handle copying from a read-only directory */
63954570Sandrew mod_flag = 1;
64054570Sandrew if (mkdir(np, mode | S_IRWXU) < 0)
64154570Sandrew goto bad;
64254570Sandrew }
64338100Sbostic vect[0] = np;
64438100Sbostic sink(1, vect);
64523101Slepreau if (setimes) {
64623101Slepreau setimes = 0;
64738100Sbostic if (utimes(np, tv) < 0)
64859512Sbostic run_err("%s: set times: %s",
64938469Sbostic np, strerror(errno));
65023101Slepreau }
65154570Sandrew if (mod_flag)
65254570Sandrew (void)chmod(np, mode);
6536440Swnj continue;
65418126Sralph }
65554570Sandrew omode = mode;
65654570Sandrew mode |= S_IWRITE;
65738100Sbostic if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) {
65859512Sbostic bad: run_err("%s: %s", np, strerror(errno));
6596440Swnj continue;
6606440Swnj }
66138098Sbostic (void)write(rem, "", 1);
66254151Sbostic if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == NULL) {
66338100Sbostic (void)close(ofd);
66421254Smckusick continue;
66521254Smckusick }
66621254Smckusick cp = bp->buf;
66738469Sbostic wrerr = NO;
66854570Sandrew for (count = i = 0; i < size; i += BUFSIZ) {
66921254Smckusick amt = BUFSIZ;
6706440Swnj if (i + amt > size)
6716440Swnj amt = size - i;
67221254Smckusick count += amt;
6736440Swnj do {
67421254Smckusick j = read(rem, cp, amt);
67524711Sbloom if (j <= 0) {
67659512Sbostic run_err("%s", j ? strerror(errno) :
67738100Sbostic "dropped connection");
6786440Swnj exit(1);
67924711Sbloom }
6806440Swnj amt -= j;
6816440Swnj cp += j;
6826440Swnj } while (amt > 0);
68321254Smckusick if (count == bp->cnt) {
68454570Sandrew /* Keep reading so we stay sync'd up. */
68554570Sandrew if (wrerr == NO) {
68654570Sandrew j = write(ofd, bp->buf, count);
68754570Sandrew if (j != count) {
68854570Sandrew wrerr = YES;
68954570Sandrew wrerrno = j >= 0 ? EIO : errno;
69054570Sandrew }
69154570Sandrew }
69221254Smckusick count = 0;
69321254Smckusick cp = bp->buf;
69421254Smckusick }
6956440Swnj }
69638469Sbostic if (count != 0 && wrerr == NO &&
69756587Sbostic (j = write(ofd, bp->buf, count)) != count) {
69838469Sbostic wrerr = YES;
69956587Sbostic wrerrno = j >= 0 ? EIO : errno;
70056587Sbostic }
70138469Sbostic if (ftruncate(ofd, size)) {
70259512Sbostic run_err("%s: truncate: %s", np, strerror(errno));
70338469Sbostic wrerr = DISPLAYED;
70438469Sbostic }
70554570Sandrew if (pflag) {
70654570Sandrew if (exists || omode != mode)
70759512Sbostic if (fchmod(ofd, omode))
70859512Sbostic run_err("%s: set mode: %s",
70959512Sbostic np, strerror(errno));
71054570Sandrew } else {
71154570Sandrew if (!exists && omode != mode)
71259512Sbostic if (fchmod(ofd, omode & ~mask))
71359512Sbostic run_err("%s: set mode: %s",
71459512Sbostic np, strerror(errno));
71554570Sandrew }
71638100Sbostic (void)close(ofd);
71738098Sbostic (void)response();
71838469Sbostic if (setimes && wrerr == NO) {
71923101Slepreau setimes = 0;
72038469Sbostic if (utimes(np, tv) < 0) {
72159512Sbostic run_err("%s: set times: %s",
72238469Sbostic np, strerror(errno));
72338469Sbostic wrerr = DISPLAYED;
72438469Sbostic }
72538469Sbostic }
72638469Sbostic switch(wrerr) {
72738469Sbostic case YES:
72859512Sbostic run_err("%s: %s", np, strerror(wrerrno));
72938469Sbostic break;
73038469Sbostic case NO:
73138098Sbostic (void)write(rem, "", 1);
73238469Sbostic break;
73338469Sbostic case DISPLAYED:
73438469Sbostic break;
73538469Sbostic }
7366440Swnj }
7376440Swnj screwup:
73859512Sbostic run_err("protocol error: %s", why);
7396440Swnj exit(1);
7406440Swnj }
7416440Swnj
74254151Sbostic #ifdef KERBEROS
74354151Sbostic int
kerberos(host,bp,locuser,user)74454151Sbostic kerberos(host, bp, locuser, user)
74554151Sbostic char **host, *bp, *locuser, *user;
74621254Smckusick {
74754151Sbostic struct servent *sp;
74821254Smckusick
74954151Sbostic again:
75054151Sbostic if (use_kerberos) {
75154151Sbostic rem = KSUCCESS;
75254151Sbostic errno = 0;
75354151Sbostic if (dest_realm == NULL)
75454151Sbostic dest_realm = krb_realmofhost(*host);
75554151Sbostic rem =
75659512Sbostic #ifdef CRYPT
75759512Sbostic doencrypt ?
75859512Sbostic krcmd_mutual(host,
75959512Sbostic port, user, bp, 0, dest_realm, &cred, schedule) :
76059512Sbostic #endif
76154151Sbostic krcmd(host, port, user, bp, 0, dest_realm);
76254151Sbostic
76354151Sbostic if (rem < 0) {
76454151Sbostic use_kerberos = 0;
76559512Sbostic if ((sp = getservbyname("shell", "tcp")) == NULL)
76659512Sbostic errx(1, "unknown service shell/tcp");
76754151Sbostic if (errno == ECONNREFUSED)
76854151Sbostic oldw("remote host doesn't support Kerberos");
76954151Sbostic else if (errno == ENOENT)
77054151Sbostic oldw("can't provide Kerberos authentication data");
77154151Sbostic port = sp->s_port;
77254151Sbostic goto again;
77321254Smckusick }
77454151Sbostic } else {
77559512Sbostic #ifdef CRYPT
77659512Sbostic if (doencrypt)
77759512Sbostic errx(1,
77859512Sbostic "the -x option requires Kerberos authentication");
77959512Sbostic #endif
78056587Sbostic rem = rcmd(host, port, locuser, user, bp, 0);
78121254Smckusick }
78254151Sbostic return (rem);
78321254Smckusick }
78454151Sbostic #endif /* KERBEROS */
78521254Smckusick
78654151Sbostic int
response()78754151Sbostic response()
7886440Swnj {
789*66619Spendry char ch, *cp, resp, rbuf[BUFSIZ];
7906440Swnj
79154151Sbostic if (read(rem, &resp, sizeof(resp)) != sizeof(resp))
79254151Sbostic lostconn(0);
79332127Sbostic
79454151Sbostic cp = rbuf;
79554151Sbostic switch(resp) {
79654151Sbostic case 0: /* ok */
79754151Sbostic return (0);
79854151Sbostic default:
79954151Sbostic *cp++ = resp;
80054151Sbostic /* FALLTHROUGH */
80154151Sbostic case 1: /* error, followed by error msg */
80254151Sbostic case 2: /* fatal error, "" */
80354151Sbostic do {
80454151Sbostic if (read(rem, &ch, sizeof(ch)) != sizeof(ch))
80554151Sbostic lostconn(0);
80654151Sbostic *cp++ = ch;
80754151Sbostic } while (cp < &rbuf[BUFSIZ] && ch != '\n');
80854151Sbostic
80954151Sbostic if (!iamremote)
81054151Sbostic (void)write(STDERR_FILENO, rbuf, cp - rbuf);
81154151Sbostic ++errs;
81254151Sbostic if (resp == 1)
81354151Sbostic return (-1);
81454151Sbostic exit(1);
81554151Sbostic }
81654151Sbostic /* NOTREACHED */
81738100Sbostic }
81838100Sbostic
81954151Sbostic void
usage()82032127Sbostic usage()
82132127Sbostic {
82238098Sbostic #ifdef KERBEROS
82359512Sbostic #ifdef CRYPT
82438098Sbostic (void)fprintf(stderr, "%s\n\t%s\n",
82559512Sbostic "usage: rcp [-Kpx] [-k realm] f1 f2",
82659512Sbostic "or: rcp [-Kprx] [-k realm] f1 ... fn directory");
82759512Sbostic #else
82859512Sbostic (void)fprintf(stderr, "%s\n\t%s\n",
82954151Sbostic "usage: rcp [-Kp] [-k realm] f1 f2",
83054151Sbostic "or: rcp [-Kpr] [-k realm] f1 ... fn directory");
83159512Sbostic #endif
83254151Sbostic #else
83338098Sbostic (void)fprintf(stderr,
83454151Sbostic "usage: rcp [-p] f1 f2; or: rcp [-pr] f1 ... fn directory\n");
83536626Skfall #endif
83632127Sbostic exit(1);
83732127Sbostic }
83838879Skfall
83954151Sbostic #if __STDC__
84054151Sbostic #include <stdarg.h>
84154151Sbostic #else
84254151Sbostic #include <varargs.h>
84354151Sbostic #endif
84454151Sbostic
84538879Skfall #ifdef KERBEROS
84654151Sbostic void
84754151Sbostic #if __STDC__
oldw(const char * fmt,...)84854151Sbostic oldw(const char *fmt, ...)
84954151Sbostic #else
85054151Sbostic oldw(fmt, va_alist)
85154151Sbostic char *fmt;
85254151Sbostic va_dcl
85354151Sbostic #endif
85438879Skfall {
85554151Sbostic va_list ap;
85654151Sbostic #if __STDC__
85754151Sbostic va_start(ap, fmt);
85854151Sbostic #else
85954151Sbostic va_start(ap);
86054151Sbostic #endif
86154151Sbostic (void)fprintf(stderr, "rcp: ");
86254151Sbostic (void)vfprintf(stderr, fmt, ap);
86354151Sbostic (void)fprintf(stderr, ", using standard rcp\n");
86454151Sbostic va_end(ap);
86538879Skfall }
86654151Sbostic #endif
86738879Skfall
86854151Sbostic void
86954151Sbostic #if __STDC__
run_err(const char * fmt,...)87059512Sbostic run_err(const char *fmt, ...)
87154151Sbostic #else
87259512Sbostic run_err(fmt, va_alist)
87354151Sbostic char *fmt;
87454151Sbostic va_dcl
87554151Sbostic #endif
87638879Skfall {
87754151Sbostic static FILE *fp;
87854151Sbostic va_list ap;
87954151Sbostic #if __STDC__
88054151Sbostic va_start(ap, fmt);
88154151Sbostic #else
88254151Sbostic va_start(ap);
88354151Sbostic #endif
88438879Skfall
88554151Sbostic ++errs;
88659512Sbostic if (fp == NULL && !(fp = fdopen(rem, "w")))
88754151Sbostic return;
88854151Sbostic (void)fprintf(fp, "%c", 0x01);
88954151Sbostic (void)fprintf(fp, "rcp: ");
89054151Sbostic (void)vfprintf(fp, fmt, ap);
89154151Sbostic (void)fprintf(fp, "\n");
89259512Sbostic (void)fflush(fp);
89359512Sbostic
89459512Sbostic if (!iamremote)
89559512Sbostic vwarnx(fmt, ap);
89659512Sbostic
89754151Sbostic va_end(ap);
89838879Skfall }
899