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