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