Allow setting a reconnection delay time after a failed authentication attempt (added min-reauth-time option).

This commit is contained in:
Nikos Mavrogiannopoulos
2013-03-04 19:42:10 +01:00
parent 2674af5aec
commit 432a2da897
11 changed files with 135 additions and 30 deletions

2
NEWS
View File

@@ -8,6 +8,8 @@
enable non-openconnect clients to connect. They are enabled with
the configure option --enable-anyconnect-compat.
- Allow setting a rate limit on the number of connections.
- Allow setting a reconnection delay time after a failed authentication
attempt (added min-reauth-time option).
* Version 0.0.1 (released 2013-02-20)

View File

@@ -85,6 +85,10 @@ tls-priorities = "PERFORMANCE:%SERVER_PRECEDENCE"
# to authentication
auth-timeout = 40
# The time (in seconds) that a client is not allowed to reconnect after a failed
# authentication attempt.
min-reauth-time = 10
# Cookie validity time (in seconds)
# Once a client is authenticated he's provided a cookie with
# which he can reconnect. This option sets the maximum lifetime

View File

@@ -176,6 +176,7 @@ unsigned j;
READ_NUMERIC("cookie-validity", config->cookie_validity, 1);
READ_NUMERIC("auth-timeout", config->auth_timeout, 0);
READ_NUMERIC("max-clients", config->max_clients, 0);
READ_NUMERIC("min-reauth-time", config->min_reauth_time, 0);
READ_NUMERIC("max-same-clients", config->max_same_clients, 0);
val = optionGetValue(pov, "run-as-user"); \

View File

@@ -261,7 +261,7 @@ unsigned int entries = 1; /* that one */
if (s->config->max_same_clients == 0)
return 0; /* ok */
list_for_each(&s->clist->head, ctmp, list) {
list_for_each(&s->clist.head, ctmp, list) {
if (ctmp != proc) {
if (strcmp(proc->username, ctmp->username) == 0) {

View File

@@ -111,7 +111,6 @@ int send_udp_fd(main_server_st* s, struct proc_st * proc, int fd)
int handle_commands(main_server_st *s, struct proc_st* proc)
{
struct iovec iov[2];
char buf[128];
uint8_t cmd;
struct msghdr hdr;
struct lease_st *lease;
@@ -123,10 +122,8 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
struct cmd_tun_mtu_st tmtu;
} cmd_data;
int ret, cmd_data_len, e;
const char* peer_ip, *group;
const char* group;
peer_ip = human_addr((void*)&proc->remote_addr, proc->remote_addr_len, buf, sizeof(buf));
memset(&cmd_data, 0, sizeof(cmd_data));
iov[0].iov_base = &cmd;
@@ -142,7 +139,7 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
ret = recvmsg( proc->fd, &hdr, 0);
if (ret == -1) {
e = errno;
mslog(s, proc, LOG_ERR, "cannot obtain data from command socket (pid: %d, peer: %s): %s", proc->pid, peer_ip, strerror(e));
mslog(s, proc, LOG_ERR, "cannot obtain data from command socket: %s", strerror(e));
return -1;
}
@@ -241,6 +238,8 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
mslog(s, proc, LOG_INFO, "user '%s' disconnected due to script", proc->username);
}
}
} else {
add_to_ip_ban_list(s, &proc->remote_addr, proc->remote_addr_len);
}
if (ret == 0) {
@@ -275,7 +274,7 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
mslog(s, proc, LOG_INFO, "failed authentication attempt for user '%s'", proc->username);
ret = send_auth_reply( s, proc, REP_AUTH_FAILED, NULL);
if (ret < 0) {
mslog(s, proc, LOG_ERR, "could not send reply cmd (pid: %d, peer: %s).", proc->pid, peer_ip);
mslog(s, proc, LOG_ERR, "could not send reply cmd.");
ret = -2;
goto lease_cleanup;
}
@@ -301,3 +300,67 @@ lease_cleanup:
return 0;
}
int check_if_banned(main_server_st* s, struct sockaddr_storage *addr, socklen_t addr_len)
{
time_t now = time(0);
struct banned_st *btmp, *bpos;
if (s->config->min_reauth_time == 0)
return 0;
list_for_each_safe(&s->ban_list.head, btmp, bpos, list) {
if (now-btmp->failed_time > s->config->min_reauth_time) {
/* invalid entry. Clean it up */
list_del(&btmp->list);
free(btmp);
}
if (SA_IN_SIZE(btmp->addr_len) == SA_IN_SIZE(addr_len) &&
memcmp(SA_IN_P_GENERIC(&btmp->addr, btmp->addr_len),
SA_IN_P_GENERIC(addr, addr_len),
SA_IN_SIZE(btmp->addr_len)) == 0) {
return -1;
}
}
return 0;
}
void expire_banned(main_server_st* s)
{
time_t now = time(0);
struct banned_st *btmp, *bpos;
if (s->config->min_reauth_time == 0)
return;
list_for_each_safe(&s->ban_list.head, btmp, bpos, list) {
if (now-btmp->failed_time > s->config->min_reauth_time) {
/* invalid entry. Clean it up */
list_del(&btmp->list);
free(btmp);
}
}
return;
}
void add_to_ip_ban_list(main_server_st* s, struct sockaddr_storage *addr, socklen_t addr_len)
{
struct banned_st *btmp;
if (s->config->min_reauth_time == 0)
return;
btmp = malloc(sizeof(*btmp));
if (btmp == NULL)
return;
btmp->failed_time = time(0);
memcpy(&btmp->addr, addr, addr_len);
btmp->addr_len = addr_len;
list_add(&s->ban_list.head, &(btmp->list));
}

View File

@@ -350,25 +350,32 @@ static void drop_privileges(main_server_st* s)
}
}
/* clears the server llist and clist. To be used after fork() */
/* clears the server llist and clist. To be used after fork().
* It frees unused memory and descriptors.
*/
void clear_lists(main_server_st *s)
{
struct listener_st *ltmp, *lpos;
struct proc_st *ctmp, *cpos;
struct banned_st *btmp, *bpos;
list_for_each_safe(&s->llist->head, ltmp, lpos, list) {
list_for_each_safe(&s->llist.head, ltmp, lpos, list) {
close(ltmp->fd);
list_del(&ltmp->list);
s->llist->total--;
s->llist.total--;
}
list_for_each_safe(&s->clist->head, ctmp, cpos, list) {
list_for_each_safe(&s->clist.head, ctmp, cpos, list) {
if (ctmp->fd >= 0)
close(ctmp->fd);
list_del(&ctmp->list);
s->clist->total--;
s->clist.total--;
}
list_for_each_safe(&s->ban_list.head, btmp, bpos, list) {
list_del(&btmp->list);
}
tls_cache_deinit(s->tls_db);
}
@@ -376,7 +383,7 @@ static void kill_children(main_server_st* s)
{
struct proc_st *ctmp;
list_for_each(&s->clist->head, ctmp, list) {
list_for_each(&s->clist.head, ctmp, list) {
if (ctmp->pid != -1) {
kill(ctmp->pid, SIGTERM);
user_disconnected(s, ctmp);
@@ -455,7 +462,7 @@ int connected = 0;
session_id = &buffer[RECORD_PAYLOAD_POS+HANDSHAKE_SESSION_ID_POS+1];
/* search for the IP and the session ID in all procs */
list_for_each(&s->clist->head, ctmp, list) {
list_for_each(&s->clist.head, ctmp, list) {
if (session_id_size == ctmp->session_id_size &&
memcmp(session_id, ctmp->session_id, session_id_size) == 0) {
@@ -519,6 +526,7 @@ static void check_other_work(main_server_st *s)
mslog(s, NULL, LOG_INFO, "Performing maintainance");
expire_tls_sessions(s);
expire_cookies(s);
expire_banned(s);
alarm(MAINTAINANCE_TIME(s));
}
@@ -548,8 +556,6 @@ static int check_tcp_wrapper(int fd)
int main(int argc, char** argv)
{
int fd, pid, e;
struct listen_list_st llist;
struct proc_list_st clist;
struct listener_st *ltmp;
struct proc_st *ctmp, *cpos;
struct tun_st tun;
@@ -564,7 +570,8 @@ int main(int argc, char** argv)
memset(&s, 0, sizeof(s));
list_head_init(&clist.head);
list_head_init(&s.clist.head);
list_head_init(&s.ban_list.head);
tun_st_init(&tun);
tls_cache_init(&s.tls_db);
@@ -594,8 +601,6 @@ int main(int argc, char** argv)
s.config = &config;
s.tun = &tun;
s.llist = &llist;
s.clist = &clist;
ret = cookie_db_init(&s);
if (ret < 0) {
@@ -604,7 +609,7 @@ int main(int argc, char** argv)
}
/* Listen to network ports */
ret = listen_ports(&config, &llist, config.name);
ret = listen_ports(&config, &s.llist, config.name);
if (ret < 0) {
fprintf(stderr, "Cannot listen to specified ports\n");
exit(1);
@@ -645,7 +650,7 @@ int main(int argc, char** argv)
/* initialize select */
FD_ZERO(&rd);
list_for_each(&llist.head, ltmp, list) {
list_for_each(&s.llist.head, ltmp, list) {
if (ltmp->fd == -1) continue;
val = fcntl(ltmp->fd, F_GETFL, 0);
@@ -661,7 +666,7 @@ int main(int argc, char** argv)
n = MAX(n, ltmp->fd);
}
list_for_each(&clist.head, ctmp, list) {
list_for_each(&s.clist.head, ctmp, list) {
FD_SET(ctmp->fd, &rd);
n = MAX(n, ctmp->fd);
}
@@ -680,7 +685,7 @@ int main(int argc, char** argv)
}
/* Check for new connections to accept */
list_for_each(&llist.head, ltmp, list) {
list_for_each(&s.llist.head, ltmp, list) {
set = FD_ISSET(ltmp->fd, &rd);
if (set && ltmp->socktype == SOCK_STREAM) {
/* connection on TCP port */
@@ -693,6 +698,15 @@ int main(int argc, char** argv)
}
set_cloexec_flag (fd, 1);
/* Check if the client is on the banned list */
ret = check_if_banned(&s, &ws.remote_addr, ws.remote_addr_len);
if (ret < 0) {
/* banned */
close(fd);
mslog(&s, NULL, LOG_INFO, "dropping client connection due to a previous failed authentication attempt");
break;
}
if (config.max_clients > 0 && active_clients >= config.max_clients) {
close(fd);
mslog(&s, NULL, LOG_INFO, "Reached maximum client limit (active: %u)", active_clients);
@@ -756,7 +770,7 @@ fork_failed:
ctmp->fd = cmd_fd[0];
set_cloexec_flag (cmd_fd[0], 1);
list_add(&clist.head, &(ctmp->list));
list_add(&s.clist.head, &(ctmp->list));
active_clients++;
}
close(cmd_fd[1]);
@@ -777,7 +791,7 @@ fork_failed:
}
/* Check for any pending commands */
list_for_each_safe(&clist.head, ctmp, cpos, list) {
list_for_each_safe(&s.clist.head, ctmp, cpos, list) {
if (FD_ISSET(ctmp->fd, &rd)) {
ret = handle_commands(&s, ctmp);
if (ret < 0) {

View File

@@ -62,6 +62,17 @@ struct proc_list_st {
unsigned int total;
};
struct banned_st {
struct list_node list;
time_t failed_time; /* The time authentication failed */
struct sockaddr_storage addr; /* local socket address */
socklen_t addr_len;
};
struct ban_list_st {
struct list_head head;
};
typedef struct main_server_st {
struct cfg_st *config;
struct tun_st *tun;
@@ -71,8 +82,9 @@ typedef struct main_server_st {
/* tls credentials */
struct tls_st creds;
struct listen_list_st* llist;
struct proc_list_st* clist;
struct listen_list_st llist;
struct proc_list_st clist;
struct ban_list_st ban_list;
} main_server_st;
void clear_lists(main_server_st *s);
@@ -117,4 +129,8 @@ int handle_auth_req(main_server_st *s, struct proc_st* proc,
int check_multiple_users(main_server_st *s, struct proc_st* proc);
void add_to_ip_ban_list(main_server_st* s, struct sockaddr_storage *addr, socklen_t addr_len);
void expire_banned(main_server_st* s);
int check_if_banned(main_server_st* s, struct sockaddr_storage *addr, socklen_t addr_len);
#endif

View File

@@ -2,7 +2,7 @@
*
* DO NOT EDIT THIS FILE (ocserv-args.c)
*
* It has been AutoGen-ed March 4, 2013 at 06:18:05 AM by AutoGen 5.16
* It has been AutoGen-ed March 4, 2013 at 07:36:47 PM by AutoGen 5.16
* From the definitions ocserv-args.def
* and the template file options
*

View File

@@ -150,6 +150,10 @@ tls-priorities = "PERFORMANCE:%SERVER_PRECEDENCE"
# to authentication
auth-timeout = 40
# The time (in seconds) that a client is not allowed to reconnect after a failed
# authentication attempt.
min-reauth-time = 2
# Cookie validity time (in seconds)
# Once a client is authenticated he's provided a cookie with
# which he can reconnect. This option sets the maximum lifetime

View File

@@ -2,7 +2,7 @@
*
* DO NOT EDIT THIS FILE (ocserv-args.h)
*
* It has been AutoGen-ed March 4, 2013 at 06:18:05 AM by AutoGen 5.16
* It has been AutoGen-ed March 4, 2013 at 07:36:47 PM by AutoGen 5.16
* From the definitions ocserv-args.def
* and the template file options
*

View File

@@ -72,6 +72,7 @@ struct cfg_st {
char *chroot_dir; /* where the xml files are served from */
char *banner;
time_t cookie_validity; /* in seconds */
time_t min_reauth_time; /* after a failed auth, how soon one can reauthenticate -> in seconds */
unsigned auth_timeout; /* timeout of HTTP auth */
unsigned keepalive;
unsigned dpd;