Asterisk - The Open Source Telephony Project GIT-master-8f1982c
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros Modules Pages
Enumerations | Functions | Variables
res_pjsip_authenticator_digest.c File Reference

PJSIP UAS Authentication. More...

#include "asterisk.h"
#include <pjsip.h>
#include "asterisk/res_pjsip.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/strings.h"
#include "asterisk/test.h"
Include dependency graph for res_pjsip_authenticator_digest.c:

Go to the source code of this file.

Enumerations

enum  digest_verify_result { AUTH_FAIL = 0 , AUTH_SUCCESS , AUTH_STALE , AUTH_NOAUTH }
 Result of digest verification. More...
 

Functions

static void __init_auth_store (void)
 Thread-local storage for ast_sip_auth. More...
 
static void __reg_module (void)
 
static void __unreg_module (void)
 
 AO2_GLOBAL_OBJ_STATIC (entity_id)
 
struct ast_moduleAST_MODULE_SELF_SYM (void)
 
static void auth_store_cleanup (void *data)
 
static int build_entity_id (void)
 
static int build_nonce (struct ast_str **nonce, const char *timestamp, const pjsip_rx_data *rdata, const char *realm)
 Calculate a nonce. More...
 
static void challenge (const char *endpoint_id, struct ast_sip_auth *auth, pjsip_tx_data *tdata, const pjsip_rx_data *rdata, int is_stale, const pjsip_auth_algorithm *algorithm)
 Send a WWW-Authenticate challenge. More...
 
static int check_nonce (const char *candidate, const pjsip_rx_data *rdata, const struct ast_sip_auth *auth)
 Ensure that a nonce on an incoming request is sane. More...
 
static enum ast_sip_check_auth_result digest_check_auth (struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pjsip_tx_data *tdata)
 Check authentication using Digest scheme. More...
 
static pj_status_t digest_lookup (pj_pool_t *pool, const pjsip_auth_lookup_cred_param *param, pjsip_cred_info *cred_info)
 Lookup callback for authentication verification. More...
 
static int digest_requires_authentication (struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
 Determine if authentication is required. More...
 
static enum digest_verify_result find_authorization (const char *endpoint_id, const struct ast_sip_auth *auth, const pjsip_rx_data *rdata)
 
static const struct ast_sip_authget_auth (void)
 Retrieve shallow copy authentication information from thread-local storage. More...
 
static struct pjsip_authorization_hdr * get_authorization_hdr (const char *auth_id, const char *realm, const pjsip_rx_data *rdata)
 
static void global_loaded (const char *object_type)
 
static int load_module (void)
 
static int reload_module (void)
 
static int remove_auth (void)
 Remove shallow copy authentication information from thread-local storage. More...
 
static void setup_auth_srv (pj_pool_t *pool, pjsip_auth_srv *auth_server, const char *realm)
 Common code for initializing a pjsip_auth_srv. More...
 
static int store_auth (const struct ast_sip_auth *auth)
 Store shallow copy authentication information in thread-local storage. More...
 
static int unload_module (void)
 
static int verify (const char *endpoint_id, const struct ast_sip_auth *auth, pjsip_rx_data *rdata, pj_pool_t *pool)
 Verify incoming credentials. More...
 

Variables

static struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP authentication resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND - 5, .requires = "res_pjsip", }
 
static const struct ast_module_infoast_module_info = &__mod_info
 
static struct ast_threadstorage auth_store = { .once = PTHREAD_ONCE_INIT , .key_init = __init_auth_store , .custom_init = NULL , }
 
static char * check_auth_result_str []
 
static char default_realm [AST_SIP_AUTH_MAX_REALM_LENGTH+1]
 
static struct ast_sip_authenticator digest_authenticator
 
static struct ast_sorcery_observer global_observer
 Observer which is used to update our default_realm when the global setting changes. More...
 
static char * verify_result_str []
 

Detailed Description

PJSIP UAS Authentication.

This module handles authentication when Asterisk is the UAS.

Definition in file res_pjsip_authenticator_digest.c.

Enumeration Type Documentation

◆ digest_verify_result

Result of digest verification.

Enumerator
AUTH_FAIL 

Authentication credentials incorrect

AUTH_SUCCESS 

Authentication credentials correct

AUTH_STALE 

Authentication credentials correct but nonce mismatch

AUTH_NOAUTH 

Authentication credentials were not provided

Definition at line 352 of file res_pjsip_authenticator_digest.c.

352 {
353 /*! Authentication credentials incorrect */
354 AUTH_FAIL = 0,
355 /*! Authentication credentials correct */
357 /*! Authentication credentials correct but nonce mismatch */
359 /*! Authentication credentials were not provided */
361};

Function Documentation

◆ __init_auth_store()

static void __init_auth_store ( void  )
static

Thread-local storage for ast_sip_auth.

The PJSIP authentication API is a bit annoying. When you set up an authentication server, you specify a lookup callback to call into when verifying incoming credentials. The problem with this callback is that it only gives you the realm and authentication username. In 2.0.5, there is a new version of the callback you can use that gives the pjsip_rx_data in addition.

Unfortunately, the data we actually need is the ast_sip_auth we are currently observing. So we have two choices: 1) Use the current PJSIP API and use thread-local storage to temporarily store our SIP authentication information. Then in the callback, we can retrieve the authentication info and use as needed. Given our threading model, this is safe. 2) Use the 2.0.5 API and temporarily store the authentication information in the rdata's endpoint_info. Then in the callback, we can retrieve the authentication info from the rdata.

I've chosen option 1 since it does not require backporting any APIs from future versions of PJSIP, plus I feel the thread-local option is a bit cleaner.

Definition at line 94 of file res_pjsip_authenticator_digest.c.

100{

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 839 of file res_pjsip_authenticator_digest.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 839 of file res_pjsip_authenticator_digest.c.

◆ AO2_GLOBAL_OBJ_STATIC()

AO2_GLOBAL_OBJ_STATIC ( entity_id  )

◆ AST_MODULE_SELF_SYM()

struct ast_module * AST_MODULE_SELF_SYM ( void  )

Definition at line 839 of file res_pjsip_authenticator_digest.c.

◆ auth_store_cleanup()

static void auth_store_cleanup ( void *  data)
static

Definition at line 60 of file res_pjsip_authenticator_digest.c.

61{
62 struct ast_sip_auth **auth = data;
63
64 ao2_cleanup(*auth);
65 ast_free(data);
66}
#define ast_free(a)
Definition: astmm.h:180
#define ao2_cleanup(obj)
Definition: astobj2.h:1934

References ao2_cleanup, and ast_free.

◆ build_entity_id()

static int build_entity_id ( void  )
static

Definition at line 775 of file res_pjsip_authenticator_digest.c.

776{
777 char *eid;
778
780 if (!eid) {
781 return -1;
782 }
783
785 ao2_global_obj_replace_unref(entity_id, eid);
786 ao2_ref(eid, -1);
787 return 0;
788}
#define ao2_global_obj_replace_unref(holder, obj)
Replace an ao2 object in the global holder, throwing away any old object.
Definition: astobj2.h:901
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition: astobj2.h:459
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:409
#define NULL
Definition: resample.c:96
#define AST_UUID_STR_LEN
Definition: uuid.h:27
char * ast_uuid_generate_str(char *buf, size_t size)
Generate a UUID string.
Definition: uuid.c:141

References ao2_alloc, ao2_global_obj_replace_unref, ao2_ref, ast_uuid_generate_str(), AST_UUID_STR_LEN, and NULL.

Referenced by load_module(), and reload_module().

◆ build_nonce()

static int build_nonce ( struct ast_str **  nonce,
const char *  timestamp,
const pjsip_rx_data *  rdata,
const char *  realm 
)
static

Calculate a nonce.

We use this in order to create authentication challenges. We also use this in order to verify that an incoming request with credentials could be in response to one of our challenges.

The nonce is calculated from a timestamp, the source IP address, the source port, a unique ID for us, and the realm. This helps to ensure that the incoming request is from the same source that the nonce was calculated for. Including the realm ensures that multiple challenges to the same request have different nonces.

Parameters
nonce
timestampA UNIX timestamp expressed as a string
rdataThe incoming request
realmThe realm for which authentication should occur

Definition at line 287 of file res_pjsip_authenticator_digest.c.

289{
290 struct ast_str *str = ast_str_alloca(256);
291 RAII_VAR(char *, eid, ao2_global_obj_ref(entity_id), ao2_cleanup);
292 char hash[33];
293
294 /*
295 * Note you may be tempted to think why not include the port. The reason
296 * is that when using TCP the port can potentially differ from before.
297 */
298 ast_str_append(&str, 0, "%s", timestamp);
299 ast_str_append(&str, 0, ":%s", rdata->pkt_info.src_name);
300 ast_str_append(&str, 0, ":%s", eid);
301 ast_str_append(&str, 0, ":%s", realm);
303
304 ast_str_append(nonce, 0, "%s/%s", timestamp, hash);
305 return 0;
306}
const char * str
Definition: app_jack.c:150
#define ao2_global_obj_ref(holder)
Get a reference to the object stored in the global holder.
Definition: astobj2.h:918
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition: strings.h:1139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:761
#define ast_str_alloca(init_len)
Definition: strings.h:848
Support for dynamic strings.
Definition: strings.h:623
#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
void ast_md5_hash(char *output, const char *input)
Produces MD5 hash based on input string.
Definition: utils.c:250

References ao2_cleanup, ao2_global_obj_ref, ast_md5_hash(), ast_str_alloca, ast_str_append(), ast_str_buffer(), RAII_VAR, and str.

Referenced by challenge(), and check_nonce().

◆ challenge()

static void challenge ( const char *  endpoint_id,
struct ast_sip_auth auth,
pjsip_tx_data *  tdata,
const pjsip_rx_data *  rdata,
int  is_stale,
const pjsip_auth_algorithm algorithm 
)
static

Send a WWW-Authenticate challenge.

Parameters
endpoint_idFor logging
authThe auth object to use for the challenge
tdataThe response to add the challenge to
rdataThe request the challenge is in response to
is_staleIndicates whether nonce on incoming request was stale
algorithm_typeThe algorithm to use for the challenge

Definition at line 507 of file res_pjsip_authenticator_digest.c.

510{
511 pj_str_t qop;
512 pj_str_t pj_nonce;
513 pjsip_auth_srv auth_server;
514 struct ast_str *nonce = ast_str_alloca(256);
515 char time_buf[32];
516 time_t timestamp = time(NULL);
517 pj_status_t res;
518 const char *realm = S_OR(auth->realm, default_realm);
519 const char *auth_id = ast_sorcery_object_get_id(auth);
520 const char *src_name = rdata->pkt_info.src_name;
521 SCOPE_ENTER(5, "%s:%s:%s: realm: %s time: %d algorithm: " PJSTR_PRINTF_SPEC " stale? %s\n",
522 endpoint_id, auth_id, src_name, realm, (int)timestamp,
523 PJSTR_PRINTF_VAR(algorithm->iana_name), is_stale ? "yes" : "no");
524
525 snprintf(time_buf, sizeof(time_buf), "%d", (int) timestamp);
526
527 build_nonce(&nonce, time_buf, rdata, realm);
528
529 setup_auth_srv(tdata->pool, &auth_server, realm);
530
531 pj_cstr(&pj_nonce, ast_str_buffer(nonce));
532 pj_cstr(&qop, "auth");
533#ifdef HAVE_PJSIP_AUTH_NEW_DIGESTS
534 res = pjsip_auth_srv_challenge2(&auth_server, &qop, &pj_nonce,
535 NULL, is_stale ? PJ_TRUE : PJ_FALSE, tdata, algorithm->algorithm_type);
536#else
537 res = pjsip_auth_srv_challenge(&auth_server, &qop, &pj_nonce,
538 NULL, is_stale ? PJ_TRUE : PJ_FALSE, tdata);
539#endif
540 SCOPE_EXIT_RTN("%s:%s:%s: Sending challenge for realm: %s algorithm: " PJSTR_PRINTF_SPEC
541 " %s\n",
542 endpoint_id, auth_id, src_name, realm, PJSTR_PRINTF_VAR(algorithm->iana_name),
543 res == PJ_SUCCESS ? "succeeded" : "failed");
544}
#define SCOPE_EXIT_RTN(...)
#define SCOPE_ENTER(level,...)
#define PJSTR_PRINTF_VAR(_v)
Definition: res_pjsip.h:72
#define PJSTR_PRINTF_SPEC
Definition: res_pjsip.h:71
static void setup_auth_srv(pj_pool_t *pool, pjsip_auth_srv *auth_server, const char *realm)
Common code for initializing a pjsip_auth_srv.
static char default_realm[AST_SIP_AUTH_MAX_REALM_LENGTH+1]
static int build_nonce(struct ast_str **nonce, const char *timestamp, const pjsip_rx_data *rdata, const char *realm)
Calculate a nonce.
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
#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
const ast_string_field realm
Definition: res_pjsip.h:681
pjsip_auth_algorithm_type algorithm_type
Definition: res_pjsip.h:618

References pjsip_auth_algorithm::algorithm_type, ast_sorcery_object_get_id(), ast_str_alloca, ast_str_buffer(), build_nonce(), default_realm, pjsip_auth_algorithm::iana_name, NULL, PJSTR_PRINTF_SPEC, PJSTR_PRINTF_VAR, ast_sip_auth::realm, S_OR, SCOPE_ENTER, SCOPE_EXIT_RTN, and setup_auth_srv().

Referenced by ast_sip_create_request_with_auth(), authenticate(), authenticate_reply(), authenticate_request(), decrypt_frame(), digest_check_auth(), digest_create_request_with_auth(), get_auth_search_type(), manager_login(), register_verify(), registry_authrequest(), registry_rerequest(), send_request_cb(), and set_auth_creds().

◆ check_nonce()

static int check_nonce ( const char *  candidate,
const pjsip_rx_data *  rdata,
const struct ast_sip_auth auth 
)
static

Ensure that a nonce on an incoming request is sane.

The nonce in an incoming Authorization header needs to pass some scrutiny in order for us to consider accepting it. What we do is re-build a nonce based on request data and a realm and see if it matches the nonce they sent us.

Parameters
candidateThe nonce on an incoming request
rdataThe incoming request
authThe auth credentials we are trying to match against.
Return values
0Nonce does not pass validity checks
1Nonce passes validity check

Definition at line 320 of file res_pjsip_authenticator_digest.c.

321{
322 char *copy = ast_strdupa(candidate);
323 char *timestamp = strsep(&copy, "/");
324 int timestamp_int;
325 time_t now = time(NULL);
326 struct ast_str *calculated = ast_str_alloca(64);
327
328 if (!copy) {
329 /* Clearly a bad nonce! */
330 return 0;
331 }
332
333 if (sscanf(timestamp, "%30d", &timestamp_int) != 1) {
334 return 0;
335 }
336
337 if ((int) now - timestamp_int > auth->nonce_lifetime) {
338 return 0;
339 }
340
341 build_nonce(&calculated, timestamp, rdata, S_OR(auth->realm, default_realm));
342 ast_debug(3, "Calculated nonce %s. Actual nonce is %s\n", ast_str_buffer(calculated), candidate);
343 if (strcmp(ast_str_buffer(calculated), candidate)) {
344 return 0;
345 }
346 return 1;
347}
static int copy(char *infile, char *outfile)
Utility function to copy a file.
char * strsep(char **str, const char *delims)
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
#define ast_debug(level,...)
Log a DEBUG message.
unsigned int nonce_lifetime
Definition: res_pjsip.h:683

References ast_debug, ast_str_alloca, ast_str_buffer(), ast_strdupa, build_nonce(), copy(), default_realm, ast_sip_auth::nonce_lifetime, NULL, ast_sip_auth::realm, S_OR, and strsep().

Referenced by find_authorization().

◆ digest_check_auth()

static enum ast_sip_check_auth_result digest_check_auth ( struct ast_sip_endpoint endpoint,
pjsip_rx_data *  rdata,
pjsip_tx_data *  tdata 
)
static

Check authentication using Digest scheme.

This function will check an incoming message against configured authentication options. If any of the incoming Authorization headers result in successful authentication, then authentication is considered successful.

Warning
The return code from the function is used by the distributor to determine which log messages (if any) are emitted. Many admins will be using log parsers like fail2ban to block IPs that are repeatedly failing to authenticate so changing the return code could have unintended consequences.
Return values
AST_SIP_AUTHENTICATION_SUCCESSThere was an Authorization header in the request and it verified successfully with at least one auth object on the endpoint. No further challenges sent.
AST_SIP_AUTHENTICATION_CHALLENGEThere was NO Authorization header in the incoming request. We sent a 401 with one or more challenges.
AST_SIP_AUTHENTICATION_FAILEDThere were one or more Authorization headers in the request but they all failed to verify with any auth object on the endpoint. We sent a 401 with one or more challenges.
AST_SIP_AUTHENTICATION_ERRORAn internal error occurred. No challenges were sent.
See also
ast_sip_check_authentication

Definition at line 583 of file res_pjsip_authenticator_digest.c.

585{
586 struct ast_sip_auth **auths;
587 enum digest_verify_result *verify_res;
590 int idx;
591 int is_artificial;
592 int failures = 0;
593 size_t auth_size;
594 const char *endpoint_id = ast_sorcery_object_get_id(endpoint);
595 char *src_name = rdata->pkt_info.src_name;
596 SCOPE_ENTER(3, "%s:%s\n", endpoint_id, src_name);
597
598 auth_size = AST_VECTOR_SIZE(&endpoint->inbound_auths);
599 ast_assert(0 < auth_size);
600
601 auths = ast_alloca(auth_size * sizeof(*auths));
602 verify_res = ast_alloca(auth_size * sizeof(*verify_res));
603
605 if (!artificial_endpoint) {
606 /* Should not happen except possibly if we are shutting down. */
608 }
609
610 is_artificial = endpoint == artificial_endpoint;
612 if (is_artificial) {
613 ast_trace(3, "%s:%s: Using artificial endpoint for authentication\n",
614 endpoint_id, src_name);
615 ast_assert(auth_size == 1);
616 auths[0] = ast_sip_get_artificial_auth();
617 if (!auths[0]) {
618 /* Should not happen except possibly if we are shutting down. */
620 }
621 } else {
622 ast_trace(3, "%s:%s: Using endpoint for authentication\n",
623 endpoint_id, src_name);
624 memset(auths, 0, auth_size * sizeof(*auths));
625 /*
626 * If ast_sip_retrieve_auths returns a failure we still need
627 * to cleanup the auths array because it may have been partially
628 * filled in.
629 */
630 if (ast_sip_retrieve_auths(&endpoint->inbound_auths, auths)) {
631 ast_sip_cleanup_auths(auths, auth_size);
633 "%s:%s: Failed to retrieve some or all auth objects from endpoint\n",
634 endpoint_id, src_name);
635 }
636 }
637
638 /*
639 * Verify any Authorization headers in the incoming request against the
640 * auth objects on the endpoint. If there aren't any Authorization headers
641 * verify() will return AUTH_NOAUTH.
642 *
643 * NOTE: The only reason to use multiple auth objects as a UAS might
644 * be to send challenges for multiple realms however we currently don't
645 * know of anyone actually doing this.
646 */
647 for (idx = 0; idx < auth_size; ++idx) {
648 struct ast_sip_auth *auth = auths[idx];
649 const char *auth_id = ast_sorcery_object_get_id(auth);
650 SCOPE_ENTER(4, "%s:%s:%s: Auth %d of %d: Verifying\n",
651 endpoint_id, auth_id, src_name, idx + 1, (int)auth_size);
652
653 verify_res[idx] = SCOPE_CALL_WITH_RESULT(-1, int, verify, endpoint_id, auth, rdata, tdata->pool);
654 switch((int)verify_res[idx]) {
655 case AUTH_SUCCESS:
657 break;
658 case AUTH_FAIL:
659 failures++;
660 break;
661 case AUTH_NOAUTH:
662 case AUTH_STALE:
663 break;
664 }
665
666 SCOPE_EXIT("%s:%s:%s: Auth %d of %d: Result: %s Failure count: %d\n",
667 endpoint_id, auth_id, src_name, idx + 1, (int)auth_size,
668 verify_result_str[verify_res[idx]], failures);
669
670 /*
671 * If there was a success or there was no Authorization header in the
672 * incoming request, we can stop verifying the rest of the auth objects.
673 */
674 if (verify_res[idx] == AUTH_SUCCESS || verify_res[idx] == AUTH_NOAUTH) {
675 break;
676 }
677 }
678
680 ast_sip_cleanup_auths(auths, auth_size);
681 SCOPE_EXIT_RTN_VALUE(res, "%s:%s: Result: %s\n",
682 endpoint_id, src_name,
684 }
685 ast_trace(-1, "%s:%s: Done with verification. Failures: %d of %d\n",
686 endpoint_id, src_name, failures, (int)auth_size);
687
688 /*
689 * If none of the Authorization headers in the incoming request were
690 * successfully verified, or there were no Authorization headers in the
691 * request, we need to send challenges for each auth object
692 * on the endpoint.
693 */
694 for (idx = 0; idx < auth_size; ++idx) {
695 int i = 0;
696 struct ast_sip_auth *auth = auths[idx];
697 const char *realm = S_OR(auth->realm, default_realm);
698 const char *auth_id = ast_sorcery_object_get_id(auth);
699 SCOPE_ENTER(4, "%s:%s:%s: Auth %d of %d: Sending challenges\n",
700 endpoint_id, auth_id, src_name, idx + 1, (int)auth_size);
701
702 for (i = 0; i < AST_VECTOR_SIZE(&auth->supported_algorithms_uas); i++) {
704 const pjsip_auth_algorithm *algorithm = ast_sip_auth_get_algorithm_by_type(algorithm_type);
705 pjsip_www_authenticate_hdr *auth_hdr = NULL;
706 int already_sent_challenge = 0;
707 SCOPE_ENTER(5, "%s:%s:%s: Auth %d of %d: Challenging with " PJSTR_PRINTF_SPEC "\n",
708 endpoint_id, auth_id, src_name, idx + 1, (int)auth_size,
709 PJSTR_PRINTF_VAR(algorithm->iana_name));
710
711 /*
712 * Per RFC 7616, if we've already sent a challenge for this realm
713 * and algorithm, we must not send another.
714 */
715 while ((auth_hdr = pjsip_msg_find_hdr(tdata->msg,
716 PJSIP_H_WWW_AUTHENTICATE, auth_hdr ? auth_hdr->next : NULL))) {
717 if (pj_strcmp2(&auth_hdr->challenge.common.realm, realm) == 0 &&
718 !pj_stricmp(&auth_hdr->challenge.digest.algorithm, &algorithm->iana_name)) {
719 ast_trace(-1, "%s:%s:%s: Auth %d of %d: Not sending duplicate challenge for realm: %s algorithm: "
721 endpoint_id, auth_id, src_name, idx + 1, (int)auth_size,
722 realm, PJSTR_PRINTF_VAR(algorithm->iana_name));
723 already_sent_challenge = 1;
724 }
725 }
726 if (already_sent_challenge) {
727 SCOPE_EXIT_EXPR(continue);
728 }
729
730 SCOPE_CALL(5, challenge, endpoint_id, auth, tdata, rdata,
731 verify_res[idx] == AUTH_STALE, algorithm);
733
734 SCOPE_EXIT("%s:%s:%s: Auth %d of %d: Challenged with " PJSTR_PRINTF_SPEC "\n",
735 endpoint_id, auth_id, src_name, idx + 1, (int)auth_size,
736 PJSTR_PRINTF_VAR(algorithm->iana_name));
737 }
738 SCOPE_EXIT("%s:%s:%s: Auth %d of %d: Done with challenges\n",
739 endpoint_id, auth_id, src_name, idx + 1, (int)auth_size);
740 }
741
742 /*
743 * If we've sent challenges for multiple auth objects, we currently
744 * return SUCCESS when the first one succeeds. We may want to change
745 * this in the future to require that all succeed but as stated above,
746 * currently we don't have a use case for even using more than one
747 * auth object as a UAS.
748 */
749
750 /*
751 * If the authentication failed for any reason, we want to send
752 * a 401 with a challenge. If it was because there was no
753 * Authorization header or there was a stale nonce, fine. That's not
754 * unusual so we return AST_SIP_AUTHENTICATION_CHALLENGE. If it
755 * failed because of a user/password mismatch then we return
756 * AST_SIP_AUTHENTICATION_FAILED which causes the distributor to
757 * print a "Failed to authenticate" message.
758 */
759 if (failures == auth_size) {
761 }
762
763 ast_sip_cleanup_auths(auths, auth_size);
764 SCOPE_EXIT_RTN_VALUE(res, "%s:%s: Result: %s\n",
765 endpoint_id, src_name,
767
768}
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
#define SCOPE_CALL_WITH_RESULT(level, __var, __funcname,...)
#define SCOPE_EXIT_EXPR(__expr,...)
#define SCOPE_CALL(level, __funcname,...)
#define SCOPE_EXIT(...)
#define ast_trace(level,...)
static struct ast_sip_endpoint * artificial_endpoint
struct ast_sip_auth * ast_sip_get_artificial_auth(void)
Retrieves a reference to the artificial auth.
pjsip_auth_algorithm_type
Definition: res_pjsip.h:607
const pjsip_auth_algorithm * ast_sip_auth_get_algorithm_by_type(pjsip_auth_algorithm_type algorithm_type)
Get algorithm by algorithm type.
Definition: config_auth.c:66
struct ast_sip_endpoint * ast_sip_get_artificial_endpoint(void)
Retrieves a reference to the artificial endpoint.
void ast_sip_cleanup_auths(struct ast_sip_auth *auths[], size_t num_auths)
Clean up retrieved auth structures from memory.
int ast_sip_retrieve_auths(const struct ast_sip_auth_vector *auths, struct ast_sip_auth **out)
Retrieve relevant SIP auth structures from sorcery.
ast_sip_check_auth_result
Possible returns from ast_sip_check_authentication.
Definition: res_pjsip.h:1321
@ AST_SIP_AUTHENTICATION_CHALLENGE
Definition: res_pjsip.h:1323
@ AST_SIP_AUTHENTICATION_ERROR
Definition: res_pjsip.h:1329
@ AST_SIP_AUTHENTICATION_SUCCESS
Definition: res_pjsip.h:1325
@ AST_SIP_AUTHENTICATION_FAILED
Definition: res_pjsip.h:1327
digest_verify_result
Result of digest verification.
static int verify(const char *endpoint_id, const struct ast_sip_auth *auth, pjsip_rx_data *rdata, pj_pool_t *pool)
Verify incoming credentials.
static void challenge(const char *endpoint_id, struct ast_sip_auth *auth, pjsip_tx_data *tdata, const pjsip_rx_data *rdata, int is_stale, const pjsip_auth_algorithm *algorithm)
Send a WWW-Authenticate challenge.
static char * check_auth_result_str[]
static char * verify_result_str[]
struct pjsip_auth_algorithm_type_vector supported_algorithms_uas
Definition: res_pjsip.h:689
An entity with which Asterisk communicates.
Definition: res_pjsip.h:1051
struct ast_sip_auth_vector inbound_auths
Definition: res_pjsip.h:1096
#define ast_assert(a)
Definition: utils.h:739
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:609
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:680

References ao2_ref, artificial_endpoint, ast_alloca, ast_assert, ast_sip_auth_get_algorithm_by_type(), AST_SIP_AUTHENTICATION_CHALLENGE, AST_SIP_AUTHENTICATION_ERROR, AST_SIP_AUTHENTICATION_FAILED, AST_SIP_AUTHENTICATION_SUCCESS, ast_sip_cleanup_auths(), ast_sip_get_artificial_auth(), ast_sip_get_artificial_endpoint(), ast_sip_retrieve_auths(), ast_sorcery_object_get_id(), ast_trace, AST_VECTOR_GET, AST_VECTOR_SIZE, AUTH_FAIL, AUTH_NOAUTH, AUTH_STALE, AUTH_SUCCESS, challenge(), check_auth_result_str, default_realm, pjsip_auth_algorithm::iana_name, ast_sip_endpoint::inbound_auths, NULL, PJSTR_PRINTF_SPEC, PJSTR_PRINTF_VAR, ast_sip_auth::realm, S_OR, SCOPE_CALL, SCOPE_CALL_WITH_RESULT, SCOPE_ENTER, SCOPE_EXIT, SCOPE_EXIT_EXPR, SCOPE_EXIT_RTN_VALUE, ast_sip_auth::supported_algorithms_uas, verify(), and verify_result_str.

◆ digest_lookup()

static pj_status_t digest_lookup ( pj_pool_t *  pool,
const pjsip_auth_lookup_cred_param *  param,
pjsip_cred_info *  cred_info 
)
static

Lookup callback for authentication verification.

This function is called when we call pjsip_auth_srv_verify(). It expects us to verify that the realm and account name from the Authorization header are correct and that we can support the digest algorithm specified. We are then supposed to supply a password or password_digest for the algorithm.

The auth object must have previously been saved to thread-local storage.

Parameters
poolA memory pool we can use for allocations
paramContains the realm, username, rdata and auth header
cred_infoThe credentials we need to fill in
Return values
PJ_SUCCESSSuccessful authentication
otherUnsuccessful

Definition at line 178 of file res_pjsip_authenticator_digest.c.

181{
182 const struct ast_sip_auth *auth = get_auth();
183 const char *realm = S_OR(auth->realm, default_realm);
184 const char *creds;
185 const char *auth_name = (auth ? ast_sorcery_object_get_id(auth) : "none");
186 struct pjsip_authorization_hdr *auth_hdr = get_authorization_hdr(auth_name, realm, param->rdata);
187 const pjsip_auth_algorithm *algorithm =
188 ast_sip_auth_get_algorithm_by_iana_name(&auth_hdr->credential.digest.algorithm);
189 const char *src_name = param->rdata->pkt_info.src_name;
190 SCOPE_ENTER(4, "%s:%s:"
191 " srv realm: " PJSTR_PRINTF_SPEC
192 " auth realm: %s"
193 " hdr realm: " PJSTR_PRINTF_SPEC
194 " auth user: %s"
195 " hdr user: " PJSTR_PRINTF_SPEC
196 " algorithm: " PJSTR_PRINTF_SPEC
197 "\n",
198 auth_name, src_name,
199 PJSTR_PRINTF_VAR(param->realm),
200 realm,
201 PJSTR_PRINTF_VAR(auth_hdr->credential.common.realm),
202 auth->auth_user,
203 PJSTR_PRINTF_VAR(param->acc_name),
204 PJSTR_PRINTF_VAR(algorithm->iana_name));
205
206 if (!auth) {
207 /* This can only happen if the auth object was not saved to thread-local storage */
208 SCOPE_EXIT_RTN_VALUE(PJSIP_SC_FORBIDDEN, "%s:%s: No auth object found\n",
209 auth_name, src_name);
210 }
211
212 if (auth->type == AST_SIP_AUTH_TYPE_ARTIFICIAL) {
213 /*
214 * This shouldn't happen because this function can only be invoked
215 * if there was an Authorization header in the incoming request.
216 */
217 SCOPE_EXIT_RTN_VALUE(PJSIP_SC_FORBIDDEN, "%s:%s: Artificial auth object\n",
218 auth_name, src_name);
219 }
220
221 if (pj_strcmp2(&param->realm, realm) != 0) {
222 /*
223 * This shouldn't happen because param->realm was passed in from the auth
224 * when we called pjsip_auth_srv_init2.
225 */
226 SCOPE_EXIT_RTN_VALUE(PJSIP_SC_FORBIDDEN, "%s:%s: Realm '%s' mismatch\n",
227 auth_name, src_name, realm);
228 }
229
230 if (pj_strcmp2(&param->acc_name, auth->auth_user) != 0) {
231 SCOPE_EXIT_RTN_VALUE(PJSIP_SC_FORBIDDEN, "%s:%s: Username '%s' mismatch\n",
232 auth_name, src_name, auth->auth_user);
233 }
234
236 algorithm->algorithm_type)) {
237 /*
238 * This shouldn't happen because we shouldn't have sent a challenge for
239 * an unsupported algorithm.
240 */
241 SCOPE_EXIT_RTN_VALUE(PJSIP_SC_FORBIDDEN, "%s:%s: Algorithm '" PJSTR_PRINTF_SPEC
242 "' not supported or auth doesn't contain appropriate credentials\n",
243 auth_name, src_name, PJSTR_PRINTF_VAR(algorithm->iana_name));
244 }
245
246 pj_strdup2(pool, &cred_info->realm, realm);
247 pj_strdup2(pool, &cred_info->username, auth->auth_user);
248
249 creds = ast_sip_auth_get_creds(auth, algorithm->algorithm_type, &cred_info->data_type);
250 if (!creds) {
251 /*
252 * This shouldn't happen because we checked the auth object when we
253 * loaded it to make sure it had the appropriate credentials for each
254 * algorithm in supported_algorithms_uas.
255 */
256 SCOPE_EXIT_RTN_VALUE(PJSIP_SC_FORBIDDEN, "%s:%s: No plain text or digest password found for algorithm '" PJSTR_PRINTF_SPEC "'\n",
257 auth_name, src_name, PJSTR_PRINTF_VAR(algorithm->iana_name));
258 }
259 pj_strdup2(pool, &cred_info->data, creds);
260#ifdef HAVE_PJSIP_AUTH_NEW_DIGESTS
261 if (cred_info->data_type == PJSIP_CRED_DATA_DIGEST) {
262 cred_info->algorithm_type = algorithm->algorithm_type;
263 }
264#endif
265
266 SCOPE_EXIT_RTN_VALUE(PJ_SUCCESS, "%s:%s: Success. Data type: %s Algorithm '" PJSTR_PRINTF_SPEC "'\n",
267 auth_name, src_name, cred_info->data_type ? "digest" : "plain text", PJSTR_PRINTF_VAR(algorithm->iana_name));
268}
const pjsip_auth_algorithm * ast_sip_auth_get_algorithm_by_iana_name(const pj_str_t *iana_name)
Get algorithm by IANA name.
Definition: config_auth.c:83
@ AST_SIP_AUTH_TYPE_ARTIFICIAL
Definition: res_pjsip.h:585
const char * ast_sip_auth_get_creds(const struct ast_sip_auth *auth, const pjsip_auth_algorithm_type algorithm_type, int *cred_type)
Get the plain text or digest password from an auth object.
Definition: config_auth.c:407
int ast_sip_auth_is_algorithm_available(const struct ast_sip_auth *auth, const struct pjsip_auth_algorithm_type_vector *algorithms, pjsip_auth_algorithm_type algorithm_type)
Checks an pjsip_auth_algorithm_type_vector to see if it contains an algorithm.
Definition: config_auth.c:386
static struct pjsip_authorization_hdr * get_authorization_hdr(const char *auth_id, const char *realm, const pjsip_rx_data *rdata)
static const struct ast_sip_auth * get_auth(void)
Retrieve shallow copy authentication information from thread-local storage.
const ast_string_field auth_user
Definition: res_pjsip.h:681
enum ast_sip_auth_type type
Definition: res_pjsip.h:685

References pjsip_auth_algorithm::algorithm_type, ast_sip_auth_get_algorithm_by_iana_name(), ast_sip_auth_get_creds(), ast_sip_auth_is_algorithm_available(), AST_SIP_AUTH_TYPE_ARTIFICIAL, ast_sorcery_object_get_id(), ast_sip_auth::auth_user, default_realm, get_auth(), get_authorization_hdr(), pjsip_auth_algorithm::iana_name, PJSTR_PRINTF_SPEC, PJSTR_PRINTF_VAR, ast_sip_auth::realm, S_OR, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, ast_sip_auth::supported_algorithms_uas, and ast_sip_auth::type.

Referenced by setup_auth_srv().

◆ digest_requires_authentication()

static int digest_requires_authentication ( struct ast_sip_endpoint endpoint,
pjsip_rx_data *  rdata 
)
static

Determine if authentication is required.

Authentication is required if the endpoint has at least one auth section specified

Definition at line 53 of file res_pjsip_authenticator_digest.c.

54{
56
57 return endpoint == artificial || AST_VECTOR_SIZE(&endpoint->inbound_auths) > 0;
58}

References ao2_cleanup, ast_sip_get_artificial_endpoint(), AST_VECTOR_SIZE, ast_sip_endpoint::inbound_auths, and RAII_VAR.

◆ find_authorization()

static enum digest_verify_result find_authorization ( const char *  endpoint_id,
const struct ast_sip_auth auth,
const pjsip_rx_data *  rdata 
)
static

Definition at line 370 of file res_pjsip_authenticator_digest.c.

372{
373 const char *auth_id = ast_sorcery_object_get_id(auth);
374 const char *src_name = rdata->pkt_info.src_name;
375 const char *realm = S_OR(auth->realm, default_realm);
376 struct pjsip_authorization_hdr *auth_hdr =
377 (pjsip_authorization_hdr *) &rdata->msg_info.msg->hdr;
379 int authorization_found = 0;
380 char nonce[64];
381 SCOPE_ENTER(3, "%s:%s:%s: realm: %s\n",
382 endpoint_id, auth_id, src_name, realm);
383
384 while ((auth_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg,
385 PJSIP_H_AUTHORIZATION, auth_hdr ? auth_hdr->next : NULL))) {
386 ast_copy_pj_str(nonce, &auth_hdr->credential.digest.nonce, sizeof(nonce));
387 ast_trace(-1, "%s:%s:%s: Checking nonce %s hdr-realm: " PJSTR_PRINTF_SPEC " hdr-algo: " PJSTR_PRINTF_SPEC " \n",
388 endpoint_id, auth_id, src_name, nonce,
389 PJSTR_PRINTF_VAR(auth_hdr->credential.digest.realm),
390 PJSTR_PRINTF_VAR(auth_hdr->credential.digest.algorithm));
391 authorization_found++;
392 if (check_nonce(nonce, rdata, auth)
393 && pj_strcmp2(&auth_hdr->credential.digest.realm, realm) == 0) {
394 res = AUTH_SUCCESS;
395 break;
396 } else {
397 res = AUTH_STALE;
398 }
399 }
400 if (!authorization_found) {
401 ast_trace(-1, "%s:%s:%s: No Authorization header found\n",
402 endpoint_id, auth_id, src_name);
403 res = AUTH_NOAUTH;
404 }
405
406 SCOPE_EXIT_RTN_VALUE(res, "%s:%s:%s: realm: %s Result %s\n",
407 endpoint_id, auth_id, src_name, realm, verify_result_str[res]);
408}
void ast_copy_pj_str(char *dest, const pj_str_t *src, size_t size)
Copy a pj_str_t into a standard character buffer.
Definition: res_pjsip.c:2201
static int check_nonce(const char *candidate, const pjsip_rx_data *rdata, const struct ast_sip_auth *auth)
Ensure that a nonce on an incoming request is sane.

References ast_copy_pj_str(), ast_sorcery_object_get_id(), ast_trace, AUTH_NOAUTH, AUTH_STALE, AUTH_SUCCESS, check_nonce(), default_realm, NULL, PJSTR_PRINTF_SPEC, PJSTR_PRINTF_VAR, ast_sip_auth::realm, S_OR, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, and verify_result_str.

Referenced by verify().

◆ get_auth()

static const struct ast_sip_auth * get_auth ( void  )
static

Retrieve shallow copy authentication information from thread-local storage.

Definition at line 131 of file res_pjsip_authenticator_digest.c.

132{
133 struct ast_sip_auth **auth;
134
135 auth = ast_threadstorage_get(&auth_store, sizeof(auth));
136 if (auth) {
137 return *auth;
138 }
139 return NULL;
140}
static struct ast_threadstorage auth_store
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.

References ast_threadstorage_get(), auth_store, and NULL.

Referenced by digest_lookup().

◆ get_authorization_hdr()

static struct pjsip_authorization_hdr * get_authorization_hdr ( const char *  auth_id,
const char *  realm,
const pjsip_rx_data *  rdata 
)
static

Definition at line 142 of file res_pjsip_authenticator_digest.c.

144{
145 const char *src_name = rdata->pkt_info.src_name;
146 struct pjsip_authorization_hdr *auth_hdr =
147 (pjsip_authorization_hdr *) &rdata->msg_info.msg->hdr;
148 SCOPE_ENTER(3, "%s:%s: realm: %s\n", auth_id, src_name, realm);
149
150 while ((auth_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg,
151 PJSIP_H_AUTHORIZATION, auth_hdr ? auth_hdr->next : NULL))) {
152 if (pj_strcmp2(&auth_hdr->credential.common.realm, realm) == 0) {
153 SCOPE_EXIT_RTN_VALUE(auth_hdr, "%s:%s: realm: %s Found header\n",
154 auth_id, src_name, realm);
155 }
156 }
157 SCOPE_EXIT_RTN_VALUE(NULL, "%s:%s: realm: %s No auth header found\n",
158 auth_id, src_name, realm);
159}

References NULL, SCOPE_ENTER, and SCOPE_EXIT_RTN_VALUE.

Referenced by digest_lookup().

◆ global_loaded()

static void global_loaded ( const char *  object_type)
static

Definition at line 790 of file res_pjsip_authenticator_digest.c.

791{
793}
void ast_sip_get_default_realm(char *realm, size_t size)
Retrieve the global default realm.

References ast_sip_get_default_realm(), and default_realm.

◆ load_module()

static int load_module ( void  )
static

Definition at line 808 of file res_pjsip_authenticator_digest.c.

809{
810 if (build_entity_id()) {
812 }
813
816
818 ao2_global_obj_release(entity_id);
820 }
822}
#define ao2_global_obj_release(holder)
Release the ao2 object held in the global holder.
Definition: astobj2.h:859
@ 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
int ast_sip_register_authenticator(struct ast_sip_authenticator *auth)
Register a SIP authenticator.
Definition: res_pjsip.c:140
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
static struct ast_sorcery_observer global_observer
Observer which is used to update our default_realm when the global setting changes.
static int build_entity_id(void)
static struct ast_sip_authenticator digest_authenticator
int ast_sorcery_observer_add(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Add an observer to a specific object type.
Definition: sorcery.c:2391
void ast_sorcery_reload_object(const struct ast_sorcery *sorcery, const char *type)
Inform any wizards of a specific object type to reload persistent objects.
Definition: sorcery.c:1442

References ao2_global_obj_release, AST_MODULE_LOAD_DECLINE, AST_MODULE_LOAD_SUCCESS, ast_sip_get_sorcery(), ast_sip_register_authenticator(), ast_sorcery_observer_add(), ast_sorcery_reload_object(), build_entity_id(), digest_authenticator, and global_observer.

◆ reload_module()

static int reload_module ( void  )
static

Definition at line 800 of file res_pjsip_authenticator_digest.c.

801{
802 if (build_entity_id()) {
803 return -1;
804 }
805 return 0;
806}

References build_entity_id().

◆ remove_auth()

static int remove_auth ( void  )
static

Remove shallow copy authentication information from thread-local storage.

Definition at line 115 of file res_pjsip_authenticator_digest.c.

116{
117 struct ast_sip_auth **pointing;
118
119 pointing = ast_threadstorage_get(&auth_store, sizeof(pointing));
120 if (!pointing) {
121 return -1;
122 }
123
124 *pointing = NULL;
125 return 0;
126}

References ast_threadstorage_get(), auth_store, and NULL.

Referenced by verify().

◆ setup_auth_srv()

static void setup_auth_srv ( pj_pool_t *  pool,
pjsip_auth_srv *  auth_server,
const char *  realm 
)
static

Common code for initializing a pjsip_auth_srv.

Definition at line 413 of file res_pjsip_authenticator_digest.c.

414{
415 pjsip_auth_srv_init_param *param = pj_pool_alloc(pool, sizeof(*param));
416 pj_str_t *pj_realm = pj_pool_alloc(pool, sizeof(*pj_realm));
417
418 pj_cstr(pj_realm, realm);
419 param->realm = pj_realm;
420 param->lookup2 = digest_lookup;
421 param->options = 0;
422
423 pjsip_auth_srv_init2(pool, auth_server, param);
424}
static pj_status_t digest_lookup(pj_pool_t *pool, const pjsip_auth_lookup_cred_param *param, pjsip_cred_info *cred_info)
Lookup callback for authentication verification.

References digest_lookup().

Referenced by challenge(), and verify().

◆ store_auth()

static int store_auth ( const struct ast_sip_auth auth)
static

Store shallow copy authentication information in thread-local storage.

Definition at line 99 of file res_pjsip_authenticator_digest.c.

100{
101 const struct ast_sip_auth **pointing;
102
103 pointing = ast_threadstorage_get(&auth_store, sizeof(pointing));
104 if (!pointing) {
105 return -1;
106 }
107
108 *pointing = auth;
109 return 0;
110}

References ast_threadstorage_get(), and auth_store.

Referenced by verify().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 824 of file res_pjsip_authenticator_digest.c.

825{
828 ao2_global_obj_release(entity_id);
829 return 0;
830}
void ast_sip_unregister_authenticator(struct ast_sip_authenticator *auth)
Unregister a SIP authenticator.
Definition: res_pjsip.c:152
void ast_sorcery_observer_remove(const struct ast_sorcery *sorcery, const char *type, const struct ast_sorcery_observer *callbacks)
Remove an observer from a specific object type.
Definition: sorcery.c:2423

References ao2_global_obj_release, ast_sip_get_sorcery(), ast_sip_unregister_authenticator(), ast_sorcery_observer_remove(), digest_authenticator, and global_observer.

◆ verify()

static int verify ( const char *  endpoint_id,
const struct ast_sip_auth auth,
pjsip_rx_data *  rdata,
pj_pool_t *  pool 
)
static

Verify incoming credentials.

Parameters
endpoint_idFor logging
authThe ast_sip_auth to check against
rdataThe incoming request
poolA pool to use for the auth server
Returns
One of digest_verify_result

Definition at line 435 of file res_pjsip_authenticator_digest.c.

437{
438 const char *auth_id = ast_sorcery_object_get_id(auth);
439 const char *realm = S_OR(auth->realm, default_realm);
440 const char *src_name = rdata->pkt_info.src_name;
441 pj_status_t authed;
442 int response_code;
443 pjsip_auth_srv auth_server;
444 int stale = 0;
446 SCOPE_ENTER(3, "%s:%s:%s: realm: %s\n",
447 endpoint_id, auth_id, src_name, realm);
448
449 res = find_authorization(endpoint_id, auth, rdata);
450 if (res == AUTH_NOAUTH)
451 {
452 ast_test_suite_event_notify("INCOMING_AUTH_VERIFY_RESULT",
453 "Realm: %s\r\n"
454 "Username: %s\r\n"
455 "Status: %s",
456 realm, auth->auth_user, verify_result_str[res]);
457 SCOPE_EXIT_RTN_VALUE(res, "%s:%s:%s: No Authorization header found\n",
458 endpoint_id, auth_id, src_name);
459 }
460
461 if (res == AUTH_STALE) {
462 /* Couldn't find an authorization with a sane nonce.
463 * Nonce mismatch may just be due to staleness.
464 */
465 stale = 1;
466 }
467
468 setup_auth_srv(pool, &auth_server, realm);
469 store_auth(auth);
470 /* pjsip_auth_srv_verify will invoke digest_lookup */
471 authed = SCOPE_CALL_WITH_RESULT(-1, pj_status_t, pjsip_auth_srv_verify, &auth_server, rdata, &response_code);
472 remove_auth();
473 if (authed == PJ_SUCCESS) {
474 if (stale) {
475 res = AUTH_STALE;
476 } else {
477 res = AUTH_SUCCESS;
478 }
479 } else {
480 char err[256];
481 res = AUTH_FAIL;
482 pj_strerror(authed, err, sizeof(err));
483 ast_trace(-1, "%s:%s:%s: authed: %s\n", endpoint_id, auth_id, src_name, err);
484 }
485
486 ast_test_suite_event_notify("INCOMING_AUTH_VERIFY_RESULT",
487 "Realm: %s\r\n"
488 "Username: %s\r\n"
489 "Status: %s",
490 realm, auth->auth_user, verify_result_str[res]);
491
492 SCOPE_EXIT_RTN_VALUE(res, "%s:%s:%s: Realm: %s Username: %s Result: %s\n",
493 endpoint_id, auth_id, src_name, realm,
494 auth->auth_user, verify_result_str[res]);
495}
static enum digest_verify_result find_authorization(const char *endpoint_id, const struct ast_sip_auth *auth, const pjsip_rx_data *rdata)
static int store_auth(const struct ast_sip_auth *auth)
Store shallow copy authentication information in thread-local storage.
static int remove_auth(void)
Remove shallow copy authentication information from thread-local storage.
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189

References ast_sorcery_object_get_id(), ast_test_suite_event_notify, ast_trace, AUTH_FAIL, AUTH_NOAUTH, AUTH_STALE, AUTH_SUCCESS, ast_sip_auth::auth_user, default_realm, find_authorization(), ast_sip_auth::realm, remove_auth(), S_OR, SCOPE_CALL_WITH_RESULT, SCOPE_ENTER, SCOPE_EXIT_RTN_VALUE, setup_auth_srv(), store_auth(), and verify_result_str.

Referenced by digest_check_auth().

Variable Documentation

◆ __mod_info

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .description = "PJSIP authentication resource" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .support_level = AST_MODULE_SUPPORT_CORE, .load = load_module, .unload = unload_module, .reload = reload_module, .load_pri = AST_MODPRI_CHANNEL_DEPEND - 5, .requires = "res_pjsip", }
static

Definition at line 839 of file res_pjsip_authenticator_digest.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 839 of file res_pjsip_authenticator_digest.c.

◆ auth_store

struct ast_threadstorage auth_store = { .once = PTHREAD_ONCE_INIT , .key_init = __init_auth_store , .custom_init = NULL , }
static

Definition at line 94 of file res_pjsip_authenticator_digest.c.

Referenced by get_auth(), remove_auth(), and store_auth().

◆ check_auth_result_str

char* check_auth_result_str[]
static

Definition at line 546 of file res_pjsip_authenticator_digest.c.

Referenced by digest_check_auth().

◆ default_realm

char default_realm[AST_SIP_AUTH_MAX_REALM_LENGTH+1]
static

◆ digest_authenticator

struct ast_sip_authenticator digest_authenticator
static
Initial value:
= {
.requires_authentication = digest_requires_authentication,
.check_authentication = digest_check_auth,
}
static enum ast_sip_check_auth_result digest_check_auth(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata, pjsip_tx_data *tdata)
Check authentication using Digest scheme.
static int digest_requires_authentication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
Determine if authentication is required.

Definition at line 770 of file res_pjsip_authenticator_digest.c.

Referenced by load_module(), and unload_module().

◆ global_observer

struct ast_sorcery_observer global_observer
static
Initial value:
= {
.loaded = global_loaded,
}
static void global_loaded(const char *object_type)

Observer which is used to update our default_realm when the global setting changes.

Definition at line 796 of file res_pjsip_authenticator_digest.c.

Referenced by load_module(), and unload_module().

◆ verify_result_str

char* verify_result_str[]
static

Definition at line 363 of file res_pjsip_authenticator_digest.c.

Referenced by digest_check_auth(), find_authorization(), and verify().