mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-03-22 14:39:24 -05:00
General mechanism for ensuring a dodgy SFTP server can't return
malicious filenames via FXP_READDIR. [originally from svn r4995]
This commit is contained in:
parent
5ea746b15d
commit
6c81ee6706
16
pscp.c
16
pscp.c
@ -687,7 +687,6 @@ void scp_sftp_listdir(char *dirname)
|
|||||||
|
|
||||||
for (i = 0; i < names->nnames; i++)
|
for (i = 0; i < names->nnames; i++)
|
||||||
ournames[nnames++] = names->names[i];
|
ournames[nnames++] = names->names[i];
|
||||||
|
|
||||||
names->nnames = 0; /* prevent free_names */
|
names->nnames = 0; /* prevent free_names */
|
||||||
fxp_free_names(names);
|
fxp_free_names(names);
|
||||||
}
|
}
|
||||||
@ -1289,8 +1288,21 @@ int scp_get_sink_action(struct scp_sink_action *act)
|
|||||||
namesize += names->nnames + 128;
|
namesize += names->nnames + 128;
|
||||||
ournames = sresize(ournames, namesize, struct fxp_name);
|
ournames = sresize(ournames, namesize, struct fxp_name);
|
||||||
}
|
}
|
||||||
for (i = 0; i < names->nnames; i++)
|
for (i = 0; i < names->nnames; i++) {
|
||||||
|
if (!strcmp(names->names[i].filename, ".") ||
|
||||||
|
!strcmp(names->names[i].filename, "..")) {
|
||||||
|
/*
|
||||||
|
* . and .. are normal consequences of
|
||||||
|
* reading a directory, and aren't worth
|
||||||
|
* complaining about.
|
||||||
|
*/
|
||||||
|
} else if (!vet_filename(names->names[i].filename)) {
|
||||||
|
tell_user(stderr, "ignoring potentially dangerous server-"
|
||||||
|
"supplied filename '%s'\n",
|
||||||
|
names->names[i].filename);
|
||||||
|
} else
|
||||||
ournames[nnames++] = names->names[i];
|
ournames[nnames++] = names->names[i];
|
||||||
|
}
|
||||||
names->nnames = 0; /* prevent free_names */
|
names->nnames = 0; /* prevent free_names */
|
||||||
fxp_free_names(names);
|
fxp_free_names(names);
|
||||||
}
|
}
|
||||||
|
23
psftp.c
23
psftp.c
@ -40,14 +40,6 @@ static Config cfg;
|
|||||||
* Higher-level helper functions used in commands.
|
* Higher-level helper functions used in commands.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* Determine whether a string is entirely composed of dots.
|
|
||||||
*/
|
|
||||||
static int is_dots(char *str)
|
|
||||||
{
|
|
||||||
return str[strspn(str, ".")] == '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Attempt to canonify a pathname starting from the pwd. If
|
* Attempt to canonify a pathname starting from the pwd. If
|
||||||
* canonification fails, at least fall back to returning a _valid_
|
* canonification fails, at least fall back to returning a _valid_
|
||||||
@ -291,10 +283,19 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart,
|
|||||||
ournames = sresize(ournames, namesize, struct fxp_name *);
|
ournames = sresize(ournames, namesize, struct fxp_name *);
|
||||||
}
|
}
|
||||||
for (i = 0; i < names->nnames; i++)
|
for (i = 0; i < names->nnames; i++)
|
||||||
if (!is_dots(names->names[i].filename) &&
|
if (strcmp(names->names[i].filename, ".") &&
|
||||||
|
strcmp(names->names[i].filename, "..") &&
|
||||||
(!wildcard || wc_match(wildcard,
|
(!wildcard || wc_match(wildcard,
|
||||||
names->names[i].filename)))
|
names->names[i].filename))) {
|
||||||
ournames[nnames++] = fxp_dup_name(&names->names[i]);
|
if (!vet_filename(names->names[i].filename)) {
|
||||||
|
printf("ignoring potentially dangerous server-"
|
||||||
|
"supplied filename '%s'\n",
|
||||||
|
names->names[i].filename);
|
||||||
|
} else {
|
||||||
|
ournames[nnames++] =
|
||||||
|
fxp_dup_name(&names->names[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
fxp_free_names(names);
|
fxp_free_names(names);
|
||||||
}
|
}
|
||||||
sftp_register(req = fxp_close_send(dirhandle));
|
sftp_register(req = fxp_close_send(dirhandle));
|
||||||
|
10
psftp.h
10
psftp.h
@ -149,6 +149,16 @@ WildcardMatcher *begin_wildcard_matching(char *name);
|
|||||||
char *wildcard_get_filename(WildcardMatcher *dir);
|
char *wildcard_get_filename(WildcardMatcher *dir);
|
||||||
void finish_wildcard_matching(WildcardMatcher *dir);
|
void finish_wildcard_matching(WildcardMatcher *dir);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Vet a filename returned from the remote host, to ensure it isn't
|
||||||
|
* in some way malicious. The idea is that this function is applied
|
||||||
|
* to filenames returned from FXP_READDIR, which means we can panic
|
||||||
|
* if we see _anything_ resembling a directory separator.
|
||||||
|
*
|
||||||
|
* Returns TRUE if the filename is kosher, FALSE if dangerous.
|
||||||
|
*/
|
||||||
|
int vet_filename(char *name);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a directory. Returns 0 on error, !=0 on success.
|
* Create a directory. Returns 0 on error, !=0 on success.
|
||||||
*/
|
*/
|
||||||
|
@ -341,6 +341,17 @@ void finish_wildcard_matching(WildcardMatcher *dir) {
|
|||||||
sfree(dir);
|
sfree(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int vet_filename(char *name)
|
||||||
|
{
|
||||||
|
if (strchr(name, '/'))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (name[0] == '.' && (!name[1] || (name[1] == '.' && !name[2])))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
int create_directory(char *name)
|
int create_directory(char *name)
|
||||||
{
|
{
|
||||||
return mkdir(name, 0777) == 0;
|
return mkdir(name, 0777) == 0;
|
||||||
|
@ -445,6 +445,17 @@ void finish_wildcard_matching(WildcardMatcher *dir)
|
|||||||
sfree(dir);
|
sfree(dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int vet_filename(char *name)
|
||||||
|
{
|
||||||
|
if (strchr(name, '/') || strchr(name, '\\') || strchr(name, ':'))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!name[strspn(name, ".")]) /* entirely composed of dots */
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
int create_directory(char *name)
|
int create_directory(char *name)
|
||||||
{
|
{
|
||||||
return CreateDirectory(name, NULL) != 0;
|
return CreateDirectory(name, NULL) != 0;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user