Annotation of src/usr.bin/ssh/scp.c, Revision 1.3
1.1 deraadt 1: /*
2:
3: scp - secure remote copy. This is basically patched BSD rcp which uses ssh
4: to do the data transfer (instead of using rcmd).
5:
6: NOTE: This version should NOT be suid root. (This uses ssh to do the transfer
7: and ssh has the necessary privileges.)
8:
9: 1995 Timo Rinne <tri@iki.fi>, Tatu Ylonen <ylo@cs.hut.fi>
10:
11: */
12:
13: /*
14: * Copyright (c) 1983, 1990, 1992, 1993, 1995
15: * The Regents of the University of California. All rights reserved.
16: *
17: * Redistribution and use in source and binary forms, with or without
18: * modification, are permitted provided that the following conditions
19: * are met:
20: * 1. Redistributions of source code must retain the above copyright
21: * notice, this list of conditions and the following disclaimer.
22: * 2. Redistributions in binary form must reproduce the above copyright
23: * notice, this list of conditions and the following disclaimer in the
24: * documentation and/or other materials provided with the distribution.
25: * 3. All advertising materials mentioning features or use of this software
26: * must display the following acknowledgement:
27: * This product includes software developed by the University of
28: * California, Berkeley and its contributors.
29: * 4. Neither the name of the University nor the names of its contributors
30: * may be used to endorse or promote products derived from this software
31: * without specific prior written permission.
32: *
33: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
34: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
37: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43: * SUCH DAMAGE.
44: *
1.3 ! deraadt 45: * $Id: scp.c,v 1.2 1999/09/29 18:16:20 dugsong Exp $
1.1 deraadt 46: */
47:
48: #include "includes.h"
1.3 ! deraadt 49: RCSID("$Id: scp.c,v 1.2 1999/09/29 18:16:20 dugsong Exp $");
1.1 deraadt 50:
51: #include "ssh.h"
52: #include "xmalloc.h"
53: #ifdef HAVE_UTIME_H
54: #include <utime.h>
55: #ifdef _NEXT_SOURCE
56: struct utimbuf {
57: time_t actime;
58: time_t modtime;
59: };
60: #endif /* _NEXT_SOURCE */
61: #else
62: struct utimbuf
63: {
64: long actime;
65: long modtime;
66: };
67: #endif
68:
69: #define _PATH_CP "cp"
70:
71: #ifndef STDIN_FILENO
72: #define STDIN_FILENO 0
73: #endif
74: #ifndef STDOUT_FILENO
75: #define STDOUT_FILENO 1
76: #endif
77: #ifndef STDERR_FILENO
78: #define STDERR_FILENO 2
79: #endif
80:
81: /* This is set to non-zero to enable verbose mode. */
82: int verbose = 0;
83:
84: /* This is set to non-zero if compression is desired. */
85: int compress = 0;
86:
87: /* This is set to non-zero if running in batch mode (that is, password
88: and passphrase queries are not allowed). */
89: int batchmode = 0;
90:
91: /* This is set to the cipher type string if given on the command line. */
92: char *cipher = NULL;
93:
94: /* This is set to the RSA authentication identity file name if given on
95: the command line. */
96: char *identity = NULL;
97:
98: /* This is the port to use in contacting the remote site (is non-NULL). */
99: char *port = NULL;
100:
101: /* This function executes the given command as the specified user on the given
102: host. This returns < 0 if execution fails, and >= 0 otherwise.
103: This assigns the input and output file descriptors on success. */
104:
105: int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout)
106: {
107: int pin[2], pout[2], reserved[2];
108:
109: if (verbose)
110: fprintf(stderr, "Executing: host %s, user %s, command %s\n",
111: host, remuser ? remuser : "(unspecified)", cmd);
112:
113: /* Reserve two descriptors so that the real pipes won't get descriptors
114: 0 and 1 because that will screw up dup2 below. */
115: pipe(reserved);
116:
117: /* Create a socket pair for communicating with ssh. */
118: if (pipe(pin) < 0)
119: fatal("pipe: %s", strerror(errno));
120: if (pipe(pout) < 0)
121: fatal("pipe: %s", strerror(errno));
122:
123: /* Free the reserved descriptors. */
124: close(reserved[0]);
125: close(reserved[1]);
126:
127: /* For a child to execute the command on the remote host using ssh. */
128: if (fork() == 0)
129: {
130: char *args[100];
131: unsigned int i;
132:
133: /* Child. */
134: close(pin[1]);
135: close(pout[0]);
136: dup2(pin[0], 0);
137: dup2(pout[1], 1);
138: close(pin[0]);
139: close(pout[1]);
140:
141: i = 0;
142: args[i++] = SSH_PROGRAM;
143: args[i++] = "-x";
144: args[i++] = "-oFallBackToRsh no";
145: if (verbose)
146: args[i++] = "-v";
147: if (compress)
148: args[i++] = "-C";
149: if (batchmode)
150: args[i++] = "-oBatchMode yes";
151: if (cipher != NULL)
152: {
153: args[i++] = "-c";
154: args[i++] = cipher;
155: }
156: if (identity != NULL)
157: {
158: args[i++] = "-i";
159: args[i++] = identity;
160: }
161: if (port != NULL)
162: {
163: args[i++] = "-p";
164: args[i++] = port;
165: }
166: if (remuser != NULL)
167: {
168: args[i++] = "-l";
169: args[i++] = remuser;
170: }
171: args[i++] = host;
172: args[i++] = cmd;
173: args[i++] = NULL;
174:
175: execvp(SSH_PROGRAM, args);
176: perror(SSH_PROGRAM);
177: exit(1);
178: }
179: /* Parent. Close the other side, and return the local side. */
180: close(pin[0]);
181: *fdout = pin[1];
182: close(pout[1]);
183: *fdin = pout[0];
184: return 0;
185: }
186:
187: void fatal(const char *fmt, ...)
188: {
189: va_list ap;
190: char buf[1024];
191:
192: va_start(ap, fmt);
193: vsnprintf(buf, sizeof(buf), fmt, ap);
194: va_end(ap);
195: fprintf(stderr, "%s\n", buf);
196: exit(255);
197: }
198:
199: /* This stuff used to be in BSD rcp extern.h. */
200:
201: typedef struct {
202: int cnt;
203: char *buf;
204: } BUF;
205:
206: extern int iamremote;
207:
208: BUF *allocbuf(BUF *, int, int);
209: char *colon(char *);
210: void lostconn(int);
211: void nospace(void);
212: int okname(char *);
213: void run_err(const char *, ...);
214: void verifydir(char *);
215:
216: /* Stuff from BSD rcp.c continues. */
217:
218: struct passwd *pwd;
219: uid_t userid;
220: int errs, remin, remout;
221: int pflag, iamremote, iamrecursive, targetshouldbedirectory;
222:
223: #define CMDNEEDS 64
224: char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */
225:
226: int response(void);
227: void rsource(char *, struct stat *);
228: void sink(int, char *[]);
229: void source(int, char *[]);
230: void tolocal(int, char *[]);
231: void toremote(char *, int, char *[]);
232: void usage(void);
233:
234: int
235: main(argc, argv)
236: int argc;
237: char *argv[];
238: {
239: int ch, fflag, tflag;
240: char *targ;
241: extern char *optarg;
242: extern int optind;
243:
244: fflag = tflag = 0;
245: while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:")) != EOF)
246: switch(ch) { /* User-visible flags. */
247: case 'p':
248: pflag = 1;
249: break;
250: case 'P':
251: port = optarg;
252: break;
253: case 'r':
254: iamrecursive = 1;
255: break;
256: /* Server options. */
257: case 'd':
258: targetshouldbedirectory = 1;
259: break;
260: case 'f': /* "from" */
261: iamremote = 1;
262: fflag = 1;
263: break;
264: case 't': /* "to" */
265: iamremote = 1;
266: tflag = 1;
267: break;
268: case 'c':
269: cipher = optarg;
270: break;
271: case 'i':
272: identity = optarg;
273: break;
274: case 'v':
275: verbose = 1;
276: break;
277: case 'B':
278: batchmode = 1;
279: break;
280: case 'C':
281: compress = 1;
282: break;
283: case '?':
284: default:
285: usage();
286: }
287: argc -= optind;
288: argv += optind;
289:
290: if ((pwd = getpwuid(userid = getuid())) == NULL)
291: fatal("unknown user %d", (int)userid);
292:
293: remin = STDIN_FILENO;
294: remout = STDOUT_FILENO;
295:
296: if (fflag) { /* Follow "protocol", send data. */
297: (void)response();
298: source(argc, argv);
299: exit(errs != 0);
300: }
301:
302: if (tflag) { /* Receive data. */
303: sink(argc, argv);
304: exit(errs != 0);
305: }
306:
307: if (argc < 2)
308: usage();
309: if (argc > 2)
310: targetshouldbedirectory = 1;
311:
312: remin = remout = -1;
313: /* Command to be executed on remote system using "ssh". */
314: (void)sprintf(cmd, "scp%s%s%s%s", verbose ? " -v" : "",
315: iamrecursive ? " -r" : "", pflag ? " -p" : "",
316: targetshouldbedirectory ? " -d" : "");
317:
318: (void)signal(SIGPIPE, lostconn);
319:
320: if ((targ = colon(argv[argc - 1]))) /* Dest is remote host. */
321: toremote(targ, argc, argv);
322: else {
323: tolocal(argc, argv); /* Dest is local host. */
324: if (targetshouldbedirectory)
325: verifydir(argv[argc - 1]);
326: }
327: exit(errs != 0);
328: }
329:
330: void
331: toremote(targ, argc, argv)
332: char *targ, *argv[];
333: int argc;
334: {
335: int i, len;
336: char *bp, *host, *src, *suser, *thost, *tuser;
337:
338: *targ++ = 0;
339: if (*targ == 0)
340: targ = ".";
341:
342: if ((thost = strchr(argv[argc - 1], '@'))) {
343: /* user@host */
344: *thost++ = 0;
345: tuser = argv[argc - 1];
346: if (*tuser == '\0')
347: tuser = NULL;
348: else if (!okname(tuser))
349: exit(1);
350: } else {
351: thost = argv[argc - 1];
352: tuser = NULL;
353: }
354:
355: for (i = 0; i < argc - 1; i++) {
356: src = colon(argv[i]);
357: if (src) { /* remote to remote */
358: *src++ = 0;
359: if (*src == 0)
360: src = ".";
361: host = strchr(argv[i], '@');
362: len = strlen(SSH_PROGRAM) + strlen(argv[i]) +
363: strlen(src) + (tuser ? strlen(tuser) : 0) +
364: strlen(thost) + strlen(targ) + CMDNEEDS + 32;
365: bp = xmalloc(len);
366: if (host) {
367: *host++ = 0;
368: suser = argv[i];
369: if (*suser == '\0')
370: suser = pwd->pw_name;
371: else if (!okname(suser))
372: continue;
373: (void)sprintf(bp,
374: "%s%s -x -o'FallBackToRsh no' -n -l %s %s %s %s '%s%s%s:%s'",
375: SSH_PROGRAM, verbose ? " -v" : "",
376: suser, host, cmd, src,
377: tuser ? tuser : "", tuser ? "@" : "",
378: thost, targ);
379: } else
380: (void)sprintf(bp,
381: "exec %s%s -x -o'FallBackToRsh no' -n %s %s %s '%s%s%s:%s'",
382: SSH_PROGRAM, verbose ? " -v" : "",
383: argv[i], cmd, src,
384: tuser ? tuser : "", tuser ? "@" : "",
385: thost, targ);
386: if (verbose)
387: fprintf(stderr, "Executing: %s\n", bp);
388: (void)system(bp);
389: (void)xfree(bp);
390: } else { /* local to remote */
391: if (remin == -1) {
392: len = strlen(targ) + CMDNEEDS + 20;
393: bp = xmalloc(len);
394: (void)sprintf(bp, "%s -t %s", cmd, targ);
395: host = thost;
396: if (do_cmd(host, tuser,
397: bp, &remin, &remout) < 0)
398: exit(1);
399: if (response() < 0)
400: exit(1);
401: (void)xfree(bp);
402: }
403: source(1, argv+i);
404: }
405: }
406: }
407:
408: void
409: tolocal(argc, argv)
410: int argc;
411: char *argv[];
412: {
413: int i, len;
414: char *bp, *host, *src, *suser;
415:
416: for (i = 0; i < argc - 1; i++) {
417: if (!(src = colon(argv[i]))) { /* Local to local. */
418: len = strlen(_PATH_CP) + strlen(argv[i]) +
419: strlen(argv[argc - 1]) + 20;
420: bp = xmalloc(len);
421: (void)sprintf(bp, "exec %s%s%s %s %s", _PATH_CP,
422: iamrecursive ? " -r" : "", pflag ? " -p" : "",
423: argv[i], argv[argc - 1]);
424: if (verbose)
425: fprintf(stderr, "Executing: %s\n", bp);
426: if (system(bp))
427: ++errs;
428: (void)xfree(bp);
429: continue;
430: }
431: *src++ = 0;
432: if (*src == 0)
433: src = ".";
434: if ((host = strchr(argv[i], '@')) == NULL) {
435: host = argv[i];
436: suser = NULL;
437: } else {
438: *host++ = 0;
439: suser = argv[i];
440: if (*suser == '\0')
441: suser = pwd->pw_name;
442: else if (!okname(suser))
443: continue;
444: }
445: len = strlen(src) + CMDNEEDS + 20;
446: bp = xmalloc(len);
447: (void)sprintf(bp, "%s -f %s", cmd, src);
448: if (do_cmd(host, suser, bp, &remin, &remout) < 0) {
449: (void)xfree(bp);
450: ++errs;
451: continue;
452: }
453: xfree(bp);
454: sink(1, argv + argc - 1);
455: (void)close(remin);
456: remin = remout = -1;
457: }
458: }
459:
460: void
461: source(argc, argv)
462: int argc;
463: char *argv[];
464: {
465: struct stat stb;
466: static BUF buffer;
467: BUF *bp;
468: off_t i;
469: int amt, fd, haderr, indx, result;
470: char *last, *name, buf[2048];
471:
472: for (indx = 0; indx < argc; ++indx) {
473: name = argv[indx];
474: if ((fd = open(name, O_RDONLY, 0)) < 0)
475: goto syserr;
476: if (fstat(fd, &stb) < 0) {
477: syserr: run_err("%s: %s", name, strerror(errno));
478: goto next;
479: }
480: switch (stb.st_mode & S_IFMT) {
481: case S_IFREG:
482: break;
483: case S_IFDIR:
484: if (iamrecursive) {
485: rsource(name, &stb);
486: goto next;
487: }
488: /* FALLTHROUGH */
489: default:
490: run_err("%s: not a regular file", name);
491: goto next;
492: }
493: if ((last = strrchr(name, '/')) == NULL)
494: last = name;
495: else
496: ++last;
497: if (pflag) {
498: /*
499: * Make it compatible with possible future
500: * versions expecting microseconds.
501: */
502: (void)sprintf(buf, "T%lu 0 %lu 0\n",
503: (unsigned long)stb.st_mtime,
504: (unsigned long)stb.st_atime);
505: (void)write(remout, buf, strlen(buf));
506: if (response() < 0)
507: goto next;
508: }
509: #define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
510: (void)sprintf(buf, "C%04o %lu %s\n",
511: (unsigned int)(stb.st_mode & FILEMODEMASK),
512: (unsigned long)stb.st_size,
513: last);
514: if (verbose)
515: {
516: fprintf(stderr, "Sending file modes: %s", buf);
517: fflush(stderr);
518: }
519: (void)write(remout, buf, strlen(buf));
520: if (response() < 0)
521: goto next;
522: if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) {
523: next: (void)close(fd);
524: continue;
525: }
526:
527: /* Keep writing after an error so that we stay sync'd up. */
528: for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
529: amt = bp->cnt;
530: if (i + amt > stb.st_size)
531: amt = stb.st_size - i;
532: if (!haderr) {
533: result = read(fd, bp->buf, amt);
534: if (result != amt)
535: haderr = result >= 0 ? EIO : errno;
536: }
537: if (haderr)
538: (void)write(remout, bp->buf, amt);
539: else {
540: result = write(remout, bp->buf, amt);
541: if (result != amt)
542: haderr = result >= 0 ? EIO : errno;
543: }
544: }
545: if (close(fd) < 0 && !haderr)
546: haderr = errno;
547: if (!haderr)
548: (void)write(remout, "", 1);
549: else
550: run_err("%s: %s", name, strerror(haderr));
551: (void)response();
552: }
553: }
554:
555: void
556: rsource(name, statp)
557: char *name;
558: struct stat *statp;
559: {
560: DIR *dirp;
561: struct dirent *dp;
562: char *last, *vect[1], path[1100];
563:
564: if (!(dirp = opendir(name))) {
565: run_err("%s: %s", name, strerror(errno));
566: return;
567: }
568: last = strrchr(name, '/');
569: if (last == 0)
570: last = name;
571: else
572: last++;
573: if (pflag) {
574: (void)sprintf(path, "T%lu 0 %lu 0\n",
575: (unsigned long)statp->st_mtime,
576: (unsigned long)statp->st_atime);
577: (void)write(remout, path, strlen(path));
578: if (response() < 0) {
579: closedir(dirp);
580: return;
581: }
582: }
583: (void)sprintf(path,
584: "D%04o %d %.1024s\n", (unsigned int)(statp->st_mode & FILEMODEMASK),
585: 0, last);
586: if (verbose)
587: fprintf(stderr, "Entering directory: %s", path);
588: (void)write(remout, path, strlen(path));
589: if (response() < 0) {
590: closedir(dirp);
591: return;
592: }
593: while ((dp = readdir(dirp))) {
594: if (dp->d_ino == 0)
595: continue;
596: if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
597: continue;
598: if (strlen(name) + 1 + strlen(dp->d_name) >= sizeof(path) - 1) {
599: run_err("%s/%s: name too long", name, dp->d_name);
600: continue;
601: }
602: (void)sprintf(path, "%s/%s", name, dp->d_name);
603: vect[0] = path;
604: source(1, vect);
605: }
606: (void)closedir(dirp);
607: (void)write(remout, "E\n", 2);
608: (void)response();
609: }
610:
611: void
612: sink(argc, argv)
613: int argc;
614: char *argv[];
615: {
616: static BUF buffer;
617: struct stat stb;
618: enum { YES, NO, DISPLAYED } wrerr;
619: BUF *bp;
620: off_t i, j;
621: int amt, count, exists, first, mask, mode, ofd, omode;
622: int setimes, size, targisdir, wrerrno = 0;
623: char ch, *cp, *np, *targ, *why, *vect[1], buf[2048];
624: struct utimbuf ut;
625: int dummy_usec;
626:
627: #define SCREWUP(str) { why = str; goto screwup; }
628:
629: setimes = targisdir = 0;
630: mask = umask(0);
631: if (!pflag)
632: (void)umask(mask);
633: if (argc != 1) {
634: run_err("ambiguous target");
635: exit(1);
636: }
637: targ = *argv;
638: if (targetshouldbedirectory)
639: verifydir(targ);
640:
641: (void)write(remout, "", 1);
642: if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
643: targisdir = 1;
644: for (first = 1;; first = 0) {
645: cp = buf;
646: if (read(remin, cp, 1) <= 0)
647: return;
648: if (*cp++ == '\n')
649: SCREWUP("unexpected <newline>");
650: do {
651: if (read(remin, &ch, sizeof(ch)) != sizeof(ch))
652: SCREWUP("lost connection");
653: *cp++ = ch;
654: } while (cp < &buf[sizeof(buf) - 1] && ch != '\n');
655: *cp = 0;
656:
657: if (buf[0] == '\01' || buf[0] == '\02') {
658: if (iamremote == 0)
659: (void)write(STDERR_FILENO,
660: buf + 1, strlen(buf + 1));
661: if (buf[0] == '\02')
662: exit(1);
663: ++errs;
664: continue;
665: }
666: if (buf[0] == 'E') {
667: (void)write(remout, "", 1);
668: return;
669: }
670:
671: if (ch == '\n')
672: *--cp = 0;
673:
674: #define getnum(t) (t) = 0; \
675: while (*cp >= '0' && *cp <= '9') (t) = (t) * 10 + (*cp++ - '0');
676: cp = buf;
677: if (*cp == 'T') {
678: setimes++;
679: cp++;
680: getnum(ut.modtime);
681: if (*cp++ != ' ')
682: SCREWUP("mtime.sec not delimited");
683: getnum(dummy_usec);
684: if (*cp++ != ' ')
685: SCREWUP("mtime.usec not delimited");
686: getnum(ut.actime);
687: if (*cp++ != ' ')
688: SCREWUP("atime.sec not delimited");
689: getnum(dummy_usec);
690: if (*cp++ != '\0')
691: SCREWUP("atime.usec not delimited");
692: (void)write(remout, "", 1);
693: continue;
694: }
695: if (*cp != 'C' && *cp != 'D') {
696: /*
697: * Check for the case "rcp remote:foo\* local:bar".
698: * In this case, the line "No match." can be returned
699: * by the shell before the rcp command on the remote is
700: * executed so the ^Aerror_message convention isn't
701: * followed.
702: */
703: if (first) {
704: run_err("%s", cp);
705: exit(1);
706: }
707: SCREWUP("expected control record");
708: }
709: mode = 0;
710: for (++cp; cp < buf + 5; cp++) {
711: if (*cp < '0' || *cp > '7')
712: SCREWUP("bad mode");
713: mode = (mode << 3) | (*cp - '0');
714: }
715: if (*cp++ != ' ')
716: SCREWUP("mode not delimited");
717:
718: for (size = 0; *cp >= '0' && *cp <= '9';)
719: size = size * 10 + (*cp++ - '0');
720: if (*cp++ != ' ')
721: SCREWUP("size not delimited");
722: if (targisdir) {
723: static char *namebuf;
724: static int cursize;
725: size_t need;
726:
727: need = strlen(targ) + strlen(cp) + 250;
728: if (need > cursize)
729: namebuf = xmalloc(need);
730: (void)sprintf(namebuf, "%s%s%s", targ,
731: *targ ? "/" : "", cp);
732: np = namebuf;
733: } else
734: np = targ;
735: exists = stat(np, &stb) == 0;
736: if (buf[0] == 'D') {
737: int mod_flag = pflag;
738: if (exists) {
739: if (!S_ISDIR(stb.st_mode)) {
740: errno = ENOTDIR;
741: goto bad;
742: }
743: if (pflag)
744: (void)chmod(np, mode);
745: } else {
746: /* Handle copying from a read-only directory */
747: mod_flag = 1;
748: if (mkdir(np, mode | S_IRWXU) < 0)
749: goto bad;
750: }
751: vect[0] = np;
752: sink(1, vect);
753: if (setimes) {
754: setimes = 0;
755: if (utime(np, &ut) < 0)
756: run_err("%s: set times: %s",
757: np, strerror(errno));
758: }
759: if (mod_flag)
760: (void)chmod(np, mode);
761: continue;
762: }
763: omode = mode;
764: mode |= S_IWRITE;
765: if ((ofd = open(np, O_WRONLY|O_CREAT|O_TRUNC, mode)) < 0) {
766: bad: run_err("%s: %s", np, strerror(errno));
767: continue;
768: }
769: (void)write(remout, "", 1);
770: if ((bp = allocbuf(&buffer, ofd, 4096)) == NULL) {
771: (void)close(ofd);
772: continue;
773: }
774: cp = bp->buf;
775: wrerr = NO;
776: for (count = i = 0; i < size; i += 4096) {
777: amt = 4096;
778: if (i + amt > size)
779: amt = size - i;
780: count += amt;
781: do {
782: j = read(remin, cp, amt);
783: if (j <= 0) {
784: run_err("%s", j ? strerror(errno) :
785: "dropped connection");
786: exit(1);
787: }
788: amt -= j;
789: cp += j;
790: } while (amt > 0);
791: if (count == bp->cnt) {
792: /* Keep reading so we stay sync'd up. */
793: if (wrerr == NO) {
794: j = write(ofd, bp->buf, count);
795: if (j != count) {
796: wrerr = YES;
797: wrerrno = j >= 0 ? EIO : errno;
798: }
799: }
800: count = 0;
801: cp = bp->buf;
802: }
803: }
804: if (count != 0 && wrerr == NO &&
805: (j = write(ofd, bp->buf, count)) != count) {
806: wrerr = YES;
807: wrerrno = j >= 0 ? EIO : errno;
808: }
809: #if 0
810: if (ftruncate(ofd, size)) {
811: run_err("%s: truncate: %s", np, strerror(errno));
812: wrerr = DISPLAYED;
813: }
814: #endif
815: if (pflag) {
816: if (exists || omode != mode)
817: #ifdef HAVE_FCHMOD
818: if (fchmod(ofd, omode))
819: #else /* HAVE_FCHMOD */
820: if (chmod(np, omode))
821: #endif /* HAVE_FCHMOD */
822: run_err("%s: set mode: %s",
823: np, strerror(errno));
824: } else {
825: if (!exists && omode != mode)
826: #ifdef HAVE_FCHMOD
827: if (fchmod(ofd, omode & ~mask))
828: #else /* HAVE_FCHMOD */
829: if (chmod(np, omode & ~mask))
830: #endif /* HAVE_FCHMOD */
831: run_err("%s: set mode: %s",
832: np, strerror(errno));
833: }
834: (void)close(ofd);
835: (void)response();
836: if (setimes && wrerr == NO) {
837: setimes = 0;
838: if (utime(np, &ut) < 0) {
839: run_err("%s: set times: %s",
840: np, strerror(errno));
841: wrerr = DISPLAYED;
842: }
843: }
844: switch(wrerr) {
845: case YES:
846: run_err("%s: %s", np, strerror(wrerrno));
847: break;
848: case NO:
849: (void)write(remout, "", 1);
850: break;
851: case DISPLAYED:
852: break;
853: }
854: }
855: screwup:
856: run_err("protocol error: %s", why);
857: exit(1);
858: }
859:
860: int
861: response()
862: {
863: char ch, *cp, resp, rbuf[2048];
864:
865: if (read(remin, &resp, sizeof(resp)) != sizeof(resp))
866: lostconn(0);
867:
868: cp = rbuf;
869: switch(resp) {
870: case 0: /* ok */
871: return (0);
872: default:
873: *cp++ = resp;
874: /* FALLTHROUGH */
875: case 1: /* error, followed by error msg */
876: case 2: /* fatal error, "" */
877: do {
878: if (read(remin, &ch, sizeof(ch)) != sizeof(ch))
879: lostconn(0);
880: *cp++ = ch;
881: } while (cp < &rbuf[sizeof(rbuf) - 1] && ch != '\n');
882:
883: if (!iamremote)
884: (void)write(STDERR_FILENO, rbuf, cp - rbuf);
885: ++errs;
886: if (resp == 1)
887: return (-1);
888: exit(1);
889: }
890: /* NOTREACHED */
891: }
892:
893: void
894: usage()
895: {
896: (void)fprintf(stderr,
897: "usage: scp [-p] f1 f2; or: scp [-pr] f1 ... fn directory\n");
898: exit(1);
899: }
900:
901: void
902: run_err(const char *fmt, ...)
903: {
904: static FILE *fp;
905: va_list ap;
906: va_start(ap, fmt);
907:
908: ++errs;
909: if (fp == NULL && !(fp = fdopen(remout, "w")))
910: return;
911: (void)fprintf(fp, "%c", 0x01);
912: (void)fprintf(fp, "scp: ");
913: (void)vfprintf(fp, fmt, ap);
914: (void)fprintf(fp, "\n");
915: (void)fflush(fp);
916:
917: if (!iamremote)
918: {
919: vfprintf(stderr, fmt, ap);
920: fprintf(stderr, "\n");
921: }
922:
923: va_end(ap);
924: }
925:
926: /* Stuff below is from BSD rcp util.c. */
927:
928: /*-
929: * Copyright (c) 1992, 1993
930: * The Regents of the University of California. All rights reserved.
931: *
932: * Redistribution and use in source and binary forms, with or without
933: * modification, are permitted provided that the following conditions
934: * are met:
935: * 1. Redistributions of source code must retain the above copyright
936: * notice, this list of conditions and the following disclaimer.
937: * 2. Redistributions in binary form must reproduce the above copyright
938: * notice, this list of conditions and the following disclaimer in the
939: * documentation and/or other materials provided with the distribution.
940: * 3. All advertising materials mentioning features or use of this software
941: * must display the following acknowledgement:
942: * This product includes software developed by the University of
943: * California, Berkeley and its contributors.
944: * 4. Neither the name of the University nor the names of its contributors
945: * may be used to endorse or promote products derived from this software
946: * without specific prior written permission.
947: *
948: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
949: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
950: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
951: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
952: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
953: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
954: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
955: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
956: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
957: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
958: * SUCH DAMAGE.
959: *
1.3 ! deraadt 960: * $Id: scp.c,v 1.2 1999/09/29 18:16:20 dugsong Exp $
1.1 deraadt 961: */
962:
963: char *
964: colon(cp)
965: char *cp;
966: {
967: if (*cp == ':') /* Leading colon is part of file name. */
968: return (0);
969:
970: for (; *cp; ++cp) {
971: if (*cp == ':')
972: return (cp);
973: if (*cp == '/')
974: return (0);
975: }
976: return (0);
977: }
978:
979: void
980: verifydir(cp)
981: char *cp;
982: {
983: struct stat stb;
984:
985: if (!stat(cp, &stb)) {
986: if (S_ISDIR(stb.st_mode))
987: return;
988: errno = ENOTDIR;
989: }
990: run_err("%s: %s", cp, strerror(errno));
991: exit(1);
992: }
993:
994: int
995: okname(cp0)
996: char *cp0;
997: {
998: int c;
999: char *cp;
1000:
1001: cp = cp0;
1002: do {
1003: c = *cp;
1004: if (c & 0200)
1005: goto bad;
1006: if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
1007: goto bad;
1008: } while (*++cp);
1009: return (1);
1010:
1011: bad: fprintf(stderr, "%s: invalid user name", cp0);
1012: return (0);
1013: }
1014:
1015: BUF *
1016: allocbuf(bp, fd, blksize)
1017: BUF *bp;
1018: int fd, blksize;
1019: {
1020: size_t size;
1021: struct stat stb;
1022:
1023: if (fstat(fd, &stb) < 0) {
1024: run_err("fstat: %s", strerror(errno));
1025: return (0);
1026: }
1027: if (stb.st_blksize == 0)
1028: size = blksize;
1029: else
1030: size = blksize + (stb.st_blksize - blksize % stb.st_blksize) %
1.3 ! deraadt 1031: stb.st_blksize;
1.1 deraadt 1032: if (bp->cnt >= size)
1033: return (bp);
1034: if (bp->buf == NULL)
1035: bp->buf = xmalloc(size);
1036: else
1037: bp->buf = xrealloc(bp->buf, size);
1038: bp->cnt = size;
1039: return (bp);
1040: }
1041:
1042: void
1043: lostconn(signo)
1044: int signo;
1045: {
1046: if (!iamremote)
1047: fprintf(stderr, "lost connection\n");
1048: exit(1);
1049: }