|
|
1.1 root 1: /*
2: * Copyright (c) 1983 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: char copyright[] =
9: "@(#) Copyright (c) 1983 Regents of the University of California.\n\
10: All rights reserved.\n";
11: #endif not lint
12:
13: #ifndef lint
14: static char sccsid[] = "@(#)rcp.c 5.4 (Berkeley) 9/12/85";
15: #endif not lint
16:
17: /*
18: * rcp
19: */
20: #include <sys/param.h>
21: #include <sys/stat.h>
22: #include <sys/time.h>
23: #include <sys/ioctl.h>
24:
25: #include <netinet/in.h>
26:
27: #include <stdio.h>
28: #include <signal.h>
29: #include <pwd.h>
30: #include <ctype.h>
31: #include <netdb.h>
32: #include <errno.h>
33:
34: int rem;
35: char *colon(), *index(), *rindex(), *malloc(), *strcpy(), *sprintf();
36: int errs;
37: int lostconn();
38: int errno;
39: char *sys_errlist[];
40: int iamremote, targetshouldbedirectory;
41: int iamrecursive;
42: int pflag;
43: struct passwd *pwd;
44: struct passwd *getpwuid();
45: int userid;
46: int port;
47:
48: struct buffer {
49: int cnt;
50: char *buf;
51: } *allocbuf();
52:
53: /*VARARGS*/
54: int error();
55:
56: #define ga() (void) write(rem, "", 1)
57:
58: main(argc, argv)
59: int argc;
60: char **argv;
61: {
62: char *targ, *host, *src;
63: char *suser, *tuser, *thost;
64: int i;
65: char buf[BUFSIZ], cmd[16];
66: struct servent *sp;
67:
68: sp = getservbyname("shell", "tcp");
69: if (sp == NULL) {
70: fprintf(stderr, "rcp: shell/tcp: unknown service\n");
71: exit(1);
72: }
73: port = sp->s_port;
74: pwd = getpwuid(userid = getuid());
75: if (pwd == 0) {
76: fprintf(stderr, "who are you?\n");
77: exit(1);
78: }
79:
80: for (argc--, argv++; argc > 0 && **argv == '-'; argc--, argv++) {
81: (*argv)++;
82: while (**argv) switch (*(*argv)++) {
83:
84: case 'r':
85: iamrecursive++;
86: break;
87:
88: case 'p': /* preserve mtimes and atimes */
89: pflag++;
90: break;
91:
92: /* The rest of these are not for users. */
93: case 'd':
94: targetshouldbedirectory = 1;
95: break;
96:
97: case 'f': /* "from" */
98: iamremote = 1;
99: (void) response();
100: (void) setuid(userid);
101: source(--argc, ++argv);
102: exit(errs);
103:
104: case 't': /* "to" */
105: iamremote = 1;
106: (void) setuid(userid);
107: sink(--argc, ++argv);
108: exit(errs);
109:
110: default:
111: fprintf(stderr,
112: "Usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn d2\n");
113: exit(1);
114: }
115: }
116: rem = -1;
117: if (argc > 2)
118: targetshouldbedirectory = 1;
119: (void) sprintf(cmd, "rcp%s%s%s",
120: iamrecursive ? " -r" : "", pflag ? " -p" : "",
121: targetshouldbedirectory ? " -d" : "");
122: (void) signal(SIGPIPE, lostconn);
123: targ = colon(argv[argc - 1]);
124: if (targ) { /* ... to remote */
125: *targ++ = 0;
126: if (*targ == 0)
127: targ = ".";
128: thost = index(argv[argc - 1], '@');
129: if (thost) {
130: *thost++ = 0;
131: tuser = argv[argc - 1];
132: if (*tuser == '\0')
133: tuser = NULL;
134: else if (!okname(tuser))
135: exit(1);
136: } else {
137: thost = argv[argc - 1];
138: tuser = NULL;
139: }
140: for (i = 0; i < argc - 1; i++) {
141: src = colon(argv[i]);
142: if (src) { /* remote to remote */
143: *src++ = 0;
144: if (*src == 0)
145: src = ".";
146: host = index(argv[i], '@');
147: if (host) {
148: *host++ = 0;
149: suser = argv[i];
150: if (*suser == '\0')
151: suser = pwd->pw_name;
152: else if (!okname(suser))
153: continue;
154: (void) sprintf(buf, "rsh %s -l %s -n %s %s '%s%s%s:%s'",
155: host, suser, cmd, src, tuser,
156: tuser ? "@" : "",
157: thost, targ);
158: } else
159: (void) sprintf(buf, "rsh %s -n %s %s '%s%s%s:%s'",
160: argv[i], cmd, src, tuser,
161: tuser ? "@" : "",
162: thost, targ);
163: (void) susystem(buf);
164: } else { /* local to remote */
165: if (rem == -1) {
166: (void) sprintf(buf, "%s -t %s",
167: cmd, targ);
168: host = thost;
169: rem = rcmd(&host, port, pwd->pw_name,
170: tuser ? tuser : pwd->pw_name,
171: buf, 0);
172: if (rem < 0)
173: exit(1);
174: if (response() < 0)
175: exit(1);
176: (void) setuid(userid);
177: }
178: source(1, argv+i);
179: }
180: }
181: } else { /* ... to local */
182: if (targetshouldbedirectory)
183: verifydir(argv[argc - 1]);
184: for (i = 0; i < argc - 1; i++) {
185: src = colon(argv[i]);
186: if (src == 0) { /* local to local */
187: (void) sprintf(buf, "/bin/cp%s%s %s %s",
188: iamrecursive ? " -r" : "",
189: pflag ? " -p" : "",
190: argv[i], argv[argc - 1]);
191: (void) susystem(buf);
192: } else { /* remote to local */
193: *src++ = 0;
194: if (*src == 0)
195: src = ".";
196: host = index(argv[i], '@');
197: if (host) {
198: *host++ = 0;
199: suser = argv[i];
200: if (*suser == '\0')
201: suser = pwd->pw_name;
202: else if (!okname(suser))
203: continue;
204: } else {
205: host = argv[i];
206: suser = pwd->pw_name;
207: }
208: (void) sprintf(buf, "%s -f %s", cmd, src);
209: rem = rcmd(&host, port, pwd->pw_name, suser,
210: buf, 0);
211: if (rem < 0)
212: continue;
213: (void) setreuid(0, userid);
214: sink(1, argv+argc-1);
215: (void) setreuid(userid, 0);
216: (void) close(rem);
217: rem = -1;
218: }
219: }
220: }
221: exit(errs);
222: }
223:
224: verifydir(cp)
225: char *cp;
226: {
227: struct stat stb;
228:
229: if (stat(cp, &stb) >= 0) {
230: if ((stb.st_mode & S_IFMT) == S_IFDIR)
231: return;
232: errno = ENOTDIR;
233: }
234: error("rcp: %s: %s.\n", cp, sys_errlist[errno]);
235: exit(1);
236: }
237:
238: char *
239: colon(cp)
240: char *cp;
241: {
242:
243: while (*cp) {
244: if (*cp == ':')
245: return (cp);
246: if (*cp == '/')
247: return (0);
248: cp++;
249: }
250: return (0);
251: }
252:
253: okname(cp0)
254: char *cp0;
255: {
256: register char *cp = cp0;
257: register int c;
258:
259: do {
260: c = *cp;
261: if (c & 0200)
262: goto bad;
263: if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
264: goto bad;
265: cp++;
266: } while (*cp);
267: return (1);
268: bad:
269: fprintf(stderr, "rcp: invalid user name %s\n", cp0);
270: return (0);
271: }
272:
273: susystem(s)
274: char *s;
275: {
276: int status, pid, w;
277: register int (*istat)(), (*qstat)();
278:
279: if ((pid = vfork()) == 0) {
280: (void) setuid(userid);
281: execl("/bin/sh", "sh", "-c", s, (char *)0);
282: _exit(127);
283: }
284: istat = signal(SIGINT, SIG_IGN);
285: qstat = signal(SIGQUIT, SIG_IGN);
286: while ((w = wait(&status)) != pid && w != -1)
287: ;
288: if (w == -1)
289: status = -1;
290: (void) signal(SIGINT, istat);
291: (void) signal(SIGQUIT, qstat);
292: return (status);
293: }
294:
295: source(argc, argv)
296: int argc;
297: char **argv;
298: {
299: char *last, *name;
300: struct stat stb;
301: static struct buffer buffer;
302: struct buffer *bp;
303: int x, sizerr, f, amt;
304: off_t i;
305: char buf[BUFSIZ];
306:
307: for (x = 0; x < argc; x++) {
308: name = argv[x];
309: if ((f = open(name, 0)) < 0) {
310: error("rcp: %s: %s\n", name, sys_errlist[errno]);
311: continue;
312: }
313: if (fstat(f, &stb) < 0)
314: goto notreg;
315: switch (stb.st_mode&S_IFMT) {
316:
317: case S_IFREG:
318: break;
319:
320: case S_IFDIR:
321: if (iamrecursive) {
322: (void) close(f);
323: rsource(name, &stb);
324: continue;
325: }
326: /* fall into ... */
327: default:
328: notreg:
329: (void) close(f);
330: error("rcp: %s: not a plain file\n", name);
331: continue;
332: }
333: last = rindex(name, '/');
334: if (last == 0)
335: last = name;
336: else
337: last++;
338: if (pflag) {
339: /*
340: * Make it compatible with possible future
341: * versions expecting microseconds.
342: */
343: (void) sprintf(buf, "T%ld 0 %ld 0\n",
344: stb.st_mtime, stb.st_atime);
345: (void) write(rem, buf, strlen(buf));
346: if (response() < 0) {
347: (void) close(f);
348: continue;
349: }
350: }
351: (void) sprintf(buf, "C%04o %ld %s\n",
352: stb.st_mode&07777, stb.st_size, last);
353: (void) write(rem, buf, strlen(buf));
354: if (response() < 0) {
355: (void) close(f);
356: continue;
357: }
358: if ((bp = allocbuf(&buffer, f, BUFSIZ)) < 0) {
359: (void) close(f);
360: continue;
361: }
362: sizerr = 0;
363: for (i = 0; i < stb.st_size; i += bp->cnt) {
364: amt = bp->cnt;
365: if (i + amt > stb.st_size)
366: amt = stb.st_size - i;
367: if (sizerr == 0 && read(f, bp->buf, amt) != amt)
368: sizerr = 1;
369: (void) write(rem, bp->buf, amt);
370: }
371: (void) close(f);
372: if (sizerr == 0)
373: ga();
374: else
375: error("rcp: %s: file changed size\n", name);
376: (void) response();
377: }
378: }
379:
380: #include <sys/dir.h>
381:
382: rsource(name, statp)
383: char *name;
384: struct stat *statp;
385: {
386: DIR *d = opendir(name);
387: char *last;
388: struct direct *dp;
389: char buf[BUFSIZ];
390: char *bufv[1];
391:
392: if (d == 0) {
393: error("rcp: %s: %s\n", name, sys_errlist[errno]);
394: return;
395: }
396: last = rindex(name, '/');
397: if (last == 0)
398: last = name;
399: else
400: last++;
401: if (pflag) {
402: (void) sprintf(buf, "T%ld 0 %ld 0\n",
403: statp->st_mtime, statp->st_atime);
404: (void) write(rem, buf, strlen(buf));
405: if (response() < 0) {
406: closedir(d);
407: return;
408: }
409: }
410: (void) sprintf(buf, "D%04o %d %s\n", statp->st_mode&07777, 0, last);
411: (void) write(rem, buf, strlen(buf));
412: if (response() < 0) {
413: closedir(d);
414: return;
415: }
416: while (dp = readdir(d)) {
417: if (dp->d_ino == 0)
418: continue;
419: if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
420: continue;
421: if (strlen(name) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
422: error("%s/%s: Name too long.\n", name, dp->d_name);
423: continue;
424: }
425: (void) sprintf(buf, "%s/%s", name, dp->d_name);
426: bufv[0] = buf;
427: source(1, bufv);
428: }
429: closedir(d);
430: (void) write(rem, "E\n", 2);
431: (void) response();
432: }
433:
434: response()
435: {
436: char resp, c, rbuf[BUFSIZ], *cp = rbuf;
437:
438: if (read(rem, &resp, 1) != 1)
439: lostconn();
440: switch (resp) {
441:
442: case 0: /* ok */
443: return (0);
444:
445: default:
446: *cp++ = resp;
447: /* fall into... */
448: case 1: /* error, followed by err msg */
449: case 2: /* fatal error, "" */
450: do {
451: if (read(rem, &c, 1) != 1)
452: lostconn();
453: *cp++ = c;
454: } while (cp < &rbuf[BUFSIZ] && c != '\n');
455: if (iamremote == 0)
456: (void) write(2, rbuf, cp - rbuf);
457: errs++;
458: if (resp == 1)
459: return (-1);
460: exit(1);
461: }
462: /*NOTREACHED*/
463: }
464:
465: lostconn()
466: {
467:
468: if (iamremote == 0)
469: fprintf(stderr, "rcp: lost connection\n");
470: exit(1);
471: }
472:
473: sink(argc, argv)
474: int argc;
475: char **argv;
476: {
477: off_t i, j;
478: char *targ, *whopp, *cp;
479: int of, mode, wrerr, exists, first, count, amt, size;
480: struct buffer *bp;
481: static struct buffer buffer;
482: struct stat stb;
483: int targisdir = 0;
484: int mask = umask(0);
485: char *myargv[1];
486: char cmdbuf[BUFSIZ], nambuf[BUFSIZ];
487: int setimes = 0;
488: struct timeval tv[2];
489: #define atime tv[0]
490: #define mtime tv[1]
491: #define SCREWUP(str) { whopp = str; goto screwup; }
492:
493: if (!pflag)
494: (void) umask(mask);
495: if (argc != 1) {
496: error("rcp: ambiguous target\n");
497: exit(1);
498: }
499: targ = *argv;
500: if (targetshouldbedirectory)
501: verifydir(targ);
502: ga();
503: if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR)
504: targisdir = 1;
505: for (first = 1; ; first = 0) {
506: cp = cmdbuf;
507: if (read(rem, cp, 1) <= 0)
508: return;
509: if (*cp++ == '\n')
510: SCREWUP("unexpected '\\n'");
511: do {
512: if (read(rem, cp, 1) != 1)
513: SCREWUP("lost connection");
514: } while (*cp++ != '\n');
515: *cp = 0;
516: if (cmdbuf[0] == '\01' || cmdbuf[0] == '\02') {
517: if (iamremote == 0)
518: (void) write(2, cmdbuf+1, strlen(cmdbuf+1));
519: if (cmdbuf[0] == '\02')
520: exit(1);
521: errs++;
522: continue;
523: }
524: *--cp = 0;
525: cp = cmdbuf;
526: if (*cp == 'E') {
527: ga();
528: return;
529: }
530:
531: #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0');
532: if (*cp == 'T') {
533: setimes++;
534: cp++;
535: getnum(mtime.tv_sec);
536: if (*cp++ != ' ')
537: SCREWUP("mtime.sec not delimited");
538: getnum(mtime.tv_usec);
539: if (*cp++ != ' ')
540: SCREWUP("mtime.usec not delimited");
541: getnum(atime.tv_sec);
542: if (*cp++ != ' ')
543: SCREWUP("atime.sec not delimited");
544: getnum(atime.tv_usec);
545: if (*cp++ != '\0')
546: SCREWUP("atime.usec not delimited");
547: ga();
548: continue;
549: }
550: if (*cp != 'C' && *cp != 'D') {
551: /*
552: * Check for the case "rcp remote:foo\* local:bar".
553: * In this case, the line "No match." can be returned
554: * by the shell before the rcp command on the remote is
555: * executed so the ^Aerror_message convention isn't
556: * followed.
557: */
558: if (first) {
559: error("%s\n", cp);
560: exit(1);
561: }
562: SCREWUP("expected control record");
563: }
564: cp++;
565: mode = 0;
566: for (; cp < cmdbuf+5; cp++) {
567: if (*cp < '0' || *cp > '7')
568: SCREWUP("bad mode");
569: mode = (mode << 3) | (*cp - '0');
570: }
571: if (*cp++ != ' ')
572: SCREWUP("mode not delimited");
573: size = 0;
574: while (isdigit(*cp))
575: size = size * 10 + (*cp++ - '0');
576: if (*cp++ != ' ')
577: SCREWUP("size not delimited");
578: if (targisdir)
579: (void) sprintf(nambuf, "%s%s%s", targ,
580: *targ ? "/" : "", cp);
581: else
582: (void) strcpy(nambuf, targ);
583: exists = stat(nambuf, &stb) == 0;
584: if (cmdbuf[0] == 'D') {
585: if (exists) {
586: if ((stb.st_mode&S_IFMT) != S_IFDIR) {
587: errno = ENOTDIR;
588: goto bad;
589: }
590: if (pflag)
591: (void) chmod(nambuf, mode);
592: } else if (mkdir(nambuf, mode) < 0)
593: goto bad;
594: myargv[0] = nambuf;
595: sink(1, myargv);
596: if (setimes) {
597: setimes = 0;
598: if (utimes(nambuf, tv) < 0)
599: error("rcp: can't set times on %s: %s\n",
600: nambuf, sys_errlist[errno]);
601: }
602: continue;
603: }
604: if ((of = creat(nambuf, mode)) < 0) {
605: bad:
606: error("rcp: %s: %s\n", nambuf, sys_errlist[errno]);
607: continue;
608: }
609: if (exists && pflag)
610: (void) fchmod(of, mode);
611: ga();
612: if ((bp = allocbuf(&buffer, of, BUFSIZ)) < 0) {
613: (void) close(of);
614: continue;
615: }
616: cp = bp->buf;
617: count = 0;
618: wrerr = 0;
619: for (i = 0; i < size; i += BUFSIZ) {
620: amt = BUFSIZ;
621: if (i + amt > size)
622: amt = size - i;
623: count += amt;
624: do {
625: j = read(rem, cp, amt);
626: if (j <= 0) {
627: if (j == 0)
628: error("rcp: dropped connection");
629: else
630: error("rcp: %s\n",
631: sys_errlist[errno]);
632: exit(1);
633: }
634: amt -= j;
635: cp += j;
636: } while (amt > 0);
637: if (count == bp->cnt) {
638: if (wrerr == 0 &&
639: write(of, bp->buf, count) != count)
640: wrerr++;
641: count = 0;
642: cp = bp->buf;
643: }
644: }
645: if (count != 0 && wrerr == 0 &&
646: write(of, bp->buf, count) != count)
647: wrerr++;
648: (void) close(of);
649: (void) response();
650: if (setimes) {
651: setimes = 0;
652: if (utimes(nambuf, tv) < 0)
653: error("rcp: can't set times on %s: %s\n",
654: nambuf, sys_errlist[errno]);
655: }
656: if (wrerr)
657: error("rcp: %s: %s\n", nambuf, sys_errlist[errno]);
658: else
659: ga();
660: }
661: screwup:
662: error("rcp: protocol screwup: %s\n", whopp);
663: exit(1);
664: }
665:
666: struct buffer *
667: allocbuf(bp, fd, blksize)
668: struct buffer *bp;
669: int fd, blksize;
670: {
671: struct stat stb;
672: int size;
673:
674: if (fstat(fd, &stb) < 0) {
675: error("rcp: fstat: %s\n", sys_errlist[errno]);
676: return ((struct buffer *)-1);
677: }
678: size = roundup(stb.st_blksize, blksize);
679: if (size == 0)
680: size = blksize;
681: if (bp->cnt < size) {
682: if (bp->buf != 0)
683: free(bp->buf);
684: bp->buf = (char *)malloc((unsigned) size);
685: if (bp->buf == 0) {
686: error("rcp: malloc: out of memory\n");
687: return ((struct buffer *)-1);
688: }
689: }
690: bp->cnt = size;
691: return (bp);
692: }
693:
694: /*VARARGS1*/
695: error(fmt, a1, a2, a3, a4, a5)
696: char *fmt;
697: int a1, a2, a3, a4, a5;
698: {
699: char buf[BUFSIZ], *cp = buf;
700:
701: errs++;
702: *cp++ = 1;
703: (void) sprintf(cp, fmt, a1, a2, a3, a4, a5);
704: (void) write(rem, buf, strlen(buf));
705: if (iamremote == 0)
706: (void) write(2, buf+1, strlen(buf+1));
707: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.