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