Asterisk - The Open Source Telephony Project GIT-master-1f1c5bb
Enumerations | Functions | Variables
res_pjsip_authenticator_digest.c File Reference
#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 *realm, pjsip_tx_data *tdata, const pjsip_rx_data *rdata, int is_stale)
 astobj2 callback for adding digest challenges to responses 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 pj_str_t *realm, const pj_str_t *acc_name, pjsip_cred_info *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 int find_challenge (const pjsip_rx_data *rdata, const struct ast_sip_auth *auth)
 
static const struct ast_sip_authget_auth (void)
 Retrieve shallow copy authentication information from thread-local storage. More...
 
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 struct ast_sip_auth *auth, pjsip_rx_data *rdata, pj_pool_t *pool)
 astobj2 callback for verifying 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 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 []
 

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

297 {
298 /*! Authentication credentials incorrect */
299 AUTH_FAIL = 0,
300 /*! Authentication credentials correct */
302 /*! Authentication credentials correct but nonce mismatch */
304 /*! Authentication credentials were not provided */
306};

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

92{

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 572 of file res_pjsip_authenticator_digest.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

◆ auth_store_cleanup()

static void auth_store_cleanup ( void *  data)
static

Definition at line 52 of file res_pjsip_authenticator_digest.c.

53{
54 struct ast_sip_auth **auth = data;
55
56 ao2_cleanup(*auth);
57 ast_free(data);
58}
#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 508 of file res_pjsip_authenticator_digest.c.

509{
510 char *eid;
511
513 if (!eid) {
514 return -1;
515 }
516
518 ao2_global_obj_replace_unref(entity_id, eid);
519 ao2_ref(eid, -1);
520 return 0;
521}
#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 205 of file res_pjsip_authenticator_digest.c.

206{
207 struct ast_str *str = ast_str_alloca(256);
208 RAII_VAR(char *, eid, ao2_global_obj_ref(entity_id), ao2_cleanup);
209 char hash[33];
210
211 /*
212 * Note you may be tempted to think why not include the port. The reason
213 * is that when using TCP the port can potentially differ from before.
214 */
215 ast_str_append(&str, 0, "%s", timestamp);
216 ast_str_append(&str, 0, ":%s", rdata->pkt_info.src_name);
217 ast_str_append(&str, 0, ":%s", eid);
218 ast_str_append(&str, 0, ":%s", realm);
220
221 ast_str_append(nonce, 0, "%s/%s", timestamp, hash);
222 return 0;
223}
const char * str
Definition: app_jack.c:147
#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 *  realm,
pjsip_tx_data *  tdata,
const pjsip_rx_data *  rdata,
int  is_stale 
)
static

astobj2 callback for adding digest challenges to responses

Parameters
realmAn auth's realm to build a challenge from
tdataThe response to add the challenge to
rdataThe request the challenge is in response to
is_staleIndicates whether nonce on incoming request was stale

Definition at line 376 of file res_pjsip_authenticator_digest.c.

377{
378 pj_str_t qop;
379 pj_str_t pj_nonce;
380 pjsip_auth_srv auth_server;
381 struct ast_str *nonce = ast_str_alloca(256);
382 char time_buf[32];
383 time_t timestamp = time(NULL);
384 snprintf(time_buf, sizeof(time_buf), "%d", (int) timestamp);
385
386 build_nonce(&nonce, time_buf, rdata, realm);
387
388 setup_auth_srv(tdata->pool, &auth_server, realm);
389
390 pj_cstr(&pj_nonce, ast_str_buffer(nonce));
391 pj_cstr(&qop, "auth");
392 pjsip_auth_srv_challenge(&auth_server, &qop, &pj_nonce, NULL, is_stale ? PJ_TRUE : PJ_FALSE, tdata);
393}
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 int build_nonce(struct ast_str **nonce, const char *timestamp, const pjsip_rx_data *rdata, const char *realm)
Calculate a nonce.

References ast_str_alloca, ast_str_buffer(), build_nonce(), NULL, 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_outbound_authentication_credentials().

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

238{
239 char *copy = ast_strdupa(candidate);
240 char *timestamp = strsep(&copy, "/");
241 int timestamp_int;
242 time_t now = time(NULL);
243 struct ast_str *calculated = ast_str_alloca(64);
244
245 if (!copy) {
246 /* Clearly a bad nonce! */
247 return 0;
248 }
249
250 if (sscanf(timestamp, "%30d", &timestamp_int) != 1) {
251 return 0;
252 }
253
254 if ((int) now - timestamp_int > auth->nonce_lifetime) {
255 return 0;
256 }
257
258 build_nonce(&calculated, timestamp, rdata, auth->realm);
259 ast_debug(3, "Calculated nonce %s. Actual nonce is %s\n", ast_str_buffer(calculated), candidate);
260 if (strcmp(ast_str_buffer(calculated), candidate)) {
261 return 0;
262 }
263 return 1;
264}
static int copy(char *infile, char *outfile)
Utility function to copy a file.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
char * strsep(char **str, const char *delims)
#define ast_debug(level,...)
Log a DEBUG message.
const ast_string_field realm
Definition: res_pjsip.h:597
unsigned int nonce_lifetime
Definition: res_pjsip.h:599

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

Referenced by find_challenge().

◆ 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.

See also
ast_sip_check_authentication

Definition at line 404 of file res_pjsip_authenticator_digest.c.

406{
407 struct ast_sip_auth **auths;
408 struct ast_sip_auth **auths_shallow;
409 enum digest_verify_result *verify_res;
412 int idx;
413 int is_artificial;
414 int failures = 0;
415 size_t auth_size;
416
417 auth_size = AST_VECTOR_SIZE(&endpoint->inbound_auths);
418 ast_assert(0 < auth_size);
419
420 auths = ast_alloca(auth_size * sizeof(*auths));
421 verify_res = ast_alloca(auth_size * sizeof(*verify_res));
422
424 if (!artificial_endpoint) {
425 /* Should not happen except possibly if we are shutting down. */
427 }
428
429 is_artificial = endpoint == artificial_endpoint;
431 if (is_artificial) {
432 ast_assert(auth_size == 1);
433 auths[0] = ast_sip_get_artificial_auth();
434 if (!auths[0]) {
435 /* Should not happen except possibly if we are shutting down. */
437 }
438 } else {
439 memset(auths, 0, auth_size * sizeof(*auths));
440 if (ast_sip_retrieve_auths(&endpoint->inbound_auths, auths)) {
442 goto cleanup;
443 }
444 }
445
446 /* Setup shallow copy of auths */
448 auths_shallow = auths;
449 } else {
450 /*
451 * Set default realm on a shallow copy of the authentication
452 * objects that don't have a realm set.
453 */
454 auths_shallow = ast_alloca(auth_size * sizeof(*auths_shallow));
455 for (idx = 0; idx < auth_size; ++idx) {
456 if (ast_strlen_zero(auths[idx]->realm)) {
457 /*
458 * Make a shallow copy and set the default realm on it.
459 *
460 * The stack allocation is OK here. Normally this will
461 * loop one time. If you have multiple auths then you
462 * shouldn't need more auths than the normal complement
463 * of fingers and toes. Otherwise, you should check
464 * your sanity for setting up your system up that way.
465 */
466 auths_shallow[idx] = ast_alloca(sizeof(**auths_shallow));
467 memcpy(auths_shallow[idx], auths[idx], sizeof(**auths_shallow));
468 *((char **) (&auths_shallow[idx]->realm)) = default_realm;
469 ast_debug(3, "Using default realm '%s' on incoming auth '%s'.\n",
470 default_realm, ast_sorcery_object_get_id(auths_shallow[idx]));
471 } else {
472 auths_shallow[idx] = auths[idx];
473 }
474 }
475 }
476
477 for (idx = 0; idx < auth_size; ++idx) {
478 verify_res[idx] = verify(auths_shallow[idx], rdata, tdata->pool);
479 if (verify_res[idx] == AUTH_SUCCESS) {
481 goto cleanup;
482 }
483 if (verify_res[idx] == AUTH_FAIL) {
484 failures++;
485 }
486 }
487
488 for (idx = 0; idx < auth_size; ++idx) {
489 challenge(auths_shallow[idx]->realm, tdata, rdata, verify_res[idx] == AUTH_STALE);
490 }
491
492 if (failures == auth_size) {
494 } else {
496 }
497
498cleanup:
499 ast_sip_cleanup_auths(auths, auth_size);
500 return res;
501}
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:288
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
static struct ast_sip_endpoint * artificial_endpoint
struct ast_sip_auth * ast_sip_get_artificial_auth(void)
Retrieves a reference to the artificial auth.
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:1229
@ AST_SIP_AUTHENTICATION_CHALLENGE
Definition: res_pjsip.h:1231
@ AST_SIP_AUTHENTICATION_ERROR
Definition: res_pjsip.h:1237
@ AST_SIP_AUTHENTICATION_SUCCESS
Definition: res_pjsip.h:1233
@ AST_SIP_AUTHENTICATION_FAILED
Definition: res_pjsip.h:1235
digest_verify_result
Result of digest verification.
static char default_realm[AST_SIP_AUTH_MAX_REALM_LENGTH+1]
static int verify(const struct ast_sip_auth *auth, pjsip_rx_data *rdata, pj_pool_t *pool)
astobj2 callback for verifying incoming credentials
static void challenge(const char *realm, pjsip_tx_data *tdata, const pjsip_rx_data *rdata, int is_stale)
astobj2 callback for adding digest challenges to responses
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2317
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:65
An entity with which Asterisk communicates.
Definition: res_pjsip.h:963
struct ast_sip_auth_vector inbound_auths
Definition: res_pjsip.h:1008
#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

References ao2_ref, artificial_endpoint, ast_alloca, ast_assert, ast_debug, 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_strlen_zero(), AST_VECTOR_SIZE, AUTH_FAIL, AUTH_STALE, AUTH_SUCCESS, challenge(), cleanup(), default_realm, ast_sip_endpoint::inbound_auths, and verify().

◆ digest_lookup()

static pj_status_t digest_lookup ( pj_pool_t *  pool,
const pj_str_t *  realm,
const pj_str_t *  acc_name,
pjsip_cred_info *  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 is correct. We are then supposed to supply a password or MD5 sum of credentials.

Parameters
poolA memory pool we can use for allocations
realmThe realm from the Authorization header
acc_namethe user from the Authorization header
[out]infoThe credentials we need to fill in
Return values
PJ_SUCCESSSuccessful authentication
otherUnsuccessful

Definition at line 149 of file res_pjsip_authenticator_digest.c.

151{
152 const struct ast_sip_auth *auth;
153
154 auth = get_auth();
155 if (!auth) {
156 return PJSIP_SC_FORBIDDEN;
157 }
158
159 if (auth->type == AST_SIP_AUTH_TYPE_ARTIFICIAL) {
160 return PJSIP_SC_FORBIDDEN;
161 }
162
163 if (pj_strcmp2(realm, auth->realm)) {
164 return PJSIP_SC_FORBIDDEN;
165 }
166 if (pj_strcmp2(acc_name, auth->auth_user)) {
167 return PJSIP_SC_FORBIDDEN;
168 }
169
170 pj_strdup2(pool, &info->realm, auth->realm);
171 pj_strdup2(pool, &info->username, auth->auth_user);
172
173 switch (auth->type) {
175 pj_strdup2(pool, &info->data, auth->auth_pass);
176 info->data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
177 break;
179 pj_strdup2(pool, &info->data, auth->md5_creds);
180 info->data_type = PJSIP_CRED_DATA_DIGEST;
181 break;
182 default:
183 return PJSIP_SC_FORBIDDEN;
184 }
185 return PJ_SUCCESS;
186}
def info(msg)
@ AST_SIP_AUTH_TYPE_ARTIFICIAL
Definition: res_pjsip.h:574
@ AST_SIP_AUTH_TYPE_MD5
Definition: res_pjsip.h:570
@ AST_SIP_AUTH_TYPE_USER_PASS
Definition: res_pjsip.h:568
static const struct ast_sip_auth * get_auth(void)
Retrieve shallow copy authentication information from thread-local storage.
const ast_string_field md5_creds
Definition: res_pjsip.h:597
const ast_string_field auth_user
Definition: res_pjsip.h:597
const ast_string_field auth_pass
Definition: res_pjsip.h:597
enum ast_sip_auth_type type
Definition: res_pjsip.h:601

References AST_SIP_AUTH_TYPE_ARTIFICIAL, AST_SIP_AUTH_TYPE_MD5, AST_SIP_AUTH_TYPE_USER_PASS, ast_sip_auth::auth_pass, ast_sip_auth::auth_user, get_auth(), sip_to_pjsip::info(), ast_sip_auth::md5_creds, ast_sip_auth::realm, 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 45 of file res_pjsip_authenticator_digest.c.

46{
48
49 return endpoint == artificial || AST_VECTOR_SIZE(&endpoint->inbound_auths) > 0;
50}

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

◆ find_challenge()

static int find_challenge ( const pjsip_rx_data *  rdata,
const struct ast_sip_auth auth 
)
static

Definition at line 266 of file res_pjsip_authenticator_digest.c.

267{
268 struct pjsip_authorization_hdr *auth_hdr = (pjsip_authorization_hdr *) &rdata->msg_info.msg->hdr;
269 int challenge_found = 0;
270 char nonce[64];
271
272 while ((auth_hdr = (pjsip_authorization_hdr *) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_AUTHORIZATION, auth_hdr->next))) {
273 ast_copy_pj_str(nonce, &auth_hdr->credential.digest.nonce, sizeof(nonce));
274 if (check_nonce(nonce, rdata, auth) && !pj_strcmp2(&auth_hdr->credential.digest.realm, auth->realm)) {
275 challenge_found = 1;
276 break;
277 }
278 }
279
280 return challenge_found;
281}
while(1)
Definition: ast_expr2f.c:880
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(), check_nonce(), ast_sip_auth::realm, and while().

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

124{
125 struct ast_sip_auth **auth;
126
127 auth = ast_threadstorage_get(&auth_store, sizeof(auth));
128 if (auth) {
129 return *auth;
130 }
131 return NULL;
132}
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().

◆ global_loaded()

static void global_loaded ( const char *  object_type)
static

Definition at line 523 of file res_pjsip_authenticator_digest.c.

524{
526}
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 541 of file res_pjsip_authenticator_digest.c.

542{
543 if (build_entity_id()) {
545 }
546
549
551 ao2_global_obj_release(entity_id);
553 }
555}
#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 533 of file res_pjsip_authenticator_digest.c.

534{
535 if (build_entity_id()) {
536 return -1;
537 }
538 return 0;
539}

References build_entity_id().

◆ remove_auth()

static int remove_auth ( void  )
static

Remove shallow copy authentication information from thread-local storage.

Definition at line 107 of file res_pjsip_authenticator_digest.c.

108{
109 struct ast_sip_auth **pointing;
110
111 pointing = ast_threadstorage_get(&auth_store, sizeof(pointing));
112 if (!pointing) {
113 return -1;
114 }
115
116 *pointing = NULL;
117 return 0;
118}

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

287{
288 pj_str_t realm_str;
289 pj_cstr(&realm_str, realm);
290
291 pjsip_auth_srv_init(pool, auth_server, &realm_str, digest_lookup, 0);
292}
static pj_status_t digest_lookup(pj_pool_t *pool, const pj_str_t *realm, const pj_str_t *acc_name, pjsip_cred_info *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 91 of file res_pjsip_authenticator_digest.c.

92{
93 const struct ast_sip_auth **pointing;
94
95 pointing = ast_threadstorage_get(&auth_store, sizeof(pointing));
96 if (!pointing) {
97 return -1;
98 }
99
100 *pointing = auth;
101 return 0;
102}

References ast_threadstorage_get(), and auth_store.

Referenced by verify().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 557 of file res_pjsip_authenticator_digest.c.

558{
561 ao2_global_obj_release(entity_id);
562 return 0;
563}
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 struct ast_sip_auth auth,
pjsip_rx_data *  rdata,
pj_pool_t *  pool 
)
static

astobj2 callback for verifying incoming credentials

Parameters
authThe ast_sip_auth to check against
rdataThe incoming request
poolA pool to use for the auth server
Returns
CMP_MATCH on successful authentication
0 on failed authentication

Definition at line 323 of file res_pjsip_authenticator_digest.c.

324{
325 pj_status_t authed;
326 int response_code;
327 pjsip_auth_srv auth_server;
328 int stale = 0;
329 int res = AUTH_FAIL;
330
331 if (!find_challenge(rdata, auth)) {
332 /* Couldn't find a challenge with a sane nonce.
333 * Nonce mismatch may just be due to staleness.
334 */
335 stale = 1;
336 }
337
338 setup_auth_srv(pool, &auth_server, auth->realm);
339
340 store_auth(auth);
341 authed = pjsip_auth_srv_verify(&auth_server, rdata, &response_code);
342 remove_auth();
343
344 if (authed == PJ_SUCCESS) {
345 if (stale) {
346 res = AUTH_STALE;
347 } else {
348 res = AUTH_SUCCESS;
349 }
350 }
351
352 if (authed == PJSIP_EAUTHNOAUTH) {
353 res = AUTH_NOAUTH;
354 }
355
356 ast_debug(3, "Realm: %s Username: %s Result: %s\n",
357 auth->realm, auth->auth_user, verify_result_str[res]);
358
359 ast_test_suite_event_notify("INCOMING_AUTH_VERIFY_RESULT",
360 "Realm: %s\r\n"
361 "Username: %s\r\n"
362 "Status: %s",
363 auth->realm, auth->auth_user, verify_result_str[res]);
364
365 return res;
366}
static int find_challenge(const pjsip_rx_data *rdata, const struct ast_sip_auth *auth)
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.
static char * verify_result_str[]
#define ast_test_suite_event_notify(s, f,...)
Definition: test.h:189

References ast_debug, ast_test_suite_event_notify, AUTH_FAIL, AUTH_NOAUTH, AUTH_STALE, AUTH_SUCCESS, ast_sip_auth::auth_user, find_challenge(), ast_sip_auth::realm, remove_auth(), 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 572 of file res_pjsip_authenticator_digest.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

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

Referenced by get_auth(), remove_auth(), and store_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 503 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 529 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 308 of file res_pjsip_authenticator_digest.c.

Referenced by verify().