sterman.c

Go to the documentation of this file.
00001 /* 
00002  * $Id: sterman.c 4842 2008-09-04 14:25:02Z juhe $
00003  *
00004  * Digest Authentication - Radius 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-03-09: Based on digest.c from radius_auth module (janakj)
00027  * 2005-07-08: Radius AVP may contain any kind of Kamailio AVP - ID/name or
00028  *             int/str value (bogdan)
00029  * 2005-07-08: old RPID RADIUS AVP compatibility droped (bogdan)
00030  */
00031 
00032 
00033 #include "../../mem/mem.h"
00034 #include "../../dprint.h"
00035 #include "../../usr_avp.h"
00036 #include "../../radius.h"
00037 #include "../../ut.h"
00038 #include "../auth/api.h"
00039 #include "sterman.h"
00040 #include "authrad_mod.h"
00041 #include "extra.h"
00042 
00043 #include <stdlib.h>
00044 #include <string.h>
00045 
00046 
00047 /* Array for extra attribute values */
00048 static str val_arr[MAX_EXTRA];
00049 
00050 
00051 /* Macro to add extra attribute */
00052 #define ADD_EXTRA_AVPAIR(_attrs, _attr, _val, _len)         \
00053     do {                      \
00054    if ((_len) != 0) {                  \
00055        if ((_len) == -1) {                \
00056       if (_attrs[_attr].t != PW_TYPE_INTEGER) {    \
00057           LM_ERR("attribute %d is not of type integer\n",   \
00058             _attrs[_attr].v);          \
00059           goto err;                 \
00060       }                    \
00061        }                      \
00062        if (!rc_avpair_add( rh, &send, _attrs[_attr].v, _val, _len, 0)) { \
00063       LM_ERR("failed to add %s, %d\n", _attrs[_attr].n, _attr); \
00064       goto err;                  \
00065        }                      \
00066    }                       \
00067     }while(0)
00068 
00069 
00070 static inline int extract_avp(VALUE_PAIR* vp, unsigned short *flags,
00071                int_str *name, int_str *value)
00072 {
00073    static str names, values;
00074    unsigned int r;
00075    char *p;
00076    char *end;
00077 
00078    /* empty? */
00079    if (vp->lvalue==0 || vp->strvalue==0)
00080       goto error;
00081 
00082    p = vp->strvalue;
00083    end = vp->strvalue + vp->lvalue;
00084 
00085    LM_DBG("string is <%.*s>\n", (int)(long)(end-p), p);
00086 
00087    /* get name */
00088    if (*p!='#') {
00089       /* name AVP */
00090       *flags |= AVP_NAME_STR;
00091       names.s = p;
00092    } else {
00093       names.s = ++p;
00094    }
00095 
00096    names.len = 0;
00097    while( p<end && *p!=':' && *p!='#')
00098       p++;
00099    if (names.s==p || p==end) {
00100       LM_ERR("empty AVP name\n");
00101       goto error;
00102    }
00103    names.len = p - names.s;
00104    LM_DBG("AVP name is <%.*s>\n", names.len, names.s);
00105 
00106    /* get value */
00107    if (*p!='#') {
00108       /* string value */
00109       *flags |= AVP_VAL_STR;
00110    }
00111    values.s = ++p;
00112    values.len = end-values.s;
00113    if (values.len==0) {
00114       LM_ERR("empty AVP value\n");
00115       goto error;
00116    }
00117    LM_DBG("AVP val is <%.*s>\n", values.len, values.s);
00118 
00119    if ( !((*flags)&AVP_NAME_STR) ) {
00120       /* convert name to id*/
00121       if (str2int(&names,&r)!=0 ) {
00122          LM_ERR("invalid AVP ID '%.*s'\n", names.len,names.s);
00123          goto error;
00124       }
00125       name->n = (int)r;
00126    } else {
00127       name->s = names;
00128    }
00129 
00130    if ( !((*flags)&AVP_VAL_STR) ) {
00131       /* convert value to integer */
00132       if (str2int(&values,&r)!=0 ) {
00133          LM_ERR("invalid AVP numrical value '%.*s'\n", values.len,values.s);
00134          goto error;
00135       }
00136       value->n = (int)r;
00137    } else {
00138       value->s = values;
00139    }
00140 
00141    return 0;
00142 error:
00143    return -1;
00144 }
00145 
00146 
00147 /*
00148  * Generate AVPs from the database result
00149  */
00150 static int generate_avps(VALUE_PAIR* received)
00151 {
00152    int_str name, val;
00153    unsigned short flags;
00154    VALUE_PAIR *vp;
00155 
00156    vp = received;
00157 
00158    LM_DBG("getting SIP AVPs from avpair %d\n",  attrs[A_SIP_AVP].v);
00159 
00160    for( ; (vp=rc_avpair_get(vp,attrs[A_SIP_AVP].v,0)) ; vp=vp->next) {
00161       flags = 0;
00162       if (extract_avp( vp, &flags, &name, &val)!=0 )
00163          continue;
00164       if (add_avp( flags, name, val) < 0) {
00165          LM_ERR("unable to create a new AVP\n");
00166       } else {
00167          LM_DBG("AVP '%.*s'/%d='%.*s'/%d has been added\n",
00168             (flags&AVP_NAME_STR)?name.s.len:4,
00169             (flags&AVP_NAME_STR)?name.s.s:"null",
00170             (flags&AVP_NAME_STR)?0:name.n,
00171             (flags&AVP_VAL_STR)?val.s.len:4,
00172             (flags&AVP_VAL_STR)?val.s.s:"null",
00173             (flags&AVP_VAL_STR)?0:val.n );
00174       }
00175    }
00176 
00177    return 0;
00178 }
00179 
00180 
00181 static int add_cisco_vsa(VALUE_PAIR** send, struct sip_msg* msg)
00182 {
00183    str callid;
00184 
00185    if (!msg->callid && parse_headers(msg, HDR_CALLID_F, 0) == -1) {
00186       LM_ERR("cannot parse Call-ID header field\n");
00187       return -1;
00188    }
00189 
00190    if (!msg->callid) {
00191       LM_ERR("call-ID header field not found\n");
00192       return -1;
00193    }
00194 
00195    callid.len = msg->callid->body.len + 8;
00196    callid.s = pkg_malloc(callid.len);
00197    if (callid.s == NULL) {
00198       LM_ERR("no pkg memory left\n");
00199       return -1;
00200    }
00201 
00202    memcpy(callid.s, "call-id=", 8);
00203    memcpy(callid.s + 8, msg->callid->body.s, msg->callid->body.len);
00204 
00205    if (rc_avpair_add(rh, send, attrs[A_CISCO_AVPAIR].v, callid.s,
00206          callid.len, VENDOR(attrs[A_CISCO_AVPAIR].v)) == 0) {
00207       LM_ERR("unable to add Cisco-AVPair attribute\n");
00208       pkg_free(callid.s);
00209       return -1;
00210    }
00211 
00212    pkg_free(callid.s);
00213    return 0;
00214 }
00215 
00216 
00217 /*
00218  * This function creates and submits radius authentication request as per
00219  * draft-sterman-aaa-sip-00.txt.  In addition, _user parameter is included
00220  * in the request as value of a SER specific attribute type SIP-URI-User,
00221  * which can be be used as a check item in the request.  Service type of
00222  * the request is Authenticate-Only.
00223  */
00224 int radius_authorize_sterman(struct sip_msg* _msg, dig_cred_t* _cred, str* _method, str* _user) 
00225 {
00226    static char msg[4096];
00227    VALUE_PAIR *send, *received;
00228    uint32_t service;
00229    str method, user, user_name;
00230    str *ruri;
00231    int extra_cnt, offset, i;
00232       
00233    send = received = 0;
00234 
00235    if (!(_cred && _method && _user)) {
00236       LM_ERR("invalid parameter value\n");
00237       return -1;
00238    }
00239 
00240    method = *_method;
00241    user = *_user;
00242    
00243    /*
00244     * Add all the user digest parameters according to the qop defined.
00245     * Most devices tested only offer support for the simplest digest.
00246     */
00247    if (_cred->username.domain.len) {
00248       if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, _cred->username.whole.s, _cred->username.whole.len, 0)) {
00249          LM_ERR("unable to add User-Name attribute\n");
00250          goto err;
00251       }
00252    } else {
00253       user_name.len = _cred->username.user.len + _cred->realm.len + 1;
00254       user_name.s = pkg_malloc(user_name.len);
00255       if (!user_name.s) {
00256          LM_ERR("no pkg memory left\n");
00257          return -3;
00258       }
00259       memcpy(user_name.s, _cred->username.whole.s, _cred->username.whole.len);
00260       user_name.s[_cred->username.whole.len] = '@';
00261       memcpy(user_name.s + _cred->username.whole.len + 1, _cred->realm.s,
00262          _cred->realm.len);
00263       if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, user_name.s,
00264       user_name.len, 0)) {
00265          LM_ERR("unable to add User-Name attribute\n");
00266          pkg_free(user_name.s);
00267          goto err;
00268       }
00269       pkg_free(user_name.s);
00270    }
00271 
00272    if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_USER_NAME].v, 
00273    _cred->username.whole.s, _cred->username.whole.len, 0)) {
00274       LM_ERR("unable to add Digest-User-Name attribute\n");
00275       goto err;
00276    }
00277 
00278    if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_REALM].v, _cred->realm.s,
00279    _cred->realm.len, 0)) {
00280       LM_ERR("unable to add Digest-Realm attribute\n");
00281       goto err;
00282    }
00283    if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_NONCE].v, _cred->nonce.s,
00284    _cred->nonce.len, 0)) {
00285       LM_ERR("unable to add Digest-Nonce attribute\n");
00286       goto err;
00287    }
00288 
00289    if (use_ruri_flag < 0 || isflagset(_msg, use_ruri_flag) != 1) {
00290       ruri = &_cred->uri;
00291    } else {
00292       ruri = GET_RURI(_msg);
00293    }
00294    if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_URI].v, ruri->s,
00295    ruri->len, 0)) {
00296       LM_ERR("unable to add Digest-URI attribute\n");
00297       goto err;
00298    }
00299 
00300    if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_METHOD].v, method.s,
00301    method.len, 0)) {
00302       LM_ERR("unable to add Digest-Method attribute\n");
00303       goto err;
00304    }
00305    
00306    /* 
00307     * Add the additional authentication fields according to the QOP.
00308     */
00309    if (_cred->qop.qop_parsed == QOP_AUTH) {
00310       if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_QOP].v, "auth", 4, 0)) {
00311          LM_ERR("unable to add Digest-QOP attribute\n");
00312          goto err;
00313       }
00314       if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_NONCE_COUNT].v, 
00315       _cred->nc.s, _cred->nc.len, 0)) {
00316          LM_ERR("unable to add Digest-CNonce-Count attribute\n");
00317          goto err;
00318       }
00319       if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_CNONCE].v, 
00320       _cred->cnonce.s, _cred->cnonce.len, 0)) {
00321          LM_ERR("unable to add Digest-CNonce attribute\n");
00322          goto err;
00323       }
00324    } else if (_cred->qop.qop_parsed == QOP_AUTHINT) {
00325       if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_QOP].v,
00326       "auth-int", 8, 0)) {
00327          LM_ERR("unable to add Digest-QOP attribute\n");
00328          goto err;
00329       }
00330       if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_NONCE_COUNT].v,
00331       _cred->nc.s, _cred->nc.len, 0)) {
00332          LM_ERR("unable to add Digest-Nonce-Count attribute\n");
00333          goto err;
00334       }
00335       if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_CNONCE].v,
00336       _cred->cnonce.s, _cred->cnonce.len, 0)) {
00337          LM_ERR("unable to add Digest-CNonce attribute\n");
00338          goto err;
00339       }
00340       if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_BODY_DIGEST].v, 
00341       _cred->opaque.s, _cred->opaque.len, 0)) {
00342          LM_ERR("unable to add Digest-Body-Digest attribute\n");
00343          goto err;
00344       }
00345       
00346    } else  {
00347       /* send nothing for qop == "" */
00348    }
00349 
00350    /* Add the response... What to calculate against... */
00351    if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_RESPONSE].v, 
00352    _cred->response.s, _cred->response.len, 0)) {
00353       LM_ERR("unable to add Digest-Response attribute\n");
00354       goto err;
00355    }
00356 
00357    /* Indicate the service type, Authenticate only in our case */
00358    service = vals[V_SIP_SESSION].v;
00359    if (!rc_avpair_add(rh, &send, attrs[A_SERVICE_TYPE].v, &service, -1, 0)) {
00360       LM_ERR("unable to add Service-Type attribute\n");
00361       goto err;
00362    }
00363 
00364    /* Add SIP URI as a check item */
00365    if (!rc_avpair_add(rh,&send,attrs[A_SIP_URI_USER].v,user.s,user.len,0)) {
00366       LM_ERR("unable to add Sip-URI-User attribute\n");
00367       goto err;
00368    }
00369 
00370    if (attrs[A_CISCO_AVPAIR].n != NULL) {
00371       if (add_cisco_vsa(&send, _msg)) {
00372          goto err;
00373       }
00374    }
00375 
00376    /* Add extra attributes */
00377    extra_cnt = extra2strar(auth_extra, _msg, val_arr);
00378    if (extra_cnt == -1) {
00379        LM_ERR("in getting values of extra attributes\n");
00380        goto err;
00381    }
00382    offset = A_MAX;
00383    for (i = 0; i < extra_cnt; i++) {
00384        if (val_arr[i].len == -1) {
00385       /* Add integer attribute */
00386       ADD_EXTRA_AVPAIR(attrs, offset+i,
00387              &(val_arr[i].s), val_arr[i].len );
00388        } else {
00389       /* Add string attribute */
00390       ADD_EXTRA_AVPAIR(attrs, offset+i,
00391              val_arr[i].s, val_arr[i].len );
00392        }
00393    }
00394 
00395    /* Send request */
00396    if ((i = rc_auth(rh, SIP_PORT, send, &received, msg)) == OK_RC) {
00397       LM_DBG("Success\n");
00398       rc_avpair_free(send);
00399       send = 0;
00400 
00401       generate_avps(received);
00402 
00403       rc_avpair_free(received);
00404       return 1;
00405    } else {
00406 #ifdef REJECT_RC
00407                 if (i == REJECT_RC) {
00408                         LM_DBG("Failure\n");
00409                         goto err;
00410                 }
00411 #endif 
00412       LM_ERR("authorization failed\n");
00413    }
00414 
00415  err:
00416    if (send) rc_avpair_free(send);
00417    if (received) rc_avpair_free(received);
00418    return -1;
00419 }

Generated on Thu May 24 14:00:31 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6