|
|
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.