mirror of
https://github.com/asterisk/asterisk.git
synced 2025-11-19 08:11:21 +00:00
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
This commit is contained in:
@@ -559,6 +559,10 @@ static int max_expiry = DEFAULT_MAX_EXPIRY; /*!< Maximum accepted registr
|
||||
static int default_expiry = DEFAULT_DEFAULT_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 */
|
||||
static struct ast_jb_conf default_jbconf =
|
||||
{
|
||||
@@ -2456,21 +2460,48 @@ static void *sip_tcp_worker_fn(void *data)
|
||||
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
|
||||
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)
|
||||
{
|
||||
int res, cl;
|
||||
int res, cl, timeout = -1, authenticated = 0, flags;
|
||||
time_t start;
|
||||
struct sip_request req = { 0, } , reqcpy = { 0, };
|
||||
struct sip_threadinfo *me = NULL;
|
||||
char buf[1024] = "";
|
||||
struct pollfd fds[2] = { { 0 }, { 0 }, };
|
||||
struct ast_tcptls_session_args *ca = NULL;
|
||||
|
||||
/* If this is a server session, then the connection has already been setup,
|
||||
* simply create the threadinfo object so we can access this thread for writing.
|
||||
*
|
||||
/* If this is a server session, then the connection has already been
|
||||
* 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.
|
||||
* 1. We own the parent session args for a client connection. This pointer needs
|
||||
* to be held on to so we can decrement it's ref count on thread destruction.
|
||||
@@ -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.
|
||||
*/
|
||||
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))) {
|
||||
goto cleanup;
|
||||
}
|
||||
@@ -2510,13 +2557,41 @@ static void *_sip_tcp_helper_thread(struct sip_pvt *pvt, struct ast_tcptls_sessi
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if(time(&start) == -1) {
|
||||
ast_log(LOG_ERROR, "error executing time(): %s\n", strerror(errno));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
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) {
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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 */
|
||||
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);
|
||||
if (!fgets(buf, sizeof(buf), tcptls_session->f)) {
|
||||
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)) {
|
||||
while (cl > 0) {
|
||||
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);
|
||||
if (!(bytes_read = fread(buf, 1, MIN(sizeof(buf) - 1, cl), tcptls_session->f))) {
|
||||
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");
|
||||
|
||||
cleanup:
|
||||
if (!tcptls_session->client && !authenticated) {
|
||||
ast_atomic_fetchadd_int(&unauth_sessions, -1);
|
||||
}
|
||||
|
||||
if (me) {
|
||||
ao2_t_unlink(threadt, me, "Removing tcptls helper thread, thread is closing");
|
||||
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 */
|
||||
if (find_sdp(req)) {
|
||||
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),
|
||||
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"));
|
||||
}
|
||||
|
||||
if (res < 1) {
|
||||
/* 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);
|
||||
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 */
|
||||
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_t38_maxdatagram = -1;
|
||||
global_shrinkcallerid = 1;
|
||||
authlimit = DEFAULT_AUTHLIMIT;
|
||||
authtimeout = DEFAULT_AUTHTIMEOUT;
|
||||
|
||||
sip_cfg.matchexternaddrlocally = DEFAULT_MATCHEXTERNADDRLOCALLY;
|
||||
|
||||
@@ -27336,6 +27472,18 @@ static int reload_config(enum channelreloadreason reason)
|
||||
if (mwi_expiry < 1) {
|
||||
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")) {
|
||||
if (ast_true(v->value))
|
||||
sipdebug |= sip_debug_config;
|
||||
|
||||
Reference in New Issue
Block a user