[asterisk-commits] dlee: branch dlee/ari-authn r392859 - in /team/dlee/ari-authn/res: ./ stasis_...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Tue Jun 25 13:41:40 CDT 2013
Author: dlee
Date: Tue Jun 25 13:41:38 2013
New Revision: 392859
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=392859
Log:
ARI command line
Added:
team/dlee/ari-authn/res/stasis_http/cli.c (with props)
team/dlee/ari-authn/res/stasis_http/config.c (with props)
team/dlee/ari-authn/res/stasis_http/internal.h (with props)
Modified:
team/dlee/ari-authn/res/Makefile
team/dlee/ari-authn/res/res_stasis_http.c
Modified: team/dlee/ari-authn/res/Makefile
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-authn/res/Makefile?view=diff&rev=392859&r1=392858&r2=392859
==============================================================================
--- team/dlee/ari-authn/res/Makefile (original)
+++ team/dlee/ari-authn/res/Makefile Tue Jun 25 13:41:38 2013
@@ -80,5 +80,8 @@
$(if $(filter res_parking,$(EMBEDDED_MODS)),modules.link,res_parking.so): $(subst .c,.o,$(wildcard parking/*.c))
$(subst .c,.o,$(wildcard parking/*.c)): _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_parking)
+res_stasis_http.so: stasis_http/cli.o stasis_http/config.o
+stasis_http/cli.o stasis_http/config.o: _ASTCFLAGS+=$(call MOD_ASTCFLAGS,res_stasis_http)
+
# Dependencies for res_stasis_http_*.so are generated, so they're in this file
include stasis_http.make
Modified: team/dlee/ari-authn/res/res_stasis_http.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-authn/res/res_stasis_http.c?view=diff&rev=392859&r1=392858&r2=392859
==============================================================================
--- team/dlee/ari-authn/res/res_stasis_http.c (original)
+++ team/dlee/ari-authn/res/res_stasis_http.c Tue Jun 25 13:41:38 2013
@@ -75,236 +75,31 @@
<support_level>core</support_level>
***/
-/*** DOCUMENTATION
- <configInfo name="res_stasis_http" language="en_US">
- <synopsis>HTTP binding for the Stasis API</synopsis>
- <configFile name="stasis_http.conf">
- <configObject name="global">
- <synopsis>Global configuration settings</synopsis>
- <configOption name="enabled">
- <synopsis>Enable/disable the stasis-http module</synopsis>
- </configOption>
- <configOption name="pretty">
- <synopsis>Responses from stasis-http are formatted to be human readable</synopsis>
- </configOption>
- </configObject>
-
- <configObject name="user">
- <synopsis>Per-user configuration settings</synopsis>
- <configOption name="read_only">
- <synopsis>When set to yes, user is only authorized for read-only requests</synopsis>
- </configOption>
- <configOption name="allow_api_key">
- <synopsis>When set to yes, user may authenticate by appending ?api_key=username+password to their requests.</synopsis>
- </configOption>
- <configOption name="password">
- <synopsis>Crypted or plaintext password (see password_format)</synopsis>
- </configOption>
- <configOption name="password_format">
- <synopsis>password_format may be set to plain (the default) or crypt. When set to crypt, crypt(3) is used to validate the password. A crypted password can be generated using mkpasswd -m sha-512. When set to plain, the password is in plaintext</synopsis>
- </configOption>
- </configObject>
- </configFile>
- </configInfo>
-***/
-
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+#include "asterisk/astobj2.h"
#include "asterisk/module.h"
#include "asterisk/paths.h"
#include "asterisk/stasis_http.h"
-#include "asterisk/config_options.h"
+#include "stasis_http/internal.h"
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
-/*! \brief Global configuration options for stasis http. */
-struct conf_global_options {
- /*! Enabled by default, disabled if false. */
- int enabled;
- /*! Encoding format used during output (default compact). */
- enum ast_json_encoding_format format;
-};
-
-/*! \brief Password format */
-enum password_format {
- /*! \brief Plaintext password */
- PASSWORD_FORMAT_PLAIN,
- /*! crypt(3) password */
- PASSWORD_FORMAT_CRYPT,
-};
-
-struct conf_user_options {
- /*! Username for authentication */
- char username[128];
- /*! User's password. If 256 seems like a lot, a crypt SHA-512 has over
- * 100 characters */
- char password[256];
- /*! Format for the password field */
- enum password_format password_format;
- /*! If true, user cannot execute change operations */
- int read_only;
- /*! If true, user allowed to authenticate with ?api_key=user+password */
- int allow_api_key;
-};
-
-static void user_dtor(void *obj)
-{
- struct conf_user_options *user = obj;
-
- ast_debug(3, "Disposing of user %s", user->username);
-}
-
-static void *user_alloc(const char *cat)
-{
- RAII_VAR(struct conf_user_options *, user, NULL, ao2_cleanup);
- const char *username = strchr(cat, '-') + 1;
-
- if (!username) {
- ast_log(LOG_ERROR, "Invalid user category '%s'\n", cat);
- return NULL;
- }
-
- ast_debug(3, "Allocating user %s\n", cat);
-
- user = ao2_alloc(sizeof(*user), user_dtor);
- if (!user) {
- return NULL;
- }
-
- ao2_ref(user, +1);
- return user;
-}
-
-static int user_sort_cmp(const void *obj_left, const void *obj_right, int flags)
-{
- const struct conf_user_options *user_left = obj_left;
- const struct conf_user_options *user_right = obj_right;
- const char *right_key =
- (flags & OBJ_KEY) ? obj_right : user_right->username;
-
- return strcmp(user_left->username, right_key);
-}
-
-static void *user_find(struct ao2_container *tmp_container,
- const char *category)
-{
- return ao2_find(tmp_container, category, OBJ_KEY);
-}
-
-/*! \brief All configuration options for stasis http. */
-struct conf {
- /*! The general section configuration options. */
- struct conf_global_options *global;
- /*! Configured users */
- struct ao2_container *users;
-};
-
-/*! \brief Locking container for safe configuration access. */
-static AO2_GLOBAL_OBJ_STATIC(confs);
-
-/*! \brief Mapping of the stasis http conf struct's globals to the
- * general context in the config file. */
-static struct aco_type global_option = {
- .type = ACO_GLOBAL,
- .name = "global",
- .item_offset = offsetof(struct conf, global),
- .category = "^general$",
- .category_match = ACO_WHITELIST,
-};
-
-static struct aco_type *global_options[] = ACO_TYPES(&global_option);
-
-static struct aco_type user_option = {
- .type = ACO_ITEM,
- .name = "user",
- .category_match = ACO_WHITELIST,
- .category = "^user-.+$",
- .item_alloc = user_alloc,
- .item_find = user_find,
- .item_offset = offsetof(struct conf, users),
-};
-
-static struct aco_type *user_options[] = ACO_TYPES(&user_option);
-
-/*! \brief Disposes of the stasis http conf object */
-static void conf_destructor(void *obj)
-{
- struct conf *cfg = obj;
- ao2_cleanup(cfg->global);
-}
-
-/*! \brief Creates the statis http conf object. */
-static void *conf_alloc(void)
-{
- RAII_VAR(struct conf *, cfg, NULL, ao2_cleanup);
-
- cfg = ao2_alloc(sizeof(*cfg), conf_destructor);
- if (!cfg) {
- return NULL;
- }
-
- cfg->global = ao2_alloc(sizeof(*cfg->global), NULL);
- if (!cfg->global) {
- return NULL;
- }
-
- cfg->users = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK,
- AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, user_sort_cmp, NULL);
-
- ao2_ref(cfg, +1);
- return cfg;
-}
-
-/*! \brief The conf file that's processed for the module. */
-static struct aco_file conf_file = {
- /*! The config file name. */
- .filename = "stasis_http.conf",
- /*! The mapping object types to be processed. */
- .types = ACO_TYPES(&global_option, &user_option),
-};
-
-CONFIG_INFO_STANDARD(cfg_info, confs, conf_alloc,
- .files = ACO_FILES(&conf_file));
-
-/*! \brief Encoding format handler converts from boolean to enum. */
-static int encoding_format_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
- struct conf_global_options *global = obj;
-
- if (!strcasecmp(var->name, "pretty")) {
- global->format = ast_true(var->value) ? AST_JSON_PRETTY : AST_JSON_COMPACT;
- } else {
- return -1;
- }
-
- return 0;
-}
-
-static int password_format_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
-{
- struct conf_user_options *user = obj;
-
- if (strcasecmp(var->value, "plain") == 0) {
- user->password_format = PASSWORD_FORMAT_PLAIN;
- } else if (strcasecmp(var->value, "crypt") == 0) {
- user->password_format = PASSWORD_FORMAT_CRYPT;
- } else {
- return -1;
- }
-
- return 0;
-}
-
/*! \brief Helper function to check if module is enabled. */
-static char is_enabled(void)
-{
- RAII_VAR(struct conf *, cfg, ao2_global_obj_ref(confs), ao2_cleanup);
-
- return cfg->global->enabled;
+static int is_enabled(void)
+{
+ RAII_VAR(struct ari_conf *, cfg, ari_config_get(), ao2_cleanup);
+ return cfg->general->enabled;
+}
+
+static enum ast_json_encoding_format json_format(void)
+{
+ RAII_VAR(struct ari_conf *, cfg, ari_config_get(), ao2_cleanup);
+ return cfg->general->format;
}
/*! Lock for \ref root_handler */
@@ -890,7 +685,6 @@
struct ast_variable *get_params,
struct ast_variable *headers)
{
- RAII_VAR(struct conf *, cfg, ao2_global_obj_ref(confs), ao2_cleanup);
RAII_VAR(struct ast_str *, response_headers, ast_str_create(40), ast_free);
RAII_VAR(struct ast_str *, response_body, ast_str_create(256), ast_free);
struct stasis_http_response response = {};
@@ -938,7 +732,8 @@
if (response.message && !ast_json_is_null(response.message)) {
ast_str_append(&response_headers, 0,
"Content-type: application/json\r\n");
- if (ast_json_dump_str_format(response.message, &response_body, cfg->global->format) != 0) {
+ if (ast_json_dump_str_format(response.message, &response_body,
+ json_format()) != 0) {
/* Error encoding response */
response.response_code = 500;
response.response_text = "Internal Server Error";
@@ -974,41 +769,27 @@
{
ast_mutex_init(&root_handler_lock);
- root_handler = root_handler_create();
+ /* root_handler may have been built during a declined load */
+ if (!root_handler) {
+ root_handler = root_handler_create();
+ }
if (!root_handler) {
return AST_MODULE_LOAD_FAILURE;
}
- if (aco_info_init(&cfg_info)) {
- aco_info_destroy(&cfg_info);
+ /* alloc_failed_message may have been built during a declined load */
+ if (!alloc_failed_message) {
+ alloc_failed_message = ast_json_pack(
+ "{s: s}", "message", "Allocation failed");
+ }
+ if (!alloc_failed_message) {
+ /* Ironic */
+ return AST_MODULE_LOAD_FAILURE;
+ }
+
+ if (ari_config_init() != 0) {
return AST_MODULE_LOAD_DECLINE;
}
-
- aco_option_register(&cfg_info, "enabled", ACO_EXACT, global_options,
- "yes", OPT_BOOL_T, 1,
- FLDSET(struct conf_global_options, enabled));
- aco_option_register_custom(&cfg_info, "pretty", ACO_EXACT,
- global_options, "no", encoding_format_handler, 0);
-
- aco_option_register(&cfg_info, "read_only", ACO_EXACT, user_options,
- "no", OPT_BOOL_T, 1,
- FLDSET(struct conf_user_options, read_only));
- aco_option_register(&cfg_info, "allow_api_key", ACO_EXACT, user_options,
- "no", OPT_BOOL_T, 1,
- FLDSET(struct conf_user_options, allow_api_key));
- aco_option_register(&cfg_info, "password", ACO_EXACT, user_options,
- "", OPT_CHAR_ARRAY_T, 0,
- FLDSET(struct conf_user_options, password));
- aco_option_register_custom(&cfg_info, "password_format", ACO_EXACT,
- user_options, "plain", password_format_handler, 0);
-
- if (aco_process_config(&cfg_info, 0)) {
- aco_info_destroy(&cfg_info);
- return AST_MODULE_LOAD_DECLINE;
- }
-
- alloc_failed_message = ast_json_pack(
- "{s: s}", "message", "Allocation failed");
if (is_enabled()) {
ast_debug(3, "ARI enabled\n");
@@ -1017,26 +798,31 @@
ast_debug(3, "ARI disabled\n");
}
+ if (ari_cli_register() != 0) {
+ return AST_MODULE_LOAD_FAILURE;
+ }
+
return AST_MODULE_LOAD_SUCCESS;
}
static int unload_module(void)
{
- ast_json_unref(alloc_failed_message);
- alloc_failed_message = NULL;
+ ari_cli_unregister();
if (is_enabled()) {
ast_debug(3, "Disabling ARI\n");
ast_http_uri_unlink(&http_uri);
}
- aco_info_destroy(&cfg_info);
- ao2_global_obj_release(confs);
+ ari_config_destroy();
ao2_cleanup(root_handler);
root_handler = NULL;
ast_mutex_destroy(&root_handler_lock);
+ ast_json_unref(alloc_failed_message);
+ alloc_failed_message = NULL;
+
return 0;
}
@@ -1044,7 +830,7 @@
{
char was_enabled = is_enabled();
- if (aco_process_config(&cfg_info, 1)) {
+ if (ari_config_reload() != 0) {
return AST_MODULE_LOAD_DECLINE;
}
Added: team/dlee/ari-authn/res/stasis_http/cli.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-authn/res/stasis_http/cli.c?view=auto&rev=392859
==============================================================================
--- team/dlee/ari-authn/res/stasis_http/cli.c (added)
+++ team/dlee/ari-authn/res/stasis_http/cli.c Tue Jun 25 13:41:38 2013
@@ -1,0 +1,229 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee at digium.com>
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+/*! \file
+ *
+ * \brief Command line for ARI.
+ * \author David M. Lee, II <dlee at digium.com>
+ */
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/astobj2.h"
+#include "asterisk/cli.h"
+#include "internal.h"
+
+static char *ari_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ RAII_VAR(struct ari_conf *, conf, NULL, ao2_cleanup);
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ari show status";
+ e->usage =
+ "Usage: ari show status\n"
+ " Shows all ARI settings\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ default:
+ break;
+ }
+
+ if (a->argc != 3) {
+ return CLI_SHOWUSAGE;
+ }
+
+ conf = ari_config_get();
+
+ if (!conf) {
+ ast_cli(a->fd, "Error getting ARI configuration\n");
+ return CLI_FAILURE;
+ }
+
+ ast_cli(a->fd, "ARI Status:\n");
+ ast_cli(a->fd, "Enabled: %s\n", AST_CLI_YESNO(conf->general->enabled));
+ ast_cli(a->fd, "Output format: ");
+ switch (conf->general->format) {
+ case AST_JSON_COMPACT:
+ ast_cli(a->fd, "compact");
+ break;
+ case AST_JSON_PRETTY:
+ ast_cli(a->fd, "pretty");
+ break;
+ }
+ ast_cli(a->fd, "\n");
+ ast_cli(a->fd, "User count: %d\n", ao2_container_count(conf->users));
+ return CLI_SUCCESS;
+}
+
+static int show_users_cb(void *obj, void *arg, int flags)
+{
+ struct ari_conf_user *user = obj;
+ struct ast_cli_args *a = arg;
+
+ ast_cli(a->fd, "%-*s %-*s %s\n",
+ 4, AST_CLI_YESNO(user->read_only),
+ 7, AST_CLI_YESNO(user->allow_api_key),
+ user->username);
+ return 0;
+}
+
+static char *ari_show_users(struct ast_cli_entry *e, int cmd,
+ struct ast_cli_args *a)
+{
+ RAII_VAR(struct ari_conf *, conf, NULL, ao2_cleanup);
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ari show users";
+ e->usage =
+ "Usage: ari show users\n"
+ " Shows all ARI users\n";
+ return NULL;
+ case CLI_GENERATE:
+ return NULL;
+ default:
+ break;
+ }
+
+ if (a->argc != 3) {
+ return CLI_SHOWUSAGE;
+ }
+
+ conf = ari_config_get();
+ if (!conf) {
+ ast_cli(a->fd, "Error getting ARI configuration\n");
+ return CLI_FAILURE;
+ }
+
+ ast_cli(a->fd, "r/o? API key Username\n");
+ ast_cli(a->fd, "---- ------- --------\n");
+
+ ao2_callback(conf->users, OBJ_NODATA, show_users_cb, a);
+
+ return CLI_SUCCESS;
+}
+
+struct user_complete {
+ /*! Nth user to search for */
+ int state;
+ /*! Which user currently on */
+ int which;
+};
+
+static int complete_ari_user_search(void *obj, void *arg, void *data, int flags)
+{
+ struct user_complete *search = data;
+
+ if (++search->which > search->state) {
+ return CMP_MATCH;
+ }
+ return 0;
+}
+
+static char *complete_ari_user(struct ast_cli_args *a)
+{
+ RAII_VAR(struct ari_conf *, conf, NULL, ao2_cleanup);
+ RAII_VAR(struct ari_conf_user *, user, NULL, ao2_cleanup);
+
+ struct user_complete search = {
+ .state = a->n,
+ };
+
+ conf = ari_config_get();
+ if (!conf) {
+ ast_cli(a->fd, "Error getting ARI configuration\n");
+ return CLI_FAILURE;
+ }
+
+ user = ao2_callback_data(conf->users,
+ ast_strlen_zero(a->word) ? 0 : OBJ_PARTIAL_KEY,
+ complete_ari_user_search, (char*)a->word, &search);
+
+ return user ? ast_strdup(user->username) : NULL;
+}
+
+static char *complete_ari_show_user(struct ast_cli_args *a)
+{
+ if (a->pos == 3) {
+ return complete_ari_user(a);
+ }
+
+ return NULL;
+}
+
+static char *ari_show_user(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+ RAII_VAR(struct ari_conf *, conf, NULL, ao2_cleanup);
+ RAII_VAR(struct ari_conf_user *, user, NULL, ao2_cleanup);
+
+ switch (cmd) {
+ case CLI_INIT:
+ e->command = "ari show user";
+ e->usage =
+ "Usage: ari show user <username>\n"
+ " Shows a specific ARI user\n";
+ return NULL;
+ case CLI_GENERATE:
+ return complete_ari_show_user(a);
+ default:
+ break;
+ }
+
+ if (a->argc != 4) {
+ return CLI_SHOWUSAGE;
+ }
+
+ conf = ari_config_get();
+
+ if (!conf) {
+ ast_cli(a->fd, "Error getting ARI configuration\n");
+ return CLI_FAILURE;
+ }
+
+ user = ao2_find(conf->users, a->argv[3], OBJ_KEY);
+ if (!user) {
+ ast_cli(a->fd, "User '%s' not found\n", a->argv[3]);
+ return CLI_SUCCESS;
+ }
+
+ ast_cli(a->fd, "Username: %s\n", user->username);
+ ast_cli(a->fd, "Read only?: %s\n", AST_CLI_YESNO(user->read_only));
+ ast_cli(a->fd, "Allow api_key?: %s\n",
+ AST_CLI_YESNO(user->allow_api_key));
+
+ return CLI_SUCCESS;
+}
+
+
+static struct ast_cli_entry cli_ari[] = {
+ AST_CLI_DEFINE(ari_show, "Show ARI settings"),
+ AST_CLI_DEFINE(ari_show_users, "List ARI users"),
+ AST_CLI_DEFINE(ari_show_user, "List single ARI user"),
+};
+
+int ari_cli_register(void) {
+ return ast_cli_register_multiple(cli_ari, ARRAY_LEN(cli_ari));
+}
+
+void ari_cli_unregister(void) {
+ ast_cli_unregister_multiple(cli_ari, ARRAY_LEN(cli_ari));
+}
Propchange: team/dlee/ari-authn/res/stasis_http/cli.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/dlee/ari-authn/res/stasis_http/cli.c
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/dlee/ari-authn/res/stasis_http/cli.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: team/dlee/ari-authn/res/stasis_http/config.c
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-authn/res/stasis_http/config.c?view=auto&rev=392859
==============================================================================
--- team/dlee/ari-authn/res/stasis_http/config.c (added)
+++ team/dlee/ari-authn/res/stasis_http/config.c Tue Jun 25 13:41:38 2013
@@ -1,0 +1,280 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee at digium.com>
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+/*! \file
+ *
+ * \brief Config framework stuffz for ARI.
+ * \author David M. Lee, II <dlee at digium.com>
+ */
+
+/*** DOCUMENTATION
+ <configInfo name="res_stasis_http" language="en_US">
+ <synopsis>HTTP binding for the Stasis API</synopsis>
+ <configFile name="stasis_http.conf">
+ <configObject name="general">
+ <synopsis>General configuration settings</synopsis>
+ <configOption name="enabled">
+ <synopsis>Enable/disable the stasis-http module</synopsis>
+ </configOption>
+ <configOption name="pretty">
+ <synopsis>Responses from stasis-http are formatted to be human readable</synopsis>
+ </configOption>
+ </configObject>
+
+ <configObject name="user">
+ <synopsis>Per-user configuration settings</synopsis>
+ <configOption name="read_only">
+ <synopsis>When set to yes, user is only authorized for read-only requests</synopsis>
+ </configOption>
+ <configOption name="allow_api_key">
+ <synopsis>When set to yes, user may authenticate by appending ?api_key=username+password to their requests.</synopsis>
+ </configOption>
+ <configOption name="password">
+ <synopsis>Crypted or plaintext password (see password_format)</synopsis>
+ </configOption>
+ <configOption name="password_format">
+ <synopsis>password_format may be set to plain (the default) or crypt. When set to crypt, crypt(3) is used to validate the password. A crypted password can be generated using mkpasswd -m sha-512. When set to plain, the password is in plaintext</synopsis>
+ </configOption>
+ </configObject>
+ </configFile>
+ </configInfo>
+***/
+
+#include "asterisk.h"
+
+ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
+
+#include "asterisk/config_options.h"
+#include "internal.h"
+
+/*! \brief Locking container for safe configuration access. */
+static AO2_GLOBAL_OBJ_STATIC(confs);
+
+/*! \brief Mapping of the stasis http conf struct's globals to the
+ * general context in the config file. */
+static struct aco_type general_option = {
+ .type = ACO_GLOBAL,
+ .name = "global",
+ .item_offset = offsetof(struct ari_conf, general),
+ .category = "^general$",
+ .category_match = ACO_WHITELIST,
+};
+
+static struct aco_type *general_options[] = ACO_TYPES(&general_option);
+
+/*! \brief Encoding format handler converts from boolean to enum. */
+static int encoding_format_handler(const struct aco_option *opt,
+ struct ast_variable *var, void *obj)
+{
+ struct ari_conf_general *general = obj;
+
+ if (!strcasecmp(var->name, "pretty")) {
+ general->format = ast_true(var->value) ?
+ AST_JSON_PRETTY : AST_JSON_COMPACT;
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+/*! \brief Parses the ari_password_format enum from a config file */
+static int password_format_handler(const struct aco_option *opt,
+ struct ast_variable *var, void *obj)
+{
+ struct ari_conf_user *user = obj;
+
+ if (strcasecmp(var->value, "plain") == 0) {
+ user->password_format = ARI_PASSWORD_FORMAT_PLAIN;
+ } else if (strcasecmp(var->value, "crypt") == 0) {
+ user->password_format = ARI_PASSWORD_FORMAT_CRYPT;
+ } else {
+ return -1;
+ }
+
+ return 0;
+}
+
+static void user_dtor(void *obj)
+{
+ struct ari_conf_user *user = obj;
+ ast_debug(3, "Disposing of user %s\n", user->username);
+}
+
+static void *user_alloc(const char *cat)
+{
+ RAII_VAR(struct ari_conf_user *, user, NULL, ao2_cleanup);
+ const char *username = strchr(cat, '-') + 1;
+
+ if (!username) {
+ ast_log(LOG_ERROR, "Invalid user category '%s'\n", cat);
+ return NULL;
+ }
+
+ if (strlen(username) + 1 > ARRAY_LEN(user->username)) {
+ ast_log(LOG_ERROR, "User name too long '%s'\n", username);
+ return NULL;
+ }
+
+ ast_debug(3, "Allocating user %s\n", cat);
+
+ user = ao2_alloc(sizeof(*user), user_dtor);
+ if (!user) {
+ return NULL;
+ }
+
+ strncpy(user->username, username, ARRAY_LEN(user->username));
+
+ ao2_ref(user, +1);
+ return user;
+}
+
+static int user_sort_cmp(const void *obj_left, const void *obj_right, int flags)
+{
+ const struct ari_conf_user *user_left = obj_left;
+
+ if (flags & OBJ_PARTIAL_KEY) {
+ const char *key_right = obj_right;
+ return strncasecmp(user_left->username, key_right,
+ strlen(key_right));
+ } else if (flags & OBJ_KEY) {
+ const char *key_right = obj_right;
+ return strcasecmp(user_left->username, key_right);
+ } else {
+ const struct ari_conf_user *user_right = obj_right;
+ const char *key_right = user_right->username;
+ return strcasecmp(user_left->username, key_right);
+ }
+}
+
+static void *user_find(struct ao2_container *tmp_container,
+ const char *category)
+{
+ return ao2_find(tmp_container, category, OBJ_KEY);
+}
+
+static struct aco_type user_option = {
+ .type = ACO_ITEM,
+ .name = "user",
+ .category_match = ACO_WHITELIST,
+ .category = "^user-.+$",
+ .item_alloc = user_alloc,
+ .item_find = user_find,
+ .item_offset = offsetof(struct ari_conf, users),
+};
+
+static struct aco_type *user[] = ACO_TYPES(&user_option);
+
+/*! \brief Disposes of the stasis http conf object */
+static void conf_destructor(void *obj)
+{
+ struct ari_conf *cfg = obj;
+ ao2_cleanup(cfg->general);
+ ao2_cleanup(cfg->users);
+}
+
+/*! \brief Creates the statis http conf object. */
+static void *conf_alloc(void)
+{
+ RAII_VAR(struct ari_conf *, cfg, NULL, ao2_cleanup);
+
+ cfg = ao2_alloc(sizeof(*cfg), conf_destructor);
+ if (!cfg) {
+ return NULL;
+ }
+
+ cfg->general = ao2_alloc(sizeof(*cfg->general), NULL);
+ if (!cfg->general) {
+ return NULL;
+ }
+
+ cfg->users = ao2_container_alloc_rbtree(AO2_ALLOC_OPT_LOCK_NOLOCK,
+ AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE, user_sort_cmp, NULL);
+
+ ao2_ref(cfg, +1);
+ return cfg;
+}
+
+/*! \brief The conf file that's processed for the module. */
+static struct aco_file conf_file = {
+ /*! The config file name. */
+ .filename = "stasis_http.conf",
+ /*! The mapping object types to be processed. */
+ .types = ACO_TYPES(&general_option, &user_option),
+};
+
+CONFIG_INFO_STANDARD(cfg_info, confs, conf_alloc,
+ .files = ACO_FILES(&conf_file));
+
+int ari_config_init(void)
+{
+ if (aco_info_init(&cfg_info)) {
+ aco_info_destroy(&cfg_info);
+ return -1;
+ }
+
+ aco_option_register(&cfg_info, "enabled", ACO_EXACT, general_options,
+ "yes", OPT_BOOL_T, 1,
+ FLDSET(struct ari_conf_general, enabled));
+ aco_option_register_custom(&cfg_info, "pretty", ACO_EXACT,
+ general_options, "no", encoding_format_handler, 0);
+
+ aco_option_register(&cfg_info, "read_only", ACO_EXACT, user,
+ "no", OPT_BOOL_T, 1,
+ FLDSET(struct ari_conf_user, read_only));
+ aco_option_register(&cfg_info, "allow_api_key", ACO_EXACT, user,
+ "no", OPT_BOOL_T, 1,
+ FLDSET(struct ari_conf_user, allow_api_key));
+ aco_option_register(&cfg_info, "password", ACO_EXACT, user,
+ "", OPT_CHAR_ARRAY_T, 0,
+ FLDSET(struct ari_conf_user, password));
+ aco_option_register_custom(&cfg_info, "password_format", ACO_EXACT,
+ user, "plain", password_format_handler, 0);
+
+ if (aco_process_config(&cfg_info, 0)) {
+ aco_info_destroy(&cfg_info);
+ return -1;
+ }
+
+ return 0;
+}
+
+int ari_config_reload(void)
+{
+ switch (aco_process_config(&cfg_info, 1)) {
+ case ACO_PROCESS_OK:
+ case ACO_PROCESS_UNCHANGED:
+ return 0;
+ case ACO_PROCESS_ERROR:
+ return -1;
+ }
+
+ return -1;
+}
+
+void ari_config_destroy(void)
+{
+ aco_info_destroy(&cfg_info);
+ ao2_global_obj_release(confs);
+}
+
+struct ari_conf *ari_config_get(void)
+{
+ return ao2_global_obj_ref(confs);
+}
+
Propchange: team/dlee/ari-authn/res/stasis_http/config.c
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/dlee/ari-authn/res/stasis_http/config.c
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/dlee/ari-authn/res/stasis_http/config.c
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: team/dlee/ari-authn/res/stasis_http/internal.h
URL: http://svnview.digium.com/svn/asterisk/team/dlee/ari-authn/res/stasis_http/internal.h?view=auto&rev=392859
==============================================================================
--- team/dlee/ari-authn/res/stasis_http/internal.h (added)
+++ team/dlee/ari-authn/res/stasis_http/internal.h Tue Jun 25 13:41:38 2013
@@ -1,0 +1,119 @@
+/*
+ * Asterisk -- An open source telephony toolkit.
+ *
+ * Copyright (C) 2013, Digium, Inc.
+ *
+ * David M. Lee, II <dlee at digium.com>
+ *
+ * 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.
+ *
+ * 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.
+ */
+
+#ifndef STASIS_HTTP_INTERNAL_H_
+#define STASIS_HTTP_INTERNAL_H_
+
+/*! \file
+ *
+ * \brief Internal API's for res_stasis_http.
+ * \author David M. Lee, II <dlee at digium.com>
+ */
+
+#include "asterisk/json.h"
+
+/*! @{ */
+
+/*!
+ * \brief Register CLI commands for ARI.
+ *
+ * \return 0 on success.
+ * \return Non-zero on error.
+ */
+int ari_cli_register(void);
+
+/*!
+ * \brief Unregister CLI commands for ARI.
+ */
+void ari_cli_unregister(void);
+
+/*! @} */
+
+/*! @{ */
+
+struct ari_conf_general;
+
+/*! \brief All configuration options for stasis http. */
+struct ari_conf {
+ /*! The general section configuration options. */
+ struct ari_conf_general *general;
+ /*! Configured users */
+ struct ao2_container *users;
+};
+
+/*! \brief Global configuration options for stasis http. */
+struct ari_conf_general {
+ /*! Enabled by default, disabled if false. */
+ int enabled;
+ /*! Encoding format used during output (default compact). */
+ enum ast_json_encoding_format format;
+};
+
+/*! \brief Password format */
+enum ari_password_format {
+ /*! \brief Plaintext password */
+ ARI_PASSWORD_FORMAT_PLAIN,
+ /*! crypt(3) password */
+ ARI_PASSWORD_FORMAT_CRYPT,
+};
+
+/*! \brief Per-user configuration options */
+struct ari_conf_user {
+ /*! Username for authentication */
+ char username[128];
+ /*! User's password. If 256 seems like a lot, a crypt SHA-512 has over
+ * 100 characters */
+ char password[256];
+ /*! Format for the password field */
+ enum ari_password_format password_format;
+ /*! If true, user cannot execute change operations */
+ int read_only;
+ /*! If true, user allowed to authenticate with ?api_key=user+password */
+ int allow_api_key;
+};
+
+/*!
+ * \brief Initialize the ARI configuration
+ */
+int ari_config_init(void);
+
+/*!
+ * \brief Reload the ARI configuration
+ */
+int ari_config_reload(void);
+
+/*!
+ * \brief Destroy the ARI configuration
+ */
+void ari_config_destroy(void);
+
+/*!
+ * \brief Get the current ARI configuration.
+ *
+ * This is an immutable object, so don't modify it. It is AO2 managed, so
+ * ao2_cleanup() when you're done with it.
+ *
+ * \return ARI configuration object.
+ * \return \c NULL on error.
+ */
+struct ari_conf *ari_config_get(void);
+
+/*! @} */
+
+
+#endif /* STASIS_HTTP_INTERNAL_H_ */
Propchange: team/dlee/ari-authn/res/stasis_http/internal.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: team/dlee/ari-authn/res/stasis_http/internal.h
------------------------------------------------------------------------------
svn:keywords = Author Date Id Revision
Propchange: team/dlee/ari-authn/res/stasis_http/internal.h
------------------------------------------------------------------------------
svn:mime-type = text/plain
More information about the asterisk-commits
mailing list