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: }