auth_db/authorize.c

Go to the documentation of this file.
00001 /*
00002  * $Id: authorize.c 5597 2009-02-12 18:16:53Z miconda $
00003  *
00004  * Digest Authentication - Database support
00005  *
00006  * Copyright (C) 2001-2003 FhG Fokus
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License 
00021  * along with this program; if not, write to the Free Software 
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  *
00024  * history:
00025  * ---------
00026  * 2003-02-28 scratchpad compatibility abandoned
00027  * 2003-01-27 next baby-step to removing ZT - PRESERVE_ZT (jiri)
00028  * 2004-06-06 updated to the new DB api, added auth_db_{init,bind,close,ver}
00029  *             (andrei)
00030  * 2005-05-31 general definition of AVPs in credentials now accepted - ID AVP,
00031  *            STRING AVP, AVP aliases (bogdan)
00032  * 2006-03-01 pseudo variables support for domain name (bogdan)
00033  */
00034 
00035 
00036 #include <string.h>
00037 #include "../../ut.h"
00038 #include "../../str.h"
00039 #include "../../db/db.h"
00040 #include "../../dprint.h"
00041 #include "../../parser/digest/digest.h"
00042 #include "../../parser/hf.h"
00043 #include "../../parser/parser_f.h"
00044 #include "../../usr_avp.h"
00045 #include "../../mod_fix.h"
00046 #include "../../mem/mem.h"
00047 #include "aaa_avps.h"
00048 #include "authdb_mod.h"
00049 
00050 
00051 static str auth_500_err = str_init("Server Internal Error");
00052 
00053 
00054 static inline int get_ha1(struct username* _username, str* _domain,
00055            const str* _table, char* _ha1, db_res_t** res)
00056 {
00057    struct aaa_avp *cred;
00058    db_key_t keys[2];
00059    db_val_t vals[2];
00060    db_key_t *col;
00061    str result;
00062 
00063    int n, nc;
00064 
00065    col = pkg_malloc(sizeof(*col) * (credentials_n + 1));
00066    if (col == NULL) {
00067       LM_ERR("no more pkg memory\n");
00068       return -1;
00069    }
00070 
00071    keys[0] = &user_column;
00072    keys[1] = &domain_column;
00073    /* should we calculate the HA1, and is it calculated with domain? */
00074    col[0] = (_username->domain.len && !calc_ha1) ?
00075       (&pass_column_2) : (&pass_column);
00076 
00077    for (n = 0, cred=credentials; cred ; n++, cred=cred->next) {
00078       col[1 + n] = &cred->attr_name;
00079    }
00080 
00081    VAL_TYPE(vals) = VAL_TYPE(vals + 1) = DB_STR;
00082    VAL_NULL(vals) = VAL_NULL(vals + 1) = 0;
00083 
00084    VAL_STR(vals).s = _username->user.s;
00085    VAL_STR(vals).len = _username->user.len;
00086 
00087    if (_username->domain.len) {
00088       VAL_STR(vals + 1) = _username->domain;
00089    } else {
00090       VAL_STR(vals + 1) = *_domain;
00091    }
00092 
00093    n = (use_domain ? 2 : 1);
00094    nc = 1 + credentials_n;
00095    if (auth_dbf.use_table(auth_db_handle, _table) < 0) {
00096       LM_ERR("failed to use_table\n");
00097       pkg_free(col);
00098       return -1;
00099    }
00100 
00101    if (auth_dbf.query(auth_db_handle, keys, 0, vals, col, n, nc, 0, res) < 0) {
00102       LM_ERR("failed to query database\n");
00103       pkg_free(col);
00104       return -1;
00105    }
00106    pkg_free(col);
00107 
00108    if (RES_ROW_N(*res) == 0) {
00109       LM_DBG("no result for user \'%.*s@%.*s\'\n",
00110             _username->user.len, ZSW(_username->user.s),
00111          (use_domain ? (_domain->len) : 0), ZSW(_domain->s));
00112       return 1;
00113    }
00114 
00115    result.s = (char*)ROW_VALUES(RES_ROWS(*res))[0].val.string_val;
00116    result.len = strlen(result.s);
00117 
00118    if (calc_ha1) {
00119       /* Only plaintext passwords are stored in database,
00120        * we have to calculate HA1 */
00121       auth_api.calc_HA1(HA_MD5, &_username->whole, _domain, &result,
00122             0, 0, _ha1);
00123       LM_DBG("HA1 string calculated: %s\n", _ha1);
00124    } else {
00125       memcpy(_ha1, result.s, result.len);
00126       _ha1[result.len] = '\0';
00127    }
00128 
00129    return 0;
00130 }
00131 
00132 
00133 /*
00134  * Generate AVPs from the database result
00135  */
00136 static int generate_avps(db_res_t* result)
00137 {
00138    struct aaa_avp *cred;
00139    int_str ivalue;
00140    int i;
00141 
00142    for (cred=credentials, i=1; cred; cred=cred->next, i++) {
00143       switch (result->col.types[i]) {
00144       case DB_STR:
00145          ivalue.s = VAL_STR(&(result->rows[0].values[i]));
00146 
00147          if (VAL_NULL(&(result->rows[0].values[i])) ||
00148          ivalue.s.s == NULL || ivalue.s.len==0)
00149             continue;
00150 
00151          if (add_avp(cred->avp_type|AVP_VAL_STR,cred->avp_name,ivalue)!=0){
00152             LM_ERR("failed to add AVP\n");
00153             return -1;
00154          }
00155 
00156          LM_DBG("set string AVP \"%s\"/%d = \"%.*s\"\n",
00157             (cred->avp_type&AVP_NAME_STR)?cred->avp_name.s.s:"",
00158             (cred->avp_type&AVP_NAME_STR)?0:cred->avp_name.n,
00159             ivalue.s.len, ZSW(ivalue.s.s));
00160          break;
00161       case DB_STRING:
00162          ivalue.s.s = (char*)VAL_STRING(&(result->rows[0].values[i]));
00163 
00164          if (VAL_NULL(&(result->rows[0].values[i])) ||
00165          ivalue.s.s == NULL || (ivalue.s.len=strlen(ivalue.s.s))==0 )
00166             continue;
00167 
00168          if (add_avp(cred->avp_type|AVP_VAL_STR,cred->avp_name,ivalue)!=0){
00169             LM_ERR("failed to add AVP\n");
00170             return -1;
00171          }
00172 
00173          LM_DBG("set string AVP \"%s\"/%d = \"%.*s\"\n",
00174             (cred->avp_type&AVP_NAME_STR)?cred->avp_name.s.s:"",
00175             (cred->avp_type&AVP_NAME_STR)?0:cred->avp_name.n,
00176             ivalue.s.len, ZSW(ivalue.s.s));
00177          break;
00178       case DB_INT:
00179          if (VAL_NULL(&(result->rows[0].values[i])))
00180             continue;
00181 
00182          ivalue.n = (int)VAL_INT(&(result->rows[0].values[i]));
00183 
00184          if (add_avp(cred->avp_type, cred->avp_name, ivalue)!=0) {
00185             LM_ERR("failed to add AVP\n");
00186             return -1;
00187          }
00188 
00189          LM_DBG("set int AVP \"%s\"/%d = %d\n",
00190             (cred->avp_type&AVP_NAME_STR)?cred->avp_name.s.s:"",
00191             (cred->avp_type&AVP_NAME_STR)?0:cred->avp_name.n,
00192             ivalue.n);
00193          break;
00194       default:
00195          LM_ERR("subscriber table column `%.*s' has unsuported type. "
00196             "Only string/str or int columns are supported by"
00197             "load_credentials.\n", result->col.names[i]->len, result->col.names[i]->s);
00198          break;
00199       }
00200    }
00201 
00202    return 0;
00203 }
00204 
00205 
00206 /*
00207  * Authorize digest credentials
00208  */
00209 static inline int authorize(struct sip_msg* _m, gparam_p _realm,
00210                            char* _table, hdr_types_t _hftype)
00211 {
00212    char ha1[256];
00213    int res;
00214    struct hdr_field* h;
00215    auth_body_t* cred;
00216    auth_result_t ret;
00217    str domain, table;
00218    db_res_t* result = NULL;
00219 
00220    if(!_table) {
00221       LM_ERR("invalid table parameter\n");
00222       return -1;
00223    }
00224 
00225    table.s = _table;
00226    table.len = strlen(_table);
00227 
00228    if(fixup_get_svalue(_m, _realm, &domain)!=0)
00229    {
00230       LM_ERR("invalid realm parameter\n");
00231       return AUTH_ERROR;
00232    }
00233 
00234    if (domain.len==0)
00235       domain.s = 0;
00236 
00237    ret = auth_api.pre_auth(_m, &domain, _hftype, &h);
00238 
00239    if (ret != DO_AUTHORIZATION)
00240       return ret;
00241 
00242    cred = (auth_body_t*)h->parsed;
00243 
00244    res = get_ha1(&cred->digest.username, &domain, &table, ha1, &result);
00245    if (res < 0) {
00246       /* Error while accessing the database */
00247       if (slb.send_reply(_m, 500, &auth_500_err) == -1) {
00248          LM_ERR("failed to send 500 reply\n");
00249       }
00250       return ERROR;
00251    }
00252    if (res > 0) {
00253       /* Username not found in the database */
00254       auth_dbf.free_result(auth_db_handle, result);
00255       return USER_UNKNOWN;
00256    }
00257 
00258    /* Recalculate response, it must be same to authorize successfully */
00259    if (!auth_api.check_response(&(cred->digest),
00260             &_m->first_line.u.request.method, ha1)) {
00261       ret = auth_api.post_auth(_m, h);
00262       if (ret == AUTHORIZED)
00263          generate_avps(result);
00264       auth_dbf.free_result(auth_db_handle, result);
00265       return ret;
00266    }
00267 
00268    auth_dbf.free_result(auth_db_handle, result);
00269    return INVALID_PASSWORD;
00270 }
00271 
00272 
00273 /*
00274  * Authorize using Proxy-Authorize header field
00275  */
00276 int proxy_authorize(struct sip_msg* _m, char* _realm, char* _table)
00277 {
00278    return authorize(_m, (gparam_p)_realm, _table, HDR_PROXYAUTH_T);
00279 }
00280 
00281 
00282 /*
00283  * Authorize using WWW-Authorize header field
00284  */
00285 int www_authorize(struct sip_msg* _m, char* _realm, char* _table)
00286 {
00287    return authorize(_m, (gparam_p)_realm, _table, HDR_AUTHORIZATION_T);
00288 }

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