summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordjm@openbsd.org <djm@openbsd.org>2019-01-26 22:41:28 +0000
committerDamien Miller <djm@mindrot.org>2019-01-27 09:42:39 +1100
commit391ffc4b9d31fa1f4ad566499fef9176ff8a07dc (patch)
tree58ebbdac03a5cfe199f0edc3eedb36af756cd6d9
parentc2c18a39683db382a15b438632afab3f551d50ce (diff)
upstream: check in scp client that filenames sent during
remote->local directory copies satisfy the wildcard specified by the user. This checking provides some protection against a malicious server sending unexpected filenames, but it comes at a risk of rejecting wanted files due to differences between client and server wildcard expansion rules. For this reason, this also adds a new -T flag to disable the check. reported by Harry Sintonen fix approach suggested by markus@; has been in snaps for ~1wk courtesy deraadt@ OpenBSD-Commit-ID: 00f44b50d2be8e321973f3c6d014260f8f7a8eda
-rw-r--r--scp.116
-rw-r--r--scp.c39
2 files changed, 43 insertions, 12 deletions
diff --git a/scp.1 b/scp.1
index 8bb63edaa..a2833dab0 100644
--- a/scp.1
+++ b/scp.1
@@ -8,9 +8,9 @@
8.\" 8.\"
9.\" Created: Sun May 7 00:14:37 1995 ylo 9.\" Created: Sun May 7 00:14:37 1995 ylo
10.\" 10.\"
11.\" $OpenBSD: scp.1,v 1.84 2019/01/22 06:58:31 jmc Exp $ 11.\" $OpenBSD: scp.1,v 1.85 2019/01/26 22:41:28 djm Exp $
12.\" 12.\"
13.Dd $Mdocdate: January 22 2019 $ 13.Dd $Mdocdate: January 26 2019 $
14.Dt SCP 1 14.Dt SCP 1
15.Os 15.Os
16.Sh NAME 16.Sh NAME
@@ -18,7 +18,7 @@
18.Nd secure copy (remote file copy program) 18.Nd secure copy (remote file copy program)
19.Sh SYNOPSIS 19.Sh SYNOPSIS
20.Nm scp 20.Nm scp
21.Op Fl 346BCpqrv 21.Op Fl 346BCpqrTv
22.Op Fl c Ar cipher 22.Op Fl c Ar cipher
23.Op Fl F Ar ssh_config 23.Op Fl F Ar ssh_config
24.Op Fl i Ar identity_file 24.Op Fl i Ar identity_file
@@ -222,6 +222,16 @@ to use for the encrypted connection.
222The program must understand 222The program must understand
223.Xr ssh 1 223.Xr ssh 1
224options. 224options.
225.It Fl T
226Disable strict filename checking.
227By default when copying files from a remote host to a local directory
228.Nm
229checks that the received filenames match those requested on the command-line
230to prevent the remote end from sending unexpected or unwanted files.
231Because of differences in how various operating systems and shells interpret
232filename wildcards, these checks may cause wanted files to be rejected.
233This option disables these checks at the expense of fully trusting that
234the server will not send unexpected filenames.
225.It Fl v 235.It Fl v
226Verbose mode. 236Verbose mode.
227Causes 237Causes
diff --git a/scp.c b/scp.c
index 74dfe521a..e669e815e 100644
--- a/scp.c
+++ b/scp.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: scp.c,v 1.201 2019/01/24 16:52:17 dtucker Exp $ */ 1/* $OpenBSD: scp.c,v 1.202 2019/01/26 22:41:28 djm Exp $ */
2/* 2/*
3 * scp - secure remote copy. This is basically patched BSD rcp which 3 * scp - secure remote copy. This is basically patched BSD rcp which
4 * uses ssh to do the data transfer (instead of using rcmd). 4 * uses ssh to do the data transfer (instead of using rcmd).
@@ -94,6 +94,7 @@
94#include <dirent.h> 94#include <dirent.h>
95#include <errno.h> 95#include <errno.h>
96#include <fcntl.h> 96#include <fcntl.h>
97#include <fnmatch.h>
97#include <limits.h> 98#include <limits.h>
98#include <locale.h> 99#include <locale.h>
99#include <pwd.h> 100#include <pwd.h>
@@ -375,14 +376,14 @@ void verifydir(char *);
375struct passwd *pwd; 376struct passwd *pwd;
376uid_t userid; 377uid_t userid;
377int errs, remin, remout; 378int errs, remin, remout;
378int pflag, iamremote, iamrecursive, targetshouldbedirectory; 379int Tflag, pflag, iamremote, iamrecursive, targetshouldbedirectory;
379 380
380#define CMDNEEDS 64 381#define CMDNEEDS 64
381char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */ 382char cmd[CMDNEEDS]; /* must hold "rcp -r -p -d\0" */
382 383
383int response(void); 384int response(void);
384void rsource(char *, struct stat *); 385void rsource(char *, struct stat *);
385void sink(int, char *[]); 386void sink(int, char *[], const char *);
386void source(int, char *[]); 387void source(int, char *[]);
387void tolocal(int, char *[]); 388void tolocal(int, char *[]);
388void toremote(int, char *[]); 389void toremote(int, char *[]);
@@ -423,8 +424,9 @@ main(int argc, char **argv)
423 addargs(&args, "-oRemoteCommand=none"); 424 addargs(&args, "-oRemoteCommand=none");
424 addargs(&args, "-oRequestTTY=no"); 425 addargs(&args, "-oRequestTTY=no");
425 426
426 fflag = tflag = 0; 427 fflag = Tflag = tflag = 0;
427 while ((ch = getopt(argc, argv, "dfl:prtvBCc:i:P:q12346S:o:F:J:")) != -1) 428 while ((ch = getopt(argc, argv,
429 "dfl:prtTvBCc:i:P:q12346S:o:F:J:")) != -1) {
428 switch (ch) { 430 switch (ch) {
429 /* User-visible flags. */ 431 /* User-visible flags. */
430 case '1': 432 case '1':
@@ -504,9 +506,13 @@ main(int argc, char **argv)
504 setmode(0, O_BINARY); 506 setmode(0, O_BINARY);
505#endif 507#endif
506 break; 508 break;
509 case 'T':
510 Tflag = 1;
511 break;
507 default: 512 default:
508 usage(); 513 usage();
509 } 514 }
515 }
510 argc -= optind; 516 argc -= optind;
511 argv += optind; 517 argv += optind;
512 518
@@ -537,7 +543,7 @@ main(int argc, char **argv)
537 } 543 }
538 if (tflag) { 544 if (tflag) {
539 /* Receive data. */ 545 /* Receive data. */
540 sink(argc, argv); 546 sink(argc, argv, NULL);
541 exit(errs != 0); 547 exit(errs != 0);
542 } 548 }
543 if (argc < 2) 549 if (argc < 2)
@@ -795,7 +801,7 @@ tolocal(int argc, char **argv)
795 continue; 801 continue;
796 } 802 }
797 free(bp); 803 free(bp);
798 sink(1, argv + argc - 1); 804 sink(1, argv + argc - 1, src);
799 (void) close(remin); 805 (void) close(remin);
800 remin = remout = -1; 806 remin = remout = -1;
801 } 807 }
@@ -971,7 +977,7 @@ rsource(char *name, struct stat *statp)
971 (sizeof(type) != 4 && sizeof(type) != 8)) 977 (sizeof(type) != 4 && sizeof(type) != 8))
972 978
973void 979void
974sink(int argc, char **argv) 980sink(int argc, char **argv, const char *src)
975{ 981{
976 static BUF buffer; 982 static BUF buffer;
977 struct stat stb; 983 struct stat stb;
@@ -987,6 +993,7 @@ sink(int argc, char **argv)
987 unsigned long long ull; 993 unsigned long long ull;
988 int setimes, targisdir, wrerrno = 0; 994 int setimes, targisdir, wrerrno = 0;
989 char ch, *cp, *np, *targ, *why, *vect[1], buf[2048], visbuf[2048]; 995 char ch, *cp, *np, *targ, *why, *vect[1], buf[2048], visbuf[2048];
996 char *src_copy = NULL, *restrict_pattern = NULL;
990 struct timeval tv[2]; 997 struct timeval tv[2];
991 998
992#define atime tv[0] 999#define atime tv[0]
@@ -1011,6 +1018,17 @@ sink(int argc, char **argv)
1011 (void) atomicio(vwrite, remout, "", 1); 1018 (void) atomicio(vwrite, remout, "", 1);
1012 if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode)) 1019 if (stat(targ, &stb) == 0 && S_ISDIR(stb.st_mode))
1013 targisdir = 1; 1020 targisdir = 1;
1021 if (src != NULL && !iamrecursive && !Tflag) {
1022 /*
1023 * Prepare to try to restrict incoming filenames to match
1024 * the requested destination file glob.
1025 */
1026 if ((src_copy = strdup(src)) == NULL)
1027 fatal("strdup failed");
1028 if ((restrict_pattern = strrchr(src_copy, '/')) != NULL) {
1029 *restrict_pattern++ = '\0';
1030 }
1031 }
1014 for (first = 1;; first = 0) { 1032 for (first = 1;; first = 0) {
1015 cp = buf; 1033 cp = buf;
1016 if (atomicio(read, remin, cp, 1) != 1) 1034 if (atomicio(read, remin, cp, 1) != 1)
@@ -1115,6 +1133,9 @@ sink(int argc, char **argv)
1115 run_err("error: unexpected filename: %s", cp); 1133 run_err("error: unexpected filename: %s", cp);
1116 exit(1); 1134 exit(1);
1117 } 1135 }
1136 if (restrict_pattern != NULL &&
1137 fnmatch(restrict_pattern, cp, 0) != 0)
1138 SCREWUP("filename does not match request");
1118 if (targisdir) { 1139 if (targisdir) {
1119 static char *namebuf; 1140 static char *namebuf;
1120 static size_t cursize; 1141 static size_t cursize;
@@ -1152,7 +1173,7 @@ sink(int argc, char **argv)
1152 goto bad; 1173 goto bad;
1153 } 1174 }
1154 vect[0] = xstrdup(np); 1175 vect[0] = xstrdup(np);
1155 sink(1, vect); 1176 sink(1, vect, src);
1156 if (setimes) { 1177 if (setimes) {
1157 setimes = 0; 1178 setimes = 0;
1158 if (utimes(vect[0], tv) < 0) 1179 if (utimes(vect[0], tv) < 0)