/*!
 * \brief Check authentication using Digest scheme
 *
 * This function will check an incoming message against configured authentication
 * options. If \b any of the incoming Authorization headers result in successful
 * authentication, then authentication is considered successful.
 *
 * \see ast_sip_check_authentication
 */
static enum ast_sip_check_auth_result digest_check_auth(struct ast_sip_endpoint *endpoint,
		pjsip_rx_data *rdata, pjsip_tx_data *tdata)
{
	struct ast_sip_auth **auths;
	enum digest_verify_result *verify_res;
	enum ast_sip_check_auth_result res;
	int i;
	int failures = 0;
	size_t auth_size;

	RAII_VAR(struct ast_sip_endpoint *, artificial_endpoint,
		 ast_sip_get_artificial_endpoint(), ao2_cleanup);

	auth_size = AST_VECTOR_SIZE(&endpoint->inbound_auths);

	auths = ast_alloca(auth_size * sizeof(*auths));
	verify_res = ast_alloca(auth_size * sizeof(*verify_res));

	if (!auths) {
		return AST_SIP_AUTHENTICATION_ERROR;
	}

	if (endpoint == artificial_endpoint) {
		auths[0] = ast_sip_get_artificial_auth();
	} else if (ast_sip_retrieve_auths(&endpoint->inbound_auths, auths)) {
		res = AST_SIP_AUTHENTICATION_ERROR;
		goto cleanup;
	}

	for (i = 0; i < auth_size; ++i) {
		if (ast_strlen_zero(auths[i]->realm)) {
			ast_string_field_set(auths[i], realm, "asterisk");
		}
		verify_res[i] = verify(auths[i], rdata, tdata->pool);
		if (verify_res[i] == AUTH_SUCCESS) {
			res = AST_SIP_AUTHENTICATION_SUCCESS;
			goto cleanup;
		}
		if (verify_res[i] == AUTH_FAIL) {
			failures++;
		}
	}

	for (i = 0; i < auth_size; ++i) {
		challenge(auths[i]->realm, tdata, rdata, verify_res[i] == AUTH_STALE);
	}

	if (failures == auth_size) {
		res = AST_SIP_AUTHENTICATION_FAILED;
	} else {
		res = AST_SIP_AUTHENTICATION_CHALLENGE;
	}

cleanup:
	ast_sip_cleanup_auths(auths, auth_size);
	return res;
}
Ejemplo n.º 2
0
static int set_outbound_authentication_credentials(pjsip_auth_clt_sess *auth_sess,
		const struct ast_sip_auth_vector *auth_vector, pjsip_rx_data *challenge)
{
	size_t auth_size = AST_VECTOR_SIZE(auth_vector);
	struct ast_sip_auth **auths = ast_alloca(auth_size * sizeof(*auths));
	pjsip_cred_info *auth_creds = ast_alloca(auth_size * sizeof(*auth_creds));
	pjsip_www_authenticate_hdr *auth_hdr = NULL;
	int res = 0;
	int i;

	if (ast_sip_retrieve_auths(auth_vector, auths)) {
		res = -1;
		goto cleanup;
	}

	auth_hdr = get_auth_header(challenge);
	if (auth_hdr == NULL) {
		res = -1;
		ast_log(LOG_ERROR, "Unable to find authenticate header in challenge.\n");
		goto cleanup;
	}

	for (i = 0; i < auth_size; ++i) {
		if (ast_strlen_zero(auths[i]->realm)) {
			auth_creds[i].realm = auth_hdr->challenge.common.realm;
		} else {
			pj_cstr(&auth_creds[i].realm, auths[i]->realm);
		}
		pj_cstr(&auth_creds[i].username, auths[i]->auth_user);
		pj_cstr(&auth_creds[i].scheme, "digest");
		switch (auths[i]->type) {
		case AST_SIP_AUTH_TYPE_USER_PASS:
			pj_cstr(&auth_creds[i].data, auths[i]->auth_pass);
			auth_creds[i].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD;
			break;
		case AST_SIP_AUTH_TYPE_MD5:
			pj_cstr(&auth_creds[i].data, auths[i]->md5_creds);
			auth_creds[i].data_type = PJSIP_CRED_DATA_DIGEST;
			break;
		case AST_SIP_AUTH_TYPE_ARTIFICIAL:
			ast_log(LOG_ERROR, "Trying to set artificial outbound auth credentials shouldn't happen.\n");
			break;
		}
	}

	pjsip_auth_clt_set_credentials(auth_sess, auth_size, auth_creds);

cleanup:
	ast_sip_cleanup_auths(auths, auth_size);
	return res;
}