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