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