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