Merged revisions 314628 via svnmerge from

https://origsvn.digium.com/svn/asterisk/branches/1.8

................
  r314628 | mnicholson | 2011-04-21 13:24:05 -0500 (Thu, 21 Apr 2011) | 27 lines
  
  Merged revisions 314620 via svnmerge from 
  https://origsvn.digium.com/svn/asterisk/branches/1.6.2
  
  ................
    r314620 | mnicholson | 2011-04-21 13:22:19 -0500 (Thu, 21 Apr 2011) | 20 lines
    
    Merged revisions 314607 via svnmerge from 
    https://origsvn.digium.com/svn/asterisk/branches/1.4
    
    ........
      r314607 | mnicholson | 2011-04-21 13:19:21 -0500 (Thu, 21 Apr 2011) | 14 lines
      
      Added limits to the number of unauthenticated sessions TCP based protocols are allowed to have open simultaneously.  Also added timeouts for unauthenticated sessions where it made sense to do so.
      
      Unrelated, the manager interface now properly checks if the user has the "system" privilege before executing shell commands via the Originate action. 
      
      AST-2011-005
      AST-2011-006
      
      (closes issue #18787)
      Reported by: kobaz
      
      (related to issue #18996)
      Reported by: tzafrir
    ........
  ................
................


git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@314666 65c4cc65-6c06-0410-ace0-fbb531ad65f3
10-digiumphones
Matthew Nicholson 15 years ago
parent 7f23115ad2
commit 079e794b1c

@ -559,6 +559,10 @@ static int max_expiry = DEFAULT_MAX_EXPIRY; /*!< Maximum accepted registr
static int default_expiry = DEFAULT_DEFAULT_EXPIRY; static int default_expiry = DEFAULT_DEFAULT_EXPIRY;
static int mwi_expiry = DEFAULT_MWI_EXPIRY; static int mwi_expiry = DEFAULT_MWI_EXPIRY;
static int unauth_sessions = 0;
static int authlimit = DEFAULT_AUTHLIMIT;
static int authtimeout = DEFAULT_AUTHTIMEOUT;
/*! \brief Global jitterbuffer configuration - by default, jb is disabled */ /*! \brief Global jitterbuffer configuration - by default, jb is disabled */
static struct ast_jb_conf default_jbconf = static struct ast_jb_conf default_jbconf =
{ {
@ -2456,20 +2460,47 @@ static void *sip_tcp_worker_fn(void *data)
return _sip_tcp_helper_thread(NULL, tcptls_session); return _sip_tcp_helper_thread(NULL, tcptls_session);
} }
/*! \brief Check if the authtimeout has expired.
* \param start the time when the session started
*
* \retval 0 the timeout has expired
* \retval -1 error
* \return the number of milliseconds until the timeout will expire
*/
static int sip_check_authtimeout(time_t start)
{
int timeout;
time_t now;
if(time(&now) == -1) {
ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
return -1;
}
timeout = (authtimeout - (now - start)) * 1000;
if (timeout < 0) {
/* we have timed out */
return 0;
}
return timeout;
}
/*! \brief SIP TCP thread management function /*! \brief SIP TCP thread management function
This function reads from the socket, parses the packet into a request This function reads from the socket, parses the packet into a request
*/ */
static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_session_instance *tcptls_session) static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_session_instance *tcptls_session)
{ {
int res, cl; int res, cl, timeout = -1, authenticated = 0, flags;
time_t start;
struct sip_request req = { 0, } , reqcpy = { 0, }; struct sip_request req = { 0, } , reqcpy = { 0, };
struct sip_threadinfo *me = NULL; struct sip_threadinfo *me = NULL;
char buf[1024] = ""; char buf[1024] = "";
struct pollfd fds[2] = { { 0 }, { 0 }, }; struct pollfd fds[2] = { { 0 }, { 0 }, };
struct ast_tcptls_session_args *ca = NULL; struct ast_tcptls_session_args *ca = NULL;
/* If this is a server session, then the connection has already been setup, /* If this is a server session, then the connection has already been
* simply create the threadinfo object so we can access this thread for writing. * setup. Check if the authlimit has been reached and if not create the
* threadinfo object so we can access this thread for writing.
* *
* if this is a client connection more work must be done. * if this is a client connection more work must be done.
* 1. We own the parent session args for a client connection. This pointer needs * 1. We own the parent session args for a client connection. This pointer needs
@ -2479,6 +2510,22 @@ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_sessi
* 3. Last, the tcptls_session must be started. * 3. Last, the tcptls_session must be started.
*/ */
if (!tcptls_session->client) { if (!tcptls_session->client) {
if (ast_atomic_fetchadd_int(&unauth_sessions, +1) >= authlimit) {
/* unauth_sessions is decremented in the cleanup code */
goto cleanup;
}
if ((flags = fcntl(tcptls_session->fd, F_GETFL)) == -1) {
ast_log(LOG_ERROR, "error setting socket to non blocking mode, fcntl() failed: %s\n", strerror(errno));
goto cleanup;
}
flags |= O_NONBLOCK;
if (fcntl(tcptls_session->fd, F_SETFL, flags) == -1) {
ast_log(LOG_ERROR, "error setting socket to non blocking mode, fcntl() failed: %s\n", strerror(errno));
goto cleanup;
}
if (!(me = sip_threadinfo_create(tcptls_session, tcptls_session->ssl ? SIP_TRANSPORT_TLS : SIP_TRANSPORT_TCP))) { if (!(me = sip_threadinfo_create(tcptls_session, tcptls_session->ssl ? SIP_TRANSPORT_TLS : SIP_TRANSPORT_TCP))) {
goto cleanup; goto cleanup;
} }
@ -2510,13 +2557,41 @@ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_sessi
goto cleanup; goto cleanup;
} }
if(time(&start) == -1) {
ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
goto cleanup;
}
for (;;) { for (;;) {
struct ast_str *str_save; struct ast_str *str_save;
res = ast_poll(fds, 2, -1); /* polls for both socket and alert_pipe */ if (!tcptls_session->client && req.authenticated && !authenticated) {
authenticated = 1;
ast_atomic_fetchadd_int(&unauth_sessions, -1);
}
/* calculate the timeout for unauthenticated server sessions */
if (!tcptls_session->client && !authenticated ) {
if ((timeout = sip_check_authtimeout(start)) < 0) {
goto cleanup;
}
if (timeout == 0) {
ast_debug(2, "SIP %s server timed out\n", tcptls_session->ssl ? "SSL": "TCP");
goto cleanup;
}
} else {
timeout = -1;
}
res = ast_poll(fds, 2, timeout); /* polls for both socket and alert_pipe */
if (res < 0) { if (res < 0) {
ast_debug(2, "SIP %s server :: ast_wait_for_input returned %d\n", tcptls_session->ssl ? "SSL": "TCP", res); ast_debug(2, "SIP %s server :: ast_wait_for_input returned %d\n", tcptls_session->ssl ? "SSL": "TCP", res);
goto cleanup; goto cleanup;
} else if (res == 0) {
/* timeout */
ast_debug(2, "SIP %s server timed out\n", tcptls_session->ssl ? "SSL": "TCP");
goto cleanup;
} }
/* handle the socket event, check for both reads from the socket fd, /* handle the socket event, check for both reads from the socket fd,
@ -2549,6 +2624,29 @@ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_sessi
/* Read in headers one line at a time */ /* Read in headers one line at a time */
while (req.len < 4 || strncmp(REQ_OFFSET_TO_STR(&req, len - 4), "\r\n\r\n", 4)) { while (req.len < 4 || strncmp(REQ_OFFSET_TO_STR(&req, len - 4), "\r\n\r\n", 4)) {
if (!tcptls_session->client && !authenticated ) {
if ((timeout = sip_check_authtimeout(start)) < 0) {
goto cleanup;
}
if (timeout == 0) {
ast_debug(2, "SIP %s server timed out\n", tcptls_session->ssl ? "SSL": "TCP");
goto cleanup;
}
} else {
timeout = -1;
}
res = ast_wait_for_input(tcptls_session->fd, timeout);
if (res < 0) {
ast_debug(2, "SIP %s server :: ast_wait_for_input returned %d\n", tcptls_session->ssl ? "SSL": "TCP", res);
goto cleanup;
} else if (res == 0) {
/* timeout */
ast_debug(2, "SIP %s server timed out\n", tcptls_session->ssl ? "SSL": "TCP");
goto cleanup;
}
ast_mutex_lock(&tcptls_session->lock); ast_mutex_lock(&tcptls_session->lock);
if (!fgets(buf, sizeof(buf), tcptls_session->f)) { if (!fgets(buf, sizeof(buf), tcptls_session->f)) {
ast_mutex_unlock(&tcptls_session->lock); ast_mutex_unlock(&tcptls_session->lock);
@ -2567,6 +2665,29 @@ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_sessi
if (sscanf(get_header(&reqcpy, "Content-Length"), "%30d", &cl)) { if (sscanf(get_header(&reqcpy, "Content-Length"), "%30d", &cl)) {
while (cl > 0) { while (cl > 0) {
size_t bytes_read; size_t bytes_read;
if (!tcptls_session->client && !authenticated ) {
if ((timeout = sip_check_authtimeout(start)) < 0) {
goto cleanup;
}
if (timeout == 0) {
ast_debug(2, "SIP %s server timed out", tcptls_session->ssl ? "SSL": "TCP");
goto cleanup;
}
} else {
timeout = -1;
}
res = ast_wait_for_input(tcptls_session->fd, timeout);
if (res < 0) {
ast_debug(2, "SIP %s server :: ast_wait_for_input returned %d\n", tcptls_session->ssl ? "SSL": "TCP", res);
goto cleanup;
} else if (res == 0) {
/* timeout */
ast_debug(2, "SIP %s server timed out", tcptls_session->ssl ? "SSL": "TCP");
goto cleanup;
}
ast_mutex_lock(&tcptls_session->lock); ast_mutex_lock(&tcptls_session->lock);
if (!(bytes_read = fread(buf, 1, MIN(sizeof(buf) - 1, cl), tcptls_session->f))) { if (!(bytes_read = fread(buf, 1, MIN(sizeof(buf) - 1, cl), tcptls_session->f))) {
ast_mutex_unlock(&tcptls_session->lock); ast_mutex_unlock(&tcptls_session->lock);
@ -2626,6 +2747,10 @@ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_sessi
ast_debug(2, "Shutting down thread for %s server\n", tcptls_session->ssl ? "SSL" : "TCP"); ast_debug(2, "Shutting down thread for %s server\n", tcptls_session->ssl ? "SSL" : "TCP");
cleanup: cleanup:
if (!tcptls_session->client && !authenticated) {
ast_atomic_fetchadd_int(&unauth_sessions, -1);
}
if (me) { if (me) {
ao2_t_unlink(threadt, me, "Removing tcptls helper thread, thread is closing"); ao2_t_unlink(threadt, me, "Removing tcptls helper thread, thread is closing");
ao2_t_ref(me, -1, "Removing tcp_helper_threads threadinfo ref"); ao2_t_ref(me, -1, "Removing tcp_helper_threads threadinfo ref");
@ -21789,6 +21914,8 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, int
} }
} }
req->authenticated = 1;
/* We have a successful authentication, process the SDP portion if there is one */ /* We have a successful authentication, process the SDP portion if there is one */
if (find_sdp(req)) { if (find_sdp(req)) {
if (process_sdp(p, req, SDP_T38_INITIATE)) { if (process_sdp(p, req, SDP_T38_INITIATE)) {
@ -24020,8 +24147,10 @@ static int handle_request_register(struct sip_pvt *p, struct sip_request *req, s
get_header(req, "To"), ast_sockaddr_stringify(addr), get_header(req, "To"), ast_sockaddr_stringify(addr),
reason); reason);
append_history(p, "RegRequest", "Failed : Account %s : %s", get_header(req, "To"), reason); append_history(p, "RegRequest", "Failed : Account %s : %s", get_header(req, "To"), reason);
} else } else {
req->authenticated = 1;
append_history(p, "RegRequest", "Succeeded : Account %s", get_header(req, "To")); append_history(p, "RegRequest", "Succeeded : Account %s", get_header(req, "To"));
}
if (res < 1) { if (res < 1) {
/* Destroy the session, but keep us around for just a bit in case they don't /* Destroy the session, but keep us around for just a bit in case they don't
@ -24407,6 +24536,11 @@ static int handle_request_do(struct sip_request *req, struct ast_sockaddr *addr)
copy_socket_data(&p->socket, &req->socket); copy_socket_data(&p->socket, &req->socket);
ast_sockaddr_copy(&p->recv, addr); ast_sockaddr_copy(&p->recv, addr);
/* if we have an owner, then this request has been authenticated */
if (p->owner) {
req->authenticated = 1;
}
if (p->do_history) /* This is a request or response, note what it was for */ if (p->do_history) /* This is a request or response, note what it was for */
append_history(p, "Rx", "%s / %s / %s", req->data->str, get_header(req, "CSeq"), REQ_OFFSET_TO_STR(req, rlPart2)); append_history(p, "Rx", "%s / %s / %s", req->data->str, get_header(req, "CSeq"), REQ_OFFSET_TO_STR(req, rlPart2));
@ -27073,6 +27207,8 @@ static int reload_config(enum channelreloadreason reason)
global_qualifyfreq = DEFAULT_QUALIFYFREQ; global_qualifyfreq = DEFAULT_QUALIFYFREQ;
global_t38_maxdatagram = -1; global_t38_maxdatagram = -1;
global_shrinkcallerid = 1; global_shrinkcallerid = 1;
authlimit = DEFAULT_AUTHLIMIT;
authtimeout = DEFAULT_AUTHTIMEOUT;
sip_cfg.matchexternaddrlocally = DEFAULT_MATCHEXTERNADDRLOCALLY; sip_cfg.matchexternaddrlocally = DEFAULT_MATCHEXTERNADDRLOCALLY;
@ -27336,6 +27472,18 @@ static int reload_config(enum channelreloadreason reason)
if (mwi_expiry < 1) { if (mwi_expiry < 1) {
mwi_expiry = DEFAULT_MWI_EXPIRY; mwi_expiry = DEFAULT_MWI_EXPIRY;
} }
} else if (!strcasecmp(v->name, "tcpauthtimeout")) {
if (ast_parse_arg(v->value, PARSE_INT32|PARSE_DEFAULT|PARSE_IN_RANGE,
&authtimeout, DEFAULT_AUTHTIMEOUT, 1, INT_MAX)) {
ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of %s\n",
v->name, v->value, v->lineno, config);
}
} else if (!strcasecmp(v->name, "tcpauthlimit")) {
if (ast_parse_arg(v->value, PARSE_INT32|PARSE_DEFAULT|PARSE_IN_RANGE,
&authlimit, DEFAULT_AUTHLIMIT, 1, INT_MAX)) {
ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of %s\n",
v->name, v->value, v->lineno, config);
}
} else if (!strcasecmp(v->name, "sipdebug")) { } else if (!strcasecmp(v->name, "sipdebug")) {
if (ast_true(v->value)) if (ast_true(v->value))
sipdebug |= sip_debug_config; sipdebug |= sip_debug_config;

@ -164,6 +164,8 @@ enum skinny_codecs {
#define DEFAULT_SKINNY_PORT 2000 #define DEFAULT_SKINNY_PORT 2000
#define DEFAULT_SKINNY_BACKLOG 2 #define DEFAULT_SKINNY_BACKLOG 2
#define SKINNY_MAX_PACKET 1000 #define SKINNY_MAX_PACKET 1000
#define DEFAULT_AUTH_TIMEOUT 30
#define DEFAULT_AUTH_LIMIT 50
static struct { static struct {
unsigned int tos; unsigned int tos;
@ -175,6 +177,9 @@ static struct {
} qos = { 0, 0, 0, 0, 0, 0 }; } qos = { 0, 0, 0, 0, 0, 0 };
static int keep_alive = 120; static int keep_alive = 120;
static int auth_timeout = DEFAULT_AUTH_TIMEOUT;
static int auth_limit = DEFAULT_AUTH_LIMIT;
static int unauth_sessions = 0;
static char global_vmexten[AST_MAX_EXTENSION]; /* Voicemail pilot number */ static char global_vmexten[AST_MAX_EXTENSION]; /* Voicemail pilot number */
static char used_context[AST_MAX_EXTENSION]; /* placeholder to check if context are already used in regcontext */ static char used_context[AST_MAX_EXTENSION]; /* placeholder to check if context are already used in regcontext */
static char regcontext[AST_MAX_CONTEXT]; /* Context for auto-extension */ static char regcontext[AST_MAX_CONTEXT]; /* Context for auto-extension */
@ -1374,6 +1379,7 @@ static struct ast_jb_conf global_jbconf;*/
struct skinnysession { struct skinnysession {
pthread_t t; pthread_t t;
ast_mutex_t lock; ast_mutex_t lock;
time_t start;
struct sockaddr_in sin; struct sockaddr_in sin;
int fd; int fd;
char inbuf[SKINNY_MAX_PACKET]; char inbuf[SKINNY_MAX_PACKET];
@ -6119,6 +6125,7 @@ static int handle_message(struct skinny_req *req, struct skinnysession *s)
break; break;
case REGISTER_MESSAGE: case REGISTER_MESSAGE:
if (skinny_register(req, s)) { if (skinny_register(req, s)) {
ast_atomic_fetchadd_int(&unauth_sessions, -1);
ast_verb(3, "Device '%s' successfully registered\n", s->device->name); ast_verb(3, "Device '%s' successfully registered\n", s->device->name);
transmit_registerack(s->device); transmit_registerack(s->device);
transmit_capabilitiesreq(s->device); transmit_capabilitiesreq(s->device);
@ -6286,6 +6293,9 @@ static void destroy_session(struct skinnysession *s)
if (s->fd > -1) if (s->fd > -1)
close(s->fd); close(s->fd);
if (!s->device)
ast_atomic_fetchadd_int(&unauth_sessions, -1);
ast_mutex_destroy(&s->lock); ast_mutex_destroy(&s->lock);
ast_free(s); ast_free(s);
@ -6301,13 +6311,30 @@ static int get_input(struct skinnysession *s)
{ {
int res; int res;
int dlen = 0; int dlen = 0;
int timeout = keep_alive * 1100;
time_t now;
int *bufaddr; int *bufaddr;
struct pollfd fds[1]; struct pollfd fds[1];
if (!s->device) {
if(time(&now) == -1) {
ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
return -1;
}
timeout = (auth_timeout - (now - s->start)) * 1000;
if (timeout < 0) {
/* we have timed out */
if (skinnydebug)
ast_verb(1, "Skinny Client failed to authenticate in %d seconds\n", auth_timeout);
return -1;
}
}
fds[0].fd = s->fd; fds[0].fd = s->fd;
fds[0].events = POLLIN; fds[0].events = POLLIN;
fds[0].revents = 0; fds[0].revents = 0;
res = ast_poll(fds, 1, (keep_alive * 1100)); /* If nothing has happen, client is dead */ res = ast_poll(fds, 1, timeout); /* If nothing has happen, client is dead */
/* we add 10% to the keep_alive to deal */ /* we add 10% to the keep_alive to deal */
/* with network delays, etc */ /* with network delays, etc */
if (res < 0) { if (res < 0) {
@ -6316,8 +6343,13 @@ static int get_input(struct skinnysession *s)
return res; return res;
} }
} else if (res == 0) { } else if (res == 0) {
if (skinnydebug) if (skinnydebug) {
if (s->device) {
ast_verb(1, "Skinny Client was lost, unregistering\n"); ast_verb(1, "Skinny Client was lost, unregistering\n");
} else {
ast_verb(1, "Skinny Client failed to authenticate in %d seconds\n", auth_timeout);
}
}
skinny_unregister(NULL, s); skinny_unregister(NULL, s);
return -1; return -1;
} }
@ -6450,18 +6482,35 @@ static void *accept_thread(void *ignore)
ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno)); ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno));
continue; continue;
} }
if (ast_atomic_fetchadd_int(&unauth_sessions, +1) >= auth_limit) {
close(as);
ast_atomic_fetchadd_int(&unauth_sessions, -1);
continue;
}
p = getprotobyname("tcp"); p = getprotobyname("tcp");
if(p) { if(p) {
if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) { if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) {
ast_log(LOG_WARNING, "Failed to set Skinny tcp connection to TCP_NODELAY mode: %s\n", strerror(errno)); ast_log(LOG_WARNING, "Failed to set Skinny tcp connection to TCP_NODELAY mode: %s\n", strerror(errno));
} }
} }
if (!(s = ast_calloc(1, sizeof(struct skinnysession)))) if (!(s = ast_calloc(1, sizeof(struct skinnysession)))) {
close(as);
ast_atomic_fetchadd_int(&unauth_sessions, -1);
continue; continue;
}
memcpy(&s->sin, &sin, sizeof(sin)); memcpy(&s->sin, &sin, sizeof(sin));
ast_mutex_init(&s->lock); ast_mutex_init(&s->lock);
s->fd = as; s->fd = as;
if(time(&s->start) == -1) {
ast_log(LOG_ERROR, "error executing time(): %s; disconnecting client\n", strerror(errno));
destroy_session(s);
continue;
}
AST_LIST_LOCK(&sessions); AST_LIST_LOCK(&sessions);
AST_LIST_INSERT_HEAD(&sessions, s, list); AST_LIST_INSERT_HEAD(&sessions, s, list);
AST_LIST_UNLOCK(&sessions); AST_LIST_UNLOCK(&sessions);
@ -6611,6 +6660,26 @@ static struct ast_channel *skinny_request(const char *type, struct ast_format_ca
} else if (!strcasecmp(v->name, "keepalive")) { } else if (!strcasecmp(v->name, "keepalive")) {
keep_alive = atoi(v->value); keep_alive = atoi(v->value);
continue; continue;
} else if (!strcasecmp(v->name, "authtimeout")) {
int timeout = atoi(v->value);
if (timeout < 1) {
ast_log(LOG_WARNING, "Invalid authtimeout value '%s', using default value\n", v->value);
auth_timeout = DEFAULT_AUTH_TIMEOUT;
} else {
auth_timeout = timeout;
}
continue;
} else if (!strcasecmp(v->name, "authlimit")) {
int limit = atoi(v->value);
if (limit < 1) {
ast_log(LOG_WARNING, "Invalid authlimit value '%s', using default value\n", v->value);
auth_limit = DEFAULT_AUTH_LIMIT;
} else {
auth_limit = limit;
}
continue;
} else if (!strcasecmp(v->name, "regcontext")) { } else if (!strcasecmp(v->name, "regcontext")) {
ast_copy_string(newcontexts, v->value, sizeof(newcontexts)); ast_copy_string(newcontexts, v->value, sizeof(newcontexts));
stringp = newcontexts; stringp = newcontexts;

@ -59,6 +59,9 @@
#define DEFAULT_REGISTRATION_TIMEOUT 20 #define DEFAULT_REGISTRATION_TIMEOUT 20
#define DEFAULT_MAX_FORWARDS 70 #define DEFAULT_MAX_FORWARDS 70
#define DEFAULT_AUTHLIMIT 100
#define DEFAULT_AUTHTIMEOUT 30
/* guard limit must be larger than guard secs */ /* guard limit must be larger than guard secs */
/* guard min must be < 1000, and should be >= 250 */ /* guard min must be < 1000, and should be >= 250 */
#define EXPIRY_GUARD_SECS 15 /*!< How long before expiry do we reregister */ #define EXPIRY_GUARD_SECS 15 /*!< How long before expiry do we reregister */
@ -743,6 +746,7 @@ struct sip_request {
char debug; /*!< print extra debugging if non zero */ char debug; /*!< print extra debugging if non zero */
char has_to_tag; /*!< non-zero if packet has To: tag */ char has_to_tag; /*!< non-zero if packet has To: tag */
char ignore; /*!< if non-zero This is a re-transmit, ignore it */ char ignore; /*!< if non-zero This is a re-transmit, ignore it */
char authenticated; /*!< non-zero if this request was authenticated */
ptrdiff_t header[SIP_MAX_HEADERS]; /*!< Array of offsets into the request string of each SIP header*/ ptrdiff_t header[SIP_MAX_HEADERS]; /*!< Array of offsets into the request string of each SIP header*/
ptrdiff_t line[SIP_MAX_LINES]; /*!< Array of offsets into the request string of each SDP line*/ ptrdiff_t line[SIP_MAX_LINES]; /*!< Array of offsets into the request string of each SDP line*/
struct ast_str *data; struct ast_str *data;

@ -34,6 +34,11 @@ bindaddr=127.0.0.1
; ;
;prefix=asterisk ;prefix=asterisk
; ;
; sessionlimit specifies the maximum number of httpsessions that will be
; allowed to exist at any given time. (default: 100)
;
;sessionlimit=100
;
; Whether Asterisk should serve static content from http-static ; Whether Asterisk should serve static content from http-static
; Default is no. ; Default is no.
; ;

@ -202,6 +202,16 @@ tcpbindaddr=0.0.0.0 ; IP address for TCP server to bind to (0.0.0.0
; For details how to construct a certificate for SIP see ; For details how to construct a certificate for SIP see
; http://tools.ietf.org/html/draft-ietf-sip-domain-certs ; http://tools.ietf.org/html/draft-ietf-sip-domain-certs
;tcpauthtimeout = 30 ; tcpauthtimeout 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)
;tcpauthlimit = 100 ; tcpauthlimit specifies the maximum number of
; unauthenticated sessions that will be allowed
; to connect at any given time. (default: 100)
srvlookup=yes ; Enable DNS SRV lookups on outbound calls srvlookup=yes ; Enable DNS SRV lookups on outbound calls
; Note: Asterisk only uses the first host ; Note: Asterisk only uses the first host
; in SRV records ; in SRV records

@ -9,6 +9,15 @@ dateformat=M-D-Y ; M,D,Y in any order (6 chars max)
; Use M for month, D for day, Y for year, A for 12-hour time. ; Use M for month, D for day, Y for year, A for 12-hour time.
keepalive=120 keepalive=120
;authtimeout = 30 ; 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)
;authlimit = 50 ; authlimit specifies the maximum number of
; unauthenticated sessions that will be allowed to
; connect at any given time. (default: 50)
;vmexten=8500 ; Systemwide voicemailmain pilot number ;vmexten=8500 ; Systemwide voicemailmain pilot number
; It must be in the same context as the calling ; It must be in the same context as the calling
; device/line ; device/line

@ -57,12 +57,16 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#define MAX_PREFIX 80 #define MAX_PREFIX 80
#define DEFAULT_PORT 8088 #define DEFAULT_PORT 8088
#define DEFAULT_TLS_PORT 8089 #define DEFAULT_TLS_PORT 8089
#define DEFAULT_SESSION_LIMIT 100
/* See http.h for more information about the SSL implementation */ /* See http.h for more information about the SSL implementation */
#if defined(HAVE_OPENSSL) && (defined(HAVE_FUNOPEN) || defined(HAVE_FOPENCOOKIE)) #if defined(HAVE_OPENSSL) && (defined(HAVE_FUNOPEN) || defined(HAVE_FOPENCOOKIE))
#define DO_SSL /* comment in/out if you want to support ssl */ #define DO_SSL /* comment in/out if you want to support ssl */
#endif #endif
static int session_limit = DEFAULT_SESSION_LIMIT;
static int session_count = 0;
static struct ast_tls_config http_tls_cfg; static struct ast_tls_config http_tls_cfg;
static void *httpd_helper_thread(void *arg); static void *httpd_helper_thread(void *arg);
@ -829,6 +833,10 @@ static void *httpd_helper_thread(void *data)
char *uri, *method; char *uri, *method;
enum ast_http_method http_method = AST_HTTP_UNKNOWN; enum ast_http_method http_method = AST_HTTP_UNKNOWN;
if (ast_atomic_fetchadd_int(&session_count, +1) >= session_limit) {
goto done;
}
if (!fgets(buf, sizeof(buf), ser->f)) { if (!fgets(buf, sizeof(buf), ser->f)) {
goto done; goto done;
} }
@ -894,17 +902,19 @@ static void *httpd_helper_thread(void *data)
if (!*uri) { if (!*uri) {
ast_http_error(ser, 400, "Bad Request", "Invalid Request"); ast_http_error(ser, 400, "Bad Request", "Invalid Request");
return NULL; goto done;
} }
handle_uri(ser, uri, http_method, headers); handle_uri(ser, uri, http_method, headers);
/* Clean up all the header information pulled as well */ done:
ast_atomic_fetchadd_int(&session_count, -1);
/* clean up all the header information */
if (headers) { if (headers) {
ast_variables_destroy(headers); ast_variables_destroy(headers);
} }
done:
if (ser->f) { if (ser->f) {
fclose(ser->f); fclose(ser->f);
} }
@ -1044,6 +1054,12 @@ static int __ast_http_load(int reload)
} }
} else if (!strcasecmp(v->name, "redirect")) { } else if (!strcasecmp(v->name, "redirect")) {
add_redirect(v->value); add_redirect(v->value);
} else if (!strcasecmp(v->name, "sessionlimit")) {
if (ast_parse_arg(v->value, PARSE_INT32|PARSE_DEFAULT|PARSE_IN_RANGE,
&session_limit, DEFAULT_SESSION_LIMIT, 1, INT_MAX)) {
ast_log(LOG_WARNING, "Invalid %s '%s' at line %d of http.conf\n",
v->name, v->value, v->lineno);
}
} else { } else {
ast_log(LOG_WARNING, "Ignoring unknown option '%s' in http.conf\n", v->name); ast_log(LOG_WARNING, "Ignoring unknown option '%s' in http.conf\n", v->name);
} }

@ -3891,6 +3891,27 @@ static int action_originate(struct mansession *s, const struct message *m)
ast_format_cap_remove_all(cap); ast_format_cap_remove_all(cap);
ast_parse_allow_disallow(NULL, cap, codecs, 1); ast_parse_allow_disallow(NULL, cap, codecs, 1);
} }
if (!ast_strlen_zero(app)) {
/* To run the System application (or anything else that goes to
* shell), you must have the additional System privilege */
if (!(s->session->writeperm & EVENT_FLAG_SYSTEM)
&& (
strcasestr(app, "system") || /* System(rm -rf /)
TrySystem(rm -rf /) */
strcasestr(app, "exec") || /* Exec(System(rm -rf /))
TryExec(System(rm -rf /)) */
strcasestr(app, "agi") || /* AGI(/bin/rm,-rf /)
EAGI(/bin/rm,-rf /) */
strstr(appdata, "SHELL") || /* NoOp(${SHELL(rm -rf /)}) */
strstr(appdata, "EVAL") /* NoOp(${EVAL(${some_var_containing_SHELL})}) */
)) {
astman_send_error(s, m, "Originate with certain 'Application' arguments requires the additional System privilege, which you do not have.");
res = 0;
goto fast_orig_cleanup;
}
}
/* Allocate requested channel variables */ /* Allocate requested channel variables */
vars = astman_get_variables(m); vars = astman_get_variables(m);
@ -3928,22 +3949,6 @@ static int action_originate(struct mansession *s, const struct message *m)
} }
} }
} else if (!ast_strlen_zero(app)) { } else if (!ast_strlen_zero(app)) {
/* To run the System application (or anything else that goes to shell), you must have the additional System privilege */
if (!(s->session->writeperm & EVENT_FLAG_SYSTEM)
&& (
strcasestr(app, "system") || /* System(rm -rf /)
TrySystem(rm -rf /) */
strcasestr(app, "exec") || /* Exec(System(rm -rf /))
TryExec(System(rm -rf /)) */
strcasestr(app, "agi") || /* AGI(/bin/rm,-rf /)
EAGI(/bin/rm,-rf /) */
strstr(appdata, "SHELL") || /* NoOp(${SHELL(rm -rf /)}) */
strstr(appdata, "EVAL") /* NoOp(${EVAL(${some_var_containing_SHELL})}) */
)) {
astman_send_error(s, m, "Originate with certain 'Application' arguments requires the additional System privilege, which you do not have.");
res = 0;
goto fast_orig_cleanup;
}
res = ast_pbx_outgoing_app(tech, cap, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL); res = ast_pbx_outgoing_app(tech, cap, data, to, app, appdata, &reason, 1, l, n, vars, account, NULL);
} else { } else {
if (exten && context && pi) { if (exten && context && pi) {

Loading…
Cancel
Save