mirror of
https://github.com/InfrastructureServices/vsftpd.git
synced 2025-04-19 01:24:02 +03:00
Updated to v1.1.2
This commit is contained in:
parent
14c0cc79c7
commit
0c431cac6a
3
AUDIT
3
AUDIT
@ -11,6 +11,7 @@ dirchange.c 3
|
||||
filestr.c 3
|
||||
ftpcmdio.c 3
|
||||
ftpdataio.c 2
|
||||
hash.c 1
|
||||
logging.c 3
|
||||
ls.c 2
|
||||
main.c 3
|
||||
@ -25,7 +26,7 @@ privparent.c 3
|
||||
privsock.c 3
|
||||
secbuf.c 3
|
||||
secutil.c 3
|
||||
standalone.c 2
|
||||
standalone.c 1
|
||||
str.c 2
|
||||
strlist.c 2
|
||||
sysdeputil.c 2
|
||||
|
10
Changelog
10
Changelog
@ -613,3 +613,13 @@ broken log parsers.
|
||||
At this point: 1.1.1 package released
|
||||
-------------------------------------
|
||||
|
||||
- Add per-IP connection limits in standalone mode.
|
||||
- Add logging of refused connect due to global or IP connection limits.
|
||||
- (Many thanks for testing and suggestions from Rob van Nieuwkerk
|
||||
<robn@verdi.et.tudelft.nl> and Adrian Reber <adrian@lisas.de>.
|
||||
- Make connection limit exceeded messages nonblocking.
|
||||
- Don't exit the listener if fork fails.
|
||||
|
||||
At this point: 1.1.2 package released
|
||||
-------------------------------------
|
||||
|
||||
|
2
INSTALL
2
INSTALL
@ -9,7 +9,7 @@ Step 1) Build vsftpd.
|
||||
Switch to the directory created when you unpacked the vsftpd .tar.gz file.
|
||||
e.g.:
|
||||
|
||||
cd vsftpd-1.1.1
|
||||
cd vsftpd-1.1.2
|
||||
|
||||
Just type "make" (and mail me to fix it if it doesn't build ;-).
|
||||
This should produce you a vsftpd binary. You can test for this, e.g.:
|
||||
|
2
Makefile
2
Makefile
@ -12,7 +12,7 @@ OBJS = main.o utility.o prelogin.o ftpcmdio.o postlogin.o privsock.o \
|
||||
tunables.o ftpdataio.o secbuf.o ls.o \
|
||||
postprivparent.o logging.o str.o netstr.o sysstr.o strlist.o \
|
||||
banner.o filestr.o parseconf.o secutil.o \
|
||||
ascii.o oneprocess.o twoprocess.o privops.o standalone.o \
|
||||
ascii.o oneprocess.o twoprocess.o privops.o standalone.o hash.o \
|
||||
sysutil.o sysdeputil.o
|
||||
|
||||
.c.o:
|
||||
|
2
README
2
README
@ -1,4 +1,4 @@
|
||||
This is vsftpd, version 1.1.1
|
||||
This is vsftpd, version 1.1.2
|
||||
Author: Chris Evans
|
||||
Contact: chris@scary.beasts.org
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
Summary: vsftpd - Very Secure Ftp Daemon
|
||||
Name: vsftpd
|
||||
Version: 1.1.1
|
||||
Version: 1.1.2
|
||||
Release: rh6_1
|
||||
Copyright: GPL
|
||||
Group: System Environment/Daemons
|
||||
|
@ -1,6 +1,6 @@
|
||||
Summary: vsftpd - Very Secure Ftp Daemon
|
||||
Name: vsftpd
|
||||
Version: 1.1.1
|
||||
Version: 1.1.2
|
||||
Release: rh7_2
|
||||
Copyright: GPL
|
||||
Group: System Environment/Daemons
|
||||
|
2
TODO
2
TODO
@ -10,7 +10,7 @@ NOT SO CRITICAL
|
||||
- separate upload/download max rates
|
||||
- select() is assuming Linux behaviour (not threatening stability)
|
||||
- IPv6 support
|
||||
- enhance standalone support (IP filtering, per-IP limits)
|
||||
- enhance standalone support (IP filtering? - tcp_wrappers?)
|
||||
|
||||
ON THE BACK BURNER
|
||||
==================
|
||||
|
@ -32,6 +32,7 @@
|
||||
#define FTP_IDLE_TIMEOUT 421
|
||||
#define FTP_DATA_TIMEOUT 421
|
||||
#define FTP_TOO_MANY_USERS 421
|
||||
#define FTP_IP_LIMIT 421
|
||||
#define FTP_BADSENDCONN 425
|
||||
#define FTP_BADSENDNET 426
|
||||
#define FTP_BADSENDFILE 451
|
||||
|
147
hash.c
Normal file
147
hash.c
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* Part of Very Secure FTPd
|
||||
* Licence: GPL
|
||||
* Author: Chris Evans
|
||||
* hash.c
|
||||
*
|
||||
* Routines to handle simple hash table lookups and modifications.
|
||||
*/
|
||||
|
||||
#include "hash.h"
|
||||
#include "sysutil.h"
|
||||
#include "utility.h"
|
||||
|
||||
struct hash_node
|
||||
{
|
||||
void* p_key;
|
||||
void* p_value;
|
||||
struct hash_node* p_prev;
|
||||
struct hash_node* p_next;
|
||||
};
|
||||
|
||||
struct hash
|
||||
{
|
||||
unsigned int buckets;
|
||||
unsigned int key_size;
|
||||
unsigned int value_size;
|
||||
hashfunc_t hash_func;
|
||||
struct hash_node** p_nodes;
|
||||
};
|
||||
|
||||
/* Internal functions */
|
||||
struct hash_node** hash_get_bucket(struct hash* p_hash, void* p_key);
|
||||
struct hash_node* hash_get_node_by_key(struct hash* p_hash, void* p_key);
|
||||
|
||||
struct hash*
|
||||
hash_alloc(unsigned int buckets, unsigned int key_size,
|
||||
unsigned int value_size, hashfunc_t hash_func)
|
||||
{
|
||||
unsigned int size;
|
||||
struct hash* p_hash = vsf_sysutil_malloc(sizeof(*p_hash));
|
||||
p_hash->buckets = buckets;
|
||||
p_hash->key_size = key_size;
|
||||
p_hash->value_size = value_size;
|
||||
p_hash->hash_func = hash_func;
|
||||
size = sizeof(struct hash_node*) * buckets;
|
||||
p_hash->p_nodes = vsf_sysutil_malloc(size);
|
||||
vsf_sysutil_memclr(p_hash->p_nodes, size);
|
||||
return p_hash;
|
||||
}
|
||||
|
||||
void*
|
||||
hash_lookup_entry(struct hash* p_hash, void* p_key)
|
||||
{
|
||||
struct hash_node* p_node = hash_get_node_by_key(p_hash, p_key);
|
||||
if (!p_node)
|
||||
{
|
||||
return p_node;
|
||||
}
|
||||
return p_node->p_value;
|
||||
}
|
||||
|
||||
void
|
||||
hash_add_entry(struct hash* p_hash, void* p_key, void* p_value)
|
||||
{
|
||||
struct hash_node** p_bucket;
|
||||
struct hash_node* p_new_node;
|
||||
if (hash_lookup_entry(p_hash, p_key))
|
||||
{
|
||||
bug("duplicate hash key");
|
||||
}
|
||||
p_bucket = hash_get_bucket(p_hash, p_key);
|
||||
p_new_node = vsf_sysutil_malloc(sizeof(*p_new_node));
|
||||
p_new_node->p_prev = 0;
|
||||
p_new_node->p_next = 0;
|
||||
p_new_node->p_key = vsf_sysutil_malloc(p_hash->key_size);
|
||||
vsf_sysutil_memcpy(p_new_node->p_key, p_key, p_hash->key_size);
|
||||
p_new_node->p_value = vsf_sysutil_malloc(p_hash->value_size);
|
||||
vsf_sysutil_memcpy(p_new_node->p_value, p_value, p_hash->value_size);
|
||||
|
||||
if (!*p_bucket)
|
||||
{
|
||||
*p_bucket = p_new_node;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_new_node->p_next = *p_bucket;
|
||||
(*p_bucket)->p_prev = p_new_node;
|
||||
*p_bucket = p_new_node;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
hash_free_entry(struct hash* p_hash, void* p_key)
|
||||
{
|
||||
struct hash_node* p_node = hash_get_node_by_key(p_hash, p_key);
|
||||
if (!p_node)
|
||||
{
|
||||
bug("hash node not found");
|
||||
}
|
||||
vsf_sysutil_free(p_node->p_key);
|
||||
vsf_sysutil_free(p_node->p_value);
|
||||
|
||||
if (p_node->p_prev)
|
||||
{
|
||||
p_node->p_prev->p_next = p_node->p_next;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct hash_node** p_bucket = hash_get_bucket(p_hash, p_key);
|
||||
*p_bucket = p_node->p_next;
|
||||
}
|
||||
if (p_node->p_next)
|
||||
{
|
||||
p_node->p_next->p_prev = p_node->p_prev;
|
||||
}
|
||||
|
||||
vsf_sysutil_free(p_node);
|
||||
}
|
||||
|
||||
struct hash_node**
|
||||
hash_get_bucket(struct hash* p_hash, void* p_key)
|
||||
{
|
||||
unsigned int bucket = (*p_hash->hash_func)(p_hash->buckets, p_key);
|
||||
if (bucket >= p_hash->buckets)
|
||||
{
|
||||
bug("bad bucket lookup");
|
||||
}
|
||||
return &(p_hash->p_nodes[bucket]);
|
||||
}
|
||||
|
||||
struct hash_node*
|
||||
hash_get_node_by_key(struct hash* p_hash, void* p_key)
|
||||
{
|
||||
struct hash_node** p_bucket = hash_get_bucket(p_hash, p_key);
|
||||
struct hash_node* p_node = *p_bucket;
|
||||
if (!p_node)
|
||||
{
|
||||
return p_node;
|
||||
}
|
||||
while (p_node != 0 &&
|
||||
vsf_sysutil_memcmp(p_key, p_node->p_key, p_hash->key_size) != 0)
|
||||
{
|
||||
p_node = p_node->p_next;
|
||||
}
|
||||
return p_node;
|
||||
}
|
||||
|
15
hash.h
Normal file
15
hash.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef VSFTP_HASH_H
|
||||
#define VSFTP_HASH_H
|
||||
|
||||
struct hash;
|
||||
|
||||
typedef unsigned int (*hashfunc_t)(unsigned int, void*);
|
||||
|
||||
struct hash* hash_alloc(unsigned int buckets, unsigned int key_size,
|
||||
unsigned int value_size, hashfunc_t hash_func);
|
||||
void* hash_lookup_entry(struct hash* p_hash, void* p_key);
|
||||
void hash_add_entry(struct hash* p_hash, void* p_key, void* p_value);
|
||||
void hash_free_entry(struct hash* p_hash, void* p_key);
|
||||
|
||||
#endif /* VSFTP_HASH_H */
|
||||
|
@ -204,7 +204,8 @@ vsf_log_do_log_vsftpd_format(struct vsf_session* p_sess, struct mystr* p_str,
|
||||
str_append_text(p_str, "] ");
|
||||
}
|
||||
/* And the action */
|
||||
if (what != kVSFLogEntryFTPInput && what != kVSFLogEntryFTPOutput)
|
||||
if (what != kVSFLogEntryFTPInput && what != kVSFLogEntryFTPOutput &&
|
||||
what != kVSFLogEntryConnection)
|
||||
{
|
||||
if (succeeded)
|
||||
{
|
||||
@ -235,6 +236,9 @@ vsf_log_do_log_vsftpd_format(struct vsf_session* p_sess, struct mystr* p_str,
|
||||
case kVSFLogEntryFTPOutput:
|
||||
str_append_text(p_str, "FTP response");
|
||||
break;
|
||||
case kVSFLogEntryConnection:
|
||||
str_append_text(p_str, "CONNECT");
|
||||
break;
|
||||
default:
|
||||
bug("bad entry_type in vsf_log_do_log");
|
||||
break;
|
||||
|
@ -13,7 +13,8 @@ enum EVSFLogEntryType
|
||||
kVSFLogEntryMkdir,
|
||||
kVSFLogEntryLogin,
|
||||
kVSFLogEntryFTPInput,
|
||||
kVSFLogEntryFTPOutput
|
||||
kVSFLogEntryFTPOutput,
|
||||
kVSFLogEntryConnection
|
||||
};
|
||||
|
||||
/* vsf_log_init()
|
||||
|
6
main.c
6
main.c
@ -54,7 +54,7 @@ main(int argc, const char* argv[])
|
||||
/* Parent <-> child comms */
|
||||
0, -1, -1,
|
||||
/* Number of clients */
|
||||
-1
|
||||
0, 0
|
||||
};
|
||||
int config_specified = 0;
|
||||
const char* p_config_name = VSFTP_DEFAULT_CONFIG;
|
||||
@ -103,7 +103,9 @@ main(int argc, const char* argv[])
|
||||
if (tunable_listen)
|
||||
{
|
||||
/* Standalone mode */
|
||||
the_session.num_clients = vsf_standalone_main();
|
||||
struct vsf_client_launch ret = vsf_standalone_main();
|
||||
the_session.num_clients = ret.num_children;
|
||||
the_session.num_this_ip = ret.num_this_ip;
|
||||
}
|
||||
/* Sanity checks - exit with a graceful error message if our STDIN is not
|
||||
* a socket. Also check various config options don't collide.
|
||||
|
@ -94,6 +94,7 @@ parseconf_uint_array[] =
|
||||
{ "listen_port", &tunable_listen_port },
|
||||
{ "max_clients", &tunable_max_clients },
|
||||
{ "file_open_mode", &tunable_file_open_mode },
|
||||
{ "max_per_ip", &tunable_max_per_ip },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
|
20
prelogin.c
20
prelogin.c
@ -19,6 +19,7 @@
|
||||
#include "sysutil.h"
|
||||
#include "session.h"
|
||||
#include "banner.h"
|
||||
#include "logging.h"
|
||||
|
||||
/* Functions used */
|
||||
static void emit_greeting(struct vsf_session* p_sess);
|
||||
@ -44,14 +45,27 @@ init_connection(struct vsf_session* p_sess)
|
||||
static void
|
||||
emit_greeting(struct vsf_session* p_sess)
|
||||
{
|
||||
/* Check for client limit (standalone mode only) */
|
||||
struct mystr str_log_line = INIT_MYSTR;
|
||||
/* Check for client limits (standalone mode only) */
|
||||
if (tunable_max_clients > 0 &&
|
||||
p_sess->num_clients > (int)tunable_max_clients)
|
||||
p_sess->num_clients > tunable_max_clients)
|
||||
{
|
||||
vsf_cmdio_write(p_sess, FTP_TOO_MANY_USERS,
|
||||
str_alloc_text(&str_log_line, "Connection refused: too many sessions.");
|
||||
vsf_log_line(p_sess, kVSFLogEntryConnection, &str_log_line);
|
||||
vsf_cmdio_write_noblock(p_sess, FTP_TOO_MANY_USERS,
|
||||
"There are too many connected users, please try later.");
|
||||
vsf_sysutil_exit(0);
|
||||
}
|
||||
if (tunable_max_per_ip > 0 &&
|
||||
p_sess->num_this_ip > tunable_max_per_ip)
|
||||
{
|
||||
str_alloc_text(&str_log_line,
|
||||
"Connection refused: too many sessions for this address.");
|
||||
vsf_log_line(p_sess, kVSFLogEntryConnection, &str_log_line);
|
||||
vsf_cmdio_write_noblock(p_sess, FTP_IP_LIMIT,
|
||||
"There are too many connections from your internet address.");
|
||||
vsf_sysutil_exit(0);
|
||||
}
|
||||
if (!str_isempty(&p_sess->banner_str))
|
||||
{
|
||||
vsf_banner_write(p_sess, &p_sess->banner_str, FTP_GREET);
|
||||
|
@ -72,7 +72,8 @@ struct vsf_session
|
||||
int child_fd;
|
||||
|
||||
/* Other details */
|
||||
int num_clients;
|
||||
unsigned int num_clients;
|
||||
unsigned int num_this_ip;
|
||||
};
|
||||
|
||||
#endif /* VSF_SESSION_H */
|
||||
|
137
standalone.c
137
standalone.c
@ -15,28 +15,40 @@
|
||||
#include "sysdeputil.h"
|
||||
#include "utility.h"
|
||||
#include "defs.h"
|
||||
#include "hash.h"
|
||||
|
||||
static int s_reload_needed;
|
||||
static int s_children;
|
||||
static unsigned int s_children;
|
||||
static struct hash* s_p_ip_count_hash;
|
||||
static struct hash* s_p_pid_ip_hash;
|
||||
|
||||
static void handle_sigchld(int duff);
|
||||
static void handle_sigchld(void* p_private);
|
||||
static void handle_sighup(int duff);
|
||||
static void do_reload(void);
|
||||
static void prepare_child(int sockfd);
|
||||
static unsigned int handle_ip_count(
|
||||
struct vsf_sysutil_ipv4addr* p_accept_addr);
|
||||
static void drop_ip_count(struct vsf_sysutil_ipv4addr* p_ip);
|
||||
|
||||
int
|
||||
static unsigned int hash_ip(unsigned int buckets, void* p_key);
|
||||
static unsigned int hash_pid(unsigned int buckets, void* p_key);
|
||||
|
||||
struct vsf_client_launch
|
||||
vsf_standalone_main(void)
|
||||
{
|
||||
struct vsf_sysutil_sockaddr* p_sockaddr = 0;
|
||||
struct vsf_sysutil_ipv4addr listen_ipaddr;
|
||||
int listen_sock = vsf_sysutil_get_ipv4_sock();
|
||||
int retval;
|
||||
|
||||
s_p_ip_count_hash = hash_alloc(256, sizeof(struct vsf_sysutil_ipv4addr),
|
||||
sizeof(unsigned int), hash_ip);
|
||||
s_p_pid_ip_hash = hash_alloc(256, sizeof(int),
|
||||
sizeof(struct vsf_sysutil_ipv4addr), hash_pid);
|
||||
if (tunable_setproctitle_enable)
|
||||
{
|
||||
vsf_sysutil_setproctitle("LISTENER");
|
||||
}
|
||||
vsf_sysutil_install_async_sighandler(kVSFSysUtilSigCHLD, handle_sigchld);
|
||||
vsf_sysutil_install_sighandler(kVSFSysUtilSigCHLD, handle_sigchld, 0);
|
||||
vsf_sysutil_install_async_sighandler(kVSFSysUtilSigHUP, handle_sighup);
|
||||
|
||||
vsf_sysutil_activate_reuseaddr(listen_sock);
|
||||
@ -61,8 +73,15 @@ vsf_standalone_main(void)
|
||||
|
||||
while (1)
|
||||
{
|
||||
struct vsf_client_launch child_info;
|
||||
static struct vsf_sysutil_sockaddr* p_accept_addr;
|
||||
int new_child;
|
||||
int new_client_sock = vsf_sysutil_accept_timeout(listen_sock, 0, 0);
|
||||
struct vsf_sysutil_ipv4addr ip_addr;
|
||||
/* NOTE - wake up every 10 seconds to make sure we notice child exit
|
||||
* in a timely manner (the sync signal framework race)
|
||||
*/
|
||||
int new_client_sock = vsf_sysutil_accept_timeout(
|
||||
listen_sock, &p_accept_addr, 10);
|
||||
if (s_reload_needed)
|
||||
{
|
||||
s_reload_needed = 0;
|
||||
@ -70,18 +89,27 @@ vsf_standalone_main(void)
|
||||
}
|
||||
if (vsf_sysutil_retval_is_error(new_client_sock))
|
||||
{
|
||||
if (vsf_sysutil_get_error() == kVSFSysUtilErrINTR)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
die("accept");
|
||||
continue;
|
||||
}
|
||||
ip_addr = vsf_sysutil_sockaddr_get_ipaddr(p_accept_addr);
|
||||
++s_children;
|
||||
new_child = vsf_sysutil_fork();
|
||||
if (new_child)
|
||||
child_info.num_children = s_children;
|
||||
child_info.num_this_ip = handle_ip_count(&ip_addr);
|
||||
new_child = vsf_sysutil_fork_failok();
|
||||
if (new_child != 0)
|
||||
{
|
||||
/* Parent context */
|
||||
vsf_sysutil_close(new_client_sock);
|
||||
if (new_child > 0)
|
||||
{
|
||||
hash_add_entry(s_p_pid_ip_hash, (void*)&new_child, (void*)&ip_addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* fork() failed, clear up! */
|
||||
--s_children;
|
||||
drop_ip_count(&ip_addr);
|
||||
}
|
||||
/* Fall through to while() loop and accept() again */
|
||||
}
|
||||
else
|
||||
@ -92,7 +120,7 @@ vsf_standalone_main(void)
|
||||
/* By returning here we "launch" the child process with the same
|
||||
* contract as xinetd would provide.
|
||||
*/
|
||||
return s_children;
|
||||
return child_info;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -109,21 +137,48 @@ prepare_child(int new_client_sock)
|
||||
vsf_sysutil_close(new_client_sock);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
handle_sigchld(int duff)
|
||||
drop_ip_count(struct vsf_sysutil_ipv4addr* p_ip)
|
||||
{
|
||||
/* WARNING - async handler. Must not call anything which might have
|
||||
* re-entrancy issues
|
||||
*/
|
||||
int reap_one = 1;
|
||||
(void) duff;
|
||||
unsigned int count;
|
||||
unsigned int* p_count =
|
||||
(unsigned int*)hash_lookup_entry(s_p_ip_count_hash, (void*)p_ip);
|
||||
if (!p_count)
|
||||
{
|
||||
bug("IP address missing from hash");
|
||||
}
|
||||
count = *p_count;
|
||||
if (!count)
|
||||
{
|
||||
bug("zero count for IP address");
|
||||
}
|
||||
count--;
|
||||
*p_count = count;
|
||||
if (!count)
|
||||
{
|
||||
hash_free_entry(s_p_ip_count_hash, (void*)p_ip);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
handle_sigchld(void* p_private)
|
||||
{
|
||||
unsigned int reap_one = 1;
|
||||
(void) p_private;
|
||||
while (reap_one)
|
||||
{
|
||||
reap_one = vsf_sysutil_wait_reap_one();
|
||||
reap_one = (unsigned int)vsf_sysutil_wait_reap_one();
|
||||
if (reap_one)
|
||||
{
|
||||
struct vsf_sysutil_ipv4addr* p_ip;
|
||||
/* Account total number of instances */
|
||||
--s_children;
|
||||
/* Account per-IP limit */
|
||||
p_ip = (struct vsf_sysutil_ipv4addr*)
|
||||
hash_lookup_entry(s_p_pid_ip_hash, (void*)&reap_one);
|
||||
drop_ip_count(p_ip);
|
||||
hash_free_entry(s_p_pid_ip_hash, (void*)&reap_one);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -144,3 +199,41 @@ do_reload(void)
|
||||
vsf_parseconf_load_file(0);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
hash_ip(unsigned int buckets, void* p_key)
|
||||
{
|
||||
struct vsf_sysutil_ipv4addr* p_addr = (struct vsf_sysutil_ipv4addr*)p_key;
|
||||
unsigned int val = p_addr->data[0] << 24;
|
||||
val |= p_addr->data[1] << 16;
|
||||
val |= p_addr->data[2] << 8;
|
||||
val |= p_addr->data[3];
|
||||
return val % buckets;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
hash_pid(unsigned int buckets, void* p_key)
|
||||
{
|
||||
unsigned int* p_pid = (unsigned int*)p_key;
|
||||
return (*p_pid) % buckets;
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
handle_ip_count(struct vsf_sysutil_ipv4addr* p_accept_addr)
|
||||
{
|
||||
unsigned int* p_count =
|
||||
(unsigned int*)hash_lookup_entry(s_p_ip_count_hash, (void*)p_accept_addr);
|
||||
unsigned int count;
|
||||
if (!p_count)
|
||||
{
|
||||
count = 1;
|
||||
hash_add_entry(s_p_ip_count_hash, (void*)p_accept_addr, (void*)&count);
|
||||
}
|
||||
else
|
||||
{
|
||||
count = *p_count;
|
||||
count++;
|
||||
*p_count = count;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
|
11
standalone.h
11
standalone.h
@ -1,6 +1,12 @@
|
||||
#ifndef VSF_STANDALONE_H
|
||||
#define VSF_STANDALONE_H
|
||||
|
||||
struct vsf_client_launch
|
||||
{
|
||||
unsigned int num_children;
|
||||
unsigned int num_this_ip;
|
||||
};
|
||||
|
||||
/* vsf_standalone_main()
|
||||
* PURPOSE
|
||||
* This function starts listening on the network for incoming FTP connections.
|
||||
@ -8,9 +14,10 @@
|
||||
* descriptor 0, 1 and 2 set to the network socket of the new client.
|
||||
*
|
||||
* RETURNS
|
||||
* Returns the current number of clients.
|
||||
* Returns a structure representing the current number of clients, and
|
||||
* instances for this IP addresss.
|
||||
*/
|
||||
int vsf_standalone_main(void);
|
||||
struct vsf_client_launch vsf_standalone_main(void);
|
||||
|
||||
#endif /* VSF_STANDALONE_H */
|
||||
|
||||
|
18
sysutil.c
18
sysutil.c
@ -440,12 +440,19 @@ vsf_sysutil_getpid(void)
|
||||
int
|
||||
vsf_sysutil_fork(void)
|
||||
{
|
||||
int retval = fork();
|
||||
int retval = vsf_sysutil_fork_failok();
|
||||
if (retval < 0)
|
||||
{
|
||||
die("fork");
|
||||
}
|
||||
else if (retval == 0)
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
vsf_sysutil_fork_failok(void)
|
||||
{
|
||||
int retval = fork();
|
||||
if (retval == 0)
|
||||
{
|
||||
s_current_pid = -1;
|
||||
}
|
||||
@ -485,8 +492,12 @@ vsf_sysutil_wait_reap_one(void)
|
||||
/* No more children */
|
||||
return 0;
|
||||
}
|
||||
if (retval < 0)
|
||||
{
|
||||
die("waitpid");
|
||||
}
|
||||
/* Got one */
|
||||
return 1;
|
||||
return retval;
|
||||
}
|
||||
|
||||
int
|
||||
@ -1477,6 +1488,7 @@ vsf_sysutil_accept_timeout(int fd, struct vsf_sysutil_sockaddr** p_sockptr,
|
||||
}
|
||||
}
|
||||
retval = accept(fd, (struct sockaddr*) &remote_addr, &socklen);
|
||||
vsf_sysutil_check_pending_actions(kVSFSysUtilUnknown, 0, 0);
|
||||
if (retval < 0)
|
||||
{
|
||||
return retval;
|
||||
|
@ -154,6 +154,7 @@ void vsf_sysutil_free(void* p_ptr);
|
||||
/* Process creation/exit/process handling */
|
||||
unsigned int vsf_sysutil_getpid(void);
|
||||
int vsf_sysutil_fork(void);
|
||||
int vsf_sysutil_fork_failok(void);
|
||||
void vsf_sysutil_exit(int exit_code);
|
||||
struct vsf_sysutil_wait_retval
|
||||
{
|
||||
|
@ -61,6 +61,7 @@ unsigned int tunable_listen_port = 21;
|
||||
unsigned int tunable_max_clients = 0;
|
||||
/* -rw-rw-rw- */
|
||||
unsigned int tunable_file_open_mode = 0666;
|
||||
unsigned int tunable_max_per_ip = 0;
|
||||
|
||||
const char* tunable_secure_chroot_dir = "/usr/share/empty";
|
||||
const char* tunable_ftp_username = "ftp";
|
||||
|
@ -55,6 +55,7 @@ extern unsigned int tunable_local_max_rate;
|
||||
extern unsigned int tunable_listen_port;
|
||||
extern unsigned int tunable_max_clients;
|
||||
extern unsigned int tunable_file_open_mode;
|
||||
extern unsigned int tunable_max_per_ip;
|
||||
|
||||
/* String defines */
|
||||
extern const char* tunable_secure_chroot_dir;
|
||||
|
@ -396,6 +396,13 @@ Default: 077
|
||||
If vsftpd is in standalone mode, this is the maximum number of clients which
|
||||
may be connected. Any additional clients connecting will get an error message.
|
||||
|
||||
Default: 0 (unlimited)
|
||||
.TP
|
||||
.B max_per_ip
|
||||
If vsftpd is in standalone mode, this is the maximum number of clients which
|
||||
may be connected from the same source internet address. A client will get an
|
||||
error message if they go over this limit.
|
||||
|
||||
Default: 0 (unlimited)
|
||||
.TP
|
||||
.B pasv_max_port
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef VSF_VERSION_H
|
||||
#define VSF_VERSION_H
|
||||
|
||||
#define VSF_VERSION "1.1.1"
|
||||
#define VSF_VERSION "1.1.2"
|
||||
|
||||
#endif /* VSF_VERSION_H */
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user