2300 lines
63 KiB
C
Executable File
2300 lines
63 KiB
C
Executable File
#include "config.h"
|
|
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <stdarg.h>
|
|
/* added for FreeBSD compatibility */
|
|
#include <limits.h>
|
|
#include <signal.h>
|
|
|
|
#define __USE_GNU
|
|
#include <unistd.h>
|
|
#ifdef HAVE_SYS_TYPES_H
|
|
#include <sys/types.h>
|
|
#endif
|
|
#ifdef HAVE_SYS_STAT_H
|
|
#include <sys/stat.h>
|
|
#endif
|
|
#ifdef HAVE_SYS_SOCKET_H
|
|
#include <sys/socket.h>
|
|
#endif
|
|
#ifdef HAVE_ASM_SOCKET_H
|
|
#include <asm/socket.h>
|
|
#endif
|
|
#ifdef HAVE_NETINET_IN_H
|
|
#include <netinet/in.h>
|
|
#endif
|
|
#ifdef HAVE_ARPA_INET_H
|
|
#include <arpa/inet.h>
|
|
#endif
|
|
#ifdef HAVE_SYS_TIME_H
|
|
#include <sys/time.h>
|
|
#endif
|
|
#ifdef HAVE_TIME_H
|
|
#include <time.h>
|
|
#endif
|
|
#include <fcntl.h>
|
|
#include <string.h>
|
|
#ifdef HAVE_WAIT_H
|
|
# include <wait.h>
|
|
#else
|
|
# ifdef HAVE_SYS_WAIT_H
|
|
# include <sys/wait.h>
|
|
# endif
|
|
#endif
|
|
|
|
#include "mystring.h"
|
|
#include "login.h"
|
|
#include "logging.h"
|
|
#include "dirlist.h"
|
|
#include "options.h"
|
|
#include "main.h"
|
|
#include "targzip.h"
|
|
#include "cwd.h"
|
|
#include "bftpdutmp.h"
|
|
#include "md5.h"
|
|
|
|
|
|
#ifdef HAVE_ZLIB_H
|
|
#include <zlib.h>
|
|
#else
|
|
#undef WANT_GZIP
|
|
#endif
|
|
|
|
#define TRENDCHIP 1
|
|
|
|
#ifdef TRENDCHIP
|
|
#include "../lib/libtcapi.h"
|
|
#if defined(TCSUPPORT_CT)
|
|
#include "../../private/cfg_manager_ct/cfg_manager.h"
|
|
#else
|
|
#include "../../private/cfg_manager/cfg_manager.h"
|
|
#endif
|
|
|
|
//#define UG_ROMFILE "1"
|
|
//#define UG_KERNEL "2"
|
|
//#define UG_FS "3"
|
|
#define UPLOAD_CHECK "upload"
|
|
#endif
|
|
#if defined(TCSUPPORT_CT_NETWORKMANAGESERVICE) || defined(TCSUPPORT_FTP_USB)
|
|
#define FTP_USERDEF_PASSWD_CONF "/etc/ftppasswd"
|
|
inline struct passwd *getPasswd(const char *user);
|
|
#endif
|
|
|
|
|
|
// frank added 20110428
|
|
#if defined(TCSUPPORT_CPU_MT7510) || defined(TCSUPPORT_CPU_MT7520)
|
|
#define MAX_RECV_FILE_SIZE 0xc00000 //12MB
|
|
#else
|
|
#define MAX_RECV_FILE_SIZE 0x800000 //5.5MB
|
|
#endif
|
|
|
|
int state = STATE_CONNECTED;
|
|
char user[USERLEN + 1];
|
|
#ifdef TCSUPPORT_IPV6_FTP
|
|
struct sockaddr_storage sa;
|
|
#else
|
|
struct sockaddr_in sa;
|
|
#endif
|
|
char pasv = 0;
|
|
int sock = -1;
|
|
int pasvsock;
|
|
char *philename = NULL;
|
|
unsigned long offset = 0;
|
|
short int xfertype = TYPE_BINARY;
|
|
int ratio_send = 1, ratio_recv = 1;
|
|
/* long unsigned bytes_sent = 0, bytes_recvd = 0; */
|
|
double bytes_sent = 0.0, bytes_recvd = 0.0;
|
|
int epsvall = 0;
|
|
int xfer_bufsize;
|
|
|
|
|
|
void control_printf(char success, char *format, ...)
|
|
{
|
|
char buffer[MAX_STRING_LENGTH];
|
|
va_list val;
|
|
va_start(val, format);
|
|
vsnprintf(buffer, sizeof(buffer), format, val);
|
|
va_end(val);
|
|
fprintf(stderr, "%s\r\n", buffer);
|
|
replace(buffer, "\r", "", MAX_STRING_LENGTH);
|
|
bftpd_statuslog(3, success, "%s", buffer);
|
|
}
|
|
|
|
void new_umask()
|
|
{
|
|
int um;
|
|
unsigned long get_um;
|
|
char *foo = config_getoption("UMASK");
|
|
if (!foo[0])
|
|
um = 022;
|
|
else
|
|
{
|
|
get_um = strtoul(foo, NULL, 8);
|
|
if (get_um <= INT_MAX)
|
|
um = get_um;
|
|
else
|
|
{
|
|
bftpd_log("Error with umask value. Setting to 022.\n", 0);
|
|
um = 022;
|
|
}
|
|
}
|
|
umask(um);
|
|
}
|
|
|
|
void prepare_sock(int sock)
|
|
{
|
|
int on = 1;
|
|
#ifdef TCP_NODELAY
|
|
setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, (void *) &on, sizeof(on));
|
|
#endif
|
|
#ifdef TCP_NOPUSH
|
|
setsockopt(sock, IPPROTO_TCP, TCP_NOPUSH, (void *) &on, sizeof(on));
|
|
#endif
|
|
#ifdef SO_REUSEADDR
|
|
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &on, sizeof(on));
|
|
#endif
|
|
#ifdef SO_REUSEPORT
|
|
setsockopt(sock, SOL_SOCKET, SO_REUSEPORT, (void *) &on, sizeof(on));
|
|
#endif
|
|
#ifdef SO_SNDBUF
|
|
on = 65536;
|
|
setsockopt(sock, SOL_SOCKET, SO_SNDBUF, (void *) &on, sizeof(on));
|
|
#endif
|
|
#if defined(TCSUPPORT_USB_FTP_SERVER)
|
|
#ifdef SO_RCVBUF
|
|
on = 65536;
|
|
setsockopt(sock, SOL_SOCKET, SO_RCVBUF, (void *) &on, sizeof(on));
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
int dataconn()
|
|
{
|
|
struct sockaddr foo;
|
|
#ifdef TCSUPPORT_IPV6_FTP
|
|
struct sockaddr_storage local;
|
|
#else
|
|
struct sockaddr_in local;
|
|
#endif
|
|
socklen_t namelen = sizeof(foo);
|
|
int curuid = geteuid();
|
|
|
|
memset(&foo, 0, sizeof(foo));
|
|
memset(&local, 0, sizeof(local));
|
|
|
|
if (pasv) {
|
|
sock = accept(pasvsock, (struct sockaddr *) &foo, (socklen_t *) &namelen);
|
|
if (sock == -1) {
|
|
control_printf(SL_FAILURE, "425-Unable to accept data connection.\r\n425 %s.",
|
|
strerror(errno));
|
|
return 1;
|
|
}
|
|
close(pasvsock);
|
|
prepare_sock(sock);
|
|
} else {
|
|
#ifdef TCSUPPORT_IPV6_FTP
|
|
if (STORAGE_FAMILY(sa) == AF_INET6)
|
|
{
|
|
sock = socket(AF_INET6, SOCK_STREAM, 0);
|
|
|
|
memcpy(&local, &name, sizeof local);
|
|
if (!strcasecmp(config_getoption("DATAPORT20"), "yes"))
|
|
{
|
|
seteuid(0);
|
|
STORAGE_PORT6(local) = htons(20);
|
|
}
|
|
else
|
|
{
|
|
STORAGE_PORT6(local) = htons(0);
|
|
}
|
|
|
|
STORAGE_FAMILY(local) = AF_INET6;
|
|
}
|
|
else
|
|
{
|
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
if (!strcasecmp(config_getoption("DATAPORT20"), "yes"))
|
|
{
|
|
seteuid(0);
|
|
STORAGE_PORT(local) = htons(20);
|
|
}
|
|
memcpy(storage_sin_addr(&(local)), storage_sin_addr(&(name)), sizeof(struct in_addr));
|
|
STORAGE_FAMILY(local) = AF_INET;
|
|
}
|
|
|
|
prepare_sock(sock);
|
|
if (bind(sock, (struct sockaddr *) &local, STORAGE_LEN(local)) < 0) {
|
|
control_printf(SL_FAILURE, "425-Unable to bind data socket.\r\n425 %s.",
|
|
strerror(errno));
|
|
return 1;
|
|
}
|
|
if (!strcasecmp(config_getoption("DATAPORT20"), "yes"))
|
|
seteuid(curuid);
|
|
|
|
if (connect(sock, (struct sockaddr *) &sa, STORAGE_LEN(sa)) == -1) {
|
|
control_printf(SL_FAILURE, "425-Unable to establish data connection.\r\n"
|
|
"425 %s.", strerror(errno));
|
|
return 1;
|
|
}
|
|
#else
|
|
sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
prepare_sock(sock);
|
|
local.sin_addr.s_addr = name.sin_addr.s_addr;
|
|
local.sin_family = AF_INET;
|
|
if (!strcasecmp(config_getoption("DATAPORT20"), "yes")) {
|
|
seteuid(0);
|
|
local.sin_port = htons(20);
|
|
}
|
|
if (bind(sock, (struct sockaddr *) &local, sizeof(local)) < 0) {
|
|
control_printf(SL_FAILURE, "425-Unable to bind data socket.\r\n425 %s.",
|
|
strerror(errno));
|
|
return 1;
|
|
}
|
|
if (!strcasecmp(config_getoption("DATAPORT20"), "yes"))
|
|
seteuid(curuid);
|
|
sa.sin_family = AF_INET;
|
|
if (connect(sock, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
|
|
control_printf(SL_FAILURE, "425-Unable to establish data connection.\r\n"
|
|
"425 %s.", strerror(errno));
|
|
return 1;
|
|
}
|
|
#endif
|
|
}
|
|
control_printf(SL_SUCCESS, "150 %s data connection established.",
|
|
xfertype == TYPE_BINARY ? "BINARY" : "ASCII");
|
|
return 0;
|
|
}
|
|
|
|
void init_userinfo()
|
|
{
|
|
#ifndef NO_GETPWNAM
|
|
/*Brian Load account information from ftppasswd file*/
|
|
#if defined(TCSUPPORT_CT_NETWORKMANAGESERVICE) || defined(TCSUPPORT_FTP_USB)
|
|
struct passwd *temp = getPasswd(user);
|
|
#else
|
|
struct passwd *temp = getpwnam(user);
|
|
#endif
|
|
if (temp) {
|
|
userinfo.pw_name = strdup(temp->pw_name);
|
|
userinfo.pw_passwd = strdup(temp->pw_passwd);
|
|
userinfo.pw_uid = temp->pw_uid;
|
|
userinfo.pw_gid = temp->pw_gid;
|
|
userinfo.pw_gecos = strdup(temp->pw_gecos);
|
|
userinfo.pw_dir = strdup(temp->pw_dir);
|
|
userinfo.pw_shell = strdup(temp->pw_shell);
|
|
userinfo_set = 1;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
void command_user(char *username)
|
|
{
|
|
char *alias;
|
|
if (state) {
|
|
control_printf(SL_FAILURE, "503 Username already given.");
|
|
return;
|
|
}
|
|
mystrncpy(user, username, sizeof(user) - 1);
|
|
userinfo_set = 1; /* Dirty! */
|
|
alias = (char *) config_getoption("ALIAS");
|
|
userinfo_set = 0;
|
|
if (alias[0] != '\0')
|
|
mystrncpy(user, alias, sizeof(user) - 1);
|
|
init_userinfo();
|
|
#ifdef DEBUG
|
|
bftpd_log("Trying to log in as %s.\n", user);
|
|
#endif
|
|
expand_groups();
|
|
if (!strcasecmp(config_getoption("ANONYMOUS_USER"), "yes"))
|
|
{
|
|
state = STATE_USER;
|
|
control_printf(SL_SUCCESS, "331 Password please.");
|
|
/* bftpd_login(""); */
|
|
}
|
|
else {
|
|
state = STATE_USER;
|
|
control_printf(SL_SUCCESS, "331 Password please.");
|
|
}
|
|
}
|
|
|
|
void command_pass(char *password)
|
|
{
|
|
if (state > STATE_USER) {
|
|
control_printf(SL_FAILURE, "503 Already logged in.");
|
|
return;
|
|
}
|
|
if (bftpd_login(password)) {
|
|
bftpd_log("Login as user '%s' failed.\n", user);
|
|
control_printf(SL_FAILURE, "530 Login incorrect.");
|
|
// exit(0);
|
|
state = STATE_CONNECTED;
|
|
return;
|
|
}
|
|
}
|
|
#if defined(TC_REMOVE) || defined(TCSUPPORT_FTP_CMD)
|
|
void command_pwd(char *params)
|
|
{
|
|
char *my_cwd = NULL;
|
|
|
|
my_cwd = bftpd_cwd_getcwd();
|
|
if (my_cwd)
|
|
{
|
|
control_printf(SL_SUCCESS, "257 \"%s\" is the current working directory.", my_cwd);
|
|
free(my_cwd);
|
|
}
|
|
}
|
|
|
|
|
|
void command_type(char *params)
|
|
{
|
|
if ((*params == 'A') || (*params == 'a')) {
|
|
control_printf(SL_SUCCESS, "200 Transfer type changed to ASCII");
|
|
xfertype = TYPE_ASCII;
|
|
} else if ((*params == 'I') || (*params == 'i')) {
|
|
control_printf(SL_SUCCESS, "200 Transfer type changed to BINARY");
|
|
xfertype = TYPE_BINARY;
|
|
} else
|
|
control_printf(SL_FAILURE, "500 Type '%c' not supported.", *params);
|
|
}
|
|
#endif
|
|
void command_port(char *params) {
|
|
unsigned long a0, a1, a2, a3, p0, p1, addr;
|
|
#ifdef TCSUPPORT_IPV6_FTP
|
|
struct sockaddr_in *temp;
|
|
#endif
|
|
if (epsvall) {
|
|
control_printf(SL_FAILURE, "500 EPSV ALL has been called.");
|
|
return;
|
|
}
|
|
sscanf(params, "%lu,%lu,%lu,%lu,%lu,%lu", &a0, &a1, &a2, &a3, &p0, &p1);
|
|
addr = htonl((a0 << 24) + (a1 << 16) + (a2 << 8) + a3);
|
|
#ifdef TCSUPPORT_IPV6_FTP
|
|
if (STORAGE_FAMILY(remotename) == AF_INET6)
|
|
{
|
|
control_printf(SL_FAILURE, "500 The given address is not match.");
|
|
return;
|
|
}
|
|
|
|
temp = (struct sockaddr_in *)&remotename;
|
|
if((addr != temp->sin_addr.s_addr) &&( strncasecmp(config_getoption("ALLOW_FXP"), "yes", 3))) {
|
|
control_printf(SL_FAILURE, "500 The given address is not yours.");
|
|
return;
|
|
}
|
|
#else
|
|
if((addr != remotename.sin_addr.s_addr) &&( strncasecmp(config_getoption("ALLOW_FXP"), "yes", 3))) {
|
|
control_printf(SL_FAILURE, "500 The given address is not yours.");
|
|
return;
|
|
}
|
|
#endif
|
|
#ifdef TCSUPPORT_IPV6_FTP
|
|
memset(&sa, 0, sizeof sa);
|
|
STORAGE_FAMILY(sa) = AF_INET;
|
|
STORAGE_SIN_ADDR(sa) = addr;
|
|
STORAGE_PORT(sa) = htons((p0 << 8) + p1);
|
|
SET_STORAGE_LEN(sa, sizeof(struct sockaddr_in));
|
|
#else
|
|
sa.sin_addr.s_addr = addr;
|
|
sa.sin_port = htons((p0 << 8) + p1);
|
|
#endif
|
|
if (pasv) {
|
|
if(sock != -1){
|
|
close(sock);
|
|
sock = -1;
|
|
}
|
|
pasv = 0;
|
|
}
|
|
control_printf(SL_SUCCESS, "200 PORT %lu.%lu.%lu.%lu:%lu OK",
|
|
a0, a1, a2, a3, (p0 << 8) + p1);
|
|
}
|
|
//#ifdef TC_REMOVE
|
|
#ifdef TCSUPPORT_IPV6_FTP
|
|
void command_eprt(char *params) {
|
|
char delim;
|
|
int af;
|
|
char addr[51];
|
|
char foo[20];
|
|
int port;
|
|
int flag = 0;
|
|
if (epsvall) {
|
|
control_printf(SL_FAILURE, "500 EPSV ALL has been called.");
|
|
return;
|
|
}
|
|
if (strlen(params) < 5) {
|
|
control_printf(SL_FAILURE, "500 Syntax error.");
|
|
return;
|
|
}
|
|
delim = params[0];
|
|
sprintf(foo, "%c%%i%c%%50[^%c]%c%%i%c", delim, delim, delim, delim, delim);
|
|
|
|
if (sscanf(params, foo, &af, addr, &port) < 3) {
|
|
control_printf(SL_FAILURE, "500 Syntax error.");
|
|
return;
|
|
}
|
|
#ifndef TCSUPPORT_IPV6_FTP
|
|
if (af != 1) {
|
|
control_printf(SL_FAILURE, "522 Protocol unsupported, use (1)");
|
|
return;
|
|
}
|
|
#endif
|
|
#ifdef TCSUPPORT_IPV6_FTP
|
|
if (STORAGE_FAMILY(remotename) == AF_INET6)
|
|
{
|
|
memset(&sa, 0, sizeof sa);
|
|
inet_pton(AF_INET6,addr,&STORAGE_SIN_ADDR6(sa));
|
|
flag = memcmp(&((struct sockaddr_in6 *)&sa)->sin6_addr, &((struct sockaddr_in6 *)&remotename)->sin6_addr, sizeof(struct in6_addr));
|
|
if(flag &&( strncasecmp(config_getoption("ALLOW_FXP"), "yes", 3))) {
|
|
control_printf(SL_FAILURE, "500 The given address is not yours.");
|
|
return;
|
|
}
|
|
|
|
STORAGE_FAMILY(sa) = AF_INET6;
|
|
STORAGE_PORT6(sa) = htons(port);
|
|
SET_STORAGE_LEN(sa, sizeof(struct sockaddr_in6));
|
|
}
|
|
else
|
|
{
|
|
memset(&sa, 0, sizeof sa);
|
|
inet_pton(AF_INET,addr,&STORAGE_SIN_ADDR(sa));
|
|
flag = memcmp(&((struct sockaddr_in *)&sa)->sin_addr, &((struct sockaddr_in *)&remotename)->sin_addr, sizeof(struct in_addr));
|
|
if(flag &&( strncasecmp(config_getoption("ALLOW_FXP"), "yes", 3))) {
|
|
control_printf(SL_FAILURE, "500 The given address is not yours.");
|
|
return;
|
|
}
|
|
|
|
STORAGE_FAMILY(sa) = AF_INET;
|
|
STORAGE_PORT(sa) = htons(port);
|
|
SET_STORAGE_LEN(sa, sizeof(struct sockaddr_in));
|
|
}
|
|
#else
|
|
sa.sin_addr.s_addr = inet_addr(addr);
|
|
if ((sa.sin_addr.s_addr != remotename.sin_addr.s_addr) && (strncasecmp(config_getoption("ALLOW_FXP"), "yes", 3))) {
|
|
control_printf(SL_FAILURE, "500 The given address is not yours.");
|
|
return;
|
|
}
|
|
sa.sin_port = htons(port);
|
|
#endif
|
|
if (pasv) {
|
|
if(sock != -1){
|
|
close(sock);
|
|
sock = -1;
|
|
}
|
|
pasv = 0;
|
|
}
|
|
control_printf(SL_FAILURE, "200 EPRT %s:%i OK", addr, port);
|
|
}
|
|
|
|
#endif
|
|
#if defined(TC_REMOVE) || defined(TCSUPPORT_FTP_CMD)
|
|
void command_pasv(char *foo)
|
|
{
|
|
int a1, a2, a3, a4;
|
|
socklen_t namelen;
|
|
struct sockaddr_in localsock;
|
|
char *my_override_ip;
|
|
|
|
if (epsvall) {
|
|
control_printf(SL_FAILURE, "500 EPSV ALL has been called.");
|
|
return;
|
|
}
|
|
pasvsock = socket(AF_INET, SOCK_STREAM, 0);
|
|
sa.sin_addr.s_addr = INADDR_ANY;
|
|
sa.sin_family = AF_INET;
|
|
|
|
if (!config_getoption("PASSIVE_PORTS") || !strlen(config_getoption("PASSIVE_PORTS"))) {
|
|
/* bind to any port */
|
|
sa.sin_port = 0;
|
|
if (bind(pasvsock, (struct sockaddr *) &sa, sizeof(sa)) == -1)
|
|
{
|
|
control_printf(SL_FAILURE, "425-Error: Unable to bind data socket.\r\n425 %s", strerror(errno));
|
|
return;
|
|
}
|
|
}
|
|
|
|
else {
|
|
int i = 0, success = 0, port;
|
|
for (;;) {
|
|
port = int_from_list(config_getoption("PASSIVE_PORTS"), i++);
|
|
if (port < 0)
|
|
break;
|
|
sa.sin_port = htons(port);
|
|
if (bind(pasvsock, (struct sockaddr *) &sa, sizeof(sa)) == 0) {
|
|
success = 1;
|
|
#ifdef DEBUG
|
|
bftpd_log("Passive mode: Successfully bound port %d\n", port);
|
|
#endif
|
|
break;
|
|
}
|
|
} /* end of for loop */
|
|
if (!success) {
|
|
control_printf(SL_FAILURE, "425 Error: Unable to bind data socket.");
|
|
return;
|
|
}
|
|
prepare_sock(pasvsock);
|
|
} /* end of else using list of ports */
|
|
|
|
if (listen(pasvsock, 1)) {
|
|
control_printf(SL_FAILURE, "425-Error: Unable to make socket listen.\r\n425 %s",
|
|
strerror(errno));
|
|
return;
|
|
}
|
|
namelen = sizeof(localsock);
|
|
getsockname(pasvsock, (struct sockaddr *) &localsock, (socklen_t *) &namelen);
|
|
|
|
/* see if we should over-ride the IP address sent to the client */
|
|
my_override_ip = config_getoption("OVERRIDE_IP");
|
|
if (my_override_ip[0])
|
|
{
|
|
sscanf( my_override_ip, "%i.%i.%i.%i",
|
|
&a1, &a2, &a3, &a4);
|
|
}
|
|
else /* noraml, no over-ride */
|
|
{
|
|
sscanf((char *) inet_ntoa(name.sin_addr), "%i.%i.%i.%i",
|
|
&a1, &a2, &a3, &a4);
|
|
}
|
|
|
|
control_printf(SL_SUCCESS, "227 Entering Passive Mode (%i,%i,%i,%i,%i,%i)", a1, a2, a3, a4,
|
|
ntohs(localsock.sin_port) >> 8, ntohs(localsock.sin_port) & 0xFF);
|
|
pasv = 1;
|
|
}
|
|
|
|
void command_epsv(char *params)
|
|
{
|
|
struct sockaddr_in localsock;
|
|
socklen_t namelen;
|
|
int af;
|
|
if (params[0]) {
|
|
if (!strncasecmp(params, "ALL", 3))
|
|
epsvall = 1;
|
|
else {
|
|
if (sscanf(params, "%i", &af) < 1) {
|
|
control_printf(SL_FAILURE, "500 Syntax error.");
|
|
return;
|
|
} else {
|
|
if (af != 1) {
|
|
control_printf(SL_FAILURE, "522 Protocol unsupported, use (1)");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
pasvsock = socket(AF_INET, SOCK_STREAM, 0);
|
|
sa.sin_addr.s_addr = INADDR_ANY;
|
|
sa.sin_port = 0;
|
|
sa.sin_family = AF_INET;
|
|
if (bind(pasvsock, (struct sockaddr *) &sa, sizeof(sa)) == -1) {
|
|
control_printf(SL_FAILURE, "500-Error: Unable to bind data socket.\r\n425 %s",
|
|
strerror(errno));
|
|
return;
|
|
}
|
|
if (listen(pasvsock, 1)) {
|
|
control_printf(SL_FAILURE, "500-Error: Unable to make socket listen.\r\n425 %s",
|
|
strerror(errno));
|
|
return;
|
|
}
|
|
namelen = sizeof(localsock);
|
|
getsockname(pasvsock, (struct sockaddr *) &localsock, (socklen_t *) &namelen);
|
|
control_printf(SL_SUCCESS, "229 Entering extended passive mode (|||%i|)",
|
|
ntohs(localsock.sin_port));
|
|
pasv = 1;
|
|
}
|
|
#endif
|
|
char test_abort(char selectbefore, int file, int sock)
|
|
{
|
|
char str[256];
|
|
fd_set rfds;
|
|
struct timeval tv;
|
|
if (selectbefore) {
|
|
tv.tv_sec = 0;
|
|
tv.tv_usec = 0;
|
|
FD_ZERO(&rfds);
|
|
FD_SET(fileno(stdin), &rfds);
|
|
if (!select(fileno(stdin) + 1, &rfds, NULL, NULL, &tv))
|
|
return 0;
|
|
}
|
|
fgets(str, sizeof(str), stdin);
|
|
if (strstr(str, "ABOR")) {
|
|
control_printf(SL_SUCCESS, "426 Transfer aborted.");
|
|
close(file);
|
|
if(sock != -1){
|
|
close(sock);
|
|
sock = -1;
|
|
}
|
|
control_printf(SL_SUCCESS, "226 Aborted.");
|
|
bftpd_log("Client aborted file transmission.\n");
|
|
alarm(control_timeout);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
#if defined(TC_REMOVE) || defined(TCSUPPORT_FTP_CMD)
|
|
void command_allo(char *foo)
|
|
{
|
|
command_noop(foo);
|
|
}
|
|
|
|
|
|
/* This function allows the storage of multiple files on the server. */
|
|
void command_mput(char *filenames)
|
|
{
|
|
char filename[MAXCMD]; /* single filename */
|
|
int from_index, to_index; /* position in "filenames" and "filename" */
|
|
|
|
from_index = 0; /* start at begining of filenames */
|
|
memset(filename, 0, MAXCMD); /* clear filename */
|
|
to_index = 0;
|
|
|
|
/* go until we find a NULL character */
|
|
while ( filenames[from_index] > 0)
|
|
{
|
|
/* copy filename until we hit a space */
|
|
if (filenames[from_index] == ' ')
|
|
{
|
|
/* got a full filename */
|
|
command_stor(filename);
|
|
/* clear filename and reset to_index */
|
|
to_index = 0;
|
|
memset(filename, 0, MAXCMD);
|
|
|
|
while (filenames[from_index] == ' ')
|
|
from_index++; /* goto next position */
|
|
}
|
|
|
|
/* if we haven't hit a space, then copy the letter */
|
|
else
|
|
{
|
|
filename[to_index] = filenames[from_index];
|
|
to_index++;
|
|
from_index++;
|
|
/* if the next character is a NULL, then this is the end of the filename */
|
|
if (! filenames[from_index])
|
|
{
|
|
command_stor(filename); /* get the file */
|
|
to_index = 0; /* reset filename index */
|
|
memset(filename, 0, MAXCMD); /* clear filename buffer */
|
|
from_index++; /* goto next character */
|
|
}
|
|
}
|
|
|
|
/* if the buffer is getting too big, then stop */
|
|
if (to_index > (MAXCMD - 2) )
|
|
{
|
|
bftpd_log("Error: Filename in '%s' too long.\n", filenames);
|
|
return;
|
|
}
|
|
|
|
} /* end of while */
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef TCSUPPORT_FW_UPGRADE_16M
|
|
extern unsigned int mark;
|
|
#define SSID1_PORT_MASK 5
|
|
#define SSID4_PORT_MASK 8
|
|
#endif
|
|
|
|
void do_stor(char *filename, int flags)
|
|
{
|
|
char *buffer;
|
|
int fd, i, max;
|
|
fd_set rfds;
|
|
struct timeval tv;
|
|
char *p, *pp;
|
|
char *mapped = bftpd_cwd_mappath(filename);
|
|
|
|
int my_buffer_size; /* total transfer buffer size divided by number of clients */
|
|
int num_clients = 1; /* number of clients connected to the server */
|
|
int new_num_clients = 1;
|
|
int xfer_delay;
|
|
int attempt_gzip = FALSE;
|
|
unsigned long get_value;
|
|
int change_buffer_size = FALSE;
|
|
int stdin_fileno;
|
|
#ifdef HAVE_ZLIB_H
|
|
gzFile my_zip_file = NULL;
|
|
#endif
|
|
|
|
#ifdef TRENDCHIP
|
|
struct stat fd_st;
|
|
char ug_type[2];
|
|
int check_flag = 0;
|
|
FILE *fp;
|
|
int caIndex = 0;
|
|
char indexBuf[2] = {0};
|
|
#endif
|
|
|
|
#if defined(TCSUPPORT_CT) || defined(TCSUPPORT_FTP_USB)
|
|
double bytes_recvd_tmp=0;
|
|
#endif
|
|
|
|
#if !defined(TCSUPPORT_CT_FTP_DOWNLOADCLIENT) && !defined(TCSUPPORT_FTP_USB)
|
|
#ifdef TRENDCHIP
|
|
memset(ug_type,0,sizeof(ug_type));
|
|
check_flag = stat(UPLOAD_CHECK, &fd_st);
|
|
if(check_flag == -1){
|
|
#if !defined(TCSUPPORT_C1_NEW_GUI)
|
|
/*File isn't exist, we need to check the file name*/
|
|
#if 0
|
|
if((strcmp(filename, "linux.7z.trx") != 0)
|
|
&& (strcmp(filename, "rootfs.trx") != 0)
|
|
&& (strcmp(filename, "tclinux.bin") != 0)){
|
|
#else
|
|
if((strcmp(filename, "tclinux.bin") != 0) && (strcmp(filename, "romfile.cfg") != 0)){
|
|
#endif
|
|
/* strcpy(ug_type,UG_KERNEL);
|
|
}
|
|
else if(strcmp(filename, "rootfs.trx") == 0){
|
|
strcpy(ug_type,UG_FS);
|
|
}
|
|
}else{*/
|
|
/*Allowed upload CA file,added by jlinliu_20091215*/
|
|
if((strcmp(filename, "ca1.pem") == 0) ||
|
|
(strcmp(filename, "ca2.pem") == 0) ||
|
|
(strcmp(filename, "ca3.pem") == 0) ||
|
|
(strcmp(filename, "ca4.pem") == 0)){
|
|
//printf("\nftp got ca file,check flag = 0 \n");
|
|
check_flag = 0;
|
|
}
|
|
else{
|
|
bftpd_log("Not allowed to upload '%s'.\n", filename);
|
|
control_printf(SL_FAILURE,
|
|
"553 Error: Remote file is not allowed.");
|
|
if(mapped){
|
|
free(mapped);
|
|
}
|
|
if(sock != -1){
|
|
close(sock);
|
|
sock = -1;
|
|
}
|
|
return;
|
|
}
|
|
#ifdef WITHVOIP
|
|
}else{
|
|
|
|
fp = fopen("/etc/restart_voip","w");
|
|
if(fp != NULL){
|
|
fputc('s',fp);
|
|
fclose(fp);
|
|
}
|
|
sleep(3);
|
|
#endif
|
|
|
|
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef TCSUPPORT_FW_UPGRADE_16M
|
|
if(strcmp(filename, "tclinux.bin") == 0)
|
|
{
|
|
tcapi_set("System_Entry", "upgrade_status", "true");
|
|
#if !defined(TCSUPPORT_CD_NEW_GUI)
|
|
mark = (mark & 0xf0000000) >> 28;
|
|
#if 1
|
|
//tcdbg_printf("%s, mark = %d\n", __FUNCTION__, mark);
|
|
#endif
|
|
if (mark >= SSID1_PORT_MASK && mark <= SSID4_PORT_MASK)
|
|
system("/usr/script/before_web_download.sh 3");
|
|
else
|
|
system("sh /usr/script/before_web_download_remove_wifi.sh 3");
|
|
|
|
#endif
|
|
sleep(1);
|
|
sync();
|
|
}
|
|
#endif
|
|
if (pre_write_script)
|
|
run_script(pre_write_script, mapped);
|
|
|
|
#ifdef HAVE_ZLIB_H
|
|
if (! strcmp( config_getoption("GZ_UPLOAD"), "yes") )
|
|
{
|
|
attempt_gzip = TRUE;
|
|
strcat(mapped, ".gz");
|
|
}
|
|
else
|
|
attempt_gzip = FALSE;
|
|
#endif
|
|
|
|
/* See if we should delay between data transfers */
|
|
get_value = strtoul( config_getoption("XFER_DELAY"), NULL, 0);
|
|
if (get_value <= INT_MAX)
|
|
xfer_delay = get_value;
|
|
else
|
|
{
|
|
bftpd_log("Error getting xfer_delay in do_stor().\n", 0);
|
|
xfer_delay = 0;
|
|
}
|
|
|
|
/* Check to see if the file exists and if we can over-write
|
|
it, if it does. -- Jesse */
|
|
fd = open(mapped, O_RDONLY);
|
|
if (fd >= 0) /* file exists */
|
|
{
|
|
/* close the file */
|
|
close(fd);
|
|
/* check if we can over-write it */
|
|
if ( !strcasecmp( config_getoption("ALLOWCOMMAND_DELE"), "no") )
|
|
{
|
|
bftpd_log("Not allowed to over-write '%s'.\n", filename);
|
|
control_printf(SL_FAILURE,
|
|
"553 Error: Remote file is write protected.");
|
|
|
|
if(mapped){
|
|
free(mapped);
|
|
}
|
|
if(sock != -1){
|
|
close(sock);
|
|
sock = -1;
|
|
}
|
|
|
|
#ifdef TCSUPPORT_FW_UPGRADE_16M
|
|
system("reboot");
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (! attempt_gzip)
|
|
{
|
|
fd = open(mapped, flags, 00666);
|
|
/*
|
|
do this below
|
|
if (mapped)
|
|
free(mapped);
|
|
*/
|
|
if (fd == -1) {
|
|
bftpd_log("Error: '%s' while trying to store file '%s'.\n",
|
|
strerror(errno), filename);
|
|
control_printf(SL_FAILURE, "553 Error: %s.", strerror(errno));
|
|
|
|
close(fd); /* make sure it is not open */
|
|
if (post_write_script)
|
|
run_script(post_write_script, mapped);
|
|
if(mapped){
|
|
free(mapped);
|
|
}
|
|
#ifdef TCSUPPORT_FW_UPGRADE_16M
|
|
system("reboot");
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
|
|
#ifdef HAVE_ZLIB_H
|
|
if ( attempt_gzip )
|
|
{
|
|
my_zip_file = gzopen(mapped, "wb+");
|
|
if (mapped)
|
|
{
|
|
free(mapped);
|
|
mapped = NULL;
|
|
}
|
|
if (! my_zip_file)
|
|
{
|
|
control_printf(SL_FAILURE, "553 Error: An error occured creating compressed file.");
|
|
if(sock != -1){
|
|
close(sock);
|
|
sock = -1;
|
|
}
|
|
close(fd);
|
|
#ifdef TCSUPPORT_FW_UPGRADE_16M
|
|
system("reboot");
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
bftpd_log("Client is storing file '%s'.\n", filename);
|
|
if (dataconn())
|
|
{
|
|
close(fd);
|
|
if (post_write_script)
|
|
run_script(post_write_script, mapped);
|
|
if (mapped)
|
|
free(mapped);
|
|
#ifdef TCSUPPORT_FW_UPGRADE_16M
|
|
system("reboot");
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
|
|
/* decide if the transfer buffer size should change. */
|
|
if (! strcasecmp( config_getoption("CHANGE_BUFSIZE"), "yes") )
|
|
change_buffer_size = TRUE;
|
|
|
|
/* Figure out how big the transfer buffer should be.
|
|
This will be the total size divided by the number of clients connected.
|
|
-- Jesse
|
|
*/
|
|
if (change_buffer_size)
|
|
{
|
|
num_clients = bftpdutmp_usercount("*");
|
|
my_buffer_size = get_buffer_size(num_clients);
|
|
}
|
|
else
|
|
my_buffer_size = xfer_bufsize;
|
|
|
|
alarm(0);
|
|
buffer = malloc(xfer_bufsize);
|
|
/* Check to see if we are out of memory. -- Jesse */
|
|
if (! buffer)
|
|
{
|
|
bftpd_log("Unable to create buffer to receive file.\n", 0);
|
|
control_printf(SL_FAILURE, "553 Error: An unknown error occured on the server.");
|
|
if (fd >= 0)
|
|
close(fd);
|
|
if(sock != -1){
|
|
close(sock);
|
|
sock = -1;
|
|
}
|
|
#ifdef TCSUPPORT_FW_UPGRADE_16M
|
|
system("reboot");
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
lseek(fd, offset, SEEK_SET);
|
|
offset = 0;
|
|
/* Do not use the whole buffer, because a null byte has to be
|
|
* written after the string in ASCII mode. */
|
|
stdin_fileno = fileno(stdin);
|
|
max = (sock > stdin_fileno ? sock : stdin_fileno) + 1;
|
|
for (;;) /* start receiving loop */
|
|
{
|
|
FD_ZERO(&rfds);
|
|
FD_SET(sock, &rfds);
|
|
FD_SET( stdin_fileno, &rfds);
|
|
|
|
tv.tv_sec = data_timeout;
|
|
tv.tv_usec = 0;
|
|
if (!select(max, &rfds, NULL, NULL, &tv)) {
|
|
if(sock != -1){
|
|
close(sock);
|
|
sock = -1;
|
|
}
|
|
close(fd);
|
|
control_printf(SL_FAILURE, "426 Kicked due to data transmission timeout.");
|
|
bftpd_log("Kicked due to data transmission timeout.\n");
|
|
/* Before we exit, let's remove our entry in the log file. -- Jesse */
|
|
if (post_write_script)
|
|
run_script(post_write_script, mapped);
|
|
|
|
bftpdutmp_end();
|
|
exit(0);
|
|
}
|
|
if (FD_ISSET(stdin_fileno, &rfds)) {
|
|
test_abort(0, fd, sock);
|
|
if (buffer)
|
|
free(buffer);
|
|
close(fd);
|
|
if (post_write_script)
|
|
run_script(post_write_script, mapped);
|
|
if(mapped){
|
|
free(mapped);
|
|
}
|
|
#ifdef TCSUPPORT_FW_UPGRADE_16M
|
|
system("reboot");
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
if (!((i = recv(sock, buffer, my_buffer_size - 1, 0))))
|
|
break;
|
|
bytes_recvd += i;
|
|
#if defined(TCSUPPORT_CT) || defined(TCSUPPORT_FTP_USB)
|
|
bytes_recvd_tmp += i;
|
|
|
|
/*if receive more than 5M, sync immediately*/
|
|
if(bytes_recvd_tmp >= 0x500000)
|
|
{
|
|
sync();
|
|
bytes_recvd_tmp=0;
|
|
}
|
|
#endif
|
|
#if !defined(TCSUPPORT_CT) && !defined(TCSUPPORT_FTP_USB) && !defined(TCSUPPORT_USB_FTP_SERVER)
|
|
if (bytes_recvd > MAX_RECV_FILE_SIZE) {
|
|
tcdbg_printf("Upload file size is out of range\n");
|
|
#ifdef TCSUPPORT_FW_UPGRADE_16M
|
|
system("reboot");
|
|
#else
|
|
unlink(TCLINUX_PATH);
|
|
#endif
|
|
return;
|
|
}
|
|
#endif
|
|
if (xfertype == TYPE_ASCII) {
|
|
buffer[i] = '\0';
|
|
/* on ASCII stransfer, strip character 13 */
|
|
p = pp = buffer;
|
|
while (*p) {
|
|
if ((unsigned char) *p == 13)
|
|
p++;
|
|
else
|
|
*pp++ = *p++;
|
|
}
|
|
*pp++ = 0;
|
|
i = strlen(buffer);
|
|
} // end of if ASCII type transfer
|
|
|
|
#ifdef HAVE_ZLIB_H
|
|
if (my_zip_file)
|
|
gzwrite( my_zip_file, buffer, i );
|
|
#endif
|
|
if(! attempt_gzip)
|
|
write(fd, buffer, i);
|
|
|
|
/* Check to see if our bandwidth usage should change. -- Jesse */
|
|
if (change_buffer_size)
|
|
{
|
|
new_num_clients = bftpdutmp_usercount("*");
|
|
if (new_num_clients != num_clients)
|
|
{
|
|
num_clients = new_num_clients;
|
|
my_buffer_size = get_buffer_size(num_clients);
|
|
}
|
|
}
|
|
|
|
/* check for transfer delay */
|
|
if ( xfer_delay )
|
|
{
|
|
struct timeval wait_time;
|
|
|
|
wait_time.tv_sec = 0;
|
|
wait_time.tv_usec = xfer_delay;
|
|
select( 0, NULL, NULL, NULL, &wait_time);
|
|
}
|
|
|
|
|
|
} // end of for loop, reading
|
|
|
|
free(buffer);
|
|
#ifdef HAVE_ZLIB_H
|
|
gzclose(my_zip_file);
|
|
#else
|
|
close(fd);
|
|
#endif
|
|
|
|
#ifdef TRENDCHIP
|
|
/*shnwind modify new upgrade method. 2009.3.31*/
|
|
|
|
if(check_flag == -1){ /*do firmware upgrade*/
|
|
sprintf(ug_type,"%d",NO_HEADER);
|
|
if(tcapi_set("System_Entry","upgrade_fw", ug_type) != 0){
|
|
control_printf(SL_FAILURE, "TCAPI System Set Entry Fail!!");
|
|
}
|
|
else{
|
|
if(tcapi_commit("System_Entry")!=0){
|
|
control_printf(SL_FAILURE, "The firmware is illegal!!");
|
|
}
|
|
else{
|
|
control_printf(SL_SUCCESS, "WARNING:It will take some minutes writing flash.\nThe modem will reboot itself after finishing writing flash.\nDon't reboot modem within 5 minutes.\n");
|
|
}
|
|
}
|
|
}
|
|
/*SSL CA upload ,Added by jlliu_20091215*/
|
|
if((strcmp(filename, "ca1.pem") == 0))
|
|
caIndex = 1;
|
|
else if((strcmp(filename, "ca2.pem") == 0))
|
|
caIndex = 2;
|
|
else if((strcmp(filename, "ca3.pem") == 0))
|
|
caIndex = 3;
|
|
else if((strcmp(filename, "ca4.pem") == 0))
|
|
caIndex = 4;
|
|
if(caIndex != 0){
|
|
sprintf(indexBuf,"%d",caIndex);
|
|
//control_printf(SL_SUCCESS, "The modem have got a CA file.\n");
|
|
if(tcapi_set("SslCA_Flag","UpgradeFlag", indexBuf) != 0){
|
|
control_printf(SL_FAILURE, "Upgrade CA:TCAPI System Set Entry Fail!!");
|
|
}
|
|
else{
|
|
if(tcapi_commit("SslCA")!=0){
|
|
control_printf(SL_FAILURE, "The CA file is illegal!!");
|
|
}
|
|
else{
|
|
tcapi_save();
|
|
control_printf(SL_SUCCESS, "The modem upload CA successfully.\n");
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
if(sock != -1){
|
|
close(sock);
|
|
sock = -1;
|
|
}
|
|
alarm(control_timeout);
|
|
offset = 0;
|
|
control_printf(SL_SUCCESS, "226 File transmission successful.");
|
|
bftpd_log("File transmission successful.\n");
|
|
#if defined(TCSUPPORT_USB_FTP_SERVER)
|
|
system("echo 3 > /proc/sys/vm/drop_caches");
|
|
#endif
|
|
|
|
#if 0
|
|
#ifdef TRENDCHIP
|
|
if( check_flag == -1 ){
|
|
fp = fopen("upgrade", "w");
|
|
if( fp == NULL ){
|
|
free(mapped);
|
|
return;
|
|
}
|
|
fputs(ug_type, fp);
|
|
fclose(fp);
|
|
}
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
if (post_write_script)
|
|
run_script(post_write_script, mapped);
|
|
|
|
if(mapped){
|
|
free(mapped);
|
|
}
|
|
|
|
}
|
|
|
|
void command_stor(char *filename)
|
|
{
|
|
do_stor(filename, O_CREAT | O_WRONLY | O_TRUNC);
|
|
}
|
|
|
|
void command_appe(char *filename)
|
|
{
|
|
do_stor(filename, O_CREAT | O_WRONLY | O_APPEND);
|
|
}
|
|
|
|
|
|
#if defined(TC_REMOVE) || defined(TCSUPPORT_FTP_CMD)
|
|
|
|
/* Send multpile files to the client. */
|
|
void command_mget(char *filenames)
|
|
{
|
|
char filename[MAXCMD]; /* single filename */
|
|
int from_index, to_index; /* position in "filenames" and "filename" */
|
|
|
|
from_index = 0; /* start at begining of filenames */
|
|
memset(filename, 0, MAXCMD); /* clear filename */
|
|
to_index = 0;
|
|
|
|
/* go until we find a NULL character */
|
|
while ( filenames[from_index] > 0)
|
|
{
|
|
/* copy filename until we hit a space */
|
|
if (filenames[from_index] == ' ')
|
|
{
|
|
/* got a full filename */
|
|
command_retr(filename);
|
|
/* clear filename and reset to_index */
|
|
to_index = 0;
|
|
memset(filename, 0, MAXCMD);
|
|
|
|
while (filenames[from_index] == ' ')
|
|
from_index++; /* goto next position */
|
|
}
|
|
|
|
/* if we haven't hit a space, then copy the letter */
|
|
else
|
|
{
|
|
filename[to_index] = filenames[from_index];
|
|
to_index++;
|
|
from_index++;
|
|
/* if the next character is a NULL, then this is the end of the filename */
|
|
if (! filenames[from_index])
|
|
{
|
|
command_retr(filename); /* send the file */
|
|
to_index = 0; /* reset filename index */
|
|
memset(filename, 0, MAXCMD); /* clear filename buffer */
|
|
from_index++; /* goto next character */
|
|
}
|
|
}
|
|
|
|
/* if the buffer is getting too big, then stop */
|
|
if (to_index > (MAXCMD - 2) )
|
|
{
|
|
bftpd_log("Error: Filename in '%s' too long.\n", filenames);
|
|
return;
|
|
}
|
|
|
|
} /* end of while */
|
|
|
|
}
|
|
#endif
|
|
|
|
void command_retr(char *filename)
|
|
{
|
|
int num_clients = 1;
|
|
int new_num_clients = 1; /* number of connectiosn to the server */
|
|
int my_buffer_size; /* size of the transfer buffer to use */
|
|
char *mapped = NULL;
|
|
char *buffer;
|
|
int xfer_delay;
|
|
struct timeval wait_time;
|
|
unsigned long get_value;
|
|
ssize_t send_status;
|
|
int change_buffer_size = FALSE;
|
|
|
|
#if (defined(WANT_GZIP) || defined(HAVE_ZLIB_H))
|
|
gzFile gzfile;
|
|
#endif
|
|
int phile;
|
|
int i, whattodo = DO_NORMAL;
|
|
struct stat statbuf;
|
|
#if (defined(WANT_TAR) && defined(WANT_GZIP))
|
|
int filedes[2];
|
|
#endif
|
|
#if (defined(WANT_TAR) || defined(WANT_GZIP))
|
|
char *foo;
|
|
#endif
|
|
#ifdef WANT_TAR
|
|
char *argv[4];
|
|
#endif
|
|
|
|
|
|
get_value = strtoul( config_getoption("XFER_DELAY"), NULL, 0);
|
|
if (get_value <= INT_MAX)
|
|
xfer_delay = get_value;
|
|
else
|
|
{
|
|
bftpd_log("Error getting XFER_DELAY in command_retr().\n", 0);
|
|
xfer_delay = 0;
|
|
}
|
|
|
|
mapped = bftpd_cwd_mappath(filename);
|
|
if (! mapped)
|
|
{
|
|
bftpd_log("Memory error in sending file.\n", 0);
|
|
control_printf(SL_FAILURE, "553 An unknown error occured on the server.", 9);
|
|
return;
|
|
}
|
|
|
|
if (! strcasecmp( config_getoption("CHANGE_BUFSIZE"), "yes") )
|
|
change_buffer_size = TRUE;
|
|
|
|
phile = open(mapped, O_RDONLY);
|
|
if (phile == -1) { // failed to open a file
|
|
#if (defined(WANT_TAR) && defined(WANT_GZIP))
|
|
if ((foo = strstr(filename, ".tar.gz")))
|
|
if (strlen(foo) == 7) {
|
|
whattodo = DO_TARGZ;
|
|
*foo = '\0';
|
|
}
|
|
#endif
|
|
#ifdef WANT_TAR
|
|
if ((foo = strstr(filename, ".tar")))
|
|
if (strlen(foo) == 4) {
|
|
whattodo = DO_TARONLY;
|
|
*foo = '\0';
|
|
}
|
|
#endif
|
|
#ifdef WANT_GZIP
|
|
if ((foo = strstr(filename, ".gz")))
|
|
if (strlen(foo) == 3) {
|
|
whattodo = DO_GZONLY;
|
|
*foo = '\0';
|
|
}
|
|
#endif
|
|
if (whattodo == DO_NORMAL) {
|
|
bftpd_log("Error: '%s' while trying to receive file '%s'.\n",
|
|
strerror(errno), filename);
|
|
control_printf(SL_FAILURE, "553 Error: %s.", strerror(errno));
|
|
if (mapped)
|
|
free(mapped);
|
|
return;
|
|
}
|
|
}
|
|
|
|
#ifdef HAVE_ZLIB_H
|
|
else // we did open a file
|
|
{
|
|
char *my_temp;
|
|
char *zip_option;
|
|
|
|
my_temp = strstr(filename, ".gz");
|
|
zip_option = config_getoption("GZ_DOWNLOAD");
|
|
if (my_temp)
|
|
{
|
|
if ( ( strlen(my_temp) == 3) && (! strcasecmp(zip_option, "yes") ) )
|
|
whattodo = DO_GZUNZIP;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
stat(mapped, (struct stat *) &statbuf);
|
|
if (S_ISDIR(statbuf.st_mode)) {
|
|
control_printf(SL_FAILURE, "550 Error: Is a directory.");
|
|
if (mapped)
|
|
free(mapped);
|
|
return;
|
|
}
|
|
|
|
if ((((statbuf.st_size - offset) * ratio_send) / ratio_recv > bytes_recvd
|
|
- bytes_sent) && (strcmp((char *) config_getoption("RATIO"), "none"))) {
|
|
bftpd_log("Error: 'File too big (ratio)' while trying to receive file "
|
|
"'%s'.\n", filename);
|
|
control_printf(SL_FAILURE, "553 File too big. Send at least %lf bytes first.",
|
|
(double) (((statbuf.st_size - offset) * ratio_send) / ratio_recv)
|
|
- bytes_recvd);
|
|
if (mapped)
|
|
free(mapped);
|
|
return;
|
|
}
|
|
bftpd_log("Client is receiving file '%s'.\n", filename);
|
|
switch (whattodo) {
|
|
#if (defined(WANT_TAR) && defined(WANT_GZIP))
|
|
case DO_TARGZ:
|
|
close(phile);
|
|
if (dataconn()) {
|
|
if (mapped)
|
|
free(mapped);
|
|
return;
|
|
}
|
|
alarm(0);
|
|
pipe(filedes);
|
|
if (fork()) {
|
|
buffer = malloc(xfer_bufsize);
|
|
/* check to make sure alloc worked */
|
|
if (! buffer)
|
|
{
|
|
if (mapped)
|
|
free(mapped);
|
|
bftpd_log("Memory error in sending file.\n", 0);
|
|
control_printf(SL_FAILURE, "553 An unknown error occured on the server.", 9);
|
|
return;
|
|
}
|
|
|
|
/* find the size of the transfer buffer divided by number of connections */
|
|
if (change_buffer_size)
|
|
{
|
|
num_clients = bftpdutmp_usercount("*");
|
|
my_buffer_size = get_buffer_size(num_clients);
|
|
}
|
|
else
|
|
my_buffer_size = xfer_bufsize;
|
|
|
|
close(filedes[1]);
|
|
gzfile = gzdopen(sock, "wb");
|
|
while ((i = read(filedes[0], buffer, my_buffer_size))) {
|
|
gzwrite(gzfile, buffer, i);
|
|
test_abort(1, phile, sock);
|
|
|
|
/* check for a change in number of connections */
|
|
if (change_buffer_size)
|
|
{
|
|
new_num_clients = bftpdutmp_usercount("*");
|
|
if (new_num_clients != num_clients)
|
|
{
|
|
num_clients = new_num_clients;
|
|
my_buffer_size = get_buffer_size(num_clients);
|
|
}
|
|
}
|
|
/* pause between transfers */
|
|
if (xfer_delay)
|
|
{
|
|
wait_time.tv_sec = 0;
|
|
wait_time.tv_usec = xfer_delay;
|
|
select( 0, NULL, NULL, NULL, &wait_time);
|
|
}
|
|
} // end of while
|
|
free(buffer);
|
|
gzclose(gzfile);
|
|
wait(NULL); /* Kill the zombie */
|
|
} else {
|
|
stderr = devnull;
|
|
close(filedes[0]);
|
|
close(fileno(stdout));
|
|
dup2(filedes[1], fileno(stdout));
|
|
setvbuf(stdout, NULL, _IONBF, 0);
|
|
argv[0] = "tar";
|
|
argv[1] = "cf";
|
|
argv[2] = "-";
|
|
argv[3] = mapped;
|
|
exit(pax_main(4, argv));
|
|
}
|
|
break;
|
|
#endif
|
|
#ifdef WANT_TAR
|
|
case DO_TARONLY:
|
|
if (dataconn()) {
|
|
if (mapped)
|
|
free(mapped);
|
|
return;
|
|
}
|
|
alarm(0);
|
|
if (fork())
|
|
wait(NULL);
|
|
else {
|
|
stderr = devnull;
|
|
dup2(sock, fileno(stdout));
|
|
argv[0] = "tar";
|
|
argv[1] = "cf";
|
|
argv[2] = "-";
|
|
argv[3] = mapped;
|
|
exit(pax_main(4, argv));
|
|
}
|
|
break;
|
|
#endif
|
|
#ifdef WANT_GZIP
|
|
case DO_GZONLY:
|
|
if (mapped)
|
|
{
|
|
free(mapped);
|
|
mapped = NULL;
|
|
}
|
|
if ((phile = open(mapped, O_RDONLY)) < 0) {
|
|
control_printf(SL_FAILURE, "553 Error: %s.", strerror(errno));
|
|
return;
|
|
}
|
|
if (dataconn()) {
|
|
if (mapped)
|
|
free(mapped);
|
|
return;
|
|
}
|
|
alarm(0);
|
|
buffer = malloc(xfer_bufsize);
|
|
/* check for alloc error */
|
|
if (! buffer)
|
|
{
|
|
bftpd_log("Memory error while sending file.", 0);
|
|
control_printf(SL_FAILURE, "553 An unknown error occured on the server.", 0);
|
|
if (phile) close(phile);
|
|
return;
|
|
}
|
|
|
|
/* check buffer size based on number of connections */
|
|
if (change_buffer_size)
|
|
{
|
|
num_clients = bftpdutmp_usercount("*");
|
|
my_buffer_size = get_buffer_size(num_clients);
|
|
}
|
|
else
|
|
my_buffer_size = xfer_bufsize;
|
|
|
|
/* Use "wb9" for maximum compression, uses more CPU time... */
|
|
gzfile = gzdopen(sock, "wb");
|
|
while ((i = read(phile, buffer, my_buffer_size))) {
|
|
gzwrite(gzfile, buffer, i);
|
|
test_abort(1, phile, sock);
|
|
if (change_buffer_size)
|
|
{
|
|
new_num_clients = bftpdutmp_usercount("*");
|
|
if ( new_num_clients != num_clients )
|
|
{
|
|
num_clients = new_num_clients;
|
|
my_buffer_size = get_buffer_size(num_clients);
|
|
}
|
|
}
|
|
/* pause between transfers */
|
|
if (xfer_delay)
|
|
{
|
|
wait_time.tv_sec = 0;
|
|
wait_time.tv_usec = xfer_delay;
|
|
select( 0, NULL, NULL, NULL, &wait_time);
|
|
}
|
|
}
|
|
free(buffer);
|
|
close(phile);
|
|
gzclose(gzfile);
|
|
break;
|
|
#endif
|
|
|
|
#ifdef HAVE_ZLIB_H
|
|
case DO_GZUNZIP:
|
|
if ( dataconn() )
|
|
return;
|
|
|
|
gzfile = gzdopen(phile, "rb");
|
|
if (! gzfile)
|
|
{
|
|
close(phile);
|
|
bftpd_log("Memory error while sending file.", 0);
|
|
control_printf(SL_FAILURE, "553 An unknown error occured on the server.", 0);
|
|
return;
|
|
}
|
|
|
|
alarm(0);
|
|
buffer = malloc(xfer_bufsize);
|
|
if (! buffer)
|
|
{
|
|
close(phile);
|
|
gzclose(gzfile);
|
|
bftpd_log("Memory error while sending file.", 0);
|
|
control_printf(SL_FAILURE, "553 An unknown error occured on the server.", 0);
|
|
return;
|
|
}
|
|
|
|
/* check buffer size based on number of connections */
|
|
if (change_buffer_size)
|
|
{
|
|
num_clients = bftpdutmp_usercount("*");
|
|
my_buffer_size = get_buffer_size(num_clients);
|
|
}
|
|
else
|
|
my_buffer_size = xfer_bufsize;
|
|
|
|
i = gzread(gzfile, buffer, my_buffer_size);
|
|
while ( i )
|
|
{
|
|
write(sock, buffer, i);
|
|
// test_abort(1, phile, sock);
|
|
|
|
if (change_buffer_size)
|
|
{
|
|
new_num_clients = bftpdutmp_usercount("*");
|
|
if ( new_num_clients != num_clients )
|
|
{
|
|
num_clients = new_num_clients;
|
|
my_buffer_size = get_buffer_size(num_clients);
|
|
}
|
|
}
|
|
|
|
/* pause between transfers */
|
|
if (xfer_delay)
|
|
{
|
|
wait_time.tv_sec = 0;
|
|
wait_time.tv_usec = xfer_delay;
|
|
select( 0, NULL, NULL, NULL, &wait_time);
|
|
}
|
|
|
|
i = gzread(gzfile, buffer, my_buffer_size);
|
|
} // end of while not end of file
|
|
|
|
free(buffer);
|
|
close(phile);
|
|
gzclose(gzfile);
|
|
break; // send file and unzip on the fly
|
|
#endif
|
|
|
|
case DO_NORMAL:
|
|
/* used to be commented out */
|
|
if (mapped)
|
|
{
|
|
free(mapped);
|
|
mapped = NULL;
|
|
}
|
|
if (dataconn())
|
|
return;
|
|
alarm(0);
|
|
lseek(phile, offset, SEEK_SET);
|
|
offset = 0;
|
|
buffer = malloc(xfer_bufsize * 2 + 1);
|
|
/* make sure buffer was created */
|
|
if (! buffer)
|
|
{
|
|
control_printf(SL_FAILURE, "553 An unknown error occured.");
|
|
bftpd_log("Memory error while trying to send file.", 0);
|
|
if(sock != -1){
|
|
close(sock);
|
|
sock = -1;
|
|
}
|
|
close(phile);
|
|
return;
|
|
}
|
|
if (change_buffer_size)
|
|
{
|
|
num_clients = bftpdutmp_usercount("*");
|
|
my_buffer_size = get_buffer_size(num_clients);
|
|
}
|
|
else
|
|
my_buffer_size = xfer_bufsize;
|
|
|
|
while ((i = read(phile, buffer, my_buffer_size))) {
|
|
if (test_abort(1, phile, sock)) {
|
|
free(buffer);
|
|
return;
|
|
}
|
|
|
|
if (xfertype == TYPE_ASCII) {
|
|
buffer[i] = '\0';
|
|
i += replace(buffer, "\n", "\r\n", xfer_bufsize);
|
|
}
|
|
send_status = send(sock, buffer, i, 0);
|
|
// check for dropped connection
|
|
if (send_status < 0)
|
|
{
|
|
free(buffer);
|
|
close(phile);
|
|
if(sock != -1){
|
|
close(sock);
|
|
sock = -1;
|
|
}
|
|
alarm(control_timeout);
|
|
control_printf(SL_SUCCESS, "426 Transfer aborted.");
|
|
control_printf(SL_SUCCESS, "226 Aborted.");
|
|
bftpd_log("File transmission interrupted. Send failed.\n");
|
|
return;
|
|
}
|
|
|
|
bytes_sent += i;
|
|
|
|
if (change_buffer_size)
|
|
{
|
|
new_num_clients = bftpdutmp_usercount("*");
|
|
my_buffer_size = get_buffer_size(num_clients);
|
|
}
|
|
|
|
/* pause between transfers */
|
|
if (xfer_delay)
|
|
{
|
|
wait_time.tv_sec = 0;
|
|
wait_time.tv_usec = xfer_delay;
|
|
select( 0, NULL, NULL, NULL, &wait_time);
|
|
}
|
|
|
|
} // end of while
|
|
free(buffer);
|
|
}
|
|
|
|
close(phile);
|
|
if(sock != -1){
|
|
close(sock);
|
|
sock = -1;
|
|
}
|
|
offset = 0;
|
|
alarm(control_timeout);
|
|
control_printf(SL_SUCCESS, "226 File transmission successful.");
|
|
bftpd_log("File transmission of '%s' successful.\n", filename);
|
|
#if defined(TCSUPPORT_USB_FTP_SERVER)
|
|
system("echo 3 > /proc/sys/vm/drop_caches");
|
|
#endif
|
|
|
|
|
|
if (mapped) free(mapped);
|
|
}
|
|
#if defined(TC_REMOVE) || defined(TCSUPPORT_FTP_CMD)
|
|
void do_dirlist(char *dirname, char verbose)
|
|
{
|
|
FILE *datastream;
|
|
if (dirname[0] != '\0') {
|
|
/* skip arguments */
|
|
if (dirname[0] == '-') {
|
|
while ((dirname[0] != ' ') && (dirname[0] != '\0'))
|
|
dirname++;
|
|
if (dirname[0] != '\0')
|
|
dirname++;
|
|
}
|
|
}
|
|
if (dataconn())
|
|
return;
|
|
alarm(0);
|
|
datastream = fdopen(sock, "w");
|
|
if (dirname[0] == '\0')
|
|
dirlist("*", datastream, verbose);
|
|
else {
|
|
char *mapped = bftpd_cwd_mappath(dirname);
|
|
dirlist(mapped, datastream, verbose);
|
|
free(mapped);
|
|
}
|
|
fclose(datastream);
|
|
alarm(control_timeout);
|
|
control_printf(SL_SUCCESS, "226 Directory list has been submitted.");
|
|
}
|
|
|
|
void command_list(char *dirname)
|
|
{
|
|
do_dirlist(dirname, 1);
|
|
}
|
|
|
|
void command_nlst(char *dirname)
|
|
{
|
|
do_dirlist(dirname, 0);
|
|
}
|
|
|
|
void command_syst(char *params)
|
|
{
|
|
control_printf(SL_SUCCESS, "215 UNIX Type: L8");
|
|
}
|
|
|
|
void command_mdtm(char *filename)
|
|
{
|
|
struct stat statbuf;
|
|
struct tm *filetime;
|
|
char *fullfilename = bftpd_cwd_mappath(filename);
|
|
if (!stat(fullfilename, (struct stat *) &statbuf)) {
|
|
filetime = gmtime((time_t *) & statbuf.st_mtime);
|
|
control_printf(SL_SUCCESS, "213 %04i%02i%02i%02i%02i%02i",
|
|
filetime->tm_year + 1900, filetime->tm_mon + 1,
|
|
filetime->tm_mday, filetime->tm_hour, filetime->tm_min,
|
|
filetime->tm_sec);
|
|
} else {
|
|
control_printf(SL_FAILURE, "550 Error while determining the modification time: %s",
|
|
strerror(errno));
|
|
}
|
|
free(fullfilename);
|
|
}
|
|
|
|
void command_cwd(char *dir)
|
|
{
|
|
if (bftpd_cwd_chdir(dir)) {
|
|
bftpd_log("Error: '%s' while changing directory to '%s'.\n",
|
|
strerror(errno), dir);
|
|
control_printf(SL_FAILURE, "451 Error: %s.", strerror(errno));
|
|
} else {
|
|
bftpd_log("Changed directory to '%s'.\n", dir);
|
|
control_printf(SL_SUCCESS, "250 OK");
|
|
}
|
|
}
|
|
|
|
void command_cdup(char *params)
|
|
{
|
|
bftpd_log("Changed directory to '..'.\n");
|
|
bftpd_cwd_chdir("..");
|
|
control_printf(SL_SUCCESS, "250 OK");
|
|
}
|
|
|
|
void command_dele(char *filename)
|
|
{
|
|
char *mapped = bftpd_cwd_mappath(filename);
|
|
if (pre_write_script)
|
|
run_script(pre_write_script, mapped);
|
|
|
|
if (unlink(mapped)) {
|
|
bftpd_log("Error: '%s' while trying to delete file '%s'.\n",
|
|
strerror(errno), filename);
|
|
control_printf(SL_FAILURE, "451 Error: %s.", strerror(errno));
|
|
} else {
|
|
bftpd_log("Deleted file '%s'.\n", filename);
|
|
control_printf(SL_SUCCESS, "200 OK");
|
|
}
|
|
|
|
if (post_write_script)
|
|
run_script(post_write_script, mapped);
|
|
|
|
free(mapped);
|
|
}
|
|
|
|
void command_mkd(char *dirname)
|
|
{
|
|
char *mapped = bftpd_cwd_mappath(dirname);
|
|
|
|
if (pre_write_script)
|
|
run_script(pre_write_script, mapped);
|
|
|
|
if (mkdir(mapped, 0777)) {
|
|
bftpd_log("Error: '%s' while trying to create directory '%s'.\n",
|
|
strerror(errno), dirname);
|
|
control_printf(SL_FAILURE, "451 Error: %s.", strerror(errno));
|
|
} else {
|
|
bftpd_log("Created directory '%s'.\n", dirname);
|
|
control_printf(SL_SUCCESS, "257 \"%s\" has been created.", dirname);
|
|
}
|
|
|
|
if (post_write_script)
|
|
run_script(post_write_script, mapped);
|
|
|
|
free(mapped);
|
|
}
|
|
|
|
void command_rmd(char *dirname)
|
|
{
|
|
char *mapped = bftpd_cwd_mappath(dirname);
|
|
if (pre_write_script)
|
|
run_script(pre_write_script, mapped);
|
|
|
|
if (rmdir(mapped)) {
|
|
bftpd_log("Error: '%s' while trying to remove directory '%s'.\n", strerror(errno), dirname);
|
|
control_printf(SL_FAILURE, "451 Error: %s.", strerror(errno));
|
|
} else {
|
|
bftpd_log("Removed directory '%s'.\n", dirname);
|
|
control_printf(SL_SUCCESS, "250 OK");
|
|
}
|
|
|
|
if (post_write_script)
|
|
run_script(post_write_script, mapped);
|
|
free(mapped);
|
|
}
|
|
|
|
void command_noop(char *params)
|
|
{
|
|
control_printf(SL_SUCCESS, "200 OK");
|
|
}
|
|
|
|
void command_rnfr(char *oldname)
|
|
{
|
|
FILE *file;
|
|
char *mapped = bftpd_cwd_mappath(oldname);
|
|
if ((file = fopen(mapped, "r"))) {
|
|
fclose(file);
|
|
if (philename)
|
|
free(philename);
|
|
philename = mapped;
|
|
state = STATE_RENAME;
|
|
control_printf(SL_SUCCESS, "350 File exists, ready for destination name");
|
|
} else {
|
|
free(mapped);
|
|
control_printf(SL_FAILURE, "451 Error: %s.", strerror(errno));
|
|
}
|
|
}
|
|
|
|
void command_rnto(char *newname)
|
|
{
|
|
char *mapped = bftpd_cwd_mappath(newname);
|
|
|
|
if (pre_write_script)
|
|
run_script(pre_write_script, mapped);
|
|
|
|
if (rename(philename, mapped)) {
|
|
bftpd_log("Error: '%s' while trying to rename '%s' to '%s'.\n",
|
|
strerror(errno), philename, bftpd_cwd_mappath(newname));
|
|
control_printf(SL_FAILURE, "451 Error: %s.", strerror(errno));
|
|
} else {
|
|
bftpd_log("Successfully renamed '%s' to '%s'.\n", philename, bftpd_cwd_mappath(newname));
|
|
control_printf(SL_SUCCESS, "250 OK");
|
|
state = STATE_AUTHENTICATED;
|
|
}
|
|
|
|
if (post_write_script)
|
|
run_script(post_write_script, mapped);
|
|
|
|
free(philename);
|
|
free(mapped);
|
|
philename = NULL;
|
|
}
|
|
|
|
void command_rest(char *params)
|
|
{
|
|
offset = strtoul(params, NULL, 10);
|
|
control_printf(SL_SUCCESS, "350 Restarting at offset %i.", offset);
|
|
}
|
|
|
|
void command_size(char *filename)
|
|
{
|
|
struct stat statbuf;
|
|
char *mapped = bftpd_cwd_mappath(filename);
|
|
if (!stat(mapped, &statbuf)) {
|
|
control_printf(SL_SUCCESS, "213 %i", (int) statbuf.st_size);
|
|
} else {
|
|
control_printf(SL_FAILURE, "550 Error: %s.", strerror(errno));
|
|
}
|
|
free(mapped);
|
|
}
|
|
#endif
|
|
void command_quit(char *params)
|
|
{
|
|
control_printf(SL_SUCCESS, "221 %s", config_getoption("QUIT_MSG"));
|
|
/* Make sure we log user out. -- Jesse <slicer69@hotmail.com> */
|
|
bftpdutmp_end();
|
|
exit(0);
|
|
}
|
|
#if defined(TC_REMOVE) || defined(TCSUPPORT_FTP_CMD)
|
|
void command_stat(char *filename)
|
|
{
|
|
char *mapped = bftpd_cwd_mappath(filename);
|
|
control_printf(SL_SUCCESS, "213-Status of %s:", filename);
|
|
bftpd_stat(mapped, stderr);
|
|
control_printf(SL_SUCCESS, "213 End of Status.");
|
|
free(mapped);
|
|
}
|
|
|
|
/* SITE commands */
|
|
|
|
void command_chmod(char *params)
|
|
{
|
|
int permissions;
|
|
char *mapped;
|
|
char *my_string;
|
|
|
|
if (!strchr(params, ' ')) {
|
|
control_printf(SL_FAILURE, "550 Usage: SITE CHMOD <permissions> <filename>");
|
|
return;
|
|
}
|
|
my_string = strdup(strchr(params, ' ') + 1);
|
|
if (! my_string)
|
|
{
|
|
control_printf(SL_FAILURE, "550: An error occured on the server trying to CHMOD.");
|
|
return;
|
|
}
|
|
/* mapped = bftpd_cwd_mappath(strdup(strchr(params, ' ') + 1)); */
|
|
mapped = bftpd_cwd_mappath(my_string);
|
|
free(my_string);
|
|
|
|
if (pre_write_script)
|
|
run_script(pre_write_script, mapped);
|
|
|
|
*strchr(params, ' ') = '\0';
|
|
sscanf(params, "%o", &permissions);
|
|
if (chmod(mapped, permissions))
|
|
control_printf(SL_FAILURE, "Error: %s.", strerror(errno));
|
|
else {
|
|
bftpd_log("Changed permissions of '%s' to '%o'.\n", mapped,
|
|
permissions);
|
|
control_printf(SL_SUCCESS, "200 CHMOD successful.");
|
|
}
|
|
if (post_write_script)
|
|
run_script(post_write_script, mapped);
|
|
|
|
free(mapped);
|
|
}
|
|
|
|
void command_chown(char *params)
|
|
{
|
|
char foo[MAXCMD + 1], owner[MAXCMD + 1], group[MAXCMD + 1],
|
|
filename[MAXCMD + 1], *mapped;
|
|
int uid, gid;
|
|
if (!strchr(params, ' ')) {
|
|
control_printf(SL_FAILURE, "550 Usage: SITE CHOWN <owner>[.<group>] <filename>");
|
|
return;
|
|
}
|
|
sscanf(params, "%[^ ] %s", foo, filename);
|
|
if (strchr(foo, '.'))
|
|
sscanf(foo, "%[^.].%s", owner, group);
|
|
else {
|
|
strcpy(owner, foo);
|
|
group[0] = '\0';
|
|
}
|
|
if (!sscanf(owner, "%i", &uid)) /* Is it a number? */
|
|
if (((uid = mygetpwnam(owner, passwdfile))) < 0) {
|
|
control_printf(SL_FAILURE, "550 User '%s' not found.", owner);
|
|
return;
|
|
}
|
|
if (!sscanf(group, "%i", &gid))
|
|
if (((gid = mygetpwnam(group, groupfile))) < 0) {
|
|
control_printf(SL_FAILURE, "550 Group '%s' not found.", group);
|
|
return;
|
|
}
|
|
mapped = bftpd_cwd_mappath(filename);
|
|
if (pre_write_script)
|
|
run_script(pre_write_script, mapped);
|
|
|
|
if (chown(mapped, uid, gid))
|
|
control_printf(SL_FAILURE, "550 Error: %s.", strerror(errno));
|
|
else {
|
|
bftpd_log("Changed owner of '%s' to UID %i GID %i.\n", filename, uid,
|
|
gid);
|
|
control_printf(SL_SUCCESS, "200 CHOWN successful.");
|
|
}
|
|
if (post_write_script)
|
|
run_script(post_write_script, mapped);
|
|
free(mapped);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
/*
|
|
Send the md5sum check of a given file to the
|
|
client.
|
|
*/
|
|
#if defined(TC_REMOVE) || defined(TCSUPPORT_FTP_CMD)
|
|
void command_md5(char *philename)
|
|
{
|
|
FILE *myphile;
|
|
md5_t my_md5;
|
|
char buffer[1024];
|
|
int bytes_read = 0;
|
|
char md5_result[16];
|
|
char output_string[64];
|
|
|
|
if (! philename)
|
|
{
|
|
control_printf(SL_FAILURE, "550 File not found.");
|
|
return;
|
|
}
|
|
|
|
philename++;
|
|
myphile = fopen(philename, "r");
|
|
if (! myphile)
|
|
{
|
|
control_printf(SL_FAILURE, "550 Unable to open file `%s'.", philename);
|
|
return;
|
|
}
|
|
|
|
md5_init(&my_md5);
|
|
bytes_read = fread(buffer, sizeof(char), 1024, myphile);
|
|
while (bytes_read > 0)
|
|
{
|
|
md5_process(&my_md5, buffer, bytes_read);
|
|
bytes_read = fread(buffer, sizeof(char), 1024, myphile);
|
|
}
|
|
|
|
md5_finish(&my_md5, md5_result);
|
|
md5_sig_to_string(md5_result, output_string, sizeof(output_string) );
|
|
control_printf(SL_SUCCESS, "200 MD5 finger print: %s.", output_string);
|
|
fclose(myphile);
|
|
}
|
|
#endif
|
|
|
|
#if defined(TC_REMOVE) || defined(TCSUPPORT_FTP_CMD)
|
|
void command_site(char *str)
|
|
{
|
|
const struct command subcmds[] = {
|
|
{"chmod ", NULL, command_chmod, STATE_AUTHENTICATED},
|
|
{"chown ", NULL, command_chown, STATE_AUTHENTICATED},
|
|
{"md5", NULL, command_md5, STATE_AUTHENTICATED},
|
|
{NULL, NULL, 0}
|
|
};
|
|
int i;
|
|
if (!strcasecmp(config_getoption("ENABLE_SITE"), "no")) {
|
|
control_printf(SL_FAILURE, "550 SITE commands are disabled.");
|
|
return;
|
|
}
|
|
for (i = 0; subcmds[i].name; i++) {
|
|
if (!strncasecmp(str, subcmds[i].name, strlen(subcmds[i].name))) {
|
|
cutto(str, strlen(subcmds[i].name));
|
|
subcmds[i].function(str);
|
|
return;
|
|
}
|
|
}
|
|
|
|
/* see if the user needs help */
|
|
if (! strcasecmp(str, "help") )
|
|
{
|
|
control_printf(SL_SUCCESS, "211-Possible usages for SITE command:");
|
|
control_printf(SL_SUCCESS, "211-site chmod <mask> <filename>");
|
|
control_printf(SL_SUCCESS, "211-site chown <owner> <filename>");
|
|
control_printf(SL_SUCCESS, "211 site md5 <filename>");
|
|
return;
|
|
}
|
|
control_printf(SL_FAILURE, "550 Unknown command: 'SITE %s'.", str);
|
|
}
|
|
|
|
void command_auth(char *type)
|
|
{
|
|
control_printf(SL_FAILURE, "550 Not implemented yet\r\n");
|
|
}
|
|
#endif
|
|
/* Command parsing */
|
|
|
|
const struct command commands[] = {
|
|
{"USER", "<sp> username", command_user, STATE_CONNECTED, 0},
|
|
{"PASS", "<sp> password", command_pass, STATE_USER, 0},
|
|
#if defined(TC_REMOVE) || defined(TCSUPPORT_FTP_CMD)
|
|
{"XPWD", "(returns cwd)", command_pwd, STATE_AUTHENTICATED, 1},
|
|
{"PWD", "(returns cwd)", command_pwd, STATE_AUTHENTICATED, 0},
|
|
{"TYPE", "<sp> type-code (A or I)", command_type, STATE_AUTHENTICATED, 0},
|
|
#endif
|
|
{"PORT", "<sp> h1,h2,h3,h4,p1,p2", command_port, STATE_AUTHENTICATED, 0},
|
|
//#ifdef TC_REMOVE
|
|
#ifdef TCSUPPORT_IPV6_FTP
|
|
{"EPRT", "<sp><d><net-prt><d><ip><d><tcp-prt><d>", command_eprt, STATE_AUTHENTICATED, 1},
|
|
#endif
|
|
#if defined(TC_REMOVE) || defined(TCSUPPORT_FTP_CMD)
|
|
{"PASV", "(returns address/port)", command_pasv, STATE_AUTHENTICATED, 0},
|
|
{"EPSV", "(returns address/post)", command_epsv, STATE_AUTHENTICATED, 1},
|
|
{"ALLO", "<sp> size", command_allo, STATE_AUTHENTICATED, 1},
|
|
#endif
|
|
{"STOR", "<sp> pathname", command_stor, STATE_AUTHENTICATED, 0},
|
|
{"APPE", "<sp> pathname", command_appe, STATE_AUTHENTICATED, 1},
|
|
{"RETR", "<sp> pathname", command_retr, STATE_AUTHENTICATED, 0},
|
|
#if defined(TC_REMOVE) || defined(TCSUPPORT_FTP_CMD)
|
|
{"LIST", "[<sp> pathname]", command_list, STATE_AUTHENTICATED, 0},
|
|
{"NLST", "[<sp> pathname]", command_nlst, STATE_AUTHENTICATED, 0},
|
|
{"SYST", "(returns system type)", command_syst, STATE_CONNECTED, 0},
|
|
{"MDTM", "<sp> pathname", command_mdtm, STATE_AUTHENTICATED, 1},
|
|
{"XCWD", "<sp> pathname", command_cwd, STATE_AUTHENTICATED, 1},
|
|
{"CWD", "<sp> pathname", command_cwd, STATE_AUTHENTICATED, 0},
|
|
{"XCUP", "(up one directory)", command_cdup, STATE_AUTHENTICATED, 1},
|
|
{"CDUP", "(up one directory)", command_cdup, STATE_AUTHENTICATED, 0},
|
|
{"DELE", "<sp> pathname", command_dele, STATE_AUTHENTICATED, 0},
|
|
{"XMKD", "<sp> pathname", command_mkd, STATE_AUTHENTICATED, 1},
|
|
{"MKD", "<sp> pathname", command_mkd, STATE_AUTHENTICATED, 0},
|
|
{"XRMD", "<sp> pathname", command_rmd, STATE_AUTHENTICATED, 1},
|
|
{"RMD", "<sp> pathname", command_rmd, STATE_AUTHENTICATED, 0},
|
|
{"NOOP", "(no operation)", command_noop, STATE_AUTHENTICATED, 0},
|
|
{"RNFR", "<sp> pathname", command_rnfr, STATE_AUTHENTICATED, 0},
|
|
{"RNTO", "<sp> pathname", command_rnto, STATE_RENAME, 0},
|
|
{"REST", "<sp> byte-count", command_rest, STATE_AUTHENTICATED, 1},
|
|
{"SIZE", "<sp> pathname", command_size, STATE_AUTHENTICATED, 1},
|
|
#endif
|
|
{"QUIT", "(close control connection)", command_quit, STATE_CONNECTED, 0},
|
|
#if defined(TC_REMOVE) || defined(TCSUPPORT_FTP_CMD)
|
|
{"HELP", "[<sp> command]", command_help, STATE_AUTHENTICATED, 0},
|
|
{"STAT", "<sp> pathname", command_stat, STATE_AUTHENTICATED, 0},
|
|
{"SITE", "<sp> string", command_site, STATE_AUTHENTICATED, 0},
|
|
{"FEAT", "(returns list of extensions)", command_feat, STATE_AUTHENTICATED, 0},
|
|
{"AUTH", "<sp> authtype", command_auth, STATE_CONNECTED, 0},
|
|
{"ADMIN_LOGIN", "(admin)", command_adminlogin, STATE_CONNECTED, 0},
|
|
{"MGET", "<sp> pathname", command_mget, STATE_AUTHENTICATED, 0},
|
|
{"MPUT", "<sp> pathname", command_mput, STATE_AUTHENTICATED, 0},
|
|
#endif
|
|
{NULL, NULL, NULL, 0, 0}
|
|
};
|
|
#if defined(TC_REMOVE) || defined(TCSUPPORT_FTP_CMD)
|
|
void command_feat(char *params)
|
|
{
|
|
int i;
|
|
control_printf(SL_SUCCESS, "211-Extensions supported:");
|
|
for (i = 0; commands[i].name; i++)
|
|
if (commands[i].showinfeat)
|
|
control_printf(SL_SUCCESS, " %s", commands[i].name);
|
|
control_printf(SL_SUCCESS, "211 End");
|
|
}
|
|
|
|
void command_help(char *params)
|
|
{
|
|
int i;
|
|
if (params[0] == '\0') {
|
|
control_printf(SL_SUCCESS, "214-The following commands are recognized.");
|
|
for (i = 0; commands[i].name; i++)
|
|
control_printf(SL_SUCCESS, "214-%s", commands[i].name);
|
|
control_printf(SL_SUCCESS, "214 End of help");
|
|
} else {
|
|
for (i = 0; commands[i].name; i++)
|
|
if (!strcasecmp(params, commands[i].name))
|
|
control_printf(SL_SUCCESS, "214 Syntax: %s", commands[i].syntax);
|
|
}
|
|
}
|
|
#endif
|
|
int parsecmd(char *str)
|
|
{
|
|
int i;
|
|
char *p, *pp, confstr[64]; /* strlen("ALLOWCOMMAND_XXXX") + 1 == 18 */
|
|
p = pp = str; /* Remove garbage in the string */
|
|
while (*p)
|
|
if ((unsigned char) *p < 32)
|
|
p++;
|
|
else
|
|
*pp++ = *p++;
|
|
*pp++ = 0;
|
|
for (i = 0; commands[i].name; i++) { /* Parse command */
|
|
if (!strncasecmp(str, commands[i].name, strlen(commands[i].name))) {
|
|
sprintf(confstr, "ALLOWCOMMAND_%s", commands[i].name);
|
|
if (!strcasecmp(config_getoption(confstr), "no")) {
|
|
control_printf(SL_FAILURE, "550 The command '%s' is disabled.",
|
|
commands[i].name);
|
|
return 1;
|
|
}
|
|
cutto(str, strlen(commands[i].name));
|
|
p = str;
|
|
while ((*p) && ((*p == ' ') || (*p == '\t')))
|
|
p++;
|
|
memmove(str, p, strlen(str) - (p - str) + 1);
|
|
if (state >= commands[i].state_needed) {
|
|
commands[i].function(str);
|
|
return 0;
|
|
} else {
|
|
switch (state) {
|
|
case STATE_CONNECTED: {
|
|
control_printf(SL_FAILURE, "503 USER expected.");
|
|
return 1;
|
|
}
|
|
case STATE_USER: {
|
|
control_printf(SL_FAILURE, "503 PASS expected.");
|
|
return 1;
|
|
}
|
|
case STATE_AUTHENTICATED: {
|
|
control_printf(SL_FAILURE, "503 RNFR before RNTO expected.");
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
control_printf(SL_FAILURE, "500 Unknown command: \"%s\"", str);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int get_buffer_size(int num_connections)
|
|
{
|
|
int buffer_size;
|
|
|
|
if (num_connections < 1)
|
|
num_connections = 1;
|
|
|
|
buffer_size = xfer_bufsize / num_connections;
|
|
if ( buffer_size < 2)
|
|
buffer_size = 2;
|
|
|
|
return buffer_size;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
This function forks and runs a script. On success it
|
|
returns TRUE, if an error occures, it returns FALSE.
|
|
*/
|
|
int run_script(char *script, char *path)
|
|
{
|
|
pid_t process_id;
|
|
char *command_args[] = { script, path, NULL } ;
|
|
/* sighandler_t save_quit, save_int, save_chld; */
|
|
sig_t save_quit, save_int, save_chld;
|
|
|
|
/* save original signal handler values */
|
|
save_quit = signal(SIGQUIT, SIG_IGN);
|
|
save_int = signal(SIGINT, SIG_IGN);
|
|
save_chld = signal(SIGCHLD, SIG_DFL);
|
|
|
|
process_id = fork();
|
|
/* check for failure */
|
|
if (process_id < 0)
|
|
{
|
|
signal(SIGQUIT, save_quit);
|
|
signal(SIGINT, save_int);
|
|
signal(SIGCHLD, save_chld);
|
|
return FALSE;
|
|
}
|
|
|
|
/* child process */
|
|
if (process_id == 0)
|
|
{
|
|
signal(SIGQUIT, SIG_DFL);
|
|
signal(SIGINT, SIG_DFL);
|
|
signal(SIGCHLD, SIG_DFL);
|
|
|
|
execv(script, command_args);
|
|
bftpd_log("Error trying to run script: %s\n", script);
|
|
exit(127);
|
|
}
|
|
|
|
/* parent process */
|
|
do
|
|
{
|
|
process_id = wait4(process_id, NULL, 0, NULL);
|
|
} while ( (process_id == -1) && (errno == EINTR) );
|
|
|
|
signal(SIGQUIT, save_quit);
|
|
signal(SIGINT, save_int);
|
|
signal(SIGCHLD, save_chld);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#if defined(TCSUPPORT_CT_NETWORKMANAGESERVICE) || defined(TCSUPPORT_FTP_USB)
|
|
inline struct passwd *getPasswd(const char *user){
|
|
struct passwd *pwd = NULL;
|
|
FILE *file = NULL;
|
|
|
|
file = fopen(FTP_USERDEF_PASSWD_CONF, "r");
|
|
if(file == NULL)
|
|
{
|
|
fclose(file);
|
|
return NULL;
|
|
}
|
|
while((pwd = fgetpwent(file)) != NULL)
|
|
{
|
|
if (!strcmp(user,pwd->pw_name))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
fclose(file);
|
|
return pwd;
|
|
}
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|