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