challenge.c

Go to the documentation of this file.
00001 /*
00002  * $Id: challenge.c 5299 2008-12-04 18:12:33Z henningw $
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License 
00019  * along with this program; if not, write to the Free Software 
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  * History:
00023  * --------
00024  * 2003-01-20 snprintf in build_auth_hf replaced with memcpy to avoid
00025  *            possible issues with too small buffer
00026  * 2003-01-26 consume_credentials no longer complains about ACK/CANCEL(jiri)
00027  * 2006-03-01 pseudo variables support for domain name (bogdan)
00028  */
00029 
00030 /*!
00031  * \file
00032  * \brief Challenge related functions
00033  * \ingroup auth
00034  * - Module: \ref auth
00035  */
00036 
00037 #include "../../data_lump.h"
00038 #include "../../mem/mem.h"
00039 #include "../../parser/digest/digest.h"
00040 #include "../../pvar.h"
00041 #include "../../str.h"
00042 #include "../../ut.h"
00043 #include "../../mod_fix.h"
00044 #include "auth_mod.h"
00045 #include "common.h"
00046 #include "challenge.h"
00047 #include "nonce.h"
00048 #include "index.h"
00049 #include "api.h"
00050 
00051 static str auth_400_err = str_init(MESSAGE_400);
00052 static str auth_500_err = str_init(MESSAGE_500);
00053 
00054 
00055 /*
00056  * proxy_challenge function sends this reply
00057  */
00058 #define MESSAGE_407          "Proxy Authentication Required"
00059 #define PROXY_AUTH_CHALLENGE "Proxy-Authenticate"
00060 
00061 
00062 /*
00063  * www_challenge function send this reply
00064  */
00065 #define MESSAGE_401        "Unauthorized"
00066 #define WWW_AUTH_CHALLENGE "WWW-Authenticate"
00067 
00068 
00069 #define QOP_PARAM   ", qop=\"auth\""
00070 #define QOP_PARAM_LEN     (sizeof(QOP_PARAM)-1)
00071 #define STALE_PARAM    ", stale=true"
00072 #define STALE_PARAM_LEN   (sizeof(STALE_PARAM)-1)
00073 #define DIGEST_REALM   ": Digest realm=\""
00074 #define DIGEST_REALM_LEN  (sizeof(DIGEST_REALM)-1)
00075 #define DIGEST_NONCE   "\", nonce=\""
00076 #define DIGEST_NONCE_LEN  (sizeof(DIGEST_NONCE)-1)
00077 #define DIGEST_MD5     ", algorithm=MD5"
00078 #define DIGEST_MD5_LEN    (sizeof(DIGEST_MD5)-1)
00079 
00080 
00081 /*!
00082  * \brief Create {WWW,Proxy}-Authenticate header field
00083  * \param _stale
00084  * \param _realm authentification realm
00085  * \param _len length, will be set
00086  * \param _qop qop value
00087  * \param _hf_name header field name
00088  * \return created header field, or 0 on failure
00089  */
00090 static inline char *build_auth_hf(int _stale, str* _realm, int* _len,
00091       int _qop, char* _hf_name)
00092 {
00093    
00094    int hf_name_len;
00095    char *hf, *p;
00096    int index = 0;
00097 
00098    if(nonce_reuse==0)
00099    {
00100       /* get the nonce index and mark it as used */
00101       index= reserve_nonce_index();
00102       if(index == -1)
00103       {
00104          LM_ERR("no more nonces can be generated\n");
00105          return 0;
00106       }
00107       LM_DBG("nonce index= %d\n", index);
00108    }
00109         /* length calculation */
00110    *_len=hf_name_len=strlen(_hf_name);
00111    *_len+=DIGEST_REALM_LEN
00112       +_realm->len
00113       +DIGEST_NONCE_LEN
00114       +((nonce_reuse==0)?NONCE_LEN:NONCE_LEN-8)
00115       +1 /* '"' */
00116       +((_qop)? QOP_PARAM_LEN:0)
00117       +((_stale)? STALE_PARAM_LEN : 0)
00118 #ifdef _PRINT_MD5
00119       +DIGEST_MD5_LEN
00120 #endif
00121       +CRLF_LEN ;
00122    
00123    p=hf=pkg_malloc(*_len+1);
00124    if (!hf) {
00125       LM_ERR("no pkg memory left\n");
00126       *_len=0;
00127       return 0;
00128    }
00129 
00130    memcpy(p, _hf_name, hf_name_len); p+=hf_name_len;
00131    memcpy(p, DIGEST_REALM, DIGEST_REALM_LEN);p+=DIGEST_REALM_LEN;
00132    memcpy(p, _realm->s, _realm->len);p+=_realm->len;
00133    memcpy(p, DIGEST_NONCE, DIGEST_NONCE_LEN);p+=DIGEST_NONCE_LEN;
00134    calc_nonce(p, time(0) + nonce_expire, index, &secret);
00135    p+=((nonce_reuse==0)?NONCE_LEN:NONCE_LEN-8);
00136    *p='"';p++;
00137    if (_qop) {
00138       memcpy(p, QOP_PARAM, QOP_PARAM_LEN);
00139       p+=QOP_PARAM_LEN;
00140    }
00141    if (_stale) {
00142       memcpy(p, STALE_PARAM, STALE_PARAM_LEN);
00143       p+=STALE_PARAM_LEN;
00144    }
00145 #ifdef _PRINT_MD5
00146    memcpy(p, DIGEST_MD5, DIGEST_MD5_LEN ); p+=DIGEST_MD5_LEN;
00147 #endif
00148    memcpy(p, CRLF, CRLF_LEN ); p+=CRLF_LEN;
00149    *p=0; /* zero terminator, just in case */
00150    
00151    LM_DBG("'%s'\n", hf);
00152    return hf;
00153 }
00154 
00155 /*!
00156  * \brief Create and send a authentification challenge
00157  * \param _msg SIP message
00158  * \param _realm authentification realm
00159  * \param _qop qop value
00160  * \param _code response code
00161  * \param _message response message
00162  * \param _challenge_msg challenge message
00163  * \return 0 if challenge could be created and sended, -1 on failure
00164  */
00165 static inline int challenge(struct sip_msg* _msg, gparam_p _realm, int _qop,
00166                   int _code, char* _message, char* _challenge_msg)
00167 {
00168    int auth_hf_len;
00169    struct hdr_field* h;
00170    auth_body_t* cred = 0;
00171    char *auth_hf;
00172    int ret;
00173    hdr_types_t hftype = 0;
00174    struct sip_uri *uri;
00175    str realm;
00176    str reason;
00177 
00178    switch(_code) {
00179    case 401:
00180       get_authorized_cred(_msg->authorization, &h); 
00181       hftype = HDR_AUTHORIZATION_T;
00182       break;
00183    case 407:
00184       get_authorized_cred(_msg->proxy_auth, &h);
00185       hftype = HDR_PROXYAUTH_T;
00186       break;
00187    }
00188 
00189    if (h) cred = (auth_body_t*)(h->parsed);
00190 
00191    if(fixup_get_svalue(_msg, _realm, &realm)!=0)
00192    {
00193       LM_ERR("invalid realm parameter");
00194       if (send_resp(_msg, 500, &auth_500_err, 0, 0)==-1)
00195          return -1;
00196       else
00197          return 0;
00198    }
00199    if (realm.len == 0) {
00200       if (get_realm(_msg, hftype, &uri) < 0) {
00201          LM_ERR("failed to extract URI\n");
00202          if (send_resp(_msg, 400, &auth_400_err, 0, 0) == -1) {
00203             LM_ERR("failed to send the response\n");
00204             return -1;
00205          }
00206          return 0;
00207       }
00208 
00209       realm = uri->host;
00210       strip_realm(&realm);
00211    }
00212 
00213    auth_hf = build_auth_hf((cred ? cred->stale : 0), &realm, 
00214          &auth_hf_len, _qop, _challenge_msg);
00215    if (!auth_hf) {
00216       LM_ERR("failed to generate nonce\n");
00217       return -1;
00218    }
00219 
00220    reason.s = _message;
00221    reason.len = strlen(_message);
00222    ret = send_resp(_msg, _code, &reason, auth_hf, auth_hf_len);
00223    if (auth_hf) pkg_free(auth_hf);
00224    if (ret == -1) {
00225       LM_ERR("failed to send the response\n");
00226       return -1;
00227    }
00228    
00229    return 0;
00230 }
00231 
00232 
00233 
00234 int www_challenge(struct sip_msg* _msg, char* _realm, char* _qop)
00235 {/*!
00236  * \brief Challenge a user to send credentials using WWW-Authorize header field
00237  * \param _msg SIP message
00238  * \param _realm authentification realm
00239  * \param _qop qop value
00240  * \return 0 if challenge could be sended, -1 on failure
00241  */
00242    return challenge(_msg, (gparam_p)_realm, (int)(long)_qop, 401,
00243          MESSAGE_401, WWW_AUTH_CHALLENGE);
00244 }
00245 
00246 
00247 
00248 /*!
00249  * \brief Challenge a user to send credentials using Proxy-Authorize header field
00250  * \param _msg SIP message
00251  * \param _realm authentification realm
00252  * \param _qop qop value
00253  * \return 0 if challenge could be sended, -1 on failure
00254  */
00255 int proxy_challenge(struct sip_msg* _msg, char* _realm, char* _qop)
00256 {
00257    return challenge(_msg, (gparam_p)_realm, (int)(long)_qop, 407,
00258          MESSAGE_407, PROXY_AUTH_CHALLENGE);
00259 }
00260 
00261 
00262 /*!
00263  * \brief Remove used credentials from a SIP message header
00264  * \param _m SIP message
00265  * \param _s1 unused
00266  * \param _s2 unused
00267  * \return 1 when credentials could be removed, -1 if not found or on failure
00268  */
00269 int consume_credentials(struct sip_msg* _m, char* _s1, char* _s2)
00270 {
00271    struct hdr_field* h;
00272    int len;
00273 
00274    get_authorized_cred(_m->authorization, &h);
00275    if (!h) {
00276       get_authorized_cred(_m->proxy_auth, &h);
00277       if (!h) { 
00278          if (_m->REQ_METHOD!=METHOD_ACK 
00279                && _m->REQ_METHOD!=METHOD_CANCEL) {
00280             LM_ERR("no authorized credentials found (error in scripts)\n");
00281          }
00282          return -1;
00283       }
00284    }
00285 
00286    len=h->len;
00287 
00288    if (del_lump(_m, h->name.s - _m->buf, len, 0) == 0) {
00289       LM_ERR("can't remove credentials\n");
00290       return -1;
00291    }
00292 
00293    return 1;
00294 }

Generated on Mon May 21 16:00:24 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6