*/
#include "includes.h"
-RCSID("$OpenBSD: scp.c,v 1.110 2003/10/08 08:27:36 jmc Exp $");
+RCSID("$OpenBSD: scp.c,v 1.128 2005/12/06 22:38:27 reyk Exp $");
#include "xmalloc.h"
#include "atomicio.h"
#include "misc.h"
#include "progressmeter.h"
-#ifdef HAVE___PROGNAME
extern char *__progname;
-#else
-char *__progname;
-#endif
void bwlimit(int);
arglist args;
/* Bandwidth limit */
-off_t limitbw = 0;
+off_t limit_rate = 0;
/* Name of current file being transferred. */
char *curfile;
static void
killchild(int signo)
{
- if (do_cmd_pid > 1)
- kill(do_cmd_pid, signo);
+ if (do_cmd_pid > 1) {
+ kill(do_cmd_pid, signo ? signo : SIGTERM);
+ waitpid(do_cmd_pid, NULL, 0);
+ }
- _exit(1);
+ if (signo)
+ _exit(1);
+ exit(1);
}
/*
}
typedef struct {
- int cnt;
+ size_t cnt;
char *buf;
} BUF;
extern char *optarg;
extern int optind;
+ /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
+ sanitise_stdfd();
+
__progname = ssh_get_progname(argv[0]);
args.list = NULL;
addargs(&args, "ssh"); /* overwritten with ssh_program */
addargs(&args, "-x");
addargs(&args, "-oForwardAgent no");
+ addargs(&args, "-oPermitLocalCommand no");
addargs(&args, "-oClearAllForwardings yes");
fflag = tflag = 0;
speed = strtod(optarg, &endp);
if (speed <= 0 || *endp != '\0')
usage();
- limitbw = speed * 1024;
+ limit_rate = speed * 1024;
break;
case 'p':
pflag = 1;
verbose_mode = 1;
break;
case 'q':
+ addargs(&args, "-q");
showprogress = 0;
break;
toremote(char *targ, int argc, char **argv)
{
int i, len;
- char *bp, *host, *src, *suser, *thost, *tuser;
+ char *bp, *host, *src, *suser, *thost, *tuser, *arg;
*targ++ = 0;
if (*targ == 0)
targ = ".";
- if ((thost = strrchr(argv[argc - 1], '@'))) {
+ arg = xstrdup(argv[argc - 1]);
+ if ((thost = strrchr(arg, '@'))) {
/* user@host */
*thost++ = 0;
- tuser = argv[argc - 1];
+ tuser = arg;
if (*tuser == '\0')
tuser = NULL;
} else {
- thost = argv[argc - 1];
+ thost = arg;
tuser = NULL;
}
struct stat stb;
static BUF buffer;
BUF *bp;
- off_t i, amt, result, statbytes;
- int fd, haderr, indx;
+ off_t i, amt, statbytes;
+ size_t result;
+ int fd = -1, haderr, indx;
char *last, *name, buf[2048];
int len;
#define FILEMODEMASK (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO)
snprintf(buf, sizeof buf, "C%04o %lld %s\n",
(u_int) (stb.st_mode & FILEMODEMASK),
- (int64_t)stb.st_size, last);
+ (long long)stb.st_size, last);
if (verbose_mode) {
fprintf(stderr, "Sending file modes: %s", buf);
}
if (response() < 0)
goto next;
if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) {
-next: (void) close(fd);
+next: if (fd != -1) {
+ (void) close(fd);
+ fd = -1;
+ }
continue;
}
if (showprogress)
if (!haderr) {
result = atomicio(read, fd, bp->buf, amt);
if (result != amt)
- haderr = result >= 0 ? EIO : errno;
+ haderr = errno;
}
if (haderr)
(void) atomicio(vwrite, remout, bp->buf, amt);
else {
result = atomicio(vwrite, remout, bp->buf, amt);
if (result != amt)
- haderr = result >= 0 ? EIO : errno;
+ haderr = errno;
statbytes += result;
}
- if (limitbw)
+ if (limit_rate)
bwlimit(amt);
}
if (showprogress)
stop_progress_meter();
- if (close(fd) < 0 && !haderr)
- haderr = errno;
+ if (fd != -1) {
+ if (close(fd) < 0 && !haderr)
+ haderr = errno;
+ fd = -1;
+ }
if (!haderr)
(void) atomicio(vwrite, remout, "", 1);
else
{
static struct timeval bwstart, bwend;
static int lamt, thresh = 16384;
- u_int64_t wait;
+ u_int64_t waitlen;
struct timespec ts, rm;
if (!timerisset(&bwstart)) {
return;
lamt *= 8;
- wait = (double)1000000L * lamt / limitbw;
+ waitlen = (double)1000000L * lamt / limit_rate;
- bwstart.tv_sec = wait / 1000000L;
- bwstart.tv_usec = wait % 1000000L;
+ bwstart.tv_sec = waitlen / 1000000L;
+ bwstart.tv_usec = waitlen % 1000000L;
if (timercmp(&bwstart, &bwend, >)) {
timersub(&bwstart, &bwend, &bwend);
YES, NO, DISPLAYED
} wrerr;
BUF *bp;
- off_t i, j;
- int amt, count, exists, first, mask, mode, ofd, omode;
+ off_t i;
+ size_t j, count;
+ int amt, exists, first, mask, mode, ofd, omode;
off_t size, statbytes;
int setimes, targisdir, wrerrno = 0;
char ch, *cp, *np, *targ, *why, *vect[1], buf[2048];
#define atime tv[0]
#define mtime tv[1]
-#define SCREWUP(str) do { why = str; goto screwup; } while (0)
+#define SCREWUP(str) { why = str; goto screwup; }
setimes = targisdir = 0;
mask = umask(0);
targisdir = 1;
for (first = 1;; first = 0) {
cp = buf;
- if (atomicio(read, remin, cp, 1) <= 0)
+ if (atomicio(read, remin, cp, 1) != 1)
return;
if (*cp++ == '\n')
SCREWUP("unexpected <newline>");
*cp++ = ch;
} while (cp < &buf[sizeof(buf) - 1] && ch != '\n');
*cp = 0;
+ if (verbose_mode)
+ fprintf(stderr, "Sink: %s", buf);
if (buf[0] == '\01' || buf[0] == '\02') {
if (iamremote == 0)
size = size * 10 + (*cp++ - '0');
if (*cp++ != ' ')
SCREWUP("size not delimited");
+ if ((strchr(cp, '/') != NULL) || (strcmp(cp, "..") == 0)) {
+ run_err("error: unexpected filename: %s", cp);
+ exit(1);
+ }
if (targisdir) {
static char *namebuf;
- static int cursize;
+ static size_t cursize;
size_t need;
need = strlen(targ) + strlen(cp) + 250;
exists = stat(np, &stb) == 0;
if (buf[0] == 'D') {
int mod_flag = pflag;
+ if (!iamrecursive)
+ SCREWUP("received directory without -r");
if (exists) {
if (!S_ISDIR(stb.st_mode)) {
errno = ENOTDIR;
amt = size - i;
count += amt;
do {
- j = read(remin, cp, amt);
- if (j == -1 && (errno == EINTR ||
- errno == EAGAIN)) {
- continue;
- } else if (j <= 0) {
+ j = atomicio(read, remin, cp, amt);
+ if (j == 0) {
run_err("%s", j ? strerror(errno) :
"dropped connection");
exit(1);
cp += j;
statbytes += j;
} while (amt > 0);
-
- if (limitbw)
+
+ if (limit_rate)
bwlimit(4096);
if (count == bp->cnt) {
/* Keep reading so we stay sync'd up. */
if (wrerr == NO) {
- j = atomicio(vwrite, ofd, bp->buf, count);
- if (j != count) {
+ if (atomicio(vwrite, ofd, bp->buf,
+ count) != count) {
wrerr = YES;
- wrerrno = j >= 0 ? EIO : errno;
+ wrerrno = errno;
}
}
count = 0;
if (showprogress)
stop_progress_meter();
if (count != 0 && wrerr == NO &&
- (j = atomicio(vwrite, ofd, bp->buf, count)) != count) {
+ atomicio(vwrite, ofd, bp->buf, count) != count) {
wrerr = YES;
- wrerrno = j >= 0 ? EIO : errno;
+ wrerrno = errno;
}
if (wrerr == NO && ftruncate(ofd, size) != 0) {
run_err("%s: truncate: %s", np, strerror(errno));
if (pflag) {
if (exists || omode != mode)
#ifdef HAVE_FCHMOD
- if (fchmod(ofd, omode))
+ if (fchmod(ofd, omode)) {
#else /* HAVE_FCHMOD */
- if (chmod(np, omode))
+ if (chmod(np, omode)) {
#endif /* HAVE_FCHMOD */
run_err("%s: set mode: %s",
np, strerror(errno));
+ wrerr = DISPLAYED;
+ }
} else {
if (!exists && omode != mode)
#ifdef HAVE_FCHMOD
- if (fchmod(ofd, omode & ~mask))
+ if (fchmod(ofd, omode & ~mask)) {
#else /* HAVE_FCHMOD */
- if (chmod(np, omode & ~mask))
+ if (chmod(np, omode & ~mask)) {
#endif /* HAVE_FCHMOD */
run_err("%s: set mode: %s",
np, strerror(errno));
+ wrerr = DISPLAYED;
+ }
}
if (close(ofd) == -1) {
wrerr = YES;
errno = ENOTDIR;
}
run_err("%s: %s", cp, strerror(errno));
- exit(1);
+ killchild(0);
}
int