Asterisk - The Open Source Telephony Project GIT-master-97770a9
common_config.c
Go to the documentation of this file.
1/*
2 * Asterisk -- An open source telephony toolkit.
3 *
4 * Copyright (C) 2023, Sangoma Technologies Corporation
5 *
6 * George Joseph <gjoseph@sangoma.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#include "asterisk.h"
20#include "asterisk/cli.h"
21#include "asterisk/cli.h"
22#include "asterisk/logger.h"
23#include "asterisk/module.h"
24#include "asterisk/utils.h"
25#include "asterisk/stasis.h"
27
28#define AST_API_MODULE
29#include "stir_shaken.h"
30
31static struct ast_sorcery *sorcery;
33
35{
36 return sorcery;
37}
38
39#define generate_bool_handler_functions(param_name) \
40static const char *param_name ## _map[] = { \
41 [ param_name ## _NOT_SET ] = "not_set", \
42 [ param_name ## _YES ] = "yes", \
43 [ param_name ## _NO ] = "no", \
44}; \
45enum param_name ## _enum \
46 param_name ## _from_str(const char *value) \
47{ \
48 if (!strcasecmp(value, param_name ## _map[param_name ## _NOT_SET])) { \
49 return param_name ## _NOT_SET; \
50 } else if (ast_true(value)) { \
51 return param_name ## _YES; \
52 } else if (ast_false(value)) { \
53 return param_name ## _NO; \
54 } \
55 ast_log(LOG_WARNING, "Unknown " #param_name " response value '%s'\n", value); \
56 return param_name ## _UNKNOWN; \
57}\
58const char *param_name ## _to_str(enum param_name ## _enum value) \
59{ \
60 return ARRAY_IN_BOUNDS(value, param_name ## _map) ? \
61 param_name ## _map[value] : NULL; \
62}
63
64generate_bool_handler_functions(use_rfc9410_responses);
66generate_bool_handler_functions(check_tn_cert_public_url);
67generate_bool_handler_functions(relax_x5u_port_scheme_restrictions);
68generate_bool_handler_functions(relax_x5u_path_restrictions);
69
71
73 int value;
74 const char *name;
75};
76
77#define generate_enum_string_functions(param_name, default_value, ...)\
78static struct enum_name_xref_entry param_name ## _map[] = { \
79 __VA_ARGS__ \
80} ; \
81enum param_name ## _enum param_name ## _from_str( \
82 const char *value) \
83{ \
84 int i; \
85 for (i = 0; i < ARRAY_LEN(param_name ## _map); i++) { \
86 if (strcasecmp(value, param_name ##_map[i].name) == 0) { \
87 return param_name ##_map[i].value; \
88 } \
89 } \
90 return param_name ## _ ## default_value; \
91} \
92const char *param_name ## _to_str( \
93 enum param_name ## _enum value) \
94{ \
95 int i; \
96 for (i = 0; i < ARRAY_LEN(param_name ## _map); i++) { \
97 if (value == param_name ## _map[i].value) return param_name ## _map[i].name; \
98 } \
99 return NULL; \
100}
101
103 {attest_level_NOT_SET, "not_set"},
104 {attest_level_A, "A"},
105 {attest_level_B, "B"},
106 {attest_level_C, "C"},
107);
108
109generate_enum_string_functions(endpoint_behavior, OFF,
110 {endpoint_behavior_OFF, "off"},
111 {endpoint_behavior_OFF, "none"},
112 {endpoint_behavior_ATTEST, "attest"},
113 {endpoint_behavior_VERIFY, "verify"},
114 {endpoint_behavior_ON, "on"},
115 {endpoint_behavior_ON, "both"}
116);
117
118generate_enum_string_functions(stir_shaken_failure_action, CONTINUE,
121 {stir_shaken_failure_action_CONTINUE_RETURN_REASON, "continue_return_reason"},
122);
123
124static const char *translate_value(const char *val)
125{
126 if (val[0] == '0'
127 || val[0] == '\0'
128 || strcmp(val, "not_set") == 0) {
129 return "";
130 }
131
132 return val;
133}
134
135static void print_acl(int fd, struct ast_acl_list *acl_list, const char *prefix)
136{
137 struct ast_acl *acl;
138
139 AST_LIST_LOCK(acl_list);
140 AST_LIST_TRAVERSE(acl_list, acl, list) {
141 if (ast_strlen_zero(acl->name)) {
142 ast_cli(fd, "%s(permit/deny)\n", prefix);
143 } else {
144 ast_cli(fd, "%s%s\n", prefix, acl->name);
145 }
146 ast_ha_output(fd, acl->acl, prefix);
147 }
148 AST_LIST_UNLOCK(acl_list);
149}
150
151#define print_acl_cert_store(cfg, a, max_name_len) \
152({ \
153 if (cfg->vcfg_common.acl) { \
154 ast_cli(a->fd, "x5u_acl:\n"); \
155 print_acl(a->fd, cfg->vcfg_common.acl, " "); \
156 } else { \
157 ast_cli(a->fd, "%-*s: (none)\n", max_name_len, "x5u_acl"); \
158 }\
159 if (cfg->vcfg_common.tcs) { \
160 int count = 0; \
161 ast_cli(a->fd, "%-*s:\n", max_name_len, "Verification CA certificate store"); \
162 count = crypto_show_cli_store(cfg->vcfg_common.tcs, a->fd); \
163 if (count == 0 && (!ast_strlen_zero(cfg->vcfg_common.ca_path) \
164 || !ast_strlen_zero(cfg->vcfg_common.crl_path))) { \
165 ast_cli(a->fd, " Note: Certs in ca_path or crl_path won't show until used.\n"); \
166 } \
167 } else { \
168 ast_cli(a->fd, "%-*s: (none)\n", max_name_len, "Verification CA certificate store"); \
169 } \
170})
171
172int config_object_cli_show(void *obj, void *arg, void *data, int flags)
173{
174 struct ast_cli_args *a = arg;
175 struct config_object_cli_data *cli_data = data;
176 struct ast_variable *options;
177 struct ast_variable *i;
178 const char *title = NULL;
179 const char *cfg_name = NULL;
180 int max_name_len = 0;
181
182 if (!obj) {
183 ast_cli(a->fd, "No stir/shaken configuration found\n");
184 return 0;
185 }
186
187 if (!ast_strlen_zero(cli_data->title)) {
188 title = cli_data->title;
189 } else {
190 title = ast_sorcery_object_get_type(obj);
191 }
192 max_name_len = strlen(title);
193
195 || cli_data->object_type == config_object_type_tn) {
196 cfg_name = ast_sorcery_object_get_id(obj);
197 max_name_len += strlen(cfg_name) + 2 /* ": " */;
198 }
199
202 if (!options) {
203 return 0;
204 }
205
206 for (i = options; i; i = i->next) {
207 int nlen = strlen(i->name);
208 max_name_len = (nlen > max_name_len) ? nlen : max_name_len;
209 }
210
211 ast_cli(a->fd, "\n==============================================================================\n");
212 if (ast_strlen_zero(cfg_name)) {
213 ast_cli(a->fd, "%s\n", title);
214 } else {
215 ast_cli(a->fd, "%s: %s\n", title, cfg_name);
216 }
217 ast_cli(a->fd, "------------------------------------------------------------------------------\n");
218
219 for (i = options; i; i = i->next) {
220 if (!ast_strings_equal(i->name, "x5u_acl")) {
221 ast_cli(a->fd, "%-*s: %s\n", max_name_len, i->name,
223 }
224 }
225
227
228 if (cli_data->object_type == config_object_type_profile) {
229 struct profile_cfg *cfg = obj;
230 print_acl_cert_store(cfg, a, max_name_len);
231 } else if (cli_data->object_type == config_object_type_verification) {
232 struct verification_cfg *cfg = obj;
233 print_acl_cert_store(cfg, a, max_name_len);
234 }
235 ast_cli(a->fd, "---------------------------------------------\n\n"); \
236
237 return 0;
238}
239
241{
242 void *obj;
243 struct ao2_iterator it;
244 int wordlen = strlen(word);
245 int ret;
246
248 while ((obj = ao2_iterator_next(&it))) {
249 if (!strncasecmp(word, ast_sorcery_object_get_id(obj), wordlen)) {
251 if (ret) {
252 ao2_ref(obj, -1);
253 break;
254 }
255 }
256 ao2_ref(obj, -1);
257 }
259
260 return NULL;
261}
262
263
264/* Remove everything except 0-9, *, and # in telephone number according to RFC 8224
265 * (required by RFC 8225 as part of canonicalization) */
266char *canonicalize_tn(const char *tn, char *dest_tn)
267{
268 int i;
269 const char *s = tn;
270 size_t len = tn ? strlen(tn) : 0;
271 char *new_tn = dest_tn;
272 SCOPE_ENTER(3, "tn: %s\n", S_OR(tn, "(null)"));
273
274 if (ast_strlen_zero(tn)) {
275 *dest_tn = '\0';
276 SCOPE_EXIT_RTN_VALUE(NULL, "Empty TN\n");
277 }
278
279 if (!dest_tn) {
280 SCOPE_EXIT_RTN_VALUE(NULL, "No destination buffer\n");
281 }
282
283 for (i = 0; i < len; i++) {
284 if (isdigit(*s) || *s == '#' || *s == '*') { /* Only characters allowed */
285 *new_tn++ = *s;
286 }
287 s++;
288 }
289 *new_tn = '\0';
290 SCOPE_EXIT_RTN_VALUE(dest_tn, "Canonicalized '%s' -> '%s'\n", tn, dest_tn);
291}
292
293char *canonicalize_tn_alloc(const char *tn)
294{
295 char *canon_tn = ast_strlen_zero(tn) ? NULL : ast_malloc(strlen(tn) + 1);
296 if (!canon_tn) {
297 return NULL;
298 }
299 return canonicalize_tn(tn, canon_tn);
300}
301
302static char *cli_verify_cert(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
303{
304 RAII_VAR(struct profile_cfg *, profile, NULL, ao2_cleanup);
305 RAII_VAR(struct verification_cfg *, vs_cfg, NULL, ao2_cleanup);
306 struct crypto_cert_store *tcs;
307 X509 *cert = NULL;
308 const char *errmsg = NULL;
309
310 switch(cmd) {
311 case CLI_INIT:
312 e->command = "stir_shaken verify certificate_file";
313 e->usage =
314 "Usage: stir_shaken verify certificate_file <certificate_file> [ <profile> ]\n"
315 " Verify an external certificate file against the global or profile verification store\n";
316 return NULL;
317 case CLI_GENERATE:
318 if (a->pos == 4) {
320 } else {
321 return NULL;
322 }
323 }
324
325 if (a->argc < 4) {
326 return CLI_SHOWUSAGE;
327 }
328
329 if (a->argc == 5) {
330 profile = profile_get_cfg(a->argv[4]);
331 if (!profile) {
332 ast_cli(a->fd, "Profile %s doesn't exist\n", a->argv[4]);
333 return CLI_SUCCESS;
334 }
335 if (!profile->vcfg_common.tcs) {
336 ast_cli(a->fd,"Profile %s doesn't have a certificate store\n", a->argv[4]);
337 return CLI_SUCCESS;
338 }
339 tcs = profile->vcfg_common.tcs;
340 } else {
341 vs_cfg = vs_get_cfg();
342 if (!vs_cfg) {
343 ast_cli(a->fd, "No verification store found\n");
344 return CLI_SUCCESS;
345 }
346 tcs = vs_cfg->vcfg_common.tcs;
347 }
348
349 cert = crypto_load_cert_from_file(a->argv[3]);
350 if (!cert) {
351 ast_cli(a->fd, "Failed to load certificate from %s. See log for details\n", a->argv[3]);
352 return CLI_SUCCESS;
353 }
354
355 if (crypto_is_cert_trusted(tcs, cert, &errmsg)) {
356 ast_cli(a->fd, "Certificate %s trusted\n", a->argv[3]);
357 } else {
358 ast_cli(a->fd, "Certificate %s NOT trusted: %s\n", a->argv[3], errmsg);
359 }
360 X509_free(cert);
361
362 return CLI_SUCCESS;
363}
364
365static struct ast_cli_entry cli_commands[] = {
366 AST_CLI_DEFINE(cli_verify_cert, "Verify a certificate file against the global or a profile verification store"),
367};
368
370{
371 SCOPE_ENTER(2, "Stir Shaken Reload\n");
372 if (vs_reload()) {
373 SCOPE_EXIT_RTN_VALUE(AST_MODULE_LOAD_DECLINE, "Stir Shaken VS Reload failed\n");
374 }
375
376 if (as_reload()) {
377 SCOPE_EXIT_RTN_VALUE(AST_MODULE_LOAD_DECLINE, "Stir Shaken AS Reload failed\n");
378 }
379
380 if (tn_config_reload()) {
381 SCOPE_EXIT_RTN_VALUE(AST_MODULE_LOAD_DECLINE, "Stir Shaken TN Reload failed\n");
382 }
383
384 if (profile_reload()) {
385 SCOPE_EXIT_RTN_VALUE(AST_MODULE_LOAD_DECLINE, "Stir Shaken Profile Reload failed\n");
386 }
387
388 SCOPE_EXIT_RTN_VALUE(AST_MODULE_LOAD_SUCCESS, "Stir Shaken Reload Done\n");
389}
390
392{
394
397 as_unload();
398 vs_unload();
399
403 }
405 sorcery = NULL;
406
407 return 0;
408}
409
410static void named_acl_changed_cb(void *data,
412{
414 return;
415 }
416 ast_log(LOG_NOTICE, "Named acl changed. Reloading verification and profile\n");
418}
419
421{
422 SCOPE_ENTER(2, "Stir Shaken Load\n");
423
424 if (!(sorcery = ast_sorcery_open())) {
426 SCOPE_EXIT_RTN_VALUE(AST_MODULE_LOAD_DECLINE, "Stir Shaken sorcery load failed\n");
427 }
428
429 if (vs_load()) {
431 SCOPE_EXIT_RTN_VALUE(AST_MODULE_LOAD_DECLINE, "Stir Shaken VS load failed\n");
432 }
433
434 if (as_load()) {
436 SCOPE_EXIT_RTN_VALUE(AST_MODULE_LOAD_DECLINE, "Stir Shaken AS load failed\n");
437 }
438
439 if (tn_config_load()) {
441 SCOPE_EXIT_RTN_VALUE(AST_MODULE_LOAD_DECLINE, "Stir Shaken TN load failed\n");
442 }
443
444 if (profile_load()) {
446 SCOPE_EXIT_RTN_VALUE(AST_MODULE_LOAD_DECLINE, "Stir Shaken profile load failed\n");
447 }
448
454 SCOPE_EXIT_RTN_VALUE(AST_MODULE_LOAD_DECLINE, "Stir Shaken acl change subscribe failed\n");
455 }
458 }
459
461
462 SCOPE_EXIT_RTN_VALUE(AST_MODULE_LOAD_SUCCESS, "Stir Shaken Load Done\n");
463}
struct stasis_message_type * ast_named_acl_change_type(void)
a stasis_message_type for changes against a named ACL or the set of all named ACLs
void ast_ha_output(int fd, const struct ast_ha *ha, const char *prefix)
output an HA to the provided fd
Definition: acl.c:1103
Asterisk main include file. File version handling, generic pbx functions.
#define ast_strdup(str)
A wrapper for strdup()
Definition: astmm.h:241
#define ast_malloc(len)
A wrapper for malloc()
Definition: astmm.h:191
#define ast_log
Definition: astobj2.c:42
#define ao2_iterator_next(iter)
Definition: astobj2.h:1911
#define ao2_cleanup(obj)
Definition: astobj2.h:1934
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
int as_load()
Load the stir/shaken attestation service.
Definition: attestation.c:440
int as_unload()
Load the stir/shaken attestation service.
Definition: attestation.c:434
int as_reload()
Load the stir/shaken attestation service.
Definition: attestation.c:427
Standard Command Line Interface.
#define CLI_SHOWUSAGE
Definition: cli.h:45
#define CLI_SUCCESS
Definition: cli.h:44
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
Definition: clicompat.c:30
#define AST_CLI_DEFINE(fn, txt,...)
Definition: cli.h:197
int ast_cli_completion_add(char *value)
Add a result to a request for completion options.
Definition: main/cli.c:2768
void ast_cli(int fd, const char *fmt,...)
Definition: clicompat.c:6
@ CLI_INIT
Definition: cli.h:152
@ CLI_GENERATE
Definition: cli.h:153
#define ast_cli_register_multiple(e, len)
Register multiple commands.
Definition: cli.h:265
short word
int config_object_cli_show(void *obj, void *arg, void *data, int flags)
Output configuration settings to the Asterisk CLI.
char * config_object_tab_complete_name(const char *word, struct ao2_container *container)
Tab completion for name matching with STIR/SHAKEN CLI commands.
static const char * translate_value(const char *val)
int common_config_unload(void)
static struct ast_cli_entry cli_commands[]
static char * cli_verify_cert(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
struct stasis_subscription * named_acl_changed_sub
Definition: common_config.c:32
int common_config_reload(void)
char * canonicalize_tn_alloc(const char *tn)
Canonicalize a TN into nre buffer.
int common_config_load(void)
static void named_acl_changed_cb(void *data, struct stasis_subscription *sub, struct stasis_message *message)
#define generate_enum_string_functions(param_name, default_value,...)
Definition: common_config.c:77
static struct ast_sorcery * sorcery
Definition: common_config.c:31
char * canonicalize_tn(const char *tn, char *dest_tn)
Canonicalize a TN.
#define generate_bool_handler_functions(param_name)
Definition: common_config.c:39
#define print_acl_cert_store(cfg, a, max_name_len)
static void print_acl(int fd, struct ast_acl_list *acl_list, const char *prefix)
struct ast_sorcery * get_sorcery(void)
Retrieve the stir/shaken sorcery context.
Definition: common_config.c:34
@ config_object_type_tn
@ config_object_type_profile
@ config_object_type_verification
int profile_unload(void)
int profile_load(void)
int tn_config_load(void)
Definition: tn_config.c:251
struct verification_cfg * vs_get_cfg(void)
int tn_config_unload(void)
Definition: tn_config.c:243
struct profile_cfg * profile_get_cfg(const char *id)
struct ao2_container * profile_get_all(void)
int tn_config_reload(void)
Definition: tn_config.c:236
int profile_reload(void)
int crypto_is_cert_trusted(struct crypto_cert_store *store, X509 *cert, const char **err_msg)
Check if the cert is trusted.
Definition: crypto_utils.c:737
X509 * crypto_load_cert_from_file(const char *filename)
Load an X509 Cert from a file.
Definition: crypto_utils.c:189
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
#define SCOPE_ENTER(level,...)
static char prefix[MAX_PREFIX]
Definition: http.c:144
struct ast_variable * ast_variable_list_sort(struct ast_variable *head)
Performs an in-place sort on the variable list by ascending name.
Definition: main/config.c:621
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Definition: extconf.c:1262
Support for logging to various files, console and syslog Configuration in file logger....
#define LOG_NOTICE
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
Definition: linkedlists.h:491
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:40
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:140
Asterisk module definitions.
@ AST_MODULE_LOAD_SUCCESS
Definition: module.h:70
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
struct stasis_forward * sub
Definition: res_corosync.c:240
struct ao2_container * container
Definition: res_fax.c:501
@ UNKNOWN
Definition: res_pjsip.h:440
@ stir_shaken_failure_action_CONTINUE
@ stir_shaken_failure_action_CONTINUE_RETURN_REASON
@ stir_shaken_failure_action_REJECT_REQUEST
#define NULL
Definition: resample.c:96
Security Event Reporting API.
struct stasis_topic * ast_security_topic(void)
A stasis_topic which publishes messages for security related issues.
#define ast_sorcery_unref(sorcery)
Decrease the reference count of a sorcery structure.
Definition: sorcery.h:1500
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
const char * ast_sorcery_object_get_type(const void *object)
Get the type of a sorcery object.
Definition: sorcery.c:2329
@ AST_HANDLER_ONLY_STRING
Use string handler only.
Definition: sorcery.h:137
#define ast_sorcery_open()
Open a new sorcery structure.
Definition: sorcery.h:406
struct ast_variable * ast_sorcery_objectset_create2(const struct ast_sorcery *sorcery, const void *object, enum ast_sorcery_field_handler_flags flags)
Create an object set (KVP list) for an object.
Definition: sorcery.c:1511
Stasis Message Bus API. See Stasis Message Bus API for detailed documentation.
struct stasis_message_type * stasis_message_type(const struct stasis_message *msg)
Get the message type for a stasis_message.
int stasis_subscription_accept_message_type(struct stasis_subscription *subscription, const struct stasis_message_type *type)
Indicate to a subscription that we are interested in a message type.
Definition: stasis.c:1024
struct stasis_subscription * stasis_unsubscribe(struct stasis_subscription *subscription)
Cancel a subscription.
Definition: stasis.c:972
#define stasis_subscribe(topic, callback, data)
Definition: stasis.h:649
int ast_strings_equal(const char *str1, const char *str2)
Compare strings for equality checking for NULL.
Definition: strings.c:238
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
Definition: strings.h:80
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
Definition: test_acl.c:111
Generic container type.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
Definition: astobj2.h:1821
Wrapper for an ast_acl linked list.
Definition: acl.h:76
an ast_acl is a linked list node of ast_ha structs which may have names.
Definition: acl.h:67
struct ast_ha * acl
Definition: acl.h:68
struct ast_acl::@180 list
descriptor for a cli entry.
Definition: cli.h:171
char * command
Definition: cli.h:186
const char * usage
Definition: cli.h:177
Full structure for sorcery.
Definition: sorcery.c:230
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
enum config_object_type object_type
ao2 object wrapper for X509_STORE that provides locking and refcounting
Definition: crypto_utils.h:179
Definition: common_config.c:72
const char * name
Definition: common_config.c:74
int value
Definition: common_config.c:73
Profile configuration for stir/shaken.
Definition: ast_expr2.c:325
static struct test_options options
static struct test_val a
Utility functions.
#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 ARRAY_LEN(a)
Definition: utils.h:666
int vs_load()
Load the stir/shaken verification service.
int vs_unload()
Unload the stir/shaken verification service.
int vs_reload()
Reload the stir/shaken verification service.