1 /* $NetBSD: rcp.c,v 1.9 1995/03/21 08:19:06 cgd 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.9 1995/03/21 08:19:06 cgd 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 (void)setuid(userid); 199 source(argc, argv); 200 exit(errs); 201 } 202 203 if (tflag) { /* Receive data. */ 204 (void)setuid(userid); 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])) /* 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 } 242 243 void 244 toremote(targ, argc, argv) 245 char *targ, *argv[]; 246 int argc; 247 { 248 int i, len, tos; 249 char *bp, *host, *src, *suser, *thost, *tuser; 250 251 *targ++ = 0; 252 if (*targ == 0) 253 targ = "."; 254 255 if (thost = strchr(argv[argc - 1], '@')) { 256 /* user@host */ 257 *thost++ = 0; 258 tuser = argv[argc - 1]; 259 if (*tuser == '\0') 260 tuser = NULL; 261 else if (!okname(tuser)) 262 exit(1); 263 } else { 264 thost = argv[argc - 1]; 265 tuser = NULL; 266 } 267 268 for (i = 0; i < argc - 1; i++) { 269 src = colon(argv[i]); 270 if (src) { /* remote to remote */ 271 *src++ = 0; 272 if (*src == 0) 273 src = "."; 274 host = strchr(argv[i], '@'); 275 len = strlen(_PATH_RSH) + strlen(argv[i]) + 276 strlen(src) + (tuser ? strlen(tuser) : 0) + 277 strlen(thost) + strlen(targ) + CMDNEEDS + 20; 278 if (!(bp = malloc(len))) 279 err(1, NULL); 280 if (host) { 281 *host++ = 0; 282 suser = argv[i]; 283 if (*suser == '\0') 284 suser = pwd->pw_name; 285 else if (!okname(suser)) 286 continue; 287 (void)snprintf(bp, len, 288 "%s %s -l %s -n %s %s '%s%s%s:%s'", 289 _PATH_RSH, host, suser, cmd, src, 290 tuser ? tuser : "", tuser ? "@" : "", 291 thost, targ); 292 } else 293 (void)snprintf(bp, len, 294 "exec %s %s -n %s %s '%s%s%s:%s'", 295 _PATH_RSH, argv[i], cmd, src, 296 tuser ? tuser : "", tuser ? "@" : "", 297 thost, targ); 298 (void)susystem(bp, userid); 299 (void)free(bp); 300 } else { /* local to remote */ 301 if (rem == -1) { 302 len = strlen(targ) + CMDNEEDS + 20; 303 if (!(bp = malloc(len))) 304 err(1, NULL); 305 (void)snprintf(bp, len, "%s -t %s", cmd, targ); 306 host = thost; 307 #ifdef KERBEROS 308 if (use_kerberos) 309 rem = kerberos(&host, bp, 310 pwd->pw_name, 311 tuser ? tuser : pwd->pw_name); 312 else 313 #endif 314 rem = rcmd(&host, port, pwd->pw_name, 315 tuser ? tuser : pwd->pw_name, 316 bp, 0); 317 if (rem < 0) 318 exit(1); 319 tos = IPTOS_THROUGHPUT; 320 if (setsockopt(rem, IPPROTO_IP, IP_TOS, 321 &tos, sizeof(int)) < 0) 322 warn("TOS (ignored)"); 323 if (response() < 0) 324 exit(1); 325 (void)free(bp); 326 (void)setuid(userid); 327 } 328 source(1, argv+i); 329 } 330 } 331 } 332 333 void 334 tolocal(argc, argv) 335 int argc; 336 char *argv[]; 337 { 338 int i, len, tos; 339 char *bp, *host, *src, *suser; 340 341 for (i = 0; i < argc - 1; i++) { 342 if (!(src = colon(argv[i]))) { /* Local to local. */ 343 len = strlen(_PATH_CP) + strlen(argv[i]) + 344 strlen(argv[argc - 1]) + 20; 345 if (!(bp = malloc(len))) 346 err(1, NULL); 347 (void)snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP, 348 iamrecursive ? " -r" : "", pflag ? " -p" : "", 349 argv[i], argv[argc - 1]); 350 if (susystem(bp, userid)) 351 ++errs; 352 (void)free(bp); 353 continue; 354 } 355 *src++ = 0; 356 if (*src == 0) 357 src = "."; 358 if ((host = strchr(argv[i], '@')) == NULL) { 359 host = argv[i]; 360 suser = pwd->pw_name; 361 } else { 362 *host++ = 0; 363 suser = argv[i]; 364 if (*suser == '\0') 365 suser = pwd->pw_name; 366 else if (!okname(suser)) 367 continue; 368 } 369 len = strlen(src) + CMDNEEDS + 20; 370 if ((bp = malloc(len)) == NULL) 371 err(1, NULL); 372 (void)snprintf(bp, len, "%s -f %s", cmd, src); 373 rem = 374 #ifdef KERBEROS 375 use_kerberos ? 376 kerberos(&host, bp, pwd->pw_name, suser) : 377 #endif 378 rcmd(&host, port, pwd->pw_name, suser, bp, 0); 379 (void)free(bp); 380 if (rem < 0) { 381 ++errs; 382 continue; 383 } 384 (void)seteuid(userid); 385 tos = IPTOS_THROUGHPUT; 386 if (setsockopt(rem, IPPROTO_IP, IP_TOS, &tos, sizeof(int)) < 0) 387 warn("TOS (ignored)"); 388 sink(1, argv + argc - 1); 389 (void)seteuid(0); 390 (void)close(rem); 391 rem = -1; 392 } 393 } 394 395 void 396 source(argc, argv) 397 int argc; 398 char *argv[]; 399 { 400 struct stat stb; 401 static BUF buffer; 402 BUF *bp; 403 off_t i; 404 int amt, fd, haderr, indx, result; 405 char *last, *name, buf[BUFSIZ]; 406 407 for (indx = 0; indx < argc; ++indx) { 408 name = argv[indx]; 409 if ((fd = open(name, O_RDONLY, 0)) < 0) 410 goto syserr; 411 if (fstat(fd, &stb)) { 412 syserr: run_err("%s: %s", name, strerror(errno)); 413 goto next; 414 } 415 switch (stb.st_mode & S_IFMT) { 416 case S_IFREG: 417 break; 418 case S_IFDIR: 419 if (iamrecursive) { 420 rsource(name, &stb); 421 goto next; 422 } 423 /* FALLTHROUGH */ 424 default: 425 run_err("%s: not a regular file", name); 426 goto next; 427 } 428 if ((last = strrchr(name, '/')) == NULL) 429 last = name; 430 else 431 ++last; 432 if (pflag) { 433 /* 434 * Make it compatible with possible future 435 * versions expecting microseconds. 436 */ 437 (void)snprintf(buf, sizeof(buf), "T%ld 0 %ld 0\n", 438 stb.st_mtimespec.ts_sec, stb.st_atimespec.ts_sec); 439 (void)write(rem, buf, strlen(buf)); 440 if (response() < 0) 441 goto next; 442 } 443 #define MODEMASK (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO) 444 (void)snprintf(buf, sizeof(buf), "C%04o %qd %s\n", 445 stb.st_mode & MODEMASK, stb.st_size, last); 446 (void)write(rem, buf, strlen(buf)); 447 if (response() < 0) 448 goto next; 449 if ((bp = allocbuf(&buffer, fd, BUFSIZ)) == NULL) { 450 next: (void)close(fd); 451 continue; 452 } 453 454 /* Keep writing after an error so that we stay sync'd up. */ 455 for (haderr = i = 0; i < stb.st_size; i += bp->cnt) { 456 amt = bp->cnt; 457 if (i + amt > stb.st_size) 458 amt = stb.st_size - i; 459 if (!haderr) { 460 result = read(fd, bp->buf, amt); 461 if (result != amt) 462 haderr = result >= 0 ? EIO : errno; 463 } 464 if (haderr) 465 (void)write(rem, bp->buf, amt); 466 else { 467 result = write(rem, bp->buf, amt); 468 if (result != amt) 469 haderr = result >= 0 ? EIO : errno; 470 } 471 } 472 if (close(fd) && !haderr) 473 haderr = errno; 474 if (!haderr) 475 (void)write(rem, "", 1); 476 else 477 run_err("%s: %s", name, strerror(haderr)); 478 (void)response(); 479 } 480 } 481 482 void 483 rsource(name, statp) 484 char *name; 485 struct stat *statp; 486 { 487 DIR *dirp; 488 struct dirent *dp; 489 char *last, *vect[1], path[MAXPATHLEN]; 490 491 if (!(dirp = opendir(name))) { 492 run_err("%s: %s", name, strerror(errno)); 493 return; 494 } 495 last = strrchr(name, '/'); 496 if (last == 0) 497 last = name; 498 else 499 last++; 500 if (pflag) { 501 (void)snprintf(path, sizeof(path), "T%ld 0 %ld 0\n", 502 statp->st_mtimespec.ts_sec, statp->st_atimespec.ts_sec); 503 (void)write(rem, path, strlen(path)); 504 if (response() < 0) { 505 closedir(dirp); 506 return; 507 } 508 } 509 (void)snprintf(path, sizeof(path), 510 "D%04o %d %s\n", statp->st_mode & MODEMASK, 0, last); 511 (void)write(rem, path, strlen(path)); 512 if (response() < 0) { 513 closedir(dirp); 514 return; 515 } 516 while (dp = readdir(dirp)) { 517 if (dp->d_ino == 0) 518 continue; 519 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) 520 continue; 521 if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) { 522 run_err("%s/%s: name too long", name, dp->d_name); 523 continue; 524 } 525 (void)snprintf(path, sizeof(path), "%s/%s", name, dp->d_name); 526 vect[0] = path; 527 source(1, vect); 528 } 529 (void)closedir(dirp); 530 (void)write(rem, "E\n", 2); 531 (void)response(); 532 } 533 534 void 535 sink(argc, argv) 536 int argc; 537 char *argv[]; 538 { 539 static BUF buffer; 540 struct stat stb; 541 struct timeval tv[2]; 542 enum { YES, NO, DISPLAYED } wrerr; 543 BUF *bp; 544 off_t i, j; 545 int amt, count, exists, first, mask, mode, ofd, omode; 546 int setimes, size, targisdir, wrerrno; 547 char ch, *cp, *np, *targ, *why, *vect[1], buf[BUFSIZ]; 548 549 #define atime tv[0] 550 #define mtime tv[1] 551 #define SCREWUP(str) { why = str; goto screwup; } 552 553 setimes = targisdir = 0; 554 mask = umask(0); 555 if (!pflag) 556 (void)umask(mask); 557 if (argc != 1) { 558 run_err("ambiguous target"); 559 exit(1); 560 } 561 targ = *argv; 562 if (targetshouldbedirectory) 563 verifydir(targ); 564 (void)write(rem, "", 1); 565 if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) 566 targisdir = 1; 567 for (first = 1;; first = 0) { 568 cp = buf; 569 if (read(rem, cp, 1) <= 0) 570 return; 571 if (*cp++ == '\n') 572 SCREWUP("unexpected <newline>"); 573 do { 574 if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) 575 SCREWUP("lost connection"); 576 *cp++ = ch; 577 } while (cp < &buf[BUFSIZ - 1] && ch != '\n'); 578 *cp = 0; 579 580 if (buf[0] == '\01' || buf[0] == '\02') { 581 if (iamremote == 0) 582 (void)write(STDERR_FILENO, 583 buf + 1, strlen(buf + 1)); 584 if (buf[0] == '\02') 585 exit(1); 586 ++errs; 587 continue; 588 } 589 if (buf[0] == 'E') { 590 (void)write(rem, "", 1); 591 return; 592 } 593 594 if (ch == '\n') 595 *--cp = 0; 596 597 #define getnum(t) (t) = 0; while (isdigit(*cp)) (t) = (t) * 10 + (*cp++ - '0'); 598 cp = buf; 599 if (*cp == 'T') { 600 setimes++; 601 cp++; 602 getnum(mtime.tv_sec); 603 if (*cp++ != ' ') 604 SCREWUP("mtime.sec not delimited"); 605 getnum(mtime.tv_usec); 606 if (*cp++ != ' ') 607 SCREWUP("mtime.usec not delimited"); 608 getnum(atime.tv_sec); 609 if (*cp++ != ' ') 610 SCREWUP("atime.sec not delimited"); 611 getnum(atime.tv_usec); 612 if (*cp++ != '\0') 613 SCREWUP("atime.usec not delimited"); 614 (void)write(rem, "", 1); 615 continue; 616 } 617 if (*cp != 'C' && *cp != 'D') { 618 /* 619 * Check for the case "rcp remote:foo\* local:bar". 620 * In this case, the line "No match." can be returned 621 * by the shell before the rcp command on the remote is 622 * executed so the ^Aerror_message convention isn't 623 * followed. 624 */ 625 if (first) { 626 run_err("%s", cp); 627 exit(1); 628 } 629 SCREWUP("expected control record"); 630 } 631 mode = 0; 632 for (++cp; cp < buf + 5; cp++) { 633 if (*cp < '0' || *cp > '7') 634 SCREWUP("bad mode"); 635 mode = (mode << 3) | (*cp - '0'); 636 } 637 if (*cp++ != ' ') 638 SCREWUP("mode not delimited"); 639 640 for (size = 0; isdigit(*cp);) 641 size = size * 10 + (*cp++ - '0'); 642 if (*cp++ != ' ') 643 SCREWUP("size not delimited"); 644 if (targisdir) { 645 static char *namebuf; 646 static int cursize; 647 size_t need; 648 649 need = strlen(targ) + strlen(cp) + 250; 650 if (need > cursize) { 651 if (!(namebuf = malloc(need))) 652 run_err("%s", strerror(errno)); 653 } 654 (void)snprintf(namebuf, need, "%s%s%s", targ, 655 *targ ? "/" : "", cp); 656 np = namebuf; 657 } else 658 np = targ; 659 exists = stat(np, &stb) == 0; 660 if (buf[0] == 'D') { 661 int mod_flag = pflag; 662 if (exists) { 663 if (!S_ISDIR(stb.st_mode)) { 664 errno = ENOTDIR; 665 goto bad; 666 } 667 if (pflag) 668 (void)chmod(np, mode); 669 } else { 670 /* Handle copying from a read-only directory */ 671 mod_flag = 1; 672 if (mkdir(np, mode | S_IRWXU) < 0) 673 goto bad; 674 } 675 vect[0] = np; 676 sink(1, vect); 677 if (setimes) { 678 setimes = 0; 679 if (utimes(np, tv) < 0) 680 run_err("%s: set times: %s", 681 np, strerror(errno)); 682 } 683 if (mod_flag) 684 (void)chmod(np, mode); 685 continue; 686 } 687 omode = mode; 688 mode |= S_IWRITE; 689 if ((ofd = open(np, O_WRONLY|O_CREAT, mode)) < 0) { 690 bad: run_err("%s: %s", np, strerror(errno)); 691 continue; 692 } 693 (void)write(rem, "", 1); 694 if ((bp = allocbuf(&buffer, ofd, BUFSIZ)) == NULL) { 695 (void)close(ofd); 696 continue; 697 } 698 cp = bp->buf; 699 wrerr = NO; 700 for (count = i = 0; i < size; i += BUFSIZ) { 701 amt = BUFSIZ; 702 if (i + amt > size) 703 amt = size - i; 704 count += amt; 705 do { 706 j = read(rem, cp, amt); 707 if (j <= 0) { 708 run_err("%s", j ? strerror(errno) : 709 "dropped connection"); 710 exit(1); 711 } 712 amt -= j; 713 cp += j; 714 } while (amt > 0); 715 if (count == bp->cnt) { 716 /* Keep reading so we stay sync'd up. */ 717 if (wrerr == NO) { 718 j = write(ofd, bp->buf, count); 719 if (j != count) { 720 wrerr = YES; 721 wrerrno = j >= 0 ? EIO : errno; 722 } 723 } 724 count = 0; 725 cp = bp->buf; 726 } 727 } 728 if (count != 0 && wrerr == NO && 729 (j = write(ofd, bp->buf, count)) != count) { 730 wrerr = YES; 731 wrerrno = j >= 0 ? EIO : errno; 732 } 733 if (ftruncate(ofd, size)) { 734 run_err("%s: truncate: %s", np, strerror(errno)); 735 wrerr = DISPLAYED; 736 } 737 if (pflag) { 738 if (exists || omode != mode) 739 if (fchmod(ofd, omode)) 740 run_err("%s: set mode: %s", 741 np, strerror(errno)); 742 } else { 743 if (!exists && omode != mode) 744 if (fchmod(ofd, omode & ~mask)) 745 run_err("%s: set mode: %s", 746 np, strerror(errno)); 747 } 748 (void)close(ofd); 749 (void)response(); 750 if (setimes && wrerr == NO) { 751 setimes = 0; 752 if (utimes(np, tv) < 0) { 753 run_err("%s: set times: %s", 754 np, strerror(errno)); 755 wrerr = DISPLAYED; 756 } 757 } 758 switch(wrerr) { 759 case YES: 760 run_err("%s: %s", np, strerror(wrerrno)); 761 break; 762 case NO: 763 (void)write(rem, "", 1); 764 break; 765 case DISPLAYED: 766 break; 767 } 768 } 769 screwup: 770 run_err("protocol error: %s", why); 771 exit(1); 772 } 773 774 #ifdef KERBEROS 775 int 776 kerberos(host, bp, locuser, user) 777 char **host, *bp, *locuser, *user; 778 { 779 struct servent *sp; 780 781 again: 782 if (use_kerberos) { 783 rem = KSUCCESS; 784 errno = 0; 785 if (dest_realm == NULL) 786 dest_realm = krb_realmofhost(*host); 787 rem = 788 #ifdef CRYPT 789 doencrypt ? 790 krcmd_mutual(host, 791 port, user, bp, 0, dest_realm, &cred, schedule) : 792 #endif 793 krcmd(host, port, user, bp, 0, dest_realm); 794 795 if (rem < 0) { 796 use_kerberos = 0; 797 if ((sp = getservbyname("shell", "tcp")) == NULL) 798 errx(1, "unknown service shell/tcp"); 799 if (errno == ECONNREFUSED) 800 oldw("remote host doesn't support Kerberos"); 801 else if (errno == ENOENT) 802 oldw("can't provide Kerberos authentication data"); 803 port = sp->s_port; 804 goto again; 805 } 806 } else { 807 #ifdef CRYPT 808 if (doencrypt) 809 errx(1, 810 "the -x option requires Kerberos authentication"); 811 #endif 812 rem = rcmd(host, port, locuser, user, bp, 0); 813 } 814 return (rem); 815 } 816 #endif /* KERBEROS */ 817 818 int 819 response() 820 { 821 char ch, *cp, resp, rbuf[BUFSIZ]; 822 823 if (read(rem, &resp, sizeof(resp)) != sizeof(resp)) 824 lostconn(0); 825 826 cp = rbuf; 827 switch(resp) { 828 case 0: /* ok */ 829 return (0); 830 default: 831 *cp++ = resp; 832 /* FALLTHROUGH */ 833 case 1: /* error, followed by error msg */ 834 case 2: /* fatal error, "" */ 835 do { 836 if (read(rem, &ch, sizeof(ch)) != sizeof(ch)) 837 lostconn(0); 838 *cp++ = ch; 839 } while (cp < &rbuf[BUFSIZ] && ch != '\n'); 840 841 if (!iamremote) 842 (void)write(STDERR_FILENO, rbuf, cp - rbuf); 843 ++errs; 844 if (resp == 1) 845 return (-1); 846 exit(1); 847 } 848 /* NOTREACHED */ 849 } 850 851 void 852 usage() 853 { 854 #ifdef KERBEROS 855 #ifdef CRYPT 856 (void)fprintf(stderr, "%s\n\t%s\n", 857 "usage: rcp [-Kpx] [-k realm] f1 f2", 858 "or: rcp [-Kprx] [-k realm] f1 ... fn directory"); 859 #else 860 (void)fprintf(stderr, "%s\n\t%s\n", 861 "usage: rcp [-Kp] [-k realm] f1 f2", 862 "or: rcp [-Kpr] [-k realm] f1 ... fn directory"); 863 #endif 864 #else 865 (void)fprintf(stderr, 866 "usage: rcp [-p] f1 f2; or: rcp [-pr] f1 ... fn directory\n"); 867 #endif 868 exit(1); 869 } 870 871 #if __STDC__ 872 #include <stdarg.h> 873 #else 874 #include <varargs.h> 875 #endif 876 877 #ifdef KERBEROS 878 void 879 #if __STDC__ 880 oldw(const char *fmt, ...) 881 #else 882 oldw(fmt, va_alist) 883 char *fmt; 884 va_dcl 885 #endif 886 { 887 va_list ap; 888 #if __STDC__ 889 va_start(ap, fmt); 890 #else 891 va_start(ap); 892 #endif 893 (void)fprintf(stderr, "rcp: "); 894 (void)vfprintf(stderr, fmt, ap); 895 (void)fprintf(stderr, ", using standard rcp\n"); 896 va_end(ap); 897 } 898 #endif 899 900 void 901 #if __STDC__ 902 run_err(const char *fmt, ...) 903 #else 904 run_err(fmt, va_alist) 905 char *fmt; 906 va_dcl 907 #endif 908 { 909 static FILE *fp; 910 va_list ap; 911 #if __STDC__ 912 va_start(ap, fmt); 913 #else 914 va_start(ap); 915 #endif 916 917 ++errs; 918 if (fp == NULL && !(fp = fdopen(rem, "w"))) 919 return; 920 (void)fprintf(fp, "%c", 0x01); 921 (void)fprintf(fp, "rcp: "); 922 (void)vfprintf(fp, fmt, ap); 923 (void)fprintf(fp, "\n"); 924 (void)fflush(fp); 925 926 if (!iamremote) 927 vwarnx(fmt, ap); 928 929 va_end(ap); 930 } 931