/*
+ * 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 <tri@iki.fi>, Tatu Ylonen <ylo@cs.hut.fi>
*
-*/
+ * 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:
*/
#include "includes.h"
-RCSID("$OpenBSD: scp.c,v 1.37 2000/09/01 15:25:13 deraadt Exp $");
+RCSID("$OpenBSD: scp.c,v 1.51 2001/01/21 19:05:55 markus Exp $");
-#include "ssh.h"
#include "xmalloc.h"
-#include <utime.h>
-
-#define _PATH_CP "cp"
+#include "atomicio.h"
+#include "pathnames.h"
+#include "log.h"
+
+#ifdef HAVE___PROGNAME
+extern char *__progname;
+#else
+char *__progname;
+#endif
/* For progressmeter() -- number of seconds before xfer considered "stalled" */
#define STALLTIME 5
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;
/* Number of bytes of current file transferred so far. */
-volatile unsigned long statbytes;
+volatile u_long statbytes;
/* Total size of current file. */
off_t totalbytes = 0;
/* 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;
-/* This is set to non-zero if compression is desired. */
-int compress_flag = 0;
-
/* 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;
+char *ssh_program = _PATH_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
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
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]);
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_flag)
- 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);
}
return 0;
}
-void
-fatal(const char *fmt,...)
-{
- va_list ap;
- char buf[1024];
-
- va_start(ap, fmt);
- vsnprintf(buf, sizeof(buf), fmt, ap);
- va_end(ap);
- fprintf(stderr, "%s\n", buf);
- exit(255);
-}
-
typedef struct {
int cnt;
char *buf;
extern char *optarg;
extern int optind;
+ __progname = get_progname(argv[0]);
+
+ 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:")) != -1)
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. */
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_flag = 1;
- break;
- case 'q':
- showprogress = 0;
- break;
case '?':
default:
usage();
suser = pwd->pw_name;
else if (!okname(suser))
continue;
- (void) sprintf(bp,
+ sprintf(bp,
"%s%s -x -o'FallBackToRsh no' -n -l %s %s %s %s '%s%s%s:%s'",
- ssh_program, verbose_mode ? " -v" : "",
- suser, host, cmd, src,
- tuser ? tuser : "", tuser ? "@" : "",
- thost, targ);
+ ssh_program, verbose_mode ? " -v" : "",
+ suser, host, cmd, src,
+ tuser ? tuser : "", tuser ? "@" : "",
+ thost, targ);
} else {
host = cleanhostname(argv[i]);
- (void) sprintf(bp,
+ sprintf(bp,
"exec %s%s -x -o'FallBackToRsh no' -n %s %s %s '%s%s%s:%s'",
- ssh_program, verbose_mode ? " -v" : "",
- host, cmd, src,
- tuser ? tuser : "", tuser ? "@" : "",
- thost, targ);
+ ssh_program, verbose_mode ? " -v" : "",
+ host, cmd, src,
+ tuser ? tuser : "", tuser ? "@" : "",
+ thost, targ);
}
if (verbose_mode)
fprintf(stderr, "Executing: %s\n", bp);
* versions expecting microseconds.
*/
(void) sprintf(buf, "T%lu 0 %lu 0\n",
- (unsigned long) stb.st_mtime,
- (unsigned long) stb.st_atime);
+ (u_long) stb.st_mtime,
+ (u_long) stb.st_atime);
(void) atomicio(write, remout, buf, strlen(buf));
if (response() < 0)
goto next;
}
#define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
- (void) sprintf(buf, "C%04o %lu %s\n",
- (unsigned int) (stb.st_mode & FILEMODEMASK),
- (unsigned long) stb.st_size,
- last);
+ sprintf(buf, "C%04o %lu %s\n",
+ (u_int) (stb.st_mode & FILEMODEMASK),
+ (u_long) stb.st_size, last);
if (verbose_mode) {
fprintf(stderr, "Sending file modes: %s", buf);
fflush(stderr);
last++;
if (pflag) {
(void) sprintf(path, "T%lu 0 %lu 0\n",
- (unsigned long) statp->st_mtime,
- (unsigned long) statp->st_atime);
+ (u_long) statp->st_mtime,
+ (u_long) statp->st_atime);
(void) atomicio(write, remout, path, strlen(path));
if (response() < 0) {
closedir(dirp);
}
}
(void) sprintf(path, "D%04o %d %.1024s\n",
- (unsigned int) (statp->st_mode & FILEMODEMASK), 0, last);
+ (u_int) (statp->st_mode & FILEMODEMASK), 0, last);
if (verbose_mode)
fprintf(stderr, "Entering directory: %s", path);
(void) atomicio(write, remout, path, strlen(path));
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; }
if (buf[0] == '\01' || buf[0] == '\02') {
if (iamremote == 0)
(void) atomicio(write, STDERR_FILENO,
- buf + 1, strlen(buf + 1));
+ buf + 1, strlen(buf + 1));
if (buf[0] == '\02')
exit(1);
++errs;
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);
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));
}
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);
#endif
if (pflag) {
if (exists || omode != mode)
+#ifdef HAVE_FCHMOD
if (fchmod(ofd, omode))
+#else /* HAVE_FCHMOD */
+ if (chmod(np, omode))
+#endif /* HAVE_FCHMOD */
run_err("%s: set mode: %s",
np, strerror(errno));
} else {
if (!exists && omode != mode)
+#ifdef HAVE_FCHMOD
if (fchmod(ofd, omode & ~mask))
+#else /* HAVE_FCHMOD */
+ if (chmod(np, omode & ~mask))
+#endif /* HAVE_FCHMOD */
run_err("%s: set mode: %s",
np, strerror(errno));
}
(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;
c = *cp;
if (c & 0200)
goto bad;
- if (!isalpha(c) && !isdigit(c) && c != '_' && c != '-')
+ if (!isalpha(c) && !isdigit(c) &&
+ c != '_' && c != '-' && c != '.' && c != '+')
goto bad;
} while (*++cp);
return (1);
int fd, blksize;
{
size_t size;
+#ifdef HAVE_ST_BLKSIZE
struct stat stb;
if (fstat(fd, &stb) < 0) {
else
size = blksize + (stb.st_blksize - blksize % stb.st_blksize) %
stb.st_blksize;
+#else /* HAVE_ST_BLKSIZE */
+ size = blksize;
+#endif /* HAVE_ST_BLKSIZE */
if (bp->cnt >= size)
return (bp);
if (bp->buf == NULL)
if (pgrp == -1)
pgrp = getpgrp();
+#ifdef HAVE_TCGETPGRP
+ return ((ctty_pgrp = tcgetpgrp(STDOUT_FILENO)) != -1 &&
+ ctty_pgrp == pgrp);
+#else
return ((ioctl(STDOUT_FILENO, TIOCGPGRP, &ctty_pgrp) != -1 &&
ctty_pgrp == pgrp));
+#endif
}
void
abbrevsize >>= 10;
}
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %5d %c%c ",
- (int) abbrevsize, prefixes[i], prefixes[i] == ' ' ? ' ' :
- 'B');
+ (int) abbrevsize, prefixes[i], prefixes[i] == ' ' ? ' ' : 'B');
timersub(&now, &lastupdate, &wait);
if (cursize > lastsize) {
timersub(&now, &start, &td);
elapsed = td.tv_sec + (td.tv_usec / 1000000.0);
- if (statbytes <= 0 || elapsed <= 0.0 || cursize > totalbytes) {
+ if (flag != 1 &&
+ (statbytes <= 0 || elapsed <= 0.0 || cursize > totalbytes)) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
- " --:-- ETA");
+ " --:-- ETA");
} else if (wait.tv_sec >= STALLTIME) {
snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
- " - stalled -");
+ " - stalled -");
} else {
if (flag != 1)
- remaining =
- (int)(totalbytes / (statbytes / elapsed) - elapsed);
+ remaining = (int)(totalbytes / (statbytes / elapsed) -
+ elapsed);
else
remaining = elapsed;
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;
+}