Asterisk - The Open Source Telephony Project  18.5.0
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 <[email protected]>
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 <[email protected]>
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. */
38 static struct aco_type general_option = {
39  .type = ACO_GLOBAL,
40  .name = "general",
41  .item_offset = offsetof(struct ast_ari_conf, general),
42  .category = "general",
43  .category_match = ACO_WHITELIST_EXACT,
44 };
45 
46 static struct aco_type *general_options[] = ACO_TYPES(&general_option);
47 
48 /*! \brief Encoding format handler converts from boolean to enum. */
49 static 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 */
65 static 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) {
72  } else if (strcasecmp(var->value, "crypt") == 0) {
74  } else {
75  return -1;
76  }
77 
78  return 0;
79 }
80 
81 /*! \brief Destructor for \ref ast_ari_conf_user */
82 static 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 */
90 static 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 
100  user = ao2_alloc_options(sizeof(*user), user_dtor,
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 */
116 static 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) {
124  case OBJ_SEARCH_OBJECT:
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 */
147 static 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 
156 static 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 
168 static struct aco_type *global_user[] = ACO_TYPES(&user_option);
169 
170 static 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. */
178 static 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 */
187 static 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 
197  cfg->general = ao2_alloc_options(sizeof(*cfg->general), conf_general_dtor,
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. */
217 static struct aco_file conf_file = {
218  /*! The config file name. */
220  /*! The mapping object types to be processed. */
221  .types = ACO_TYPES(&general_option, &user_option),
222 };
223 
225  .files = ACO_FILES(&conf_file));
226 
228 {
229  struct ast_ari_conf *res = ao2_global_obj_ref(confs);
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 
249  user = ao2_find(conf->users, username, OBJ_SEARCH_KEY);
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 */
279 static 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. */
292 static int process_config(int reload)
293 {
295 
296  switch (aco_process_config(&cfg_info, reload)) {
297  case ACO_PROCESS_ERROR:
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 
323 static 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);
331  AST_STANDARD_APP_ARGS(args, parse);
332 
333  ast_channel_set_ari_vars(args.argc, args.vars);
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,
349  general_options, "no", encoding_format_handler, 0);
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,
373  global_user, "plain", password_format_handler, 0);
374 
375  return process_config(0);
376 }
377 
379 {
380  return process_config(1);
381 }
382 
384 {
385  aco_info_destroy(&cfg_info);
387 }
static char user[512]
void ast_ari_config_destroy(void)
Destroy the ARI configuration.
static struct aco_type user_option
static struct aco_file conf_file
The conf file that&#39;s processed for the module.
static struct aco_type general_option
Mapping of the ARI conf struct&#39;s globals to the general context in the config file.
Asterisk main include file. File version handling, generic pbx functions.
int ao2_container_count(struct ao2_container *c)
Returns the number of elements in a container.
static void * user_find(struct ao2_container *tmp_container, const char *cat)
aco_type item_find function
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.
#define aco_option_register_custom(info, name, matchtype, types, default_val, handler, flags)
Register a config option.
struct ast_ari_conf * ast_ari_config_get(void)
Get the current ARI configuration.
The arg parameter is a search key, but is not an object.
Definition: astobj2.h:1105
static void user_dtor(void *obj)
Destructor for ast_ari_conf_user.
static struct aco_type * general_options[]
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
#define LOG_WARNING
Definition: logger.h:274
struct ast_ari_conf_general * general
Definition: internal.h:56
#define ao2_callback(c, flags, cb_fn, arg)
Definition: astobj2.h:1716
All configuration options for ARI.
Definition: internal.h:54
#define aco_option_register(info, name, matchtype, types, default_val, opt_type, flags,...)
Register a config option.
static int process_config(int reload)
Load (or reload) configuration.
Structure for variables, used for configurations and for channel variables.
#define var
Definition: ast_expr2f.c:614
#define ARI_PASSWORD_LEN
User&#39;s password mx length.
Definition: internal.h:93
Type for a default handler that should do nothing.
char * username
Definition: internal.h:98
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.
int ast_ari_config_reload(void)
Reload the ARI configuration.
#define ao2_global_obj_ref(holder)
Definition: astobj2.h:925
#define ao2_alloc_options(data_size, destructor_fn, options)
Definition: astobj2.h:406
#define ast_assert(a)
Definition: utils.h:695
Plaintext password.
Definition: internal.h:83
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:243
const char * args
#define NULL
Definition: resample.c:96
The representation of a single configuration file to be processed.
list of users found in the config file
enum aco_type_t type
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:7994
#define ACO_TYPES(...)
A helper macro to ensure that aco_info types always have a sentinel.
static struct ast_str * password
Definition: cdr_mysql.c:77
#define MAX_VARS
#define ast_strlen_zero(foo)
Definition: strings.h:52
All configuration options for statsd client.
Definition: res_statsd.c:95
Type for default option handler for character array strings.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
#define ast_log
Definition: astobj2.c:42
The arg parameter is a partial search key similar to OBJ_SEARCH_KEY.
Definition: astobj2.h:1120
#define FLDSET(type,...)
Convert a struct and list of fields to an argument list of field offsets.
Global configuration options for ARI.
Definition: internal.h:65
static int channelvars_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)
int aco_info_init(struct aco_info *info)
Initialize an aco_info structure.
General Asterisk PBX channel definitions.
#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:911
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
Definition: stringfields.h:353
#define ARI_AUTH_REALM_LEN
Definition: internal.h:62
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
Support for WebSocket connections within the Asterisk HTTP server and client WebSocket connections to...
The config had not been edited and no changes applied.
Their was an error and no changes were applied.
Configuration option-handling.
static int user_sort_cmp(const void *obj_left, const void *obj_right, int flags)
Sorting function for use with red/black tree.
#define LOG_ERROR
Definition: logger.h:285
Per-user configuration options.
Definition: internal.h:96
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: main/utils.c:1951
enum ast_json_encoding_format format
Definition: internal.h:71
Internal API&#39;s for res_ari.
static int validate_user_cb(void *obj, void *arg, int flags)
Callback to validate a user object.
void aco_info_destroy(struct aco_info *info)
Destroy an initialized aco_info struct.
#define ao2_global_obj_release(holder)
Definition: astobj2.h:865
Type for default option handler for bools (ast_true/ast_false)
char password[ARI_PASSWORD_LEN]
Definition: internal.h:100
CONFIG_INFO_STANDARD(cfg_info, confs, conf_alloc,.files=ACO_FILES(&conf_file))
int ast_ari_config_init(void)
Initialize the ARI configuration.
static void * conf_alloc(void)
Allocate an ast_ari_conf for config parsing.
static void parse(struct mgcp_request *req)
Definition: chan_mgcp.c:1872
#define ast_free(a)
Definition: astmm.h:182
static int reload(void)
Definition: cdr_mysql.c:741
int aco_set_defaults(struct aco_type *type, const char *category, void *obj)
Set all default options of obj.
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.
#define ao2_find(container, arg, flags)
Definition: astobj2.h:1756
static AO2_GLOBAL_OBJ_STATIC(confs)
Locking container for safe configuration access.
structure to hold users read from users.conf
enum ast_ari_password_format password_format
Definition: internal.h:102
static void * user_alloc(const char *cat)
Allocate an ast_ari_conf_user for config parsing.
#define ACO_FILES(...)
The arg parameter is an object of the same type.
Definition: astobj2.h:1091
Replace objects with duplicate keys in container.
Definition: astobj2.h:1215
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
Type information about a category-level configurable object.
int ast_crypt_validate(const char *key, const char *expected)
Asterisk wrapper around crypt(3) for validating passwords.
Definition: crypt.c:136
const char * filename
#define AST_DEFAULT_WEBSOCKET_WRITE_TIMEOUT_STR
Default websocket write timeout, in ms (as a string)
Type for default option handler for stringfields.
#define ao2_container_alloc_rbtree(ao2_options, container_options, sort_fn, cmp_fn)
Definition: astobj2.h:1358
struct ast_ari_conf_user * ast_ari_config_validate_user(const char *username, const char *password)
Validated a user&#39;s credentials.
Generic container type.
Search option field mask.
Definition: astobj2.h:1076
Type for default option handler for signed integers.
static void conf_destructor(void *obj)
ast_ari_conf destructor.
static void conf_general_dtor(void *obj)
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
Definition: stringfields.h:368
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
#define CONF_FILENAME
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 struct aco_type * global_user[]
struct ao2_container * users
Definition: internal.h:58
#define AST_APP_ARG(name)
Define an application argument.
static int enabled
Definition: dnsmgr.c:91