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