Asterisk - The Open Source Telephony Project  21.4.1
cel_radius.c
Go to the documentation of this file.
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  */
18 
19 /*! \file
20  *
21  * \brief RADIUS CEL Support
22  * \author Philippe Sultan
23  * The Radius Client Library - http://developer.berlios.de/projects/radiusclient-ng/
24  * \ingroup cel_drivers
25  */
26 
27 /*** MODULEINFO
28  <depend>radius</depend>
29  <support_level>extended</support_level>
30  ***/
31 
32 #include "asterisk.h"
33 
34 #include RADIUS_HEADER_STR
35 
36 #include "asterisk/channel.h"
37 #include "asterisk/cel.h"
38 #include "asterisk/module.h"
39 #include "asterisk/logger.h"
40 #include "asterisk/utils.h"
41 #include "asterisk/options.h"
42 
43 /*! ISO 8601 standard format */
44 #define DATE_FORMAT "%Y-%m-%d %T %z"
45 
46 #define VENDOR_CODE 22736
47 
48 enum {
49  PW_AST_ACCT_CODE = 101,
50  PW_AST_CIDNUM = 102,
51  PW_AST_CIDNAME = 103,
52  PW_AST_CIDANI = 104,
53  PW_AST_CIDRDNIS = 105,
54  PW_AST_CIDDNID = 106,
55  PW_AST_EXTEN = 107,
56  PW_AST_CONTEXT = 108,
57  PW_AST_CHANNAME = 109,
58  PW_AST_APPNAME = 110,
59  PW_AST_APPDATA = 111,
60  PW_AST_EVENT_TIME = 112,
61  PW_AST_AMA_FLAGS = 113,
62  PW_AST_UNIQUE_ID = 114,
63  PW_AST_USER_NAME = 115,
64  PW_AST_LINKED_ID = 116,
65 };
66 
67 enum {
68  /*! Log dates and times in UTC */
70  /*! Log Unique ID */
72  /*! Log User Field */
74 };
75 
76 static char *cel_config = "cel.conf";
77 
78 #ifdef FREERADIUS_CLIENT
79 static char radiuscfg[PATH_MAX] = "/etc/radiusclient/radiusclient.conf";
80 #else
81 static char radiuscfg[PATH_MAX] = "/etc/radiusclient-ng/radiusclient.conf";
82 #endif
83 
85 
86 static rc_handle *rh = NULL;
87 
88 #define RADIUS_BACKEND_NAME "CEL Radius Logging"
89 
90 #define ADD_VENDOR_CODE(x,y) (rc_avpair_add(rh, send, x, (void *)y, strlen(y), VENDOR_CODE))
91 
92 static int build_radius_record(VALUE_PAIR **send, struct ast_cel_event_record *record)
93 {
94  int recordtype = PW_STATUS_STOP;
95  struct ast_tm tm;
96  char timestr[128];
97  char *amaflags;
98 
99  if (!rc_avpair_add(rh, send, PW_ACCT_STATUS_TYPE, &recordtype, 0, 0)) {
100  return -1;
101  }
102  /* Account code */
103  if (!ADD_VENDOR_CODE(PW_AST_ACCT_CODE, record->account_code)) {
104  return -1;
105  }
106  /* Source */
107  if (!ADD_VENDOR_CODE(PW_AST_CIDNUM, record->caller_id_num)) {
108  return -1;
109  }
110  /* Destination */
111  if (!ADD_VENDOR_CODE(PW_AST_EXTEN, record->extension)) {
112  return -1;
113  }
114  /* Destination context */
115  if (!ADD_VENDOR_CODE(PW_AST_CONTEXT, record->context)) {
116  return -1;
117  }
118  /* Caller ID */
119  if (!ADD_VENDOR_CODE(PW_AST_CIDNAME, record->caller_id_name)) {
120  return -1;
121  }
122  /* Caller ID ani */
123  if (!ADD_VENDOR_CODE(PW_AST_CIDANI, record->caller_id_ani)) {
124  return -1;
125  }
126  /* Caller ID rdnis */
127  if (!ADD_VENDOR_CODE(PW_AST_CIDRDNIS, record->caller_id_rdnis)) {
128  return -1;
129  }
130  /* Caller ID dnid */
131  if (!ADD_VENDOR_CODE(PW_AST_CIDDNID, record->caller_id_dnid)) {
132  return -1;
133  }
134  /* Channel */
135  if (!ADD_VENDOR_CODE(PW_AST_CHANNAME, record->channel_name)) {
136  return -1;
137  }
138  /* Last Application */
139  if (!ADD_VENDOR_CODE(PW_AST_APPNAME, record->application_name)) {
140  return -1;
141  }
142  /* Last Data */
143  if (!ADD_VENDOR_CODE(PW_AST_APPDATA, record->application_data)) {
144  return -1;
145  }
146  /* Event Time */
147  ast_localtime(&record->event_time, &tm,
148  ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME) ? "GMT" : NULL);
149  ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
150  if (!rc_avpair_add(rh, send, PW_AST_EVENT_TIME, timestr, strlen(timestr), VENDOR_CODE)) {
151  return -1;
152  }
153  /* AMA Flags */
154  amaflags = ast_strdupa(ast_channel_amaflags2string(record->amaflag));
155  if (!rc_avpair_add(rh, send, PW_AST_AMA_FLAGS, amaflags, strlen(amaflags), VENDOR_CODE)) {
156  return -1;
157  }
158  if (ast_test_flag(&global_flags, RADIUS_FLAG_LOGUNIQUEID)) {
159  /* Unique ID */
160  if (!ADD_VENDOR_CODE(PW_AST_UNIQUE_ID, record->unique_id)) {
161  return -1;
162  }
163  }
164  /* LinkedID */
165  if (!ADD_VENDOR_CODE(PW_AST_LINKED_ID, record->linked_id)) {
166  return -1;
167  }
168  /* Setting Acct-Session-Id & User-Name attributes for proper generation
169  of Acct-Unique-Session-Id on server side */
170  /* Channel */
171  if (!rc_avpair_add(rh, send, PW_USER_NAME, (void *)record->channel_name,
172  strlen(record->channel_name), 0)) {
173  return -1;
174  }
175  return 0;
176 }
177 
178 static void radius_log(struct ast_event *event)
179 {
180  int result = ERROR_RC;
181  VALUE_PAIR *send = NULL;
182  struct ast_cel_event_record record = {
184  };
185 
186  if (ast_cel_fill_record(event, &record)) {
187  return;
188  }
189 
190  if (build_radius_record(&send, &record)) {
191  ast_debug(1, "Unable to create RADIUS record. CEL not recorded!\n");
192  goto return_cleanup;
193  }
194 
195  result = rc_acct(rh, 0, send);
196  if (result != OK_RC) {
197  ast_log(LOG_ERROR, "Failed to record Radius CEL record!\n");
198  }
199 
200 return_cleanup:
201  if (send) {
202  rc_avpair_free(send);
203  }
204 }
205 
206 static int unload_module(void)
207 {
208  ast_cel_backend_unregister(RADIUS_BACKEND_NAME);
209  if (rh) {
210  rc_destroy(rh);
211  rh = NULL;
212  }
214 }
215 
216 static int load_module(void)
217 {
218  struct ast_config *cfg;
219  struct ast_flags config_flags = { 0 };
220  const char *tmp;
221 
222  if ((cfg = ast_config_load(cel_config, config_flags))) {
223  ast_set2_flag(&global_flags, ast_true(ast_variable_retrieve(cfg, "radius", "usegmtime")), RADIUS_FLAG_USEGMTIME);
224  if ((tmp = ast_variable_retrieve(cfg, "radius", "radiuscfg"))) {
225  ast_copy_string(radiuscfg, tmp, sizeof(radiuscfg));
226  }
227  ast_config_destroy(cfg);
228  } else {
230  }
231 
232  /* read radiusclient-ng config file */
233  if (!(rh = rc_read_config(radiuscfg))) {
234  ast_log(LOG_NOTICE, "Cannot load radiusclient-ng configuration file %s.\n", radiuscfg);
236  }
237 
238  /* read radiusclient-ng dictionaries */
239  if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary"))) {
240  ast_log(LOG_NOTICE, "Cannot load radiusclient-ng dictionary file.\n");
241  rc_destroy(rh);
242  rh = NULL;
244  }
245 
246  if (ast_cel_backend_register(RADIUS_BACKEND_NAME, radius_log)) {
247  rc_destroy(rh);
248  rh = NULL;
250  } else {
252  }
253 }
254 
255 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "RADIUS CEL Backend",
256  .support_level = AST_MODULE_SUPPORT_EXTENDED,
257  .load = load_module,
258  .unload = unload_module,
259  .load_pri = AST_MODPRI_CDR_DRIVER,
260  .requires = "cel",
261 );
Helper struct for getting the fields out of a CEL event.
Definition: cel.h:138
An event.
Definition: event.c:81
A container that holds all config-related information.
Definition: cel_custom.c:53
Asterisk main include file. File version handling, generic pbx functions.
Call Event Logging API.
int ast_cel_backend_register(const char *name, ast_cel_backend_cb backend_callback)
Register a CEL backend.
Definition: cel.c:1781
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
Definition: localtime.c:1739
Definition: astman.c:222
const char * ast_channel_amaflags2string(enum ama_flags flags)
Convert the enum representation of an AMA flag to a string representation.
Definition: channel.c:4373
Utility functions.
#define ast_config_load(filename, flags)
Load a config file.
General Asterisk PBX channel definitions.
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: astmm.h:298
uint32_t version
struct ABI version
Definition: cel.h:148
#define ast_debug(level,...)
Log a DEBUG message.
int ast_cel_backend_unregister(const char *name)
Unregister a CEL backend.
Definition: cel.c:1769
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Definition: utils.c:2199
Support for logging to various files, console and syslog Configuration in file logger.conf.
Module has failed to load, may be in an inconsistent state.
Definition: module.h:78
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
Definition: localtime.c:2524
#define AST_CEL_EVENT_RECORD_VERSION
struct ABI version
Definition: cel.h:143
Structure used to handle boolean flags.
Definition: utils.h:199
static struct ast_flags global_flags[1]
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:425
Options provided by main asterisk program.
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
Definition: extconf.c:1289
#define ASTERISK_GPL_KEY
The text the key() function should return.
Definition: module.h:46
#define DATE_FORMAT
Definition: cel_radius.c:44
Asterisk module definitions.
int ast_cel_fill_record(const struct ast_event *event, struct ast_cel_event_record *r)
Fill in an ast_cel_event_record from a CEL event.
Definition: cel.c:821