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