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