Codename Pineapple

Home page | Mailing list | Docs

Last updated: Sat Feb 3 05:01:50 2007

Asterisk developer's documentation :: Codename Pineapple


sip3_auth.c File Reference


Detailed Description

Various SIP authentication functions Version 3 of chan_sip.

Author:
Mark Spencer <markster@digium.com>

Olle E. Johansson <oej@edvina.net> (all the chan_sip3 changes)

See Also:

Definition in file sip3_auth.c.

#include "asterisk.h"
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <errno.h>
#include <stdlib.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <arpa/inet.h>
#include <netinet/ip.h>
#include <regex.h>
#include "asterisk/lock.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/logger.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/options.h"
#include "asterisk/sched.h"
#include "asterisk/io.h"
#include "asterisk/rtp.h"
#include "asterisk/udptl.h"
#include "asterisk/acl.h"
#include "asterisk/manager.h"
#include "asterisk/callerid.h"
#include "asterisk/cli.h"
#include "asterisk/app.h"
#include "asterisk/musiconhold.h"
#include "asterisk/dsp.h"
#include "asterisk/features.h"
#include "asterisk/srv.h"
#include "asterisk/astdb.h"
#include "asterisk/causes.h"
#include "asterisk/utils.h"
#include "asterisk/file.h"
#include "asterisk/astobj.h"
#include "asterisk/dnsmgr.h"
#include "asterisk/devicestate.h"
#include "asterisk/linkedlists.h"
#include "asterisk/stringfields.h"
#include "asterisk/monitor.h"
#include "asterisk/localtime.h"
#include "asterisk/abstract_jb.h"
#include "asterisk/compiler.h"
#include "sip3.h"
#include "sip3funcs.h"

Include dependency graph for sip3_auth.c:

Go to the source code of this file.

Functions

sip_authadd_realm_authentication (struct sip_auth *authlist, char *configuration, int lineno)
 Add realm authentication in list.
void auth_headers (enum sip_auth_type code, char **header, char **respheader)
 return the request and response heade for a 401 or 407 code
int build_reply_digest (struct sip_dialog *p, int method, char *digest, int digest_len)
 Build reply digest.
enum check_auth_result check_auth (struct sip_dialog *p, struct sip_request *req, const char *username, const char *secret, const char *md5secret, int sipmethod, char *uri, enum xmittype reliable, int ignore)
 Check user authorization from peer definition Some actions, like REGISTER and INVITEs from peers require authentication (if peer have secret set).
int clear_realm_authentication (struct sip_auth *authlist)
 Clear realm authentication list (at reload).
int do_proxy_auth (struct sip_dialog *p, struct sip_request *req, enum sip_auth_type code, int sipmethod, int init)
 Add authentication on outbound SIP packet.
int do_register_auth (struct sip_dialog *p, struct sip_request *req, enum sip_auth_type code)
 Authenticate for outbound registration.
sip_authfind_realm_authentication (struct sip_auth *authlist, const char *realm)
 Find authentication for a specific realm.
int reply_digest (struct sip_dialog *p, struct sip_request *req, char *header, int sipmethod, char *digest, int digest_len)
 reply to authentication for outbound registrations

Variables

sip_authauthl = NULL


Function Documentation

struct sip_auth * add_realm_authentication struct sip_auth authlist,
char *  configuration,
int  lineno
 

Add realm authentication in list.

Definition at line 495 of file sip3_auth.c.

References ast_calloc, ast_log(), ast_strlen_zero(), ast_verbose(), LOG_DEBUG, LOG_WARNING, sip_auth::md5secret, sip_auth::next, option_debug, option_verbose, sip_auth::realm, secret, strsep(), and sip_auth::username.

00496 {
00497    char authcopy[256];
00498    char *username=NULL, *realm=NULL, *secret=NULL, *md5secret=NULL;
00499    char *stringp;
00500    struct sip_auth *a, *b, *auth;
00501 
00502    if (ast_strlen_zero(configuration))
00503       return authlist;
00504 
00505    if (option_debug)
00506       ast_log(LOG_DEBUG, "Auth config ::  %s\n", configuration);
00507 
00508    ast_copy_string(authcopy, configuration, sizeof(authcopy));
00509    stringp = authcopy;
00510 
00511    username = stringp;
00512    realm = strrchr(stringp, '@');
00513    if (realm)
00514       *realm++ = '\0';
00515    if (ast_strlen_zero(username) || ast_strlen_zero(realm)) {
00516       ast_log(LOG_WARNING, "Format for authentication entry is user[:secret]@realm at line %d\n", lineno);
00517       return authlist;
00518    }
00519    stringp = username;
00520    username = strsep(&stringp, ":");
00521    if (username) {
00522       secret = strsep(&stringp, ":");
00523       if (!secret) {
00524          stringp = username;
00525          md5secret = strsep(&stringp,"#");
00526       }
00527    }
00528    if (!(auth = ast_calloc(1, sizeof(*auth))))
00529       return authlist;
00530 
00531    ast_copy_string(auth->realm, realm, sizeof(auth->realm));
00532    ast_copy_string(auth->username, username, sizeof(auth->username));
00533    if (secret)
00534       ast_copy_string(auth->secret, secret, sizeof(auth->secret));
00535    if (md5secret)
00536       ast_copy_string(auth->md5secret, md5secret, sizeof(auth->md5secret));
00537 
00538    /* find the end of the list */
00539    for (b = NULL, a = authlist; a ; b = a, a = a->next)
00540       ;
00541    if (b)
00542       b->next = auth;   /* Add structure add end of list */
00543    else
00544       authlist = auth;
00545 
00546    if (option_verbose > 2)
00547       ast_verbose("Added authentication for realm %s\n", realm);
00548 
00549    return authlist;
00550 
00551 }

void auth_headers enum sip_auth_type  code,
char **  header,
char **  respheader
 

return the request and response heade for a 401 or 407 code

sip3_auth.c

Definition at line 133 of file sip3_auth.c.

References ast_verbose(), PROXY_AUTH, and WWW_AUTH.

00134 {
00135    if (code == WWW_AUTH) {       /* 401 */
00136       *header = "WWW-Authenticate";
00137       *respheader = "Authorization";
00138    } else if (code == PROXY_AUTH) { /* 407 */
00139       *header = "Proxy-Authenticate";
00140       *respheader = "Proxy-Authorization";
00141    } else {
00142       ast_verbose("-- wrong response code %d\n", code);
00143       *header = *respheader = "Invalid";
00144    }
00145 }

int build_reply_digest struct sip_dialog p,
int  method,
char *  digest,
int  digest_len
 

Build reply digest.

Returns:
Returns -1 if we have no auth
Note:
Build digest challenge for authentication of peers (for registration) and users (for calls). Also used for authentication of CANCEL and BYE

Definition at line 428 of file sip3_auth.c.

References ast_inet_ntoa(), ast_log(), ast_md5_hash(), ast_random(), ast_strlen_zero(), authl, find_realm_authentication(), LOG_DEBUG, LOG_WARNING, sip_auth::md5secret, sip_dialog::noncecount, sip_dialog::sa, secret, sip_auth::secret, sip_method2txt(), and sip_auth::username.

00429 {
00430    char a1[256];
00431    char a2[256];
00432    char a1_hash[256];
00433    char a2_hash[256];
00434    char resp[256];
00435    char resp_hash[256];
00436    char uri[256];
00437    char cnonce[80];
00438    const char *username;
00439    const char *secret;
00440    const char *md5secret;
00441    struct sip_auth *auth = NULL; /* Realm authentication */
00442 
00443    if (!ast_strlen_zero(p->domain))
00444       ast_copy_string(uri, p->domain, sizeof(uri));
00445    else if (!ast_strlen_zero(p->uri))
00446       ast_copy_string(uri, p->uri, sizeof(uri));
00447    else
00448       snprintf(uri, sizeof(uri), "sip:%s@%s",p->peername, ast_inet_ntoa(p->sa.sin_addr));
00449 
00450    snprintf(cnonce, sizeof(cnonce), "%08lx", ast_random());
00451 
00452    /* Check if we have separate auth credentials */
00453    if ((auth = find_realm_authentication(authl, p->realm))) {
00454       ast_log(LOG_WARNING, "use realm [%s] from peer [%s]\n",
00455          auth->username, p->peername);
00456       username = auth->username;
00457       secret = auth->secret;
00458       md5secret = auth->md5secret;
00459       if (sipdebug)
00460          ast_log(LOG_DEBUG,"Using realm %s authentication for call %s\n", p->realm, p->callid);
00461    } else {
00462       /* No authentication, use peer or register= config */
00463       username = p->authname;
00464       secret =  p->peersecret;
00465       md5secret = p->peermd5secret;
00466    }
00467    if (ast_strlen_zero(username))   /* We have no authentication */
00468       return -1;
00469 
00470    /* Calculate SIP digest response */
00471    snprintf(a1,sizeof(a1), "%s:%s:%s", username, p->realm, secret);
00472    snprintf(a2,sizeof(a2), "%s:%s", sip_method2txt(method), uri);
00473    if (!ast_strlen_zero(md5secret))
00474       ast_copy_string(a1_hash, md5secret, sizeof(a1_hash));
00475    else
00476       ast_md5_hash(a1_hash, a1);
00477    ast_md5_hash(a2_hash,a2);
00478 
00479    p->noncecount++;
00480    if (!ast_strlen_zero(p->qop))
00481       snprintf(resp,sizeof(resp),"%s:%s:%08x:%s:%s:%s", a1_hash, p->nonce, p->noncecount, cnonce, "auth", a2_hash);
00482    else
00483       snprintf(resp,sizeof(resp),"%s:%s:%s", a1_hash, p->nonce, a2_hash);
00484    ast_md5_hash(resp_hash, resp);
00485    /* XXX We hard code our qop to "auth" for now.  XXX */
00486    if (!ast_strlen_zero(p->qop))
00487       snprintf(digest, digest_len, "Digest username=\"%s\", realm=\"%s\", algorithm=MD5, uri=\"%s\", nonce=\"%s\", response=\"%s\", opaque=\"%s\", qop=auth, cnonce=\"%s\", nc=%08x", username, p->realm, uri, p->nonce, resp_hash, p->opaque, cnonce, p->noncecount);
00488    else
00489       snprintf(digest, digest_len, "Digest username=\"%s\", realm=\"%s\", algorithm=MD5, uri=\"%s\", nonce=\"%s\", response=\"%s\", opaque=\"%s\"", username, p->realm, uri, p->nonce, resp_hash, p->opaque);
00490 
00491    return 0;
00492 }

enum check_auth_result check_auth struct sip_dialog p,
struct sip_request req,
const char *  username,
const char *  secret,
const char *  md5secret,
int  sipmethod,
char *  uri,
enum xmittype  reliable,
int  ignore
 

Check user authorization from peer definition Some actions, like REGISTER and INVITEs from peers require authentication (if peer have secret set).

Returns:
0 on success, non-zero on error

Definition at line 152 of file sip3_auth.c.

References ast_random(), ast_string_field_build, ast_strlen_zero(), AUTH_CHALLENGE_SENT, auth_headers(), AUTH_SUCCESSFUL, DEFAULT_TRANS_TIMEOUT, FALSE, get_header(), key(), keys, s, sip_scheddestroy(), strsep(), transmit_response_with_auth(), and WWW_AUTH.

00155 {
00156    const char *response = "407 Proxy Authentication Required";
00157    char *reqheader;
00158    char *respheader;
00159    const char *authtoken;
00160    char a1_hash[256];
00161    char resp_hash[256]="";
00162    char tmp[BUFSIZ * 2];                /* Make a large enough buffer */
00163    char *c;
00164    int  wrongnonce = FALSE;
00165    int  good_response;
00166    const char *usednonce = p->randdata;
00167 
00168    /* table of recognised keywords, and their value in the digest */
00169    enum keys { K_RESP, K_URI, K_USER, K_NONCE, K_LAST };
00170    struct x {
00171       const char *key;
00172       const char *s;
00173    } *i, keys[] = {
00174       [K_RESP] = { "response=", "" },
00175       [K_URI] = { "uri=", "" },
00176       [K_USER] = { "username=", "" },
00177       [K_NONCE] = { "nonce=", "" },
00178       [K_LAST] = { NULL, NULL}
00179    };
00180 
00181    /* Always OK if no secret */
00182    if (ast_strlen_zero(secret) && ast_strlen_zero(md5secret))
00183       return AUTH_SUCCESSFUL;
00184    response = "401 Unauthorized";
00185    auth_headers(WWW_AUTH, &respheader, &reqheader);   
00186    authtoken =  get_header(req, reqheader);  
00187    if (ignore && !ast_strlen_zero(p->randdata) && ast_strlen_zero(authtoken)) {
00188       /* This is a retransmitted invite/register/etc, don't reconstruct authentication
00189          information */
00190       if (!reliable) {
00191          /* Resend message if this was NOT a reliable delivery.   Otherwise the
00192             retransmission should get it */
00193          transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, 0);
00194          /* Schedule auto destroy in 32 seconds (according to RFC 3261) */
00195          sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
00196       }
00197       return AUTH_CHALLENGE_SENT;
00198    } else if (ast_strlen_zero(p->randdata) || ast_strlen_zero(authtoken)) {
00199       /* We have no auth, so issue challenge and request authentication */
00200       ast_string_field_build(p, randdata, "%08lx", ast_random()); /* Create nonce for challenge */
00201       transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, 0);
00202       /* Schedule auto destroy in 32 seconds */
00203       sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
00204       return AUTH_CHALLENGE_SENT;
00205    } 
00206 
00207    /* --- We have auth, so check it */
00208 
00209    /* Whoever came up with the authentication section of SIP can suck my %&#$&* for not putting
00210          an example in the spec of just what it is you're doing a hash on. */
00211 
00212 
00213    /* Make a copy of the response and parse it */
00214    ast_copy_string(tmp, authtoken, sizeof(tmp));
00215    c = tmp;
00216 
00217    while(c && *(c = ast_skip_blanks(c)) ) { /* lookup for keys */
00218       for (i = keys; i->key != NULL; i++) {
00219          const char *separator = ",";  /* default */
00220 
00221          if (strncasecmp(c, i->key, strlen(i->key)) != 0)
00222             continue;
00223          /* Found. Skip keyword, take text in quotes or up to the separator. */
00224          c += strlen(i->key);
00225          if (*c == '"') { /* in quotes. Skip first and look for last */
00226             c++;
00227             separator = "\"";
00228          }
00229          i->s = c;
00230          strsep(&c, separator);
00231          break;
00232       }
00233       if (i->key == NULL) /* not found, jump after space or comma */
00234          strsep(&c, " ,");
00235    }
00236 
00237    /* Verify that digest username matches  the username we auth as */
00238    if (strcmp(username, keys[K_USER].s)) {
00239       ast_log(LOG_WARNING, "username mismatch, have <%s>, digest has <%s>\n",
00240          username, keys[K_USER].s);
00241       /* Oops, we're trying something here */
00242       return AUTH_USERNAME_MISMATCH;
00243    }
00244 
00245    /* Verify nonce from request matches our nonce.  If not, send 401 with new nonce */
00246    if (strcasecmp(p->randdata, keys[K_NONCE].s)) { /* XXX it was 'n'casecmp ? */
00247       wrongnonce = TRUE;
00248       usednonce = keys[K_NONCE].s;
00249    }
00250 
00251    if (!ast_strlen_zero(md5secret))
00252       ast_copy_string(a1_hash, md5secret, sizeof(a1_hash));
00253    else {
00254       char a1[256];
00255       snprintf(a1, sizeof(a1), "%s:%s:%s", username, global.realm, secret);
00256       ast_md5_hash(a1_hash, a1);
00257    }
00258 
00259    /* compute the expected response to compare with what we received */
00260    {
00261       char a2[256];
00262       char a2_hash[256];
00263       char resp[256];
00264 
00265       snprintf(a2, sizeof(a2), "%s:%s", sip_method2txt(sipmethod), S_OR(keys[K_URI].s, uri));
00266       ast_md5_hash(a2_hash, a2);
00267       snprintf(resp, sizeof(resp), "%s:%s:%s", a1_hash, usednonce, a2_hash);
00268       ast_md5_hash(resp_hash, resp);
00269    }
00270 
00271    good_response = keys[K_RESP].s &&
00272          !strncasecmp(keys[K_RESP].s, resp_hash, strlen(resp_hash));
00273    if (wrongnonce) {
00274       ast_string_field_build(p, randdata, "%08lx", ast_random());
00275       if (good_response) {
00276          if (sipdebug)
00277             ast_log(LOG_NOTICE, "Correct auth, but based on stale nonce received from '%s'\n", get_header(req, "To"));
00278          /* We got working auth token, based on stale nonce . */
00279          transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, 1);
00280       } else {
00281          /* Everything was wrong, so give the device one more try with a new challenge */
00282          if (sipdebug)
00283             ast_log(LOG_NOTICE, "Bad authentication received from '%s'\n", get_header(req, "To"));
00284          transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, 0);
00285       }
00286 
00287       /* Schedule auto destroy in 32 seconds */
00288       sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
00289       return AUTH_CHALLENGE_SENT;
00290    } 
00291    if (good_response)
00292       return AUTH_SUCCESSFUL;
00293 
00294    /* Ok, we have a bad username/secret pair */
00295    /* Challenge again, and again, and again */
00296    transmit_response_with_auth(p, response, req, p->randdata, reliable, respheader, 0);
00297    sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
00298 
00299    return AUTH_CHALLENGE_SENT;
00300 }

int clear_realm_authentication struct sip_auth authlist  ) 
 

Clear realm authentication list (at reload).

Definition at line 554 of file sip3_auth.c.

References free, and sip_auth::next.

00555 {
00556    struct sip_auth *a = authlist;
00557    struct sip_auth *b;
00558 
00559    while (a) {
00560       b = a;
00561       a = a->next;
00562       free(b);
00563    }
00564 
00565    return 1;
00566 }

int do_proxy_auth struct sip_dialog p,
struct sip_request req,
enum sip_auth_type  code,
int  sipmethod,
int  init
 

Add authentication on outbound SIP packet.

Definition at line 327 of file sip3_auth.c.

References ast_calloc, ast_log(), sip_invite_param::auth, auth_headers(), sip_invite_param::authheader, sip_dialog::authtries, sip_dialog::inviteoptions, LOG_DEBUG, option_debug, reply_digest(), SIP_INVITE, sip_method2txt(), and transmit_invite().

00328 {
00329    char *header, *respheader;
00330    char digest[1024];
00331 
00332    if (!p->inviteoptions && !(p->inviteoptions = ast_calloc(1, sizeof(*p->inviteoptions))))
00333       return -2;
00334 
00335    p->authtries++;
00336    auth_headers(code, &header, &respheader);
00337    if (option_debug > 1)
00338       ast_log(LOG_DEBUG, "Auth attempt %d on %s\n", p->authtries, sip_method2txt(sipmethod));
00339    memset(digest, 0, sizeof(digest));
00340    if (reply_digest(p, req, header, sipmethod, digest, sizeof(digest) )) {
00341       /* No way to authenticate */
00342       return -1;
00343    }
00344    /* Now we have a reply digest */
00345    p->inviteoptions->auth = digest;
00346    p->inviteoptions->authheader = respheader;
00347    return transmit_invite(p, sipmethod, sipmethod == SIP_INVITE, init); 
00348 }

int do_register_auth struct sip_dialog p,
struct sip_request req,
enum sip_auth_type  code
 

Authenticate for outbound registration.

Definition at line 303 of file sip3_auth.c.

References append_history, ast_test_flag, ast_verbose(), auth_headers(), sip_dialog::authtries, sip_dialog::flags, reply_digest(), sip_debug_test_pvt(), SIP_NO_HISTORY, SIP_REGISTER, and transmit_register().

00304 {
00305    char *header, *respheader;
00306    char digest[1024];
00307 
00308    p->authtries++;
00309    auth_headers(code, &header, &respheader);
00310    memset(digest,0,sizeof(digest));
00311    if (reply_digest(p, req, header, SIP_REGISTER, digest, sizeof(digest))) {
00312       /* There's nothing to use for authentication */
00313       /* No digest challenge in request */
00314       if (sip_debug_test_pvt(p) && p->registry)
00315          ast_verbose("No authentication challenge, sending blank registration to domain/host name %s\n", p->registry->hostname);
00316          /* No old challenge */
00317       return -1;
00318    }
00319    if (!ast_test_flag(&p->flags[0], SIP_NO_HISTORY))
00320       append_history(p, "RegistryAuth", "Try: %d", p->authtries);
00321    if (sip_debug_test_pvt(p) && p->registry)
00322       ast_verbose("Responding to challenge, registration to domain/host name %s\n", p->registry->hostname);
00323    return transmit_register(p->registry, SIP_REGISTER, digest, respheader); 
00324 }

struct sip_auth * find_realm_authentication struct sip_auth authlist,
const char *  realm
 

Find authentication for a specific realm.

Definition at line 569 of file sip3_auth.c.

References sip_auth::next, and sip_auth::realm.

00570 {
00571    struct sip_auth *a;
00572 
00573    for (a = authlist; a; a = a->next) {
00574       if (!strcasecmp(a->realm, realm))
00575          break;
00576    }
00577 
00578    return a;
00579 }

int reply_digest struct sip_dialog p,
struct sip_request req,
char *  header,
int  sipmethod,
char *  digest,
int  digest_len
 

reply to authentication for outbound registrations

Returns:
Returns -1 if we have no auth
Note:
This is used for register= servers in sip.conf, SIP proxies we register with for receiving calls from.

Definition at line 354 of file sip3_auth.c.

References ast_log(), ast_string_field_index, ast_string_field_index_set, ast_strlen_zero(), get_header(), key(), keys, LOG_WARNING, and strsep().

00355 {
00356    char tmp[512];
00357    char *c;
00358    char oldnonce[256];
00359 
00360    /* table of recognised keywords, and places where they should be copied */
00361    const struct keystruct {
00362       const char *key;
00363       int field_index;
00364    } *i, keys[] = {
00365       { "realm=", ast_string_field_index(p, realm) },
00366       { "nonce=", ast_string_field_index(p, nonce) },
00367       { "opaque=", ast_string_field_index(p, opaque) },
00368       { "qop=", ast_string_field_index(p, qop) },
00369       { "domain=", ast_string_field_index(p, domain) },
00370       { NULL, 0 },
00371    };
00372 
00373    ast_copy_string(tmp, get_header(req, header), sizeof(tmp));
00374    if (ast_strlen_zero(tmp)) 
00375       return -1;
00376    if (strncasecmp(tmp, "Digest ", strlen("Digest "))) {
00377       ast_log(LOG_WARNING, "missing Digest.\n");
00378       return -1;
00379    }
00380    c = tmp + strlen("Digest ");
00381    ast_copy_string(oldnonce, p->nonce, sizeof(oldnonce));
00382    while (c && *(c = ast_skip_blanks(c))) {  /* lookup for keys */
00383       for (i = keys; i->key != NULL; i++) {
00384          char *src, *separator;
00385          if (strncasecmp(c, i->key, strlen(i->key)) != 0)
00386             continue;
00387          /* Found. Skip keyword, take text in quotes or up to the separator. */
00388          c += strlen(i->key);
00389          if (*c == '"') {
00390             src = ++c;
00391             separator = "\"";
00392          } else {
00393             src = c;
00394             separator = ",";
00395          }
00396          strsep(&c, separator); /* clear separator and move ptr */
00397          ast_string_field_index_set(p, i->field_index, src);
00398          break;
00399       }
00400       if (i->key == NULL) /* not found, try ',' */
00401          strsep(&c, ",");
00402    }
00403    /* Reset nonce count */
00404    if (strcmp(p->nonce, oldnonce)) 
00405       p->noncecount = 0;
00406 
00407    /* Save auth data for following registrations */
00408    if (p->registry) {
00409       struct sip_registry *r = p->registry;
00410 
00411       if (strcmp(r->nonce, p->nonce)) {
00412          ast_string_field_set(r, realm, p->realm);
00413          ast_string_field_set(r, nonce, p->nonce);
00414          ast_string_field_set(r, domain, p->domain);
00415          ast_string_field_set(r, opaque, p->opaque);
00416          ast_string_field_set(r, qop, p->qop);
00417          r->noncecount = 0;
00418       }
00419    }
00420    return build_reply_digest(p, sipmethod, digest, digest_len); 
00421 }


Variable Documentation

struct sip_auth* authl = NULL
 

Definition at line 130 of file sip3_auth.c.


Asterisk is a trademark for Digium, inc.. | Edvina.net | Asterisk.org | This documentation was generated with Doxygen