ftpd: Avoid TOCTOU problem

Assume that opendir() returns only non-NULL if we actually open a
directory.

Update #3530.
This commit is contained in:
Sebastian Huber
2018-10-30 11:53:46 +01:00
parent 8c3cd1e81b
commit fa0adf3618

View File

@@ -1245,7 +1245,6 @@ command_list(FTPD_SessionInfo_t *info, char const *fname, bool wide)
int s; int s;
DIR *dirp = 0; DIR *dirp = 0;
struct dirent *dp = 0; struct dirent *dp = 0;
struct stat stat_buf;
char buf[FTPD_BUFSIZE]; char buf[FTPD_BUFSIZE];
time_t curTime; time_t curTime;
bool ok = true; bool ok = true;
@@ -1265,39 +1264,29 @@ command_list(FTPD_SessionInfo_t *info, char const *fname, bool wide)
return; return;
} }
if(fname[0] == '\0') if (fname[0] == '\0')
fname = "."; fname = ".";
if (0 > stat(fname, &stat_buf)) time(&curTime);
dirp = opendir(fname);
if (dirp != NULL)
{ {
snprintf(buf, FTPD_BUFSIZE, /* FIXME: need "." and ".." only when '-a' option is given */
"%s: No such file or directory.\r\n", fname); ok = ok && send_dirline(s, wide, curTime, fname, "", ".", buf);
send(s, buf, strlen(buf), 0); ok = ok && send_dirline(s, wide, curTime, fname,
} (strcmp(fname, ftpd_root) ? ".." : ""), "..", buf);
else if (S_ISDIR(stat_buf.st_mode) && (NULL == (dirp = opendir(fname))))
{ while (ok && (dp = readdir(dirp)) != NULL)
snprintf(buf, FTPD_BUFSIZE, ok = ok &&
"%s: Can not open directory.\r\n", fname); send_dirline(s, wide, curTime, fname, dp->d_name, dp->d_name, buf);
send(s, buf, strlen(buf), 0);
closedir(dirp);
} }
else else
{ {
time(&curTime); send_dirline(s, wide, curTime, fname, "", fname, buf);
if(!dirp && *fname)
ok = ok && send_dirline(s, wide, curTime, fname, "", fname, buf);
else {
/* FIXME: need "." and ".." only when '-a' option is given */
ok = ok && send_dirline(s, wide, curTime, fname, "", ".", buf);
ok = ok && send_dirline(s, wide, curTime, fname,
(strcmp(fname, ftpd_root) ? ".." : ""), "..", buf);
while (ok && (dp = readdir(dirp)) != NULL)
ok = ok &&
send_dirline(s, wide, curTime, fname, dp->d_name, dp->d_name, buf);
}
} }
if(dirp)
closedir(dirp);
close_data_socket(info); close_data_socket(info);
if (ok) if (ok)