Merge "Restrict CLI/AMI commands on shutdown." into 13

changes/64/2464/2
zuul 9 years ago committed by Gerrit Code Review
commit 8271a06dde

@ -310,6 +310,18 @@ char **ast_cli_completion_matches(const char *, const char *);
*/
char *ast_complete_channels(const char *line, const char *word, int pos, int state, int rpos);
/*!
* \brief Allow a CLI command to be executed while Asterisk is shutting down.
*
* CLI commands by defeault are disabled when Asterisk is shutting down. This is
* to ensure the safety of the shutdown since CLI commands may attempt to access
* resources that have been freed as a result of the shutdown.
*
* If a CLI command should be allowed at shutdown, then the best way to enable this
* is to call ast_cli_allow_at_shutdown during the CLI_INIT state of the CLI handler.
*/
int ast_cli_allow_at_shutdown(struct ast_cli_entry *e);
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif

@ -2441,6 +2441,7 @@ static char *handle_stop_now(struct ast_cli_entry *e, int cmd, struct ast_cli_ar
e->usage =
"Usage: core stop now\n"
" Shuts down a running Asterisk immediately, hanging up all active calls .\n";
ast_cli_allow_at_shutdown(e);
return NULL;
case CLI_GENERATE:
return NULL;
@ -2461,6 +2462,7 @@ static char *handle_stop_gracefully(struct ast_cli_entry *e, int cmd, struct ast
"Usage: core stop gracefully\n"
" Causes Asterisk to not accept new calls, and exit when all\n"
" active calls have terminated normally.\n";
ast_cli_allow_at_shutdown(e);
return NULL;
case CLI_GENERATE:
return NULL;
@ -2480,6 +2482,7 @@ static char *handle_stop_when_convenient(struct ast_cli_entry *e, int cmd, struc
e->usage =
"Usage: core stop when convenient\n"
" Causes Asterisk to perform a shutdown when all active calls have ended.\n";
ast_cli_allow_at_shutdown(e);
return NULL;
case CLI_GENERATE:
return NULL;
@ -2501,6 +2504,7 @@ static char *handle_restart_now(struct ast_cli_entry *e, int cmd, struct ast_cli
"Usage: core restart now\n"
" Causes Asterisk to hangup all calls and exec() itself performing a cold\n"
" restart.\n";
ast_cli_allow_at_shutdown(e);
return NULL;
case CLI_GENERATE:
return NULL;
@ -2521,6 +2525,7 @@ static char *handle_restart_gracefully(struct ast_cli_entry *e, int cmd, struct
"Usage: core restart gracefully\n"
" Causes Asterisk to stop accepting new calls and exec() itself performing a cold\n"
" restart when all active calls have ended.\n";
ast_cli_allow_at_shutdown(e);
return NULL;
case CLI_GENERATE:
return NULL;
@ -2540,6 +2545,7 @@ static char *handle_restart_when_convenient(struct ast_cli_entry *e, int cmd, st
e->usage =
"Usage: core restart when convenient\n"
" Causes Asterisk to perform a cold restart when all active calls have ended.\n";
ast_cli_allow_at_shutdown(e);
return NULL;
case CLI_GENERATE:
return NULL;
@ -2561,6 +2567,7 @@ static char *handle_abort_shutdown(struct ast_cli_entry *e, int cmd, struct ast_
"Usage: core abort shutdown\n"
" Causes Asterisk to abort an executing shutdown or restart, and resume normal\n"
" call operations.\n";
ast_cli_allow_at_shutdown(e);
return NULL;
case CLI_GENERATE:
return NULL;

@ -63,6 +63,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
#include "asterisk/bridge.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/stasis_bridges.h"
#include "asterisk/vector.h"
/*!
* \brief List of restrictions per user.
@ -109,6 +110,9 @@ static struct module_level_list debug_modules = AST_RWLIST_HEAD_INIT_VALUE;
AST_THREADSTORAGE(ast_cli_buf);
AST_RWLOCK_DEFINE_STATIC(shutdown_commands_lock);
static AST_VECTOR(, struct ast_cli_entry *) shutdown_commands;
/*! \brief Initial buffer size for resulting strings in ast_cli() */
#define AST_CLI_INITLEN 256
@ -2030,6 +2034,7 @@ static void cli_shutdown(void)
/*! \brief initialize the _full_cmd string in * each of the builtins. */
void ast_builtins_init(void)
{
AST_VECTOR_INIT(&shutdown_commands, 0);
ast_cli_register_multiple(cli_cli, ARRAY_LEN(cli_cli));
ast_register_cleanup(cli_shutdown);
}
@ -2208,6 +2213,13 @@ static int cli_is_registered(struct ast_cli_entry *e)
return 0;
}
static void remove_shutdown_command(struct ast_cli_entry *e)
{
ast_rwlock_wrlock(&shutdown_commands_lock);
AST_VECTOR_REMOVE_ELEM_UNORDERED(&shutdown_commands, e, AST_VECTOR_ELEM_CLEANUP_NOOP);
ast_rwlock_unlock(&shutdown_commands_lock);
}
static int __ast_cli_unregister(struct ast_cli_entry *e, struct ast_cli_entry *ed)
{
if (e->inuse) {
@ -2216,6 +2228,7 @@ static int __ast_cli_unregister(struct ast_cli_entry *e, struct ast_cli_entry *e
AST_RWLIST_WRLOCK(&helpers);
AST_RWLIST_REMOVE(&helpers, e, list);
AST_RWLIST_UNLOCK(&helpers);
remove_shutdown_command(e);
ast_free(e->_full_cmd);
e->_full_cmd = NULL;
if (e->handler) {
@ -2679,10 +2692,27 @@ char *ast_cli_generator(const char *text, const char *word, int state)
return __ast_cli_generator(text, word, state, 1);
}
static int allowed_on_shutdown(struct ast_cli_entry *e)
{
int found = 0;
int i;
ast_rwlock_rdlock(&shutdown_commands_lock);
for (i = 0; i < AST_VECTOR_SIZE(&shutdown_commands); ++i) {
if (e == AST_VECTOR_GET(&shutdown_commands, i)) {
found = 1;
break;
}
}
ast_rwlock_unlock(&shutdown_commands_lock);
return found;
}
int ast_cli_command_full(int uid, int gid, int fd, const char *s)
{
const char *args[AST_MAX_ARGS + 1];
struct ast_cli_entry *e;
struct ast_cli_entry *e = NULL;
int x;
char *duplicate = parse_args(s, &x, args + 1, AST_MAX_ARGS, NULL);
char tmp[AST_MAX_ARGS + 1];
@ -2706,12 +2736,16 @@ int ast_cli_command_full(int uid, int gid, int fd, const char *s)
goto done;
}
if (ast_shutting_down() && !allowed_on_shutdown(e)) {
ast_cli(fd, "Command '%s' cannot be run during shutdown\n", s);
goto done;
}
ast_join(tmp, sizeof(tmp), args + 1);
/* Check if the user has rights to run this command. */
if (!cli_has_permissions(uid, gid, tmp)) {
ast_cli(fd, "You don't have permissions to run '%s' command\n", tmp);
ast_free(duplicate);
return 0;
goto done;
}
/*
@ -2728,8 +2762,11 @@ int ast_cli_command_full(int uid, int gid, int fd, const char *s)
if (retval == CLI_FAILURE)
ast_cli(fd, "Command '%s' failed.\n", s);
}
ast_atomic_fetchadd_int(&e->inuse, -1);
done:
if (e) {
ast_atomic_fetchadd_int(&e->inuse, -1);
}
ast_free(duplicate);
return 0;
}
@ -2750,3 +2787,14 @@ int ast_cli_command_multiple_full(int uid, int gid, int fd, size_t size, const c
}
return count;
}
int ast_cli_allow_at_shutdown(struct ast_cli_entry *e)
{
int res;
ast_rwlock_wrlock(&shutdown_commands_lock);
res = AST_VECTOR_APPEND(&shutdown_commands, e);
ast_rwlock_unlock(&shutdown_commands_lock);
return res;
}

@ -6114,6 +6114,14 @@ static int process_message(struct mansession *s, const struct message *m)
return 0;
}
if (ast_shutting_down()) {
ast_log(LOG_ERROR, "Unable to process manager action '%s'. Asterisk is shutting down.\n", action);
mansession_lock(s);
astman_send_error(s, m, "Asterisk is shutting down");
mansession_unlock(s);
return 0;
}
if (!s->session->authenticated
&& strcasecmp(action, "Login")
&& strcasecmp(action, "Logoff")

@ -1158,6 +1158,7 @@ static char *handle_show_locks(struct ast_cli_entry *e, int cmd, struct ast_cli_
"Usage: core show locks\n"
" This command is for lock debugging. It prints out which locks\n"
"are owned by each active thread.\n";
ast_cli_allow_on_shutdown(e);
return NULL;
case CLI_GENERATE:

Loading…
Cancel
Save