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