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