00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 #include "asterisk.h"
00031
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 398103 $")
00033
00034 #include "asterisk/config.h"
00035 #include "asterisk/config_options.h"
00036 #include "asterisk/event.h"
00037 #include "asterisk/utils.h"
00038 #include "asterisk/module.h"
00039 #include "asterisk/cli.h"
00040 #include "asterisk/acl.h"
00041 #include "asterisk/astobj2.h"
00042 #include "asterisk/paths.h"
00043
00044 #define NACL_CONFIG "acl.conf"
00045 #define ACL_FAMILY "acls"
00046
00047 struct named_acl_global_config {
00048 AST_DECLARE_STRING_FIELDS(
00049
00050 );
00051 };
00052
00053
00054
00055
00056
00057
00058 struct named_acl_config {
00059 struct named_acl_global_config *global;
00060 struct ao2_container *named_acl_list;
00061 };
00062
00063 static AO2_GLOBAL_OBJ_STATIC(globals);
00064
00065
00066 static void *named_acl_config_alloc(void);
00067 static void *named_acl_alloc(const char *cat);
00068 static void *named_acl_find(struct ao2_container *container, const char *cat);
00069
00070
00071 static struct aco_type named_acl_type = {
00072 .type = ACO_ITEM,
00073 .category_match = ACO_BLACKLIST,
00074 .category = "^general$",
00075 .item_alloc = named_acl_alloc,
00076 .item_find = named_acl_find,
00077 .item_offset = offsetof(struct named_acl_config, named_acl_list),
00078 };
00079
00080
00081 static struct aco_type global_option = {
00082 .type = ACO_GLOBAL,
00083 .item_offset = offsetof(struct named_acl_config, global),
00084 .category_match = ACO_WHITELIST,
00085 .category = "^general$",
00086 };
00087
00088
00089 struct aco_type *named_acl_types[] = ACO_TYPES(&named_acl_type);
00090
00091 struct aco_type *global_options[] = ACO_TYPES(&global_option);
00092
00093 struct aco_file named_acl_conf = {
00094 .filename = "acl.conf",
00095 .types = ACO_TYPES(&named_acl_type, &global_option),
00096 };
00097
00098
00099 CONFIG_INFO_STANDARD(cfg_info, globals, named_acl_config_alloc,
00100 .files = ACO_FILES(&named_acl_conf),
00101 );
00102
00103 struct named_acl {
00104 struct ast_ha *ha;
00105 char name[ACL_NAME_LENGTH];
00106 };
00107
00108 static int named_acl_hash_fn(const void *obj, const int flags)
00109 {
00110 const struct named_acl *entry = obj;
00111 return ast_str_hash(entry->name);
00112 }
00113
00114 static int named_acl_cmp_fn(void *obj, void *arg, const int flags)
00115 {
00116 struct named_acl *entry1 = obj;
00117 struct named_acl *entry2 = arg;
00118
00119 return (!strcmp(entry1->name, entry2->name)) ? (CMP_MATCH | CMP_STOP) : 0;
00120 }
00121
00122
00123 static void named_acl_config_destructor(void *obj)
00124 {
00125 struct named_acl_config *cfg = obj;
00126 ao2_cleanup(cfg->named_acl_list);
00127 ao2_cleanup(cfg->global);
00128 }
00129
00130 static void named_acl_global_config_destructor(void *obj)
00131 {
00132 struct named_acl_global_config *global = obj;
00133 ast_string_field_free_memory(global);
00134 }
00135
00136
00137
00138
00139 static void *named_acl_config_alloc(void)
00140 {
00141 struct named_acl_config *cfg;
00142
00143 if (!(cfg = ao2_alloc(sizeof(*cfg), named_acl_config_destructor))) {
00144 return NULL;
00145 }
00146
00147 if (!(cfg->global = ao2_alloc(sizeof(*cfg->global), named_acl_global_config_destructor))) {
00148 goto error;
00149 }
00150
00151 if (ast_string_field_init(cfg->global, 128)) {
00152 goto error;
00153 }
00154
00155 if (!(cfg->named_acl_list = ao2_container_alloc(37, named_acl_hash_fn, named_acl_cmp_fn))) {
00156 goto error;
00157 }
00158
00159 return cfg;
00160
00161 error:
00162 ao2_ref(cfg, -1);
00163 return NULL;
00164 }
00165
00166
00167 static void destroy_named_acl(void *obj)
00168 {
00169 struct named_acl *named_acl = obj;
00170 ast_free_ha(named_acl->ha);
00171 }
00172
00173
00174
00175
00176
00177
00178
00179
00180 void *named_acl_alloc(const char *cat)
00181 {
00182 struct named_acl *named_acl;
00183
00184 named_acl = ao2_alloc(sizeof(*named_acl), destroy_named_acl);
00185 if (!named_acl) {
00186 return NULL;
00187 }
00188
00189 ast_copy_string(named_acl->name, cat, sizeof(named_acl->name));
00190
00191 return named_acl;
00192 }
00193
00194
00195
00196
00197
00198
00199
00200
00201 void *named_acl_find(struct ao2_container *container, const char *cat)
00202 {
00203 struct named_acl tmp;
00204 ast_copy_string(tmp.name, cat, sizeof(tmp.name));
00205 return ao2_find(container, &tmp, OBJ_POINTER);
00206 }
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220 static int acl_order_comparator(struct ast_category *p, struct ast_category *q)
00221 {
00222 int p_value = 0, q_value = 0;
00223 struct ast_variable *p_var = ast_category_first(p);
00224 struct ast_variable *q_var = ast_category_first(q);
00225
00226 while (p_var) {
00227 if (!strcasecmp(p_var->name, "rule_order")) {
00228 p_value = atoi(p_var->value);
00229 break;
00230 }
00231 p_var = p_var->next;
00232 }
00233
00234 while (q_var) {
00235 if (!strcasecmp(q_var->name, "rule_order")) {
00236 q_value = atoi(q_var->value);
00237 break;
00238 }
00239 q_var = q_var->next;
00240 }
00241
00242 if (p_value < q_value) {
00243 return -1;
00244 } else if (q_value < p_value) {
00245 return 1;
00246 }
00247
00248 return 0;
00249 }
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259 static struct named_acl *named_acl_find_realtime(const char *name)
00260 {
00261 struct ast_config *cfg;
00262 char *item = NULL;
00263 const char *systemname = NULL;
00264 struct ast_ha *built_ha = NULL;
00265 struct named_acl *acl;
00266
00267
00268 systemname = ast_config_AST_SYSTEM_NAME;
00269
00270 if (ast_strlen_zero(systemname)) {
00271 cfg = ast_load_realtime_multientry(ACL_FAMILY, "name", name, SENTINEL);
00272 } else {
00273 cfg = ast_load_realtime_multientry(ACL_FAMILY, "name", name, "systemname", systemname, SENTINEL);
00274 }
00275
00276 if (!cfg) {
00277 return NULL;
00278 }
00279
00280
00281 ast_config_sort_categories(cfg, 0, acl_order_comparator);
00282
00283 while ((item = ast_category_browse(cfg, item))) {
00284 int append_ha_error = 0;
00285 const char *order = ast_variable_retrieve(cfg, item, "rule_order");
00286 const char *sense = ast_variable_retrieve(cfg, item, "sense");
00287 const char *rule = ast_variable_retrieve(cfg, item, "rule");
00288
00289 built_ha = ast_append_ha(sense, rule, built_ha, &append_ha_error);
00290 if (append_ha_error) {
00291
00292 ast_log(LOG_ERROR, "Rejecting realtime ACL due to bad ACL definition '%s': %s - %s - %s\n", name, order, sense, rule);
00293 ast_free_ha(built_ha);
00294 return NULL;
00295 }
00296 }
00297
00298 ast_config_destroy(cfg);
00299
00300 acl = named_acl_alloc(name);
00301 if (!acl) {
00302 ast_log(LOG_ERROR, "allocation error\n");
00303 ast_free_ha(built_ha);
00304 return NULL;
00305 }
00306
00307 acl->ha = built_ha;
00308
00309 return acl;
00310 }
00311
00312 struct ast_ha *ast_named_acl_find(const char *name, int *is_realtime, int *is_undefined) {
00313 struct ast_ha *ha = NULL;
00314
00315 RAII_VAR(struct named_acl_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
00316 RAII_VAR(struct named_acl *, named_acl, NULL, ao2_cleanup);
00317
00318 if (is_realtime) {
00319 *is_realtime = 0;
00320 }
00321
00322 if (is_undefined) {
00323 *is_undefined = 0;
00324 }
00325
00326
00327 if ((!cfg) || (!(cfg->named_acl_list))) {
00328 ast_log(LOG_ERROR, "Attempted to find named ACL '%s', but the ACL configuration isn't available.\n", name);
00329 return NULL;
00330 }
00331
00332 named_acl = named_acl_find(cfg->named_acl_list, name);
00333
00334
00335 if (!named_acl) {
00336 RAII_VAR(struct named_acl *, realtime_acl, NULL, ao2_cleanup);
00337
00338
00339 if ((realtime_acl = named_acl_find_realtime(name))) {
00340 if (is_realtime) {
00341 *is_realtime = 1;
00342 }
00343 ha = ast_duplicate_ha_list(realtime_acl->ha);
00344 return ha;
00345 }
00346
00347
00348 if (ast_realtime_is_mapping_defined(ACL_FAMILY) && !ast_check_realtime(ACL_FAMILY)) {
00349 ast_log(LOG_WARNING, "ACL '%s' does not exist. The ACL will be marked as undefined and will automatically fail if applied.\n"
00350 "This ACL may exist in the configured realtime backend, but that backend hasn't been registered yet. "
00351 "Fix this establishing preload for the backend in 'modules.conf'.\n", name);
00352 } else {
00353 ast_log(LOG_WARNING, "ACL '%s' does not exist. The ACL will be marked as undefined and will automatically fail if applied.\n", name);
00354 }
00355
00356 if (is_undefined) {
00357 *is_undefined = 1;
00358 }
00359
00360 return NULL;
00361 }
00362
00363 ha = ast_duplicate_ha_list(named_acl->ha);
00364
00365 if (!ha) {
00366 ast_log(LOG_NOTICE, "ACL '%s' contains no rules. It is valid, but it will accept addresses unconditionally.\n", name);
00367 }
00368
00369 return ha;
00370 }
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382 static int push_acl_change_event(char *name)
00383 {
00384 struct ast_event *event = ast_event_new(AST_EVENT_ACL_CHANGE,
00385 AST_EVENT_IE_DESCRIPTION, AST_EVENT_IE_PLTYPE_STR, name,
00386 AST_EVENT_IE_END);
00387 if (!event) {
00388 ast_log(LOG_ERROR, "Failed to allocate acl.conf reload event. Some modules will have out of date ACLs.\n");
00389 return -1;
00390 }
00391
00392 if (ast_event_queue(event)) {
00393 ast_event_destroy(event);
00394 ast_log(LOG_ERROR, "Failed to queue acl.conf reload event. Some modules will have out of date ACLs.\n");
00395 return -1;
00396 }
00397
00398 return 0;
00399 }
00400
00401
00402
00403
00404
00405
00406
00407 int ast_named_acl_reload(void)
00408 {
00409 enum aco_process_status status;
00410
00411 status = aco_process_config(&cfg_info, 1);
00412
00413 if (status == ACO_PROCESS_ERROR) {
00414 ast_log(LOG_WARNING, "Could not reload ACL config\n");
00415 return 0;
00416 }
00417
00418 if (status == ACO_PROCESS_UNCHANGED) {
00419
00420
00421
00422 return 0;
00423 }
00424
00425
00426 push_acl_change_event("");
00427
00428 return 0;
00429 }
00430
00431
00432
00433
00434
00435
00436
00437
00438 static void cli_display_named_acl(int fd, const char *name)
00439 {
00440 struct ast_ha *ha;
00441 int ha_index = 0;
00442 int is_realtime = 0;
00443
00444 RAII_VAR(struct named_acl_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
00445 RAII_VAR(struct named_acl *, named_acl, NULL, ao2_cleanup);
00446
00447
00448 if ((!cfg) || (!cfg->named_acl_list)) {
00449 ast_log(LOG_ERROR, "Attempted to show named ACL '%s', but the acl configuration isn't available.\n", name);
00450 return;
00451 }
00452
00453 named_acl = named_acl_find(cfg->named_acl_list, name);
00454
00455
00456 if (!named_acl) {
00457 if (!(named_acl = named_acl_find_realtime(name))) {
00458 ast_cli(fd, "\nCould not find ACL named '%s'\n", name);
00459 return;
00460 }
00461
00462 is_realtime = 1;
00463 }
00464
00465 ast_cli(fd, "\nACL: %s%s\n---------------------------------------------\n", name, is_realtime ? " (realtime)" : "");
00466 for (ha = named_acl->ha; ha; ha = ha->next) {
00467 char *addr = ast_strdupa(ast_sockaddr_stringify_addr(&ha->addr));
00468 char *mask = ast_sockaddr_stringify_addr(&ha->netmask);
00469 ast_cli(fd, "%3d: %s - %s/%s\n", ha_index, ha->sense == AST_SENSE_ALLOW ? "allow" : " deny", addr, mask);
00470 ha_index++;
00471 }
00472 }
00473
00474
00475
00476
00477
00478
00479
00480 static void cli_display_named_acl_list(int fd)
00481 {
00482 struct ao2_iterator i;
00483 void *o;
00484 RAII_VAR(struct named_acl_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
00485
00486 ast_cli(fd, "\nacl\n---\n");
00487
00488 if (!cfg || !cfg->named_acl_list) {
00489 ast_cli(fd, "ACL configuration isn't available.\n");
00490 return;
00491 }
00492 i = ao2_iterator_init(cfg->named_acl_list, 0);
00493
00494 while ((o = ao2_iterator_next(&i))) {
00495 struct named_acl *named_acl = o;
00496 ast_cli(fd, "%s\n", named_acl->name);
00497 ao2_ref(o, -1);
00498 }
00499
00500 ao2_iterator_destroy(&i);
00501 }
00502
00503
00504 static char *handle_show_named_acl_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00505 {
00506 RAII_VAR(struct named_acl_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
00507 int length;
00508 int which;
00509 struct ao2_iterator i;
00510 struct named_acl *named_acl;
00511 char *match = NULL;
00512
00513 switch (cmd) {
00514 case CLI_INIT:
00515 e->command = "acl show";
00516 e->usage =
00517 "Usage: acl show [name]\n"
00518 " Shows a list of named ACLs or lists all entries in a given named ACL.\n";
00519 return NULL;
00520 case CLI_GENERATE:
00521 if (!cfg) {
00522 return NULL;
00523 }
00524 length = strlen(a->word);
00525 which = 0;
00526 i = ao2_iterator_init(cfg->named_acl_list, 0);
00527 while ((named_acl = ao2_iterator_next(&i))) {
00528 if (!strncasecmp(a->word, named_acl->name, length) && ++which > a->n) {
00529 match = ast_strdup(named_acl->name);
00530 ao2_ref(named_acl, -1);
00531 break;
00532 }
00533 ao2_ref(named_acl, -1);
00534 }
00535 ao2_iterator_destroy(&i);
00536 return match;
00537
00538 }
00539
00540 if (a->argc == 2) {
00541 cli_display_named_acl_list(a->fd);
00542 return CLI_SUCCESS;
00543 }
00544
00545 if (a->argc == 3) {
00546 cli_display_named_acl(a->fd, a->argv[2]);
00547 return CLI_SUCCESS;
00548 }
00549
00550
00551 return CLI_SHOWUSAGE;
00552 }
00553
00554 static struct ast_cli_entry cli_named_acl[] = {
00555 AST_CLI_DEFINE(handle_show_named_acl_cmd, "Show a named ACL or list all named ACLs"),
00556 };
00557
00558 static void named_acl_cleanup(void)
00559 {
00560 ast_cli_unregister_multiple(cli_named_acl, ARRAY_LEN(cli_named_acl));
00561
00562 aco_info_destroy(&cfg_info);
00563 ao2_global_obj_release(globals);
00564 }
00565
00566 int ast_named_acl_init()
00567 {
00568 ast_cli_register_multiple(cli_named_acl, ARRAY_LEN(cli_named_acl));
00569
00570 ast_register_atexit(named_acl_cleanup);
00571
00572 if (aco_info_init(&cfg_info)) {
00573 return 0;
00574 }
00575
00576
00577 aco_option_register(&cfg_info, "permit", ACO_EXACT, named_acl_types, NULL, OPT_ACL_T, 1, FLDSET(struct named_acl, ha));
00578 aco_option_register(&cfg_info, "deny", ACO_EXACT, named_acl_types, NULL, OPT_ACL_T, 0, FLDSET(struct named_acl, ha));
00579
00580 if (aco_process_config(&cfg_info, 0)) {
00581 aco_info_destroy(&cfg_info);
00582 return 0;
00583 }
00584
00585 return 0;
00586 }