Asterisk - The Open Source Telephony Project GIT-master-a358458
res/ari/config.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2013, Digium, Inc.
5 *
6 * David M. Lee, II <dlee@digium.com>
7 *
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
13 *
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
17 */
18
19/*! \file
20 *
21 * \brief Config framework stuffz for ARI.
22 * \author David M. Lee, II <dlee@digium.com>
23 */
24
25#include "asterisk.h"
26
29#include "asterisk/app.h"
30#include "asterisk/channel.h"
31#include "internal.h"
32
33/*! \brief Locking container for safe configuration access. */
35
36/*! \brief Mapping of the ARI conf struct's globals to the
37 * general context in the config file. */
38static struct aco_type general_option = {
40 .name = "general",
41 .item_offset = offsetof(struct ast_ari_conf, general),
42 .category = "general",
43 .category_match = ACO_WHITELIST_EXACT,
44};
45
47
48/*! \brief Encoding format handler converts from boolean to enum. */
49static int encoding_format_handler(const struct aco_option *opt,
50 struct ast_variable *var, void *obj)
51{
52 struct ast_ari_conf_general *general = obj;
53
54 if (!strcasecmp(var->name, "pretty")) {
55 general->format = ast_true(var->value) ?
57 } else {
58 return -1;
59 }
60
61 return 0;
62}
63
64/*! \brief Parses the ast_ari_password_format enum from a config file */
65static int password_format_handler(const struct aco_option *opt,
66 struct ast_variable *var, void *obj)
67{
68 struct ast_ari_conf_user *user = obj;
69
70 if (strcasecmp(var->value, "plain") == 0) {
71 user->password_format = ARI_PASSWORD_FORMAT_PLAIN;
72 } else if (strcasecmp(var->value, "crypt") == 0) {
73 user->password_format = ARI_PASSWORD_FORMAT_CRYPT;
74 } else {
75 return -1;
76 }
77
78 return 0;
79}
80
81/*! \brief Destructor for \ref ast_ari_conf_user */
82static void user_dtor(void *obj)
83{
84 struct ast_ari_conf_user *user = obj;
85 ast_debug(3, "Disposing of user %s\n", user->username);
86 ast_free(user->username);
87}
88
89/*! \brief Allocate an \ref ast_ari_conf_user for config parsing */
90static void *user_alloc(const char *cat)
91{
93
94 if (!cat) {
95 return NULL;
96 }
97
98 ast_debug(3, "Allocating user %s\n", cat);
99
102 if (!user) {
103 return NULL;
104 }
105
106 user->username = ast_strdup(cat);
107 if (!user->username) {
108 return NULL;
109 }
110
111 ao2_ref(user, +1);
112 return user;
113}
114
115/*! \brief Sorting function for use with red/black tree */
116static int user_sort_cmp(const void *obj_left, const void *obj_right, int flags)
117{
118 const struct ast_ari_conf_user *user_left = obj_left;
119 const struct ast_ari_conf_user *user_right = obj_right;
120 const char *key_right = obj_right;
121 int cmp;
122
123 switch (flags & OBJ_SEARCH_MASK) {
125 key_right = user_right->username;
126 /* Fall through */
127 case OBJ_SEARCH_KEY:
128 cmp = strcasecmp(user_left->username, key_right);
129 break;
131 /*
132 * We could also use a partial key struct containing a length
133 * so strlen() does not get called for every comparison instead.
134 */
135 cmp = strncasecmp(user_left->username, key_right, strlen(key_right));
136 break;
137 default:
138 /* Sort can only work on something with a full or partial key. */
139 ast_assert(0);
140 cmp = 0;
141 break;
142 }
143 return cmp;
144}
145
146/*! \brief \ref aco_type item_find function */
147static void *user_find(struct ao2_container *tmp_container, const char *cat)
148{
149 if (!cat) {
150 return NULL;
151 }
152
153 return ao2_find(tmp_container, cat, OBJ_SEARCH_KEY);
154}
155
156static struct aco_type user_option = {
157 .type = ACO_ITEM,
158 .name = "user",
159 .category_match = ACO_BLACKLIST_EXACT,
160 .category = "general",
161 .matchfield = "type",
162 .matchvalue = "user",
163 .item_alloc = user_alloc,
164 .item_find = user_find,
165 .item_offset = offsetof(struct ast_ari_conf, users),
166};
167
169
170static void conf_general_dtor(void *obj)
171{
172 struct ast_ari_conf_general *general = obj;
173
175}
176
177/*! \brief \ref ast_ari_conf destructor. */
178static void conf_destructor(void *obj)
179{
180 struct ast_ari_conf *cfg = obj;
181
182 ao2_cleanup(cfg->general);
183 ao2_cleanup(cfg->users);
184}
185
186/*! \brief Allocate an \ref ast_ari_conf for config parsing */
187static void *conf_alloc(void)
188{
189 struct ast_ari_conf *cfg;
190
191 cfg = ao2_alloc_options(sizeof(*cfg), conf_destructor,
193 if (!cfg) {
194 return NULL;
195 }
196
199
202
203 if (!cfg->users
204 || !cfg->general
205 || ast_string_field_init(cfg->general, 64)
206 || aco_set_defaults(&general_option, "general", cfg->general)) {
207 ao2_ref(cfg, -1);
208 return NULL;
209 }
210
211 return cfg;
212}
213
214#define CONF_FILENAME "ari.conf"
215
216/*! \brief The conf file that's processed for the module. */
217static struct aco_file conf_file = {
218 /*! The config file name. */
220 /*! The mapping object types to be processed. */
222};
223
225 .files = ACO_FILES(&conf_file));
226
228{
230 if (!res) {
232 "Error obtaining config from " CONF_FILENAME "\n");
233 }
234 return res;
235}
236
238 const char *password)
239{
242 int is_valid = 0;
243
245 if (!conf) {
246 return NULL;
247 }
248
250 if (!user) {
251 return NULL;
252 }
253
254 if (ast_strlen_zero(user->password)) {
256 "User '%s' missing password; authentication failed\n",
257 user->username);
258 return NULL;
259 }
260
261 switch (user->password_format) {
263 is_valid = strcmp(password, user->password) == 0;
264 break;
266 is_valid = ast_crypt_validate(password, user->password);
267 break;
268 }
269
270 if (!is_valid) {
271 return NULL;
272 }
273
274 ao2_ref(user, +1);
275 return user;
276}
277
278/*! \brief Callback to validate a user object */
279static int validate_user_cb(void *obj, void *arg, int flags)
280{
281 struct ast_ari_conf_user *user = obj;
282
283 if (ast_strlen_zero(user->password)) {
284 ast_log(LOG_WARNING, "User '%s' missing password\n",
285 user->username);
286 }
287
288 return 0;
289}
290
291/*! \brief Load (or reload) configuration. */
292static int process_config(int reload)
293{
295
296 switch (aco_process_config(&cfg_info, reload)) {
298 return -1;
299 case ACO_PROCESS_OK:
301 break;
302 }
303
305 if (!conf) {
306 ast_assert(0); /* We just configured; it should be there */
307 return -1;
308 }
309
310 if (conf->general->enabled) {
311 if (ao2_container_count(conf->users) == 0) {
312 ast_log(LOG_ERROR, "No configured users for ARI\n");
313 } else {
315 }
316 }
317
318 return 0;
319}
320
321#define MAX_VARS 128
322
323static int channelvars_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
324{
325 char *parse = NULL;
327 AST_APP_ARG(vars)[MAX_VARS];
328 );
329
330 parse = ast_strdupa(var->value);
332
334 return 0;
335}
336
338{
339 if (aco_info_init(&cfg_info)) {
340 aco_info_destroy(&cfg_info);
341 return -1;
342 }
343
344 /* ARI general category options */
345 aco_option_register(&cfg_info, "enabled", ACO_EXACT, general_options,
346 "yes", OPT_BOOL_T, 1,
348 aco_option_register_custom(&cfg_info, "pretty", ACO_EXACT,
350 aco_option_register(&cfg_info, "auth_realm", ACO_EXACT, general_options,
351 "Asterisk REST Interface", OPT_CHAR_ARRAY_T, 0,
352 FLDSET(struct ast_ari_conf_general, auth_realm),
354 aco_option_register(&cfg_info, "allowed_origins", ACO_EXACT, general_options,
355 "", OPT_STRINGFIELD_T, 0,
356 STRFLDSET(struct ast_ari_conf_general, allowed_origins));
357 aco_option_register(&cfg_info, "websocket_write_timeout", ACO_EXACT, general_options,
359 FLDSET(struct ast_ari_conf_general, write_timeout), 1, INT_MAX);
360 aco_option_register_custom(&cfg_info, "channelvars", ACO_EXACT, general_options,
361 "", channelvars_handler, 0);
362
363 /* ARI type=user category options */
364 aco_option_register(&cfg_info, "type", ACO_EXACT, global_user, NULL,
365 OPT_NOOP_T, 0, 0);
366 aco_option_register(&cfg_info, "read_only", ACO_EXACT, global_user,
367 "no", OPT_BOOL_T, 1,
369 aco_option_register(&cfg_info, "password", ACO_EXACT, global_user,
370 "", OPT_CHAR_ARRAY_T, 0,
372 aco_option_register_custom(&cfg_info, "password_format", ACO_EXACT,
374
375 return process_config(0);
376}
377
379{
380 return process_config(1);
381}
382
384{
385 aco_info_destroy(&cfg_info);
387}
#define var
Definition: ast_expr2f.c:605
Asterisk main include file. File version handling, generic pbx functions.
#define ast_free(a)
Definition: astmm.h:180
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_log
Definition: astobj2.c:42
@ AO2_ALLOC_OPT_LOCK_NOLOCK
Definition: astobj2.h:367
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
Definition: astobj2.h:1693
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
Definition: astobj2.h:918
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1736
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Allocate and initialize a red-black tree container.
Definition: astobj2.h:1349
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:404
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Definition: astobj2.h:859
@ OBJ_SEARCH_PARTIAL_KEY
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1116
@ OBJ_SEARCH_OBJECT
The arg parameter is an object of the same type.
Definition: astobj2.h:1087
@ OBJ_NODATA
Definition: astobj2.h:1044
@ OBJ_SEARCH_MASK
Search option field mask.
Definition: astobj2.h:1072
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1101
@ AO2_CONTAINER_ALLOC_OPT_DUPS_REPLACE
Replace objects with duplicate keys in container.
Definition: astobj2.h:1211
General Asterisk PBX channel definitions.
void ast_channel_set_ari_vars(size_t varc, char **vars)
Sets the variables to be stored in the ari_vars field of all snapshots.
Definition: channel.c:7892
Configuration option-handling.
@ ACO_EXACT
int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
Set all default options of obj.
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
@ ACO_PROCESS_UNCHANGED
The config had not been edited and no changes applied.
@ ACO_PROCESS_ERROR
Their was an error and no changes were applied.
@ ACO_PROCESS_OK
The config was processed and applied.
#define STRFLDSET(type,...)
Convert a struct and a list of stringfield fields to an argument list of field offsets.
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
#define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags,...)
Register a config option.
#define ACO_FILES(...)
@ OPT_NOOP_T
Type for a default handler that should do nothing.
@ OPT_BOOL_T
Type for default option handler for bools (ast_true/ast_false)
@ OPT_CHAR_ARRAY_T
Type for default option handler for character array strings.
@ OPT_INT_T
Type for default option handler for signed integers.
@ OPT_STRINGFIELD_T
Type for default option handler for stringfields.
#define aco_option_register_custom(info, name, matchtype, types, default_val, handler, flags)
Register a config option.
@ ACO_ITEM
@ ACO_GLOBAL
@ ACO_WHITELIST_EXACT
@ ACO_BLACKLIST_EXACT
enum aco_process_status aco_process_config(struct aco_info *info, int reload)
Process a config info via the options registered with an aco_info.
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.
static int enabled
Definition: dnsmgr.c:91
Support for WebSocket connections within the Asterisk HTTP server and client WebSocket connections to...
#define AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT_STR
Default websocket write timeout, in ms (as a string)
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define LOG_WARNING
Internal API's for res_ari.
#define ARI_PASSWORD_LEN
User's password mx length.
Definition: internal.h:93
#define ARI_AUTH_REALM_LEN
Definition: internal.h:62
@ ARI_PASSWORD_FORMAT_CRYPT
Definition: internal.h:85
@ ARI_PASSWORD_FORMAT_PLAIN
Plaintext password.
Definition: internal.h:83
@ AST_JSON_COMPACT
Definition: json.h:793
@ AST_JSON_PRETTY
Definition: json.h:795
CONFIG_INFO_STANDARD(cfg_info, confs, conf_alloc,.files=ACO_FILES(&conf_file))
struct ast_ari_conf * ast_ari_config_get(void)
Get the current ARI configuration.
static int process_config(int reload)
Load (or reload) configuration.
static struct aco_type user_option
static void * conf_alloc(void)
Allocate an ast_ari_conf for config parsing.
int ast_ari_config_reload(void)
Reload the ARI configuration.
static AO2_GLOBAL_OBJ_STATIC(confs)
Locking container for safe configuration access.
static struct aco_file conf_file
The conf file that's processed for the module.
static void conf_general_dtor(void *obj)
static int password_format_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
Parses the ast_ari_password_format enum from a config file.
static void * user_alloc(const char *cat)
Allocate an ast_ari_conf_user for config parsing.
static struct aco_type general_option
Mapping of the ARI conf struct's globals to the general context in the config file.
#define MAX_VARS
static struct aco_type * global_user[]
static void conf_destructor(void *obj)
ast_ari_conf destructor.
static struct aco_type * general_options[]
int ast_ari_config_init(void)
Initialize the ARI configuration.
static int user_sort_cmp(const void *obj_left, const void *obj_right, int flags)
Sorting function for use with red/black tree.
static int encoding_format_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
Encoding format handler converts from boolean to enum.
static int channelvars_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
struct ast_ari_conf_user * ast_ari_config_validate_user(const char *username, const char *password)
Validated a user's credentials.
void ast_ari_config_destroy(void)
Destroy the ARI configuration.
static int validate_user_cb(void *obj, void *arg, int flags)
Callback to validate a user object.
static void * user_find(struct ao2_container *tmp_container, const char *cat)
aco_type item_find function
static void user_dtor(void *obj)
Destructor for ast_ari_conf_user.
#define CONF_FILENAME
static char user[512]
static int reload(void)
#define NULL
Definition: resample.c:96
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:359
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:374
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
Definition: utils.c:2199
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
The representation of a single configuration file to be processed.
const char * filename
Type information about a category-level configurable object.
enum aco_type_t type
Generic container type.
Global configuration options for ARI.
Definition: internal.h:65
enum ast_json_encoding_format format
Definition: internal.h:71
Per-user configuration options.
Definition: internal.h:96
char password[ARI_PASSWORD_LEN]
Definition: internal.h:100
char * username
Definition: internal.h:98
All configuration options for ARI.
Definition: internal.h:54
struct ao2_container * users
Definition: internal.h:58
struct ast_ari_conf_general * general
Definition: internal.h:56
Structure for variables, used for configurations and for channel variables.
All configuration options for http media cache.
struct conf_general_options * general
structure to hold users read from users.conf
list of users found in the config file
const char * args
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
Definition: utils.h:941
#define ast_assert(a)
Definition: utils.h:739
int ast_crypt_validate(const char *key, const char *expected)
Asterisk wrapper around crypt(3) for validating passwords.
Definition: crypt.c:136