[asterisk-commits] oej: branch oej/manager-check-trunk r326367 - in /team/oej/manager-check-trun...

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Tue Jul 5 14:26:01 CDT 2011


Author: oej
Date: Tue Jul  5 14:25:56 2011
New Revision: 326367

URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=326367
Log:
Reset resolve be happy. Eat ice cream and drink Formosa Oolong.

Modified:
    team/oej/manager-check-trunk/   (props changed)
    team/oej/manager-check-trunk/CHANGES
    team/oej/manager-check-trunk/channels/chan_sip.c
    team/oej/manager-check-trunk/channels/sip/include/sip.h
    team/oej/manager-check-trunk/main/manager.c

Propchange: team/oej/manager-check-trunk/
------------------------------------------------------------------------------
    automerge = http://www.codename-pineapple.org/

Propchange: team/oej/manager-check-trunk/
------------------------------------------------------------------------------
Binary property 'branch-1.8-merged' - no diff available.

Propchange: team/oej/manager-check-trunk/
------------------------------------------------------------------------------
--- svnmerge-integrated (original)
+++ svnmerge-integrated Tue Jul  5 14:25:56 2011
@@ -1,1 +1,1 @@
-/trunk:1-326243
+/trunk:1-326330

Modified: team/oej/manager-check-trunk/CHANGES
URL: http://svnview.digium.com/svn/asterisk/team/oej/manager-check-trunk/CHANGES?view=diff&rev=326367&r1=326366&r2=326367
==============================================================================
--- team/oej/manager-check-trunk/CHANGES (original)
+++ team/oej/manager-check-trunk/CHANGES Tue Jul  5 14:25:56 2011
@@ -41,6 +41,9 @@
    Description field that is set by 'description' in the channel configuration
    file.
  * Added Uniqueid header to UserEvent.
+ * Added new action FilterAdd to control event filters for the current session.
+   This requires the system permission and uses the same filter syntax as
+   filters that can be defined in manager.conf
 
 Asterisk HTTP Server
 --------------------------

Modified: team/oej/manager-check-trunk/channels/chan_sip.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/manager-check-trunk/channels/chan_sip.c?view=diff&rev=326367&r1=326366&r2=326367
==============================================================================
--- team/oej/manager-check-trunk/channels/chan_sip.c (original)
+++ team/oej/manager-check-trunk/channels/chan_sip.c Tue Jul  5 14:25:56 2011
@@ -1121,9 +1121,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 --------------*/
 
@@ -1329,9 +1330,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);
@@ -4615,8 +4615,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);
@@ -5117,6 +5119,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 */
@@ -5205,7 +5209,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);
@@ -5732,6 +5750,12 @@
 		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;
+	}
+
 	p->caps = ast_format_cap_destroy(p->caps);
 	p->jointcaps = ast_format_cap_destroy(p->jointcaps);
 	p->peercaps = ast_format_cap_destroy(p->peercaps);
@@ -17227,7 +17251,6 @@
 	char codec_buf[512];
 	struct ast_codec_pref *pref;
 	struct ast_variable *v;
-	struct sip_auth *auth;
 	int x = 0, load_realtime;
 	struct ast_format codec;
 	int realtimepeers;
@@ -17255,6 +17278,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);
 		ast_cli(fd, "  Description  : %s\n", peer->description);
@@ -17264,9 +17296,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>") );
@@ -17823,6 +17865,7 @@
 	int realtimeregs;
 	char codec_buf[SIPBUFSIZE];
 	const char *msg;	/* temporary msg pointer */
+	struct sip_auth_container *credentials;
 
 	switch (cmd) {
 	case CLI_INIT:
@@ -17835,12 +17878,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));
@@ -17867,7 +17917,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));
@@ -19065,7 +19129,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));
@@ -19076,9 +19141,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);
@@ -19095,8 +19178,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);
@@ -19127,6 +19215,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;
 }
 	
@@ -26715,20 +26806,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 */
@@ -26737,7 +26856,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 */
@@ -26747,9 +26866,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)
@@ -26757,46 +26888,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
@@ -27042,8 +27163,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;
@@ -27107,7 +27233,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' };
 
@@ -27719,9 +27845,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 */
@@ -28450,12 +28580,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)) {
@@ -30243,7 +30373,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: team/oej/manager-check-trunk/channels/sip/include/sip.h
URL: http://svnview.digium.com/svn/asterisk/team/oej/manager-check-trunk/channels/sip/include/sip.h?view=diff&rev=326367&r1=326366&r2=326367
==============================================================================
--- team/oej/manager-check-trunk/channels/sip/include/sip.h (original)
+++ team/oej/manager-check-trunk/channels/sip/include/sip.h Tue Jul  5 14:25:56 2011
@@ -829,11 +829,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 */
@@ -1046,7 +1051,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 */
@@ -1209,7 +1214,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 */

Modified: team/oej/manager-check-trunk/main/manager.c
URL: http://svnview.digium.com/svn/asterisk/team/oej/manager-check-trunk/main/manager.c?view=diff&rev=326367&r1=326366&r2=326367
==============================================================================
--- team/oej/manager-check-trunk/main/manager.c (original)
+++ team/oej/manager-check-trunk/main/manager.c Tue Jul  5 14:25:56 2011
@@ -832,6 +832,52 @@
 			</para>
 		</description>
 	</function>
+	<manager name="Filter" language="en_US">
+		<synopsis>
+			Dynamically add filters for the current manager session.
+		</synopsis>
+		<syntax>
+			<xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
+			<parameter name="Operation">
+				<enumlist>
+					<enum name="Add">
+						<para>Add a filter.</para>
+					</enum>
+				</enumlist>
+			</parameter>
+			<parameter name="Filter">
+				<para>Filters can be whitelist or blacklist</para>
+				<para>Example whitelist filter: "Event: Newchannel"</para>
+				<para>Example blacklist filter: "!Channel: DAHDI.*"</para>
+				<para>This filter option is used to whitelist or blacklist events per user to be
+				reported with regular expressions and are allowed if both the regex matches
+				and the user has read access as defined in manager.conf. Filters are assumed to be for whitelisting
+				unless preceeded by an exclamation point, which marks it as being black.
+				Evaluation of the filters is as follows:</para>
+				<para>- If no filters are configured all events are reported as normal.</para>
+				<para>- If there are white filters only: implied black all filter processed first, then white filters.</para>
+				<para>- If there are black filters only: implied white all filter processed first, then black filters.</para>
+				<para>- If there are both white and black filters: implied black all filter processed first, then white
+				filters, and lastly black filters.</para>
+			</parameter>
+		</syntax>
+		<description>
+			<para>The filters added are only used for the current session.
+			Once the connection is closed the filters are removed.</para>
+			<para>This comand requires the system permission because
+			this command can be used to create filters that may bypass
+			filters defined in manager.conf</para>
+		</description>
+	</manager>
+	<manager name="FilterList" language="en_US">
+		<synopsis>
+			Show current event filters for this session
+		</synopsis>
+		<description>
+			<para>The filters displayed are for the current session.  Only those filters defined in
+                        manager.conf will be present upon starting a new session.</para>
+		</description>
+	</manager>
  ***/
 
 enum error_type {
@@ -848,6 +894,11 @@
 	FAILURE_APPEND
 };
 
+enum add_filter_result {
+	FILTER_SUCCESS,
+        FILTER_ALLOC_FAILED,
+        FILTER_COMPILE_FAIL,
+};
 
 /*!
  * Linked list of events.
@@ -1039,6 +1090,8 @@
 
 static void free_channelvars(void);
 
+static enum add_filter_result manager_add_filter(const char *filter_pattern, struct ao2_container *whitefilters, struct ao2_container *blackfilters);
+
 /*! \brief Add a custom hook to be called when an event is fired */
 void ast_manager_register_hook(struct manager_custom_hook *hook)
 {
@@ -4142,6 +4195,88 @@
 	return 0;
 }
 
+/*
+ * \brief Manager command to add an event filter to a manager session
+ * \see For more details look at manager_add_filter
+ */
+static int action_filter(struct mansession *s, const struct message *m)
+{
+	const char *filter = astman_get_header(m, "Filter");
+        const char *operation = astman_get_header(m, "Operation");
+        int res;
+
+        if (!strcasecmp(operation, "Add")) {
+		res = manager_add_filter(filter, s->session->whitefilters, s->session->blackfilters);
+
+	        if (res != FILTER_SUCCESS) {
+		        if (res == FILTER_ALLOC_FAILED) {
+				astman_send_error(s, m, "Internal Error. Failed to allocate regex for filter");
+		                return 0;
+		        } else if (res == FILTER_COMPILE_FAIL) {
+				astman_send_error(s, m, "Filter did not compile.  Check the syntax of the filter given.");
+		                return 0;
+		        } else {
+				astman_send_error(s, m, "Internal Error. Failed adding filter.");
+		                return 0;
+	                }
+		}
+
+		astman_send_ack(s, m, "Success");
+                return 0;
+        }
+
+	astman_send_error(s, m, "Unknown operation");
+	return 0;
+}
+
+/*
+ * \brief Add an event filter to a manager session
+ *
+ * \param s               manager session to modify filters on
+ * \param filter_pattern  Filter syntax to add, see below for syntax
+ *
+ * \return FILTER_ALLOC_FAILED   Memory allocation failure
+ * \return FILTER_COMPILE_FAIL   If the filter did not compile
+ * \return FILTER_SUCCESS        Success
+ *
+ * Filter will be used to match against each line of a manager event
+ * Filter can be any valid regular expression
+ * Filter can be a valid regular expression prefixed with !, which will add the filter as a black filter
+ *
+ * \example filter_pattern = "Event: Newchannel"
+ * \example filter_pattern = "Event: New.*"
+ * \example filter_pattern = "!Channel: DAHDI.*"
+ *
+ */
+static enum add_filter_result manager_add_filter(const char *filter_pattern, struct ao2_container *whitefilters, struct ao2_container *blackfilters) {
+	regex_t *new_filter = ao2_t_alloc(sizeof(*new_filter), event_filter_destructor, "event_filter allocation");
+	int is_blackfilter;
+
+	if (!new_filter) {
+		return FILTER_ALLOC_FAILED;
+	}
+
+	if (filter_pattern[0] == '!') {
+		is_blackfilter = 1;
+		filter_pattern++;
+	} else {
+		is_blackfilter = 0;
+	}
+
+	if (regcomp(new_filter, filter_pattern, 0)) {
+		ao2_t_ref(new_filter, -1, "failed to make regx");
+		return FILTER_COMPILE_FAIL;
+	}
+
+	if (is_blackfilter) {
+		ao2_t_link(blackfilters, new_filter, "link new filter into black user container");
+	} else {
+		ao2_t_link(whitefilters, new_filter, "link new filter into white user container");
+	}
+
+        return FILTER_SUCCESS;
+}
+
 static int match_filter(struct mansession *s, char *eventdata)
 {
 	int result = 0;
@@ -6372,6 +6507,7 @@
 		ast_manager_register_xml("ModuleLoad", EVENT_FLAG_SYSTEM, manager_moduleload);
 		ast_manager_register_xml("ModuleCheck", EVENT_FLAG_SYSTEM, manager_modulecheck);
 		ast_manager_register_xml("AOCMessage", EVENT_FLAG_AOC, action_aocmessage);
+		ast_manager_register_xml("Filter", EVENT_FLAG_SYSTEM, action_filter);
 
 		ast_cli_register_multiple(cli_manager, ARRAY_LEN(cli_manager));
 		__ast_custom_function_register(&managerclient_function, NULL);
@@ -6652,25 +6788,7 @@
 				}
 			} else if (!strcasecmp(var->name, "eventfilter")) {
 				const char *value = var->value;
-				regex_t *new_filter = ao2_t_alloc(sizeof(*new_filter), event_filter_destructor, "event_filter allocation");
-				if (new_filter) {
-					int is_blackfilter;
-					if (value[0] == '!') {
-						is_blackfilter = 1;
-						value++;
-					} else {
-						is_blackfilter = 0;
-					}
-					if (regcomp(new_filter, value, 0)) {
-						ao2_t_ref(new_filter, -1, "failed to make regx");
-					} else {
-						if (is_blackfilter) {
-							ao2_t_link(user->blackfilters, new_filter, "link new filter into black user container");
-						} else {
-							ao2_t_link(user->whitefilters, new_filter, "link new filter into white user container");
-						}
-					}
-				}
+                                manager_add_filter(value, user->whitefilters, user->blackfilters);
 			} else {
 				ast_debug(1, "%s is an unknown option.\n", var->name);
 			}




More information about the asterisk-commits mailing list