auth_mod.c

Go to the documentation of this file.
00001 /*
00002  * $Id: auth_mod.c 5367 2008-12-16 10:19:53Z 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-02-26 checks and group moved to separate modules (janakj)
00025  * 2003-03-10 New module interface (janakj)
00026  * 2003-03-16 flags export parameter added (janakj)
00027  * 2003-03-19 all mallocs/frees replaced w/ pkg_malloc/pkg_free (andrei)
00028  * 2003-04-28 rpid contributed by Juha Heinanen added (janakj) 
00029  * 2005-05-31 general avp specification added for rpid (bogdan)
00030  * 2006-03-01 pseudo variables support for domain name (bogdan)
00031  */
00032 
00033 /*!
00034  * \file
00035  * \brief Digest Authentication Module
00036  * \ingroup auth
00037  * - Module: \ref auth
00038  */
00039 
00040 /*!
00041  * \defgroup auth AUTH :: The Kamailio auth Module
00042  * The module provides functions to authentificate users.
00043  * It also exports a API that can be used from other modules.
00044  */
00045 
00046 #include <stdio.h>
00047 #include <stdlib.h>
00048 #include <time.h>
00049 #include "../../sr_module.h"
00050 #include "../../dprint.h"
00051 #include "../../mem/mem.h"
00052 #include "../../error.h"
00053 #include "../../pvar.h"
00054 #include "../../ut.h"
00055 #include "../../mod_fix.h"
00056 #include "../../lock_alloc.h"
00057 #include "../sl/sl_api.h"
00058 #include "auth_mod.h"
00059 #include "challenge.h"
00060 #include "rpid.h"
00061 #include "api.h"
00062 
00063 MODULE_VERSION
00064 
00065 /*! length of the random secret */
00066 #define RAND_SECRET_LEN 32
00067 
00068 #define DEF_RPID_PREFIX ""
00069 #define DEF_RPID_SUFFIX ";party=calling;id-type=subscriber;screen=yes"
00070 #define DEF_STRIP_REALM ""
00071 #define DEF_RPID_AVP "$avp(s:rpid)"
00072 
00073 
00074 /*!
00075  * Module destroy function prototype
00076  */
00077 static void destroy(void);
00078 
00079 /*!
00080  * Module initialization function prototype
00081  */
00082 static int mod_init(void);
00083 
00084 int pv_proxy_authorize(struct sip_msg* msg, char* realm, char* str2);
00085 int pv_www_authorize(struct sip_msg* msg, char* realm, char* str2);
00086 
00087 /*! SL binds */
00088 struct sl_binds slb;
00089 
00090 
00091 /*
00092  * Module parameter variables
00093  */
00094 char* sec_param    = 0;   /*!< If the parameter is not used, the secret phrase will be auto-generated */
00095 unsigned int   nonce_expire = 30; /*!< Nonce lifetime - default 30 seconds */
00096 
00097 str secret;
00098 char* sec_rand = 0;
00099 
00100 int auth_calc_ha1 = 0;
00101 
00102 /*! Default Remote-Party-ID prefix */
00103 str rpid_prefix = {DEF_RPID_PREFIX, sizeof(DEF_RPID_PREFIX) - 1};
00104 /*! Default Remote-Party-IDD suffix */
00105 str rpid_suffix = {DEF_RPID_SUFFIX, sizeof(DEF_RPID_SUFFIX) - 1};
00106 /*! Prefix to strip from realm */
00107 str realm_prefix = {DEF_STRIP_REALM, sizeof(DEF_STRIP_REALM) - 1};
00108 
00109 /*! definition of AVP containing rpid value */
00110 char* rpid_avp_param = DEF_RPID_AVP;
00111 
00112 /*! definition of AVP containing username value */
00113 char* user_spec_param = 0;
00114 static pv_spec_t user_spec;
00115 
00116 
00117 /*! definition of AVP containing password value */
00118 char* passwd_spec_param = 0;
00119 static pv_spec_t passwd_spec;
00120 
00121 /*! nonce index */
00122 gen_lock_t* nonce_lock= NULL;
00123 char* nonce_buf= NULL;
00124 int* sec_monit= NULL;
00125 int* second= NULL;
00126 int* next_index= NULL;
00127 
00128 /*! control nonce usage checking */
00129 int nonce_reuse = 0;
00130 
00131 /*
00132  * Exported functions
00133  */
00134 static cmd_export_t cmds[] = {
00135    {"www_challenge",       (cmd_function)www_challenge,           2,
00136       fixup_spve_uint, 0, REQUEST_ROUTE},
00137    {"proxy_challenge",     (cmd_function)proxy_challenge,         2,
00138       fixup_spve_uint, 0, REQUEST_ROUTE},
00139    {"pv_www_authorize",    (cmd_function)pv_www_authorize,        1,
00140       fixup_spve_null, 0, REQUEST_ROUTE},
00141    {"pv_proxy_authorize",  (cmd_function)pv_proxy_authorize,      1,
00142       fixup_spve_null, 0, REQUEST_ROUTE},
00143    {"consume_credentials", (cmd_function)consume_credentials,     0, 0,
00144          0, REQUEST_ROUTE},
00145    {"is_rpid_user_e164",   (cmd_function)is_rpid_user_e164,       0, 0,
00146          0, REQUEST_ROUTE},
00147    {"append_rpid_hf",      (cmd_function)append_rpid_hf,          0, 0,
00148          0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE},
00149    {"append_rpid_hf",      (cmd_function)append_rpid_hf_p,        2,
00150          fixup_str_str,
00151          0, REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE},
00152    {"bind_auth",           (cmd_function)bind_auth, 0, 0,
00153          0, 0},
00154    {0, 0, 0, 0, 0, 0}
00155 };
00156 
00157 
00158 /*
00159  * Exported parameters
00160  */
00161 static param_export_t params[] = {
00162    {"secret",          STR_PARAM, &sec_param      },
00163    {"nonce_expire",    INT_PARAM, &nonce_expire   },
00164    {"rpid_prefix",     STR_PARAM, &rpid_prefix.s  },
00165    {"rpid_suffix",     STR_PARAM, &rpid_suffix.s  },
00166    {"realm_prefix",    STR_PARAM, &realm_prefix.s },
00167    {"rpid_avp",        STR_PARAM, &rpid_avp_param },
00168    {"username_spec",   STR_PARAM, &user_spec_param   },
00169    {"password_spec",   STR_PARAM, &passwd_spec_param },
00170    {"calculate_ha1",   INT_PARAM, &auth_calc_ha1     },
00171    {"nonce_reuse",     INT_PARAM, &nonce_reuse       },
00172    {0, 0, 0}
00173 };
00174 
00175 
00176 /*
00177  * Module interface
00178  */
00179 struct module_exports exports = {
00180    "auth", 
00181    DEFAULT_DLFLAGS, /* dlopen flags */
00182    cmds,
00183    params,
00184    0,          /* exported statistics */
00185    0,          /* exported MI functions */
00186    0,          /* exported pseudo-variables */
00187    0,          /* extra processes */
00188    mod_init,   /* module initialization function */
00189    0,          /* response function */
00190    destroy,    /* destroy function */
00191    0           /* child initialization function */
00192 };
00193 
00194 
00195 /*!
00196  * \brief Generate a random secret
00197  *
00198  * Generate a random secret. A secret parameter was not used so we
00199  * generate a random value here.
00200  * \return 0 on success, -1 on failure
00201  */
00202 static inline int generate_random_secret(void)
00203 {
00204    int i;
00205 
00206    sec_rand = (char*)pkg_malloc(RAND_SECRET_LEN);
00207    if (!sec_rand) {
00208       LM_ERR("no pkg memory left\n");
00209       return -1;
00210    }
00211 
00212    /* the generator is seeded from the core */
00213 
00214    for(i = 0; i < RAND_SECRET_LEN; i++) {
00215       sec_rand[i] = 32 + (int)(95.0 * rand() / (RAND_MAX + 1.0));
00216    }
00217 
00218    secret.s = sec_rand;
00219    secret.len = RAND_SECRET_LEN;
00220 
00221    /*LM_DBG("Generated secret: '%.*s'\n", secret.len, secret.s); */
00222 
00223    return 0;
00224 }
00225 
00226 
00227 static int mod_init(void)
00228 {
00229    str stmp;
00230    
00231    /* load the SL API */
00232    if (load_sl_api(&slb)!=0) {
00233       LM_ERR("can't load SL API\n");
00234       return -1;
00235    }
00236 
00237    /* If the parameter was not used */
00238    if (sec_param == 0) {
00239       /* Generate secret using random generator */
00240       if (generate_random_secret() < 0) {
00241          LM_ERR("failed to generate random secret\n");
00242          return -3;
00243       }
00244    } else {
00245       /* Otherwise use the parameter's value */
00246       secret.s = sec_param;
00247       secret.len = strlen(secret.s);
00248    }
00249 
00250    if ( init_rpid_avp(rpid_avp_param)<0 ) {
00251       LM_ERR("failed to process rpid AVPs\n");
00252       return -4;
00253    }
00254 
00255    rpid_prefix.len = strlen(rpid_prefix.s);
00256    rpid_suffix.len = strlen(rpid_suffix.s);
00257    realm_prefix.len = strlen(realm_prefix.s);
00258 
00259    if(user_spec_param!=0)
00260    {
00261       stmp.s = user_spec_param; stmp.len = strlen(stmp.s);
00262       if(pv_parse_spec(&stmp, &user_spec)==NULL)
00263       {
00264          LM_ERR("failed to parse username spec\n");
00265          return -5;
00266       }
00267       switch(user_spec.type) {
00268          case PVT_NONE:
00269          case PVT_EMPTY:
00270          case PVT_NULL:
00271          case PVT_MARKER:
00272          case PVT_COLOR:
00273             LM_ERR("invalid username spec\n");
00274             return -6;
00275          default: ;
00276       }
00277    }
00278    if(passwd_spec_param!=0)
00279    {
00280       stmp.s = passwd_spec_param; stmp.len = strlen(stmp.s);
00281       if(pv_parse_spec(&stmp, &passwd_spec)==NULL)
00282       {
00283          LM_ERR("failed to parse password spec\n");
00284          return -7;
00285       }
00286       switch(passwd_spec.type) {
00287          case PVT_NONE:
00288          case PVT_EMPTY:
00289          case PVT_NULL:
00290          case PVT_MARKER:
00291          case PVT_COLOR:
00292             LM_ERR("invalid password spec\n");
00293             return -8;
00294          default: ;
00295       }
00296    }
00297 
00298    if(nonce_reuse==0)
00299    {
00300        nonce_lock = (gen_lock_t*)lock_alloc();
00301       if(nonce_lock== NULL)
00302        {
00303           LM_ERR("no more shared memory\n");
00304          return -1;
00305        }
00306 
00307       /* initialize lock_nonce */
00308        if(lock_init(nonce_lock)== 0)
00309       {
00310            LM_ERR("failed to init lock\n");
00311           return -9;
00312        }
00313 
00314       nonce_buf= (char*)shm_malloc(NBUF_LEN);
00315       if(nonce_buf== NULL)
00316        {
00317           LM_ERR("no more share memory\n");
00318          return -10;
00319        }
00320       memset(nonce_buf, 255, NBUF_LEN);
00321 
00322       sec_monit= (int*)shm_malloc((nonce_expire +1)* sizeof(int));
00323       if(sec_monit== NULL)
00324       {
00325          LM_ERR("no more share memory\n");
00326            return -10;
00327       }
00328       memset(sec_monit, -1, (nonce_expire +1)* sizeof(int));
00329       second= (int*)shm_malloc(sizeof(int));
00330       next_index= (int*)shm_malloc(sizeof(int));
00331       if(second==  NULL || next_index== NULL)
00332        {
00333           LM_ERR("no more share memory\n");
00334            return -10;
00335       }
00336       *next_index= -1;
00337    }
00338 
00339    return 0;
00340 }
00341 
00342 
00343 static void destroy(void)
00344 {
00345    if (sec_rand) pkg_free(sec_rand);
00346 
00347    if(nonce_reuse==0)
00348    {
00349        if(nonce_lock)
00350       {
00351          lock_destroy(nonce_lock);
00352            lock_dealloc(nonce_lock);
00353       }
00354 
00355        if(nonce_buf)
00356           shm_free(nonce_buf);
00357        if(second)
00358           shm_free(second);
00359        if(sec_monit)
00360           shm_free(sec_monit);
00361        if(next_index)
00362           shm_free(next_index);
00363    }
00364 }
00365 
00366 
00367 /*!
00368  * \brief Generate a HA1 response from username and domain
00369  * \param msg SIP message
00370  * \param _username user name
00371  * \param _domain domain
00372  * \param _ha1 generated HA1
00373  * \return 0 on success, 1 on error and when the user could not found
00374  */
00375 static inline int auth_get_ha1(struct sip_msg *msg, struct username* _username,
00376       str* _domain, char* _ha1)
00377 {
00378    pv_value_t sval;
00379    
00380    /* get username from PV */
00381    memset(&sval, 0, sizeof(pv_value_t));
00382    if(pv_get_spec_value(msg, &user_spec, &sval)==0)
00383    {
00384       if(sval.flags==PV_VAL_NONE || (sval.flags&PV_VAL_NULL)
00385             || (sval.flags&PV_VAL_EMPTY) || (!(sval.flags&PV_VAL_STR)))
00386       {
00387          pv_value_destroy(&sval);
00388          return 1;
00389       }
00390       if(sval.rs.len!= _username->user.len
00391             || strncasecmp(sval.rs.s, _username->user.s, sval.rs.len))
00392       {
00393          LM_DBG("username mismatch [%.*s] [%.*s]\n",
00394             _username->user.len, _username->user.s, sval.rs.len, sval.rs.s);
00395          pv_value_destroy(&sval);
00396          return 1;
00397       }
00398    } else {
00399       return 1;
00400    }
00401    /* get password from PV */
00402    memset(&sval, 0, sizeof(pv_value_t));
00403    if(pv_get_spec_value(msg, &passwd_spec, &sval)==0)
00404    {
00405       if(sval.flags==PV_VAL_NONE || (sval.flags&PV_VAL_NULL)
00406             || (sval.flags&PV_VAL_EMPTY) || (!(sval.flags&PV_VAL_STR)))
00407       {
00408          pv_value_destroy(&sval);
00409          return 1;
00410       }
00411    } else {
00412       return 1;
00413    }
00414    if (auth_calc_ha1) {
00415       /* Only plaintext passwords are stored in database,
00416        * we have to calculate HA1 */
00417       calc_HA1(HA_MD5, &_username->whole, _domain, &sval.rs, 0, 0, _ha1);
00418       LM_DBG("HA1 string calculated: %s\n", _ha1);
00419    } else {
00420       memcpy(_ha1, sval.rs.s, sval.rs.len);
00421       _ha1[sval.rs.len] = '\0';
00422    }
00423 
00424    return 0;
00425 }
00426 
00427 
00428 /*!
00429  * \brief Check authorization from a pseudo-variable
00430  * \param msg SIP message
00431  * \param realm authentification realm
00432  * \param hftype type of the header field
00433  * \return 1 when authorized, null on errors, negative on authentification failure
00434  */
00435 static inline int pv_authorize(struct sip_msg* msg, gparam_p realm,
00436                               hdr_types_t hftype)
00437 {
00438    static char ha1[256];
00439    struct hdr_field* h;
00440    auth_body_t* cred;
00441    auth_result_t ret;
00442    str domain;
00443 
00444    if(fixup_get_svalue(msg, realm, &domain)!=0)
00445    {
00446       LM_ERR("invalid realm parameter\n");
00447       return -1;
00448    }
00449 
00450    if (domain.len==0)
00451       domain.s = 0;
00452 
00453    ret = pre_auth(msg, &domain, hftype, &h);
00454 
00455    if (ret != DO_AUTHORIZATION)
00456       return ret;
00457 
00458    cred = (auth_body_t*)h->parsed;
00459 
00460    if ((auth_get_ha1(msg, &cred->digest.username, &domain, ha1)) > 0) {
00461       /* Username not found */
00462       return USER_UNKNOWN;
00463    }
00464 
00465    /* Recalculate response, it must be same to authorize successfully */
00466    if (!check_response(&(cred->digest),&msg->first_line.u.request.method,ha1))
00467    {
00468       return post_auth(msg, h);
00469    }
00470    return AUTH_ERROR;
00471 }
00472 
00473 
00474 /*!
00475  * \brief Small wrapper around pv_authorize, use proxy challenge
00476  * \param msg SIP message
00477  * \param realm authenfication realm
00478  * \param str2 unused
00479  * \return 1 on sucess, 0 on errors, negative on authentification failures
00480  */
00481 int pv_proxy_authorize(struct sip_msg* msg, char* realm, char* str2)
00482 {
00483    return pv_authorize(msg, (gparam_p)realm, HDR_PROXYAUTH_T);
00484 }
00485 
00486 
00487 /*!
00488  * \brief Small wrapper around pv_authorize, use www challenge
00489  * \param msg SIP message
00490  * \param realm authenfication realm
00491  * \param str2 unused
00492  * \return 1 on sucess, 0 on errors, negative on authentification failures
00493  */
00494 int pv_www_authorize(struct sip_msg* msg, char* realm, char* str2)
00495 {
00496    return pv_authorize(msg, (gparam_p)realm, HDR_AUTHORIZATION_T);
00497 }

Generated on Thu May 17 12:00:25 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6