Limit the number of unauthenticated manager sessions and also limit the time they have to authenticate.

AST-2011-005

(closes issue #18996)
Reported by: tzafrir
Tested by: mnicholson


git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@312761 65c4cc65-6c06-0410-ace0-fbb531ad65f3
1.4
Matthew Nicholson 16 years ago
parent cd24c868cb
commit 059e1a2dec

@ -26,6 +26,17 @@ enabled = no
;webenabled = yes
port = 5038
; authtimeout specifies the maximum number of seconds a client has to
; authenticate. If the client does not authenticate beofre this timeout
; expires, the client will be disconnected. (default: 30 seconds)
;authtimeout = 30
; authlimit specifies the maximum number of unauthenticated sessions that will
; be allowed to connect at any given time.
;authlimit = 50
;httptimeout = 60
; a) httptimeout sets the Max-Age of the http cookie
; b) httptimeout is the amount of time the webserver waits

@ -104,6 +104,8 @@ static const int DEFAULT_DISPLAYCONNECTS = 1; /*!< Default setting for displayin
static const int DEFAULT_TIMESTAMPEVENTS = 0; /*!< Default setting for timestampevents */
static const int DEFAULT_HTTPTIMEOUT = 60; /*!< Default manager http timeout */
static const int DEFAULT_BROKENEVENTSACTION = 0; /*!< Default setting for brokeneventsaction */
static const int DEFAULT_AUTHTIMEOUT = 30; /*!< Default setting for authtimeout */
static const int DEFAULT_AUTHLIMIT = 50; /*!< Default setting for authlimit */
static int enabled;
@ -113,10 +115,13 @@ static int displayconnects;
static int timestampevents;
static int httptimeout;
static int broken_events_action;
static int authtimeout;
static int authlimit;
static pthread_t t;
static int block_sockets;
static int num_sessions;
static int unauth_sessions = 0;
/* Protected by the sessions list lock */
struct eventqent *master_eventq = NULL;
@ -222,6 +227,7 @@ struct mansession_session {
struct eventqent *eventq;
/* Timeout for ast_carefulwrite() */
int writetimeout;
time_t authstart;
int pending_event; /*!< Pending events indicator in case when waiting_thread is NULL */
AST_LIST_ENTRY(mansession_session) list;
};
@ -2306,6 +2312,7 @@ static int process_message(struct mansession *s, const struct message *m)
return -1;
} else {
s->session->authenticated = 1;
ast_atomic_fetchadd_int(&unauth_sessions, -1);
if (option_verbose > 1) {
if (displayconnects) {
ast_verbose(VERBOSE_PREFIX_2 "%sManager '%s' logged on from %s\n",
@ -2360,6 +2367,8 @@ static int get_input(struct mansession_session *s, char *output)
int res;
int x;
struct pollfd fds[1];
int timeout = -1;
time_t now;
for (x = 1; x < s->inlen; x++) {
if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) {
/* Copy output data up to and including \r\n */
@ -2378,7 +2387,22 @@ static int get_input(struct mansession_session *s, char *output)
}
fds[0].fd = s->fd;
fds[0].events = POLLIN;
do {
/* calculate a timeout if we are not authenticated */
if (!s->authenticated) {
if(time(&now) == -1) {
ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
return -1;
}
timeout = (authtimeout - (now - s->authstart)) * 1000;
if (timeout < 0) {
/* we have timed out */
return 0;
}
}
ast_mutex_lock(&s->__lock);
if (s->pending_event) {
s->pending_event = 0;
@ -2388,7 +2412,7 @@ static int get_input(struct mansession_session *s, char *output)
s->waiting_thread = pthread_self();
ast_mutex_unlock(&s->__lock);
res = ast_poll(fds, 1, -1);
res = ast_poll(fds, 1, timeout);
ast_mutex_lock(&s->__lock);
s->waiting_thread = AST_PTHREADT_NULL;
@ -2406,6 +2430,9 @@ static int get_input(struct mansession_session *s, char *output)
if (res < 1)
return -1;
break;
} else {
/* timeout */
return 0;
}
} while(1);
s->inlen += res;
@ -2418,6 +2445,7 @@ static int do_message(struct mansession *s)
struct message m = { 0 };
char header_buf[sizeof(s->session->inbuf)] = { '\0' };
int res;
time_t now;
for (;;) {
/* Check if any events are pending and do them if needed */
@ -2427,6 +2455,17 @@ static int do_message(struct mansession *s)
}
res = get_input(s->session, header_buf);
if (res == 0) {
if (!s->session->authenticated) {
if(time(&now) == -1) {
ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
return -1;
}
if (now - s->session->authstart > authtimeout) {
ast_log(LOG_EVENT, "Client from %s, failed to authenticate in %d seconds\n", ast_inet_ntoa(s->session->sin.sin_addr), authtimeout);
return -1;
}
}
continue;
} else if (res > 0) {
/* Strip trailing \r\n */
@ -2461,6 +2500,7 @@ static void *session_do(void *data)
}
ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", session->username, ast_inet_ntoa(session->sin.sin_addr));
} else {
ast_atomic_fetchadd_int(&unauth_sessions, -1);
if (option_verbose > 1) {
if (displayconnects)
ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(session->sin.sin_addr));
@ -2534,14 +2574,25 @@ static void *accept_thread(void *ignore)
ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
continue;
}
if (ast_atomic_fetchadd_int(&unauth_sessions, +1) >= authlimit) {
close(as);
ast_atomic_fetchadd_int(&unauth_sessions, -1);
ast_log(LOG_WARNING, "manager connection rejected, too many unauthenticated sessions.\n");
continue;
}
p = getprotobyname("tcp");
if (p) {
if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
}
}
if (!(s = ast_calloc(1, sizeof(*s))))
if (!(s = ast_calloc(1, sizeof(*s)))) {
close(as);
ast_atomic_fetchadd_int(&unauth_sessions, -1);
continue;
}
memcpy(&s->sin, &sin, sizeof(sin));
s->writetimeout = 100;
@ -2568,8 +2619,16 @@ static void *accept_thread(void *ignore)
s->eventq = s->eventq->next;
ast_atomic_fetchadd_int(&s->eventq->usecount, 1);
AST_LIST_UNLOCK(&sessions);
if (ast_pthread_create_background(&t, &attr, session_do, s))
if(time(&s->authstart) == -1) {
ast_log(LOG_ERROR, "error executing time(): %s; disconnecting client\n", strerror(errno));
ast_atomic_fetchadd_int(&unauth_sessions, -1);
destroy_session(s);
continue;
}
if (ast_pthread_create_background(&t, &attr, session_do, s)) {
ast_atomic_fetchadd_int(&unauth_sessions, -1);
destroy_session(s);
}
}
pthread_attr_destroy(&attr);
return NULL;
@ -3106,6 +3165,8 @@ int init_manager(void)
block_sockets = DEFAULT_BLOCKSOCKETS;
timestampevents = DEFAULT_TIMESTAMPEVENTS;
httptimeout = DEFAULT_HTTPTIMEOUT;
authtimeout = DEFAULT_AUTHTIMEOUT;
authlimit = DEFAULT_AUTHLIMIT;
cfg = ast_config_load("manager.conf");
if (!cfg) {
@ -3143,6 +3204,26 @@ int init_manager(void)
if ((val = ast_variable_retrieve(cfg, "general", "httptimeout")))
newhttptimeout = atoi(val);
if ((val = ast_variable_retrieve(cfg, "general", "authtimeout"))) {
int timeout = atoi(val);
if (timeout < 1) {
ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", val);
} else {
authtimeout = timeout;
}
}
if ((val = ast_variable_retrieve(cfg, "general", "authlimit"))) {
int limit = atoi(val);
if (limit < 1) {
ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", val);
} else {
authlimit = limit;
}
}
memset(&ba, 0, sizeof(ba));
ba.sin_family = AF_INET;
ba.sin_port = htons(portno);

Loading…
Cancel
Save