cel_radius.c 7.0 KB

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