php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #34742 [PATCH] FTP fopen wrapper does not work with all servers
Submitted: 2005-10-05 17:01 UTC Modified: 2005-10-11 16:41 UTC
From: fcartegnie at nordnet dot fr Assigned:
Status: Closed Package: FTP related
PHP Version: 5CVS, 4CVS (2005-10-06) (cvs) OS: *
Private report: No CVE-ID: None
 [2005-10-05 17:01 UTC] fcartegnie at nordnet dot fr
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) {


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2005-10-05 17:28 UTC] nlopess@php.net
I've been already hited by this problem (see bug #30516), but I was connecting to another FTP server.
In that time, Konqueror and Mozilla weren't also able to connect to that server, so PHP isn't alone :)
 [2005-10-05 17:35 UTC] fcartegnie at nordnet dot fr
I've read your bug #. I guess that this problem is then happening with more than one ftpserver. Minor changes in php would ensure compatibility. Also, splitting commands like 'USER' or 'PASS' in multiple packets does not make really sense.
 [2005-10-11 16:41 UTC] iliaa@php.net
This bug has been fixed in CVS.

Snapshots of the sources are packaged every three hours; this change
will be in the next snapshot. You can grab the snapshot at
http://snaps.php.net/.
 
Thank you for the report, and for helping us make PHP better.


 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 11:01:30 2024 UTC