Skip to content
Snippets Groups Projects
cli.c 76.5 KiB
Newer Older
Mark Spencer's avatar
Mark Spencer committed
/*
 * Asterisk -- An open source telephony toolkit.
Mark Spencer's avatar
Mark Spencer committed
 *
 * Copyright (C) 1999 - 2006, Digium, Inc.
Mark Spencer's avatar
Mark Spencer committed
 *
 * Mark Spencer <markster@digium.com>
Mark Spencer's avatar
Mark Spencer committed
 *
 * See http://www.asterisk.org for more information about
 * the Asterisk project. Please do not directly contact
 * any of the maintainers of this project for assistance;
 * the project provides a web site, mailing lists and IRC
 * channels for your use.
 *
Mark Spencer's avatar
Mark Spencer committed
 * This program is free software, distributed under the terms of
 * the GNU General Public License Version 2. See the LICENSE file
 * at the top of the source tree.
 */

 * \brief Standard Command Line Interface
 * \author Mark Spencer <markster@digium.com>
/*! \li \ref cli.c uses the configuration file \ref cli_permissions.conf
 * \addtogroup configuration_file Configuration Files
 */

/*!
 * \page cli_permissions.conf cli_permissions.conf
 * \verbinclude cli_permissions.conf.sample
 */

/*** MODULEINFO
	<support_level>core</support_level>
 ***/

#include "asterisk.h"

ASTERISK_FILE_VERSION(__FILE__, "$Revision$")

#include "asterisk/_private.h"
#include "asterisk/paths.h"	/* use ast_config_AST_MODULE_DIR */
#include <sys/signal.h>
#include <signal.h>
#include <ctype.h>
#include <pwd.h>
#include <grp.h>
#include "asterisk/linkedlists.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/channel.h"
#include "asterisk/utils.h"
#include "asterisk/threadstorage.h"
#include "asterisk/translate.h"
#include "asterisk/bridge.h"
#include "asterisk/stasis_channels.h"
#include "asterisk/stasis_bridges.h"
#include "asterisk/vector.h"
/*!
 * \brief List of restrictions per user.
 */
struct cli_perm {
	unsigned int permit:1;				/*!< 1=Permit 0=Deny */
	char *command;				/*!< Command name (to apply restrictions) */
	AST_LIST_ENTRY(cli_perm) list;
};

AST_LIST_HEAD_NOLOCK(cli_perm_head, cli_perm);

/*! \brief list of users to apply restrictions. */
struct usergroup_cli_perm {
	int uid;				/*!< User ID (-1 disabled) */
	int gid;				/*!< Group ID (-1 disabled) */
	struct cli_perm_head *perms;		/*!< List of permissions. */
	AST_LIST_ENTRY(usergroup_cli_perm) list;/*!< List mechanics */
};
/*! \brief CLI permissions config file. */
static const char perms_config[] = "cli_permissions.conf";
/*! \brief Default permissions value 1=Permit 0=Deny */
static int cli_default_perm = 1;

/*! \brief mutex used to prevent a user from running the 'cli reload permissions' command while
 * it is already running. */
AST_MUTEX_DEFINE_STATIC(permsconfiglock);
/*! \brief  List of users and permissions. */
static AST_RWLIST_HEAD_STATIC(cli_perms, usergroup_cli_perm);
Russell Bryant's avatar
Russell Bryant committed
/*!
 * \brief map a debug or verbose level to a module name
Russell Bryant's avatar
Russell Bryant committed
 */
Russell Bryant's avatar
Russell Bryant committed
	unsigned int level;
	AST_RWLIST_ENTRY(module_level) entry;
	char module[0];
AST_RWLIST_HEAD(module_level_list, module_level);
/*! list of module names and their debug levels */
static struct module_level_list debug_modules = AST_RWLIST_HEAD_INIT_VALUE;
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() */
void ast_cli(int fd, const char *fmt, ...)
Mark Spencer's avatar
Mark Spencer committed
{
	struct ast_str *buf;
Mark Spencer's avatar
Mark Spencer committed
	va_list ap;
	if (!(buf = ast_str_thread_get(&ast_cli_buf, AST_CLI_INITLEN)))
Mark Spencer's avatar
Mark Spencer committed
	va_start(ap, fmt);
	res = ast_str_set_va(&buf, 0, fmt, ap);
Mark Spencer's avatar
Mark Spencer committed
	va_end(ap);
	if (res != AST_DYNSTR_BUILD_FAILED) {
		ast_carefulwrite(fd, ast_str_buffer(buf), ast_str_strlen(buf), 100);
	}
unsigned int ast_debug_get_by_module(const char *module)
Russell Bryant's avatar
Russell Bryant committed
{
Russell Bryant's avatar
Russell Bryant committed
	unsigned int res = 0;

	AST_RWLIST_RDLOCK(&debug_modules);
	AST_LIST_TRAVERSE(&debug_modules, ml, entry) {
		if (!strcasecmp(ml->module, module)) {
			res = ml->level;
Russell Bryant's avatar
Russell Bryant committed
			break;
		}
	}
	AST_RWLIST_UNLOCK(&debug_modules);
unsigned int ast_verbose_get_by_module(const char *module)
Russell Bryant's avatar
Russell Bryant committed
{
/*! \internal
 *  \brief Check if the user with 'uid' and 'gid' is allow to execute 'command',
 *	   if command starts with '_' then not check permissions, just permit
 *	   to run the 'command'.
 *	   if uid == -1 or gid == -1 do not check permissions.
 *	   if uid == -2 and gid == -2 is because rasterisk client didn't send
 *	   the credentials, so the cli_default_perm will be applied.
 *  \param uid User ID.
 *  \param gid Group ID.
 *  \param command Command name to check permissions.
 *  \retval 1 if has permission
 *  \retval 0 if it is not allowed.
 */
static int cli_has_permissions(int uid, int gid, const char *command)
{
	struct usergroup_cli_perm *user_perm;
	struct cli_perm *perm;
	/* set to the default permissions general option. */
	int isallowg = cli_default_perm, isallowu = -1, ispattern;
	regex_t regexbuf;

	/* if uid == -1 or gid == -1 do not check permissions.
	   if uid == -2 and gid == -2 is because rasterisk client didn't send
	   the credentials, so the cli_default_perm will be applied. */
	if ((uid == CLI_NO_PERMS && gid == CLI_NO_PERMS) || command[0] == '_') {
		return 1;
	}

	if (gid < 0 && uid < 0) {
		return cli_default_perm;
	}

	AST_RWLIST_RDLOCK(&cli_perms);
	AST_LIST_TRAVERSE(&cli_perms, user_perm, list) {
		if (user_perm->gid != gid && user_perm->uid != uid) {
			continue;
		}
		AST_LIST_TRAVERSE(user_perm->perms, perm, list) {
			if (strcasecmp(perm->command, "all") && strncasecmp(perm->command, command, strlen(perm->command))) {
				/* if the perm->command is a pattern, check it against command. */
				ispattern = !regcomp(&regexbuf, perm->command, REG_EXTENDED | REG_NOSUB | REG_ICASE);
				if (ispattern && regexec(&regexbuf, command, 0, NULL, 0)) {
					regfree(&regexbuf);
Loading
Loading full blame...