Asterisk - The Open Source Telephony Project  18.5.0
res_pjsip_authenticator_digest.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2013, Digium, Inc.
5  *
6  * Mark Michelson <[email protected]>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 #include "asterisk.h"
20 
21 #include <pjsip.h>
22 
23 #include "asterisk/res_pjsip.h"
24 #include "asterisk/logger.h"
25 #include "asterisk/module.h"
26 #include "asterisk/strings.h"
27 #include "asterisk/test.h"
28 
29 /*** MODULEINFO
30  <depend>pjproject</depend>
31  <depend>res_pjsip</depend>
32  <support_level>core</support_level>
33  ***/
34 
35 /* From the auth/realm realtime column size */
36 #define MAX_REALM_LENGTH 40
38 
39 AO2_GLOBAL_OBJ_STATIC(entity_id);
40 
41 /*!
42  * \brief Determine if authentication is required
43  *
44  * Authentication is required if the endpoint has at least one auth
45  * section specified
46  */
47 static int digest_requires_authentication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
48 {
50 
51  return endpoint == artificial || AST_VECTOR_SIZE(&endpoint->inbound_auths) > 0;
52 }
53 
54 static void auth_store_cleanup(void *data)
55 {
56  struct ast_sip_auth **auth = data;
57 
58  ao2_cleanup(*auth);
59  ast_free(data);
60 }
61 
62 /*!
63  * \brief Thread-local storage for \ref ast_sip_auth
64  *
65  * The PJSIP authentication API is a bit annoying. When you set
66  * up an authentication server, you specify a lookup callback to
67  * call into when verifying incoming credentials. The problem
68  * with this callback is that it only gives you the realm and
69  * authentication username. In 2.0.5, there is a new version of
70  * the callback you can use that gives the pjsip_rx_data in
71  * addition.
72  *
73  * Unfortunately, the data we actually \b need is the
74  * \ref ast_sip_auth we are currently observing. So we have two
75  * choices:
76  * 1) Use the current PJSIP API and use thread-local storage
77  * to temporarily store our SIP authentication information. Then
78  * in the callback, we can retrieve the authentication info and
79  * use as needed. Given our threading model, this is safe.
80  * 2) Use the 2.0.5 API and temporarily store the authentication
81  * information in the rdata's endpoint_info. Then in the callback,
82  * we can retrieve the authentication info from the rdata.
83  *
84  * I've chosen option 1 since it does not require backporting
85  * any APIs from future versions of PJSIP, plus I feel the
86  * thread-local option is a bit cleaner.
87  */
89 
90 /*!
91  * \brief Store shallow copy authentication information in thread-local storage
92  */
93 static int store_auth(const struct ast_sip_auth *auth)
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 }
105 
106 /*!
107  * \brief Remove shallow copy authentication information from thread-local storage
108  */
109 static int remove_auth(void)
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 }
121 
122 /*!
123  * \brief Retrieve shallow copy authentication information from thread-local storage
124  */
125 static const struct ast_sip_auth *get_auth(void)
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 }
135 
136 /*!
137  * \brief Lookup callback for authentication verification
138  *
139  * This function is called when we call pjsip_auth_srv_verify(). It
140  * expects us to verify that the realm and account name from the
141  * Authorization header is correct. We are then supposed to supply
142  * a password or MD5 sum of credentials.
143  *
144  * \param pool A memory pool we can use for allocations
145  * \param realm The realm from the Authorization header
146  * \param acc_name the user from the Authorization header
147  * \param[out] info The credentials we need to fill in
148  * \retval PJ_SUCCESS Successful authentication
149  * \retval other Unsuccessful
150  */
151 static pj_status_t digest_lookup(pj_pool_t *pool, const pj_str_t *realm,
152  const pj_str_t *acc_name, pjsip_cred_info *info)
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 }
189 
190 /*!
191  * \brief Calculate a nonce
192  *
193  * We use this in order to create authentication challenges. We also use this in order
194  * to verify that an incoming request with credentials could be in response to one
195  * of our challenges.
196  *
197  * The nonce is calculated from a timestamp, the source IP address, the source port, a
198  * unique ID for us, and the realm. This helps to ensure that the incoming request
199  * is from the same source that the nonce was calculated for. Including the realm
200  * ensures that multiple challenges to the same request have different nonces.
201  *
202  * \param A UNIX timestamp expressed as a string
203  * \param rdata The incoming request
204  * \param realm The realm for which authentication should occur
205  */
206 static int build_nonce(struct ast_str **nonce, const char *timestamp, const pjsip_rx_data *rdata, const char *realm)
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 }
225 
226 /*!
227  * \brief Ensure that a nonce on an incoming request is sane.
228  *
229  * The nonce in an incoming Authorization header needs to pass some scrutiny in order
230  * for us to consider accepting it. What we do is re-build a nonce based on request
231  * data and a realm and see if it matches the nonce they sent us.
232  * \param candidate The nonce on an incoming request
233  * \param rdata The incoming request
234  * \param auth The auth credentials we are trying to match against.
235  * \retval 0 Nonce does not pass validity checks
236  * \retval 1 Nonce passes validity check
237  */
238 static int check_nonce(const char *candidate, const pjsip_rx_data *rdata, const struct ast_sip_auth *auth)
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 }
266 
267 static int find_challenge(const pjsip_rx_data *rdata, const struct ast_sip_auth *auth)
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 }
283 
284 /*!
285  * \brief Common code for initializing a pjsip_auth_srv
286  */
287 static void setup_auth_srv(pj_pool_t *pool, pjsip_auth_srv *auth_server, const char *realm)
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 }
294 
295 /*!
296  * \brief Result of digest verification
297  */
299  /*! Authentication credentials incorrect */
301  /*! Authentication credentials correct */
303  /*! Authentication credentials correct but nonce mismatch */
305  /*! Authentication credentials were not provided */
307 };
308 
309 static char *verify_result_str[] = {
310  "FAIL",
311  "SUCCESS",
312  "STALE",
313  "NOAUTH"
314 };
315 /*!
316  * \brief astobj2 callback for verifying incoming credentials
317  *
318  * \param auth The ast_sip_auth to check against
319  * \param rdata The incoming request
320  * \param pool A pool to use for the auth server
321  * \return CMP_MATCH on successful authentication
322  * \return 0 on failed authentication
323  */
324 static int verify(const struct ast_sip_auth *auth, pjsip_rx_data *rdata, pj_pool_t *pool)
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 }
368 
369 /*!
370  * \brief astobj2 callback for adding digest challenges to responses
371  *
372  * \param realm An auth's realm to build a challenge from
373  * \param tdata The response to add the challenge to
374  * \param rdata The request the challenge is in response to
375  * \param is_stale Indicates whether nonce on incoming request was stale
376  */
377 static void challenge(const char *realm, pjsip_tx_data *tdata, const pjsip_rx_data *rdata, int is_stale)
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 }
395 
396 /*!
397  * \brief Check authentication using Digest scheme
398  *
399  * This function will check an incoming message against configured authentication
400  * options. If \b any of the incoming Authorization headers result in successful
401  * authentication, then authentication is considered successful.
402  *
403  * \see ast_sip_check_authentication
404  */
406  pjsip_rx_data *rdata, pjsip_tx_data *tdata)
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 }
503 
506  .check_authentication = digest_check_auth,
507 };
508 
509 static int build_entity_id(void)
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 }
523 
524 static void global_loaded(const char *object_type)
525 {
527 }
528 
529 /*! \brief Observer which is used to update our default_realm when the global setting changes */
532 };
533 
534 static int reload_module(void)
535 {
536  if (build_entity_id()) {
537  return -1;
538  }
539  return 0;
540 }
541 
542 static int load_module(void)
543 {
544  if (build_entity_id()) {
546  }
547 
548  ast_sorcery_observer_add(ast_sip_get_sorcery(), "global", &global_observer);
550 
551  if (ast_sip_register_authenticator(&digest_authenticator)) {
552  ao2_global_obj_release(entity_id);
554  }
556 }
557 
558 static int unload_module(void)
559 {
560  ast_sorcery_observer_remove(ast_sip_get_sorcery(), "global", &global_observer);
561  ast_sip_unregister_authenticator(&digest_authenticator);
562  ao2_global_obj_release(entity_id);
563  return 0;
564 }
565 
566 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "PJSIP authentication resource",
567  .support_level = AST_MODULE_SUPPORT_CORE,
568  .load = load_module,
569  .unload = unload_module,
571  .load_pri = AST_MODPRI_CHANNEL_DEPEND - 5,
572  .requires = "res_pjsip",
573 );
Asterisk main include file. File version handling, generic pbx functions.
static const struct ast_sip_auth * get_auth(void)
Retrieve shallow copy authentication information from thread-local storage.
static int unload_module(void)
int ast_sip_register_authenticator(struct ast_sip_authenticator *auth)
Register a SIP authenticator.
Definition: res_pjsip.c:3338
void * ast_threadstorage_get(struct ast_threadstorage *ts, size_t init_size)
Retrieve thread storage.
String manipulation functions.
static int verify(const struct ast_sip_auth *auth, pjsip_rx_data *rdata, pj_pool_t *pool)
astobj2 callback for verifying incoming credentials
#define AST_UUID_STR_LEN
Definition: uuid.h:27
static char default_realm[MAX_REALM_LENGTH+1]
AO2_GLOBAL_OBJ_STATIC(entity_id)
const ast_string_field md5_creds
Definition: res_pjsip.h:454
ast_sip_check_auth_result
Possible returns from ast_sip_check_authentication.
Definition: res_pjsip.h:932
static int build_entity_id(void)
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:714
static pj_pool_t * pool
Global memory pool for configuration and timers.
Test Framework API.
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.
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
static int copy(char *infile, char *outfile)
Utility function to copy a file.
#define ast_assert(a)
Definition: utils.h:695
#define ast_str_alloca(init_len)
Definition: strings.h:800
void ast_sip_get_default_realm(char *realm, size_t size)
Retrieve the global default realm.
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
const char * str
Definition: app_jack.c:147
#define NULL
Definition: resample.c:96
static int digest_requires_authentication(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
Determine if authentication is required.
#define MAX_REALM_LENGTH
#define ast_strlen_zero(foo)
Definition: strings.h:52
digest_verify_result
Result of digest verification.
static int reload_module(void)
void ast_sip_unregister_authenticator(struct ast_sip_authenticator *auth)
Unregister a SIP authenticator.
Definition: res_pjsip.c:3350
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
#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
static struct ast_sip_endpoint * artificial_endpoint
while(1)
Definition: ast_expr2f.c:894
#define ao2_ref(o, delta)
Definition: astobj2.h:464
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
const char * ast_sorcery_object_get_id(const void *object)
Get the unique identifier of a sorcery object.
Definition: sorcery.c:2312
int(* requires_authentication)(struct ast_sip_endpoint *endpoint, pjsip_rx_data *rdata)
Check if a request requires authentication See ast_sip_requires_authentication for more details...
Definition: res_pjsip.h:955
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
static int store_auth(const struct ast_sip_auth *auth)
Store shallow copy authentication information in thread-local storage.
An entity with which Asterisk communicates.
Definition: res_pjsip.h:812
static int load_module(void)
static void global_loaded(const char *object_type)
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 ast_test_suite_event_notify(s, f,...)
Definition: test.h:196
#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.
static void auth_store_cleanup(void *data)
struct ast_sip_auth_vector inbound_auths
Definition: res_pjsip.h:853
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:584
static char * verify_result_str[]
const ast_string_field realm
Definition: res_pjsip.h:448
static struct ast_threadstorage auth_store
Interface for a sorcery object type observer.
Definition: sorcery.h:332
#define ao2_global_obj_release(holder)
Definition: astobj2.h:865
def info(msg)
struct ast_sip_endpoint * ast_sip_get_artificial_endpoint(void)
Retrieves a reference to the artificial endpoint.
#define ao2_alloc(data_size, destructor_fn)
Definition: astobj2.h:411
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.
void ast_sip_cleanup_auths(struct ast_sip_auth *auths[], size_t num_auths)
Clean up retrieved auth structures from memory.
#define ast_free(a)
Definition: astmm.h:182
static struct ast_sorcery_observer global_observer
Observer which is used to update our default_realm when the global setting changes.
static int reload(void)
Definition: cdr_mysql.c:741
static int remove_auth(void)
Remove shallow copy authentication information from thread-local storage.
char * ast_uuid_generate_str(char *buf, size_t size)
Generate a UUID string.
Definition: uuid.c:143
const ast_string_field auth_pass
Definition: res_pjsip.h:452
enum ast_sip_auth_type type
Definition: res_pjsip.h:464
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
static void * cleanup(void *unused)
Definition: pbx_realtime.c:124
void(* loaded)(const char *object_type)
Callback for when an object type is loaded/reloaded.
Definition: sorcery.h:343
Support for logging to various files, console and syslog Configuration in file logger.conf.
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS|AST_MODFLAG_LOAD_ORDER, "HTTP Phone Provisioning",.support_level=AST_MODULE_SUPPORT_EXTENDED,.load=load_module,.unload=unload_module,.reload=reload,.load_pri=AST_MODPRI_CHANNEL_DEPEND,.requires="http",)
#define AST_THREADSTORAGE_CUSTOM(a, b, c)
Define a thread storage variable, with custom initialization and cleanup.
static int build_nonce(struct ast_str **nonce, const char *timestamp, const pjsip_rx_data *rdata, const char *realm)
Calculate a nonce.
#define ao2_global_obj_replace_unref(holder, obj)
Definition: astobj2.h:908
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
char * strsep(char **str, const char *delims)
An interchangeable way of handling digest authentication for SIP.
Definition: res_pjsip.h:950
struct ast_sorcery * ast_sip_get_sorcery(void)
Get a pointer to the SIP sorcery structure.
#define ao2_cleanup(obj)
Definition: astobj2.h:1958
static int find_challenge(const pjsip_rx_data *rdata, const struct ast_sip_auth *auth)
void ast_md5_hash(char *output, const char *input)
Produces MD5 hash based on input string.
Definition: main/utils.c:248
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
Asterisk module definitions.
static struct ast_sip_authenticator digest_authenticator
const ast_string_field auth_user
Definition: res_pjsip.h:450
#define AST_VECTOR_SIZE(vec)
Get the number of elements in a vector.
Definition: vector.h:611
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
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.
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.