Asterisk - The Open Source Telephony Project GIT-master-0a46be9
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 377 of file res_pjsip_authenticator_digest.c.

377 {
378 /*! Authentication credentials incorrect */
379 AUTH_FAIL = 0,
380 /*! Authentication credentials correct */
382 /*! Authentication credentials correct but nonce mismatch */
384 /*! Authentication credentials were not provided */
386};

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 864 of file res_pjsip_authenticator_digest.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

Definition at line 864 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 864 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 800 of file res_pjsip_authenticator_digest.c.

801{
802 char *eid;
803
805 if (!eid) {
806 return -1;
807 }
808
810 ao2_global_obj_replace_unref(entity_id, eid);
811 ao2_ref(eid, -1);
812 return 0;
813}
#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 312 of file res_pjsip_authenticator_digest.c.

314{
315 struct ast_str *str = ast_str_alloca(256);
316 RAII_VAR(char *, eid, ao2_global_obj_ref(entity_id), ao2_cleanup);
317 char hash[33];
318
319 /*
320 * Note you may be tempted to think why not include the port. The reason
321 * is that when using TCP the port can potentially differ from before.
322 */
323 ast_str_append(&str, 0, "%s", timestamp);
324 ast_str_append(&str, 0, ":%s", rdata->pkt_info.src_name);
325 ast_str_append(&str, 0, ":%s", eid);
326 ast_str_append(&str, 0, ":%s", realm);
328
329 ast_str_append(nonce, 0, "%s/%s", timestamp, hash);
330 return 0;
331}
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:978
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 532 of file res_pjsip_authenticator_digest.c.

535{
536 pj_str_t qop;
537 pj_str_t pj_nonce;
538 pjsip_auth_srv auth_server;
539 struct ast_str *nonce = ast_str_alloca(256);
540 char time_buf[32];
541 time_t timestamp = time(NULL);
542 pj_status_t res;
543 const char *realm = S_OR(auth->realm, default_realm);
544 const char *auth_id = ast_sorcery_object_get_id(auth);
545 const char *src_name = rdata->pkt_info.src_name;
546 SCOPE_ENTER(5, "%s:%s:%s: realm: %s time: %d algorithm: " PJSTR_PRINTF_SPEC " stale? %s\n",
547 endpoint_id, auth_id, src_name, realm, (int)timestamp,
548 PJSTR_PRINTF_VAR(algorithm->iana_name), is_stale ? "yes" : "no");
549
550 snprintf(time_buf, sizeof(time_buf), "%d", (int) timestamp);
551
552 build_nonce(&nonce, time_buf, rdata, realm);
553
554 setup_auth_srv(tdata->pool, &auth_server, realm);
555
556 pj_cstr(&pj_nonce, ast_str_buffer(nonce));
557 pj_cstr(&qop, "auth");
558#ifdef HAVE_PJSIP_AUTH_NEW_DIGESTS
559 res = pjsip_auth_srv_challenge2(&auth_server, &qop, &pj_nonce,
560 NULL, is_stale ? PJ_TRUE : PJ_FALSE, tdata, algorithm->algorithm_type);
561#else
562 res = pjsip_auth_srv_challenge(&auth_server, &qop, &pj_nonce,
563 NULL, is_stale ? PJ_TRUE : PJ_FALSE, tdata);
564#endif
565 SCOPE_EXIT_RTN("%s:%s:%s: Sending challenge for realm: %s algorithm: " PJSTR_PRINTF_SPEC
566 " %s\n",
567 endpoint_id, auth_id, src_name, realm, PJSTR_PRINTF_VAR(algorithm->iana_name),
568 res == PJ_SUCCESS ? "succeeded" : "failed");
569}
#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:2380
#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 345 of file res_pjsip_authenticator_digest.c.

346{
347 char *copy = ast_strdupa(candidate);
348 char *timestamp = strsep(&copy, "/");
349 int timestamp_int;
350 time_t now = time(NULL);
351 struct ast_str *calculated = ast_str_alloca(64);
352
353 if (!copy) {
354 /* Clearly a bad nonce! */
355 return 0;
356 }
357
358 if (sscanf(timestamp, "%30d", &timestamp_int) != 1) {
359 return 0;
360 }
361
362 if ((int) now - timestamp_int > auth->nonce_lifetime) {
363 return 0;
364 }
365
366 build_nonce(&calculated, timestamp, rdata, S_OR(auth->realm, default_realm));
367 ast_debug(3, "Calculated nonce %s. Actual nonce is %s\n", ast_str_buffer(calculated), candidate);
368 if (strcmp(ast_str_buffer(calculated), candidate)) {
369 return 0;
370 }
371 return 1;
372}
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 608 of file res_pjsip_authenticator_digest.c.

610{
611 struct ast_sip_auth **auths;
612 enum digest_verify_result *verify_res;
615 int idx;
616 int is_artificial;
617 int failures = 0;
618 size_t auth_size;
619 const char *endpoint_id = ast_sorcery_object_get_id(endpoint);
620 char *src_name = rdata->pkt_info.src_name;
621 SCOPE_ENTER(3, "%s:%s\n", endpoint_id, src_name);
622
623 auth_size = AST_VECTOR_SIZE(&endpoint->inbound_auths);
624 ast_assert(0 < auth_size);
625
626 auths = ast_alloca(auth_size * sizeof(*auths));
627 verify_res = ast_alloca(auth_size * sizeof(*verify_res));
628
630 if (!artificial_endpoint) {
631 /* Should not happen except possibly if we are shutting down. */
633 }
634
635 is_artificial = endpoint == artificial_endpoint;
637 if (is_artificial) {
638 ast_trace(3, "%s:%s: Using artificial endpoint for authentication\n",
639 endpoint_id, src_name);
640 ast_assert(auth_size == 1);
641 auths[0] = ast_sip_get_artificial_auth();
642 if (!auths[0]) {
643 /* Should not happen except possibly if we are shutting down. */
645 }
646 } else {
647 ast_trace(3, "%s:%s: Using endpoint for authentication\n",
648 endpoint_id, src_name);
649 memset(auths, 0, auth_size * sizeof(*auths));
650 /*
651 * If ast_sip_retrieve_auths returns a failure we still need
652 * to cleanup the auths array because it may have been partially
653 * filled in.
654 */
655 if (ast_sip_retrieve_auths(&endpoint->inbound_auths, auths)) {
656 ast_sip_cleanup_auths(auths, auth_size);
658 "%s:%s: Failed to retrieve some or all auth objects from endpoint\n",
659 endpoint_id, src_name);
660 }
661 }
662
663 /*
664 * Verify any Authorization headers in the incoming request against the
665 * auth objects on the endpoint. If there aren't any Authorization headers
666 * verify() will return AUTH_NOAUTH.
667 *
668 * NOTE: The only reason to use multiple auth objects as a UAS might
669 * be to send challenges for multiple realms however we currently don't
670 * know of anyone actually doing this.
671 */
672 for (idx = 0; idx < auth_size; ++idx) {
673 struct ast_sip_auth *auth = auths[idx];
674 const char *auth_id = ast_sorcery_object_get_id(auth);
675 SCOPE_ENTER(4, "%s:%s:%s: Auth %d of %d: Verifying\n",
676 endpoint_id, auth_id, src_name, idx + 1, (int)auth_size);
677
678 verify_res[idx] = SCOPE_CALL_WITH_RESULT(-1, int, verify, endpoint_id, auth, rdata, tdata->pool);
679 switch((int)verify_res[idx]) {
680 case AUTH_SUCCESS:
682 break;
683 case AUTH_FAIL:
684 failures++;
685 break;
686 case AUTH_NOAUTH:
687 case AUTH_STALE:
688 break;
689 }
690
691 SCOPE_EXIT("%s:%s:%s: Auth %d of %d: Result: %s Failure count: %d\n",
692 endpoint_id, auth_id, src_name, idx + 1, (int)auth_size,
693 verify_result_str[verify_res[idx]], failures);
694
695 /*
696 * If there was a success or there was no Authorization header in the
697 * incoming request, we can stop verifying the rest of the auth objects.
698 */
699 if (verify_res[idx] == AUTH_SUCCESS || verify_res[idx] == AUTH_NOAUTH) {
700 break;
701 }
702 }
703
705 ast_sip_cleanup_auths(auths, auth_size);
706 SCOPE_EXIT_RTN_VALUE(res, "%s:%s: Result: %s\n",
707 endpoint_id, src_name,
709 }
710 ast_trace(-1, "%s:%s: Done with verification. Failures: %d of %d\n",
711 endpoint_id, src_name, failures, (int)auth_size);
712
713 /*
714 * If none of the Authorization headers in the incoming request were
715 * successfully verified, or there were no Authorization headers in the
716 * request, we need to send challenges for each auth object
717 * on the endpoint.
718 */
719 for (idx = 0; idx < auth_size; ++idx) {
720 int i = 0;
721 struct ast_sip_auth *auth = auths[idx];
722 const char *realm = S_OR(auth->realm, default_realm);
723 const char *auth_id = ast_sorcery_object_get_id(auth);
724 SCOPE_ENTER(4, "%s:%s:%s: Auth %d of %d: Sending challenges\n",
725 endpoint_id, auth_id, src_name, idx + 1, (int)auth_size);
726
727 for (i = 0; i < AST_VECTOR_SIZE(&auth->supported_algorithms_uas); i++) {
729 const pjsip_auth_algorithm *algorithm = ast_sip_auth_get_algorithm_by_type(algorithm_type);
730 pjsip_www_authenticate_hdr *auth_hdr = NULL;
731 int already_sent_challenge = 0;
732 SCOPE_ENTER(5, "%s:%s:%s: Auth %d of %d: Challenging with " PJSTR_PRINTF_SPEC "\n",
733 endpoint_id, auth_id, src_name, idx + 1, (int)auth_size,
734 PJSTR_PRINTF_VAR(algorithm->iana_name));
735
736 /*
737 * Per RFC 7616, if we've already sent a challenge for this realm
738 * and algorithm, we must not send another.
739 */
740 while ((auth_hdr = pjsip_msg_find_hdr(tdata->msg,
741 PJSIP_H_WWW_AUTHENTICATE, auth_hdr ? auth_hdr->next : NULL))) {
742 if (pj_strcmp2(&auth_hdr->challenge.common.realm, realm) == 0 &&
743 !pj_stricmp(&auth_hdr->challenge.digest.algorithm, &algorithm->iana_name)) {
744 ast_trace(-1, "%s:%s:%s: Auth %d of %d: Not sending duplicate challenge for realm: %s algorithm: "
746 endpoint_id, auth_id, src_name, idx + 1, (int)auth_size,
747 realm, PJSTR_PRINTF_VAR(algorithm->iana_name));
748 already_sent_challenge = 1;
749 }
750 }
751 if (already_sent_challenge) {
752 SCOPE_EXIT_EXPR(continue);
753 }
754
755 SCOPE_CALL(5, challenge, endpoint_id, auth, tdata, rdata,
756 verify_res[idx] == AUTH_STALE, algorithm);
758
759 SCOPE_EXIT("%s:%s:%s: Auth %d of %d: Challenged with " PJSTR_PRINTF_SPEC "\n",
760 endpoint_id, auth_id, src_name, idx + 1, (int)auth_size,
761 PJSTR_PRINTF_VAR(algorithm->iana_name));
762 }
763 SCOPE_EXIT("%s:%s:%s: Auth %d of %d: Done with challenges\n",
764 endpoint_id, auth_id, src_name, idx + 1, (int)auth_size);
765 }
766
767 /*
768 * If we've sent challenges for multiple auth objects, we currently
769 * return SUCCESS when the first one succeeds. We may want to change
770 * this in the future to require that all succeed but as stated above,
771 * currently we don't have a use case for even using more than one
772 * auth object as a UAS.
773 */
774
775 /*
776 * If the authentication failed for any reason, we want to send
777 * a 401 with a challenge. If it was because there was no
778 * Authorization header or there was a stale nonce, fine. That's not
779 * unusual so we return AST_SIP_AUTHENTICATION_CHALLENGE. If it
780 * failed because of a user/password mismatch then we return
781 * AST_SIP_AUTHENTICATION_FAILED which causes the distributor to
782 * print a "Failed to authenticate" message.
783 */
784 if (failures == auth_size) {
786 }
787
788 ast_sip_cleanup_auths(auths, auth_size);
789 SCOPE_EXIT_RTN_VALUE(res, "%s:%s: Result: %s\n",
790 endpoint_id, src_name,
792
793}
#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:776
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:620
#define AST_VECTOR_GET(vec, idx)
Get an element from a vector.
Definition: vector.h:691

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 = auth_hdr ?
188 ast_sip_auth_get_algorithm_by_iana_name(&auth_hdr->credential.digest.algorithm) : NULL;
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 " auth user: %s"
194 " hdr user: " PJSTR_PRINTF_SPEC
195 "\n",
196 auth_name, src_name,
197 PJSTR_PRINTF_VAR(param->realm),
198 realm,
199 auth->auth_user,
200 PJSTR_PRINTF_VAR(param->acc_name));
201
202 /*
203 * If a client is responding correctly, most of the error conditions below
204 * can't happen because we sent them the correct info in the 401 response.
205 * However, if a client is trying to authenticate with us without
206 * having received a challenge or if they are trying to
207 * authenticate with a different realm or algorithm than we sent them,
208 * we need to catch that.
209 */
210
211 if (!auth) {
212 /* This can only happen if the auth object was not saved to thread-local storage */
213 SCOPE_EXIT_RTN_VALUE(PJSIP_SC_FORBIDDEN, "%s:%s: No auth object found\n",
214 auth_name, src_name);
215 }
216
217 if (auth_hdr == NULL) {
218 /*
219 * This can only happen if the incoming request did not have an
220 * Authorization header or the realm in the header was missing or incorrect.
221 */
222 SCOPE_EXIT_RTN_VALUE(PJSIP_SC_FORBIDDEN,
223 "%s:%s: No Authorization header found for realm '%s'\n",
224 auth_name, src_name, realm);
225 }
226
227 if (algorithm == NULL) {
228 /*
229 * This can only happen if the incoming request had an algorithm
230 * we don't support.
231 */
232 SCOPE_EXIT_RTN_VALUE(PJSIP_SC_FORBIDDEN,
233 "%s:%s: Unsupported algorithm '" PJSTR_PRINTF_SPEC "'\n",
234 auth_name, src_name, PJSTR_PRINTF_VAR(auth_hdr->credential.digest.algorithm));
235 }
236
237 if (auth->type == AST_SIP_AUTH_TYPE_ARTIFICIAL) {
238 /*
239 * This shouldn't happen because this function can only be invoked
240 * if there was an Authorization header in the incoming request.
241 */
242 SCOPE_EXIT_RTN_VALUE(PJSIP_SC_FORBIDDEN, "%s:%s: Artificial auth object\n",
243 auth_name, src_name);
244 }
245
246 if (pj_strcmp2(&param->realm, realm) != 0) {
247 /*
248 * This shouldn't happen because param->realm was passed in from the auth
249 * when we called pjsip_auth_srv_init2.
250 */
251 SCOPE_EXIT_RTN_VALUE(PJSIP_SC_FORBIDDEN, "%s:%s: Realm '%s' mismatch\n",
252 auth_name, src_name, realm);
253 }
254
255 if (pj_strcmp2(&param->acc_name, auth->auth_user) != 0) {
256 SCOPE_EXIT_RTN_VALUE(PJSIP_SC_FORBIDDEN, "%s:%s: Username '%s' mismatch\n",
257 auth_name, src_name, auth->auth_user);
258 }
259
261 algorithm->algorithm_type)) {
262 /*
263 * This shouldn't happen because we shouldn't have sent a challenge for
264 * an unsupported algorithm.
265 */
266 SCOPE_EXIT_RTN_VALUE(PJSIP_SC_FORBIDDEN, "%s:%s: Algorithm '" PJSTR_PRINTF_SPEC
267 "' not supported or auth doesn't contain appropriate credentials\n",
268 auth_name, src_name, PJSTR_PRINTF_VAR(algorithm->iana_name));
269 }
270
271 pj_strdup2(pool, &cred_info->realm, realm);
272 pj_strdup2(pool, &cred_info->username, auth->auth_user);
273
274 creds = ast_sip_auth_get_creds(auth, algorithm->algorithm_type, &cred_info->data_type);
275 if (!creds) {
276 /*
277 * This shouldn't happen because we checked the auth object when we
278 * loaded it to make sure it had the appropriate credentials for each
279 * algorithm in supported_algorithms_uas.
280 */
281 SCOPE_EXIT_RTN_VALUE(PJSIP_SC_FORBIDDEN, "%s:%s: No plain text or digest password found for algorithm '" PJSTR_PRINTF_SPEC "'\n",
282 auth_name, src_name, PJSTR_PRINTF_VAR(algorithm->iana_name));
283 }
284 pj_strdup2(pool, &cred_info->data, creds);
285#ifdef HAVE_PJSIP_AUTH_NEW_DIGESTS
286 if (cred_info->data_type == PJSIP_CRED_DATA_DIGEST) {
287 cred_info->algorithm_type = algorithm->algorithm_type;
288 }
289#endif
290
291 SCOPE_EXIT_RTN_VALUE(PJ_SUCCESS, "%s:%s: Success. Data type: %s Algorithm '" PJSTR_PRINTF_SPEC "'\n",
292 auth_name, src_name, cred_info->data_type ? "digest" : "plain text", PJSTR_PRINTF_VAR(algorithm->iana_name));
293}
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, NULL, 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 395 of file res_pjsip_authenticator_digest.c.

397{
398 const char *auth_id = ast_sorcery_object_get_id(auth);
399 const char *src_name = rdata->pkt_info.src_name;
400 const char *realm = S_OR(auth->realm, default_realm);
401 struct pjsip_authorization_hdr *auth_hdr =
402 (pjsip_authorization_hdr *) &rdata->msg_info.msg->hdr;
404 int authorization_found = 0;
405 char nonce[64];
406 SCOPE_ENTER(3, "%s:%s:%s: realm: %s\n",
407 endpoint_id, auth_id, src_name, realm);
408
409 while ((auth_hdr = pjsip_msg_find_hdr(rdata->msg_info.msg,
410 PJSIP_H_AUTHORIZATION, auth_hdr ? auth_hdr->next : NULL))) {
411 ast_copy_pj_str(nonce, &auth_hdr->credential.digest.nonce, sizeof(nonce));
412 ast_trace(-1, "%s:%s:%s: Checking nonce %s hdr-realm: " PJSTR_PRINTF_SPEC " hdr-algo: " PJSTR_PRINTF_SPEC " \n",
413 endpoint_id, auth_id, src_name, nonce,
414 PJSTR_PRINTF_VAR(auth_hdr->credential.digest.realm),
415 PJSTR_PRINTF_VAR(auth_hdr->credential.digest.algorithm));
416 authorization_found++;
417 if (check_nonce(nonce, rdata, auth)
418 && pj_strcmp2(&auth_hdr->credential.digest.realm, realm) == 0) {
419 res = AUTH_SUCCESS;
420 break;
421 } else {
422 res = AUTH_STALE;
423 }
424 }
425 if (!authorization_found) {
426 ast_trace(-1, "%s:%s:%s: No Authorization header found\n",
427 endpoint_id, auth_id, src_name);
428 res = AUTH_NOAUTH;
429 }
430
431 SCOPE_EXIT_RTN_VALUE(res, "%s:%s:%s: realm: %s Result %s\n",
432 endpoint_id, auth_id, src_name, realm, verify_result_str[res]);
433}
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 815 of file res_pjsip_authenticator_digest.c.

816{
818}
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 833 of file res_pjsip_authenticator_digest.c.

834{
835 if (build_entity_id()) {
837 }
838
841
843 ao2_global_obj_release(entity_id);
845 }
847}
#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:2454
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:1505

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 825 of file res_pjsip_authenticator_digest.c.

826{
827 if (build_entity_id()) {
828 return -1;
829 }
830 return 0;
831}

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 438 of file res_pjsip_authenticator_digest.c.

439{
440 pjsip_auth_srv_init_param *param = pj_pool_alloc(pool, sizeof(*param));
441 pj_str_t *pj_realm = pj_pool_alloc(pool, sizeof(*pj_realm));
442
443 pj_cstr(pj_realm, realm);
444 param->realm = pj_realm;
445 param->lookup2 = digest_lookup;
446 param->options = 0;
447
448 pjsip_auth_srv_init2(pool, auth_server, param);
449}
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 849 of file res_pjsip_authenticator_digest.c.

850{
853 ao2_global_obj_release(entity_id);
854 return 0;
855}
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:2486

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 460 of file res_pjsip_authenticator_digest.c.

462{
463 const char *auth_id = ast_sorcery_object_get_id(auth);
464 const char *realm = S_OR(auth->realm, default_realm);
465 const char *src_name = rdata->pkt_info.src_name;
466 pj_status_t authed;
467 int response_code;
468 pjsip_auth_srv auth_server;
469 int stale = 0;
471 SCOPE_ENTER(3, "%s:%s:%s: realm: %s\n",
472 endpoint_id, auth_id, src_name, realm);
473
474 res = find_authorization(endpoint_id, auth, rdata);
475 if (res == AUTH_NOAUTH)
476 {
477 ast_test_suite_event_notify("INCOMING_AUTH_VERIFY_RESULT",
478 "Realm: %s\r\n"
479 "Username: %s\r\n"
480 "Status: %s",
481 realm, auth->auth_user, verify_result_str[res]);
482 SCOPE_EXIT_RTN_VALUE(res, "%s:%s:%s: No Authorization header found\n",
483 endpoint_id, auth_id, src_name);
484 }
485
486 if (res == AUTH_STALE) {
487 /* Couldn't find an authorization with a sane nonce.
488 * Nonce mismatch may just be due to staleness.
489 */
490 stale = 1;
491 }
492
493 setup_auth_srv(pool, &auth_server, realm);
494 store_auth(auth);
495 /* pjsip_auth_srv_verify will invoke digest_lookup */
496 authed = SCOPE_CALL_WITH_RESULT(-1, pj_status_t, pjsip_auth_srv_verify, &auth_server, rdata, &response_code);
497 remove_auth();
498 if (authed == PJ_SUCCESS) {
499 if (stale) {
500 res = AUTH_STALE;
501 } else {
502 res = AUTH_SUCCESS;
503 }
504 } else {
505 char err[256];
506 res = AUTH_FAIL;
507 pj_strerror(authed, err, sizeof(err));
508 ast_trace(-1, "%s:%s:%s: authed: %s\n", endpoint_id, auth_id, src_name, err);
509 }
510
511 ast_test_suite_event_notify("INCOMING_AUTH_VERIFY_RESULT",
512 "Realm: %s\r\n"
513 "Username: %s\r\n"
514 "Status: %s",
515 realm, auth->auth_user, verify_result_str[res]);
516
517 SCOPE_EXIT_RTN_VALUE(res, "%s:%s:%s: Realm: %s Username: %s Result: %s\n",
518 endpoint_id, auth_id, src_name, realm,
519 auth->auth_user, verify_result_str[res]);
520}
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 864 of file res_pjsip_authenticator_digest.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

Definition at line 864 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 571 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 795 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 821 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 388 of file res_pjsip_authenticator_digest.c.

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