]> git.saurik.com Git - apple/network_cmds.git/blame_incremental - rcp.tproj/rcp.c
network_cmds-77.tar.gz
[apple/network_cmds.git] / rcp.tproj / rcp.c
... / ...
CommitLineData
1/*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24/*
25 * Copyright (c) 1983, 1990, 1992, 1993
26 * The Regents of the University of California. All rights reserved.
27 *
28 * Redistribution and use in source and binary forms, with or without
29 * modification, are permitted provided that the following conditions
30 * are met:
31 * 1. Redistributions of source code must retain the above copyright
32 * notice, this list of conditions and the following disclaimer.
33 * 2. Redistributions in binary form must reproduce the above copyright
34 * notice, this list of conditions and the following disclaimer in the
35 * documentation and/or other materials provided with the distribution.
36 * 3. All advertising materials mentioning features or use of this software
37 * must display the following acknowledgement:
38 * This product includes software developed by the University of
39 * California, Berkeley and its contributors.
40 * 4. Neither the name of the University nor the names of its contributors
41 * may be used to endorse or promote products derived from this software
42 * without specific prior written permission.
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
55 */
56
57
58#include <sys/param.h>
59#include <sys/stat.h>
60#include <sys/time.h>
61#include <sys/socket.h>
62#include <netinet/in.h>
63#include <netinet/in_systm.h>
64#include <netinet/ip.h>
65
66#include <ctype.h>
67#include <dirent.h>
68#include <err.h>
69#include <errno.h>
70#include <fcntl.h>
71#include <netdb.h>
72#include <pwd.h>
73#include <signal.h>
74#include <stdio.h>
75#include <stdlib.h>
76#include <string.h>
77#include <string.h>
78#include <unistd.h>
79
80#include "pathnames.h"
81#include "extern.h"
82
83#ifdef KERBEROS
84#include <kerberosIV/des.h>
85#include <kerberosIV/krb.h>
86
87char dst_realm_buf[REALM_SZ];
88char *dest_realm = NULL;
89int use_kerberos = 1;
90CREDENTIALS cred;
91Key_schedule schedule;
92extern char *krb_realmofhost();
93#ifdef CRYPT
94int doencrypt = 0;
95#define OPTIONS "dfKk:prtx"
96#else
97#define OPTIONS "dfKk:prt"
98#endif
99#else
100#define OPTIONS "dfprt"
101#endif
102
103struct passwd *pwd;
104u_short port;
105uid_t userid;
106int errs, rem;
107int pflag, iamremote, iamrecursive, targetshouldbedirectory;
108
109#define CMDNEEDS 64
110char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */
111
112#ifdef KERBEROS
113int kerberos __P((char **, char *, char *, char *));
114void oldw __P((const char *, ...));
115#endif
116int response __P((void));
117void rsource __P((char *, struct stat *));
118void sink __P((int, char *[]));
119void source __P((int, char *[]));
120void tolocal __P((int, char *[]));
121void toremote __P((char *, int, char *[]));
122void usage __P((void));
123
124int
125main(argc, argv)
126 int argc;
127 char *argv[];
128{
129 struct servent *sp;
130 int ch, fflag, tflag;
131 char *targ, *shell;
132
133 fflag = tflag = 0;
134 while ((ch = getopt(argc, argv, OPTIONS)) != EOF)
135 switch(ch) { /* User-visible flags. */
136 case 'K':
137#ifdef KERBEROS
138 use_kerberos = 0;
139#endif
140 break;
141#ifdef KERBEROS
142 case 'k':
143 dest_realm = dst_realm_buf;
144 (void)strncpy(dst_realm_buf, optarg, REALM_SZ);
145 break;
146#ifdef CRYPT
147 case 'x':
148 doencrypt = 1;
149 /* des_set_key(cred.session, schedule); */
150 break;
151#endif
152#endif
153 case 'p':
154 pflag = 1;
155 break;
156 case 'r':
157 iamrecursive = 1;
158 break;
159 /* Server options. */
160 case 'd':
161 targetshouldbedirectory = 1;
162 break;
163 case 'f': /* "from" */
164 iamremote = 1;
165 fflag = 1;
166 break;
167 case 't': /* "to" */
168 iamremote = 1;
169 tflag = 1;
170 break;
171 case '?':
172 default:
173 usage();
174 }
175 argc -= optind;
176 argv += optind;
177
178#ifdef KERBEROS
179 if (use_kerberos) {
180#ifdef CRYPT
181 shell = doencrypt ? "ekshell" : "kshell";
182#else
183 shell = "kshell";
184#endif
185 if ((sp = getservbyname(shell, "tcp")) == NULL) {
186 use_kerberos = 0;
187 oldw("can't get entry for %s/tcp service", shell);
188 sp = getservbyname(shell = "shell", "tcp");
189 }
190 } else
191 sp = getservbyname(shell = "shell", "tcp");
192#else
193 sp = getservbyname(shell = "shell", "tcp");
194#endif
195 if (sp == NULL)
196 errx(1, "%s/tcp: unknown service", shell);
197 port = sp->s_port;
198
199 if ((pwd = getpwuid(userid = getuid())) == NULL)
200 errx(1, "unknown user %d", (int)userid);
201
202 rem = STDIN_FILENO; /* XXX */
203
204 if (fflag) { /* Follow "protocol", send data. */
205 (void)response();
206 (void)setuid(userid);
207 source(argc, argv);
208 exit(errs);
209 }
210
211 if (tflag) { /* Receive data. */
212 (void)setuid(userid);
213 sink(argc, argv);
214 exit(errs);
215 }
216
217 if (argc < 2)
218 usage();
219 if (argc > 2)
220 targetshouldbedirectory = 1;
221
222 rem = -1;
223 /* Command to be executed on remote system using "rsh". */
224#ifdef KERBEROS
225 (void)snprintf(cmd, sizeof(cmd),
226 "rcp%s%s%s%s", iamrecursive ? " -r" : "",
227#ifdef CRYPT
228 (doencrypt && use_kerberos ? " -x" : ""),
229#else
230 "",
231#endif
232 pflag ? " -p" : "", targetshouldbedirectory ? " -d" : "");
233#else
234 (void)snprintf(cmd, sizeof(cmd), "rcp%s%s%s",
235 iamrecursive ? " -r" : "", pflag ? " -p" : "",
236 targetshouldbedirectory ? " -d" : "");
237#endif
238
239 (void)signal(SIGPIPE, lostconn);
240
241 if (targ = colon(argv[argc - 1])) /* Dest is remote host. */
242 toremote(targ, argc, argv);
243 else {
244 tolocal(argc, argv); /* Dest is local host. */
245 if (targetshouldbedirectory)
246 verifydir(argv[argc - 1]);
247 }
248 exit(errs);
249}
250
251void
252toremote(targ, argc, argv)
253 char *targ, *argv[];
254 int argc;
255{
256 int i, len, tos;
257 char *bp, *host, *src, *suser, *thost, *tuser;
258
259 *targ++ = 0;
260 if (*targ == 0)
261 targ = ".";
262
263 if (thost = strchr(argv[argc - 1], '@')) {
264 /* user@host */
265 *thost++ = 0;
266 tuser = argv[argc - 1];
267 if (*tuser == '\0')
268 tuser = NULL;
269 else if (!okname(tuser))
270 exit(1);
271 } else {
272 thost = argv[argc - 1];
273 tuser = NULL;
274 }
275
276 for (i = 0; i < argc - 1; i++) {
277 src = colon(argv[i]);
278 if (src) { /* remote to remote */
279 *src++ = 0;
280 if (*src == 0)
281 src = ".";
282 host = strchr(argv[i], '@');
283 len = strlen(_PATH_RSH) + strlen(argv[i]) +
284 strlen(src) + (tuser ? strlen(tuser) : 0) +
285 strlen(thost) + strlen(targ) + CMDNEEDS + 20;
286 if (!(bp = malloc(len)))
287 err(1, NULL);
288 if (host) {
289 *host++ = 0;
290 suser = argv[i];
291 if (*suser == '\0')
292 suser = pwd->pw_name;
293 else if (!okname(suser))
294 continue;
295 (void)snprintf(bp, len,
296 "%s %s -l %s -n %s %s '%s%s%s:%s'",
297 _PATH_RSH, host, suser, cmd, src,
298 tuser ? tuser : "", tuser ? "@" : "",
299 thost, targ);
300 } else
301 (void)snprintf(bp, len,
302 "exec %s %s -n %s %s '%s%s%s:%s'",
303 _PATH_RSH, argv[i], cmd, src,
304 tuser ? tuser : "", tuser ? "@" : "",
305 thost, targ);
306 (void)susystem(bp, userid);
307 (void)free(bp);
308 } else { /* local to remote */
309 if (rem == -1) {
310 len = strlen(targ) + CMDNEEDS + 20;
311 if (!(bp = malloc(len)))
312 err(1, NULL);
313 (void)snprintf(bp, len, "%s -t %s", cmd, targ);
314 host = thost;
315#ifdef KERBEROS
316 if (use_kerberos)
317 rem = kerberos(&host, bp,
318 pwd->pw_name,
319 tuser ? tuser : pwd->pw_name);
320 else
321#endif
322 rem = rcmd(&host, port, pwd->pw_name,
323 tuser ? tuser : pwd->pw_name,
324 bp, 0);
325 if (rem < 0)
326 exit(1);
327 tos = IPTOS_THROUGHPUT;
328 if (setsockopt(rem, IPPROTO_IP, IP_TOS,
329 &tos, sizeof(int)) < 0)
330 warn("TOS (ignored)");
331 if (response() < 0)
332 exit(1);
333 (void)free(bp);
334 (void)setuid(userid);
335 }
336 source(1, argv+i);
337 }
338 }
339}
340
341void
342tolocal(argc, argv)
343 int argc;
344 char *argv[];
345{
346 int i, len, tos;
347 char *bp, *host, *src, *suser;
348
349 for (i = 0; i < argc - 1; i++) {
350 if (!(src = colon(argv[i]))) { /* Local to local. */
351 len = strlen(_PATH_CP) + strlen(argv[i]) +
352 strlen(argv[argc - 1]) + 20;
353 if (!(bp = malloc(len)))
354 err(1, NULL);
355 (void)snprintf(bp, len, "exec %s%s%s %s %s", _PATH_CP,
356 iamrecursive ? " -r" : "", pflag ? " -p" : "",
357 argv[i], argv[argc - 1]);
358 if (susystem(bp, userid))
359 ++errs;
360 (void)free(bp);
361 continue;
362 }
363 *src++ = 0;
364 if (*src == 0)
365 src = ".";
366 if ((host = strchr(argv[i], '@')) == NULL) {
367 host = argv[i];
368 suser = pwd->pw_name;
369 } else {
370 *host++ = 0;
371 suser = argv[i];
372 if (*suser == '\0')
373 suser = pwd->pw_name;
374 else if (!okname(suser))
375 continue;
376 }
377 len = strlen(src) + CMDNEEDS + 20;
378 if ((bp = malloc(len)) == NULL)
379 err(1, NULL);
380 (void)snprintf(bp, len, "%s -f %s", cmd, src);
381 rem =
382#ifdef KERBEROS
383 use_kerberos ?
384 kerberos(&host, bp, pwd->pw_name, suser) :
385#endif
386 rcmd(&host, port, pwd->pw_name, suser, bp, 0);
387 (void)free(bp);
388 if (rem < 0) {
389 ++errs;
390 continue;
391 }
392 (void)seteuid(userid);
393 tos = IPTOS_THROUGHPUT;
394 if (setsockopt(rem, IPPROTO_IP, IP_TOS, &tos, sizeof(int)) < 0)
395 warn("TOS (ignored)");
396 sink(1, argv + argc - 1);
397 (void)seteuid(0);
398 (void)close(rem);
399 rem = -1;
400 }
401}
402
403void
404source(argc, argv)
405 int argc;
406 char *argv[];
407{
408 struct stat stb;
409 static BUF buffer;
410 BUF *bp;
411 off_t i;
412 int amt, fd, haderr, indx, result;
413 char *last, *name, buf[BUFSIZ];
414
415 for (indx = 0; indx < argc; ++indx) {
416 name = argv[indx];
417 if ((fd = open(name, O_RDONLY, 0)) < 0)
418 goto syserr;
419 if (fstat(fd, &stb)) {
420syserr: run_err("%s: %s", name, strerror(errno));
421 goto next;
422 }
423 switch (stb.st_mode & S_IFMT) {
424 case S_IFREG:
425 break;
426 case S_IFDIR:
427 if (iamrecursive) {
428 rsource(name, &stb);
429 goto next;
430 }
431 /* FALLTHROUGH */
432 default:
433 run_err("%s: not a regular file", name);
434 goto next;
435 }
436 if ((last = strrchr(name, '/')) == NULL)
437 last = name;
438 else
439 ++last;
440 if (pflag) {
441 /*
442 * Make it compatible with possible future
443 * versions expecting microseconds.
444 */
445 (void)snprintf(buf, sizeof(buf), "T%ld 0 %ld 0\n",
446 stb.st_mtimespec.tv_sec, stb.st_atimespec.tv_sec);
447 (void)write(rem, buf, strlen(buf));
448 if (response() < 0)
449 goto next;
450 }
451#define MODEMASK (S_ISUID|S_ISGID|S_ISTXT|S_IRWXU|S_IRWXG|S_IRWXO)
452 (void)snprintf(buf, sizeof(buf), "C%04o %qd %s\n",
453 stb.st_mode & MODEMASK, stb.st_size, last);
454 (void)write(rem, buf, strlen(buf));
455 if (response() < 0)
456 goto next;
457 if ((bp = allocbuf(&buffer, fd, BUFSIZ)) == NULL) {
458next: (void)close(fd);
459 continue;
460 }
461
462 /* Keep writing after an error so that we stay sync'd up. */
463 for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
464 amt = bp->cnt;
465 if (i + amt > stb.st_size)
466 amt = stb.st_size - i;
467 if (!haderr) {
468 result = read(fd, bp->buf, amt);
469 if (result != amt)
470 haderr = result >= 0 ? EIO : errno;
471 }
472 if (haderr)
473 (void)write(rem, bp->buf, amt);
474 else {
475 result = write(rem, bp->buf, amt);
476 if (result != amt)
477 haderr = result >= 0 ? EIO : errno;
478 }
479 }
480 if (close(fd) && !haderr)
481 haderr = errno;
482 if (!haderr)
483 (void)write(rem, "", 1);
484 else
485 run_err("%s: %s", name, strerror(haderr));
486 (void)response();
487 }
488}
489
490void
491rsource(name, statp)
492 char *name;
493 struct stat *statp;
494{
495 DIR *dirp;
496 struct dirent *dp;
497 char *last, *vect[1], path[MAXPATHLEN];
498
499 if (!(dirp = opendir(name))) {
500 run_err("%s: %s", name, strerror(errno));
501 return;
502 }
503 last = strrchr(name, '/');
504 if (last == 0)
505 last = name;
506 else
507 last++;
508 if (pflag) {
509 (void)snprintf(path, sizeof(path), "T%ld 0 %ld 0\n",
510 statp->st_mtimespec.tv_sec, statp->st_atimespec.tv_sec);
511 (void)write(rem, path, strlen(path));
512 if (response() < 0) {
513 closedir(dirp);
514 return;
515 }
516 }
517 (void)snprintf(path, sizeof(path),
518 "D%04o %d %s\n", statp->st_mode & MODEMASK, 0, last);
519 (void)write(rem, path, strlen(path));
520 if (response() < 0) {
521 closedir(dirp);
522 return;
523 }
524 while (dp = readdir(dirp)) {
525 if (dp->d_ino == 0)
526 continue;
527 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
528 continue;
529 if (strlen(name) + 1 + strlen(dp->d_name) >= MAXPATHLEN - 1) {
530 run_err("%s/%s: name too long", name, dp->d_name);
531 continue;
532 }
533 (void)snprintf(path, sizeof(path), "%s/%s", name, dp->d_name);
534 vect[0] = path;
535 source(1, vect);
536 }
537 (void)closedir(dirp);
538 (void)write(rem, "E\n", 2);
539 (void)response();
540}
541
542void
543sink(argc, argv)
544 int argc;
545 char *argv[];
546{
547 static BUF buffer;
548 struct stat stb;
549 struct timeval tv[2];
550 enum { YES, NO, DISPLAYED } wrerr;
551 BUF *bp;
552 off_t i, j;
553 int amt, count, exists, first, mask, mode, ofd, omode;
554 int setimes, size, targisdir, wrerrno;
555 char ch, *cp, *np, *targ, *why, *vect[1], buf[BUFSIZ];
556
557#define atime tv[0]
558#define mtime tv[1]
559#define SCREWUP(str) { why = str; goto screwup; }
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(*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(*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) {
698bad: 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 (void)close(ofd);
757 (void)response();
758 if (setimes && wrerr == NO) {
759 setimes = 0;
760 if (utimes(np, tv) < 0) {
761 run_err("%s: set times: %s",
762 np, strerror(errno));
763 wrerr = DISPLAYED;
764 }
765 }
766 switch(wrerr) {
767 case YES:
768 run_err("%s: %s", np, strerror(wrerrno));
769 break;
770 case NO:
771 (void)write(rem, "", 1);
772 break;
773 case DISPLAYED:
774 break;
775 }
776 }
777screwup:
778 run_err("protocol error: %s", why);
779 exit(1);
780}
781
782#ifdef KERBEROS
783int
784kerberos(host, bp, locuser, user)
785 char **host, *bp, *locuser, *user;
786{
787 struct servent *sp;
788
789again:
790 if (use_kerberos) {
791 rem = KSUCCESS;
792 errno = 0;
793 if (dest_realm == NULL)
794 dest_realm = krb_realmofhost(*host);
795 rem =
796#ifdef CRYPT
797 doencrypt ?
798 krcmd_mutual(host,
799 port, user, bp, 0, dest_realm, &cred, schedule) :
800#endif
801 krcmd(host, port, user, bp, 0, dest_realm);
802
803 if (rem < 0) {
804 use_kerberos = 0;
805 if ((sp = getservbyname("shell", "tcp")) == NULL)
806 errx(1, "unknown service shell/tcp");
807 if (errno == ECONNREFUSED)
808 oldw("remote host doesn't support Kerberos");
809 else if (errno == ENOENT)
810 oldw("can't provide Kerberos authentication data");
811 port = sp->s_port;
812 goto again;
813 }
814 } else {
815#ifdef CRYPT
816 if (doencrypt)
817 errx(1,
818 "the -x option requires Kerberos authentication");
819#endif
820 rem = rcmd(host, port, locuser, user, bp, 0);
821 }
822 return (rem);
823}
824#endif /* KERBEROS */
825
826int
827response()
828{
829 char ch, *cp, resp, rbuf[BUFSIZ];
830
831 if (read(rem, &resp, sizeof(resp)) != sizeof(resp))
832 lostconn(0);
833
834 cp = rbuf;
835 switch(resp) {
836 case 0: /* ok */
837 return (0);
838 default:
839 *cp++ = resp;
840 /* FALLTHROUGH */
841 case 1: /* error, followed by error msg */
842 case 2: /* fatal error, "" */
843 do {
844 if (read(rem, &ch, sizeof(ch)) != sizeof(ch))
845 lostconn(0);
846 *cp++ = ch;
847 } while (cp < &rbuf[BUFSIZ] && ch != '\n');
848
849 if (!iamremote)
850 (void)write(STDERR_FILENO, rbuf, cp - rbuf);
851 ++errs;
852 if (resp == 1)
853 return (-1);
854 exit(1);
855 }
856 /* NOTREACHED */
857}
858
859void
860usage()
861{
862#ifdef KERBEROS
863#ifdef CRYPT
864 (void)fprintf(stderr, "%s\n\t%s\n",
865 "usage: rcp [-Kpx] [-k realm] f1 f2",
866 "or: rcp [-Kprx] [-k realm] f1 ... fn directory");
867#else
868 (void)fprintf(stderr, "%s\n\t%s\n",
869 "usage: rcp [-Kp] [-k realm] f1 f2",
870 "or: rcp [-Kpr] [-k realm] f1 ... fn directory");
871#endif
872#else
873 (void)fprintf(stderr,
874 "usage: rcp [-p] f1 f2; or: rcp [-pr] f1 ... fn directory\n");
875#endif
876 exit(1);
877}
878
879#if __STDC__
880#include <stdarg.h>
881#else
882#include <varargs.h>
883#endif
884
885#ifdef KERBEROS
886void
887#if __STDC__
888oldw(const char *fmt, ...)
889#else
890oldw(fmt, va_alist)
891 char *fmt;
892 va_dcl
893#endif
894{
895 va_list ap;
896#if __STDC__
897 va_start(ap, fmt);
898#else
899 va_start(ap);
900#endif
901 (void)fprintf(stderr, "rcp: ");
902 (void)vfprintf(stderr, fmt, ap);
903 (void)fprintf(stderr, ", using standard rcp\n");
904 va_end(ap);
905}
906#endif
907
908void
909#if __STDC__
910run_err(const char *fmt, ...)
911#else
912run_err(fmt, va_alist)
913 char *fmt;
914 va_dcl
915#endif
916{
917 static FILE *fp;
918 va_list ap;
919#if __STDC__
920 va_start(ap, fmt);
921#else
922 va_start(ap);
923#endif
924
925 ++errs;
926 if (fp == NULL && !(fp = fdopen(rem, "w")))
927 return;
928 (void)fprintf(fp, "%c", 0x01);
929 (void)fprintf(fp, "rcp: ");
930 (void)vfprintf(fp, fmt, ap);
931 (void)fprintf(fp, "\n");
932 (void)fflush(fp);
933
934 if (!iamremote)
935 vwarnx(fmt, ap);
936
937 va_end(ap);
938}