Asterisk - The Open Source Telephony Project  18.5.0
Macros | 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.

Macros

#define MAX_REALM_LENGTH   40
 

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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .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 [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 []
 

Macro Definition Documentation

◆ MAX_REALM_LENGTH

#define MAX_REALM_LENGTH   40

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

298  {
299  /*! Authentication credentials incorrect */
300  AUTH_FAIL = 0,
301  /*! Authentication credentials correct */
302  AUTH_SUCCESS,
303  /*! Authentication credentials correct but nonce mismatch */
304  AUTH_STALE,
305  /*! Authentication credentials were not provided */
306  AUTH_NOAUTH,
307 };

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

94 {

◆ __reg_module()

static void __reg_module ( void  )
static

Definition at line 573 of file res_pjsip_authenticator_digest.c.

◆ __unreg_module()

static void __unreg_module ( void  )
static

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

◆ auth_store_cleanup()

static void auth_store_cleanup ( void *  data)
static

Definition at line 54 of file res_pjsip_authenticator_digest.c.

References ao2_cleanup, and ast_free.

55 {
56  struct ast_sip_auth **auth = data;
57 
58  ao2_cleanup(*auth);
59  ast_free(data);
60 }
#define ast_free(a)
Definition: astmm.h:182
#define ao2_cleanup(obj)
Definition: astobj2.h:1958

◆ build_entity_id()

static int build_entity_id ( void  )
static

Definition at line 509 of file res_pjsip_authenticator_digest.c.

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().

510 {
511  char *eid;
512 
514  if (!eid) {
515  return -1;
516  }
517 
519  ao2_global_obj_replace_unref(entity_id, eid);
520  ao2_ref(eid, -1);
521  return 0;
522 }
#define AST_UUID_STR_LEN
Definition: uuid.h:27
#define NULL
Definition: resample.c:96
#define ao2_ref(o, delta)
Definition: astobj2.h:464
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
char * ast_uuid_generate_str(char *buf, size_t size)
Generate a UUID string.
Definition: uuid.c:143
#define ao2_global_obj_replace_unref(holder, obj)
Definition: astobj2.h:908

◆ 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
AUNIX timestamp expressed as a string
rdataThe incoming request
realmThe realm for which authentication should occur

Definition at line 206 of file res_pjsip_authenticator_digest.c.

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().

207 {
208  struct ast_str *str = ast_str_alloca(256);
209  RAII_VAR(char *, eid, ao2_global_obj_ref(entity_id), ao2_cleanup);
210  char hash[33];
211 
212  /*
213  * Note you may be tempted to think why not include the port. The reason
214  * is that when using TCP the port can potentially differ from before.
215  */
216  ast_str_append(&str, 0, "%s", timestamp);
217  ast_str_append(&str, 0, ":%s", rdata->pkt_info.src_name);
218  ast_str_append(&str, 0, ":%s", eid);
219  ast_str_append(&str, 0, ":%s", realm);
220  ast_md5_hash(hash, ast_str_buffer(str));
221 
222  ast_str_append(nonce, 0, "%s/%s", timestamp, hash);
223  return 0;
224 }
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
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:1091
#define ao2_global_obj_ref(holder)
Definition: astobj2.h:925
#define ast_str_alloca(init_len)
Definition: strings.h:800
const char * str
Definition: app_jack.c:147
#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:911
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
void ast_md5_hash(char *output, const char *input)
Produces MD5 hash based on input string.
Definition: main/utils.c:248

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

References ast_str_alloca, ast_str_buffer(), build_nonce(), NULL, and setup_auth_srv().

Referenced by authenticate_reply(), authenticate_request(), decrypt_frame(), digest_check_auth(), manager_login(), register_verify(), registry_authrequest(), registry_rerequest(), and send_request_cb().

378 {
379  pj_str_t qop;
380  pj_str_t pj_nonce;
381  pjsip_auth_srv auth_server;
382  struct ast_str *nonce = ast_str_alloca(256);
383  char time_buf[32];
384  time_t timestamp = time(NULL);
385  snprintf(time_buf, sizeof(time_buf), "%d", (int) timestamp);
386 
387  build_nonce(&nonce, time_buf, rdata, realm);
388 
389  setup_auth_srv(tdata->pool, &auth_server, realm);
390 
391  pj_cstr(&pj_nonce, ast_str_buffer(nonce));
392  pj_cstr(&qop, "auth");
393  pjsip_auth_srv_challenge(&auth_server, &qop, &pj_nonce, NULL, is_stale ? PJ_TRUE : PJ_FALSE, tdata);
394 }
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
#define ast_str_alloca(init_len)
Definition: strings.h:800
#define NULL
Definition: resample.c:96
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
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.

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

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().

239 {
240  char *copy = ast_strdupa(candidate);
241  char *timestamp = strsep(&copy, "/");
242  int timestamp_int;
243  time_t now = time(NULL);
244  struct ast_str *calculated = ast_str_alloca(64);
245 
246  if (!copy) {
247  /* Clearly a bad nonce! */
248  return 0;
249  }
250 
251  if (sscanf(timestamp, "%30d", &timestamp_int) != 1) {
252  return 0;
253  }
254 
255  if ((int) now - timestamp_int > auth->nonce_lifetime) {
256  return 0;
257  }
258 
259  build_nonce(&calculated, timestamp, rdata, auth->realm);
260  ast_debug(3, "Calculated nonce %s. Actual nonce is %s\n", ast_str_buffer(calculated), candidate);
261  if (strcmp(ast_str_buffer(calculated), candidate)) {
262  return 0;
263  }
264  return 1;
265 }
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
static int copy(char *infile, char *outfile)
Utility function to copy a file.
#define ast_str_alloca(init_len)
Definition: strings.h:800
#define NULL
Definition: resample.c:96
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
unsigned int nonce_lifetime
Definition: res_pjsip.h:462
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:300
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
const ast_string_field realm
Definition: res_pjsip.h:448
static int build_nonce(struct ast_str **nonce, const char *timestamp, const pjsip_rx_data *rdata, const char *realm)
Calculate a nonce.
char * strsep(char **str, const char *delims)

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

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().

407 {
408  struct ast_sip_auth **auths;
409  struct ast_sip_auth **auths_shallow;
410  enum digest_verify_result *verify_res;
412  enum ast_sip_check_auth_result res;
413  int idx;
414  int is_artificial;
415  int failures = 0;
416  size_t auth_size;
417 
418  auth_size = AST_VECTOR_SIZE(&endpoint->inbound_auths);
419  ast_assert(0 < auth_size);
420 
421  auths = ast_alloca(auth_size * sizeof(*auths));
422  verify_res = ast_alloca(auth_size * sizeof(*verify_res));
423 
424  artificial_endpoint = ast_sip_get_artificial_endpoint();
425  if (!artificial_endpoint) {
426  /* Should not happen except possibly if we are shutting down. */
428  }
429 
430  is_artificial = endpoint == artificial_endpoint;
431  ao2_ref(artificial_endpoint, -1);
432  if (is_artificial) {
433  ast_assert(auth_size == 1);
434  auths[0] = ast_sip_get_artificial_auth();
435  if (!auths[0]) {
436  /* Should not happen except possibly if we are shutting down. */
438  }
439  } else {
440  memset(auths, 0, auth_size * sizeof(*auths));
441  if (ast_sip_retrieve_auths(&endpoint->inbound_auths, auths)) {
443  goto cleanup;
444  }
445  }
446 
447  /* Setup shallow copy of auths */
449  auths_shallow = auths;
450  } else {
451  /*
452  * Set default realm on a shallow copy of the authentication
453  * objects that don't have a realm set.
454  */
455  auths_shallow = ast_alloca(auth_size * sizeof(*auths_shallow));
456  for (idx = 0; idx < auth_size; ++idx) {
457  if (ast_strlen_zero(auths[idx]->realm)) {
458  /*
459  * Make a shallow copy and set the default realm on it.
460  *
461  * The stack allocation is OK here. Normally this will
462  * loop one time. If you have multiple auths then you
463  * shouldn't need more auths than the normal complement
464  * of fingers and toes. Otherwise, you should check
465  * your sanity for setting up your system up that way.
466  */
467  auths_shallow[idx] = ast_alloca(sizeof(**auths_shallow));
468  memcpy(auths_shallow[idx], auths[idx], sizeof(**auths_shallow));
469  *((char **) (&auths_shallow[idx]->realm)) = default_realm;
470  ast_debug(3, "Using default realm '%s' on incoming auth '%s'.\n",
471  default_realm, ast_sorcery_object_get_id(auths_shallow[idx]));
472  } else {
473  auths_shallow[idx] = auths[idx];
474  }
475  }
476  }
477 
478  for (idx = 0; idx < auth_size; ++idx) {
479  verify_res[idx] = verify(auths_shallow[idx], rdata, tdata->pool);
480  if (verify_res[idx] == AUTH_SUCCESS) {
482  goto cleanup;
483  }
484  if (verify_res[idx] == AUTH_FAIL) {
485  failures++;
486  }
487  }
488 
489  for (idx = 0; idx < auth_size; ++idx) {
490  challenge(auths_shallow[idx]->realm, tdata, rdata, verify_res[idx] == AUTH_STALE);
491  }
492 
493  if (failures == auth_size) {
495  } else {
497  }
498 
499 cleanup:
500  ast_sip_cleanup_auths(auths, auth_size);
501  return res;
502 }
static int verify(const struct ast_sip_auth *auth, pjsip_rx_data *rdata, pj_pool_t *pool)
astobj2 callback for verifying incoming credentials
static char default_realm[MAX_REALM_LENGTH+1]
ast_sip_check_auth_result
Possible returns from ast_sip_check_authentication.
Definition: res_pjsip.h:932
#define ast_assert(a)
Definition: utils.h:695
#define ast_strlen_zero(foo)
Definition: strings.h:52
digest_verify_result
Result of digest verification.
int ast_sip_retrieve_auths(const struct ast_sip_auth_vector *auths, struct ast_sip_auth **out)
Retrieve relevant SIP auth structures from sorcery.
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:452
static struct ast_sip_endpoint * artificial_endpoint
#define ao2_ref(o, delta)
Definition: astobj2.h:464
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
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
An entity with which Asterisk communicates.
Definition: res_pjsip.h:812
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
Definition: astmm.h:290
struct ast_sip_auth * ast_sip_get_artificial_auth(void)
Retrieves a reference to the artificial auth.
struct ast_sip_auth_vector inbound_auths
Definition: res_pjsip.h:853
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.
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

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

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(), ast_sip_auth::md5_creds, ast_sip_auth::realm, and ast_sip_auth::type.

Referenced by setup_auth_srv().

153 {
154  const struct ast_sip_auth *auth;
155 
156  auth = get_auth();
157  if (!auth) {
158  return PJSIP_SC_FORBIDDEN;
159  }
160 
161  if (auth->type == AST_SIP_AUTH_TYPE_ARTIFICIAL) {
162  return PJSIP_SC_FORBIDDEN;
163  }
164 
165  if (pj_strcmp2(realm, auth->realm)) {
166  return PJSIP_SC_FORBIDDEN;
167  }
168  if (pj_strcmp2(acc_name, auth->auth_user)) {
169  return PJSIP_SC_FORBIDDEN;
170  }
171 
172  pj_strdup2(pool, &info->realm, auth->realm);
173  pj_strdup2(pool, &info->username, auth->auth_user);
174 
175  switch (auth->type) {
177  pj_strdup2(pool, &info->data, auth->auth_pass);
178  info->data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
179  break;
181  pj_strdup2(pool, &info->data, auth->md5_creds);
182  info->data_type = PJSIP_CRED_DATA_DIGEST;
183  break;
184  default:
185  return PJSIP_SC_FORBIDDEN;
186  }
187  return PJ_SUCCESS;
188 }
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:454
static pj_pool_t * pool
Global memory pool for configuration and timers.
const ast_string_field realm
Definition: res_pjsip.h:448
def info(msg)
const ast_string_field auth_pass
Definition: res_pjsip.h:452
enum ast_sip_auth_type type
Definition: res_pjsip.h:464
const ast_string_field auth_user
Definition: res_pjsip.h:450

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

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

48 {
50 
51  return endpoint == artificial || AST_VECTOR_SIZE(&endpoint->inbound_auths) > 0;
52 }
#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:911
An entity with which Asterisk communicates.
Definition: res_pjsip.h:812
struct ast_sip_auth_vector inbound_auths
Definition: res_pjsip.h:853
struct ast_sip_endpoint * ast_sip_get_artificial_endpoint(void)
Retrieves a reference to the artificial endpoint.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611

◆ find_challenge()

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

Definition at line 267 of file res_pjsip_authenticator_digest.c.

References ast_copy_pj_str(), check_nonce(), ast_sip_auth::realm, and while().

Referenced by verify().

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

◆ get_auth()

static const struct ast_sip_auth* get_auth ( void  )
static

Retrieve shallow copy authentication information from thread-local storage.

Definition at line 125 of file res_pjsip_authenticator_digest.c.

References ast_threadstorage_get(), auth_store, and NULL.

Referenced by digest_lookup().

126 {
127  struct ast_sip_auth **auth;
128 
129  auth = ast_threadstorage_get(&auth_store, sizeof(auth));
130  if (auth) {
131  return *auth;
132  }
133  return NULL;
134 }
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
#define NULL
Definition: resample.c:96
static struct ast_threadstorage auth_store

◆ global_loaded()

static void global_loaded ( const char *  object_type)
static

Definition at line 524 of file res_pjsip_authenticator_digest.c.

References ast_sip_get_default_realm(), and default_realm.

525 {
527 }
static char default_realm[MAX_REALM_LENGTH+1]
void ast_sip_get_default_realm(char *realm, size_t size)
Retrieve the global default realm.

◆ load_module()

static int load_module ( void  )
static

Definition at line 542 of file res_pjsip_authenticator_digest.c.

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(), and build_entity_id().

Referenced by unload_module().

543 {
544  if (build_entity_id()) {
546  }
547 
550 
552  ao2_global_obj_release(entity_id);
554  }
556 }
int ast_sip_register_authenticator(struct ast_sip_authenticator *auth)
Register a SIP authenticator.
Definition: res_pjsip.c:3338
static int build_entity_id(void)
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:2386
#define ao2_global_obj_release(holder)
Definition: astobj2.h:865
static struct ast_sorcery_observer global_observer
Observer which is used to update our default_realm when the global setting changes.
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
static struct ast_sip_authenticator digest_authenticator
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

◆ reload_module()

static int reload_module ( void  )
static

Definition at line 534 of file res_pjsip_authenticator_digest.c.

References build_entity_id().

Referenced by unload_module().

535 {
536  if (build_entity_id()) {
537  return -1;
538  }
539  return 0;
540 }
static int build_entity_id(void)

◆ remove_auth()

static int remove_auth ( void  )
static

Remove shallow copy authentication information from thread-local storage.

Definition at line 109 of file res_pjsip_authenticator_digest.c.

References ast_threadstorage_get(), auth_store, and NULL.

Referenced by verify().

110 {
111  struct ast_sip_auth **pointing;
112 
113  pointing = ast_threadstorage_get(&auth_store, sizeof(pointing));
114  if (!pointing) {
115  return -1;
116  }
117 
118  *pointing = NULL;
119  return 0;
120 }
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
#define NULL
Definition: resample.c:96
static struct ast_threadstorage auth_store

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

References digest_lookup().

Referenced by challenge(), and verify().

288 {
289  pj_str_t realm_str;
290  pj_cstr(&realm_str, realm);
291 
292  pjsip_auth_srv_init(pool, auth_server, &realm_str, digest_lookup, 0);
293 }
static pj_pool_t * pool
Global memory pool for configuration and timers.
const ast_string_field realm
Definition: res_pjsip.h:448
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.

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

References ast_threadstorage_get(), and auth_store.

Referenced by verify().

94 {
95  const struct ast_sip_auth **pointing;
96 
97  pointing = ast_threadstorage_get(&auth_store, sizeof(pointing));
98  if (!pointing) {
99  return -1;
100  }
101 
102  *pointing = auth;
103  return 0;
104 }
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
static struct ast_threadstorage auth_store

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 558 of file res_pjsip_authenticator_digest.c.

References ao2_global_obj_release, AST_MODFLAG_LOAD_ORDER, AST_MODPRI_CHANNEL_DEPEND, AST_MODULE_INFO(), AST_MODULE_SUPPORT_CORE, ast_sip_get_sorcery(), ast_sip_unregister_authenticator(), ast_sorcery_observer_remove(), ASTERISK_GPL_KEY, load_module(), reload(), and reload_module().

559 {
562  ao2_global_obj_release(entity_id);
563  return 0;
564 }
void ast_sip_unregister_authenticator(struct ast_sip_authenticator *auth)
Unregister a SIP authenticator.
Definition: res_pjsip.c:3350
#define ao2_global_obj_release(holder)
Definition: astobj2.h:865
static struct ast_sorcery_observer global_observer
Observer which is used to update our default_realm when the global setting changes.
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:2418
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
static struct ast_sip_authenticator digest_authenticator

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

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().

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

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 = "30ef0c93b36035ec78c9cfd712d36d9b" , .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 573 of file res_pjsip_authenticator_digest.c.

◆ ast_module_info

const struct ast_module_info* ast_module_info = &__mod_info
static

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

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

◆ default_realm

char default_realm[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 int digest_requires_authentication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
Determine if authentication is required.
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.

Definition at line 504 of file res_pjsip_authenticator_digest.c.

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

◆ verify_result_str

char* verify_result_str[]
static

Definition at line 309 of file res_pjsip_authenticator_digest.c.

Referenced by verify().