123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- /*
- * $Id$
- *
- * Digest Authentication Module
- *
- * Copyright (C) 2001-2003 FhG Fokus
- *
- * This file is part of ser, a free SIP server.
- *
- * ser is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version
- *
- * For a license to use the ser software under conditions
- * other than those described here, or to purchase support for this
- * software, please contact iptel.org by e-mail at the following addresses:
- * [email protected]
- *
- * ser is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
- /*
- * History:
- * --------
- * ...
- * 2008-07-01 set c->stale in auth_check_hdr_md5 (andrei)
- */
- #include <string.h>
- #include "api.h"
- #include "../../dprint.h"
- #include "../../parser/digest/digest.h"
- #include "../../sr_module.h"
- #include "../../ut.h"
- #include "auth_mod.h"
- #include "nonce.h"
- static int auth_check_hdr_md5(struct sip_msg* msg, auth_body_t* auth_body,
- auth_result_t* auth_res);
- /*
- * Purpose of this function is to find credentials with given realm,
- * do sanity check, validate credential correctness and determine if
- * we should really authenticate (there must be no authentication for
- * ACK and CANCEL
- * @param hdr output param where the Authorize headerfield will be returned.
- * @param check_hdr pointer to the function checking Authorization header field
- */
- auth_result_t pre_auth(struct sip_msg* msg, str* realm, hdr_types_t hftype,
- struct hdr_field** hdr,
- check_auth_hdr_t check_auth_hdr)
- {
- int ret;
- auth_body_t* c;
- check_auth_hdr_t check_hf;
- auth_result_t auth_rv;
- /* ACK and CANCEL must be always authenticated, there is
- * no way how to challenge ACK and CANCEL cannot be
- * challenged because it must have the same CSeq as
- * the request to be canceled.
- * PRACK is also not authenticated
- */
- if (msg->REQ_METHOD & (METHOD_ACK|METHOD_CANCEL|METHOD_PRACK))
- return AUTHENTICATED;
- /* Try to find credentials with corresponding realm
- * in the message, parse them and return pointer to
- * parsed structure
- */
- strip_realm(realm);
- ret = find_credentials(msg, realm, hftype, hdr);
- if (ret < 0) {
- LOG(L_ERR, "auth:pre_auth: Error while looking for credentials\n");
- return ERROR;
- } else if (ret > 0) {
- DBG("auth:pre_auth: Credentials with realm '%.*s' not found\n",
- realm->len, ZSW(realm->s));
- return NO_CREDENTIALS;
- }
- /* Pointer to the parsed credentials */
- c = (auth_body_t*)((*hdr)->parsed);
- /* digest headers are in c->digest */
- DBG("auth: digest-algo: %.*s parsed value: %d\n",
- c->digest.alg.alg_str.len, c->digest.alg.alg_str.s,
- c->digest.alg.alg_parsed);
- if (mark_authorized_cred(msg, *hdr) < 0) {
- LOG(L_ERR, "auth:pre_auth: Error while marking parsed credentials\n");
- return ERROR;
- }
- /* check authorization header field's validity */
- if (check_auth_hdr == NULL) {
- check_hf = auth_check_hdr_md5;
- } else { /* use check function of external authentication module */
- check_hf = check_auth_hdr;
- }
- /* use the right function */
- if (!check_hf(msg, c, &auth_rv)) {
- return auth_rv;
- }
-
- return DO_AUTHENTICATION;
- }
- /**
- * TODO move it to rfc2617.c
- *
- * @param auth_res return value of authentication. Maybe the it will be not affected.
- * @result if authentication should continue (1) or not (0)
- *
- */
- static int auth_check_hdr_md5(struct sip_msg* msg, auth_body_t* auth,
- auth_result_t* auth_res)
- {
- int ret;
-
- /* Check credentials correctness here */
- if (check_dig_cred(&auth->digest) != E_DIG_OK) {
- LOG(L_ERR, "auth:pre_auth: Credentials are not filled properly\n");
- *auth_res = BAD_CREDENTIALS;
- return 0;
- }
- ret = check_nonce(auth, &secret1, &secret2, msg);
- if (ret!=0){
- if (ret==3 || ret==4){
- /* failed auth_extra_checks or stale */
- auth->stale=1; /* we mark the nonce as stale
- (hack that makes our life much easier) */
- *auth_res = STALE_NONCE;
- return 0;
- } else if (ret==6) {
- *auth_res = NONCE_REUSED;
- return 0;
- } else {
- DBG("auth:pre_auth: Invalid nonce value received (ret %d)\n", ret);
- *auth_res = NOT_AUTHENTICATED;
- return 0;
- }
- }
- return 1;
- }
- /*
- * Purpose of this function is to do post authentication steps like
- * marking authorized credentials and so on.
- */
- auth_result_t post_auth(struct sip_msg* msg, struct hdr_field* hdr)
- {
- int res = AUTHENTICATED;
- auth_body_t* c;
- c = (auth_body_t*)((hdr)->parsed);
- if (c->stale ) {
- if ((msg->REQ_METHOD == METHOD_ACK) ||
- (msg->REQ_METHOD == METHOD_CANCEL)) {
- /* Method is ACK or CANCEL, we must accept stale
- * nonces because there is no way how to challenge
- * with new nonce (ACK has no response associated
- * and CANCEL must have the same CSeq as the request
- * to be canceled)
- */
- } else {
- c->stale = 1;
- res = NOT_AUTHENTICATED;
- }
- }
- return res;
- }
- /*
- * Calculate the response and compare with the given response string
- * Authorization is successful if this two strings are same
- */
- int auth_check_response(dig_cred_t* cred, str* method, char* ha1)
- {
- HASHHEX resp, hent;
- /*
- * First, we have to verify that the response received has
- * the same length as responses created by us
- */
- if (cred->response.len != 32) {
- DBG("check_response: Receive response len != 32\n");
- return BAD_CREDENTIALS;
- }
- /*
- * Now, calculate our response from parameters received
- * from the user agent
- */
- calc_response(ha1, &(cred->nonce),
- &(cred->nc), &(cred->cnonce),
- &(cred->qop.qop_str), cred->qop.qop_parsed == QOP_AUTHINT,
- method, &(cred->uri), hent, resp);
- DBG("check_response: Our result = \'%s\'\n", resp);
- /*
- * And simply compare the strings, the user is
- * authorized if they match
- */
- if (!memcmp(resp, cred->response.s, 32)) {
- DBG("check_response: Authorization is OK\n");
- return AUTHENTICATED;
- } else {
- DBG("check_response: Authorization failed\n");
- return NOT_AUTHENTICATED;
- }
- }
- int bind_auth_s(auth_api_s_t* api)
- {
- if (!api) {
- LOG(L_ERR, "bind_auth: Invalid parameter value\n");
- return -1;
- }
- api->pre_auth = pre_auth;
- api->post_auth = post_auth;
- api->build_challenge = build_challenge_hf;
- api->qop = &auth_qop;
- api->calc_HA1 = calc_HA1;
- api->calc_response = calc_response;
- api->check_response = auth_check_response;
- api->auth_challenge = auth_challenge;
- api->pv_authenticate = pv_authenticate;
- api->consume_credentials = consume_credentials;
- return 0;
- }
|