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