cel_radius.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief RADIUS CEL Support
00022  * \author Philippe Sultan
00023  * The Radius Client Library - http://developer.berlios.de/projects/radiusclient-ng/
00024  *
00025  * \arg See also \ref AstCEL
00026  * \ingroup cel_drivers
00027  */
00028 
00029 /*** MODULEINFO
00030    <depend>radius</depend>
00031    <support_level>extended</support_level>
00032  ***/
00033 
00034 #include "asterisk.h"
00035 
00036 ASTERISK_FILE_VERSION(__FILE__, "$Rev: 419592 $")
00037 
00038 #ifdef FREERADIUS_CLIENT
00039 #include <freeradius-client.h>
00040 #else
00041 #include <radiusclient-ng.h>
00042 #endif
00043 
00044 #include "asterisk/channel.h"
00045 #include "asterisk/cel.h"
00046 #include "asterisk/module.h"
00047 #include "asterisk/logger.h"
00048 #include "asterisk/utils.h"
00049 #include "asterisk/options.h"
00050 
00051 /*! ISO 8601 standard format */
00052 #define DATE_FORMAT "%Y-%m-%d %T %z"
00053 
00054 #define VENDOR_CODE           22736
00055 
00056 enum {
00057    PW_AST_ACCT_CODE =    101,
00058    PW_AST_CIDNUM =       102,
00059    PW_AST_CIDNAME =      103,
00060    PW_AST_CIDANI =       104,
00061    PW_AST_CIDRDNIS =     105,
00062    PW_AST_CIDDNID =      106,
00063    PW_AST_EXTEN =        107,
00064    PW_AST_CONTEXT =      108,
00065    PW_AST_CHANNAME =     109,
00066    PW_AST_APPNAME =      110,
00067    PW_AST_APPDATA =      111,
00068    PW_AST_EVENT_TIME =   112,
00069    PW_AST_AMA_FLAGS =    113,
00070    PW_AST_UNIQUE_ID =    114,
00071    PW_AST_USER_NAME =    115,
00072    PW_AST_LINKED_ID =    116,
00073 };
00074 
00075 enum {
00076    /*! Log dates and times in UTC */
00077    RADIUS_FLAG_USEGMTIME = (1 << 0),
00078    /*! Log Unique ID */
00079    RADIUS_FLAG_LOGUNIQUEID = (1 << 1),
00080    /*! Log User Field */
00081    RADIUS_FLAG_LOGUSERFIELD = (1 << 2)
00082 };
00083 
00084 static char *cel_config = "cel.conf";
00085 
00086 #ifdef FREERADIUS_CLIENT
00087 static char radiuscfg[PATH_MAX] = "/etc/radiusclient/radiusclient.conf";
00088 #else
00089 static char radiuscfg[PATH_MAX] = "/etc/radiusclient-ng/radiusclient.conf";
00090 #endif
00091 
00092 static struct ast_flags global_flags = { RADIUS_FLAG_USEGMTIME | RADIUS_FLAG_LOGUNIQUEID | RADIUS_FLAG_LOGUSERFIELD };
00093 
00094 static rc_handle *rh = NULL;
00095 
00096 #define RADIUS_BACKEND_NAME "CEL Radius Logging"
00097 
00098 #define ADD_VENDOR_CODE(x,y) (rc_avpair_add(rh, send, x, &y, strlen(y), VENDOR_CODE))
00099 
00100 static int build_radius_record(VALUE_PAIR **send, struct ast_cel_event_record *record)
00101 {
00102    int recordtype = PW_STATUS_STOP;
00103    struct ast_tm tm;
00104    char timestr[128];
00105    char *amaflags;
00106 
00107    if (!rc_avpair_add(rh, send, PW_ACCT_STATUS_TYPE, &recordtype, 0, 0)) {
00108       return -1;
00109    }
00110    /* Account code */
00111    if (!ADD_VENDOR_CODE(PW_AST_ACCT_CODE, record->account_code)) {
00112       return -1;
00113    }
00114    /* Source */
00115    if (!ADD_VENDOR_CODE(PW_AST_CIDNUM, record->caller_id_num)) {
00116       return -1;
00117    }
00118    /* Destination */
00119    if (!ADD_VENDOR_CODE(PW_AST_EXTEN, record->extension)) {
00120       return -1;
00121    }
00122    /* Destination context */
00123    if (!ADD_VENDOR_CODE(PW_AST_CONTEXT, record->context)) {
00124       return -1;
00125    }
00126    /* Caller ID */
00127    if (!ADD_VENDOR_CODE(PW_AST_CIDNAME, record->caller_id_name)) {
00128       return -1;
00129    }
00130    /* Caller ID ani */
00131    if (!ADD_VENDOR_CODE(PW_AST_CIDANI, record->caller_id_ani)) {
00132       return -1;
00133    }
00134    /* Caller ID rdnis */
00135    if (!ADD_VENDOR_CODE(PW_AST_CIDRDNIS, record->caller_id_rdnis)) {
00136       return -1;
00137    }
00138    /* Caller ID dnid */
00139    if (!ADD_VENDOR_CODE(PW_AST_CIDDNID, record->caller_id_dnid)) {
00140       return -1;
00141    }
00142    /* Channel */
00143    if (!ADD_VENDOR_CODE(PW_AST_CHANNAME, record->channel_name)) {
00144       return -1;
00145    }
00146    /* Last Application */
00147    if (!ADD_VENDOR_CODE(PW_AST_APPNAME, record->application_name)) {
00148       return -1;
00149    }
00150    /* Last Data */
00151    if (!ADD_VENDOR_CODE(PW_AST_APPDATA, record->application_data)) {
00152       return -1;
00153    }
00154    /* Event Time */
00155    ast_localtime(&record->event_time, &tm,
00156       ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME) ? "GMT" : NULL);
00157    ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
00158    if (!rc_avpair_add(rh, send, PW_AST_EVENT_TIME, timestr, strlen(timestr), VENDOR_CODE)) {
00159       return -1;
00160    }
00161    /* AMA Flags */
00162    amaflags = ast_strdupa(ast_channel_amaflags2string(record->amaflag));
00163    if (!rc_avpair_add(rh, send, PW_AST_AMA_FLAGS, amaflags, strlen(amaflags), VENDOR_CODE)) {
00164       return -1;
00165    }
00166    if (ast_test_flag(&global_flags, RADIUS_FLAG_LOGUNIQUEID)) {
00167       /* Unique ID */
00168       if (!ADD_VENDOR_CODE(PW_AST_UNIQUE_ID, record->unique_id)) {
00169          return -1;
00170       }
00171    }
00172    /* LinkedID */
00173    if (!ADD_VENDOR_CODE(PW_AST_LINKED_ID, record->linked_id)) {
00174       return -1;
00175    }
00176    /* Setting Acct-Session-Id & User-Name attributes for proper generation
00177       of Acct-Unique-Session-Id on server side */
00178    /* Channel */
00179    if (!rc_avpair_add(rh, send, PW_USER_NAME, &record->channel_name,
00180          strlen(record->channel_name), 0)) {
00181       return -1;
00182    }
00183    return 0;
00184 }
00185 
00186 static void radius_log(struct ast_event *event)
00187 {
00188    int result = ERROR_RC;
00189    VALUE_PAIR *send = NULL;
00190    struct ast_cel_event_record record = {
00191       .version = AST_CEL_EVENT_RECORD_VERSION,
00192    };
00193 
00194    if (ast_cel_fill_record(event, &record)) {
00195       return;
00196    }
00197 
00198    if (build_radius_record(&send, &record)) {
00199       ast_debug(1, "Unable to create RADIUS record. CEL not recorded!\n");
00200       goto return_cleanup;
00201    }
00202 
00203    result = rc_acct(rh, 0, send);
00204    if (result != OK_RC) {
00205       ast_log(LOG_ERROR, "Failed to record Radius CEL record!\n");
00206    }
00207 
00208 return_cleanup:
00209    if (send) {
00210       rc_avpair_free(send);
00211    }
00212 }
00213 
00214 static int unload_module(void)
00215 {
00216    ast_cel_backend_unregister(RADIUS_BACKEND_NAME);
00217    if (rh) {
00218       rc_destroy(rh);
00219       rh = NULL;
00220    }
00221    return AST_MODULE_LOAD_SUCCESS;
00222 }
00223 
00224 static int load_module(void)
00225 {
00226    struct ast_config *cfg;
00227    struct ast_flags config_flags = { 0 };
00228    const char *tmp;
00229 
00230    if ((cfg = ast_config_load(cel_config, config_flags))) {
00231       ast_set2_flag(&global_flags, ast_true(ast_variable_retrieve(cfg, "radius", "usegmtime")), RADIUS_FLAG_USEGMTIME);
00232       if ((tmp = ast_variable_retrieve(cfg, "radius", "radiuscfg"))) {
00233          ast_copy_string(radiuscfg, tmp, sizeof(radiuscfg));
00234       }
00235       ast_config_destroy(cfg);
00236    } else {
00237       return AST_MODULE_LOAD_DECLINE;
00238    }
00239 
00240    /*
00241     * start logging
00242     *
00243     * NOTE: Yes this causes a slight memory leak if the module is
00244     * unloaded.  However, it is better than a crash if cdr_radius
00245     * and cel_radius are both loaded.
00246     */
00247    tmp = ast_strdup("asterisk");
00248    if (tmp) {
00249       rc_openlog((char *) tmp);
00250    }
00251 
00252    /* read radiusclient-ng config file */
00253    if (!(rh = rc_read_config(radiuscfg))) {
00254       ast_log(LOG_NOTICE, "Cannot load radiusclient-ng configuration file %s.\n", radiuscfg);
00255       return AST_MODULE_LOAD_DECLINE;
00256    }
00257 
00258    /* read radiusclient-ng dictionaries */
00259    if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary"))) {
00260       ast_log(LOG_NOTICE, "Cannot load radiusclient-ng dictionary file.\n");
00261       rc_destroy(rh);
00262       rh = NULL;
00263       return AST_MODULE_LOAD_DECLINE;
00264    }
00265 
00266    if (ast_cel_backend_register(RADIUS_BACKEND_NAME, radius_log)) {
00267       rc_destroy(rh);
00268       rh = NULL;
00269       return AST_MODULE_LOAD_DECLINE;
00270    } else {
00271       return AST_MODULE_LOAD_SUCCESS;
00272    }
00273 }
00274 
00275 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "RADIUS CEL Backend",
00276    .support_level = AST_MODULE_SUPPORT_EXTENDED,
00277    .load = load_module,
00278    .unload = unload_module,
00279    .load_pri = AST_MODPRI_CDR_DRIVER,
00280 );

Generated on Thu Apr 16 06:27:18 2015 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6