cel_radius.c 7.0 KB

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