Asterisk - The Open Source Telephony Project  21.4.1
common_config.h
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 #ifndef COMMON_CONFIG_H_
20 #define COMMON_CONFIG_H_
21 
22 #include <openssl/evp.h>
23 
24 #include "asterisk.h"
25 #include "asterisk/paths.h"
26 #include "asterisk/sorcery.h"
27 #include "asterisk/stringfields.h"
28 
29 /*!
30  * \brief Boolean field to/from string prototype generator
31  *
32  * Most of the boolean fields that appear in the verification and
33  * attestation objects can be ovrridden in the profile object;
34  * "use_rfc9410_responses" for instance. If they were registered as
35  * normal YESNO types, we couldn't tell if a "0" value in the profile
36  * object meant the user set it to "no" to override a value of "yes"
37  * in the verification object, or it just defaulted to "0". By making
38  * the _NOT_SET enum a non-0/1 and making it the default value, we can
39  * tell the difference. The _UNKNOWN enum gets set if the string value
40  * provided to the _from_str function wasn't recognized as one of the
41  * values acceptable to ast_true() or ast_false().
42  *
43  * The result of calling the generator for a field will look like:
44  *
45  \code
46  enum use_rfc9410_responses_enum {
47  use_rfc9410_responses_UNKNOWN = -1,
48  use_rfc9410_responses_NO = 0,
49  use_rfc9410_responses_YES,
50  use_rfc9410_responses_NOT_SET,
51 };
52 enum use_rfc9410_responses_enum
53  use_rfc9410_responses_from_str(const char *value);
54 const char *use_rfc9410_responses_to_str(enum use_rfc9410_responses_enum value);
55 \endcode
56 
57 Most of the macros that follow depend on enum values formatted
58 as <param_name>_SOMETHING and their defaults as DEFAULT_<param_name>.
59  */
60 #define generate_bool_string_prototypes(param_name) \
61 enum param_name ## _enum { \
62  param_name ## _UNKNOWN = -1, \
63  param_name ## _NO = 0, \
64  param_name ## _YES, \
65  param_name ## _NOT_SET, \
66 }; \
67 enum param_name ## _enum \
68  param_name ## _from_str(const char *value); \
69 const char *param_name ## _to_str(enum param_name ## _enum value);
70 
71 /*
72  * Run the generators
73  */
74 generate_bool_string_prototypes(use_rfc9410_responses);
75 
76 generate_bool_string_prototypes(relax_x5u_port_scheme_restrictions);
77 
78 generate_bool_string_prototypes(relax_x5u_path_restrictions);
79 
80 generate_bool_string_prototypes(load_system_certs);
81 
82 generate_bool_string_prototypes(check_tn_cert_public_url);
83 
84 generate_bool_string_prototypes(send_mky);
85 
86 /*!
87  * \brief Enum field to/from string prototype generator
88  *
89  * This operates like the bool generator except you supply
90  * a list of the enum values. The first one MUST be
91  * param_name_UNKNOWN with a value of -1 and the rest running
92  * sequentially with the last being param_name_NOT_SET.
93  */
94 #define generate_enum_string_prototypes(param_name, ...) \
95 enum param_name ## _enum { \
96  __VA_ARGS__ \
97 }; \
98 enum param_name ## _enum \
99  param_name ## _from_str(const char *value); \
100 const char *param_name ## _to_str(enum param_name ## _enum value);
101 
102 generate_enum_string_prototypes(endpoint_behavior,
103  endpoint_behavior_UNKNOWN = -1,
104  endpoint_behavior_OFF = 0,
105  endpoint_behavior_ATTEST,
106  endpoint_behavior_VERIFY,
107  endpoint_behavior_ON,
108  endpoint_behavior_NOT_SET
109 );
110 
111 generate_enum_string_prototypes(attest_level,
112  attest_level_UNKNOWN = -1,
113  attest_level_A = 0,
114  attest_level_B,
115  attest_level_C,
116  attest_level_NOT_SET,
117 );
118 
119 /*
120  * enum stir_shaken_failure_action is defined in
121  * res_stir_shaken.h because res_pjsip_stir_shaken needs it
122  * we we need to just declare the function prototypes.
123  */
124 
125 enum stir_shaken_failure_action_enum
126  stir_shaken_failure_action_from_str(const char *action_str);
127 
128 const char *stir_shaken_failure_action_to_str(
129  enum stir_shaken_failure_action_enum action);
130 
131 /*!
132  * \brief Enum sorcery handler generator
133  *
134  * These macros can create the two functions needed to
135  * register an enum field with sorcery as long as there
136  * are _to_str and _from_str functions defined elsewhere.
137  *
138  */
139 #define generate_sorcery_enum_to_str(__struct, __substruct, __lc_param) \
140 static int sorcery_ ## __lc_param ## _to_str(const void *obj, const intptr_t *args, char **buf) \
141 { \
142  const struct __struct *cfg = obj; \
143  *buf = ast_strdup(__lc_param ## _to_str(cfg->__substruct __lc_param)); \
144  return *buf ? 0 : -1; \
145 }
146 
147 #define generate_sorcery_enum_from_str_ex(__struct, __substruct, __lc_param, __unknown) \
148 static int sorcery_ ## __lc_param ## _from_str(const struct aco_option *opt, struct ast_variable *var, void *obj) \
149 { \
150  struct __struct *cfg = obj; \
151  cfg->__substruct __lc_param = __lc_param ## _from_str (var->value); \
152  if (cfg->__substruct __lc_param == __unknown) { \
153  ast_log(LOG_WARNING, "Unknown value '%s' specified for %s\n", \
154  var->value, var->name); \
155  return -1; \
156  } \
157  return 0; \
158 }
159 
160 #define generate_sorcery_enum_from_str(__struct, __substruct, __lc_param, __unknown) \
161  generate_sorcery_enum_from_str_ex(__struct, __substruct, __lc_param, __lc_param ## _ ## __unknown) \
162 
163 
164 #define generate_sorcery_acl_to_str(__struct, __lc_param) \
165 static int sorcery_acl_to_str(const void *obj, const intptr_t *args, char **buf) \
166 { \
167  const struct __struct *cfg = obj; \
168  struct ast_acl *first_acl; \
169  if (!ast_acl_list_is_empty(cfg->vcfg_common.acl)) { \
170  AST_LIST_LOCK(cfg->vcfg_common.acl); \
171  first_acl = AST_LIST_FIRST(cfg->vcfg_common.acl); \
172  if (ast_strlen_zero(first_acl->name)) { \
173  *buf = "deny/permit"; \
174  } else { \
175  *buf = first_acl->name; \
176  } \
177  AST_LIST_UNLOCK(cfg->vcfg_common.acl); \
178  } \
179  *buf = ast_strdup(*buf); \
180  return 0; \
181 }
182 
183 #define generate_sorcery_acl_from_str(__struct, __lc_param, __unknown) \
184 static int sorcery_acl_from_str(const struct aco_option *opt, struct ast_variable *var, void *obj) \
185 { \
186  struct __struct *cfg = obj; \
187  int error = 0; \
188  int ignore; \
189  const char *name = var->name + strlen("x5u_"); \
190  if (ast_strlen_zero(var->value)) { \
191  return 0; \
192  } \
193  ast_append_acl(name, var->value, &cfg->vcfg_common.acl, &error, &ignore); \
194  return error; \
195 }
196 
197 struct ast_acl_list *get_default_acl_list(void);
198 
199 #define EFFECTIVE_ENUM(__enum1, __enum2, __field, __default) \
200  ( __enum1 != ( __field ## _ ## NOT_SET ) ? __enum1 : \
201  (__enum2 != __field ## _ ## NOT_SET ? \
202  __enum2 : __default ))
203 
204 #define EFFECTIVE_ENUM_BOOL(__enum1, __enum2, __field, __default) \
205  (( __enum1 != ( __field ## _ ## NOT_SET ) ? __enum1 : \
206  (__enum2 != __field ## _ ## NOT_SET ? \
207  __enum2 : __field ## _ ## __default )) == __field ## _ ## YES)
208 
209 #define ENUM_BOOL(__enum1, __field) \
210  (__enum1 == ( __field ## _ ## YES ))
211 
212 /*!
213  * \brief Common config copy utilities
214  *
215  * These macros are designed to be called from as_copy_cfg_common
216  * and vs_copy_cfg_common only. They'll only copy a field if the
217  * field contains a vaild value. Thus a NOT_SET value in the source
218  * won't override a pre-existing good value in the dest. A good
219  * value in the source WILL overwrite a good value in the dest.
220  *
221  */
222 #define cfg_stringfield_copy(__cfg_dst, __cfg_src, __field) \
223 ({ \
224  int __res = 0; \
225  if (!ast_strlen_zero(__cfg_src->__field)) { \
226  __res = ast_string_field_set(__cfg_dst, __field, __cfg_src->__field); \
227  } \
228  __res; \
229 })
230 
231 /*!
232  * \brief cfg_copy_wrapper
233  *
234  * Invoke cfg_stringfield_copy and cause the calling runction to
235  * return a -1 of the copy fails.
236  */
237 #define cfg_sf_copy_wrapper(id, __cfg_dst, __cfg_src, __field) \
238 { \
239  int rc = cfg_stringfield_copy(__cfg_dst, __cfg_src, __field); \
240  if (rc != 0) { \
241  ast_log(LOG_ERROR, "%s: Unable to copy field %s from %s to %s\n", \
242  id, #__field, #__cfg_src, #__cfg_dst); \
243  return -1; \
244  } \
245 }
246 
247 /*!
248  * \brief cfg_uint_copy
249  *
250  * Copy a uint from the source to the dest only if the source > 0.
251  * For stir-shaken, 0 isn't a valid value for any uint fields.
252  */
253 #define cfg_uint_copy(__cfg_dst, __cfg_src, __field) \
254 ({ \
255  if (__cfg_src->__field > 0) { \
256  __cfg_dst->__field = __cfg_src->__field; \
257  } \
258 })
259 
260 /*!
261  * \brief cfg_enum_copy
262  *
263  * Copy an enum from the source to the dest only if the source is
264  * neither NOT_SET nor UNKNOWN
265  */
266 #define cfg_enum_copy(__cfg_dst, __cfg_src, __field) \
267 ({ \
268  if (__cfg_src->__field != __field ## _NOT_SET \
269  && __cfg_src->__field != __field ## _UNKNOWN) { \
270  __cfg_dst->__field = __cfg_src->__field; \
271  } \
272 })
273 
274 /*!
275  * \brief Attestation Service configuration for stir/shaken
276  *
277  * The common structure also appears in profile_cfg.
278  */
281  AST_STRING_FIELD(private_key_file);
282  AST_STRING_FIELD(public_cert_url);
283  );
284  enum attest_level_enum attest_level;
285  enum check_tn_cert_public_url_enum check_tn_cert_public_url;
286  enum send_mky_enum send_mky;
287  unsigned char *raw_key;
288  size_t raw_key_length;
289 };
290 
291 #define generate_acfg_common_sorcery_handlers(object) \
292  generate_sorcery_enum_from_str(object, acfg_common., check_tn_cert_public_url, UNKNOWN); \
293  generate_sorcery_enum_to_str(object, acfg_common., check_tn_cert_public_url); \
294  generate_sorcery_enum_from_str(object, acfg_common., send_mky, UNKNOWN); \
295  generate_sorcery_enum_to_str(object, acfg_common., send_mky); \
296  generate_sorcery_enum_from_str(object, acfg_common., attest_level, UNKNOWN); \
297  generate_sorcery_enum_to_str(object, acfg_common., attest_level);
298 
299 int as_check_common_config(const char *id,
300  struct attestation_cfg_common *acfg_common);
301 
302 int as_copy_cfg_common(const char *id, struct attestation_cfg_common *cfg_dst,
303  struct attestation_cfg_common *cfg_src);
304 
305 void acfg_cleanup(struct attestation_cfg_common *cfg);
306 
308  SORCERY_OBJECT(details);
309  /*
310  * We need an empty AST_DECLARE_STRING_FIELDS() here
311  * because when STRFLDSET is used with sorcery, the
312  * memory for all sub-structures that have stringfields
313  * is allocated from the parent's stringfield pool.
314  */
316  struct attestation_cfg_common acfg_common;
317  int global_disable;
318 };
319 
320 struct attestation_cfg *as_get_cfg(void);
321 int as_is_config_loaded(void);
322 int as_config_load(void);
323 int as_config_reload(void);
324 int as_config_unload(void);
325 
326 /*!
327  * \brief Verification Service configuration for stir/shaken
328  *
329  * The common structure also appears in profile_cfg.
330  */
333  AST_STRING_FIELD(ca_file);
334  AST_STRING_FIELD(ca_path);
335  AST_STRING_FIELD(crl_file);
336  AST_STRING_FIELD(crl_path);
337  AST_STRING_FIELD(cert_cache_dir);
338  );
339  unsigned int curl_timeout;
340  unsigned int max_iat_age;
341  unsigned int max_date_header_age;
342  unsigned int max_cache_entry_age;
343  unsigned int max_cache_size;
344  enum stir_shaken_failure_action_enum
345  stir_shaken_failure_action;
346  enum use_rfc9410_responses_enum use_rfc9410_responses;
347  enum relax_x5u_port_scheme_restrictions_enum
348  relax_x5u_port_scheme_restrictions;
349  enum relax_x5u_path_restrictions_enum
350  relax_x5u_path_restrictions;
351  enum load_system_certs_enum load_system_certs;
352 
353  struct ast_acl_list *acl;
354  struct crypto_cert_store *tcs;
355 };
356 
357 #define generate_vcfg_common_sorcery_handlers(object) \
358  generate_sorcery_enum_from_str(object, vcfg_common.,use_rfc9410_responses, UNKNOWN); \
359  generate_sorcery_enum_to_str(object, vcfg_common.,use_rfc9410_responses); \
360  generate_sorcery_enum_from_str(object, vcfg_common.,stir_shaken_failure_action, UNKNOWN); \
361  generate_sorcery_enum_to_str(object, vcfg_common.,stir_shaken_failure_action); \
362  generate_sorcery_enum_from_str(object, vcfg_common.,relax_x5u_port_scheme_restrictions, UNKNOWN); \
363  generate_sorcery_enum_to_str(object, vcfg_common.,relax_x5u_port_scheme_restrictions); \
364  generate_sorcery_enum_from_str(object, vcfg_common.,relax_x5u_path_restrictions, UNKNOWN); \
365  generate_sorcery_enum_to_str(object, vcfg_common.,relax_x5u_path_restrictions); \
366  generate_sorcery_enum_from_str(object, vcfg_common.,load_system_certs, UNKNOWN); \
367  generate_sorcery_enum_to_str(object, vcfg_common.,load_system_certs); \
368  generate_sorcery_acl_from_str(object, acl, NULL); \
369  generate_sorcery_acl_to_str(object, acl);
370 
371 int vs_check_common_config(const char *id,
372  struct verification_cfg_common *vcfg_common);
373 
374 int vs_copy_cfg_common(const char *id, struct verification_cfg_common *cfg_dst,
375  struct verification_cfg_common *cfg_src);
376 
377 void vcfg_cleanup(struct verification_cfg_common *cfg);
378 
380  SORCERY_OBJECT(details);
381  /*
382  * We need an empty AST_DECLARE_STRING_FIELDS() here
383  * because when STRFLDSET is used with sorcery, the
384  * memory for all sub-structures that have stringfields
385  * is allocated from the parent's stringfield pool.
386  */
388  struct verification_cfg_common vcfg_common;
389  int global_disable;
390 };
391 
392 struct verification_cfg *vs_get_cfg(void);
393 int vs_is_config_loaded(void);
394 int vs_config_load(void);
395 int vs_config_reload(void);
396 int vs_config_unload(void);
397 
398 /*!
399  * \brief Profile configuration for stir/shaken
400  */
401 struct profile_cfg {
402  SORCERY_OBJECT(details);
403  /*
404  * We need an empty AST_DECLARE_STRING_FIELDS() here
405  * because when STRFLDSET is used with sorcery, the
406  * memory for all sub-structures that have stringfields
407  * is allocated from the parent's stringfield pool.
408  */
410  struct attestation_cfg_common acfg_common;
411  struct verification_cfg_common vcfg_common;
412  enum endpoint_behavior_enum endpoint_behavior;
413  struct profile_cfg *eprofile;
414 };
415 
416 struct profile_cfg *profile_get_cfg(const char *id);
417 struct profile_cfg *eprofile_get_cfg(const char *id);
418 int profile_load(void);
419 int profile_reload(void);
420 int profile_unload(void);
421 
422 #define PROFILE_ALLOW_ATTEST(__profile) \
423  (__profile->endpoint_behavior == endpoint_behavior_ON || \
424  __profile->endpoint_behavior == endpoint_behavior_ATTEST)
425 
426 #define PROFILE_ALLOW_VERIFY(__profile) \
427  (__profile->endpoint_behavior == endpoint_behavior_ON || \
428  __profile->endpoint_behavior == endpoint_behavior_VERIFY)
429 
430 /*!
431  * \brief TN configuration for stir/shaken
432  *
433  * TN-specific attestation_cfg.
434  */
435 
436 struct tn_cfg {
437  SORCERY_OBJECT(details);
438  /*
439  * We need an empty AST_DECLARE_STRING_FIELDS() here
440  * because when STRFLDSET is used with sorcery, the
441  * memory for all sub-structures that have stringfields
442  * is allocated from the parent's stringfield pool.
443  */
445  struct attestation_cfg_common acfg_common;
446 };
447 
448 struct tn_cfg *tn_get_cfg(const char *tn);
449 struct tn_cfg *tn_get_etn(const char *tn,
450  struct profile_cfg *eprofile);
451 int tn_config_load(void);
452 int tn_config_reload(void);
453 int tn_config_unload(void);
454 
455 /*!
456  * \brief Sorcery fields register helpers
457  *
458  * Most of the fields on attestation_cfg and verification_cfg are also
459  * in profile_cfg. To prevent having to maintain duplicate sets of
460  * sorcery register statements, we can do this once here and call
461  * register_common_verification_fields() from both profile_config and
462  * verification_config and call register_common_attestation_fields()
463  * from profile_cfg and attestation_config.
464  *
465  * Most of the fields in question are in sub-structures like
466  * verification_cfg.vcfg_common which is why there are separate name
467  * and field parameters. For verification_cfg.vcfg_common.ca_file
468  * for instance, name would be ca_file and field would be
469  * vcfg_common.ca_file.
470  *
471  *\note These macros depend on default values being defined
472  * in the 4 _config.c files as DEFAULT_<field_name>.
473  *
474  */
475 #define stringfield_option_register(sorcery, CONFIG_TYPE, object, name, field, nodoc) \
476  ast_sorcery_object_field_register ## nodoc(sorcery, CONFIG_TYPE, #name, \
477  DEFAULT_ ## name, OPT_STRINGFIELD_T, 0, \
478  STRFLDSET(struct object, field))
479 
480 #define uint_option_register(sorcery, CONFIG_TYPE, object, name, field, nodoc) \
481  ast_sorcery_object_field_register ## nodoc(sorcery, CONFIG_TYPE, #name, \
482  __stringify(DEFAULT_ ## name), OPT_UINT_T, 0, \
483  FLDSET(struct object, field))
484 
485 #define enum_option_register_ex(sorcery, CONFIG_TYPE, name, field, nodoc) \
486  ast_sorcery_object_field_register_custom ## nodoc(sorcery, CONFIG_TYPE, \
487  #name, field ## _to_str(DEFAULT_ ## field), \
488  sorcery_ ## field ## _from_str, sorcery_ ## field ## _to_str, NULL, 0, 0)
489 
490 #define enum_option_register(sorcery, CONFIG_TYPE, name, nodoc) \
491  enum_option_register_ex(sorcery, CONFIG_TYPE, name, name, nodoc)
492 
493 #define register_common_verification_fields(sorcery, object, CONFIG_TYPE, nodoc) \
494 ({ \
495  stringfield_option_register(sorcery, CONFIG_TYPE, object, ca_file, vcfg_common.ca_file, nodoc); \
496  stringfield_option_register(sorcery, CONFIG_TYPE, object, ca_path, vcfg_common.ca_path, nodoc); \
497  stringfield_option_register(sorcery, CONFIG_TYPE, object, crl_file, vcfg_common.crl_file, nodoc); \
498  stringfield_option_register(sorcery, CONFIG_TYPE, object, crl_path, vcfg_common.crl_path, nodoc); \
499  stringfield_option_register(sorcery, CONFIG_TYPE, object, cert_cache_dir, vcfg_common.cert_cache_dir, nodoc); \
500 \
501  uint_option_register(sorcery, CONFIG_TYPE, object, curl_timeout, vcfg_common.curl_timeout, nodoc);\
502  uint_option_register(sorcery, CONFIG_TYPE, object, max_iat_age, vcfg_common.max_iat_age, nodoc);\
503  uint_option_register(sorcery, CONFIG_TYPE, object, max_date_header_age, vcfg_common.max_date_header_age, nodoc);\
504  uint_option_register(sorcery, CONFIG_TYPE, object, max_cache_entry_age, vcfg_common.max_cache_entry_age, nodoc);\
505  uint_option_register(sorcery, CONFIG_TYPE, object, max_cache_size, vcfg_common.max_cache_size, nodoc);\
506 \
507  enum_option_register_ex(sorcery, CONFIG_TYPE, failure_action, stir_shaken_failure_action, nodoc); \
508  enum_option_register(sorcery, CONFIG_TYPE, use_rfc9410_responses, nodoc); \
509  enum_option_register(sorcery, CONFIG_TYPE, \
510  relax_x5u_port_scheme_restrictions, nodoc); \
511  enum_option_register(sorcery, CONFIG_TYPE, \
512  relax_x5u_path_restrictions, nodoc); \
513  enum_option_register(sorcery, CONFIG_TYPE, \
514  load_system_certs, nodoc); \
515 \
516  ast_sorcery_object_field_register_custom ## nodoc(sorcery, CONFIG_TYPE, "x5u_deny", "", sorcery_acl_from_str, NULL, NULL, 0, 0); \
517  ast_sorcery_object_field_register_custom ## nodoc(sorcery, CONFIG_TYPE, "x5u_permit", "", sorcery_acl_from_str, NULL, NULL, 0, 0); \
518  ast_sorcery_object_field_register_custom ## nodoc(sorcery, CONFIG_TYPE, "x5u_acl", "", sorcery_acl_from_str, sorcery_acl_to_str, NULL, 0, 0); \
519 })
520 
521 #define register_common_attestation_fields(sorcery, object, CONFIG_TYPE, nodoc) \
522 ({ \
523  stringfield_option_register(sorcery, CONFIG_TYPE, object, private_key_file, acfg_common.private_key_file, nodoc); \
524  stringfield_option_register(sorcery, CONFIG_TYPE, object, public_cert_url, acfg_common.public_cert_url, nodoc); \
525  enum_option_register(sorcery, CONFIG_TYPE, attest_level, nodoc); \
526  enum_option_register(sorcery, CONFIG_TYPE, check_tn_cert_public_url, nodoc); \
527  enum_option_register(sorcery, CONFIG_TYPE, send_mky, nodoc); \
528 })
529 
530 int common_config_load(void);
531 int common_config_unload(void);
532 int common_config_reload(void);
533 
534 enum config_object_type {
535  config_object_type_attestation = 0,
536  config_object_type_verification,
537  config_object_type_profile,
538  config_object_type_tn,
539 };
540 
542  const char *title;
543  enum config_object_type object_type;
544 };
545 
546 /*!
547  * \brief Output configuration settings to the Asterisk CLI
548  *
549  * \param obj A sorcery object containing configuration data
550  * \param arg Asterisk CLI argument object
551  * \param flags ao2 container flags
552  *
553  * \retval 0
554  */
555 int config_object_cli_show(void *obj, void *arg, void *data, int flags);
556 
557 /*!
558  * \brief Tab completion for name matching with STIR/SHAKEN CLI commands
559  *
560  * \param word The word to tab complete on
561  * \param container The sorcery container to iterate through
562  *
563  * \retval The tab completion options
564  */
565 char *config_object_tab_complete_name(const char *word, struct ao2_container *container);
566 
567 /*!
568  * \brief Canonicalize a TN
569  *
570  * \param tn TN to canonicalize
571  * \param dest_tn Pointer to destination buffer to receive the new TN
572  *
573  * \retval dest_tn or NULL on failure
574  */
575 char *canonicalize_tn(const char *tn, char *dest_tn);
576 
577 /*!
578  * \brief Canonicalize a TN into nre buffer
579  *
580  * \param tn TN to canonicalize
581  *
582  * \retval dest_tn (which must be freed with ast_free) or NULL on failure
583  */
584 char *canonicalize_tn_alloc(const char *tn);
585 
586 #endif /* COMMON_CONFIG_H_ */
Asterisk main include file. File version handling, generic pbx functions.
TN configuration for stir/shaken.
#define AST_DECLARE_STRING_FIELDS(field_list)
Declare the fields needed in a structure.
Definition: stringfields.h:341
Wrapper for an ast_acl linked list.
Definition: acl.h:76
Asterisk file paths, configured in asterisk.conf.
#define AST_STRING_FIELD(name)
Declare a string field.
Definition: stringfields.h:303
ao2 object wrapper for X509_STORE that provides locking and refcounting
Definition: crypto_utils.h:170
struct ao2_container * container
Definition: res_fax.c:501
Verification Service configuration for stir/shaken.
Definition: test_acl.c:111
Attestation Service configuration for stir/shaken.
Profile configuration for stir/shaken.
Generic container type.
Sorcery Data Access Layer API.