diff --git a/fuzz/Makefile.am b/fuzz/Makefile.am
index ba48a511..c155444c 100644
--- a/fuzz/Makefile.am
+++ b/fuzz/Makefile.am
@@ -10,6 +10,7 @@ LDADD = ../lib/libgnu.a \
WGET_TESTS = \
wget_css_fuzzer$(EXEEXT) \
+ wget_ftpls_fuzzer$(EXEEXT) \
wget_html_fuzzer$(EXEEXT) \
wget_options_fuzzer$(EXEEXT)
@@ -34,6 +35,9 @@ endif
wget_css_fuzzer_SOURCES = wget_css_fuzzer.c $(MAIN)
wget_css_fuzzer_LDADD = ../src/libunittest.a $(LDADD)
+wget_ftpls_fuzzer_SOURCES = wget_ftpls_fuzzer.c $(MAIN)
+wget_ftpls_fuzzer_LDADD = ../src/libunittest.a $(LDADD)
+
wget_html_fuzzer_SOURCES = wget_html_fuzzer.c $(MAIN)
wget_html_fuzzer_LDADD = ../src/libunittest.a $(LDADD)
diff --git a/fuzz/wget_ftpls_fuzzer.c b/fuzz/wget_ftpls_fuzzer.c
new file mode 100644
index 00000000..138a5492
--- /dev/null
+++ b/fuzz/wget_ftpls_fuzzer.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright(c) 2017-2018 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Wget.
+ *
+ * GNU Wget is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GNU Wget is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Wget. If not, see .
+ */
+
+#include
+
+#include
+#include // opendir, readdir
+#include // uint8_t
+#include // fmemopen
+#include // strncmp
+#include // free
+#include // open flags
+#include // close
+#include // longjmp, setjmp
+
+#include "wget.h"
+#undef fopen_wgetrc
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+ #include "ftp.h"
+
+ // declarations for wget internal functions
+ int main_wget(int argc, const char **argv);
+ void cleanup(void);
+ FILE *fopen_wget(const char *pathname, const char *mode);
+ FILE *fopen_wgetrc(const char *pathname, const char *mode);
+ void exit_wget(int status);
+#ifdef __cplusplus
+ }
+#endif
+
+#include "fuzzer.h"
+
+FILE *fopen_wget(const char *pathname, const char *mode)
+{
+ return fopen("/dev/null", mode);
+}
+
+FILE *fopen_wgetrc(const char *pathname, const char *mode)
+{
+ return NULL;
+}
+
+#ifdef FUZZING
+void exit_wget(int status)
+{
+}
+#else
+void exit(int status)
+{
+}
+#endif
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+ FILE *fp, *bak;
+ struct fileinfo *fi;
+
+ if (size > 4096) // same as max_len = ... in .options file
+ return 0;
+
+ bak = stderr;
+ stderr = fopen("/dev/null", "w");
+
+ fp = fmemopen((void *) data, size, "r");
+ if (!fp) return 0;
+
+ fi = ftp_parse_ls_fp(fp, ST_UNIX);
+ freefileinfo(fi);
+ rewind(fp);
+
+ fi = ftp_parse_ls_fp(fp, ST_VMS);
+ freefileinfo(fi);
+ rewind(fp);
+
+ fi = ftp_parse_ls_fp(fp, ST_WINNT);
+ freefileinfo(fi);
+ rewind(fp);
+
+ fi = ftp_parse_ls_fp(fp, ST_MACOS);
+ freefileinfo(fi);
+
+ fclose(fp);
+
+ fclose(stderr);
+ stderr = bak;
+
+ return 0;
+}
diff --git a/fuzz/wget_ftpls_fuzzer.dict b/fuzz/wget_ftpls_fuzzer.dict
new file mode 100644
index 00000000..2137bfa8
--- /dev/null
+++ b/fuzz/wget_ftpls_fuzzer.dict
@@ -0,0 +1,20 @@
+"Jan"
+"Feb"
+"Mar"
+"Apr"
+"May"
+"Jun"
+"Jul"
+"Aug"
+"Sep"
+"Oct"
+"Nov"
+"Dec"
+"total"
+"0644"
+"0755"
+" -> "
+".."
+"Total of "
+".DIR"
+".DIR;1"
diff --git a/fuzz/wget_ftpls_fuzzer.in/starter b/fuzz/wget_ftpls_fuzzer.in/starter
new file mode 100644
index 00000000..e9675bb9
--- /dev/null
+++ b/fuzz/wget_ftpls_fuzzer.in/starter
@@ -0,0 +1 @@
+-rwxr--r-- 1 owner group 640 1970 01 01 test
diff --git a/src/ftp-ls.c b/src/ftp-ls.c
index 4b33413a..6808eb6c 100644
--- a/src/ftp-ls.c
+++ b/src/ftp-ls.c
@@ -90,9 +90,8 @@ clean_line (char *line, int len)
The time stamps are stored in a separate variable, time_t
compatible (I hope). The timezones are ignored. */
static struct fileinfo *
-ftp_parse_unix_ls (const char *file, int ignore_perms)
+ftp_parse_unix_ls (FILE *fp, int ignore_perms)
{
- FILE *fp;
static const char *months[] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
@@ -107,12 +106,6 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
char *line = NULL, *tok, *ptok; /* tokenizer */
struct fileinfo *dir, *l, cur; /* list creation */
- fp = fopen (file, "rb");
- if (!fp)
- {
- logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno));
- return NULL;
- }
dir = l = NULL;
/* Line loop to end of file: */
@@ -413,14 +406,12 @@ ftp_parse_unix_ls (const char *file, int ignore_perms)
}
xfree (line);
- fclose (fp);
return dir;
}
static struct fileinfo *
-ftp_parse_winnt_ls (const char *file)
+ftp_parse_winnt_ls (FILE *fp)
{
- FILE *fp;
int len;
int year, month, day; /* for time analysis */
int hour, min;
@@ -431,12 +422,6 @@ ftp_parse_winnt_ls (const char *file)
char *filename;
struct fileinfo *dir, *l, cur; /* list creation */
- fp = fopen (file, "rb");
- if (!fp)
- {
- logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno));
- return NULL;
- }
dir = l = NULL;
/* Line loop to end of file: */
@@ -562,7 +547,6 @@ ftp_parse_winnt_ls (const char *file)
}
xfree (line);
- fclose(fp);
return dir;
}
@@ -677,25 +661,18 @@ static void eat_carets( char *str)
static struct fileinfo *
-ftp_parse_vms_ls (const char *file)
+ftp_parse_vms_ls (FILE *fp)
{
- FILE *fp;
int dt, i, j, len;
int perms;
size_t bufsize = 0;
time_t timenow;
struct tm *timestruct;
- char date_str[ 32];
+ char date_str[32];
char *line = NULL, *tok; /* tokenizer */
struct fileinfo *dir, *l, cur; /* list creation */
- fp = fopen (file, "r");
- if (!fp)
- {
- logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno));
- return NULL;
- }
dir = l = NULL;
/* Skip blank lines, Directory heading, and more blank lines. */
@@ -1003,7 +980,6 @@ ftp_parse_vms_ls (const char *file)
}
xfree (line);
- fclose (fp);
return dir;
}
@@ -1016,39 +992,51 @@ ftp_parse_vms_ls (const char *file)
struct fileinfo *
ftp_parse_ls (const char *file, const enum stype system_type)
+{
+ FILE *fp;
+ struct fileinfo *fi;
+
+ fp = fopen (file, "rb");
+ if (!fp)
+ {
+ logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno));
+ return NULL;
+ }
+
+ fi = ftp_parse_ls_fp (fp, system_type);
+ fclose(fp);
+
+ return fi;
+}
+
+struct fileinfo *
+ftp_parse_ls_fp (FILE *fp, const enum stype system_type)
{
switch (system_type)
{
case ST_UNIX:
- return ftp_parse_unix_ls (file, 0);
+ return ftp_parse_unix_ls (fp, 0);
case ST_WINNT:
{
/* Detect whether the listing is simulating the UNIX format */
- FILE *fp;
- int c;
- fp = fopen (file, "rb");
- if (!fp)
- {
- logprintf (LOG_NOTQUIET, "%s: %s\n", file, strerror (errno));
- return NULL;
- }
- c = fgetc(fp);
- fclose(fp);
+ int c = fgetc(fp);
+ rewind(fp);
+
/* If the first character of the file is '0'-'9', it's WINNT
format. */
if (c >= '0' && c <='9')
- return ftp_parse_winnt_ls (file);
+ return ftp_parse_winnt_ls (fp);
else
- return ftp_parse_unix_ls (file, 1);
+ return ftp_parse_unix_ls (fp, 1);
}
case ST_VMS:
- return ftp_parse_vms_ls (file);
+ return ftp_parse_vms_ls (fp);
case ST_MACOS:
- return ftp_parse_unix_ls (file, 1);
+ return ftp_parse_unix_ls (fp, 1);
default:
logprintf (LOG_NOTQUIET, _("\
Unsupported listing type, trying Unix listing parser.\n"));
- return ftp_parse_unix_ls (file, 0);
+ return ftp_parse_unix_ls (fp, 0);
}
}
diff --git a/src/ftp.c b/src/ftp.c
index a0531df0..f11a9be0 100644
--- a/src/ftp.c
+++ b/src/ftp.c
@@ -2185,7 +2185,6 @@ static uerr_t ftp_retrieve_dirs (struct url *, struct url *,
struct fileinfo *, ccon *);
static uerr_t ftp_retrieve_glob (struct url *, struct url *, ccon *, int);
static struct fileinfo *delelement (struct fileinfo *, struct fileinfo **);
-static void freefileinfo (struct fileinfo *f);
/* Retrieve a list of files given in struct fileinfo linked list. If
a file is a symbolic link, do not retrieve it, but rather try to
@@ -2828,7 +2827,7 @@ delelement (struct fileinfo *f, struct fileinfo **start)
}
/* Free the fileinfo linked list of files. */
-static void
+void
freefileinfo (struct fileinfo *f)
{
while (f)
diff --git a/src/ftp.h b/src/ftp.h
index d30f8d0f..8f7c4c17 100644
--- a/src/ftp.h
+++ b/src/ftp.h
@@ -30,6 +30,9 @@ as that of the covered work. */
#ifndef FTP_H
#define FTP_H
+#include
+#include
+
#include "host.h"
#include "url.h"
@@ -167,6 +170,8 @@ enum wget_ftp_fstatus
};
struct fileinfo *ftp_parse_ls (const char *, const enum stype);
+struct fileinfo *ftp_parse_ls_fp (FILE *, const enum stype);
+void freefileinfo(struct fileinfo *);
uerr_t ftp_loop (struct url *, struct url *, char **, int *, struct url *,
bool, bool);