diff -r 733187d496d0 -r 8ec65b8f6e2c opensips/modules/uac/auth.c --- a/opensips/modules/uac/auth.c Wed Feb 10 21:21:24 2010 +0100 +++ b/opensips/modules/uac/auth.c Wed Feb 10 21:25:01 2010 +0100 @@ -24,6 +24,7 @@ * --------- * 2005-01-31 first version (ramona) * 2006-03-02 UAC authentication looks first in AVPs for credential (bogdan) + * 2010-01-18 UAC replaces proxy-auth entries with new credentials (msvb) */ @@ -375,14 +376,172 @@ HASHHEX response; str *new_hdr; + /* pretransact */ + int nret = 0; + pv_value_t pv_val; + str *newuri = 0; + struct uac_credential *tst = 0; + struct hdr_field *tmp_hdr = 0; + struct hdr_field *del_hdr = 0; + + + /* Goes something like this... */ + /* HA1 = echo -n 'username:realm:password' | md5sum */ + /* echo -n 'itsme:mydom.com:stupidpass' | md5sum */ + /* HA2 = echo -n 'message:uri' | md5sum */ + /* echo -n 'INVITE:sip:danc@ing.fool.es' | md5sum */ + /* Response = echo -n 'HA1:nonce:HA2' | md5sum */ /* get transaction */ t = uac_tmb.t_gett(); - if (t==T_UNDEFINED || t==T_NULL_CELL) - { - LM_CRIT("no current transaction found\n"); - goto error; - } + if (t==T_UNDEFINED || t==T_NULL_CELL) { + /* begin without any transaction */ + /* set relevant structure variables */ + crd = 0; + crd = pkg_malloc(sizeof(struct uac_credential)); + if (!crd) { + LM_ERR("no more pkg memory\n"); + goto error; + } + /* set the realm from existing UAC message */ + tmp_hdr = msg->proxy_auth; + del_hdr = 0; + while (tmp_hdr) { + crd->realm.s = strchr(strstr(tmp_hdr->body.s, "realm="), '"') + 1; + crd->realm.len = strchr(crd->realm.s, '"') - crd->realm.s; + if(pv_get_spec_value(msg, &auth_realm_spec, &pv_val)==0 \ + && pv_val.rs.len>0) /* ensure realm is the desired one */ + if (strncmp(crd->realm.s, pv_val.rs.s, crd->realm.len)==0) + del_hdr = tmp_hdr; + tmp_hdr = tmp_hdr->sibling; + } + if (del_hdr) + crd->realm = pv_val.rs; /* success */ + else + nret++; /* failure */ + + /* set username from new AVP proxy values */ + if(pv_get_spec_value(msg, &auth_username_spec, &pv_val)!=0 \ + || pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0) + nret++; /* signal failure with nonzero value */ + else + crd->user = pv_val.rs; + + /* set password from new AVP proxy values */ + if(pv_get_spec_value(msg, &auth_password_spec, &pv_val)!=0 \ + || pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0) + nret++; /* signal failure with nonzero value */ + else + crd->passwd = pv_val.rs; + + if (nret) { /* if not found, look into predefined credentials */ + tst = lookup_realm(&crd->realm); + + if (tst==0) { /* found? */ + LM_DBG("no credential for realm \"%.*s\"\n", \ + crd->realm.len, crd->realm.s); + pkg_free(crd); + goto error; + } + + crd = tst; /* use predefined credentials */ + /* set the realm from existing UAC message */ + tmp_hdr = msg->proxy_auth; + del_hdr = 0; + while (tmp_hdr) { + if(pv_get_spec_value(msg, &auth_realm_spec, &pv_val)==0 \ + && pv_val.rs.len>0) /* ensure realm is the desired one */ + if (strncmp(crd->realm.s, pv_val.rs.s, crd->realm.len)==0) + del_hdr = tmp_hdr; + tmp_hdr = tmp_hdr->sibling; + } + if (del_hdr == 0) { /* proxy-auth header matching realm not found */ + LM_DBG("no credential for realm \"%.*s\"\n", \ + crd->realm.len, crd->realm.s); + pkg_free(crd); + goto error; + } + } + + /* set the uri from existing UAC message */ + newuri = pkg_malloc(sizeof(str)); + if (!newuri) { + LM_ERR("no more pkg memory\n"); + goto error; + } + newuri->s = pkg_malloc(msg->new_uri.len); + if (!newuri->s) { + LM_ERR("no more pkg memory\n"); + pkg_free(newuri); + goto error; + } + newuri->len = msg->new_uri.len; + strncpy(newuri->s, msg->new_uri.s, msg->new_uri.len); + if (!newuri->s) { + LM_DBG("failed to retrieve URI from UAC message\n"); + pkg_free(newuri->s); + pkg_free(newuri); + goto error; + } + + /* set the nonce from existing UAC message */ + tmp_hdr = msg->proxy_auth; + auth.nonce.len = 0; + auth.nonce.s = 0; + while (tmp_hdr) { + if(pv_get_spec_value(msg, &auth_realm_spec, &pv_val)==0 \ + && pv_val.rs.len>0) /* ensure realm is the desired one */ + if (strncmp(crd->realm.s, pv_val.rs.s, crd->realm.len)==0) { + auth.nonce.s = strchr(strstr(tmp_hdr->body.s, "nonce="), '"') + 1; + auth.nonce.len = strchr(auth.nonce.s, '"') - auth.nonce.s; + } + tmp_hdr = tmp_hdr->sibling; + } + if (auth.nonce.s == 0) { + LM_DBG("failed to retrieve nonce from UAC message\n"); + pkg_free(crd); + goto error; + } + + /* do authentication */ + do_uac_auth(msg, newuri, crd, &auth, response); + if (response==0) { + LM_ERR("failed to calculate challenge response\n"); + pkg_free(crd); + goto error; + } + + /* build the authorization header */ + new_hdr = build_authorization_hdr(407, newuri, crd, &auth, response); + if (new_hdr==0) { + LM_ERR("failed to build authorization hdr\n"); + pkg_free(crd); + goto error; + } + + /* remove the old proxy-auth header and relink message index */ + /* before updating the authorization credentials of the message */ + if (del_hdr) { /* updated a record and must remove the old one */ + if (del_lump(msg, del_hdr->name.s - msg->buf, del_hdr->len, 0)==0) { + LM_ERR("can't remove credentials\n"); + pkg_free(crd); + goto error; + } + } + + /* so far, so good -> add the header and set the proper RURI */ + if (apply_urihdr_changes(msg, newuri, new_hdr)<0) + { + LM_ERR("failed to apply changes\n"); + pkg_free(crd); + goto error; + } + + pkg_free(crd); /* finished calculating new response string, success */ + return 0; + } /* if (t==T_UNDEFINED || t==T_NULL_CELL) */ + + /* begin with transaction reply */ /* get the selected branch */ branch = uac_tmb.t_get_picked(); if (branch<0) {