[asterisk-commits] rmudgett: branch 1.8 r326291 - in /branches/1.8/channels: ./ sip/include/
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue Jul 5 12:23:05 CDT 2011
Author: rmudgett
Date: Tue Jul 5 12:22:59 2011
New Revision: 326291
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=326291
Log:
Used auth= parameter freed during "sip reload" causes crash.
If you use the auth= parameter and do a "sip reload" while there is an
ongoing call. The peer->auth data points to free'd memory.
The patch does several things:
1) Puts the authentication list into an ao2 object for reference counting
to fix the reported crash during a SIP reload.
2) Converts the authentication list from open coding to AST list macros.
3) Adds display of the global authentication list in "sip show settings".
(closes issue ASTERISK-17939)
Reported by: wdoekes
Patches:
jira_asterisk_17939_v1.8.patch (license #5621) patch uploaded by rmudgett
Review: https://reviewboard.asterisk.org/r/1303/
JIRA SWP-3526
Modified:
branches/1.8/channels/chan_sip.c
branches/1.8/channels/sip/include/sip.h
Modified: branches/1.8/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/channels/chan_sip.c?view=diff&rev=326291&r1=326290&r2=326291
==============================================================================
--- branches/1.8/channels/chan_sip.c (original)
+++ branches/1.8/channels/chan_sip.c Tue Jul 5 12:22:59 2011
@@ -1106,9 +1106,10 @@
/*! \brief A per-thread temporary pvt structure */
AST_THREADSTORAGE_CUSTOM(ts_temp_pvt, temp_pvt_init, temp_pvt_cleanup);
-/*! \brief Authentication list for realm authentication
- * \todo Move the sip_auth list to AST_LIST */
-static struct sip_auth *authl = NULL;
+/*! \brief Authentication container for realm authentication */
+static struct sip_auth_container *authl = NULL;
+/*! \brief Global authentication container protection while adjusting the references. */
+AST_MUTEX_DEFINE_STATIC(authl_lock);
/* --- Sockets and networking --------------*/
@@ -1313,9 +1314,8 @@
static void clear_sip_domains(void);
/*--- SIP realm authentication */
-static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, const char *configuration, int lineno);
-static int clear_realm_authentication(struct sip_auth *authlist); /* Clear realm authentication list (at reload) */
-static struct sip_auth *find_realm_authentication(struct sip_auth *authlist, const char *realm);
+static void add_realm_authentication(struct sip_auth_container **credentials, const char *configuration, int lineno);
+static struct sip_auth *find_realm_authentication(struct sip_auth_container *credentials, const char *realm);
/*--- Misc functions */
static void check_rtp_timeout(struct sip_pvt *dialog, time_t t);
@@ -4578,8 +4578,10 @@
ast_debug(3, "-REALTIME- peer Destroyed. Name: %s. Realtime Peer objects: %d\n", peer->name, rpeerobjs);
} else
ast_atomic_fetchadd_int(&speerobjs, -1);
- clear_realm_authentication(peer->auth);
- peer->auth = NULL;
+ if (peer->auth) {
+ ao2_t_ref(peer->auth, -1, "Removing peer authentication");
+ peer->auth = NULL;
+ }
if (peer->dnsmgr)
ast_dnsmgr_release(peer->dnsmgr);
clear_peer_mailboxes(peer);
@@ -5077,6 +5079,8 @@
*/
static int create_addr_from_peer(struct sip_pvt *dialog, struct sip_peer *peer)
{
+ struct sip_auth_container *credentials;
+
/* this checks that the dialog is contacting the peer on a valid
* transport type based on the peers transport configuration,
* otherwise, this function bails out */
@@ -5165,7 +5169,21 @@
dialog->allowtransfer = peer->allowtransfer;
dialog->jointnoncodeccapability = dialog->noncodeccapability;
dialog->rtptimeout = peer->rtptimeout;
- dialog->peerauth = peer->auth;
+
+ /* Update dialog authorization credentials */
+ ao2_lock(peer);
+ credentials = peer->auth;
+ if (credentials) {
+ ao2_t_ref(credentials, +1, "Ref peer auth for dialog");
+ }
+ ao2_unlock(peer);
+ ao2_lock(dialog);
+ if (dialog->peerauth) {
+ ao2_t_ref(dialog->peerauth, -1, "Unref old dialog peer auth");
+ }
+ dialog->peerauth = credentials;
+ ao2_unlock(dialog);
+
dialog->maxcallbitrate = peer->maxcallbitrate;
dialog->disallowed_methods = peer->disallowed_methods;
ast_cc_copy_config_params(dialog->cc_params, peer->cc_params);
@@ -5691,6 +5709,11 @@
if (p->socket.tcptls_session) {
ao2_ref(p->socket.tcptls_session, -1);
p->socket.tcptls_session = NULL;
+ }
+
+ if (p->peerauth) {
+ ao2_t_ref(p->peerauth, -1, "Removing active peer authentication");
+ p->peerauth = NULL;
}
}
@@ -16763,7 +16786,6 @@
char codec_buf[512];
struct ast_codec_pref *pref;
struct ast_variable *v;
- struct sip_auth *auth;
int x = 0, load_realtime;
format_t codec = 0;
int realtimepeers;
@@ -16791,6 +16813,15 @@
}
if (peer && type==0 ) { /* Normal listing */
struct ast_str *mailbox_str = ast_str_alloca(512);
+ struct sip_auth_container *credentials;
+
+ ao2_lock(peer);
+ credentials = peer->auth;
+ if (credentials) {
+ ao2_t_ref(credentials, +1, "Ref peer auth for show");
+ }
+ ao2_unlock(peer);
+
ast_cli(fd, "\n\n");
ast_cli(fd, " * Name : %s\n", peer->name);
if (realtimepeers) { /* Realtime is enabled */
@@ -16799,9 +16830,19 @@
ast_cli(fd, " Secret : %s\n", ast_strlen_zero(peer->secret)?"<Not set>":"<Set>");
ast_cli(fd, " MD5Secret : %s\n", ast_strlen_zero(peer->md5secret)?"<Not set>":"<Set>");
ast_cli(fd, " Remote Secret: %s\n", ast_strlen_zero(peer->remotesecret)?"<Not set>":"<Set>");
- for (auth = peer->auth; auth; auth = auth->next) {
- ast_cli(fd, " Realm-auth : Realm %-15.15s User %-10.20s ", auth->realm, auth->username);
- ast_cli(fd, "%s\n", !ast_strlen_zero(auth->secret)?"<Secret set>":(!ast_strlen_zero(auth->md5secret)?"<MD5secret set>" : "<Not set>"));
+ if (credentials) {
+ struct sip_auth *auth;
+
+ AST_LIST_TRAVERSE(&credentials->list, auth, node) {
+ ast_cli(fd, " Realm-auth : Realm %-15.15s User %-10.20s %s\n",
+ auth->realm,
+ auth->username,
+ !ast_strlen_zero(auth->secret)
+ ? "<Secret set>"
+ : (!ast_strlen_zero(auth->md5secret)
+ ? "<MD5secret set>" : "<Not set>"));
+ }
+ ao2_t_ref(credentials, -1, "Unref peer auth for show");
}
ast_cli(fd, " Context : %s\n", peer->context);
ast_cli(fd, " Subscr.Cont. : %s\n", S_OR(peer->subscribecontext, "<Not set>") );
@@ -17357,6 +17398,7 @@
int realtimeregs;
char codec_buf[SIPBUFSIZE];
const char *msg; /* temporary msg pointer */
+ struct sip_auth_container *credentials;
switch (cmd) {
case CLI_INIT:
@@ -17369,12 +17411,19 @@
return NULL;
}
+ if (a->argc != 3)
+ return CLI_SHOWUSAGE;
realtimepeers = ast_check_realtime("sippeers");
realtimeregs = ast_check_realtime("sipregs");
- if (a->argc != 3)
- return CLI_SHOWUSAGE;
+ ast_mutex_lock(&authl_lock);
+ credentials = authl;
+ if (credentials) {
+ ao2_t_ref(credentials, +1, "Ref global auth for show");
+ }
+ ast_mutex_unlock(&authl_lock);
+
ast_cli(a->fd, "\n\nGlobal Settings:\n");
ast_cli(a->fd, "----------------\n");
ast_cli(a->fd, " UDP Bindaddress: %s\n", ast_sockaddr_stringify(&bindaddr));
@@ -17401,7 +17450,21 @@
ast_cli(a->fd, " Allow promisc. redir: %s\n", AST_CLI_YESNO(ast_test_flag(&global_flags[0], SIP_PROMISCREDIR)));
ast_cli(a->fd, " Enable call counters: %s\n", AST_CLI_YESNO(global_callcounter));
ast_cli(a->fd, " SIP domain support: %s\n", AST_CLI_YESNO(!AST_LIST_EMPTY(&domain_list)));
- ast_cli(a->fd, " Realm. auth: %s\n", AST_CLI_YESNO(authl != NULL));
+ ast_cli(a->fd, " Realm. auth: %s\n", AST_CLI_YESNO(credentials != NULL));
+ if (credentials) {
+ struct sip_auth *auth;
+
+ AST_LIST_TRAVERSE(&credentials->list, auth, node) {
+ ast_cli(a->fd, " Realm. auth entry: Realm %-15.15s User %-10.20s %s\n",
+ auth->realm,
+ auth->username,
+ !ast_strlen_zero(auth->secret)
+ ? "<Secret set>"
+ : (!ast_strlen_zero(auth->md5secret)
+ ? "<MD5secret set>" : "<Not set>"));
+ }
+ ao2_t_ref(credentials, -1, "Unref global auth for show");
+ }
ast_cli(a->fd, " Our auth realm %s\n", sip_cfg.realm);
ast_cli(a->fd, " Use domains as realms: %s\n", AST_CLI_YESNO(sip_cfg.domainsasrealm));
ast_cli(a->fd, " Call to non-local dom.: %s\n", AST_CLI_YESNO(sip_cfg.allow_external_domains));
@@ -18568,7 +18631,8 @@
const char *username;
const char *secret;
const char *md5secret;
- struct sip_auth *auth = NULL; /* Realm authentication */
+ struct sip_auth *auth; /* Realm authentication credential */
+ struct sip_auth_container *credentials;
if (!ast_strlen_zero(p->domain))
ast_copy_string(uri, p->domain, sizeof(uri));
@@ -18579,9 +18643,27 @@
snprintf(cnonce, sizeof(cnonce), "%08lx", ast_random());
- /* Check if we have separate auth credentials */
- if(!(auth = find_realm_authentication(p->peerauth, p->realm))) /* Start with peer list */
- auth = find_realm_authentication(authl, p->realm); /* If not, global list */
+ /* Check if we have peer credentials */
+ ao2_lock(p);
+ credentials = p->peerauth;
+ if (credentials) {
+ ao2_t_ref(credentials, +1, "Ref peer auth for digest");
+ }
+ ao2_unlock(p);
+ auth = find_realm_authentication(credentials, p->realm);
+ if (!auth) {
+ /* If not, check global credentials */
+ if (credentials) {
+ ao2_t_ref(credentials, -1, "Unref peer auth for digest");
+ }
+ ast_mutex_lock(&authl_lock);
+ credentials = authl;
+ if (credentials) {
+ ao2_t_ref(credentials, +1, "Ref global auth for digest");
+ }
+ ast_mutex_unlock(&authl_lock);
+ auth = find_realm_authentication(credentials, p->realm);
+ }
if (auth) {
ast_debug(3, "use realm [%s] from peer [%s][%s]\n", auth->username, p->peername, p->username);
@@ -18598,8 +18680,13 @@
? p->relatedpeer->remotesecret : p->peersecret;
md5secret = p->peermd5secret;
}
- if (ast_strlen_zero(username)) /* We have no authentication */
+ if (ast_strlen_zero(username)) {
+ /* We have no authentication */
+ if (credentials) {
+ ao2_t_ref(credentials, -1, "Unref auth for digest");
+ }
return -1;
+ }
/* Calculate SIP digest response */
snprintf(a1, sizeof(a1), "%s:%s:%s", username, p->realm, secret);
@@ -18630,6 +18717,9 @@
append_history(p, "AuthResp", "Auth response sent for %s in realm %s - nc %d", username, p->realm, p->noncecount);
+ if (credentials) {
+ ao2_t_ref(credentials, -1, "Unref auth for digest");
+ }
return 0;
}
@@ -26071,20 +26161,48 @@
AST_LIST_UNLOCK(&domain_list);
}
-
-/*! \brief Add realm authentication in list */
-static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, const char *configuration, int lineno)
-{
- char authcopy[256];
+/*!
+ * \internal
+ * \brief Realm authentication container destructor.
+ *
+ * \param obj Container object to destroy.
+ *
+ * \return Nothing
+ */
+static void destroy_realm_authentication(void *obj)
+{
+ struct sip_auth_container *credentials = obj;
+ struct sip_auth *auth;
+
+ while ((auth = AST_LIST_REMOVE_HEAD(&credentials->list, node))) {
+ ast_free(auth);
+ }
+}
+
+/*!
+ * \internal
+ * \brief Add realm authentication to credentials.
+ *
+ * \param credentials Realm authentication container to create/add authentication credentials.
+ * \param configuration Credential configuration value.
+ * \param lineno Line number in config file.
+ *
+ * \return Nothing
+ */
+static void add_realm_authentication(struct sip_auth_container **credentials, const char *configuration, int lineno)
+{
+ char *authcopy;
char *username=NULL, *realm=NULL, *secret=NULL, *md5secret=NULL;
- struct sip_auth *a, *b, *auth;
-
- if (ast_strlen_zero(configuration))
- return authlist;
+ struct sip_auth *auth;
+
+ if (ast_strlen_zero(configuration)) {
+ /* Nothing to add */
+ return;
+ }
ast_debug(1, "Auth config :: %s\n", configuration);
- ast_copy_string(authcopy, configuration, sizeof(authcopy));
+ authcopy = ast_strdupa(configuration);
username = authcopy;
/* split user[:secret] and relm */
@@ -26093,7 +26211,7 @@
*realm++ = '\0';
if (ast_strlen_zero(username) || ast_strlen_zero(realm)) {
ast_log(LOG_WARNING, "Format for authentication entry is user[:secret]@realm at line %d\n", lineno);
- return authlist;
+ return;
}
/* parse username at ':' for secret, or '#" for md5secret */
@@ -26103,9 +26221,21 @@
*md5secret++ = '\0';
}
- if (!(auth = ast_calloc(1, sizeof(*auth))))
- return authlist;
-
+ /* Create the continer if needed. */
+ if (!*credentials) {
+ *credentials = ao2_t_alloc(sizeof(**credentials), destroy_realm_authentication,
+ "Create realm auth container.");
+ if (!*credentials) {
+ /* Failed to create the credentials container. */
+ return;
+ }
+ }
+
+ /* Create the authentication credential entry. */
+ auth = ast_calloc(1, sizeof(*auth));
+ if (!auth) {
+ return;
+ }
ast_copy_string(auth->realm, realm, sizeof(auth->realm));
ast_copy_string(auth->username, username, sizeof(auth->username));
if (secret)
@@ -26113,46 +26243,36 @@
if (md5secret)
ast_copy_string(auth->md5secret, md5secret, sizeof(auth->md5secret));
- /* find the end of the list */
- for (b = NULL, a = authlist; a ; b = a, a = a->next)
- ;
- if (b)
- b->next = auth; /* Add structure add end of list */
- else
- authlist = auth;
+ /* Add credential to container list. */
+ AST_LIST_INSERT_TAIL(&(*credentials)->list, auth, node);
ast_verb(3, "Added authentication for realm %s\n", realm);
-
- return authlist;
-
-}
-
-/*! \brief Clear realm authentication list (at reload) */
-static int clear_realm_authentication(struct sip_auth *authlist)
-{
- struct sip_auth *a = authlist;
- struct sip_auth *b;
-
- while (a) {
- b = a;
- a = a->next;
- ast_free(b);
- }
-
- return 1;
-}
-
-/*! \brief Find authentication for a specific realm */
-static struct sip_auth *find_realm_authentication(struct sip_auth *authlist, const char *realm)
-{
- struct sip_auth *a;
-
- for (a = authlist; a; a = a->next) {
- if (!strcasecmp(a->realm, realm))
- break;
- }
-
- return a;
+}
+
+/*!
+ * \internal
+ * \brief Find authentication for a specific realm.
+ *
+ * \param credentials Realm authentication container to search.
+ * \param realm Authentication realm to find.
+ *
+ * \return Found authentication credential or NULL.
+ */
+static struct sip_auth *find_realm_authentication(struct sip_auth_container *credentials, const char *realm)
+{
+ struct sip_auth *auth;
+
+ if (credentials) {
+ AST_LIST_TRAVERSE(&credentials->list, auth, node) {
+ if (!strcasecmp(auth->realm, realm)) {
+ break;
+ }
+ }
+ } else {
+ auth = NULL;
+ }
+
+ return auth;
}
/*! \brief
@@ -26387,8 +26507,13 @@
peer->portinuri = 0;
/* If we have realm authentication information, remove them (reload) */
- clear_realm_authentication(peer->auth);
- peer->auth = NULL;
+ ao2_lock(peer);
+ if (peer->auth) {
+ ao2_t_ref(peer->auth, -1, "Removing old peer authentication");
+ peer->auth = NULL;
+ }
+ ao2_unlock(peer);
+
/* clear the transport information. We will detect if a default value is required after parsing the config */
peer->default_outbound_transport = 0;
peer->transports = 0;
@@ -26450,7 +26575,7 @@
} else if (!strcasecmp(v->name, "md5secret")) {
ast_string_field_set(peer, md5secret, v->value);
} else if (!strcasecmp(v->name, "auth")) {
- peer->auth = add_realm_authentication(peer->auth, v->value, v->lineno);
+ add_realm_authentication(&peer->auth, v->value, v->lineno);
} else if (!strcasecmp(v->name, "callerid")) {
char cid_name[80] = { '\0' }, cid_num[80] = { '\0' };
@@ -27044,9 +27169,13 @@
if (reason != CHANNEL_MODULE_LOAD) {
ast_debug(4, "--------------- SIP reload started\n");
- clear_realm_authentication(authl);
clear_sip_domains();
- authl = NULL;
+ ast_mutex_lock(&authl_lock);
+ if (authl) {
+ ao2_t_ref(authl, -1, "Removing old global authentication");
+ authl = NULL;
+ }
+ ast_mutex_unlock(&authl_lock);
/* First, destroy all outstanding registry calls */
/* This is needed, since otherwise active registry entries will not be destroyed */
@@ -27764,12 +27893,12 @@
}
/* Build list of authentication to various SIP realms, i.e. service providers */
- for (v = ast_variable_browse(cfg, "authentication"); v ; v = v->next) {
- /* Format for authentication is auth = username:password at realm */
- if (!strcasecmp(v->name, "auth")) {
- authl = add_realm_authentication(authl, v->value, v->lineno);
- }
- }
+ for (v = ast_variable_browse(cfg, "authentication"); v ; v = v->next) {
+ /* Format for authentication is auth = username:password at realm */
+ if (!strcasecmp(v->name, "auth")) {
+ add_realm_authentication(&authl, v->value, v->lineno);
+ }
+ }
if (bindport) {
if (ast_sockaddr_port(&bindaddr)) {
@@ -29533,7 +29662,12 @@
/* Free memory for local network address mask */
ast_free_ha(localaddr);
- clear_realm_authentication(authl);
+ ast_mutex_lock(&authl_lock);
+ if (authl) {
+ ao2_t_ref(authl, -1, "Removing global authentication");
+ authl = NULL;
+ }
+ ast_mutex_unlock(&authl_lock);
destroy_escs();
Modified: branches/1.8/channels/sip/include/sip.h
URL: http://svnview.digium.com/svn/asterisk/branches/1.8/channels/sip/include/sip.h?view=diff&rev=326291&r1=326290&r2=326291
==============================================================================
--- branches/1.8/channels/sip/include/sip.h (original)
+++ branches/1.8/channels/sip/include/sip.h Tue Jul 5 12:22:59 2011
@@ -824,11 +824,16 @@
/*! \brief sip_auth: Credentials for authentication to other SIP services */
struct sip_auth {
+ AST_LIST_ENTRY(sip_auth) node;
char realm[AST_MAX_EXTENSION]; /*!< Realm in which these credentials are valid */
char username[256]; /*!< Username */
char secret[256]; /*!< Secret */
char md5secret[256]; /*!< MD5Secret */
- struct sip_auth *next; /*!< Next auth structure in list */
+};
+
+/*! \brief Container of SIP authentication credentials. */
+struct sip_auth_container {
+ AST_LIST_HEAD_NOLOCK(, sip_auth) list;
};
/*! \brief T.38 channel settings (at some point we need to make this alloc'ed */
@@ -1039,7 +1044,7 @@
struct ast_channel *owner; /*!< Who owns us (if we have an owner) */
struct sip_route *route; /*!< Head of linked list of routing steps (fm Record-Route) */
struct sip_notify *notify; /*!< Custom notify type */
- struct sip_auth *peerauth; /*!< Realm authentication */
+ struct sip_auth_container *peerauth;/*!< Realm authentication credentials */
int noncecount; /*!< Nonce-count */
unsigned int stalenonce:1; /*!< Marks the current nonce as responded too */
char lastmsg[256]; /*!< Last Message sent/received */
@@ -1200,7 +1205,7 @@
* for incoming calls
*/
unsigned short deprecated_username:1; /*!< If it's a realtime peer, are they using the deprecated "username" instead of "defaultuser" */
- struct sip_auth *auth; /*!< Realm authentication list */
+ struct sip_auth_container *auth;/*!< Realm authentication credentials */
int amaflags; /*!< AMA Flags (for billing) */
int callingpres; /*!< Calling id presentation */
int inUse; /*!< Number of calls in use */
More information about the asterisk-commits
mailing list