diff --git a/ext/ftp/tests/server.inc b/ext/ftp/tests/server.inc index add8c3ae70ac..f76dd013a9e1 100644 --- a/ext/ftp/tests/server.inc +++ b/ext/ftp/tests/server.inc @@ -407,6 +407,10 @@ if ($pid) { fclose($fs); + }elseif (preg_match('/^PASV/', $buf, $matches) && isset($pasv_reply_at_buffer_end)) { + // The address ends at the 510th byte and the port is cut off. + fputs($s, "227 " . str_repeat("x", 496) . "127,0,0,1,4,210)\r\n"); + }elseif (preg_match('/^PASV/', $buf, $matches)) { $pasv=true; $host = "127.0.0.1"; @@ -537,6 +541,13 @@ if ($pid) { fclose($fs); }elseif (preg_match('/^SIZE \/bug73457/', $buf)) { fputs($s, "213 10\r\n"); + }elseif (preg_match('/^SIZE \/pasvbufferend/', $buf)) { + fputs($s, "213 10\r\n"); + }elseif (preg_match('/^SIZE \/mdtmnodigits/', $buf)) { + // A longer line with digits, read into the same buffer before MDTM. + fputs($s, "213 10 bytes (19991005213102)\r\n"); + }elseif (preg_match('/^MDTM \/mdtmnodigits/', $buf)) { + fputs($s, "213 unknown\r\n"); }elseif (preg_match("/^SITE/", $buf)) { fputs($s, "500 Syntax error, command unrecognized.\r\n"); }else { diff --git a/ext/standard/ftp_fopen_wrapper.c b/ext/standard/ftp_fopen_wrapper.c index fd7ecec02f19..ecaac6bae4b3 100644 --- a/ext/standard/ftp_fopen_wrapper.c +++ b/ext/standard/ftp_fopen_wrapper.c @@ -77,10 +77,14 @@ typedef struct _php_ftp_dirstream_data { static inline int get_ftp_result(php_stream *stream, char *buffer, size_t buffer_size) { buffer[0] = '\0'; /* in case read fails to read anything */ - while (php_stream_gets(stream, buffer, buffer_size-1) && - !(isdigit((unsigned char)buffer[0]) && isdigit((unsigned char)buffer[1]) && - isdigit((unsigned char)buffer[2]) && buffer[3] == ' ')); - return strtol(buffer, NULL, 10); + while (php_stream_gets(stream, buffer, buffer_size-1)) { + if (isdigit((unsigned char)buffer[0]) && isdigit((unsigned char)buffer[1]) && + isdigit((unsigned char)buffer[2]) && buffer[3] == ' ') { + return strtol(buffer, NULL, 10); + } + } + /* no complete status line, callers parse the reply from buffer + 4 */ + return 0; } /* }}} */ @@ -352,8 +356,10 @@ static unsigned short php_fopen_do_pasv(php_stream *stream, char *ip, size_t ip_ tpath++; } tpath[-1] = '\0'; - memcpy(ip, hoststart, ip_size); - ip[ip_size-1] = '\0'; + if ((size_t)(tpath - hoststart) > ip_size) { + return 0; + } + memcpy(ip, hoststart, tpath - hoststart); hoststart = ip; /* pull out the MSB of the port */ @@ -825,11 +831,11 @@ static int php_stream_ftp_url_stat(php_stream_wrapper *wrapper, const char *url, struct tm tm, tmbuf, *gmt; time_t stamp; - while ((size_t)(p - tmp_line) < sizeof(tmp_line) && !isdigit((unsigned char)*p)) { + while (*p && !isdigit((unsigned char)*p)) { p++; } - if ((size_t)(p - tmp_line) > sizeof(tmp_line)) { + if (!*p) { goto mdtm_error; } diff --git a/ext/standard/tests/streams/ftp_fopen_do_pasv_reply_bounds.phpt b/ext/standard/tests/streams/ftp_fopen_do_pasv_reply_bounds.phpt new file mode 100644 index 000000000000..2cdadd415417 --- /dev/null +++ b/ext/standard/tests/streams/ftp_fopen_do_pasv_reply_bounds.phpt @@ -0,0 +1,20 @@ +--TEST-- +ftp:// wrapper rejects a PASV reply whose address ends at the reply buffer limit +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +Warning: fopen(%s): Failed to open stream: FTP server reports %a in %s on line %d +bool(false) diff --git a/ext/standard/tests/streams/ftp_url_stat_mdtm_no_digits.phpt b/ext/standard/tests/streams/ftp_url_stat_mdtm_no_digits.phpt new file mode 100644 index 000000000000..033c8f016a00 --- /dev/null +++ b/ext/standard/tests/streams/ftp_url_stat_mdtm_no_digits.phpt @@ -0,0 +1,20 @@ +--TEST-- +stat() on ftp:// ignores an MDTM reply without digits +--SKIPIF-- + +--FILE-- + +--EXPECT-- +int(10) +int(-1)