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