Re-apply scp filename matching fix.

This commit is contained in:
Dag-Erling Smørgrav 2019-02-05 15:05:22 +00:00
parent d18f6dc96d
commit 8cb908a5b4
2 changed files with 42 additions and 11 deletions

12
scp.1
View File

@ -18,7 +18,7 @@
.Nd secure copy (remote file copy program)
.Sh SYNOPSIS
.Nm scp
.Op Fl 346BCpqrv
.Op Fl 346BCpqrTv
.Op Fl c Ar cipher
.Op Fl F Ar ssh_config
.Op Fl i Ar identity_file
@ -208,6 +208,16 @@ to use for the encrypted connection.
The program must understand
.Xr ssh 1
options.
.It Fl T
Disable strict filename checking.
By default when copying files from a remote host to a local directory
.Nm
checks that the received filenames match those requested on the command-line
to prevent the remote end from sending unexpected or unwanted files.
Because of differences in how various operating systems and shells interpret
filename wildcards, these checks may cause wanted files to be rejected.
This option disables these checks at the expense of fully trusting that
the server will not send unexpected filenames.
.It Fl v
Verbose mode.
Causes

41
scp.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: scp.c,v 1.197 2018/06/01 04:31:48 dtucker Exp $ */
/* $OpenBSD: scp.c,v 1.203 2019/01/27 07:14:11 jmc Exp $ */
/*
* scp - secure remote copy. This is basically patched BSD rcp which
* uses ssh to do the data transfer (instead of using rcmd).
@ -94,6 +94,7 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <limits.h>
#include <locale.h>
#include <pwd.h>
@ -375,14 +376,14 @@ void verifydir(char *);
struct passwd *pwd;
uid_t userid;
int errs, remin, remout;
int pflag, iamremote, iamrecursive, targetshouldbedirectory;
int Tflag, pflag, iamremote, iamrecursive, targetshouldbedirectory;
#define CMDNEEDS 64
char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */
int response(void);
void rsource(char *, struct stat *);
void sink(int, char *[]);
void sink(int, char *[], const char *);
void source(int, char *[]);
void tolocal(int, char *[]);
void toremote(int, char *[]);
@ -421,8 +422,9 @@ main(int argc, char **argv)
addargs(&args, "-oRemoteCommand=none");
addargs(&args, "-oRequestTTY=no");
fflag = tflag = 0;
while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:")) != -1)
fflag = Tflag = tflag = 0;
while ((ch = getopt(argc, argv,
"dfl:prtTvBCc:i:P:q12346S:o:F:")) != -1) {
switch (ch) {
/* User-visible flags. */
case '1':
@ -501,9 +503,13 @@ main(int argc, char **argv)
setmode(0, O_BINARY);
#endif
break;
case 'T':
Tflag = 1;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
@ -534,7 +540,7 @@ main(int argc, char **argv)
}
if (tflag) {
/* Receive data. */
sink(argc, argv);
sink(argc, argv, NULL);
exit(errs != 0);
}
if (argc < 2)
@ -791,7 +797,7 @@ tolocal(int argc, char **argv)
continue;
}
free(bp);
sink(1, argv + argc - 1);
sink(1, argv + argc - 1, src);
(void) close(remin);
remin = remout = -1;
}
@ -967,7 +973,7 @@ rsource(char *name, struct stat *statp)
(sizeof(type) != 4 && sizeof(type) != 8))
void
sink(int argc, char **argv)
sink(int argc, char **argv, const char *src)
{
static BUF buffer;
struct stat stb;
@ -983,6 +989,7 @@ sink(int argc, char **argv)
unsigned long long ull;
int setimes, targisdir, wrerrno = 0;
char ch, *cp, *np, *targ, *why, *vect[1], buf[2048], visbuf[2048];
char *src_copy = NULL, *restrict_pattern = NULL;
struct timeval tv[2];
#define atime tv[0]
@ -1007,6 +1014,17 @@ sink(int argc, char **argv)
(void) atomicio(vwrite, remout, "", 1);
if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
targisdir = 1;
if (src != NULL && !iamrecursive && !Tflag) {
/*
* Prepare to try to restrict incoming filenames to match
* the requested destination file glob.
*/
if ((src_copy = strdup(src)) == NULL)
fatal("strdup failed");
if ((restrict_pattern = strrchr(src_copy, '/')) != NULL) {
*restrict_pattern++ = '\0';
}
}
for (first = 1;; first = 0) {
cp = buf;
if (atomicio(read, remin, cp, 1) != 1)
@ -1110,6 +1128,9 @@ sink(int argc, char **argv)
run_err("error: unexpected filename: %s", cp);
exit(1);
}
if (restrict_pattern != NULL &&
fnmatch(restrict_pattern, cp, 0) != 0)
SCREWUP("filename does not match request");
if (targisdir) {
static char *namebuf;
static size_t cursize;
@ -1147,7 +1168,7 @@ sink(int argc, char **argv)
goto bad;
}
vect[0] = xstrdup(np);
sink(1, vect);
sink(1, vect, src);
if (setimes) {
setimes = 0;
if (utimes(vect[0], tv) < 0)
@ -1315,7 +1336,7 @@ void
usage(void)
{
(void) fprintf(stderr,
"usage: scp [-346BCpqrv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
"usage: scp [-346BCpqrTv] [-c cipher] [-F ssh_config] [-i identity_file]\n"
" [-l limit] [-o ssh_option] [-P port] [-S program] source ... target\n");
exit(1);
}