From: fcartegnie at nordnet dot fr Operating system: Linux PHP version: 4.4.0 PHP Bug Type: FTP related Bug description: FTP Fopen Wrappers doesn't work work with every server
Description: ------------ I was stuck with a fopen("ftp://... resulting in a "failed to open stream: FTP server reports 220 Serv-U FTP Server v6.0 for WinSock ready..." This URL was working with any other software (WGET, CURL). After analysing and tracing the code, I found the reason: This ftpserver (or maybe firewall) expects only full line commands. The FTP_fopen_wrapper outputs commands while generating then. TCPdumping the flow shows the php client sends "USER " in a single packet, then the remaining of the command. Thoses servers answers after the packet, and php read a wrong command result so. Reproduce code: --------------- I can give privately IP/login/pass for reproducing. Expected result: ---------------- Commands in a single line/packet. Patch follows. Actual result: -------------- --- php-4.4.0/ext/standard/ftp_fopen_wrapper.c 2005-06-27 10:27:23.000000000 +0200 +++ php-4.4.0_modifie/ext/standard/ftp_fopen_wrapper.c 2005-10-05 16:46:03.000000000 +0200 @@ -139,7 +139,7 @@ php_url *resource=NULL; char tmp_line[512]; char ip[sizeof("123.123.123.123")]; - unsigned short portno; + unsigned short portno;char *commandbuffer=NULL; char *scratch; int result; int i, use_ssl, tmp_len; @@ -255,18 +255,19 @@ } /* send the user name */ - php_stream_write_string(stream, "USER "); if (resource->user != NULL) { unsigned char *s, *e; tmp_len = php_raw_url_decode(resource->user, strlen(resource->user)); PHP_FTP_CNTRL_CHK(resource->user, tmp_len, "Invalid login %s") - php_stream_write_string(stream, resource->user); + commandbuffer = (char *) malloc((strlen("USER \r\n") + strlen(resource->user) + 1) * sizeof(char)); + commandbuffer[0]='\0'; commandbuffer = strcat( strcat( strcat(commandbuffer,"USER "), resource->user), "\r\n"); + php_stream_write_string(stream, commandbuffer); + free(commandbuffer); } else { - php_stream_write_string(stream, "anonymous"); + php_stream_write_string(stream, "USER anonymous\r\n"); } - php_stream_write_string(stream, "\r\n"); /* get the response */ result = GET_FTP_RESULT(stream); @@ -275,23 +276,27 @@ if (result >= 300 && result <= 399) { php_stream_notify_info(context, PHP_STREAM_NOTIFY_AUTH_REQUIRED, tmp_line, 0); - php_stream_write_string(stream, "PASS "); if (resource->pass != NULL) { tmp_len = php_raw_url_decode(resource->pass, strlen(resource->pass)); PHP_FTP_CNTRL_CHK(resource->pass, tmp_len, "Invalid password %s") - php_stream_write_string(stream, resource->pass); + commandbuffer = (char *) malloc((strlen("PASS \r\n") + strlen(resource->pass) + 1) * sizeof(char)); + commandbuffer[0]='\0'; commandbuffer = strcat( strcat( strcat(commandbuffer,"PASS "), resource->pass), "\r\n"); + php_stream_write_string(stream, commandbuffer); + free(commandbuffer); } else { /* if the user has configured who they are, send that as the password */ if (cfg_get_string("from", &scratch) == SUCCESS) { - php_stream_write_string(stream, scratch); + commandbuffer = (char *) malloc((strlen("PASS \r\n") + strlen(scratch) + 1) * sizeof(char)); + commandbuffer[0]='\0'; commandbuffer = strcat( strcat( strcat(commandbuffer,"PASS "), scratch), "\r\n"); + php_stream_write_string(stream, commandbuffer); + free(commandbuffer); } else { - php_stream_write_string(stream, "anonymous"); + php_stream_write_string(stream, "PASS anonymous\r\n"); } } - php_stream_write_string(stream, "\r\n"); /* read the response */ result = GET_FTP_RESULT(stream); @@ -312,9 +317,10 @@ goto errexit; /* find out the size of the file (verifying it exists) */ - php_stream_write_string(stream, "SIZE "); - php_stream_write_string(stream, resource->path); - php_stream_write_string(stream, "\r\n"); + commandbuffer = (char *) malloc((strlen("SIZE \r\n") + strlen(resource->path) + 1) * sizeof(char)); + commandbuffer[0]='\0'; commandbuffer = strcat( strcat( strcat(commandbuffer,"SIZE "), resource->path), "\r\n"); + php_stream_write_string(stream, commandbuffer); + free(commandbuffer); /* read the response */ result = GET_FTP_RESULT(stream); @@ -411,17 +417,27 @@ if (mode[0] == 'r') { /* retrieve file */ - php_stream_write_string(stream, "RETR "); + if (resource->path == NULL) { + php_stream_write_string(stream, "RETR / \r\n"); + } else { + commandbuffer = (char *) malloc((strlen("RETR \r\n") + strlen(resource->path) + 1) * sizeof(char)); + commandbuffer[0]='\0'; + commandbuffer = strcat( strcat( strcat(commandbuffer, "RETR "), resource->path), "\r\n"); + php_stream_write_string(stream, commandbuffer); + free(commandbuffer); + } } else { /* store file */ - php_stream_write_string(stream, "STOR "); - } - if (resource->path != NULL) { - php_stream_write_string(stream, resource->path); - } else { - php_stream_write_string(stream, "/"); + if (resource->path == NULL) { + php_stream_write_string(stream, "STOR / \r\n"); + } else { + commandbuffer = (char *) malloc((strlen("STOR \r\n") + strlen(resource->path) + 1) * sizeof(char)); + commandbuffer[0]='\0'; + commandbuffer = strcat( strcat( strcat(commandbuffer, "STOR "), resource->path), "\r\n"); + php_stream_write_string(stream, commandbuffer); + free(commandbuffer); + } } - php_stream_write_string(stream, "\r\n"); /* open the data channel */ if (hoststart == NULL) { -- Edit bug report at http://bugs.php.net/?id=34742&edit=1 -- Try a CVS snapshot (php4): http://bugs.php.net/fix.php?id=34742&r=trysnapshot4 Try a CVS snapshot (php5.0): http://bugs.php.net/fix.php?id=34742&r=trysnapshot50 Try a CVS snapshot (php5.1): http://bugs.php.net/fix.php?id=34742&r=trysnapshot51 Fixed in CVS: http://bugs.php.net/fix.php?id=34742&r=fixedcvs Fixed in release: http://bugs.php.net/fix.php?id=34742&r=alreadyfixed Need backtrace: http://bugs.php.net/fix.php?id=34742&r=needtrace Need Reproduce Script: http://bugs.php.net/fix.php?id=34742&r=needscript Try newer version: http://bugs.php.net/fix.php?id=34742&r=oldversion Not developer issue: http://bugs.php.net/fix.php?id=34742&r=support Expected behavior: http://bugs.php.net/fix.php?id=34742&r=notwrong Not enough info: http://bugs.php.net/fix.php?id=34742&r=notenoughinfo Submitted twice: http://bugs.php.net/fix.php?id=34742&r=submittedtwice register_globals: http://bugs.php.net/fix.php?id=34742&r=globals PHP 3 support discontinued: http://bugs.php.net/fix.php?id=34742&r=php3 Daylight Savings: http://bugs.php.net/fix.php?id=34742&r=dst IIS Stability: http://bugs.php.net/fix.php?id=34742&r=isapi Install GNU Sed: http://bugs.php.net/fix.php?id=34742&r=gnused Floating point limitations: http://bugs.php.net/fix.php?id=34742&r=float No Zend Extensions: http://bugs.php.net/fix.php?id=34742&r=nozend MySQL Configuration Error: http://bugs.php.net/fix.php?id=34742&r=mysqlcfg