Example #1
0
/*
 * Create new request message to be forwarded upstream to new destination URI 
 * in uri. 
 */
PJ_DEF(pj_status_t) pjsip_endpt_create_request_fwd(pjsip_endpoint *endpt,
						   pjsip_rx_data *rdata, 
						   const pjsip_uri *uri,
						   const pj_str_t *branch,
						   unsigned options,
						   pjsip_tx_data **p_tdata)
{
    pjsip_tx_data *tdata;
    pj_status_t status;
    PJ_USE_EXCEPTION;


    PJ_ASSERT_RETURN(endpt && rdata && p_tdata, PJ_EINVAL);
    PJ_ASSERT_RETURN(rdata->msg_info.msg->type == PJSIP_REQUEST_MSG, 
		     PJSIP_ENOTREQUESTMSG);

    PJ_UNUSED_ARG(options);


    /* Request forwarding rule in RFC 3261 section 16.6:
     *
     * For each target, the proxy forwards the request following these
     * steps:
     * 
     * 1.  Make a copy of the received request
     * 2.  Update the Request-URI
     * 3.  Update the Max-Forwards header field
     * 4.  Optionally add a Record-route header field value
     * 5.  Optionally add additional header fields
     * 6.  Postprocess routing information
     * 7.  Determine the next-hop address, port, and transport
     * 8.  Add a Via header field value
     * 9.  Add a Content-Length header field if necessary
     * 10. Forward the new request
     *
     * Of these steps, we only do step 1-3, since the later will be
     * done by application.
     */

    status = pjsip_endpt_create_tdata(endpt, &tdata);
    if (status != PJ_SUCCESS)
	return status;

    /* Always increment ref counter to 1 */
    pjsip_tx_data_add_ref(tdata);

    /* Duplicate the request */
    PJ_TRY {
	pjsip_msg *dst;
	const pjsip_msg *src = rdata->msg_info.msg;
	const pjsip_hdr *hsrc;

	/* Create the request */
	tdata->msg = dst = pjsip_msg_create(tdata->pool, PJSIP_REQUEST_MSG);

	/* Duplicate request method */
	pjsip_method_copy(tdata->pool, &tdata->msg->line.req.method,
			  &src->line.req.method);

	/* Set request URI */
	if (uri) {
	    dst->line.req.uri = (pjsip_uri*) 
	    			pjsip_uri_clone(tdata->pool, uri);
	} else {
	    dst->line.req.uri= (pjsip_uri*)
	    		       pjsip_uri_clone(tdata->pool, src->line.req.uri);
	}

	/* Clone ALL headers */
	hsrc = src->hdr.next;
	while (hsrc != &src->hdr) {

	    pjsip_hdr *hdst;

	    /* If this is the top-most Via header, insert our own before
	     * cloning the header.
	     */
	    if (hsrc == (pjsip_hdr*)rdata->msg_info.via) {
		pjsip_via_hdr *hvia;
		hvia = pjsip_via_hdr_create(tdata->pool);
		if (branch)
		    pj_strdup(tdata->pool, &hvia->branch_param, branch);
		else {
		    pj_str_t new_branch = pjsip_calculate_branch_id(rdata);
		    pj_strdup(tdata->pool, &hvia->branch_param, &new_branch);
		}
		pjsip_msg_add_hdr(dst, (pjsip_hdr*)hvia);

	    }
	    /* Skip Content-Type and Content-Length as these would be 
	     * generated when the the message is printed.
	     */
	    else if (hsrc->type == PJSIP_H_CONTENT_LENGTH ||
		     hsrc->type == PJSIP_H_CONTENT_TYPE) {

		hsrc = hsrc->next;
		continue;

	    }
#if 0
	    /* If this is the top-most Route header and it indicates loose
	     * route, remove the header.
	     */
	    else if (hsrc == (pjsip_hdr*)rdata->msg_info.route) {

		const pjsip_route_hdr *hroute = (const pjsip_route_hdr*) hsrc;
		const pjsip_sip_uri *sip_uri;

		if (!PJSIP_URI_SCHEME_IS_SIP(hroute->name_addr.uri) &&
		    !PJSIP_URI_SCHEME_IS_SIPS(hroute->name_addr.uri))
		{
		    /* This is a bad request! */
		    status = PJSIP_EINVALIDHDR;
		    goto on_error;
		}

		sip_uri = (pjsip_sip_uri*) hroute->name_addr.uri;

		if (sip_uri->lr_param) {
		    /* Yes lr param is present, skip this Route header */
		    hsrc = hsrc->next;
		    continue;
		}
	    }
#endif

	    /* Clone the header */
	    hdst = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, hsrc);

	    /* If this is Max-Forward header, decrement the value */
	    if (hdst->type == PJSIP_H_MAX_FORWARDS) {
		pjsip_max_fwd_hdr *hmaxfwd = (pjsip_max_fwd_hdr*)hdst;
		--hmaxfwd->ivalue;
	    }

	    /* Append header to new request */
	    pjsip_msg_add_hdr(dst, hdst);


	    hsrc = hsrc->next;
	}

	/* 16.6.3:
	 * If the copy does not contain a Max-Forwards header field, the
         * proxy MUST add one with a field value, which SHOULD be 70.
	 */
	if (rdata->msg_info.max_fwd == NULL) {
	    pjsip_max_fwd_hdr *hmaxfwd = 
		pjsip_max_fwd_hdr_create(tdata->pool, 70);
	    pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)hmaxfwd);
	}

	/* Clone request body */
	if (src->body) {
	    dst->body = pjsip_msg_body_clone(tdata->pool, src->body);
	}

    }
    PJ_CATCH_ANY {
	status = PJ_ENOMEM;
	goto on_error;
    }
    PJ_END


    /* Done */
    *p_tdata = tdata;
    return PJ_SUCCESS;

on_error:
    pjsip_tx_data_dec_ref(tdata);
    return status;
}
Example #2
0
/* 
 * Create Authorization/Proxy-Authorization response header based on the challege
 * in WWW-Authenticate/Proxy-Authenticate header.
 */
static pj_status_t auth_respond( pj_pool_t *req_pool,
				 const pjsip_www_authenticate_hdr *hdr,
				 const pjsip_uri *uri,
				 const pjsip_cred_info *cred_info,
				 const pjsip_method *method,
				 pj_pool_t *sess_pool,
				 pjsip_cached_auth *cached_auth,
				 pjsip_authorization_hdr **p_h_auth)
{
    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;

}
Example #3
0
pjsip_auth_respond( pj_pool_t *req_pool,
		    const pjsip_www_authenticate_hdr *hdr,
		    const pjsip_uri *uri,
		    const pjsip_cred_info *cred_info,
		    const pjsip_method *method,
		    pj_pool_t *sess_pool,
		    pjsip_auth_session *auth_sess)
{
    pjsip_authorization_hdr *auth;
    char tmp[PJSIP_MAX_URL_SIZE];
    pj_str_t uri_str;
    pj_pool_t *pool;

    pj_assert(hdr != NULL);
    pj_assert(uri != NULL);
    pj_assert(cred_info != NULL);
    pj_assert(method != NULL);

    /* 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!");
	PJ_LOG(4,(THIS_FILE, "Unable to authorize: URI is too long!"));
	return NULL;
    }

#   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)
	auth = pjsip_authorization_hdr_create(pool);
    else if (hdr->type == PJSIP_H_PROXY_AUTHENTICATE)
	auth = pjsip_proxy_authorization_hdr_create(pool);
    else {
	pj_assert(0);
	return NULL;
    }

    /* Only support digest scheme at the moment. */
    if (!pj_stricmp(&hdr->scheme, &pjsip_DIGEST_STR)) {
	pj_status_t rc;
	pj_str_t *cnonce = NULL;
	pj_uint32_t nc = 1;

	/* Update the session (nonce-count etc) if required. */
#	if PJSIP_AUTH_QOP_SUPPORT
	{
	    if (auth_sess) {
		update_digest_session( sess_pool, auth_sess, hdr );

		cnonce = &auth_sess->cnonce;
		nc = auth_sess->nc;
	    }
	}
#	endif	/* PJSIP_AUTH_QOP_SUPPORT */

	auth->scheme = pjsip_DIGEST_STR;
	rc = respond_digest( pool, &auth->credential.digest,
			     &hdr->challenge.digest, &uri_str, cred_info,
			     cnonce, nc, &method->name);
	if (rc != 0)
	    return NULL;

	/* Set qop type in auth session the first time only. */
	if (hdr->challenge.digest.qop.slen != 0 && auth_sess) {
	    if (auth_sess->qop_value == PJSIP_AUTH_QOP_NONE) {
		pj_str_t *qop_val = &auth->credential.digest.qop;
		if (!pj_strcmp(qop_val, &pjsip_AUTH_STR)) {
		    auth_sess->qop_value = PJSIP_AUTH_QOP_AUTH;
		} else {
		    auth_sess->qop_value = PJSIP_AUTH_QOP_UNKNOWN;
		}
	    }
	}
    } else {
	auth = NULL;
    }

    /* Keep the new authorization header in the cache, only
     * if no qop is not present.
     */
#   if PJSIP_AUTH_HEADER_CACHING
    {
	if (auth && auth_sess && auth_sess->qop_value == PJSIP_AUTH_QOP_NONE) {
	    pjsip_cached_auth_hdr *cached_hdr;

	    /* Delete old header with the same method. */
	    cached_hdr = auth_sess->cached_hdr.next;
	    while (cached_hdr != &auth_sess->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 != &auth_sess->cached_hdr) {
		cached_hdr->hdr = auth;
	    } else {
		cached_hdr = pj_pool_alloc(pool, sizeof(*cached_hdr));
		pjsip_method_copy( pool, &cached_hdr->method, method);
		cached_hdr->hdr = auth;
		pj_list_insert_before( &auth_sess->cached_hdr, cached_hdr );
	    }
	}
    }
#   endif

    return auth;

}