[asterisk-commits] mnicholson: branch 1.4 r312761 - in /branches/1.4: configs/ main/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Apr 5 09:10:39 CDT 2011


Author: mnicholson
Date: Tue Apr  5 09:10:34 2011
New Revision: 312761

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=312761
Log:
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

Modified:
    branches/1.4/configs/manager.conf.sample
    branches/1.4/main/manager.c

Modified: branches/1.4/configs/manager.conf.sample
URL: http://svnview.digium.com/svn/asterisk/branches/1.4/configs/manager.conf.sample?view=diff&rev=312761&r1=312760&r2=312761
==============================================================================
--- branches/1.4/configs/manager.conf.sample (original)
+++ branches/1.4/configs/manager.conf.sample Tue Apr  5 09:10:34 2011
@@ -25,6 +25,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

Modified: branches/1.4/main/manager.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.4/main/manager.c?view=diff&rev=312761&r1=312760&r2=312761
==============================================================================
--- branches/1.4/main/manager.c (original)
+++ branches/1.4/main/manager.c Tue Apr  5 09:10:34 2011
@@ -104,6 +104,8 @@
 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 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 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 @@
 				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 @@
 	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 @@
 	}
 	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 @@
 		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 @@
 			if (res < 1)
 				return -1;
 			break;
+		} else {
+			/* timeout */
+			return 0;
 		}
 	} while(1);
 	s->inlen += res;
@@ -2418,6 +2445,7 @@
 	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 @@
 		}
 		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 @@
 		}
 		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 @@
 			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 @@
 			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 @@
 	block_sockets = DEFAULT_BLOCKSOCKETS;
 	timestampevents = DEFAULT_TIMESTAMPEVENTS;
 	httptimeout = DEFAULT_HTTPTIMEOUT;
+	authtimeout = DEFAULT_AUTHTIMEOUT;
+	authlimit = DEFAULT_AUTHLIMIT;
 
 	cfg = ast_config_load("manager.conf");
 	if (!cfg) {
@@ -3142,6 +3203,26 @@
 
 	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;




More information about the asterisk-commits mailing list