cel_radius.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  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. /*! \file
  19. *
  20. * \brief RADIUS CEL Support
  21. * \author Philippe Sultan
  22. * \extref The Radius Client Library - http://developer.berlios.de/projects/radiusclient-ng/
  23. *
  24. * \arg See also \ref AstCEL
  25. * \ingroup cel_drivers
  26. */
  27. /*** MODULEINFO
  28. <depend>radius</depend>
  29. <support_level>extended</support_level>
  30. <defaultenabled>no</defaultenabled>
  31. ***/
  32. #include "asterisk.h"
  33. ASTERISK_FILE_VERSION(__FILE__, "$Rev$")
  34. #include <radiusclient-ng.h>
  35. #include "asterisk/channel.h"
  36. #include "asterisk/cel.h"
  37. #include "asterisk/module.h"
  38. #include "asterisk/logger.h"
  39. #include "asterisk/utils.h"
  40. #include "asterisk/options.h"
  41. /*! ISO 8601 standard format */
  42. #define DATE_FORMAT "%Y-%m-%d %T %z"
  43. #define VENDOR_CODE 22736
  44. enum {
  45. PW_AST_ACCT_CODE = 101,
  46. PW_AST_CIDNUM = 102,
  47. PW_AST_CIDNAME = 103,
  48. PW_AST_CIDANI = 104,
  49. PW_AST_CIDRDNIS = 105,
  50. PW_AST_CIDDNID = 106,
  51. PW_AST_EXTEN = 107,
  52. PW_AST_CONTEXT = 108,
  53. PW_AST_CHANNAME = 109,
  54. PW_AST_APPNAME = 110,
  55. PW_AST_APPDATA = 111,
  56. PW_AST_EVENT_TIME = 112,
  57. PW_AST_AMA_FLAGS = 113,
  58. PW_AST_UNIQUE_ID = 114,
  59. PW_AST_USER_NAME = 115,
  60. PW_AST_LINKED_ID = 116,
  61. };
  62. enum {
  63. /*! Log dates and times in UTC */
  64. RADIUS_FLAG_USEGMTIME = (1 << 0),
  65. /*! Log Unique ID */
  66. RADIUS_FLAG_LOGUNIQUEID = (1 << 1),
  67. /*! Log User Field */
  68. RADIUS_FLAG_LOGUSERFIELD = (1 << 2)
  69. };
  70. static char *cel_config = "cel.conf";
  71. static char radiuscfg[PATH_MAX] = "/etc/radiusclient-ng/radiusclient.conf";
  72. static struct ast_flags global_flags = { RADIUS_FLAG_USEGMTIME | RADIUS_FLAG_LOGUNIQUEID | RADIUS_FLAG_LOGUSERFIELD };
  73. static rc_handle *rh = NULL;
  74. static struct ast_event_sub *event_sub = NULL;
  75. #define ADD_VENDOR_CODE(x,y) (rc_avpair_add(rh, send, x, &y, strlen(y), VENDOR_CODE))
  76. static int build_radius_record(VALUE_PAIR **send, struct ast_cel_event_record *record)
  77. {
  78. int recordtype = PW_STATUS_STOP;
  79. struct ast_tm tm;
  80. char timestr[128];
  81. char *amaflags;
  82. if (!rc_avpair_add(rh, send, PW_ACCT_STATUS_TYPE, &recordtype, 0, 0)) {
  83. return -1;
  84. }
  85. /* Account code */
  86. if (!ADD_VENDOR_CODE(PW_AST_ACCT_CODE, record->account_code)) {
  87. return -1;
  88. }
  89. /* Source */
  90. if (!ADD_VENDOR_CODE(PW_AST_CIDNUM, record->caller_id_num)) {
  91. return -1;
  92. }
  93. /* Destination */
  94. if (!ADD_VENDOR_CODE(PW_AST_EXTEN, record->extension)) {
  95. return -1;
  96. }
  97. /* Destination context */
  98. if (!ADD_VENDOR_CODE(PW_AST_CONTEXT, record->context)) {
  99. return -1;
  100. }
  101. /* Caller ID */
  102. if (!ADD_VENDOR_CODE(PW_AST_CIDNAME, record->caller_id_name)) {
  103. return -1;
  104. }
  105. /* Caller ID ani */
  106. if (!ADD_VENDOR_CODE(PW_AST_CIDANI, record->caller_id_ani)) {
  107. return -1;
  108. }
  109. /* Caller ID rdnis */
  110. if (!ADD_VENDOR_CODE(PW_AST_CIDRDNIS, record->caller_id_rdnis)) {
  111. return -1;
  112. }
  113. /* Caller ID dnid */
  114. if (!ADD_VENDOR_CODE(PW_AST_CIDDNID, record->caller_id_dnid)) {
  115. return -1;
  116. }
  117. /* Channel */
  118. if (!ADD_VENDOR_CODE(PW_AST_CHANNAME, record->channel_name)) {
  119. return -1;
  120. }
  121. /* Last Application */
  122. if (!ADD_VENDOR_CODE(PW_AST_APPNAME, record->application_name)) {
  123. return -1;
  124. }
  125. /* Last Data */
  126. if (!ADD_VENDOR_CODE(PW_AST_APPDATA, record->application_data)) {
  127. return -1;
  128. }
  129. /* Event Time */
  130. ast_localtime(&record->event_time, &tm,
  131. ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME) ? "GMT" : NULL);
  132. ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm);
  133. if (!rc_avpair_add(rh, send, PW_AST_EVENT_TIME, timestr, strlen(timestr), VENDOR_CODE)) {
  134. return -1;
  135. }
  136. /* AMA Flags */
  137. amaflags = ast_strdupa(ast_cel_get_ama_flag_name(record->amaflag));
  138. if (!rc_avpair_add(rh, send, PW_AST_AMA_FLAGS, amaflags, strlen(amaflags), VENDOR_CODE)) {
  139. return -1;
  140. }
  141. if (ast_test_flag(&global_flags, RADIUS_FLAG_LOGUNIQUEID)) {
  142. /* Unique ID */
  143. if (!ADD_VENDOR_CODE(PW_AST_UNIQUE_ID, record->unique_id)) {
  144. return -1;
  145. }
  146. }
  147. /* LinkedID */
  148. if (!ADD_VENDOR_CODE(PW_AST_LINKED_ID, record->linked_id)) {
  149. return -1;
  150. }
  151. /* Setting Acct-Session-Id & User-Name attributes for proper generation
  152. of Acct-Unique-Session-Id on server side */
  153. /* Channel */
  154. if (!rc_avpair_add(rh, send, PW_USER_NAME, &record->channel_name,
  155. strlen(record->channel_name), 0)) {
  156. return -1;
  157. }
  158. return 0;
  159. }
  160. static void radius_log(const struct ast_event *event, void *userdata)
  161. {
  162. int result = ERROR_RC;
  163. VALUE_PAIR *send = NULL;
  164. struct ast_cel_event_record record = {
  165. .version = AST_CEL_EVENT_RECORD_VERSION,
  166. };
  167. if (ast_cel_fill_record(event, &record)) {
  168. return;
  169. }
  170. if (build_radius_record(&send, &record)) {
  171. if (option_debug) {
  172. ast_log(LOG_DEBUG, "Unable to create RADIUS record. CEL not recorded!\n");
  173. }
  174. goto return_cleanup;
  175. }
  176. result = rc_acct(rh, 0, send);
  177. if (result != OK_RC) {
  178. ast_log(LOG_ERROR, "Failed to record Radius CEL record!\n");
  179. }
  180. return_cleanup:
  181. if (send) {
  182. rc_avpair_free(send);
  183. }
  184. }
  185. static int unload_module(void)
  186. {
  187. if (event_sub) {
  188. event_sub = ast_event_unsubscribe(event_sub);
  189. }
  190. if (rh) {
  191. rc_destroy(rh);
  192. rh = NULL;
  193. }
  194. return AST_MODULE_LOAD_SUCCESS;
  195. }
  196. static int load_module(void)
  197. {
  198. struct ast_config *cfg;
  199. struct ast_flags config_flags = { 0 };
  200. const char *tmp;
  201. if ((cfg = ast_config_load(cel_config, config_flags))) {
  202. ast_set2_flag(&global_flags, ast_true(ast_variable_retrieve(cfg, "radius", "usegmtime")), RADIUS_FLAG_USEGMTIME);
  203. if ((tmp = ast_variable_retrieve(cfg, "radius", "radiuscfg"))) {
  204. ast_copy_string(radiuscfg, tmp, sizeof(radiuscfg));
  205. }
  206. ast_config_destroy(cfg);
  207. } else {
  208. return AST_MODULE_LOAD_DECLINE;
  209. }
  210. /*
  211. * start logging
  212. *
  213. * NOTE: Yes this causes a slight memory leak if the module is
  214. * unloaded. However, it is better than a crash if cdr_radius
  215. * and cel_radius are both loaded.
  216. */
  217. tmp = ast_strdup("asterisk");
  218. if (tmp) {
  219. rc_openlog((char *) tmp);
  220. }
  221. /* read radiusclient-ng config file */
  222. if (!(rh = rc_read_config(radiuscfg))) {
  223. ast_log(LOG_NOTICE, "Cannot load radiusclient-ng configuration file %s.\n", radiuscfg);
  224. return AST_MODULE_LOAD_DECLINE;
  225. }
  226. /* read radiusclient-ng dictionaries */
  227. if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary"))) {
  228. ast_log(LOG_NOTICE, "Cannot load radiusclient-ng dictionary file.\n");
  229. rc_destroy(rh);
  230. rh = NULL;
  231. return AST_MODULE_LOAD_DECLINE;
  232. }
  233. event_sub = ast_event_subscribe(AST_EVENT_CEL, radius_log, "CEL Radius Logging", NULL, AST_EVENT_IE_END);
  234. if (!event_sub) {
  235. rc_destroy(rh);
  236. rh = NULL;
  237. return AST_MODULE_LOAD_DECLINE;
  238. } else {
  239. return AST_MODULE_LOAD_SUCCESS;
  240. }
  241. }
  242. AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_LOAD_ORDER, "RADIUS CEL Backend",
  243. .load = load_module,
  244. .unload = unload_module,
  245. .load_pri = AST_MODPRI_CDR_DRIVER,
  246. );