avp_radius.c

00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2004 Juha Heinanen <jh@tutpro.com>
00005  * Copyright (C) 2004 FhG Fokus
00006  *
00007  * This file is part of ser, a free SIP server.
00008  *
00009  * ser is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version
00013  *
00014  * For a license to use the ser software under conditions
00015  * other than those described here, or to purchase support for this
00016  * software, please contact iptel.org by e-mail at the following addresses:
00017  *    info@iptel.org
00018  *
00019  * ser is distributed in the hope that it will be useful,
00020  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00021  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022  * GNU General Public License for more details.
00023  *
00024  * You should have received a copy of the GNU General Public License
00025  * along with this program; if not, write to the Free Software
00026  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00027  */
00028 
00029 #ifdef RADIUSCLIENT_NG_4
00030 #  include <radiusclient.h>
00031 # else
00032 #  include <radiusclient-ng.h>
00033 #endif
00034 
00035 #include "../../rad_dict.h"
00036 #include "../../sr_module.h"
00037 #include "../../mem/mem.h"
00038 #include "../../parser/digest/digest_parser.h"
00039 #include "../../parser/digest/digest.h"
00040 #include "../../parser/parse_uri.h"
00041 #include "../../parser/parse_from.h"
00042 #include "../domain/domain.h"
00043 #include "../../usr_avp.h"
00044 #include "../../ut.h"
00045 #include "../../config.h"
00046 
00047 
00048 MODULE_VERSION
00049 
00050 
00051 static int mod_init(void);
00052 static int radius_load_attrs(struct sip_msg*, char*, char*);
00053 static int attrs_fixup(void**, int);
00054 
00055 static char *radius_config = "/usr/local/etc/radiusclient/radiusclient.conf";
00056 
00057 static void *rh;
00058 struct attr attrs[A_MAX];
00059 struct val vals[V_MAX];
00060 
00061 static domain_get_did_t dm_get_did = NULL;
00062 
00063 
00064 /*
00065  * Exported functions
00066  */
00067 static cmd_export_t cmds[] = {
00068     {"radius_load_attrs", radius_load_attrs, 2, attrs_fixup, REQUEST_ROUTE | FAILURE_ROUTE},
00069     {0, 0, 0, 0, 0}
00070 };
00071 
00072 
00073 /*
00074  * Exported parameters
00075  */
00076 static param_export_t params[] = {
00077     {"radius_config", PARAM_STRING, &radius_config },
00078     {0, 0, 0}
00079 };
00080 
00081 
00082 struct module_exports exports = {
00083     "avp_radius",
00084     cmds,      /* Exported commands */
00085     0,         /* RPC methods */
00086     params,    /* Exported parameters */
00087     mod_init,  /* module initialization function */
00088     0,         /* response function*/
00089     0,         /* destroy function */
00090     0,         /* oncancel function */
00091     0          /* per-child init function */
00092 };
00093 
00094 
00095 static int mod_init(void)
00096 {
00097     DICT_VENDOR *vend;
00098     memset(attrs, 0, sizeof(attrs));
00099     memset(vals, 0, sizeof(vals));
00100     
00101     attrs[A_USER_NAME].n        = "User-Name";
00102     attrs[A_SER_SERVICE_TYPE].n = "SER-Service-Type";
00103     attrs[A_SER_ATTR].n         = "SER-Attr";
00104     attrs[A_SER_DID].n          = "SER-DID";
00105     attrs[A_SER_URI_SCHEME].n   = "SER-Uri-Scheme";
00106     
00107     vals[V_GET_URI_ATTRS].n  = "Get-URI-Attrs";
00108     vals[V_GET_USER_ATTRS].n = "Get-User-Attrs";
00109 
00110          /* open log */
00111     rc_openlog("ser");
00112     
00113          /* read config */
00114     if ((rh = rc_read_config(radius_config)) == NULL) {
00115         LOG(L_ERR, "avp_radius: Error opening radius config file: %s\n",
00116             radius_config);
00117         return -1;
00118     }
00119     
00120          /* read dictionary */
00121     if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")) != 0) {
00122         LOG(L_ERR, "avp_radius: Error reading radius dictionary\n");
00123         return -1;
00124     }
00125     
00126     vend = rc_dict_findvend(rh, "iptelorg");
00127     if (vend == NULL) {
00128         ERR("RADIUS dictionary is missing required vendor 'iptelorg'\n");
00129         return -1;
00130     }
00131 
00132     INIT_AV(rh, attrs, vals, "avp", -1, -1);
00133     return 0;
00134 }
00135 
00136 
00137 static void attr_name_value(str* name, str* value, VALUE_PAIR* vp)
00138 {
00139     int i;
00140     
00141     for (i = 0; i < vp->lvalue; i++) {
00142         if (vp->strvalue[i] == ':' || vp->strvalue[i] == '=') {
00143             name->s = vp->strvalue;
00144             name->len = i;
00145             
00146             if (i == (vp->lvalue - 1)) {
00147                 value->s = (char*)0;
00148                 value->len = 0;
00149             } else {
00150                 value->s = vp->strvalue + i + 1;
00151                 value->len = vp->lvalue - i - 1;
00152             }
00153             return;
00154         }
00155     }
00156 
00157     name->len = value->len = 0;
00158     name->s = value->s = (char*)0;
00159 }
00160 
00161 
00162 /*
00163  * Generate AVPs from the database result
00164  */
00165 static int generate_avps(unsigned int flags, VALUE_PAIR* received)
00166 {
00167     int_str name, val;
00168     VALUE_PAIR *vp;
00169     
00170     vp = received;
00171     while ((vp = rc_avpair_get(vp, ATTRID(attrs[A_SER_ATTR].v), VENDOR(attrs[A_SER_ATTR].v)))) {
00172         attr_name_value(&name.s, &val.s, vp);
00173         if (name.s.len == 0) {
00174             ERR("Missing attribute name\n");
00175             return -1;
00176         }
00177 
00178         if (add_avp(flags | AVP_NAME_STR | AVP_VAL_STR, name, val) < 0) {
00179             ERR("Unable to create a new SER attribute\n");
00180             return -1;
00181         }
00182         vp = vp->next;
00183     }
00184     
00185     return 0;
00186 }
00187 
00188 
00189 static int load_user_attrs(struct sip_msg* msg, unsigned long flags, fparam_t* fp)
00190 {
00191     static char rad_msg[4096];
00192     str uid;
00193     UINT4 service;
00194     VALUE_PAIR* send, *received;
00195 
00196     send = NULL;
00197     received = NULL;
00198 
00199     if (get_str_fparam(&uid, msg, (fparam_t*)fp) < 0) {
00200         ERR("Unable to get UID\n");
00201         return -1;
00202     }
00203 
00204     service = vals[V_GET_USER_ATTRS].v;
00205 
00206     if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_USER_NAME].v), 
00207                        uid.s, uid.len,
00208                        VENDOR(attrs[A_USER_NAME].v))) {
00209         ERR("Error while adding A_USER_NAME\n");
00210         goto error;
00211     }
00212     
00213     if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SER_SERVICE_TYPE].v), 
00214                        &vals[V_GET_USER_ATTRS].v, -1, 
00215                        VENDOR(attrs[A_SER_SERVICE_TYPE].v))) {
00216         ERR("Error adding A_SERVICE_TYPE\n");
00217         goto error;
00218     }
00219 
00220 
00221     if (rc_auth(rh, 0, send, &received, rad_msg) != OK_RC) {
00222         DBG("load_user_attrs: Failure\n");
00223         goto error;
00224     }
00225 
00226     DBG("load_user_attrs: Success\n");
00227     rc_avpair_free(send);
00228 
00229     if (generate_avps(flags, received) < 0) {
00230         rc_avpair_free(received);
00231         goto error;
00232     }
00233 
00234     rc_avpair_free(received);
00235     return 1;
00236 
00237  error:
00238     if (send) rc_avpair_free(send);
00239     if (received) rc_avpair_free(send);
00240     return -1;
00241 }
00242 
00243 
00244 static int load_uri_attrs(struct sip_msg* msg, unsigned long flags, fparam_t* fp)
00245 {
00246     static char rad_msg[4096];
00247     struct sip_uri puri;
00248     str uri, did, scheme;
00249     UINT4 service;
00250     VALUE_PAIR* send, *received;
00251 
00252     send = NULL;
00253     received = NULL;
00254 
00255     if (get_str_fparam(&uri, msg, (fparam_t*)fp) != 0) {
00256         ERR("Unable to get URI\n");
00257         return -1;
00258     }
00259 
00260     if (parse_uri(uri.s, uri.len, &puri) < 0) {
00261         ERR("Error while parsing URI '%.*s'\n", uri.len, uri.s);
00262         return -1;
00263     }
00264 
00265     if (puri.host.len) {
00266         /* domain name is present */
00267         if (dm_get_did(&did, &puri.host) < 0) {
00268                 DBG("Cannot lookup DID for domain %.*s, using default value\n", puri.host.len, ZSW(puri.host.s));
00269                 did.s = DEFAULT_DID;
00270                 did.len = sizeof(DEFAULT_DID) - 1;
00271         }
00272     } else {
00273         /* domain name is missing -- can be caused by tel: URI */
00274         DBG("There is no domain name, using default value\n");
00275         did.s = DEFAULT_DID;
00276         did.len = sizeof(DEFAULT_DID) - 1;
00277     }
00278 
00279     uri_type_to_str(puri.type, &scheme);
00280     service = vals[V_GET_URI_ATTRS].v;
00281 
00282     if (scheme.len) {
00283         if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SER_URI_SCHEME].v), 
00284                            scheme.s, scheme.len,
00285                            VENDOR(attrs[A_SER_URI_SCHEME].v))) {
00286             ERR("Error while adding A_SER_URI_SCHEME\n");
00287             goto error;
00288         }
00289     }
00290 
00291     if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_USER_NAME].v), 
00292                        puri.user.s, puri.user.len,
00293                        VENDOR(attrs[A_USER_NAME].v))) {
00294         ERR("Error while adding A_USER_NAME\n");
00295         goto error;
00296     }
00297 
00298     if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SER_DID].v), 
00299                        did.s, did.len,
00300                        VENDOR(attrs[A_SER_DID].v))) {
00301         ERR("Error while adding A_SER_DID\n");
00302         goto error;
00303     }
00304     
00305     if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SER_SERVICE_TYPE].v), 
00306                        &vals[V_GET_URI_ATTRS].v, -1,
00307                        VENDOR(attrs[A_SER_SERVICE_TYPE].v))) {
00308         ERR("Error adding A_SERVICE_TYPE\n");
00309         goto error;
00310     }
00311 
00312     if (rc_auth(rh, 0, send, &received, rad_msg) != OK_RC) {
00313         DBG("load_uri_attrs: Failure\n");
00314         goto error;
00315     }
00316 
00317     DBG("load_uri_attrs: Success\n");
00318     rc_avpair_free(send);
00319 
00320     if (generate_avps(flags, received) < 0) {
00321         rc_avpair_free(received);
00322         goto error;
00323     }
00324 
00325     rc_avpair_free(received);
00326     return 1;
00327 
00328  error:
00329     if (send) rc_avpair_free(send);
00330     if (received) rc_avpair_free(send);
00331     return -1;
00332 }
00333 
00334 
00335 /*
00336  * Load user attributes
00337  */
00338 static int radius_load_attrs(struct sip_msg* msg, char* fl, char* fp)
00339 {
00340     unsigned long flags;
00341     
00342     flags = (unsigned long)fl;
00343 
00344     if (flags & AVP_CLASS_URI) {
00345         return load_uri_attrs(msg, flags, (fparam_t*)fp);
00346     } else {
00347         return load_user_attrs(msg, flags, (fparam_t*)fp);
00348     }
00349 }
00350 
00351 
00352 static int attrs_fixup(void** param, int param_no)
00353 {
00354     unsigned long flags;
00355     char* s;
00356     
00357     if (param_no == 1) {
00358              /* Determine the track and class of attributes to be loaded */
00359         s = (char*)*param;
00360         flags = 0;
00361         if (*s != '$' || (strlen(s) != 3)) {
00362             ERR("Invalid parameter value, $xy expected\n");
00363             return -1;
00364         }
00365         switch((s[1] << 8) + s[2]) {
00366         case 0x4655: /* $fu */
00367         case 0x6675:
00368         case 0x4675:
00369         case 0x6655:
00370             flags = AVP_TRACK_FROM | AVP_CLASS_USER;
00371             break;
00372             
00373         case 0x4652: /* $fr */
00374         case 0x6672:
00375         case 0x4672:
00376         case 0x6652:
00377             flags = AVP_TRACK_FROM | AVP_CLASS_URI;
00378             break;
00379             
00380         case 0x5455: /* $tu */
00381         case 0x7475:
00382         case 0x5475:
00383         case 0x7455:
00384             flags = AVP_TRACK_TO | AVP_CLASS_USER;
00385             break;
00386             
00387         case 0x5452: /* $tr */
00388         case 0x7472:
00389         case 0x5472:
00390         case 0x7452:
00391             flags = AVP_TRACK_TO | AVP_CLASS_URI;
00392             break;
00393             
00394         default:
00395             ERR("Invalid parameter value: '%s'\n", s);
00396             return -1;
00397         }
00398 
00399         if ((flags & AVP_CLASS_URI) && !dm_get_did) {
00400             dm_get_did = (domain_get_did_t)find_export("get_did", 0, 0);
00401             if (!dm_get_did) {
00402                 ERR("Domain module required but not found\n");
00403                 return -1;
00404             }
00405         }
00406         
00407         pkg_free(*param);
00408         *param = (void*)flags;
00409     } else if (param_no == 2) {
00410         return fixup_var_str_12(param, 2);
00411     }
00412     return 0;
00413 }