|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983, 1990 The Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * Redistribution and use in source and binary forms are permitted provided ! 6: * that: (1) source distributions retain this entire copyright notice and ! 7: * comment, and (2) distributions including binaries display the following ! 8: * acknowledgement: ``This product includes software developed by the ! 9: * University of California, Berkeley and its contributors'' in the ! 10: * documentation or other materials provided with the distribution and in ! 11: * all advertising materials mentioning features or use of this software. ! 12: * Neither the name of the University nor the names of its contributors may ! 13: * be used to endorse or promote products derived from this software without ! 14: * specific prior written permission. ! 15: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 16: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 17: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 18: */ ! 19: ! 20: #ifndef lint ! 21: char copyright[] = ! 22: "@(#) Copyright (c) 1983, 1990 The Regents of the University of California.\n\ ! 23: All rights reserved.\n"; ! 24: #endif /* not lint */ ! 25: ! 26: #ifndef lint ! 27: static char sccsid[] = "@(#)rcp.c 5.30.1.1 (Berkeley) 10/21/90"; ! 28: #endif /* not lint */ ! 29: ! 30: /* ! 31: * rcp ! 32: */ ! 33: #include <sys/param.h> ! 34: #include <sys/file.h> ! 35: #include <sys/stat.h> ! 36: #include <sys/time.h> ! 37: #include <sys/ioctl.h> ! 38: #include <sys/dir.h> ! 39: #include <sys/signal.h> ! 40: #include <netinet/in.h> ! 41: #include <netinet/in_systm.h> ! 42: #include <netinet/ip.h> ! 43: #include <pwd.h> ! 44: #include <netdb.h> ! 45: #include <errno.h> ! 46: #include <string.h> ! 47: #include <stdio.h> ! 48: #include <ctype.h> ! 49: #include "pathnames.h" ! 50: ! 51: #ifdef KERBEROS ! 52: #include <kerberosIV/des.h> ! 53: #include <kerberosIV/krb.h> ! 54: char dst_realm_buf[REALM_SZ]; ! 55: char *dest_realm = NULL; ! 56: int use_kerberos = 1; ! 57: CREDENTIALS cred; ! 58: Key_schedule schedule; ! 59: extern char *krb_realmofhost(); ! 60: #define OPTIONS "dfkprt" ! 61: #else ! 62: #define OPTIONS "dfprt" ! 63: #endif ! 64: ! 65: extern int errno; ! 66: struct passwd *pwd; ! 67: u_short port; ! 68: uid_t userid; ! 69: int errs, rem; ! 70: int pflag, iamremote, iamrecursive, targetshouldbedirectory; ! 71: ! 72: #define CMDNEEDS 64 ! 73: char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ ! 74: ! 75: typedef struct _buf { ! 76: int cnt; ! 77: char *buf; ! 78: } BUF; ! 79: ! 80: main(argc, argv) ! 81: int argc; ! 82: char **argv; ! 83: { ! 84: extern int optind; ! 85: struct servent *sp; ! 86: int ch, fflag, tflag; ! 87: char *targ, *shell, *colon(); ! 88: struct passwd *getpwuid(); ! 89: int lostconn(); ! 90: ! 91: fflag = tflag = 0; ! 92: while ((ch = getopt(argc, argv, OPTIONS)) != EOF) ! 93: switch(ch) { ! 94: /* user-visible flags */ ! 95: case 'p': /* preserve access/mod times */ ! 96: ++pflag; ! 97: break; ! 98: case 'r': ! 99: ++iamrecursive; ! 100: break; ! 101: #ifdef KERBEROS ! 102: case 'k': ! 103: strncpy(dst_realm_buf, ++argv, REALM_SZ); ! 104: dest_realm = dst_realm_buf; ! 105: break; ! 106: #endif ! 107: /* rshd-invoked options (server) */ ! 108: case 'd': ! 109: targetshouldbedirectory = 1; ! 110: break; ! 111: case 'f': /* "from" */ ! 112: iamremote = 1; ! 113: fflag = 1; ! 114: break; ! 115: case 't': /* "to" */ ! 116: iamremote = 1; ! 117: tflag = 1; ! 118: break; ! 119: ! 120: case '?': ! 121: default: ! 122: usage(); ! 123: } ! 124: argc -= optind; ! 125: argv += optind; ! 126: ! 127: #ifdef KERBEROS ! 128: shell = "kshell"; ! 129: sp = getservbyname(shell, "tcp"); ! 130: if (sp == NULL) { ! 131: char msgbuf[64]; ! 132: use_kerberos = 0; ! 133: (void) sprintf(msgbuf, "can't get entry for %s/tcp service", ! 134: shell); ! 135: old_warning(msgbuf); ! 136: sp = getservbyname("shell", "tcp"); ! 137: } ! 138: #else ! 139: sp = getservbyname("shell", "tcp"); ! 140: #endif ! 141: if (sp == NULL) { ! 142: (void)fprintf(stderr, "rcp: shell/tcp: unknown service\n"); ! 143: exit(1); ! 144: } ! 145: port = sp->s_port; ! 146: ! 147: if (!(pwd = getpwuid(userid = getuid()))) { ! 148: (void)fprintf(stderr, "rcp: unknown user %d.\n", userid); ! 149: exit(1); ! 150: } ! 151: ! 152: if (fflag) { ! 153: /* follow "protocol", send data */ ! 154: (void)response(); ! 155: (void)setuid(userid); ! 156: source(argc, argv); ! 157: exit(errs); ! 158: } ! 159: ! 160: if (tflag) { ! 161: /* receive data */ ! 162: (void)setuid(userid); ! 163: sink(argc, argv); ! 164: exit(errs); ! 165: } ! 166: ! 167: if (argc < 2) ! 168: usage(); ! 169: if (argc > 2) ! 170: targetshouldbedirectory = 1; ! 171: ! 172: rem = -1; ! 173: /* command to be executed on remote system using "rsh" */ ! 174: #ifdef KERBEROS ! 175: (void)sprintf(cmd, "rcp%s%s%s%s", iamrecursive ? " -r" : "", ! 176: "", ! 177: pflag ? " -p" : "", targetshouldbedirectory ? " -d" : ""); ! 178: #else ! 179: (void)sprintf(cmd, "rcp%s%s%s", iamrecursive ? " -r" : "", ! 180: pflag ? " -p" : "", targetshouldbedirectory ? " -d" : ""); ! 181: #endif ! 182: ! 183: (void)signal(SIGPIPE, lostconn); ! 184: ! 185: if (targ = colon(argv[argc - 1])) ! 186: toremote(targ, argc, argv); /* destination is remote host */ ! 187: else { ! 188: tolocal(argc, argv); /* destination is local host */ ! 189: if (targetshouldbedirectory) ! 190: verifydir(argv[argc - 1]); ! 191: } ! 192: exit(errs); ! 193: } ! 194: ! 195: toremote(targ, argc, argv) ! 196: char *targ; ! 197: int argc; ! 198: char **argv; ! 199: { ! 200: int i, tos; ! 201: char *bp, *host, *src, *suser, *thost, *tuser; ! 202: char *colon(), *malloc(); ! 203: ! 204: *targ++ = 0; ! 205: if (*targ == 0) ! 206: targ = "."; ! 207: ! 208: if (thost = index(argv[argc - 1], '@')) { ! 209: /* user@host */ ! 210: *thost++ = 0; ! 211: tuser = argv[argc - 1]; ! 212: if (*tuser == '\0') ! 213: tuser = NULL; ! 214: else if (!okname(tuser)) ! 215: exit(1); ! 216: } else { ! 217: thost = argv[argc - 1]; ! 218: tuser = NULL; ! 219: } ! 220: ! 221: for (i = 0; i < argc - 1; i++) { ! 222: src = colon(argv[i]); ! 223: if (src) { /* remote to remote */ ! 224: *src++ = 0; ! 225: if (*src == 0) ! 226: src = "."; ! 227: host = index(argv[i], '@'); ! 228: if (!(bp = malloc((u_int)(strlen(_PATH_RSH) + ! 229: strlen(argv[i]) + strlen(src) + ! 230: tuser ? strlen(tuser) : 0 + strlen(thost) + ! 231: strlen(targ)) + CMDNEEDS + 20))) ! 232: nospace(); ! 233: if (host) { ! 234: *host++ = 0; ! 235: suser = argv[i]; ! 236: if (*suser == '\0') ! 237: suser = pwd->pw_name; ! 238: else if (!okname(suser)) ! 239: continue; ! 240: (void)sprintf(bp, ! 241: "%s %s -l %s -n %s %s '%s%s%s:%s'", ! 242: _PATH_RSH, host, suser, cmd, src, ! 243: tuser ? tuser : "", tuser ? "@" : "", ! 244: thost, targ); ! 245: } else ! 246: (void)sprintf(bp, "%s %s -n %s %s '%s%s%s:%s'", ! 247: _PATH_RSH, argv[i], cmd, src, ! 248: tuser ? tuser : "", tuser ? "@" : "", ! 249: thost, targ); ! 250: (void)susystem(bp); ! 251: (void)free(bp); ! 252: } else { /* local to remote */ ! 253: if (rem == -1) { ! 254: if (!(bp = malloc((u_int)strlen(targ) + ! 255: CMDNEEDS + 20))) ! 256: nospace(); ! 257: (void)sprintf(bp, "%s -t %s", cmd, targ); ! 258: host = thost; ! 259: #ifdef KERBEROS ! 260: if (use_kerberos) ! 261: rem = kerberos(&host, bp, ! 262: pwd->pw_name, ! 263: tuser ? tuser : pwd->pw_name); ! 264: else ! 265: #endif ! 266: rem = rcmd(&host, port, pwd->pw_name, ! 267: tuser ? tuser : pwd->pw_name, ! 268: bp, 0); ! 269: if (rem < 0) ! 270: exit(1); ! 271: tos = IPTOS_THROUGHPUT; ! 272: if (setsockopt(rem, IPPROTO_IP, IP_TOS, ! 273: (char *)&tos, sizeof(int)) < 0) ! 274: perror("rcp: setsockopt TOS (ignored)"); ! 275: if (response() < 0) ! 276: exit(1); ! 277: (void)free(bp); ! 278: (void)setuid(userid); ! 279: } ! 280: source(1, argv+i); ! 281: } ! 282: } ! 283: } ! 284: ! 285: tolocal(argc, argv) ! 286: int argc; ! 287: char **argv; ! 288: { ! 289: int i, tos; ! 290: char *bp, *host, *src, *suser; ! 291: char *colon(), *malloc(); ! 292: ! 293: for (i = 0; i < argc - 1; i++) { ! 294: if (!(src = colon(argv[i]))) { /* local to local */ ! 295: if (!(bp = malloc((u_int)(strlen(_PATH_CP) + ! 296: strlen(argv[i]) + strlen(argv[argc - 1])) + 20))) ! 297: nospace(); ! 298: (void)sprintf(bp, "%s%s%s %s %s", _PATH_CP, ! 299: iamrecursive ? " -r" : "", pflag ? " -p" : "", ! 300: argv[i], argv[argc - 1]); ! 301: (void)susystem(bp); ! 302: (void)free(bp); ! 303: continue; ! 304: } ! 305: *src++ = 0; ! 306: if (*src == 0) ! 307: src = "."; ! 308: host = index(argv[i], '@'); ! 309: if (host) { ! 310: *host++ = 0; ! 311: suser = argv[i]; ! 312: if (*suser == '\0') ! 313: suser = pwd->pw_name; ! 314: else if (!okname(suser)) ! 315: continue; ! 316: } else { ! 317: host = argv[i]; ! 318: suser = pwd->pw_name; ! 319: } ! 320: if (!(bp = malloc((u_int)(strlen(src)) + CMDNEEDS + 20))) ! 321: nospace(); ! 322: (void)sprintf(bp, "%s -f %s", cmd, src); ! 323: #ifdef KERBEROS ! 324: if (use_kerberos) ! 325: rem = kerberos(&host, bp, pwd->pw_name, suser); ! 326: else ! 327: #endif ! 328: rem = rcmd(&host, port, pwd->pw_name, suser, bp, 0); ! 329: (void)free(bp); ! 330: if (rem < 0) ! 331: continue; ! 332: (void)seteuid(userid); ! 333: tos = IPTOS_THROUGHPUT; ! 334: if (setsockopt(rem, IPPROTO_IP, IP_TOS, ! 335: (char *)&tos, sizeof(int)) < 0) ! 336: perror("rcp: setsockopt TOS (ignored)"); ! 337: sink(1, argv + argc - 1); ! 338: (void)seteuid(0); ! 339: (void)close(rem); ! 340: rem = -1; ! 341: } ! 342: } ! 343: ! 344: verifydir(cp) ! 345: char *cp; ! 346: { ! 347: struct stat stb; ! 348: ! 349: if (stat(cp, &stb) >= 0) { ! 350: if ((stb.st_mode & S_IFMT) == S_IFDIR) ! 351: return; ! 352: errno = ENOTDIR; ! 353: } ! 354: error("rcp: %s: %s.\n", cp, strerror(errno)); ! 355: exit(1); ! 356: } ! 357: ! 358: char * ! 359: colon(cp) ! 360: register char *cp; ! 361: { ! 362: for (; *cp; ++cp) { ! 363: if (*cp == ':') ! 364: return(cp); ! 365: if (*cp == '/') ! 366: return(0); ! 367: } ! 368: return(0); ! 369: } ! 370: ! 371: okname(cp0) ! 372: char *cp0; ! 373: { ! 374: register char *cp = cp0; ! 375: register int c; ! 376: ! 377: do { ! 378: c = *cp; ! 379: if (c & 0200) ! 380: goto bad; ! 381: if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-') ! 382: goto bad; ! 383: } while (*++cp); ! 384: return(1); ! 385: bad: ! 386: (void)fprintf(stderr, "rcp: invalid user name %s\n", cp0); ! 387: return(0); ! 388: } ! 389: ! 390: susystem(s) ! 391: char *s; ! 392: { ! 393: int status, pid, w; ! 394: register sig_t istat, qstat; ! 395: ! 396: if ((pid = vfork()) == 0) { ! 397: (void)setuid(userid); ! 398: execl(_PATH_BSHELL, "sh", "-c", s, (char *)0); ! 399: _exit(127); ! 400: } ! 401: istat = signal(SIGINT, SIG_IGN); ! 402: qstat = signal(SIGQUIT, SIG_IGN); ! 403: while ((w = wait(&status)) != pid && w != -1) ! 404: ; ! 405: if (w == -1) ! 406: status = -1; ! 407: (void)signal(SIGINT, istat); ! 408: (void)signal(SIGQUIT, qstat); ! 409: return(status); ! 410: } ! 411: ! 412: source(argc, argv) ! 413: int argc; ! 414: char **argv; ! 415: { ! 416: struct stat stb; ! 417: static BUF buffer; ! 418: BUF *bp; ! 419: off_t i; ! 420: int x, readerr, f, amt; ! 421: char *last, *name, buf[BUFSIZ]; ! 422: BUF *allocbuf(); ! 423: ! 424: for (x = 0; x < argc; x++) { ! 425: name = argv[x]; ! 426: if ((f = open(name, O_RDONLY, 0)) < 0) { ! 427: error("rcp: %s: %s\n", name, strerror(errno)); ! 428: continue; ! 429: } ! 430: if (fstat(f, &stb) < 0) ! 431: goto notreg; ! 432: switch (stb.st_mode&S_IFMT) { ! 433: ! 434: case S_IFREG: ! 435: break; ! 436: ! 437: case S_IFDIR: ! 438: if (iamrecursive) { ! 439: (void)close(f); ! 440: rsource(name, &stb); ! 441: continue; ! 442: } ! 443: /* FALLTHROUGH */ ! 444: default: ! 445: notreg: (void)close(f); ! 446: error("rcp: %s: not a plain file\n", name); ! 447: continue; ! 448: } ! 449: last = rindex(name, '/'); ! 450: if (last == 0) ! 451: last = name; ! 452: else ! 453: last++; ! 454: if (pflag) { ! 455: /* ! 456: * Make it compatible with possible future ! 457: * versions expecting microseconds. ! 458: */ ! 459: (void)sprintf(buf, "T%ld 0 %ld 0\n", stb.st_mtime, ! 460: stb.st_atime); ! 461: (void)write(rem, buf, strlen(buf)); ! 462: if (response() < 0) { ! 463: (void)close(f); ! 464: continue; ! 465: } ! 466: } ! 467: (void)sprintf(buf, "C%04o %ld %s\n", stb.st_mode&07777, ! 468: stb.st_size, last); ! 469: (void)write(rem, buf, strlen(buf)); ! 470: if (response() < 0) { ! 471: (void)close(f); ! 472: continue; ! 473: } ! 474: if ((bp = allocbuf(&buffer, f, BUFSIZ)) == 0) { ! 475: (void)close(f); ! 476: continue; ! 477: } ! 478: readerr = 0; ! 479: for (i = 0; i < stb.st_size; i += bp->cnt) { ! 480: amt = bp->cnt; ! 481: if (i + amt > stb.st_size) ! 482: amt = stb.st_size - i; ! 483: if (readerr == 0 && read(f, bp->buf, amt) != amt) ! 484: readerr = errno; ! 485: (void)write(rem, bp->buf, amt); ! 486: } ! 487: (void)close(f); ! 488: if (readerr == 0) ! 489: (void)write(rem, "", 1); ! 490: else ! 491: error("rcp: %s: %s\n", name, strerror(readerr)); ! 492: (void)response(); ! 493: } ! 494: } ! 495: ! 496: rsource(name, statp) ! 497: char *name; ! 498: struct stat *statp; ! 499: { ! 500: DIR *d; ! 501: struct direct *dp; ! 502: char *last, *vect[1], path[MAXPATHLEN]; ! 503: ! 504: if (!(d = opendir(name))) { ! 505: error("rcp: %s: %s\n", name, strerror(errno)); ! 506: return; ! 507: } ! 508: last = rindex(name, '/'); ! 509: if (last == 0) ! 510: last = name; ! 511: else ! 512: last++; ! 513: if (pflag) { ! 514: (void)sprintf(path, "T%ld 0 %ld 0\n", statp->st_mtime, ! 515: statp->st_atime); ! 516: (void)write(rem, path, strlen(path)); ! 517: if (response() < 0) { ! 518: closedir(d); ! 519: return; ! 520: } ! 521: } ! 522: (void)sprintf(path, "D%04o %d %s\n", statp->st_mode&07777, 0, last); ! 523: (void)write(rem, path, strlen(path)); ! 524: if (response() < 0) { ! 525: closedir(d); ! 526: return; ! 527: } ! 528: while (dp = readdir(d)) { ! 529: if (dp->d_ino == 0) ! 530: continue; ! 531: if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) ! 532: continue; ! 533: if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) { ! 534: error("%s/%s: name too long.\n", name, dp->d_name); ! 535: continue; ! 536: } ! 537: (void)sprintf(path, "%s/%s", name, dp->d_name); ! 538: vect[0] = path; ! 539: source(1, vect); ! 540: } ! 541: closedir(d); ! 542: (void)write(rem, "E\n", 2); ! 543: (void)response(); ! 544: } ! 545: ! 546: response() ! 547: { ! 548: register char *cp; ! 549: char ch, resp, rbuf[BUFSIZ]; ! 550: ! 551: if (read(rem, &resp, sizeof(resp)) != sizeof(resp)) ! 552: lostconn(); ! 553: ! 554: cp = rbuf; ! 555: switch(resp) { ! 556: case 0: /* ok */ ! 557: return(0); ! 558: default: ! 559: *cp++ = resp; ! 560: /* FALLTHROUGH */ ! 561: case 1: /* error, followed by err msg */ ! 562: case 2: /* fatal error, "" */ ! 563: do { ! 564: if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) ! 565: lostconn(); ! 566: *cp++ = ch; ! 567: } while (cp < &rbuf[BUFSIZ] && ch != '\n'); ! 568: ! 569: if (!iamremote) ! 570: (void)write(2, rbuf, cp - rbuf); ! 571: ++errs; ! 572: if (resp == 1) ! 573: return(-1); ! 574: exit(1); ! 575: } ! 576: /*NOTREACHED*/ ! 577: } ! 578: ! 579: lostconn() ! 580: { ! 581: if (!iamremote) ! 582: (void)fprintf(stderr, "rcp: lost connection\n"); ! 583: exit(1); ! 584: } ! 585: ! 586: sink(argc, argv) ! 587: int argc; ! 588: char **argv; ! 589: { ! 590: register char *cp; ! 591: static BUF buffer; ! 592: struct stat stb; ! 593: struct timeval tv[2]; ! 594: enum { YES, NO, DISPLAYED } wrerr; ! 595: BUF *bp, *allocbuf(); ! 596: off_t i, j; ! 597: char ch, *targ, *why; ! 598: int amt, count, exists, first, mask, mode; ! 599: int ofd, setimes, size, targisdir; ! 600: char *np, *vect[1], buf[BUFSIZ], *malloc(); ! 601: ! 602: #define atime tv[0] ! 603: #define mtime tv[1] ! 604: #define SCREWUP(str) { why = str; goto screwup; } ! 605: ! 606: setimes = targisdir = 0; ! 607: mask = umask(0); ! 608: if (!pflag) ! 609: (void)umask(mask); ! 610: if (argc != 1) { ! 611: error("rcp: ambiguous target\n"); ! 612: exit(1); ! 613: } ! 614: targ = *argv; ! 615: if (targetshouldbedirectory) ! 616: verifydir(targ); ! 617: (void)write(rem, "", 1); ! 618: if (stat(targ, &stb) == 0 && (stb.st_mode & S_IFMT) == S_IFDIR) ! 619: targisdir = 1; ! 620: for (first = 1;; first = 0) { ! 621: cp = buf; ! 622: if (read(rem, cp, 1) <= 0) ! 623: return; ! 624: if (*cp++ == '\n') ! 625: SCREWUP("unexpected <newline>"); ! 626: do { ! 627: if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) ! 628: SCREWUP("lost connection"); ! 629: *cp++ = ch; ! 630: } while (cp < &buf[BUFSIZ - 1] && ch != '\n'); ! 631: *cp = 0; ! 632: ! 633: if (buf[0] == '\01' || buf[0] == '\02') { ! 634: if (iamremote == 0) ! 635: (void)write(2, buf + 1, strlen(buf + 1)); ! 636: if (buf[0] == '\02') ! 637: exit(1); ! 638: errs++; ! 639: continue; ! 640: } ! 641: if (buf[0] == 'E') { ! 642: (void)write(rem, "", 1); ! 643: return; ! 644: } ! 645: ! 646: if (ch == '\n') ! 647: *--cp = 0; ! 648: ! 649: #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0'); ! 650: cp = buf; ! 651: if (*cp == 'T') { ! 652: setimes++; ! 653: cp++; ! 654: getnum(mtime.tv_sec); ! 655: if (*cp++ != ' ') ! 656: SCREWUP("mtime.sec not delimited"); ! 657: getnum(mtime.tv_usec); ! 658: if (*cp++ != ' ') ! 659: SCREWUP("mtime.usec not delimited"); ! 660: getnum(atime.tv_sec); ! 661: if (*cp++ != ' ') ! 662: SCREWUP("atime.sec not delimited"); ! 663: getnum(atime.tv_usec); ! 664: if (*cp++ != '\0') ! 665: SCREWUP("atime.usec not delimited"); ! 666: (void)write(rem, "", 1); ! 667: continue; ! 668: } ! 669: if (*cp != 'C' && *cp != 'D') { ! 670: /* ! 671: * Check for the case "rcp remote:foo\* local:bar". ! 672: * In this case, the line "No match." can be returned ! 673: * by the shell before the rcp command on the remote is ! 674: * executed so the ^Aerror_message convention isn't ! 675: * followed. ! 676: */ ! 677: if (first) { ! 678: error("%s\n", cp); ! 679: exit(1); ! 680: } ! 681: SCREWUP("expected control record"); ! 682: } ! 683: mode = 0; ! 684: for (++cp; cp < buf + 5; cp++) { ! 685: if (*cp < '0' || *cp > '7') ! 686: SCREWUP("bad mode"); ! 687: mode = (mode << 3) | (*cp - '0'); ! 688: } ! 689: if (*cp++ != ' ') ! 690: SCREWUP("mode not delimited"); ! 691: size = 0; ! 692: while (isdigit(*cp)) ! 693: size = size * 10 + (*cp++ - '0'); ! 694: if (*cp++ != ' ') ! 695: SCREWUP("size not delimited"); ! 696: if (targisdir) { ! 697: static char *namebuf; ! 698: static int cursize; ! 699: int need; ! 700: ! 701: need = strlen(targ) + strlen(cp) + 250; ! 702: if (need > cursize) { ! 703: if (!(namebuf = malloc((u_int)need))) ! 704: error("out of memory\n"); ! 705: } ! 706: (void)sprintf(namebuf, "%s%s%s", targ, ! 707: *targ ? "/" : "", cp); ! 708: np = namebuf; ! 709: } ! 710: else ! 711: np = targ; ! 712: exists = stat(np, &stb) == 0; ! 713: if (buf[0] == 'D') { ! 714: if (exists) { ! 715: if ((stb.st_mode&S_IFMT) != S_IFDIR) { ! 716: errno = ENOTDIR; ! 717: goto bad; ! 718: } ! 719: if (pflag) ! 720: (void)chmod(np, mode); ! 721: } else if (mkdir(np, mode) < 0) ! 722: goto bad; ! 723: vect[0] = np; ! 724: sink(1, vect); ! 725: if (setimes) { ! 726: setimes = 0; ! 727: if (utimes(np, tv) < 0) ! 728: error("rcp: can't set times on %s: %s\n", ! 729: np, strerror(errno)); ! 730: } ! 731: continue; ! 732: } ! 733: if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { ! 734: bad: error("rcp: %s: %s\n", np, strerror(errno)); ! 735: continue; ! 736: } ! 737: if (exists && pflag) ! 738: (void)fchmod(ofd, mode); ! 739: (void)write(rem, "", 1); ! 740: if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == 0) { ! 741: (void)close(ofd); ! 742: continue; ! 743: } ! 744: cp = bp->buf; ! 745: count = 0; ! 746: wrerr = NO; ! 747: for (i = 0; i < size; i += BUFSIZ) { ! 748: amt = BUFSIZ; ! 749: if (i + amt > size) ! 750: amt = size - i; ! 751: count += amt; ! 752: do { ! 753: j = read(rem, cp, amt); ! 754: if (j <= 0) { ! 755: error("rcp: %s\n", ! 756: j ? strerror(errno) : ! 757: "dropped connection"); ! 758: exit(1); ! 759: } ! 760: amt -= j; ! 761: cp += j; ! 762: } while (amt > 0); ! 763: if (count == bp->cnt) { ! 764: if (wrerr == NO && ! 765: write(ofd, bp->buf, count) != count) ! 766: wrerr = YES; ! 767: count = 0; ! 768: cp = bp->buf; ! 769: } ! 770: } ! 771: if (count != 0 && wrerr == NO && ! 772: write(ofd, bp->buf, count) != count) ! 773: wrerr = YES; ! 774: if (ftruncate(ofd, size)) { ! 775: error("rcp: can't truncate %s: %s\n", np, ! 776: strerror(errno)); ! 777: wrerr = DISPLAYED; ! 778: } ! 779: (void)close(ofd); ! 780: (void)response(); ! 781: if (setimes && wrerr == NO) { ! 782: setimes = 0; ! 783: if (utimes(np, tv) < 0) { ! 784: error("rcp: can't set times on %s: %s\n", ! 785: np, strerror(errno)); ! 786: wrerr = DISPLAYED; ! 787: } ! 788: } ! 789: switch(wrerr) { ! 790: case YES: ! 791: error("rcp: %s: %s\n", np, strerror(errno)); ! 792: break; ! 793: case NO: ! 794: (void)write(rem, "", 1); ! 795: break; ! 796: case DISPLAYED: ! 797: break; ! 798: } ! 799: } ! 800: screwup: ! 801: error("rcp: protocol screwup: %s\n", why); ! 802: exit(1); ! 803: } ! 804: ! 805: BUF * ! 806: allocbuf(bp, fd, blksize) ! 807: BUF *bp; ! 808: int fd, blksize; ! 809: { ! 810: struct stat stb; ! 811: int size; ! 812: char *malloc(); ! 813: ! 814: if (fstat(fd, &stb) < 0) { ! 815: error("rcp: fstat: %s\n", strerror(errno)); ! 816: return(0); ! 817: } ! 818: size = roundup(stb.st_blksize, blksize); ! 819: if (size == 0) ! 820: size = blksize; ! 821: if (bp->cnt < size) { ! 822: if (bp->buf != 0) ! 823: free(bp->buf); ! 824: bp->buf = (char *)malloc((u_int)size); ! 825: if (!bp->buf) { ! 826: error("rcp: malloc: out of memory\n"); ! 827: return(0); ! 828: } ! 829: } ! 830: bp->cnt = size; ! 831: return(bp); ! 832: } ! 833: ! 834: /* VARARGS1 */ ! 835: error(fmt, a1, a2, a3) ! 836: char *fmt; ! 837: int a1, a2, a3; ! 838: { ! 839: static FILE *fp; ! 840: ! 841: ++errs; ! 842: if (!fp && !(fp = fdopen(rem, "w"))) ! 843: return; ! 844: (void)fprintf(fp, "%c", 0x01); ! 845: (void)fprintf(fp, fmt, a1, a2, a3); ! 846: (void)fflush(fp); ! 847: if (!iamremote) ! 848: (void)fprintf(stderr, fmt, a1, a2, a3); ! 849: } ! 850: ! 851: nospace() ! 852: { ! 853: (void)fprintf(stderr, "rcp: out of memory.\n"); ! 854: exit(1); ! 855: } ! 856: ! 857: ! 858: usage() ! 859: { ! 860: #ifdef KERBEROS ! 861: (void)fprintf(stderr, "%s\n\t%s\n", ! 862: "usage: rcp [-k realm] [-p] f1 f2", ! 863: "or: rcp [-k realm] [-rp] f1 ... fn directory"); ! 864: #else ! 865: (void)fprintf(stderr, ! 866: "usage: rcp [-p] f1 f2; or: rcp [-rp] f1 ... fn directory\n"); ! 867: #endif ! 868: exit(1); ! 869: } ! 870: ! 871: #ifdef KERBEROS ! 872: old_warning(str) ! 873: char *str; ! 874: { ! 875: (void)fprintf(stderr, "rcp: warning: %s, using standard rcp\n", str); ! 876: } ! 877: ! 878: int ! 879: kerberos(host, bp, locuser, user) ! 880: ! 881: char **host, *bp, *locuser, *user; ! 882: { ! 883: struct servent *sp; ! 884: ! 885: again: ! 886: if (use_kerberos) { ! 887: rem = KSUCCESS; ! 888: errno = 0; ! 889: if (dest_realm == NULL) ! 890: dest_realm = krb_realmofhost(*host); ! 891: ! 892: rem = krcmd( ! 893: host, port, ! 894: user, bp, 0, dest_realm); ! 895: ! 896: if (rem < 0) { ! 897: use_kerberos = 0; ! 898: sp = getservbyname("shell", "tcp"); ! 899: if (sp == NULL) { ! 900: (void)fprintf(stderr, ! 901: "rcp: unknown service shell/tcp\n"); ! 902: exit(1); ! 903: } ! 904: if (errno == ECONNREFUSED) ! 905: old_warning( ! 906: "remote host doesn't support Kerberos"); ! 907: ! 908: if (errno == ENOENT) ! 909: old_warning( ! 910: "Can't provide Kerberos auth data"); ! 911: port = sp->s_port; ! 912: goto again; ! 913: } ! 914: } else { ! 915: rem = rcmd(host, sp->s_port, locuser, user, bp, 0); ! 916: } ! 917: return(rem); ! 918: } ! 919: #endif /* KERBEROS */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.