=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/scp.c,v retrieving revision 1.30.2.1 retrieving revision 1.30.2.2 diff -u -r1.30.2.1 -r1.30.2.2 --- src/usr.bin/ssh/scp.c 2000/09/01 18:23:22 1.30.2.1 +++ src/usr.bin/ssh/scp.c 2000/11/08 21:31:12 1.30.2.2 @@ -1,14 +1,42 @@ /* + * scp - secure remote copy. This is basically patched BSD rcp which + * uses ssh to do the data transfer (instead of using rcmd). * - * scp - secure remote copy. This is basically patched BSD rcp which uses ssh - * to do the data transfer (instead of using rcmd). + * NOTE: This version should NOT be suid root. (This uses ssh to + * do the transfer and ssh has the necessary privileges.) * - * NOTE: This version should NOT be suid root. (This uses ssh to do the transfer - * and ssh has the necessary privileges.) - * * 1995 Timo Rinne , Tatu Ylonen * -*/ + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + */ +/* + * Copyright (c) 1999 Theo de Raadt. All rights reserved. + * Copyright (c) 1999 Aaron Campbell. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ /* * Parts from: @@ -47,11 +75,10 @@ */ #include "includes.h" -RCSID("$OpenBSD: scp.c,v 1.30.2.1 2000/09/01 18:23:22 jason Exp $"); +RCSID("$OpenBSD: scp.c,v 1.30.2.2 2000/11/08 21:31:12 jason Exp $"); #include "ssh.h" #include "xmalloc.h" -#include #define _PATH_CP "cp" @@ -65,6 +92,9 @@ int getttywidth(void); int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout, int argc); +/* setup arguments for the call to ssh */ +void addargs(char *fmt, ...) __attribute__((format(printf, 1, 2))); + /* Time a transfer started. */ static struct timeval start; @@ -77,12 +107,6 @@ /* Name of current file being transferred. */ char *curfile; -/* This is set to non-zero if IPv4 is desired. */ -int IPv4 = 0; - -/* This is set to non-zero if IPv6 is desired. */ -int IPv6 = 0; - /* This is set to non-zero to enable verbose mode. */ int verbose_mode = 0; @@ -92,23 +116,16 @@ /* This is set to zero if the progressmeter is not desired. */ int showprogress = 1; -/* This is set to non-zero if running in batch mode (that is, password - and passphrase queries are not allowed). */ -int batchmode = 0; - -/* This is set to the cipher type string if given on the command line. */ -char *cipher = NULL; - -/* This is set to the RSA authentication identity file name if given on - the command line. */ -char *identity = NULL; - -/* This is the port to use in contacting the remote site (is non-NULL). */ -char *port = NULL; - /* This is the program to execute for the secured connection. ("ssh" or -S) */ char *ssh_program = SSH_PROGRAM; +/* This is the list of arguments that scp passes to ssh */ +struct { + char **list; + int num; + int nalloc; +} args; + /* * This function executes the given command as the specified user on the * given host. This returns < 0 if execution fails, and >= 0 otherwise. This @@ -121,8 +138,8 @@ int pin[2], pout[2], reserved[2]; if (verbose_mode) - fprintf(stderr, "Executing: host %s, user %s, command %s\n", - host, remuser ? remuser : "(unspecified)", cmd); + fprintf(stderr, "Executing: program %s host %s, user %s, command %s\n", + ssh_program, host, remuser ? remuser : "(unspecified)", cmd); /* * Reserve two descriptors so that the real pipes won't get @@ -141,10 +158,7 @@ close(reserved[1]); /* For a child to execute the command on the remote host using ssh. */ - if (fork() == 0) { - char *args[100]; /* XXX careful */ - unsigned int i; - + if (fork() == 0) { /* Child. */ close(pin[1]); close(pout[0]); @@ -153,41 +167,13 @@ close(pin[0]); close(pout[1]); - i = 0; - args[i++] = ssh_program; - args[i++] = "-x"; - args[i++] = "-oFallBackToRsh no"; - if (IPv4) - args[i++] = "-4"; - if (IPv6) - args[i++] = "-6"; - if (verbose_mode) - args[i++] = "-v"; - if (compress) - args[i++] = "-C"; - if (batchmode) - args[i++] = "-oBatchMode yes"; - if (cipher != NULL) { - args[i++] = "-c"; - args[i++] = cipher; - } - if (identity != NULL) { - args[i++] = "-i"; - args[i++] = identity; - } - if (port != NULL) { - args[i++] = "-p"; - args[i++] = port; - } - if (remuser != NULL) { - args[i++] = "-l"; - args[i++] = remuser; - } - args[i++] = host; - args[i++] = cmd; - args[i++] = NULL; + args.list[0] = ssh_program; + if (remuser != NULL) + addargs("-l%s", remuser); + addargs("%s", host); + addargs("%s", cmd); - execvp(ssh_program, args); + execvp(ssh_program, args.list); perror(ssh_program); exit(1); } @@ -253,28 +239,46 @@ extern char *optarg; extern int optind; + args.list = NULL; + addargs("ssh"); /* overwritten with ssh_program */ + addargs("-x"); + addargs("-oFallBackToRsh no"); + fflag = tflag = 0; - while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S")) != EOF) + while ((ch = getopt(argc, argv, "dfprtvBCc:i:P:q46S:o:")) != EOF) switch (ch) { /* User-visible flags. */ case '4': - IPv4 = 1; - break; case '6': - IPv6 = 1; + case 'C': + addargs("-%c", ch); break; - case 'p': - pflag = 1; + case 'o': + case 'c': + case 'i': + addargs("-%c%s", ch, optarg); break; case 'P': - port = optarg; + addargs("-p%s", optarg); break; + case 'B': + addargs("-oBatchmode yes"); + break; + case 'p': + pflag = 1; + break; case 'r': iamrecursive = 1; break; case 'S': - ssh_program = optarg; + ssh_program = xstrdup(optarg); break; + case 'v': + verbose_mode = 1; + break; + case 'q': + showprogress = 0; + break; /* Server options. */ case 'd': @@ -288,24 +292,6 @@ iamremote = 1; tflag = 1; break; - case 'c': - cipher = optarg; - break; - case 'i': - identity = optarg; - break; - case 'v': - verbose_mode = 1; - break; - case 'B': - batchmode = 1; - break; - case 'C': - compress = 1; - break; - case 'q': - showprogress = 0; - break; case '?': default: usage(); @@ -675,8 +661,8 @@ off_t size; int setimes, targisdir, wrerrno = 0; char ch, *cp, *np, *targ, *why, *vect[1], buf[2048]; - struct utimbuf ut; int dummy_usec; + struct timeval tv[2]; #define SCREWUP(str) { why = str; goto screwup; } @@ -730,16 +716,18 @@ if (*cp == 'T') { setimes++; cp++; - getnum(ut.modtime); + getnum(tv[1].tv_sec); if (*cp++ != ' ') SCREWUP("mtime.sec not delimited"); getnum(dummy_usec); + tv[1].tv_usec = 0; if (*cp++ != ' ') SCREWUP("mtime.usec not delimited"); - getnum(ut.actime); + getnum(tv[0].tv_sec); if (*cp++ != ' ') SCREWUP("atime.sec not delimited"); getnum(dummy_usec); + tv[0].tv_usec = 0; if (*cp++ != '\0') SCREWUP("atime.usec not delimited"); (void) atomicio(write, remout, "", 1); @@ -807,7 +795,7 @@ sink(1, vect); if (setimes) { setimes = 0; - if (utime(np, &ut) < 0) + if (utimes(np, tv) < 0) run_err("%s: set times: %s", np, strerror(errno)); } @@ -840,8 +828,10 @@ amt = size - i; count += amt; do { - j = atomicio(read, remin, cp, amt); - if (j <= 0) { + j = read(remin, cp, amt); + if (j == -1 && (errno == EINTR || errno == EAGAIN)) { + continue; + } else if (j <= 0) { run_err("%s", j ? strerror(errno) : "dropped connection"); exit(1); @@ -894,7 +884,7 @@ (void) response(); if (setimes && wrerr == NO) { setimes = 0; - if (utime(np, &ut) < 0) { + if (utimes(np, tv) < 0) { run_err("%s: set times: %s", np, strerror(errno)); wrerr = DISPLAYED; @@ -1220,4 +1210,26 @@ return (winsize.ws_col ? winsize.ws_col : 80); else return (80); +} + +void +addargs(char *fmt, ...) +{ + va_list ap; + char buf[1024]; + + va_start(ap, fmt); + vsnprintf(buf, sizeof(buf), fmt, ap); + va_end(ap); + + if (args.list == NULL) { + args.nalloc = 32; + args.num = 0; + args.list = xmalloc(args.nalloc * sizeof(char *)); + } else if (args.num+2 >= args.nalloc) { + args.nalloc *= 2; + args.list = xrealloc(args.list, args.nalloc * sizeof(char *)); + } + args.list[args.num++] = xstrdup(buf); + args.list[args.num] = NULL; }