]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
manager.c: Add CLI command to kick AMI sessions.
authorNaveen Albert <asterisk@phreaknet.org>
Wed, 6 Dec 2023 17:01:49 +0000 (12:01 -0500)
committerAsterisk Development Team <asteriskteam@digium.com>
Thu, 9 May 2024 13:48:09 +0000 (13:48 +0000)
This adds a CLI command that can be used to manually
kick specific AMI sessions.

Resolves: #485

UserNote: The "manager kick session" CLI command now
allows kicking a specified AMI session.

(cherry picked from commit f4fba80708b226771581cb8c82abaaa2d65a13a9)

main/manager.c

index 20b434f1eb8bfe438f54ae448b258f62f9ba9bba..7461c46d5263c589a1d8f87af231b6c5b55f7e23 100644 (file)
@@ -1728,6 +1728,7 @@ struct mansession_session {
        time_t noncetime;       /*!< Timer for nonce value expiration */
        unsigned long oldnonce; /*!< Stale nonce value */
        unsigned long nc;       /*!< incremental  nonce counter */
+       unsigned int kicked:1;  /*!< Flag set if session is forcibly kicked */
        ast_mutex_t notify_lock; /*!< Lock for notifying this session of events */
        AST_LIST_HEAD_NOLOCK(mansession_datastores, ast_datastore) datastores; /*!< Data stores on the session */
        AST_LIST_ENTRY(mansession_session) list;
@@ -2772,6 +2773,76 @@ static char *handle_showmancmds(struct ast_cli_entry *e, int cmd, struct ast_cli
        return CLI_SUCCESS;
 }
 
+/*! \brief CLI command manager kick session */
+static char *handle_kickmanconn(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+       struct ao2_container *sessions;
+       struct mansession_session *session;
+       struct ao2_iterator i;
+       int fd = -1;
+       int found = 0;
+
+       switch (cmd) {
+       case CLI_INIT:
+               e->command = "manager kick session";
+               e->usage =
+                       "Usage: manager kick session <file descriptor>\n"
+                       "       Kick an active Asterisk Manager Interface session\n";
+               return NULL;
+       case CLI_GENERATE:
+               return NULL;
+       }
+
+       if (a->argc != 4) {
+               return CLI_SHOWUSAGE;
+       }
+
+       fd = atoi(a->argv[3]);
+       if (fd <= 0) { /* STDOUT won't be a valid AMI fd either */
+               ast_cli(a->fd, "Invalid AMI file descriptor: %s\n", a->argv[3]);
+               return CLI_FAILURE;
+       }
+
+       sessions = ao2_global_obj_ref(mgr_sessions);
+       if (sessions) {
+               i = ao2_iterator_init(sessions, 0);
+               ao2_ref(sessions, -1);
+               while ((session = ao2_iterator_next(&i))) {
+                       ao2_lock(session);
+                       if (session->stream) {
+                               if (ast_iostream_get_fd(session->stream) == fd) {
+                                       if (session->kicked) {
+                                               ast_cli(a->fd, "Manager session using file descriptor %d has already been kicked\n", fd);
+                                               ao2_unlock(session);
+                                               unref_mansession(session);
+                                               break;
+                                       }
+                                       fd = ast_iostream_get_fd(session->stream);
+                                       found = fd;
+                                       ast_cli(a->fd, "Kicking manager session connected using file descriptor %d\n", fd);
+                                       ast_mutex_lock(&session->notify_lock);
+                                       session->kicked = 1;
+                                       if (session->waiting_thread != AST_PTHREADT_NULL) {
+                                               pthread_kill(session->waiting_thread, SIGURG);
+                                       }
+                                       ast_mutex_unlock(&session->notify_lock);
+                                       ao2_unlock(session);
+                                       unref_mansession(session);
+                                       break;
+                               }
+                       }
+                       ao2_unlock(session);
+                       unref_mansession(session);
+               }
+               ao2_iterator_destroy(&i);
+       }
+
+       if (!found) {
+               ast_cli(a->fd, "No manager session found using file descriptor %d\n", fd);
+       }
+       return CLI_SUCCESS;
+}
+
 /*! \brief CLI command manager list connected */
 static char *handle_showmanconn(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
@@ -7465,6 +7536,10 @@ static int get_input(struct mansession *s, char *output)
                ast_mutex_unlock(&s->session->notify_lock);
        }
        if (res < 0) {
+               if (s->session->kicked) {
+                       ast_debug(1, "Manager session has been kicked\n");
+                       return -1;
+               }
                /* If we get a signal from some other thread (typically because
                 * there are new events queued), return 0 to notify the caller.
                 */
@@ -7664,7 +7739,7 @@ static void *session_do(void *data)
 
        astman_append(&s, "Asterisk Call Manager/%s\r\n", AMI_VERSION); /* welcome prompt */
        for (;;) {
-               if ((res = do_message(&s)) < 0 || s.write_error) {
+               if ((res = do_message(&s)) < 0 || s.write_error || session->kicked) {
                        break;
                }
                if (session->authenticated) {
@@ -7674,7 +7749,7 @@ static void *session_do(void *data)
        /* session is over, explain why and terminate */
        if (session->authenticated) {
                if (manager_displayconnects(session)) {
-                       ast_verb(2, "Manager '%s' logged off from %s\n", session->username, ast_sockaddr_stringify_addr(&session->addr));
+                       ast_verb(2, "Manager '%s' %s from %s\n", session->username, session->kicked ? "kicked" : "logged off", ast_sockaddr_stringify_addr(&session->addr));
                }
        } else {
                ast_atomic_fetchadd_int(&unauth_sessions, -1);
@@ -9591,6 +9666,7 @@ static struct ast_cli_entry cli_manager[] = {
        AST_CLI_DEFINE(handle_showmancmd, "Show a manager interface command"),
        AST_CLI_DEFINE(handle_showmancmds, "List manager interface commands"),
        AST_CLI_DEFINE(handle_showmanconn, "List connected manager interface users"),
+       AST_CLI_DEFINE(handle_kickmanconn, "Kick a connected manager interface connection"),
        AST_CLI_DEFINE(handle_showmaneventq, "List manager interface queued events"),
        AST_CLI_DEFINE(handle_showmanagers, "List configured manager users"),
        AST_CLI_DEFINE(handle_showmanager, "Display information on a specific manager user"),