for (i = 0; i < names->nnames; i++)
ournames[nnames++] = names->names[i];
-
names->nnames = 0; /* prevent free_names */
fxp_free_names(names);
}
namesize += names->nnames + 128;
ournames = sresize(ournames, namesize, struct fxp_name);
}
- for (i = 0; i < names->nnames; i++)
- ournames[nnames++] = names->names[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];
+ }
names->nnames = 0; /* prevent free_names */
fxp_free_names(names);
}
*/
/*
- * 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
* canonification fails, at least fall back to returning a _valid_
* pathname (though it may be ugly, eg /home/simon/../foobar).
ournames = sresize(ournames, namesize, struct fxp_name *);
}
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,
- names->names[i].filename)))
- ournames[nnames++] = fxp_dup_name(&names->names[i]);
+ names->names[i].filename))) {
+ 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);
}
sftp_register(req = fxp_close_send(dirhandle));
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.
*/
int create_directory(char *name);
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)
{
return mkdir(name, 0777) == 0;
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)
{
return CreateDirectory(name, NULL) != 0;