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