summaryrefslogtreecommitdiff
path: root/scp.c
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 /scp.c
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
Diffstat (limited to 'scp.c')
-rw-r--r--scp.c39
1 files changed, 30 insertions, 9 deletions
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)