1
0
Files
2016-11-30 09:03:17 +08:00

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