📄 sip_auth_client.c
字号:
pjsip_authorization_hdr *hauth;
char tmp[PJSIP_MAX_URL_SIZE];
pj_str_t uri_str;
pj_pool_t *pool;
pj_status_t status;
/* Verify arguments. */
PJ_ASSERT_RETURN(req_pool && hdr && uri && cred_info && method &&
sess_pool && cached_auth && p_h_auth, PJ_EINVAL);
/* Print URL in the original request. */
uri_str.ptr = tmp;
uri_str.slen = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, uri, tmp,sizeof(tmp));
if (uri_str.slen < 1) {
pj_assert(!"URL is too long!");
return PJSIP_EURITOOLONG;
}
# if (PJSIP_AUTH_HEADER_CACHING)
{
pool = sess_pool;
PJ_UNUSED_ARG(req_pool);
}
# else
{
pool = req_pool;
PJ_UNUSED_ARG(sess_pool);
}
# endif
if (hdr->type == PJSIP_H_WWW_AUTHENTICATE)
hauth = pjsip_authorization_hdr_create(pool);
else if (hdr->type == PJSIP_H_PROXY_AUTHENTICATE)
hauth = pjsip_proxy_authorization_hdr_create(pool);
else {
pj_assert(!"Invalid response header!");
return PJSIP_EINVALIDHDR;
}
/* Only support digest scheme at the moment. */
if (!pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR)) {
pj_str_t *cnonce = NULL;
pj_uint32_t nc = 1;
/* Update the session (nonce-count etc) if required. */
# if PJSIP_AUTH_QOP_SUPPORT
{
if (cached_auth) {
update_digest_session( sess_pool, cached_auth, hdr );
cnonce = &cached_auth->cnonce;
nc = cached_auth->nc;
}
}
# endif /* PJSIP_AUTH_QOP_SUPPORT */
hauth->scheme = pjsip_DIGEST_STR;
status = respond_digest( pool, &hauth->credential.digest,
&hdr->challenge.digest, &uri_str, cred_info,
cnonce, nc, &method->name);
if (status != PJ_SUCCESS)
return status;
/* Set qop type in auth session the first time only. */
if (hdr->challenge.digest.qop.slen != 0 && cached_auth) {
if (cached_auth->qop_value == PJSIP_AUTH_QOP_NONE) {
pj_str_t *qop_val = &hauth->credential.digest.qop;
if (!pj_strcmp(qop_val, &pjsip_AUTH_STR)) {
cached_auth->qop_value = PJSIP_AUTH_QOP_AUTH;
} else {
cached_auth->qop_value = PJSIP_AUTH_QOP_UNKNOWN;
}
}
}
} else {
return PJSIP_EINVALIDAUTHSCHEME;
}
/* Keep the new authorization header in the cache, only
* if no qop is not present.
*/
# if PJSIP_AUTH_HEADER_CACHING
{
if (hauth && cached_auth && cached_auth->qop_value == PJSIP_AUTH_QOP_NONE) {
pjsip_cached_auth_hdr *cached_hdr;
/* Delete old header with the same method. */
cached_hdr = cached_auth->cached_hdr.next;
while (cached_hdr != &cached_auth->cached_hdr) {
if (pjsip_method_cmp(method, &cached_hdr->method)==0)
break;
cached_hdr = cached_hdr->next;
}
/* Save the header to the list. */
if (cached_hdr != &cached_auth->cached_hdr) {
cached_hdr->hdr = hauth;
} else {
cached_hdr = pj_pool_alloc(pool, sizeof(*cached_hdr));
pjsip_method_copy( pool, &cached_hdr->method, method);
cached_hdr->hdr = hauth;
pj_list_insert_before( &cached_auth->cached_hdr, cached_hdr );
}
}
# if defined(PJSIP_AUTH_AUTO_SEND_NEXT) && PJSIP_AUTH_AUTO_SEND_NEXT!=0
if (hdr != cached_auth->last_chal) {
cached_auth->last_chal = pjsip_hdr_clone(sess_pool, hdr);
}
# endif
}
# endif
*p_h_auth = hauth;
return PJ_SUCCESS;
}
#if defined(PJSIP_AUTH_AUTO_SEND_NEXT) && PJSIP_AUTH_AUTO_SEND_NEXT!=0
static pj_status_t new_auth_for_req( pjsip_tx_data *tdata,
pjsip_auth_clt_sess *sess,
pjsip_cached_auth *auth,
pjsip_authorization_hdr **p_h_auth)
{
const pjsip_cred_info *cred;
pjsip_authorization_hdr *hauth;
pj_status_t status;
PJ_ASSERT_RETURN(tdata && sess && auth, PJ_EINVAL);
PJ_ASSERT_RETURN(auth->last_chal != NULL, PJSIP_EAUTHNOPREVCHAL);
cred = auth_find_cred( sess, &auth->realm, &auth->last_chal->scheme );
if (!cred)
return PJSIP_ENOCREDENTIAL;
status = auth_respond( tdata->pool, auth->last_chal,
tdata->msg->line.req.uri,
cred, &tdata->msg->line.req.method,
sess->pool, auth, &hauth);
if (status != PJ_SUCCESS)
return status;
pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)hauth);
if (p_h_auth)
*p_h_auth = hauth;
return PJ_SUCCESS;
}
#endif
/* Initialize outgoing request. */
PJ_DEF(pj_status_t) pjsip_auth_clt_init_req( pjsip_auth_clt_sess *sess,
pjsip_tx_data *tdata )
{
const pjsip_method *method;
pjsip_cached_auth *auth;
PJ_ASSERT_RETURN(sess && tdata, PJ_EINVAL);
PJ_ASSERT_RETURN(sess->pool, PJSIP_ENOTINITIALIZED);
PJ_ASSERT_RETURN(tdata->msg->type==PJSIP_REQUEST_MSG,
PJSIP_ENOTREQUESTMSG);
/* Get the method. */
method = &tdata->msg->line.req.method;
auth = sess->cached_auth.next;
while (auth != &sess->cached_auth) {
/* Reset stale counter */
auth->stale_cnt = 0;
if (auth->qop_value == PJSIP_AUTH_QOP_NONE) {
# if defined(PJSIP_AUTH_HEADER_CACHING) && \
PJSIP_AUTH_HEADER_CACHING!=0
{
pjsip_cached_auth_hdr *entry = auth->cached_hdr.next;
while (entry != &auth->cached_hdr) {
if (pjsip_method_cmp(&entry->method, method)==0) {
pjsip_authorization_hdr *hauth;
hauth = pjsip_hdr_shallow_clone(tdata->pool, entry->hdr);
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hauth);
break;
}
entry = entry->next;
}
# if defined(PJSIP_AUTH_AUTO_SEND_NEXT) && \
PJSIP_AUTH_AUTO_SEND_NEXT!=0
{
if (entry == &auth->cached_hdr)
new_auth_for_req( tdata, sess, auth, NULL);
}
# endif
}
# elif defined(PJSIP_AUTH_AUTO_SEND_NEXT) && \
PJSIP_AUTH_AUTO_SEND_NEXT!=0
{
new_auth_for_req( tdata, sess, auth, NULL);
}
# endif
}
# if defined(PJSIP_AUTH_QOP_SUPPORT) && \
defined(PJSIP_AUTH_AUTO_SEND_NEXT) && \
(PJSIP_AUTH_QOP_SUPPORT && PJSIP_AUTH_AUTO_SEND_NEXT)
else if (auth->qop_value == PJSIP_AUTH_QOP_AUTH) {
/* For qop="auth", we have to re-create the authorization header.
*/
const pjsip_cred_info *cred;
pjsip_authorization_hdr *hauth;
pj_status_t status;
cred = auth_find_cred(sess, &auth->realm,
&auth->last_chal->scheme);
if (!cred) {
auth = auth->next;
continue;
}
status = auth_respond( tdata->pool, auth->last_chal,
tdata->msg->line.req.uri,
cred,
&tdata->msg->line.req.method,
sess->pool, auth, &hauth);
if (status != PJ_SUCCESS)
return status;
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hauth);
}
# endif /* PJSIP_AUTH_QOP_SUPPORT && PJSIP_AUTH_AUTO_SEND_NEXT */
auth = auth->next;
}
return PJ_SUCCESS;
}
/* Process authorization challenge */
static pj_status_t process_auth( pj_pool_t *req_pool,
const pjsip_www_authenticate_hdr *hchal,
const pjsip_uri *uri,
pjsip_tx_data *tdata,
pjsip_auth_clt_sess *sess,
pjsip_cached_auth *cached_auth,
pjsip_authorization_hdr **h_auth)
{
const pjsip_cred_info *cred;
pjsip_authorization_hdr *sent_auth = NULL;
pjsip_hdr *hdr;
pj_status_t status;
/* See if we have sent authorization header for this realm */
hdr = tdata->msg->hdr.next;
while (hdr != &tdata->msg->hdr) {
if ((hchal->type == PJSIP_H_WWW_AUTHENTICATE &&
hdr->type == PJSIP_H_AUTHORIZATION) ||
(hchal->type == PJSIP_H_PROXY_AUTHENTICATE &&
hdr->type == PJSIP_H_PROXY_AUTHORIZATION))
{
sent_auth = (pjsip_authorization_hdr*) hdr;
if (pj_stricmp(&hchal->challenge.common.realm,
&sent_auth->credential.common.realm )==0)
{
break;
}
}
hdr = hdr->next;
}
/* If we have sent, see if server rejected because of stale nonce or
* other causes.
*/
if (hdr != &tdata->msg->hdr) {
if (hchal->challenge.digest.stale == 0) {
/* Our credential is rejected. No point in trying to re-supply
* the same credential.
*/
PJ_LOG(4, (THIS_FILE, "Authorization failed for %.*s@%.*s: "
"server rejected with stale=false",
sent_auth->credential.digest.username.slen,
sent_auth->credential.digest.username.ptr,
sent_auth->credential.digest.realm.slen,
sent_auth->credential.digest.realm.ptr));
return PJSIP_EFAILEDCREDENTIAL;
}
cached_auth->stale_cnt++;
if (cached_auth->stale_cnt >= PJSIP_MAX_STALE_COUNT) {
/* Our credential is rejected. No point in trying to re-supply
* the same credential.
*/
PJ_LOG(4, (THIS_FILE, "Authorization failed for %.*s@%.*s: "
"maximum number of stale retries exceeded",
sent_auth->credential.digest.username.slen,
sent_auth->credential.digest.username.ptr,
sent_auth->credential.digest.realm.slen,
sent_auth->credential.digest.realm.ptr));
return PJSIP_EAUTHSTALECOUNT;
}
/* Otherwise remove old, stale authorization header from the mesasge.
* We will supply a new one.
*/
pj_list_erase(sent_auth);
}
/* Find credential to be used for the challenge. */
cred = auth_find_cred( sess, &hchal->challenge.common.realm,
&hchal->scheme);
if (!cred) {
const pj_str_t *realm = &hchal->challenge.common.realm;
PJ_LOG(4,(THIS_FILE,
"Unable to set auth for %s: can not find credential for %.*s/%.*s",
tdata->obj_name,
realm->slen, realm->ptr,
hchal->scheme.slen, hchal->scheme.ptr));
return PJSIP_ENOCREDENTIAL;
}
/* Respond to authorization challenge. */
status = auth_respond( req_pool, hchal, uri, cred,
&tdata->msg->line.req.method,
sess->pool, cached_auth, h_auth);
return status;
}
/* Reinitialize outgoing request after 401/407 response is received.
* The purpose of this function is:
* - to add a Authorization/Proxy-Authorization header.
* - to put the newly created Authorization/Proxy-Authorization header
* in cached_list.
*/
PJ_DEF(pj_status_t) pjsip_auth_clt_reinit_req( pjsip_auth_clt_sess *sess,
const pjsip_rx_data *rdata,
pjsip_tx_data *old_request,
pjsip_tx_data **new_request )
{
pjsip_tx_data *tdata;
const pjsip_hdr *hdr;
pjsip_via_hdr *via;
pj_status_t status;
PJ_ASSERT_RETURN(sess && rdata && old_request && new_request,
PJ_EINVAL);
PJ_ASSERT_RETURN(sess->pool, PJSIP_ENOTINITIALIZED);
PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_RESPONSE_MSG,
PJSIP_ENOTRESPONSEMSG);
PJ_ASSERT_RETURN(old_request->msg->type == PJSIP_REQUEST_MSG,
PJSIP_ENOTREQUESTMSG);
PJ_ASSERT_RETURN(rdata->msg_info.msg->line.status.code == 401 ||
rdata->msg_info.msg->line.status.code == 407,
PJSIP_EINVALIDSTATUS);
tdata = old_request;
/*
* Respond to each authentication challenge.
*/
hdr = rdata->msg_info.msg->hdr.next;
while (hdr != &rdata->msg_info.msg->hdr) {
pjsip_cached_auth *cached_auth;
const pjsip_www_authenticate_hdr *hchal;
pjsip_authorization_hdr *hauth;
/* Find WWW-Authenticate or Proxy-Authenticate header. */
while (hdr->type != PJSIP_H_WWW_AUTHENTICATE &&
hdr->type != PJSIP_H_PROXY_AUTHENTICATE &&
hdr != &rdata->msg_info.msg->hdr)
{
hdr = hdr->next;
}
if (hdr == &rdata->msg_info.msg->hdr)
break;
hchal = (const pjsip_www_authenticate_hdr*) hdr;
/* Find authentication session for this realm, create a new one
* if not present.
*/
cached_auth = find_cached_auth(sess, &hchal->challenge.common.realm );
if (!cached_auth) {
cached_auth = pj_pool_zalloc( sess->pool, sizeof(*cached_auth));
pj_strdup( sess->pool, &cached_auth->realm, &hchal->challenge.common.realm);
cached_auth->is_proxy = (hchal->type == PJSIP_H_PROXY_AUTHENTICATE);
# if (PJSIP_AUTH_HEADER_CACHING)
{
pj_list_init(&cached_auth->cached_hdr);
}
# endif
pj_list_insert_before( &sess->cached_auth, cached_auth );
}
/* Create authorization header for this challenge, and update
* authorization session.
*/
status = process_auth( tdata->pool, hchal, tdata->msg->line.req.uri,
tdata, sess, cached_auth, &hauth);
if (status != PJ_SUCCESS)
return status;
/* Add to the message. */
pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hauth);
/* Process next header. */
hdr = hdr->next;
}
/* Remove branch param in Via header. */
via = pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
via->branch_param.slen = 0;
/* Must invalidate the message! */
pjsip_tx_data_invalidate_msg(tdata);
/* Increment reference counter. */
pjsip_tx_data_add_ref(tdata);
/* Done. */
*new_request = tdata;
return PJ_SUCCESS;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -