Exemple #1
0
int ftp_start_download(int sock, const char * remotename, int * size)
{
	if ((*size = ftp_get_filesize(sock, remotename)) == -1) {
		log_message("FTP: could not get filesize (trying to continue)");
		*size = 0;
	}
	return ftp_data_command(sock, "RETR", remotename);
}
Exemple #2
0
int ftp_process_request(struct ftp_session* session, char *buf)
{
	int  fd;
	struct timeval tv;
	fd_set readfds;
	char filename[256];
	int  numbytes;
	char *sbuf;
	char *parameter_ptr, *ptr;
	rt_uint32_t addr_len = sizeof(struct sockaddr_in);
	struct sockaddr_in local, pasvremote;

	sbuf =(char *)rt_malloc(FTP_BUFFER_SIZE);

	tv.tv_sec=3, tv.tv_usec=0;
	local.sin_family=PF_INET;
	local.sin_addr.s_addr=INADDR_ANY;

	/* remove \r\n */
	ptr = buf;
	while (*ptr) {
		if (*ptr == '\r' || *ptr == '\n') *ptr = 0;
		ptr ++;
	}

	/* get request parameter */
	parameter_ptr = strchr(buf, ' ');
	if (parameter_ptr != NULL) parameter_ptr ++;

	// debug:
	rt_kprintf("%s requested: \"%s\"\n", inet_ntoa(session->remote.sin_addr), buf);

	//
	//-----------------------
	if(str_begin_with(buf, "USER")==0) {
		rt_kprintf("%s sent login \"%s\"\n", inet_ntoa(session->remote.sin_addr), parameter_ptr);
		// login correct
		if(strcmp(parameter_ptr, "anonymous") == 0) {
			session->is_anonymous = RT_TRUE;
			rt_sprintf(sbuf, "331 Anonymous login OK send e-mail address for password.\r\n", parameter_ptr);
			send(session->sockfd, sbuf, strlen(sbuf), 0);
		} else if (strcmp(parameter_ptr, FTP_USER) == 0) {
			session->is_anonymous = RT_FALSE;
			rt_sprintf(sbuf, "331 Password required for %s\r\n", parameter_ptr);
			send(session->sockfd, sbuf, strlen(sbuf), 0);
		} else {
			// incorrect login
			rt_sprintf(sbuf, "530 Login incorrect. Bye.\r\n");
			send(session->sockfd, sbuf, strlen(sbuf), 0);
			rt_free(sbuf);
			return -1;
		}
		return 0;
	} else if(str_begin_with(buf, "PASS")==0) {
		rt_kprintf("%s sent password \"%s\"\n", inet_ntoa(session->remote.sin_addr), parameter_ptr);
		if (strcmp(parameter_ptr, FTP_PASSWORD)==0 ||
			session->is_anonymous == RT_TRUE) {
			// password correct
			rt_sprintf(sbuf, "230 User logged in\r\n");
			send(session->sockfd, sbuf, strlen(sbuf), 0);
			rt_free(sbuf);
			return 0;
		}

		// incorrect password
		rt_sprintf(sbuf, "530 Login or Password incorrect. Bye!\r\n");
		send(session->sockfd, sbuf, strlen(sbuf), 0);
		rt_free(sbuf);
		return -1;
	} else if(str_begin_with(buf, "LIST")==0  ) {
		memset(sbuf,0,FTP_BUFFER_SIZE);
		rt_sprintf(sbuf, "150 Opening Binary mode connection for file list.\r\n");
		send(session->sockfd, sbuf, strlen(sbuf), 0);
		do_list(session->currentdir, session->pasv_sockfd);
		closesocket(session->pasv_sockfd);
		session->pasv_active = 0;
		rt_sprintf(sbuf, "226 Transfert Complete.\r\n");
		send(session->sockfd, sbuf, strlen(sbuf), 0);
	} else if(str_begin_with(buf, "NLST")==0 ) {
		memset(sbuf, 0, FTP_BUFFER_SIZE);
		rt_sprintf(sbuf, "150 Opening Binary mode connection for file list.\r\n");
		send(session->sockfd, sbuf, strlen(sbuf), 0);
		do_simple_list(session->currentdir, session->pasv_sockfd);
		closesocket(session->pasv_sockfd);
		session->pasv_active = 0;
		rt_sprintf(sbuf, "226 Transfert Complete.\r\n");
		send(session->sockfd, sbuf, strlen(sbuf), 0);
	} else if(str_begin_with(buf, "PWD")==0 || str_begin_with(buf, "XPWD")==0) {
		rt_sprintf(sbuf, "257 \"%s\" is current directory.\r\n", session->currentdir);
		send(session->sockfd, sbuf, strlen(sbuf), 0);
	} else if(str_begin_with(buf, "TYPE")==0) {
		// Ignore it
		if(strcmp(parameter_ptr, "I")==0) {
			rt_sprintf(sbuf, "200 Type set to binary.\r\n");
			send(session->sockfd, sbuf, strlen(sbuf), 0);
		} else {
			rt_sprintf(sbuf, "200 Type set to ascii.\r\n");
			send(session->sockfd, sbuf, strlen(sbuf), 0);
		}
	} else if(str_begin_with(buf, "PASV")==0) {
		int dig1, dig2;
		int sockfd;
		char optval='1';

		session->pasv_port = 10000;
		session->pasv_active = 1;
		local.sin_port=htons(session->pasv_port);
		local.sin_addr.s_addr=INADDR_ANY;

		dig1 = (int)(session->pasv_port/256);
		dig2 = session->pasv_port % 256;

		FD_ZERO(&readfds);
		if((sockfd=socket(PF_INET, SOCK_STREAM, 0))==-1) {
			rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
			send(session->sockfd, sbuf, strlen(sbuf), 0);
			goto err1;
		}
		if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval))==-1) {
			rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
			send(session->sockfd, sbuf, strlen(sbuf), 0);
			goto err1;
		}
		if(bind(sockfd, (struct sockaddr *)&local, addr_len)==-1) {
			rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
			send(session->sockfd, sbuf, strlen(sbuf), 0);
			goto err1;
		}
		if(listen(sockfd, 1)==-1) {
			rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
			send(session->sockfd, sbuf, strlen(sbuf), 0);
			goto err1;
		}
		rt_kprintf("Listening %d seconds @ port %d\n", tv.tv_sec, session->pasv_port);
		rt_sprintf(sbuf, "227 Entering passive mode (%d,%d,%d,%d,%d,%d)\r\n", 127, 0, 0, 1, dig1, dig2);
		send(session->sockfd, sbuf, strlen(sbuf), 0);
		FD_SET(sockfd, &readfds);
		select(0, &readfds, 0, 0, &tv);
		if(FD_ISSET(sockfd, &readfds)) {
			if((session->pasv_sockfd = accept(sockfd, (struct sockaddr*)&pasvremote, &addr_len))==-1) {
				rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
				send(session->sockfd, sbuf, strlen(sbuf), 0);
				goto err1;
			} else {
				rt_kprintf("Got Data(PASV) connection from %s\n", inet_ntoa(pasvremote.sin_addr));
				session->pasv_active = 1;
				closesocket(sockfd);
			}
		} else {
err1:
			closesocket(session->pasv_sockfd);
			session->pasv_active = 0;
			rt_free(sbuf);
			return 0;
		}
	} else if (str_begin_with(buf, "RETR")==0) {
		int file_size;

		strcpy(filename, buf + 5);

		build_full_path(session, parameter_ptr, filename, 256);
		file_size = ftp_get_filesize(filename);
		if (file_size == -1) {
			rt_sprintf(sbuf, "550 \"%s\" : not a regular file\r\n", filename);
			send(session->sockfd, sbuf, strlen(sbuf), 0);
			session->offset=0;
			rt_free(sbuf);
			return 0;
		}

		fd = open(filename, O_RDONLY, 0);
		if (fd < 0) {
			rt_free(sbuf);
			return 0;
		}

		if(session->offset>0 && session->offset < file_size) {
			lseek(fd, session->offset, SEEK_SET);
			rt_sprintf(sbuf, "150 Opening binary mode data connection for partial \"%s\" (%d/%d bytes).\r\n",
					   filename, file_size - session->offset, file_size);
		} else {
			rt_sprintf(sbuf, "150 Opening binary mode data connection for \"%s\" (%d bytes).\r\n", filename, file_size);
		}
		send(session->sockfd, sbuf, strlen(sbuf), 0);
		while((numbytes = read(fd, sbuf, FTP_BUFFER_SIZE))>0) {
			send(session->pasv_sockfd, sbuf, numbytes, 0);
		}
		rt_sprintf(sbuf, "226 Finished.\r\n");
		send(session->sockfd, sbuf, strlen(sbuf), 0);
		close(fd);
		closesocket(session->pasv_sockfd);
	} else if (str_begin_with(buf, "STOR")==0) {
		if(session->is_anonymous == RT_TRUE) {
			rt_sprintf(sbuf, "550 Permission denied.\r\n");
			send(session->sockfd, sbuf, strlen(sbuf), 0);
			rt_free(sbuf);
			return 0;
		}

		build_full_path(session, parameter_ptr, filename, 256);

		fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0);
		if(fd < 0) {
			rt_sprintf(sbuf, "550 Cannot open \"%s\" for writing.\r\n", filename);
			send(session->sockfd, sbuf, strlen(sbuf), 0);
			rt_free(sbuf);
			return 0;
		}
		rt_sprintf(sbuf, "150 Opening binary mode data connection for \"%s\".\r\n", filename);
		send(session->sockfd, sbuf, strlen(sbuf), 0);
		FD_ZERO(&readfds);
		FD_SET(session->pasv_sockfd, &readfds);
		rt_kprintf("Waiting %d seconds for data...\n", tv.tv_sec);
		while(select(session->pasv_sockfd+1, &readfds, 0, 0, &tv)>0 ) {
			if((numbytes=recv(session->pasv_sockfd, sbuf, FTP_BUFFER_SIZE, 0))>0) {
				write(fd, sbuf, numbytes);
			} else if(numbytes==0) {
				close(fd);
				closesocket(session->pasv_sockfd);
				rt_sprintf(sbuf, "226 Finished.\r\n");
				send(session->sockfd, sbuf, strlen(sbuf), 0);
				break;
			} else if(numbytes==-1) {
				close(fd);
				closesocket(session->pasv_sockfd);
				rt_free(sbuf);
				return -1;
			}
		}
		closesocket(session->pasv_sockfd);
	} else if(str_begin_with(buf, "SIZE")==0) {
		int file_size;

		build_full_path(session, parameter_ptr, filename, 256);

		file_size = ftp_get_filesize(filename);
		if( file_size == -1) {
			rt_sprintf(sbuf, "550 \"%s\" : not a regular file\r\n", filename);
			send(session->sockfd, sbuf, strlen(sbuf), 0);
		} else {
			rt_sprintf(sbuf, "213 %d\r\n", file_size);
			send(session->sockfd, sbuf, strlen(sbuf), 0);
		}
	} else if(str_begin_with(buf, "MDTM")==0) {
		rt_sprintf(sbuf, "550 \"/\" : not a regular file\r\n");
		send(session->sockfd, sbuf, strlen(sbuf), 0);
	} else if(str_begin_with(buf, "SYST")==0) {
		rt_sprintf(sbuf, "215 %s\r\n", "RT-Thread RTOS");
		send(session->sockfd, sbuf, strlen(sbuf), 0);
	} else if(str_begin_with(buf, "CWD")==0) {
		build_full_path(session, parameter_ptr, filename, 256);

		rt_sprintf(sbuf, "250 Changed to directory \"%s\"\r\n", filename);
		send(session->sockfd, sbuf, strlen(sbuf), 0);
		strcpy(session->currentdir, filename);
		rt_kprintf("Changed to directory %s", filename);
	} else if(str_begin_with(buf, "CDUP")==0) {
		rt_sprintf(filename, "%s/%s", session->currentdir, "..");

		rt_sprintf(sbuf, "250 Changed to directory \"%s\"\r\n", filename);
		send(session->sockfd, sbuf, strlen(sbuf), 0);
		strcpy(session->currentdir, filename);
		rt_kprintf("Changed to directory %s", filename);
	} else if(str_begin_with(buf, "PORT")==0) {
		int i;
		int portcom[6];
		char tmpip[100];

		i=0;
		portcom[i++]=atoi(strtok(parameter_ptr, ".,;()"));
		for(; i<6; i++)
			portcom[i]=atoi(strtok(0, ".,;()"));
		rt_sprintf(tmpip, "%d.%d.%d.%d", portcom[0], portcom[1], portcom[2], portcom[3]);

		FD_ZERO(&readfds);
		if((session->pasv_sockfd=socket(AF_INET, SOCK_STREAM, 0))==-1) {
			rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
			send(session->sockfd, sbuf, strlen(sbuf), 0);
			closesocket(session->pasv_sockfd);
			session->pasv_active = 0;
			rt_free(sbuf);
			return 0;
		}
		pasvremote.sin_addr.s_addr=inet_addr(tmpip);
		pasvremote.sin_port=htons(portcom[4] * 256 + portcom[5]);
		pasvremote.sin_family=PF_INET;
		if(connect(session->pasv_sockfd, (struct sockaddr *)&pasvremote, addr_len)==-1) {
			// is it only local address?try using gloal ip addr
			pasvremote.sin_addr=session->remote.sin_addr;
			if(connect(session->pasv_sockfd, (struct sockaddr *)&pasvremote, addr_len)==-1) {
				rt_sprintf(sbuf, "425 Can't open data connection.\r\n");
				send(session->sockfd, sbuf, strlen(sbuf), 0);
				closesocket(session->pasv_sockfd);
				rt_free(sbuf);
				return 0;
			}
		}
		session->pasv_active=1;
		session->pasv_port = portcom[4] * 256 + portcom[5];
		rt_kprintf("Connected to Data(PORT) %s @ %d\n", tmpip, portcom[4] * 256 + portcom[5]);
		rt_sprintf(sbuf, "200 Port Command Successful.\r\n");
		send(session->sockfd, sbuf, strlen(sbuf), 0);
	} else if(str_begin_with(buf, "REST")==0) {
		if(atoi(parameter_ptr)>=0) {
			session->offset=atoi(parameter_ptr);
			rt_sprintf(sbuf, "350 Send RETR or STOR to start transfert.\r\n");
			send(session->sockfd, sbuf, strlen(sbuf), 0);
		}
	} else if(str_begin_with(buf, "MKD")==0) {
		if (session->is_anonymous == RT_TRUE) {
			rt_sprintf(sbuf, "550 Permission denied.\r\n");
			send(session->sockfd, sbuf, strlen(sbuf), 0);
			rt_free(sbuf);
			return 0;
		}

		build_full_path(session, parameter_ptr, filename, 256);

		if(mkdir(filename, 0) == -1) {
			rt_sprintf(sbuf, "550 File \"%s\" exists.\r\n", filename);
			send(session->sockfd, sbuf, strlen(sbuf), 0);
		} else {
			rt_sprintf(sbuf, "257 directory \"%s\" successfully created.\r\n", filename);
			send(session->sockfd, sbuf, strlen(sbuf), 0);
		}
	} else if(str_begin_with(buf, "DELE")==0) {
		if (session->is_anonymous == RT_TRUE) {
			rt_sprintf(sbuf, "550 Permission denied.\r\n");
			send(session->sockfd, sbuf, strlen(sbuf), 0);
			rt_free(sbuf);
			return 0;
		}

		build_full_path(session, parameter_ptr, filename, 256);

		if(unlink(filename)==0)
			rt_sprintf(sbuf, "250 Successfully deleted file \"%s\".\r\n", filename);
		else {
			rt_sprintf(sbuf, "550 Not such file or directory: %s.\r\n", filename);
		}
		send(session->sockfd, sbuf, strlen(sbuf), 0);
	} else if(str_begin_with(buf, "RMD")==0) {
		if (session->is_anonymous == RT_TRUE) {
			rt_sprintf(sbuf, "550 Permission denied.\r\n");
			send(session->sockfd, sbuf, strlen(sbuf), 0);
			rt_free(sbuf);
			return 0;
		}
		build_full_path(session, parameter_ptr, filename, 256);

		if(unlink(filename) == -1) {
			rt_sprintf(sbuf, "550 Directory \"%s\" doesn't exist.\r\n", filename);
			send(session->sockfd, sbuf, strlen(sbuf), 0);
		} else {
			rt_sprintf(sbuf, "257 directory \"%s\" successfully deleted.\r\n", filename);
			send(session->sockfd, sbuf, strlen(sbuf), 0);
		}
	}

	else if(str_begin_with(buf, "QUIT")==0) {
		rt_sprintf(sbuf, "221 Bye!\r\n");
		send(session->sockfd, sbuf, strlen(sbuf), 0);
		rt_free(sbuf);
		return -1;
	} else {
		rt_sprintf(sbuf, "502 Not Implemented.\r\n");
		send(session->sockfd, sbuf, strlen(sbuf), 0);
	}
	rt_free(sbuf);
	return 0;
}