<p>Michael Bradeen <strong>submitted</strong> this change.</p><p><a href="https://gerrit.asterisk.org/c/asterisk/+/18394">View Change</a></p><div style="white-space:pre-wrap">Approvals:
Michael Bradeen: Looks good to me, approved; Approved for Submit
</div><pre style="font-family: monospace,monospace; white-space: pre-wrap;">AST-2022-002 - res_stir_shaken/curl: Add ACL checks for Identity header.<br><br>Adds a new configuration option, stir_shaken_profile, in pjsip.conf that<br>can be specified on a per endpoint basis. This option will reference a<br>stir_shaken_profile that can be configured in stir_shaken.conf. The type<br>of this option must be 'profile'. The stir_shaken option can be<br>specified on this object with the same values as before (attest, verify,<br>on), but it cannot be off since having the profile itself implies wanting<br>STIR/SHAKEN support. You can also specify an ACL from acl.conf (along<br>with permit and deny lines in the object itself) that will be used to<br>limit what interfaces Asterisk will attempt to retrieve information from<br>when reading the Identity header.<br><br>ASTERISK-29476<br><br>Change-Id: I87fa61f78a9ea0cd42530691a30da3c781842406<br>---<br>M configs/samples/pjsip.conf.sample<br>M configs/samples/stir_shaken.conf.sample<br>M include/asterisk/res_pjsip.h<br>M include/asterisk/res_stir_shaken.h<br>M res/res_pjsip/pjsip_config.xml<br>M res/res_pjsip/pjsip_configuration.c<br>M res/res_pjsip_stir_shaken.c<br>M res/res_stir_shaken.c<br>M res/res_stir_shaken/curl.c<br>M res/res_stir_shaken/curl.h<br>A res/res_stir_shaken/profile.c<br>A res/res_stir_shaken/profile.h<br>A res/res_stir_shaken/profile_private.h<br>13 files changed, 558 insertions(+), 17 deletions(-)<br><br></pre><pre style="font-family: monospace,monospace; white-space: pre-wrap;"><span>diff --git a/configs/samples/pjsip.conf.sample b/configs/samples/pjsip.conf.sample</span><br><span>index 8118086..33a2ce0 100644</span><br><span>--- a/configs/samples/pjsip.conf.sample</span><br><span>+++ b/configs/samples/pjsip.conf.sample</span><br><span>@@ -337,6 +337,7 @@</span><br><span> ; STIR/SHAKEN support.</span><br><span> ;</span><br><span> ;stir_shaken=no</span><br><span style="color: hsl(120, 100%, 40%);">+;stir_shaken_profile=my_profile</span><br><span> </span><br><span> ;[6001]</span><br><span> ;type=auth</span><br><span>@@ -877,6 +878,9 @@</span><br><span> ; happens to the call if verification fails; it's up to</span><br><span> ; you to determine what to do with the results.</span><br><span> ; (default: no)</span><br><span style="color: hsl(120, 100%, 40%);">+;stir_shaken_profile =</span><br><span style="color: hsl(120, 100%, 40%);">+ ; If a profile is specified (defined in stir_shaken.conf),</span><br><span style="color: hsl(120, 100%, 40%);">+ ; this endpoint will follow the rules defined there.</span><br><span> ;allow_unauthenticated_options =</span><br><span> ; By default, chan_pjsip will challenge an incoming</span><br><span> ; OPTIONS request for authentication credentials just</span><br><span>diff --git a/configs/samples/stir_shaken.conf.sample b/configs/samples/stir_shaken.conf.sample</span><br><span>index c39bc97..677d3bb 100644</span><br><span>--- a/configs/samples/stir_shaken.conf.sample</span><br><span>+++ b/configs/samples/stir_shaken.conf.sample</span><br><span>@@ -83,3 +83,21 @@</span><br><span> ;</span><br><span> ; Must have an attestation of A, B, or C</span><br><span> ;attestation=C</span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span style="color: hsl(120, 100%, 40%);">+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;</span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span style="color: hsl(120, 100%, 40%);">+; Profiles can be defined here which can be referenced by channel drivers.</span><br><span style="color: hsl(120, 100%, 40%);">+;[my_profile]</span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span style="color: hsl(120, 100%, 40%);">+; type must be "profile"</span><br><span style="color: hsl(120, 100%, 40%);">+;type=profile</span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span style="color: hsl(120, 100%, 40%);">+; Set stir_shaken to 'attest', 'verify', or 'on', which is the default</span><br><span style="color: hsl(120, 100%, 40%);">+;stir_shaken=on</span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span style="color: hsl(120, 100%, 40%);">+; You can specify an ACL that will be used strictly for the Identity header when downloading public certificates</span><br><span style="color: hsl(120, 100%, 40%);">+;acllist=myacllist</span><br><span style="color: hsl(120, 100%, 40%);">+;</span><br><span style="color: hsl(120, 100%, 40%);">+; You can also do permit / deny lines if you want (also supports IPv6)</span><br><span style="color: hsl(120, 100%, 40%);">+;permit=0.0.0.0/0.0.0.0</span><br><span style="color: hsl(120, 100%, 40%);">+;deny=127.0.0.1</span><br><span>diff --git a/include/asterisk/res_pjsip.h b/include/asterisk/res_pjsip.h</span><br><span>index a4d0607..5d69713 100644</span><br><span>--- a/include/asterisk/res_pjsip.h</span><br><span>+++ b/include/asterisk/res_pjsip.h</span><br><span>@@ -798,6 +798,8 @@</span><br><span> AST_STRING_FIELD(accountcode);</span><br><span> /*! If set, we'll push incoming MWI NOTIFYs to stasis using this mailbox */</span><br><span> AST_STRING_FIELD(incoming_mwi_mailbox);</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! STIR/SHAKEN profile to use */</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_STRING_FIELD(stir_shaken_profile);</span><br><span> );</span><br><span> /*! Configuration for extensions */</span><br><span> struct ast_sip_endpoint_extensions extensions;</span><br><span>diff --git a/include/asterisk/res_stir_shaken.h b/include/asterisk/res_stir_shaken.h</span><br><span>index 92eb0ec..ece99b5 100644</span><br><span>--- a/include/asterisk/res_stir_shaken.h</span><br><span>+++ b/include/asterisk/res_stir_shaken.h</span><br><span>@@ -38,6 +38,8 @@</span><br><span> </span><br><span> struct ast_stir_shaken_payload;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_acl_list;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct ast_json;</span><br><span> </span><br><span> /*!</span><br><span>@@ -66,6 +68,38 @@</span><br><span> unsigned int ast_stir_shaken_get_signature_timeout(void);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Retrieve a stir_shaken_profile by id</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note The profile will need to be unref'd when not needed anymore</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param id The id of the stir_shaken_profile to get</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval stir_shaken_profile on success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL on failure</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct stir_shaken_profile *ast_stir_shaken_get_profile(const char *id);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Check if a stir_shaken_profile supports attestation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param profile The stir_shaken_profile to test</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 if not supported</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 1 if supported</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+unsigned int ast_stir_shaken_profile_supports_attestation(const struct stir_shaken_profile *profile);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Check if a stir_shaken_profile supports verification</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param profile The stir_shaken_profile to test</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 if not supported</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 1 if supported</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+unsigned int ast_stir_shaken_profile_supports_verification(const struct stir_shaken_profile *profile);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span> * \brief Add a STIR/SHAKEN verification result to a channel</span><br><span> *</span><br><span> * \param chan The channel</span><br><span>@@ -113,6 +147,26 @@</span><br><span> const char *algorithm, const char *public_cert_url, int *failure_code);</span><br><span> </span><br><span> /*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Same as ast_stir_shaken_verify2, but passes in a stir_shaken_profile with additional configuration</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \note failure_code will be written to in this function</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param header The payload header</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param payload The payload section</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param signature The payload signature</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param algorithm The signature algorithm</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param public_cert_url The public key URL</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param failure_code Additional failure information</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param profile The stir_shaken_profile</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval ast_stir_shaken_payload on success</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval NULL on failure</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_stir_shaken_payload *ast_stir_shaken_verify_with_profile(const char *header, const char *payload,</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *signature, const char *algorithm, const char *public_cert_url, int *failure,</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct stir_shaken_profile *profile);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span> * \brief Retrieve the stir/shaken sorcery context</span><br><span> *</span><br><span> * \retval The stir/shaken sorcery context</span><br><span>diff --git a/res/res_pjsip/pjsip_config.xml b/res/res_pjsip/pjsip_config.xml</span><br><span>index 6470ab6..52139b0 100644</span><br><span>--- a/res/res_pjsip/pjsip_config.xml</span><br><span>+++ b/res/res_pjsip/pjsip_config.xml</span><br><span>@@ -1118,6 +1118,13 @@</span><br><span> INVITEs, an Identity header will be added.</para></span><br><span> </description></span><br><span> </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="stir_shaken_profile" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>STIR/SHAKEN profile containing additional configuration options</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ <description><para></span><br><span style="color: hsl(120, 100%, 40%);">+ A STIR/SHAKEN profile that is defined in stir_shaken.conf. Contains</span><br><span style="color: hsl(120, 100%, 40%);">+ several options and rules used for STIR/SHAKEN.</para></span><br><span style="color: hsl(120, 100%, 40%);">+ </description></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span> <configOption name="allow_unauthenticated_options" default="no"></span><br><span> <synopsis>Skip authentication when receiving OPTIONS requests</synopsis></span><br><span> <description><para></span><br><span>diff --git a/res/res_pjsip/pjsip_configuration.c b/res/res_pjsip/pjsip_configuration.c</span><br><span>index eccc639..53a0e9b 100644</span><br><span>--- a/res/res_pjsip/pjsip_configuration.c</span><br><span>+++ b/res/res_pjsip/pjsip_configuration.c</span><br><span>@@ -2007,6 +2007,7 @@</span><br><span> ast_sorcery_object_field_register(sip_sorcery, "endpoint", "suppress_q850_reason_headers", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, suppress_q850_reason_headers));</span><br><span> ast_sorcery_object_field_register(sip_sorcery, "endpoint", "ignore_183_without_sdp", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, ignore_183_without_sdp));</span><br><span> ast_sorcery_object_field_register_custom(sip_sorcery, "endpoint", "stir_shaken", "off", stir_shaken_handler, stir_shaken_to_str, NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register(sip_sorcery, "endpoint", "stir_shaken_profile", "", OPT_STRINGFIELD_T, 0, STRFLDSET(struct ast_sip_endpoint, stir_shaken_profile));</span><br><span> ast_sorcery_object_field_register(sip_sorcery, "endpoint", "allow_unauthenticated_options", "no", OPT_BOOL_T, 1, FLDSET(struct ast_sip_endpoint, allow_unauthenticated_options));</span><br><span> </span><br><span> if (ast_sip_initialize_sorcery_transport()) {</span><br><span>diff --git a/res/res_pjsip_stir_shaken.c b/res/res_pjsip_stir_shaken.c</span><br><span>index cf17365..0637a66 100644</span><br><span>--- a/res/res_pjsip_stir_shaken.c</span><br><span>+++ b/res/res_pjsip_stir_shaken.c</span><br><span>@@ -220,13 +220,16 @@</span><br><span> int mismatch = 0;</span><br><span> struct ast_stir_shaken_payload *ss_payload;</span><br><span> int failure_code = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ RAII_VAR(struct stir_shaken_profile *, profile, NULL, ao2_cleanup);</span><br><span> </span><br><span> /* Check if this is a reinvite. If it is, we don't need to do anything */</span><br><span> if (rdata->msg_info.to->tag.slen) {</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- if ((session->endpoint->stir_shaken & AST_SIP_STIR_SHAKEN_VERIFY) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ profile = ast_stir_shaken_get_profile(session->endpoint->stir_shaken_profile);</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((profile && !ast_stir_shaken_profile_supports_verification(profile))</span><br><span style="color: hsl(120, 100%, 40%);">+ && ((session->endpoint->stir_shaken & AST_SIP_STIR_SHAKEN_VERIFY) == 0)) {</span><br><span> return 0;</span><br><span> }</span><br><span> </span><br><span>@@ -312,7 +315,8 @@</span><br><span> </span><br><span> attestation = get_attestation_from_payload(payload);</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- ss_payload = ast_stir_shaken_verify2(header, payload, signature, algorithm, public_cert_url, &failure_code);</span><br><span style="color: hsl(120, 100%, 40%);">+ ss_payload = ast_stir_shaken_verify_with_profile(header, payload, signature, algorithm, public_cert_url, &failure_code, profile);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> if (!ss_payload) {</span><br><span> </span><br><span> if (failure_code == AST_STIR_SHAKEN_VERIFY_FAILED_TO_GET_CERT) {</span><br><span>@@ -474,7 +478,11 @@</span><br><span> </span><br><span> static void stir_shaken_outgoing_request(struct ast_sip_session *session, pjsip_tx_data *tdata)</span><br><span> {</span><br><span style="color: hsl(0, 100%, 40%);">- if ((session->endpoint->stir_shaken & AST_SIP_STIR_SHAKEN_ATTEST) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ RAII_VAR(struct stir_shaken_profile *, profile, NULL, ao2_cleanup);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ profile = ast_stir_shaken_get_profile(session->endpoint->stir_shaken_profile);</span><br><span style="color: hsl(120, 100%, 40%);">+ if ((profile && !ast_stir_shaken_profile_supports_attestation(profile))</span><br><span style="color: hsl(120, 100%, 40%);">+ && ((session->endpoint->stir_shaken & AST_SIP_STIR_SHAKEN_ATTEST) == 0)) {</span><br><span> return;</span><br><span> }</span><br><span> </span><br><span>diff --git a/res/res_stir_shaken.c b/res/res_stir_shaken.c</span><br><span>index 373a1a1..157500a 100644</span><br><span>--- a/res/res_stir_shaken.c</span><br><span>+++ b/res/res_stir_shaken.c</span><br><span>@@ -38,6 +38,7 @@</span><br><span> #include "asterisk/global_datastores.h"</span><br><span> #include "asterisk/app.h"</span><br><span> #include "asterisk/test.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/acl.h"</span><br><span> </span><br><span> #include "asterisk/res_stir_shaken.h"</span><br><span> #include "res_stir_shaken/stir_shaken.h"</span><br><span>@@ -45,6 +46,7 @@</span><br><span> #include "res_stir_shaken/store.h"</span><br><span> #include "res_stir_shaken/certificate.h"</span><br><span> #include "res_stir_shaken/curl.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "res_stir_shaken/profile.h"</span><br><span> </span><br><span> /*** DOCUMENTATION</span><br><span> <configInfo name="res_stir_shaken" language="en_US"></span><br><span>@@ -108,6 +110,29 @@</span><br><span> <synopsis>The caller ID number to match on.</synopsis></span><br><span> </configOption></span><br><span> </configObject></span><br><span style="color: hsl(120, 100%, 40%);">+ <configObject name="profile"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>STIR/SHAKEN profile configuration options</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="type"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>Must be of type 'profile'.</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="stir_shaken" default="on"></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>STIR/SHAKEN configuration settings</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ <description><para></span><br><span style="color: hsl(120, 100%, 40%);">+ Attest, verify, or do both STIR/SHAKEN operations. On incoming</span><br><span style="color: hsl(120, 100%, 40%);">+ INVITEs, the Identity header will be checked for validity. On</span><br><span style="color: hsl(120, 100%, 40%);">+ outgoing INVITEs, an Identity header will be added.</para></span><br><span style="color: hsl(120, 100%, 40%);">+ </description></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="acllist" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>An existing ACL from acl.conf to use</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="permit" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>An IP or subnet to permit</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ <configOption name="deny" default=""></span><br><span style="color: hsl(120, 100%, 40%);">+ <synopsis>An IP or subnet to deny</synopsis></span><br><span style="color: hsl(120, 100%, 40%);">+ </configOption></span><br><span style="color: hsl(120, 100%, 40%);">+ </configObject></span><br><span> </configFile></span><br><span> </configInfo></span><br><span> <function name="STIR_SHAKEN" language="en_US"></span><br><span>@@ -205,6 +230,33 @@</span><br><span> return ast_stir_shaken_signature_timeout(stir_shaken_general_get());</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct stir_shaken_profile *ast_stir_shaken_get_profile(const char *id)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_strlen_zero(id)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return ast_stir_shaken_get_profile_by_name(id);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+unsigned int ast_stir_shaken_profile_supports_attestation(const struct stir_shaken_profile *profile)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!profile) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return (profile->stir_shaken & STIR_SHAKEN_ATTEST);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+unsigned int ast_stir_shaken_profile_supports_verification(const struct stir_shaken_profile *profile)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!profile) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return (profile->stir_shaken & STIR_SHAKEN_VERIFY);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /*!</span><br><span> * \brief Convert an ast_stir_shaken_verification_result to string representation</span><br><span> *</span><br><span>@@ -554,7 +606,7 @@</span><br><span> * \retval NULL on failure</span><br><span> * \retval full path filename on success</span><br><span> */</span><br><span style="color: hsl(0, 100%, 40%);">-static char *run_curl(const char *public_cert_url, const char *path)</span><br><span style="color: hsl(120, 100%, 40%);">+static char *run_curl(const char *public_cert_url, const char *path, const struct ast_acl_list *acl)</span><br><span> {</span><br><span> struct curl_cb_data *data;</span><br><span> char *filename;</span><br><span>@@ -565,7 +617,7 @@</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- filename = curl_public_key(public_cert_url, path, data);</span><br><span style="color: hsl(120, 100%, 40%);">+ filename = curl_public_key(public_cert_url, path, data, acl);</span><br><span> if (!filename) {</span><br><span> ast_log(LOG_ERROR, "Could not retrieve public key for '%s'\n", public_cert_url);</span><br><span> curl_cb_data_free(data);</span><br><span>@@ -591,7 +643,7 @@</span><br><span> * \retval NULL on failure</span><br><span> * \retval full path filename on success</span><br><span> */</span><br><span style="color: hsl(0, 100%, 40%);">-static char *curl_and_check_expiration(const char *public_cert_url, const char *path, int *curl)</span><br><span style="color: hsl(120, 100%, 40%);">+static char *curl_and_check_expiration(const char *public_cert_url, const char *path, int *curl, const struct ast_acl_list *acl)</span><br><span> {</span><br><span> char *filename;</span><br><span> </span><br><span>@@ -600,7 +652,7 @@</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- filename = run_curl(public_cert_url, path);</span><br><span style="color: hsl(120, 100%, 40%);">+ filename = run_curl(public_cert_url, path, acl);</span><br><span> if (!filename) {</span><br><span> return NULL;</span><br><span> }</span><br><span>@@ -662,7 +714,8 @@</span><br><span> * \retval 0 on success</span><br><span> * \retval 1 on failure</span><br><span> */</span><br><span style="color: hsl(0, 100%, 40%);">-static int stir_shaken_verify_setup_file_paths(const char *public_cert_url, char **file_path, char **dir_path, int *curl)</span><br><span style="color: hsl(120, 100%, 40%);">+static int stir_shaken_verify_setup_file_paths(const char *public_cert_url, char **file_path, char **dir_path, int *curl,</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct ast_acl_list *acl)</span><br><span> {</span><br><span> *file_path = get_path_to_public_key(public_cert_url);</span><br><span> if (ast_asprintf(dir_path, "%s/keys/%s", ast_config_AST_DATA_DIR, STIR_SHAKEN_DIR_NAME) < 0) {</span><br><span>@@ -680,7 +733,7 @@</span><br><span> ast_free(*file_path);</span><br><span> </span><br><span> /* Download to the default path */</span><br><span style="color: hsl(0, 100%, 40%);">- *file_path = run_curl(public_cert_url, *dir_path);</span><br><span style="color: hsl(120, 100%, 40%);">+ *file_path = run_curl(public_cert_url, *dir_path, acl);</span><br><span> if (!(*file_path)) {</span><br><span> return 1;</span><br><span> }</span><br><span>@@ -704,7 +757,7 @@</span><br><span> * \retval 1 on failure</span><br><span> */</span><br><span> static int stir_shaken_verify_validate_cert(const char *public_cert_url, char **file_path, char *dir_path, int *curl,</span><br><span style="color: hsl(0, 100%, 40%);">- EVP_PKEY **public_key)</span><br><span style="color: hsl(120, 100%, 40%);">+ EVP_PKEY **public_key, const struct ast_acl_list *acl)</span><br><span> {</span><br><span> if (public_key_is_expired(public_cert_url)) {</span><br><span> </span><br><span>@@ -714,7 +767,7 @@</span><br><span> </span><br><span> /* If this fails, then there's nothing we can do */</span><br><span> ast_free(*file_path);</span><br><span style="color: hsl(0, 100%, 40%);">- *file_path = curl_and_check_expiration(public_cert_url, dir_path, curl);</span><br><span style="color: hsl(120, 100%, 40%);">+ *file_path = curl_and_check_expiration(public_cert_url, dir_path, curl, acl);</span><br><span> if (!(*file_path)) {</span><br><span> return 1;</span><br><span> }</span><br><span>@@ -730,7 +783,7 @@</span><br><span> remove_public_key_from_astdb(public_cert_url);</span><br><span> </span><br><span> ast_free(*file_path);</span><br><span style="color: hsl(0, 100%, 40%);">- *file_path = curl_and_check_expiration(public_cert_url, dir_path, curl);</span><br><span style="color: hsl(120, 100%, 40%);">+ *file_path = curl_and_check_expiration(public_cert_url, dir_path, curl, acl);</span><br><span> if (!(*file_path)) {</span><br><span> return 1;</span><br><span> }</span><br><span>@@ -757,6 +810,12 @@</span><br><span> struct ast_stir_shaken_payload *ast_stir_shaken_verify2(const char *header, const char *payload, const char *signature,</span><br><span> const char *algorithm, const char *public_cert_url, int *failure_code)</span><br><span> {</span><br><span style="color: hsl(120, 100%, 40%);">+ return ast_stir_shaken_verify_with_profile(header, payload, signature, algorithm, public_cert_url, failure_code, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_stir_shaken_payload *ast_stir_shaken_verify_with_profile(const char *header, const char *payload, const char *signature,</span><br><span style="color: hsl(120, 100%, 40%);">+ const char *algorithm, const char *public_cert_url, int *failure_code, const struct stir_shaken_profile *profile)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span> struct ast_stir_shaken_payload *ret_payload;</span><br><span> EVP_PKEY *public_key;</span><br><span> int curl = 0;</span><br><span>@@ -764,11 +823,14 @@</span><br><span> RAII_VAR(char *, dir_path, NULL, ast_free);</span><br><span> RAII_VAR(char *, combined_str, NULL, ast_free);</span><br><span> size_t combined_size;</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct ast_acl_list *acl;</span><br><span> </span><br><span> if (stir_shaken_verify_check_empty_strings(header, payload, signature, algorithm, public_cert_url)) {</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ acl = profile ? (const struct ast_acl_list *)profile->acl : NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Check to see if we have already downloaded this public cert. The reason we</span><br><span> * store the file path is because:</span><br><span> *</span><br><span>@@ -779,12 +841,12 @@</span><br><span> * {configurable) directories, we already have the storage mechanism in place.</span><br><span> * The only thing that would be left to do is pull from the configuration.</span><br><span> */</span><br><span style="color: hsl(0, 100%, 40%);">- if (stir_shaken_verify_setup_file_paths(public_cert_url, &file_path, &dir_path, &curl)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (stir_shaken_verify_setup_file_paths(public_cert_url, &file_path, &dir_path, &curl, acl)) {</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span> /* Check to see if the cert we downloaded (or already had) is expired */</span><br><span style="color: hsl(0, 100%, 40%);">- if (stir_shaken_verify_validate_cert(public_cert_url, &file_path, dir_path, &curl, &public_key)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ if (stir_shaken_verify_validate_cert(public_cert_url, &file_path, dir_path, &curl, &public_key, acl)) {</span><br><span> *failure_code = AST_STIR_SHAKEN_VERIFY_FAILED_TO_GET_CERT;</span><br><span> return NULL;</span><br><span> }</span><br><span>@@ -1677,6 +1739,7 @@</span><br><span> {</span><br><span> int res = 0;</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ stir_shaken_profile_unload();</span><br><span> stir_shaken_certificate_unload();</span><br><span> stir_shaken_store_unload();</span><br><span> stir_shaken_general_unload();</span><br><span>@@ -1716,6 +1779,11 @@</span><br><span> return AST_MODULE_LOAD_DECLINE;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ if (stir_shaken_profile_load()) {</span><br><span style="color: hsl(120, 100%, 40%);">+ unload_module();</span><br><span style="color: hsl(120, 100%, 40%);">+ return AST_MODULE_LOAD_DECLINE;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> ast_sorcery_load(ast_stir_shaken_sorcery());</span><br><span> </span><br><span> res |= ast_custom_function_register(&stir_shaken_function);</span><br><span>diff --git a/res/res_stir_shaken/curl.c b/res/res_stir_shaken/curl.c</span><br><span>index cd78461..fb06de5 100644</span><br><span>--- a/res/res_stir_shaken/curl.c</span><br><span>+++ b/res/res_stir_shaken/curl.c</span><br><span>@@ -21,9 +21,12 @@</span><br><span> #include "asterisk/utils.h"</span><br><span> #include "asterisk/logger.h"</span><br><span> #include "asterisk/file.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/acl.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> #include "curl.h"</span><br><span> #include "general.h"</span><br><span> #include "stir_shaken.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "profile.h"</span><br><span> </span><br><span> #include <curl/curl.h></span><br><span> #include <sys/stat.h></span><br><span>@@ -52,6 +55,11 @@</span><br><span> const char *url;</span><br><span> };</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct curl_cb_open_socket {</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct ast_acl_list *acl;</span><br><span style="color: hsl(120, 100%, 40%);">+ curl_socket_t *sockfd;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> struct curl_cb_data *curl_cb_data_create(void)</span><br><span> {</span><br><span> struct curl_cb_data *data;</span><br><span>@@ -73,6 +81,18 @@</span><br><span> ast_free(data);</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+static void curl_cb_open_socket_free(struct curl_cb_open_socket *data)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!data) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ close(*data->sockfd);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ /* We don't need to free the ACL since we just use a reference */</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free(data);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> char *curl_cb_data_get_cache_control(const struct curl_cb_data *data)</span><br><span> {</span><br><span> if (!data) {</span><br><span>@@ -200,7 +220,26 @@</span><br><span> return real_size;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">-char *curl_public_key(const char *public_cert_url, const char *path, struct curl_cb_data *data)</span><br><span style="color: hsl(120, 100%, 40%);">+static curl_socket_t stir_shaken_curl_open_socket_callback(void *our_data, curlsocktype purpose, struct curl_sockaddr *address)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct curl_cb_open_socket *data = our_data;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!ast_acl_list_is_empty((struct ast_acl_list *)data->acl)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sockaddr ast_address = { {0,} };</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sockaddr_copy_sockaddr(&ast_address, &address->addr, address->addrlen);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_apply_acl((struct ast_acl_list *)data->acl, &ast_address, NULL) != AST_SENSE_ALLOW) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return CURLE_COULDNT_CONNECT;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ *data->sockfd = socket(address->family, address->socktype, address->protocol);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return *data->sockfd;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+char *curl_public_key(const char *public_cert_url, const char *path, struct curl_cb_data *data, const struct ast_acl_list *acl)</span><br><span> {</span><br><span> FILE *public_key_file;</span><br><span> char *filename;</span><br><span>@@ -209,13 +248,25 @@</span><br><span> CURL *curl;</span><br><span> char curl_errbuf[CURL_ERROR_SIZE + 1];</span><br><span> struct curl_cb_write_buf *buf;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct curl_cb_open_socket *open_socket_data;</span><br><span style="color: hsl(120, 100%, 40%);">+ curl_socket_t sockfd;</span><br><span> </span><br><span style="color: hsl(0, 100%, 40%);">- buf = ast_calloc(1, sizeof(*buf));</span><br><span style="color: hsl(120, 100%, 40%);">+ curl_errbuf[CURL_ERROR_SIZE] = '\0';</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ buf = ast_calloc(1, sizeof(*buf));</span><br><span> if (!buf) {</span><br><span> ast_log(LOG_ERROR, "Failed to allocate memory for CURL write buffer for %s\n", public_cert_url);</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ open_socket_data = ast_calloc(1, sizeof(*open_socket_data));</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!open_socket_data) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "Failed to allocate memory for open socket callback\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ open_socket_data->acl = acl;</span><br><span style="color: hsl(120, 100%, 40%);">+ open_socket_data->sockfd = &sockfd;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> buf->url = public_cert_url;</span><br><span> curl_errbuf[CURL_ERROR_SIZE] = '\0';</span><br><span> </span><br><span>@@ -231,14 +282,19 @@</span><br><span> curl_easy_setopt(curl, CURLOPT_WRITEDATA, buf);</span><br><span> curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, curl_errbuf);</span><br><span> curl_easy_setopt(curl, CURLOPT_BUFFERSIZE, MAX_BUF_SIZE_PER_WRITE);</span><br><span style="color: hsl(120, 100%, 40%);">+ curl_easy_setopt(curl, CURLOPT_OPENSOCKETFUNCTION, stir_shaken_curl_open_socket_callback);</span><br><span style="color: hsl(120, 100%, 40%);">+ curl_easy_setopt(curl, CURLOPT_OPENSOCKETDATA, open_socket_data);</span><br><span> </span><br><span> if (curl_easy_perform(curl)) {</span><br><span> ast_log(LOG_ERROR, "%s\n", curl_errbuf);</span><br><span> curl_easy_cleanup(curl);</span><br><span> ast_free(buf);</span><br><span style="color: hsl(120, 100%, 40%);">+ curl_cb_open_socket_free(open_socket_data);</span><br><span> return NULL;</span><br><span> }</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+ curl_cb_open_socket_free(open_socket_data);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);</span><br><span> </span><br><span> curl_easy_cleanup(curl);</span><br><span>diff --git a/res/res_stir_shaken/curl.h b/res/res_stir_shaken/curl.h</span><br><span>index ae8feda..2dbd5d2 100644</span><br><span>--- a/res/res_stir_shaken/curl.h</span><br><span>+++ b/res/res_stir_shaken/curl.h</span><br><span>@@ -18,6 +18,8 @@</span><br><span> #ifndef _STIR_SHAKEN_CURL_H</span><br><span> #define _STIR_SHAKEN_CURL_H</span><br><span> </span><br><span style="color: hsl(120, 100%, 40%);">+struct ast_acl_list;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span> /* Forward declaration for CURL callback data */</span><br><span> struct curl_cb_data;</span><br><span> </span><br><span>@@ -66,10 +68,11 @@</span><br><span> * \param public_cert_url The public cert URL</span><br><span> * \param path The path to download the file to</span><br><span> * \param data The curl_cb_data</span><br><span style="color: hsl(120, 100%, 40%);">+ * \param acl The ACL to use for cURL (if not NULL)</span><br><span> *</span><br><span> * \retval NULL on failure</span><br><span> * \retval full path filename on success</span><br><span> */</span><br><span style="color: hsl(0, 100%, 40%);">-char *curl_public_key(const char *public_cert_url, const char *path, struct curl_cb_data *data);</span><br><span style="color: hsl(120, 100%, 40%);">+char *curl_public_key(const char *public_cert_url, const char *path, struct curl_cb_data *data, const struct ast_acl_list *acl);</span><br><span> </span><br><span> #endif /* _STIR_SHAKEN_CURL_H */</span><br><span>diff --git a/res/res_stir_shaken/profile.c b/res/res_stir_shaken/profile.c</span><br><span>new file mode 100644</span><br><span>index 0000000..5d4fa9b</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_stir_shaken/profile.c</span><br><span>@@ -0,0 +1,241 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2022, Sangoma Technologies Corporation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Ben Ford <bford@sangoma.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/cli.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/sorcery.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "stir_shaken.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "profile.h"</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/res_stir_shaken.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#define CONFIG_TYPE "profile"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void stir_shaken_profile_destructor(void *obj)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct stir_shaken_profile *cfg = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_free_acl_list(cfg->acl);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static void *stir_shaken_profile_alloc(const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct stir_shaken_profile *cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ cfg = ast_sorcery_generic_alloc(sizeof(*cfg), stir_shaken_profile_destructor);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!cfg) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct stir_shaken_profile *stir_shaken_profile_get(const char *id)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return ast_sorcery_retrieve_by_id(ast_stir_shaken_sorcery(), CONFIG_TYPE, id);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ao2_container *stir_shaken_profile_get_all(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return ast_sorcery_retrieve_by_fields(ast_stir_shaken_sorcery(), CONFIG_TYPE,</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_RETRIEVE_FLAG_MULTIPLE | AST_RETRIEVE_FLAG_ALL, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct stir_shaken_profile *ast_stir_shaken_get_profile_by_name(const char *name)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return ast_sorcery_retrieve_by_id(ast_stir_shaken_sorcery(), CONFIG_TYPE, name);</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int stir_shaken_profile_apply(const struct ast_sorcery *sorcery, void *obj)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int stir_shaken_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct stir_shaken_profile *cfg = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!strcasecmp("attest", var->value)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ cfg->stir_shaken = STIR_SHAKEN_ATTEST;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (!strcasecmp("verify", var->value)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ cfg->stir_shaken = STIR_SHAKEN_VERIFY;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else if (!strcasecmp("on", var->value)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ cfg->stir_shaken = STIR_SHAKEN_ON;</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_WARNING, "'%s' is not a valid value for option "</span><br><span style="color: hsl(120, 100%, 40%);">+ "'stir_shaken' for %s %s\n",</span><br><span style="color: hsl(120, 100%, 40%);">+ var->value, CONFIG_TYPE, ast_sorcery_object_get_id(cfg));</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static const char *stir_shaken_map[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ [STIR_SHAKEN_ATTEST] = "attest",</span><br><span style="color: hsl(120, 100%, 40%);">+ [STIR_SHAKEN_VERIFY] = "verify",</span><br><span style="color: hsl(120, 100%, 40%);">+ [STIR_SHAKEN_ON] = "on",</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int stir_shaken_to_str(const void *obj, const intptr_t *args, char **buf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct stir_shaken_profile *cfg = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ARRAY_IN_BOUNDS(cfg->stir_shaken, stir_shaken_map)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *buf = ast_strdup(stir_shaken_map[cfg->stir_shaken]);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int stir_shaken_acl_handler(const struct aco_option *opt, struct ast_variable *var, void *obj)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct stir_shaken_profile *cfg = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+ int error = 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ int ignore;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_strlen_zero(var->value)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_append_acl(var->name, var->value, &cfg->acl, &error, &ignore);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return error;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static int acl_to_str(const void *obj, const intptr_t *args, char **buf)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ const struct stir_shaken_profile *cfg = obj;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_acl_list *acl_list;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_acl *first_acl;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (cfg && !ast_acl_list_is_empty(acl_list=cfg->acl)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_LIST_LOCK(acl_list);</span><br><span style="color: hsl(120, 100%, 40%);">+ first_acl = AST_LIST_FIRST(acl_list);</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_strlen_zero(first_acl->name)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ *buf = "deny/permit";</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ *buf = first_acl->name;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_LIST_UNLOCK(acl_list);</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ *buf = ast_strdup(*buf);</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static char *stir_shaken_profile_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct stir_shaken_profile *cfg;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch(cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case CLI_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+ e->command = "stir_shaken show profile";</span><br><span style="color: hsl(120, 100%, 40%);">+ e->usage =</span><br><span style="color: hsl(120, 100%, 40%);">+ "Usage: stir_shaken show profile <id>\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ " Show the stir/shaken profile settings for a given id\n";</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ case CLI_GENERATE:</span><br><span style="color: hsl(120, 100%, 40%);">+ if (a->pos == 3) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return stir_shaken_tab_complete_name(a->word, stir_shaken_profile_get_all());</span><br><span style="color: hsl(120, 100%, 40%);">+ } else {</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (a->argc != 4) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return CLI_SHOWUSAGE;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ cfg = stir_shaken_profile_get(a->argv[3]);</span><br><span style="color: hsl(120, 100%, 40%);">+ stir_shaken_cli_show(cfg, a, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_acl_output(a->fd, cfg->acl, NULL);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(cfg);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return CLI_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static char *stir_shaken_profile_show_all(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ao2_container *container;</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ switch(cmd) {</span><br><span style="color: hsl(120, 100%, 40%);">+ case CLI_INIT:</span><br><span style="color: hsl(120, 100%, 40%);">+ e->command = "stir_shaken show profiles";</span><br><span style="color: hsl(120, 100%, 40%);">+ e->usage =</span><br><span style="color: hsl(120, 100%, 40%);">+ "Usage: stir_shaken show profiles\n"</span><br><span style="color: hsl(120, 100%, 40%);">+ " Show all profiles for stir/shaken\n";</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ case CLI_GENERATE:</span><br><span style="color: hsl(120, 100%, 40%);">+ return NULL;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (a->argc != 3) {</span><br><span style="color: hsl(120, 100%, 40%);">+ return CLI_SHOWUSAGE;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ container = stir_shaken_profile_get_all();</span><br><span style="color: hsl(120, 100%, 40%);">+ if (!container || ao2_container_count(container) == 0) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli(a->fd, "No stir/shaken ACLs found\n");</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_cleanup(container);</span><br><span style="color: hsl(120, 100%, 40%);">+ return CLI_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_callback(container, OBJ_NODATA, stir_shaken_cli_show, a);</span><br><span style="color: hsl(120, 100%, 40%);">+ ao2_ref(container, -1);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return CLI_SUCCESS;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+static struct ast_cli_entry stir_shaken_profile_cli[] = {</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_CLI_DEFINE(stir_shaken_profile_show, "Show stir/shaken profile by id"),</span><br><span style="color: hsl(120, 100%, 40%);">+ AST_CLI_DEFINE(stir_shaken_profile_show_all, "Show all stir/shaken profiles"),</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int stir_shaken_profile_unload(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli_unregister_multiple(stir_shaken_profile_cli,</span><br><span style="color: hsl(120, 100%, 40%);">+ ARRAY_LEN(stir_shaken_profile_cli));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+int stir_shaken_profile_load(void)</span><br><span style="color: hsl(120, 100%, 40%);">+{</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_sorcery *sorcery = ast_stir_shaken_sorcery();</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_apply_default(sorcery, CONFIG_TYPE, "config", "stir_shaken.conf,criteria=type=profile");</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ if (ast_sorcery_object_register(sorcery, CONFIG_TYPE, stir_shaken_profile_alloc,</span><br><span style="color: hsl(120, 100%, 40%);">+ NULL, stir_shaken_profile_apply)) {</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_log(LOG_ERROR, "stir/shaken - failed to register '%s' sorcery object\n", CONFIG_TYPE);</span><br><span style="color: hsl(120, 100%, 40%);">+ return -1;</span><br><span style="color: hsl(120, 100%, 40%);">+ }</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register(sorcery, CONFIG_TYPE, "type", "", OPT_NOOP_T, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register_custom(sorcery, CONFIG_TYPE, "stir_shaken", "on", stir_shaken_handler, stir_shaken_to_str, NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register_custom(sorcery, CONFIG_TYPE, "deny", "", stir_shaken_acl_handler, NULL, NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register_custom(sorcery, CONFIG_TYPE, "permit", "", stir_shaken_acl_handler, NULL, NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_sorcery_object_field_register_custom(sorcery, CONFIG_TYPE, "acllist", "", stir_shaken_acl_handler, acl_to_str, NULL, 0, 0);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ ast_cli_register_multiple(stir_shaken_profile_cli,</span><br><span style="color: hsl(120, 100%, 40%);">+ ARRAY_LEN(stir_shaken_profile_cli));</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+ return 0;</span><br><span style="color: hsl(120, 100%, 40%);">+}</span><br><span>diff --git a/res/res_stir_shaken/profile.h b/res/res_stir_shaken/profile.h</span><br><span>new file mode 100644</span><br><span>index 0000000..5617e9a</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_stir_shaken/profile.h</span><br><span>@@ -0,0 +1,39 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2022, Sangoma Technologies Corporation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Ben Ford <bford@sangoma.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef _STIR_SHAKEN_PROFILE_H</span><br><span style="color: hsl(120, 100%, 40%);">+#define _STIR_SHAKEN_PROFILE_H</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "profile_private.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct stir_shaken_profile *ast_stir_shaken_get_profile_by_name(const char *name);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Load time initialization for the stir/shaken 'profile' object</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 on success, -1 on error</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int stir_shaken_profile_load(void);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+/*!</span><br><span style="color: hsl(120, 100%, 40%);">+ * \brief Unload time cleanup for the stir/shaken 'profile'</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * \retval 0 on success, -1 on error</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+int stir_shaken_profile_unload(void);</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#endif /* _STIR_SHAKEN_PROFILE_H */</span><br><span>diff --git a/res/res_stir_shaken/profile_private.h b/res/res_stir_shaken/profile_private.h</span><br><span>new file mode 100644</span><br><span>index 0000000..536a0fe</span><br><span>--- /dev/null</span><br><span>+++ b/res/res_stir_shaken/profile_private.h</span><br><span>@@ -0,0 +1,40 @@</span><br><span style="color: hsl(120, 100%, 40%);">+/*</span><br><span style="color: hsl(120, 100%, 40%);">+ * Asterisk -- An open source telephony toolkit.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Copyright (C) 2022, Sangoma Technologies Corporation</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * Ben Ford <bford@sangoma.com></span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * See http://www.asterisk.org for more information about</span><br><span style="color: hsl(120, 100%, 40%);">+ * the Asterisk project. Please do not directly contact</span><br><span style="color: hsl(120, 100%, 40%);">+ * any of the maintainers of this project for assistance;</span><br><span style="color: hsl(120, 100%, 40%);">+ * the project provides a web site, mailing lists and IRC</span><br><span style="color: hsl(120, 100%, 40%);">+ * channels for your use.</span><br><span style="color: hsl(120, 100%, 40%);">+ *</span><br><span style="color: hsl(120, 100%, 40%);">+ * This program is free software, distributed under the terms of</span><br><span style="color: hsl(120, 100%, 40%);">+ * the GNU General Public License Version 2. See the LICENSE file</span><br><span style="color: hsl(120, 100%, 40%);">+ * at the top of the source tree.</span><br><span style="color: hsl(120, 100%, 40%);">+ */</span><br><span style="color: hsl(120, 100%, 40%);">+#ifndef _STIR_SHAKEN_PROFILE_PRIVATE_H</span><br><span style="color: hsl(120, 100%, 40%);">+#define _STIR_SHAKEN_PROFILE_PRIVATE_H</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/sorcery.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#include "asterisk/acl.h"</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+enum stir_shaken_profile_behavior {</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Only do STIR/SHAKEN attestation */</span><br><span style="color: hsl(120, 100%, 40%);">+ STIR_SHAKEN_ATTEST = 1,</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Only do STIR/SHAKEN verification */</span><br><span style="color: hsl(120, 100%, 40%);">+ STIR_SHAKEN_VERIFY = 2,</span><br><span style="color: hsl(120, 100%, 40%);">+ /*! Do STIR/SHAKEN attestation and verification */</span><br><span style="color: hsl(120, 100%, 40%);">+ STIR_SHAKEN_ON = 3,</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+struct stir_shaken_profile {</span><br><span style="color: hsl(120, 100%, 40%);">+ SORCERY_OBJECT(details);</span><br><span style="color: hsl(120, 100%, 40%);">+ unsigned int stir_shaken;</span><br><span style="color: hsl(120, 100%, 40%);">+ struct ast_acl_list *acl;</span><br><span style="color: hsl(120, 100%, 40%);">+};</span><br><span style="color: hsl(120, 100%, 40%);">+</span><br><span style="color: hsl(120, 100%, 40%);">+#endif /* _STIR_SHAKEN_PROFILE_PRIVATE_H */</span><br><span></span><br></pre><div style="white-space:pre-wrap"></div><p>To view, visit <a href="https://gerrit.asterisk.org/c/asterisk/+/18394">change 18394</a>. To unsubscribe, or for help writing mail filters, visit <a href="https://gerrit.asterisk.org/settings">settings</a>.</p><div itemscope itemtype="http://schema.org/EmailMessage"><div itemscope itemprop="action" itemtype="http://schema.org/ViewAction"><link itemprop="url" href="https://gerrit.asterisk.org/c/asterisk/+/18394"/><meta itemprop="name" content="View Change"/></div></div>
<div style="display:none"> Gerrit-Project: asterisk </div>
<div style="display:none"> Gerrit-Branch: 16.25 </div>
<div style="display:none"> Gerrit-Change-Id: I87fa61f78a9ea0cd42530691a30da3c781842406 </div>
<div style="display:none"> Gerrit-Change-Number: 18394 </div>
<div style="display:none"> Gerrit-PatchSet: 1 </div>
<div style="display:none"> Gerrit-Owner: Michael Bradeen <mbradeen@sangoma.com> </div>
<div style="display:none"> Gerrit-Reviewer: Michael Bradeen <mbradeen@sangoma.com> </div>
<div style="display:none"> Gerrit-CC: Benjamin Keith Ford <bford@digium.com> </div>
<div style="display:none"> Gerrit-CC: Friendly Automation </div>
<div style="display:none"> Gerrit-MessageType: merged </div>