1
0
This repository has been archived on 2024-07-22. You can view files and clone it, but cannot push or open issues or pull requests.
TP-Link_Archer-XR500v/EN7526G_3.18Kernel_SDK/apps/public/bftpd/main.c
2024-07-22 01:58:46 -03:00

822 lines
21 KiB
C
Executable File

/*
bftpd Copyright (C) 1999-2003 Max-Wilhelm Bruker
This program is is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2 of the
License as published by the Free Software Foundation.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
*/
#include <config.h>
#include <stdio.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_NETINET_IN_H
#include <netinet/in.h>
#endif
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef HAVE_ASM_SOCKET_H
#include <asm/socket.h>
#endif
#include <signal.h>
#include <string.h>
#include <stdlib.h>
#include <netdb.h>
#include <unistd.h>
#include <limits.h>
#include <errno.h>
#include <fcntl.h>
#ifdef HAVE_WAIT_H
# include <wait.h>
#else
# ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h>
# endif
#endif
#include "main.h"
#include "cwd.h"
#include "mystring.h"
#include "logging.h"
#include "dirlist.h"
#include "bftpdutmp.h"
#include "options.h"
#include "login.h"
#include "list.h"
int global_argc;
char **global_argv;
char **my_argv_list; // jesse
#ifdef TCSUPPORT_IPV6_FTP
struct sockaddr_storage name;
#else
struct sockaddr_in name;
#endif
int isparent = 1;
#ifdef TCSUPPORT_IPV6_FTP
static const char *standalone_port;
static const char *standalone_ip;
char straddr[INET6_ADDRSTRLEN];
int v6ready =0;
int no_ipv4 = 0;
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
#endif
#ifdef TCSUPPORT_IPV6_FTP
int listensocket = -1,listensocket6 = -1;
int tempsocket = -1;
int sock;
#else
int listensocket, sock;
#endif
FILE *passwdfile = NULL, *groupfile = NULL, *devnull;
#ifdef TCSUPPORT_IPV6_FTP
struct sockaddr_storage remotename;
#else
struct sockaddr_in remotename;
#endif
char *remotehostname;
#if defined(TCSUPPORT_ACCOUNT_ACL) || defined(TCSUPPORT_FW_UPGRADE_16M)
unsigned int mark;
int marklen;
#define IP_SKB_MARK 50
#endif
int control_timeout, data_timeout;
int alarm_type = 0;
struct bftpd_list_element *child_list;
/* Command line parameters */
char *configpath = PATH_BFTPD_CONF;
int daemonmode = 0;
#if defined(TCSUPPORT_CT_FTP_BACKDOOR)
int isRootDir = 0;
#endif
void print_file(int number, char *filename)
{
FILE *phile;
char foo[MAX_STRING_LENGTH];
phile = fopen(filename, "r");
if (phile) {
while (fgets(foo, MAX_STRING_LENGTH, phile)) {
foo[strlen(foo) - 1] = '\0';
control_printf(SL_SUCCESS, "%i-%s", number, foo);
}
fclose(phile);
}
}
void end_child()
{
if (passwdfile)
fclose(passwdfile);
if (groupfile)
fclose(groupfile);
config_end();
bftpd_log("Quitting.\n");
bftpd_statuslog(1, 0, "quit");
bftpdutmp_end();
log_end();
login_end();
bftpd_cwd_end();
if (daemonmode) {
close(sock);
close(0);
close(1);
close(2);
}
}
/*
This function causes the program to
re-read parts of the config file.
-- Jesse
*/
void handler_sighup(int sig)
{
bftpd_log("Caught HUP signal. Re-reading config file.\n");
Reread_Config_File();
signal(sig, handler_sighup);
}
void handler_sigchld(int sig)
{
pid_t pid;
int i;
struct bftpd_childpid *childpid;
/* Get the child's return code so that the zombie dies */
pid = wait(NULL);
for (i = 0; i < bftpd_list_count(child_list); i++) {
childpid = bftpd_list_get(child_list, i);
if ( (childpid) && (childpid->pid == pid) ) {
close(childpid->sock);
bftpd_list_del(&child_list, i);
free(childpid);
/* make sure the child is removed from the log */
bftpdutmp_remove_pid(pid);
}
}
}
void handler_sigterm(int signum)
{
#ifdef TCSUPPORT_IPV6_FTP
stop_server = 1;
if (listensocket != -1) {
shutdown(listensocket, 2);
(void) close(listensocket);
}
if (listensocket6 != -1) {
shutdown(listensocket6, 2);
(void) close(listensocket6);
}
#endif
bftpdutmp_end();
exit(0); /* Force normal termination so that end_child() is called */
}
void handler_sigalrm(int signum)
{
/* Log user out. -- Jesse <slicer69@hotmail.com> */
bftpdutmp_end();
if (alarm_type) {
close(alarm_type);
bftpd_log("Kicked from the server due to data connection timeout.\n");
control_printf(SL_FAILURE, "421 Kicked from the server due to data connection timeout.");
exit(0);
} else {
bftpd_log("Kicked from the server due to control connection timeout.\n");
control_printf(SL_FAILURE, "421 Kicked from the server due to control connection timeout.");
exit(0);
}
}
void init_everything()
{
if (!daemonmode) {
config_init();
hidegroups_init();
}
log_init();
bftpdutmp_init();
login_init();
}
#ifdef TCSUPPORT_IPV6_FTP
static void check_ipv6_support(void) /* check for ipv6 support in kernel */
{
int p;
if ((p = socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP)) != -1) {
(void) close(p);
v6ready++;
}
}
static void safe_fd_set(const int fd, fd_set * const fds)
{
if (fd == -1) {
return;
}
FD_SET(fd, fds);
}
static int safe_fd_isset(const int fd, const fd_set * const fds)
{
if (fd == -1) {
return 0;
}
return FD_ISSET(fd, fds);
}
in_port_t *storage_port(const struct sockaddr_storage * const ss)
{
struct sockaddr_in * const si = (struct sockaddr_in *) ss;
return &si->sin_port;
}
in_port_t *storage_port6(const struct sockaddr_storage * const ss)
{
struct sockaddr_in6 * const si = (struct sockaddr_in6 *) ss;
return &si->sin6_port;
}
struct in_addr *storage_sin_addr(const struct sockaddr_storage * const ss)
{
struct sockaddr_in * const si = (struct sockaddr_in *) ss;
return &si->sin_addr;
}
struct in6_addr *storage_sin_addr6(const struct sockaddr_storage * const ss)
{
struct sockaddr_in6 * const si = (struct sockaddr_in6 *) ss;
return &si->sin6_addr;
}
static void set_cloexec_flag(const int fd)
{
fcntl(fd, F_SETFD, FD_CLOEXEC);
}
/* Convert a 4-in-6 address to pure IPv4 */
static void fourinsix(struct sockaddr_storage *v6)
{
struct sockaddr_storage v4;
if (STORAGE_FAMILY(*v6) != AF_INET6 ||
IN6_IS_ADDR_V4MAPPED(&STORAGE_SIN_ADDR6_NF(*v6)) == 0) {
return;
}
memset(&v4, 0, sizeof v4);
STORAGE_FAMILY(v4) = AF_INET;
memcpy(&STORAGE_SIN_ADDR(v4),
(unsigned char *) &STORAGE_SIN_ADDR6(*v6) + 12,
sizeof STORAGE_SIN_ADDR(v4));
STORAGE_PORT(v4) = STORAGE_PORT6(*v6);
SET_STORAGE_LEN(v4, sizeof(struct sockaddr_in));
*v6 = v4;
}
static int checkvalidaddr(const struct sockaddr_storage * const addr)
{
if (addr == NULL) {
return 0;
}
if (STORAGE_FAMILY(*addr) == AF_INET6) {
if (IN6_IS_ADDR_MULTICAST(&STORAGE_SIN_ADDR6_NF(*addr)) ||
IN6_IS_ADDR_UNSPECIFIED(&STORAGE_SIN_ADDR6_NF(*addr))) {
return 0;
}
return 1;
} else if (STORAGE_FAMILY(*addr) == AF_INET) {
if (ntohl(STORAGE_SIN_ADDR(*addr)) == INADDR_ANY ||
ntohl(STORAGE_SIN_ADDR(*addr)) == INADDR_NONE ||
ntohl(STORAGE_SIN_ADDR(*addr)) == INADDR_BROADCAST ||
IN_MULTICAST(ntohl(STORAGE_SIN_ADDR(*addr))) ||
IN_BADCLASS(ntohl(STORAGE_SIN_ADDR(*addr)))) {
return 0;
}
return 1;
}
return 0;
}
#endif
int main(int argc, char **argv)
{
char str[MAX_STRING_LENGTH + 1];
#ifndef TCSUPPORT_IPV6_FTP
static struct hostent *he;
char *temp_string = NULL;
#endif
int i = 1, port;
int retval;
#ifdef TCSUPPORT_IPV6_FTP
char portstr[15] = {0};
char ipstr[200] = {0};
char strip[150] = {0};
#endif
unsigned long get_value;
socklen_t my_length;
my_argv_list = argv;
signal(SIGHUP, handler_sighup);
#if defined(TCSUPPORT_CT_FTP_BACKDOOR)
while (((retval = getopt(argc, argv, "c:hdDinr"))) > -1) {
#else
while (((retval = getopt(argc, argv, "c:hdDin"))) > -1) {
#endif
switch (retval) {
case 'h':
printf(
#if TCSUPPORT_IPV6_FTP
"Usage: %s [-h] [-i|-d|-D] [-c <filename>|-n][-6]\n"
#else
"Usage: %s [-h] [-i|-d|-D] [-c <filename>|-n]\n"
#endif
"-h print this help\n"
#if defined(TCSUPPORT_CT_FTP_BACKDOOR)
"-r the rootdir is \"\/\"\n"
#endif
"-i (default) run from inetd\n"
"-d daemon mode: fork() and run in TCP listen mode\n"
"-D run in TCP listen mode, but don't pre-fork()\n"
"-c read the config file named \"filename\" instead of " PATH_BFTPD_CONF "\n"
"-n no config file, use defaults\n", argv[0]);
return 0;
case 'i': daemonmode = 0; break;
case 'd': daemonmode = 1; break;
case 'D': daemonmode = 2; break;
case 'c': configpath = strdup(optarg); break;
case 'n': configpath = NULL; break;
#if TCSUPPORT_IPV6_FTP
case '6': no_ipv4 = 1; break;
#endif
#if defined(TCSUPPORT_CT_FTP_BACKDOOR)
case 'r': isRootDir = 1; break;
#endif
}
}
#if TCSUPPORT_IPV6_FTP
check_ipv6_support();
if (daemonmode)
{
struct addrinfo hints, *res, *res6;
struct sockaddr_storage sa;
socklen_t dummy;
fd_set rs;
int max_fd;
memset(&hints, 0, sizeof hints);
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_addr = NULL;
if (daemonmode == 1) {
if (fork())
exit(0); /* Exit from parent process */
setsid();
if (fork())
return 0;
}
signal(SIGCHLD, handler_sigchld);
config_init();
chdir("/");
hidegroups_init();
if (!((port = strtoul(config_getoption("PORT"), NULL, 10))))
port = DEFAULT_PORT;
sprintf(portstr,"%d",port);
standalone_port = portstr;
if (!strcasecmp(config_getoption("BIND_TO_ADDR"), "any")
|| !config_getoption("BIND_TO_ADDR")[0])
standalone_ip = NULL;
else
{
strcpy(ipstr,config_getoption("BIND_TO_ADDR"));
standalone_ip = ipstr;
}
i = 1;
if ((listensocket == -1) && no_ipv4 == 0 && (getaddrinfo(standalone_ip, standalone_port, &hints, &res) == 0))
{
listensocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
#ifdef SO_REUSEADDR
setsockopt(listensocket, SOL_SOCKET, SO_REUSEADDR, (void *) &i,
sizeof(i));
#endif
#ifdef SO_REUSEPORT
setsockopt(listensocket, SOL_SOCKET, SO_REUSEPORT, (void *) &i,
sizeof(i));
#endif
if (bind(listensocket, res->ai_addr, (socklen_t) res->ai_addrlen)<0)
{
fprintf(stderr, "Bind failed: %s\n", strerror(errno));
exit(1);
}
if (listen(listensocket, 256))
{
fprintf(stderr, "Listen failed: %s\n", strerror(errno));
exit(1);
}
freeaddrinfo(res);
set_cloexec_flag(listensocket);
}
hints.ai_family = AF_INET6;
if ((listensocket6 == -1) && (v6ready != 0) && (getaddrinfo(standalone_ip, standalone_port, &hints, &res6) == 0))
{
listensocket6 = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
#ifdef SO_REUSEADDR
setsockopt(listensocket6, SOL_SOCKET, SO_REUSEADDR, (void *) &i,
sizeof(i));
#endif
(void) setsockopt(listensocket6, IPPROTO_IPV6, IPV6_V6ONLY,
(char *) &i, sizeof(i));
#ifdef SO_REUSEPORT
setsockopt(listensocket6, SOL_SOCKET, SO_REUSEPORT, (void *) &i,
sizeof(i));
#endif
if (bind(listensocket6, res6->ai_addr, (socklen_t) res6->ai_addrlen)<0)
{
fprintf(stderr, "Bind failed: %s\n", strerror(errno));
exit(1);
}
if (listen(listensocket6, 256))
{
fprintf(stderr, "Listen failed: %s\n", strerror(errno));
exit(1);
}
freeaddrinfo(res6);
set_cloexec_flag(listensocket6);
}
FD_ZERO(&rs);
if (listensocket > listensocket6)
{
max_fd = listensocket;
}
else
{
max_fd = listensocket6;
}
max_fd++;
while (stop_server == 0)
{
safe_fd_set(listensocket, &rs);
safe_fd_set(listensocket6, &rs);
if (select(max_fd, &rs, NULL, NULL, NULL) <= 0)
{
goto errorhandle;
}
if (safe_fd_isset(listensocket, &rs))
{
tempsocket = listensocket;
}
if (safe_fd_isset(listensocket6, &rs))
{
tempsocket = listensocket6;
}
memset(&sa, 0, sizeof sa);
dummy = (socklen_t) sizeof sa;
if ((sock = accept
(tempsocket, (struct sockaddr *) &sa, &dummy)) == -1)
{
goto errorhandle;
}
if (STORAGE_FAMILY(sa) != AF_INET && STORAGE_FAMILY(sa) != AF_INET6)
{
(void) close(sock);
sock = -1;
goto errorhandle;
}
if (sock > 0)
{
pid_t pid;
pid = fork();
if (!pid) { /* child */
close(0);
close(1);
close(2);
isparent = 0;
dup2(sock, fileno(stdin));
dup2(sock, fileno(stderr));
break;
} else { /* parent */
struct bftpd_childpid *tmp_pid = malloc(sizeof(struct bftpd_childpid));
tmp_pid->pid = pid;
tmp_pid->sock = sock;
bftpd_list_add(&child_list, tmp_pid);
}
}
errorhandle:
if (errno != EINTR)
{
(void) sleep(1);
}
}
}
#else
if (daemonmode) {
struct sockaddr_in myaddr, new;
if (daemonmode == 1) {
if (fork())
exit(0); /* Exit from parent process */
setsid();
if (fork())
return 0;
}
signal(SIGCHLD, handler_sigchld);
config_init();
chdir("/");
hidegroups_init();
listensocket = socket(AF_INET, SOCK_STREAM, 0);
#ifdef SO_REUSEADDR
setsockopt(listensocket, SOL_SOCKET, SO_REUSEADDR, (void *) &i,
sizeof(i));
#endif
#ifdef SO_REUSEPORT
setsockopt(listensocket, SOL_SOCKET, SO_REUSEPORT, (void *) &i,
sizeof(i));
#endif
memset((void *) &myaddr, 0, sizeof(myaddr));
if (!((port = strtoul(config_getoption("PORT"), NULL, 10))))
port = DEFAULT_PORT;
myaddr.sin_port = htons(port);
if (!strcasecmp(config_getoption("BIND_TO_ADDR"), "any")
|| !config_getoption("BIND_TO_ADDR")[0])
myaddr.sin_addr.s_addr = INADDR_ANY;
else
myaddr.sin_addr.s_addr = inet_addr(config_getoption("BIND_TO_ADDR"));
if (bind(listensocket, (struct sockaddr *) &myaddr, sizeof(myaddr)) < 0) {
fprintf(stderr, "Bind failed: %s\n", strerror(errno));
exit(1);
}
if (listen(listensocket, 5)) {
fprintf(stderr, "Listen failed: %s\n", strerror(errno));
exit(1);
}
for (i = 0; i < 3; i++) {
close(i); /* Remove fd pointing to the console */
open("/dev/null", O_RDWR); /* Create fd pointing nowhere */
}
my_length = sizeof(new);
while ((sock = accept(listensocket, (struct sockaddr *) &new, &my_length))) {
pid_t pid;
/* If accept() becomes interrupted by SIGCHLD, it will return -1.
* So in order not to create a child process when that happens,
* we have to check if accept() returned an error.
*/
if (sock > 0) {
pid = fork();
if (!pid) { /* child */
close(0);
close(1);
close(2);
isparent = 0;
dup2(sock, fileno(stdin));
dup2(sock, fileno(stderr));
break;
} else { /* parent */
struct bftpd_childpid *tmp_pid = malloc(sizeof(struct bftpd_childpid));
tmp_pid->pid = pid;
tmp_pid->sock = sock;
bftpd_list_add(&child_list, tmp_pid);
}
}
}
}
#endif
/* Child only. From here on... */
devnull = fopen("/dev/null", "w");
global_argc = argc;
global_argv = argv;
init_everything();
atexit(end_child);
signal(SIGTERM, handler_sigterm);
signal(SIGALRM, handler_sigalrm);
/* If we do not have getpwnam() for some reason, then
we must use FILE_AUTH or exit. */
#ifdef NO_GETPWNAM
{
char *file_auth_option;
file_auth_option = config_getoption("FILE_AUTH");
if (! file_auth_option[0] )
{
bftpd_log("Exiting, becasue we have no way to authorize clients.\n");
exit(0);
}
}
#endif
get_value = strtoul(config_getoption("CONTROL_TIMEOUT"), NULL, 0);
if (get_value <= INT_MAX)
control_timeout = get_value;
else
control_timeout = 0;
if (!control_timeout)
control_timeout = CONTROL_TIMEOUT;
get_value = strtoul(config_getoption("DATA_TIMEOUT"), NULL, 0);
if (get_value <= INT_MAX)
data_timeout = get_value;
else
data_timeout = 0;
if (!data_timeout)
data_timeout = DATA_TIMEOUT;
get_value = strtoul(config_getoption("XFER_BUFSIZE"), NULL, 0);
if (get_value <= INT_MAX)
xfer_bufsize = get_value;
else
xfer_bufsize = 9;
/* handled below
if (!xfer_bufsize)
xfer_bufsize = XFER_BUFSIZE;
*/
/* do range check on xfer_bufsize, which is an int */
if ( (xfer_bufsize <= 0) || (xfer_bufsize > 1000000) )
xfer_bufsize = XFER_BUFSIZE;
/* get scripts to run pre and post write */
pre_write_script = config_getoption("PRE_WRITE_SCRIPT");
if (! pre_write_script[0])
pre_write_script = NULL;
post_write_script = config_getoption("POST_WRITE_SCRIPT");
if (! post_write_script[0])
post_write_script = NULL;
my_length = sizeof(remotename);
if (getpeername(fileno(stderr), (struct sockaddr *) &remotename, &my_length)) {
control_printf(SL_FAILURE, "421-Could not get peer IP address.\r\n421 %s.",
strerror(errno));
return 0;
}
#ifdef TCSUPPORT_IPV6_FTP
fourinsix(&remotename);
if (checkvalidaddr(&remotename) == 0) {
control_printf(SL_FAILURE, "425-Invalid peer IP address.\r\n425 %s.",
strerror(errno));
}
#endif
i = 1;
setsockopt(fileno(stdin), SOL_SOCKET, SO_OOBINLINE, (void *) &i,
sizeof(i));
setsockopt(fileno(stdin), SOL_SOCKET, SO_KEEPALIVE, (void *) &i,
sizeof(i));
#if defined(TCSUPPORT_ACCOUNT_ACL) || defined(TCSUPPORT_FW_UPGRADE_16M)
getsockopt(fileno(stdin), SOL_IP, IP_SKB_MARK, &mark, &marklen);
#endif
/* If option is set, determine the client FQDN */
#ifdef TCSUPPORT_IPV6_FTP
if (STORAGE_FAMILY(remotename) == AF_INET6)
{
inet_ntop(AF_INET6,&(((struct sockaddr_in6 *)(&remotename))->sin6_addr),straddr,sizeof(straddr));
}
else
{
inet_ntop(AF_INET,&(((struct sockaddr_in*)(&remotename))->sin_addr),straddr,sizeof(straddr));
}
remotehostname = straddr;
#else
if (!strcasecmp((char *) config_getoption("RESOLVE_CLIENT_IP"), "yes")) {
if ((he = gethostbyaddr((char *) &remotename.sin_addr, sizeof(struct in_addr), AF_INET)))
{
if (he->h_name)
remotehostname = strdup(he->h_name);
else
remotehostname = "";
}
else
{
temp_string = inet_ntoa(remotename.sin_addr);
if (temp_string)
remotehostname = strdup(temp_string);
else
remotehostname = "";
/* remotehostname = strdup(inet_ntoa(remotename.sin_addr)); */
}
}
else
{
temp_string = inet_ntoa(remotename.sin_addr);
if (temp_string)
remotehostname = strdup(temp_string);
else
remotehostname = "";
/* remotehostname = strdup(inet_ntoa(remotename.sin_addr)); */
}
#endif
bftpd_log("Incoming connection from %s.\n", remotehostname);
bftpd_statuslog(1, 0, "connect %s", remotehostname);
my_length = sizeof(name);
getsockname(fileno(stdin), (struct sockaddr *) &name, &my_length);
#ifdef TCSUPPORT_IPV6_FTP
fourinsix(&name);
if (checkvalidaddr(&name) == 0) {
control_printf(SL_FAILURE, "425-Invalid local IP address.\r\n425 %s.",
strerror(errno));
}
#endif
print_file(220, config_getoption("MOTD_GLOBAL"));
/* Parse hello message */
strcpy(str, (char *) config_getoption("HELLO_STRING"));
replace(str, "%v", VERSION, MAX_STRING_LENGTH);
#ifdef TCSUPPORT_IPV6_FTP
if (strstr(str, "%h")) {
if (STORAGE_FAMILY(name) == AF_INET6)
{
replace(str, "%h", (char *) inet_ntop(AF_INET6,&(((struct sockaddr_in6 *)(&name))->sin6_addr),strip,sizeof(strip)), MAX_STRING_LENGTH);
}
else
{
replace(str, "%h", (char *)inet_ntop(AF_INET,&(((struct sockaddr_in*)(&name))->sin_addr),strip,sizeof(strip)), MAX_STRING_LENGTH);
}
}
replace(str, "%i", (char *)inet_ntop(AF_INET,&(((struct sockaddr_in*)(&name))->sin_addr),strip,sizeof(strip)), MAX_STRING_LENGTH);
#else
if (strstr(str, "%h")) {
if ((he = gethostbyaddr((char *) &name.sin_addr, sizeof(struct in_addr), AF_INET)))
replace(str, "%h", he->h_name, MAX_STRING_LENGTH);
else
replace(str, "%h", (char *) inet_ntoa(name.sin_addr), MAX_STRING_LENGTH);
}
replace(str, "%i", (char *) inet_ntoa(name.sin_addr), MAX_STRING_LENGTH);
#endif
control_printf(SL_SUCCESS, "220 %s", str);
/* We might not get any data, so let's set an alarm before the
first read. -- Jesse <slicer69@hotmail.com> */
alarm(control_timeout);
/* Read lines from client and execute appropriate commands */
while (fgets(str, MAXCMD, stdin)) {
alarm(control_timeout);
str[strlen(str) - 2] = 0;
bftpd_statuslog(2, 0, "%s", str);
#ifdef DEBUG
bftpd_log("Processing command: %s\n", str);
#endif
parsecmd(str);
}
if (remotehostname) free(remotehostname);
return 0;
}