diff --git a/src/mod/xml_int/mod_xml_radius/.gitignore b/src/mod/xml_int/mod_xml_radius/.gitignore
new file mode 100644
index 0000000000..bb7ad3d288
--- /dev/null
+++ b/src/mod/xml_int/mod_xml_radius/.gitignore
@@ -0,0 +1 @@
+freeradius-client*
\ No newline at end of file
diff --git a/src/mod/xml_int/mod_xml_radius/00_dialpla_auth.xml b/src/mod/xml_int/mod_xml_radius/00_dialpla_auth.xml
new file mode 100644
index 0000000000..d4c74539a1
--- /dev/null
+++ b/src/mod/xml_int/mod_xml_radius/00_dialpla_auth.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/mod/xml_int/mod_xml_radius/Makefile b/src/mod/xml_int/mod_xml_radius/Makefile
new file mode 100644
index 0000000000..63542dff47
--- /dev/null
+++ b/src/mod/xml_int/mod_xml_radius/Makefile
@@ -0,0 +1,26 @@
+RADCLIENT_VERSION=1.1.6
+RADCLIENT=freeradius-client-$(RADCLIENT_VERSION)
+RADCLIENT_DIR=$(switch_srcdir)/libs/$(RADCLIENT)
+RADCLIENT_BUILDDIR=$(switch_builddir)/libs/$(RADCLIENT)
+RADCLIENT_LIBDIR=$(RADCLIENT_BUILDDIR)/lib
+RADCLIENT_LA=${RADCLIENT_LIBDIR}/libfreeradius-client.la
+
+LOCAL_CFLAGS=-I$(RADCLIENT_DIR)/include
+LOCAL_LIBADD=$(RADCLIENT_LA)
+
+BASE=../../../..
+include $(BASE)/build/modmake.rules
+
+$(RADCLIENT_DIR):
+ $(GETLIB) $(RADCLIENT).tar.gz
+
+$(RADCLIENT_BUILDDIR)/Makefile: $(RADCLIENT_DIR)
+ mkdir -p $(RADCLIENT_BUILDDIR)
+ cd $(RADCLIENT_BUILDDIR) && $(DEFAULT_VARS) $(RADCLIENT_DIR)/configure $(DEFAULT_ARGS) --srcdir=$(RADCLIENT_DIR)
+ $(TOUCH_TARGET)
+
+$(RADCLIENT_LA): $(RADCLIENT_BUILDDIR)/Makefile
+ cd $(RADCLIENT_BUILDDIR) && CFLAGS="$(CFLAGS)" $(MAKE)
+ $(TOUCH_TARGET)
+
+
diff --git a/src/mod/xml_int/mod_xml_radius/dictionaries/dictionary b/src/mod/xml_int/mod_xml_radius/dictionaries/dictionary
new file mode 100644
index 0000000000..431d92c544
--- /dev/null
+++ b/src/mod/xml_int/mod_xml_radius/dictionaries/dictionary
@@ -0,0 +1,244 @@
+#
+# Updated 97/06/13 to livingston-radius-2.01 miquels@cistron.nl
+#
+# This file contains dictionary translations for parsing
+# requests and generating responses. All transactions are
+# composed of Attribute/Value Pairs. The value of each attribute
+# is specified as one of 4 data types. Valid data types are:
+#
+# string - 0-253 octets
+# ipaddr - 4 octets in network byte order
+# integer - 32 bit value in big endian order (high byte first)
+# date - 32 bit value in big endian order - seconds since
+# 00:00:00 GMT, Jan. 1, 1970
+#
+# Enumerated values are stored in the user file with dictionary
+# VALUE translations for easy administration.
+#
+# Example:
+#
+# ATTRIBUTE VALUE
+# --------------- -----
+# Framed-Protocol = PPP
+# 7 = 1 (integer encoding)
+#
+
+#
+# Following are the proper new names. Use these.
+#
+$INCLUDE /usr/local/src/freeswitch/src/mod/xml_int/mod_xml_radius/dictionaries/dictionary.cisco
+$INCLUDE /usr/local/src/freeswitch/src/mod/xml_int/mod_xml_radius/dictionaries/dictionary.rfc5090
+
+ATTRIBUTE User-Name 1 string
+ATTRIBUTE Password 2 string
+ATTRIBUTE CHAP-Password 3 string
+ATTRIBUTE NAS-IP-Address 4 ipaddr
+ATTRIBUTE NAS-Port-Id 5 integer
+ATTRIBUTE Service-Type 6 integer
+ATTRIBUTE Framed-Protocol 7 integer
+ATTRIBUTE Framed-IP-Address 8 ipaddr
+ATTRIBUTE Framed-IP-Netmask 9 ipaddr
+ATTRIBUTE Framed-Routing 10 integer
+ATTRIBUTE Filter-Id 11 string
+ATTRIBUTE Framed-MTU 12 integer
+ATTRIBUTE Framed-Compression 13 integer
+ATTRIBUTE Login-IP-Host 14 ipaddr
+ATTRIBUTE Login-Service 15 integer
+ATTRIBUTE Login-TCP-Port 16 integer
+ATTRIBUTE Reply-Message 18 string
+ATTRIBUTE Callback-Number 19 string
+ATTRIBUTE Callback-Id 20 string
+ATTRIBUTE Framed-Route 22 string
+ATTRIBUTE Framed-IPX-Network 23 ipaddr
+ATTRIBUTE State 24 string
+ATTRIBUTE Class 25 string
+ATTRIBUTE Vendor-Specific 26 string
+ATTRIBUTE Session-Timeout 27 integer
+ATTRIBUTE Idle-Timeout 28 integer
+ATTRIBUTE Termination-Action 29 integer
+ATTRIBUTE Called-Station-Id 30 string
+ATTRIBUTE Calling-Station-Id 31 string
+ATTRIBUTE NAS-Identifier 32 string
+ATTRIBUTE Proxy-State 33 string
+ATTRIBUTE Login-LAT-Service 34 string
+ATTRIBUTE Login-LAT-Node 35 string
+ATTRIBUTE Login-LAT-Group 36 string
+ATTRIBUTE Framed-AppleTalk-Link 37 integer
+ATTRIBUTE Framed-AppleTalk-Network 38 integer
+ATTRIBUTE Framed-AppleTalk-Zone 39 string
+ATTRIBUTE Acct-Status-Type 40 integer
+ATTRIBUTE Acct-Delay-Time 41 integer
+ATTRIBUTE Acct-Input-Octets 42 integer
+ATTRIBUTE Acct-Output-Octets 43 integer
+ATTRIBUTE Acct-Session-Id 44 string
+ATTRIBUTE Acct-Authentic 45 integer
+ATTRIBUTE Acct-Session-Time 46 integer
+ATTRIBUTE Acct-Input-Packets 47 integer
+ATTRIBUTE Acct-Output-Packets 48 integer
+ATTRIBUTE Acct-Terminate-Cause 49 integer
+ATTRIBUTE Acct-Multi-Session-Id 50 string
+ATTRIBUTE Acct-Link-Count 51 integer
+ATTRIBUTE Event-Timestamp 55 integer
+ATTRIBUTE CHAP-Challenge 60 string
+ATTRIBUTE NAS-Port-Type 61 integer
+ATTRIBUTE Port-Limit 62 integer
+ATTRIBUTE Login-LAT-Port 63 integer
+ATTRIBUTE Connect-Info 77 string
+
+#
+# RFC3162 IPv6 attributes
+#
+ATTRIBUTE NAS-IPv6-Address 95 string
+ATTRIBUTE Framed-Interface-Id 96 string
+ATTRIBUTE Framed-IPv6-Prefix 97 string
+ATTRIBUTE Login-IPv6-Host 98 string
+ATTRIBUTE Framed-IPv6-Route 99 string
+ATTRIBUTE Framed-IPv6-Pool 100 string
+
+#
+# Experimental Non Protocol Attributes used by Cistron-Radiusd
+#
+ATTRIBUTE Huntgroup-Name 221 string
+ATTRIBUTE User-Category 1029 string
+ATTRIBUTE Group-Name 1030 string
+ATTRIBUTE Simultaneous-Use 1034 integer
+ATTRIBUTE Strip-User-Name 1035 integer
+ATTRIBUTE Fall-Through 1036 integer
+ATTRIBUTE Add-Port-To-IP-Address 1037 integer
+ATTRIBUTE Exec-Program 1038 string
+ATTRIBUTE Exec-Program-Wait 1039 string
+ATTRIBUTE Hint 1040 string
+
+#
+# Non-Protocol Attributes
+# These attributes are used internally by the server
+#
+ATTRIBUTE Expiration 21 date
+ATTRIBUTE Auth-Type 1000 integer
+ATTRIBUTE Menu 1001 string
+ATTRIBUTE Termination-Menu 1002 string
+ATTRIBUTE Prefix 1003 string
+ATTRIBUTE Suffix 1004 string
+ATTRIBUTE Group 1005 string
+ATTRIBUTE Crypt-Password 1006 string
+ATTRIBUTE Connect-Rate 1007 integer
+
+#
+# Integer Translations
+#
+
+# User Types
+
+VALUE Service-Type Login-User 1
+VALUE Service-Type Framed-User 2
+VALUE Service-Type Callback-Login-User 3
+VALUE Service-Type Callback-Framed-User 4
+VALUE Service-Type Outbound-User 5
+VALUE Service-Type Administrative-User 6
+VALUE Service-Type NAS-Prompt-User 7
+
+# Framed Protocols
+
+VALUE Framed-Protocol PPP 1
+VALUE Framed-Protocol SLIP 2
+
+# Framed Routing Values
+
+VALUE Framed-Routing None 0
+VALUE Framed-Routing Broadcast 1
+VALUE Framed-Routing Listen 2
+VALUE Framed-Routing Broadcast-Listen 3
+
+# Framed Compression Types
+
+VALUE Framed-Compression None 0
+VALUE Framed-Compression Van-Jacobson-TCP-IP 1
+
+# Login Services
+
+VALUE Login-Service Telnet 0
+VALUE Login-Service Rlogin 1
+VALUE Login-Service TCP-Clear 2
+VALUE Login-Service PortMaster 3
+
+# Status Types
+
+VALUE Acct-Status-Type Start 1
+VALUE Acct-Status-Type Stop 2
+VALUE Acct-Status-Type Alive 3
+VALUE Acct-Status-Type Accounting-On 7
+VALUE Acct-Status-Type Accounting-Off 8
+
+# Authentication Types
+
+VALUE Acct-Authentic RADIUS 1
+VALUE Acct-Authentic Local 2
+VALUE Acct-Authentic PowerLink128 100
+
+# Termination Options
+
+VALUE Termination-Action Default 0
+VALUE Termination-Action RADIUS-Request 1
+
+# NAS Port Types, available in 3.3.1 and later
+
+VALUE NAS-Port-Type Async 0
+VALUE NAS-Port-Type Sync 1
+VALUE NAS-Port-Type ISDN 2
+VALUE NAS-Port-Type ISDN-V120 3
+VALUE NAS-Port-Type ISDN-V110 4
+
+# Acct Terminate Causes, available in 3.3.2 and later
+
+VALUE Acct-Terminate-Cause User-Request 1
+VALUE Acct-Terminate-Cause Lost-Carrier 2
+VALUE Acct-Terminate-Cause Lost-Service 3
+VALUE Acct-Terminate-Cause Idle-Timeout 4
+VALUE Acct-Terminate-Cause Session-Timeout 5
+VALUE Acct-Terminate-Cause Admin-Reset 6
+VALUE Acct-Terminate-Cause Admin-Reboot 7
+VALUE Acct-Terminate-Cause Port-Error 8
+VALUE Acct-Terminate-Cause NAS-Error 9
+VALUE Acct-Terminate-Cause NAS-Request 10
+VALUE Acct-Terminate-Cause NAS-Reboot 11
+VALUE Acct-Terminate-Cause Port-Unneeded 12
+VALUE Acct-Terminate-Cause Port-Preempted 13
+VALUE Acct-Terminate-Cause Port-Suspended 14
+VALUE Acct-Terminate-Cause Service-Unavailable 15
+VALUE Acct-Terminate-Cause Callback 16
+VALUE Acct-Terminate-Cause User-Error 17
+VALUE Acct-Terminate-Cause Host-Request 18
+
+#
+# Non-Protocol Integer Translations
+#
+
+VALUE Auth-Type Local 0
+VALUE Auth-Type System 1
+VALUE Auth-Type SecurID 2
+VALUE Auth-Type Crypt-Local 3
+VALUE Auth-Type Reject 4
+
+#
+# Cistron extensions
+#
+VALUE Auth-Type Pam 253
+VALUE Auth-Type Accept 254
+
+#
+# Experimental Non-Protocol Integer Translations for Cistron-Radiusd
+#
+VALUE Fall-Through No 0
+VALUE Fall-Through Yes 1
+VALUE Add-Port-To-IP-Address No 0
+VALUE Add-Port-To-IP-Address Yes 1
+
+#
+# Configuration Values
+# uncomment these two lines to turn account expiration on
+#
+
+#VALUE Server-Config Password-Expiration 30
+#VALUE Server-Config Password-Warning 5
+
+
diff --git a/src/mod/xml_int/mod_xml_radius/dictionaries/dictionary.cisco b/src/mod/xml_int/mod_xml_radius/dictionaries/dictionary.cisco
new file mode 100644
index 0000000000..b61c9d27cc
--- /dev/null
+++ b/src/mod/xml_int/mod_xml_radius/dictionaries/dictionary.cisco
@@ -0,0 +1,161 @@
+# -*- text -*-
+#
+# dictionary.cisco
+#
+# Accounting VSAs originally by
+# "Marcelo M. Sosa Lugones"
+#
+# Version: $Id$
+#
+# For documentation on Cisco RADIUS attributes, see:
+#
+# http://www.cisco.com/univercd/cc/td/doc/product/access/acs_serv/vapp_dev/vsaig3.htm
+#
+# For general documentation on Cisco RADIUS configuration, see:
+#
+# http://www.cisco.com/en/US/partner/tech/tk583/tk547/tsd_technology_support_sub-protocol_home.html
+#
+
+VENDOR Cisco 9
+
+#
+# Standard attribute
+#
+#BEGIN-VENDOR Cisco
+
+ATTRIBUTE Cisco-AVPair 1 string vendor=Cisco
+ATTRIBUTE Cisco-NAS-Port 2 string vendor=Cisco
+
+#
+# T.37 Store-and-Forward attributes.
+#
+ATTRIBUTE Cisco-Fax-Account-Id-Origin 3 string vendor=Cisco
+ATTRIBUTE Cisco-Fax-Msg-Id 4 string vendor=Cisco
+ATTRIBUTE Cisco-Fax-Pages 5 string vendor=Cisco
+ATTRIBUTE Cisco-Fax-Coverpage-Flag 6 string vendor=Cisco
+ATTRIBUTE Cisco-Fax-Modem-Time 7 string vendor=Cisco
+ATTRIBUTE Cisco-Fax-Connect-Speed 8 string vendor=Cisco
+ATTRIBUTE Cisco-Fax-Recipient-Count 9 string vendor=Cisco
+ATTRIBUTE Cisco-Fax-Process-Abort-Flag 10 string vendor=Cisco
+ATTRIBUTE Cisco-Fax-Dsn-Address 11 string vendor=Cisco
+ATTRIBUTE Cisco-Fax-Dsn-Flag 12 string vendor=Cisco
+ATTRIBUTE Cisco-Fax-Mdn-Address 13 string vendor=Cisco
+ATTRIBUTE Cisco-Fax-Mdn-Flag 14 string vendor=Cisco
+ATTRIBUTE Cisco-Fax-Auth-Status 15 string vendor=Cisco
+ATTRIBUTE Cisco-Email-Server-Address 16 string vendor=Cisco
+ATTRIBUTE Cisco-Email-Server-Ack-Flag 17 string vendor=Cisco
+ATTRIBUTE Cisco-Gateway-Id 18 string vendor=Cisco
+ATTRIBUTE Cisco-Call-Type 19 string vendor=Cisco
+ATTRIBUTE Cisco-Port-Used 20 string vendor=Cisco
+ATTRIBUTE Cisco-Abort-Cause 21 string vendor=Cisco
+
+#
+# Voice over IP attributes.
+#
+ATTRIBUTE h323-remote-address 23 string vendor=Cisco
+ATTRIBUTE h323-conf-id 24 string vendor=Cisco
+ATTRIBUTE h323-setup-time 25 string vendor=Cisco
+ATTRIBUTE h323-call-origin 26 string vendor=Cisco
+ATTRIBUTE h323-call-type 27 string vendor=Cisco
+ATTRIBUTE h323-connect-time 28 string vendor=Cisco
+ATTRIBUTE h323-disconnect-time 29 string vendor=Cisco
+ATTRIBUTE h323-disconnect-cause 30 string vendor=Cisco
+ATTRIBUTE h323-voice-quality 31 string vendor=Cisco
+ATTRIBUTE h323-gw-id 33 string vendor=Cisco
+ATTRIBUTE h323-incoming-conf-id 35 string vendor=Cisco
+
+ATTRIBUTE Cisco-Policy-Up 37 string vendor=Cisco
+ATTRIBUTE Cisco-Policy-Down 38 string vendor=Cisco
+
+ATTRIBUTE sip-conf-id 100 string vendor=Cisco
+ATTRIBUTE h323-credit-amount 101 string vendor=Cisco
+ATTRIBUTE h323-credit-time 102 string vendor=Cisco
+ATTRIBUTE h323-return-code 103 string vendor=Cisco
+ATTRIBUTE h323-prompt-id 104 string vendor=Cisco
+ATTRIBUTE h323-time-and-day 105 string vendor=Cisco
+ATTRIBUTE h323-redirect-number 106 string vendor=Cisco
+ATTRIBUTE h323-preferred-lang 107 string vendor=Cisco
+ATTRIBUTE h323-redirect-ip-address 108 string vendor=Cisco
+ATTRIBUTE h323-billing-model 109 string vendor=Cisco
+ATTRIBUTE h323-currency 110 string vendor=Cisco
+ATTRIBUTE subscriber 111 string vendor=Cisco
+ATTRIBUTE gw-rxd-cdn 112 string vendor=Cisco
+ATTRIBUTE gw-final-xlated-cdn 113 string vendor=Cisco
+ATTRIBUTE remote-media-address 114 string vendor=Cisco
+ATTRIBUTE release-source 115 string vendor=Cisco
+ATTRIBUTE gw-rxd-cgn 116 string vendor=Cisco
+ATTRIBUTE gw-final-xlated-cgn 117 string vendor=Cisco
+
+# SIP Attributes
+ATTRIBUTE call-id 141 string vendor=Cisco
+ATTRIBUTE session-protocol 142 string vendor=Cisco
+ATTRIBUTE method 143 string vendor=Cisco
+ATTRIBUTE prev-hop-via 144 string vendor=Cisco
+ATTRIBUTE prev-hop-ip 145 string vendor=Cisco
+ATTRIBUTE incoming-req-uri 146 string vendor=Cisco
+ATTRIBUTE outgoing-req-uri 147 string vendor=Cisco
+ATTRIBUTE next-hop-ip 148 string vendor=Cisco
+ATTRIBUTE next-hop-dn 149 string vendor=Cisco
+ATTRIBUTE sip-hdr 150 string vendor=Cisco
+
+#
+# Extra attributes sent by the Cisco, if you configure
+# "radius-server vsa accounting" (requires IOS11.2+).
+#
+ATTRIBUTE Cisco-Multilink-ID 187 integer vendor=Cisco
+ATTRIBUTE Cisco-Num-In-Multilink 188 integer vendor=Cisco
+ATTRIBUTE Cisco-Pre-Input-Octets 190 integer vendor=Cisco
+ATTRIBUTE Cisco-Pre-Output-Octets 191 integer vendor=Cisco
+ATTRIBUTE Cisco-Pre-Input-Packets 192 integer vendor=Cisco
+ATTRIBUTE Cisco-Pre-Output-Packets 193 integer vendor=Cisco
+ATTRIBUTE Cisco-Maximum-Time 194 integer vendor=Cisco
+ATTRIBUTE Cisco-Disconnect-Cause 195 integer vendor=Cisco
+ATTRIBUTE Cisco-Data-Rate 197 integer vendor=Cisco
+ATTRIBUTE Cisco-PreSession-Time 198 integer vendor=Cisco
+ATTRIBUTE Cisco-PW-Lifetime 208 integer vendor=Cisco
+ATTRIBUTE Cisco-IP-Direct 209 integer vendor=Cisco
+ATTRIBUTE Cisco-PPP-VJ-Slot-Comp 210 integer vendor=Cisco
+ATTRIBUTE Cisco-PPP-Async-Map 212 integer vendor=Cisco
+ATTRIBUTE Cisco-IP-Pool-Definition 217 string vendor=Cisco
+ATTRIBUTE Cisco-Assign-IP-Pool 218 integer vendor=Cisco
+ATTRIBUTE Cisco-Route-IP 228 integer vendor=Cisco
+ATTRIBUTE Cisco-Link-Compression 233 integer vendor=Cisco
+ATTRIBUTE Cisco-Target-Util 234 integer vendor=Cisco
+ATTRIBUTE Cisco-Maximum-Channels 235 integer vendor=Cisco
+ATTRIBUTE Cisco-Data-Filter 242 integer vendor=Cisco
+ATTRIBUTE Cisco-Call-Filter 243 integer vendor=Cisco
+ATTRIBUTE Cisco-Idle-Limit 244 integer vendor=Cisco
+ATTRIBUTE Cisco-Subscriber-Password 249 string vendor=Cisco
+ATTRIBUTE Cisco-Account-Info 250 string vendor=Cisco
+ATTRIBUTE Cisco-Service-Info 251 string vendor=Cisco
+ATTRIBUTE Cisco-Command-Code 252 string vendor=Cisco
+ATTRIBUTE Cisco-Control-Info 253 string vendor=Cisco
+ATTRIBUTE Cisco-Xmit-Rate 255 integer vendor=Cisco
+
+VALUE Cisco-Disconnect-Cause Unknown 2
+VALUE Cisco-Disconnect-Cause CLID-Authentication-Failure 4
+VALUE Cisco-Disconnect-Cause No-Carrier 10
+VALUE Cisco-Disconnect-Cause Lost-Carrier 11
+VALUE Cisco-Disconnect-Cause No-Detected-Result-Codes 12
+VALUE Cisco-Disconnect-Cause User-Ends-Session 20
+VALUE Cisco-Disconnect-Cause Idle-Timeout 21
+VALUE Cisco-Disconnect-Cause Exit-Telnet-Session 22
+VALUE Cisco-Disconnect-Cause No-Remote-IP-Addr 23
+VALUE Cisco-Disconnect-Cause Exit-Raw-TCP 24
+VALUE Cisco-Disconnect-Cause Password-Fail 25
+VALUE Cisco-Disconnect-Cause Raw-TCP-Disabled 26
+VALUE Cisco-Disconnect-Cause Control-C-Detected 27
+VALUE Cisco-Disconnect-Cause EXEC-Program-Destroyed 28
+VALUE Cisco-Disconnect-Cause Timeout-PPP-LCP 40
+VALUE Cisco-Disconnect-Cause Failed-PPP-LCP-Negotiation 41
+VALUE Cisco-Disconnect-Cause Failed-PPP-PAP-Auth-Fail 42
+VALUE Cisco-Disconnect-Cause Failed-PPP-CHAP-Auth 43
+VALUE Cisco-Disconnect-Cause Failed-PPP-Remote-Auth 44
+VALUE Cisco-Disconnect-Cause PPP-Remote-Terminate 45
+VALUE Cisco-Disconnect-Cause PPP-Closed-Event 46
+VALUE Cisco-Disconnect-Cause Session-Timeout 100
+VALUE Cisco-Disconnect-Cause Session-Failed-Security 101
+VALUE Cisco-Disconnect-Cause Session-End-Callback 102
+VALUE Cisco-Disconnect-Cause Invalid-Protocol 120
+
+#END-VENDOR Cisco
diff --git a/src/mod/xml_int/mod_xml_radius/dictionaries/dictionary.rfc5090 b/src/mod/xml_int/mod_xml_radius/dictionaries/dictionary.rfc5090
new file mode 100644
index 0000000000..4feda43628
--- /dev/null
+++ b/src/mod/xml_int/mod_xml_radius/dictionaries/dictionary.rfc5090
@@ -0,0 +1,27 @@
+# -*- text -*-
+#
+# Attributes and values defined in RFC 5090.
+# http://www.ietf.org/rfc/rfc5090.txt
+#
+# $Id$
+#
+ATTRIBUTE Digest-Response 103 string
+ATTRIBUTE Digest-Realm 104 string
+ATTRIBUTE Digest-Nonce 105 string
+ATTRIBUTE Digest-Response-Auth 106 string
+ATTRIBUTE Digest-Nextnonce 107 string
+ATTRIBUTE Digest-Method 108 string
+ATTRIBUTE Digest-URI 109 string
+ATTRIBUTE Digest-Qop 110 string
+ATTRIBUTE Digest-Algorithm 111 string
+ATTRIBUTE Digest-Entity-Body-Hash 112 string
+ATTRIBUTE Digest-CNonce 113 string
+ATTRIBUTE Digest-Nonce-Count 114 string
+ATTRIBUTE Digest-Username 115 string
+ATTRIBUTE Digest-Opaque 116 string
+ATTRIBUTE Digest-Auth-Param 117 string
+ATTRIBUTE Digest-AKA-Auts 118 string
+ATTRIBUTE Digest-Domain 119 string
+ATTRIBUTE Digest-Stale 120 string
+ATTRIBUTE Digest-HA1 121 string
+ATTRIBUTE SIP-AOR 122 string
diff --git a/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c b/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c
new file mode 100644
index 0000000000..28fd56eca6
--- /dev/null
+++ b/src/mod/xml_int/mod_xml_radius/mod_xml_radius.c
@@ -0,0 +1,824 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005-2012, Anthony Minessale II
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * William King
+ *
+ * mod_xml_radius.c -- Radius authentication and authorization
+ *
+ */
+#include
+#include
+
+static struct {
+ switch_memory_pool_t *pool;
+ switch_xml_t auth_invite_configs;
+ switch_xml_t auth_app_configs;
+ switch_xml_t acct_start_configs;
+ switch_xml_t acct_end_configs;
+ /* xml read write lock */
+} globals = {0};
+
+SWITCH_MODULE_LOAD_FUNCTION(mod_xml_radius_load);
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_xml_radius_shutdown);
+SWITCH_MODULE_DEFINITION(mod_xml_radius, mod_xml_radius_load, mod_xml_radius_shutdown, NULL);
+
+static int GLOBAL_DEBUG = 0;
+
+switch_status_t mod_xml_radius_new_handle(rc_handle **new_handle, switch_xml_t xml) {
+ switch_xml_t server, param;
+
+ *new_handle = rc_new();
+
+ if ( *new_handle == NULL ) {
+ goto err;
+ }
+
+ *new_handle = rc_config_init(*new_handle);
+
+ if ( *new_handle == NULL ) {
+ goto err;
+ }
+
+ if (rc_add_config(*new_handle, "auth_order", "radius", "mod_radius_cdr.c", 0) != 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error adding auth_order\n");
+ goto err;
+ }
+
+ if ((server = switch_xml_child(xml, "connection")) == NULL ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find 'connection' section in config file.\n");
+ goto err;
+ }
+
+ for (param = switch_xml_child(server, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ char *val = (char *) switch_xml_attr_soft(param, "value");
+
+ if ( GLOBAL_DEBUG ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Attempting to add param '%s' with value '%s' \n", var, val);
+ }
+
+ if (strncmp(var, "dictionary", 10) == 0) {
+ rc_read_dictionary(*new_handle, val);
+ } else if (rc_add_config(*new_handle, var, val, "mod_xml_radius", 0) != 0) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error adding param '%s' with value '%s' \n", var, val);
+ goto err;
+ }
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+
+ err:
+ if ( *new_handle ) {
+ rc_destroy( *new_handle );
+ *new_handle = NULL;
+ }
+ return SWITCH_STATUS_GENERR;
+}
+
+switch_status_t do_config()
+{
+ char *conf = "xml_radius.conf";
+ switch_xml_t xml, cfg, tmp, server;
+ int serv, timeout, deadtime, retries, dict, seq;
+ /* TODO:
+ 1. read new auth_invite_configs
+ 2. Create replacement xml and vas objects
+ 3. Get the write lock.
+ 4. Replace xml and vas objects
+ 5. unlock and return.
+ */
+
+ if (!(xml = switch_xml_open_cfg(conf, &cfg, NULL))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", conf);
+ goto err;
+ }
+
+ serv = timeout = deadtime = retries = dict = seq = 0;
+ if ((tmp = switch_xml_dup(switch_xml_child(cfg, "auth_invite"))) != NULL ) {
+ if ( (server = switch_xml_child(xml, "connection")) != NULL) {
+ for (param = switch_xml_child(server, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ if ( strncmp(var, "authserver", 10) == 0 ) {
+ serv = 1;
+ } else if ( strncmp(var, "radius_timeout", 14) == 0 ) {
+ timeout = 1;
+ } else if ( strncmp(var, "radius_deadtime", 15) == 0 ) {
+ deadtime = 1;
+ } else if ( strncmp(var, "radius_retries", 14) == 0 ) {
+ retries = 1;
+ } else if ( strncmp(var, "dictionary", 10) == 0 ) {
+ dict = 1;
+ } else if ( strncmp(var, "seqfile", 7) == 0 ) {
+ seq = 1;
+ }
+ }
+
+ if ( serv && timeout && deadtime && retries && dict && seq ) {
+ globals.auth_invite_configs = tmp;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing a require section for radius connections\n");
+ goto err;
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find 'connection' section for auth_invite\n");
+ goto err;
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Could not find 'auth_invite' section in config file.\n");
+ }
+
+ if ((globals.auth_app_configs = switch_xml_dup(switch_xml_child(cfg, "auth_app"))) == NULL ) {
+ if ( (server = switch_xml_child(xml, "connection")) != NULL) {
+ for (param = switch_xml_child(server, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ if ( strncmp(var, "authserver", 10) == 0 ) {
+ serv = 1;
+ } else if ( strncmp(var, "radius_timeout", 14) == 0 ) {
+ timeout = 1;
+ } else if ( strncmp(var, "radius_deadtime", 15) == 0 ) {
+ deadtime = 1;
+ } else if ( strncmp(var, "radius_retries", 14) == 0 ) {
+ retries = 1;
+ } else if ( strncmp(var, "dictionary", 10) == 0 ) {
+ dict = 1;
+ } else if ( strncmp(var, "seqfile", 7) == 0 ) {
+ seq = 1;
+ }
+ }
+
+ if ( serv && timeout && deadtime && retries && dict && seq ) {
+ globals.auth_invite_configs = tmp;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing a require section for radius connections\n");
+ goto err;
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find 'connection' section for auth_app\n");
+ goto err;
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Could not find 'auth_app' section in config file.\n");
+ }
+
+ if ((globals.acct_start_configs = switch_xml_dup(switch_xml_child(cfg, "acct_start"))) == NULL ) {
+ if ( (server = switch_xml_child(xml, "connection")) != NULL) {
+ for (param = switch_xml_child(server, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ if ( strncmp(var, "acctserver", 10) == 0 ) {
+ serv = 1;
+ } else if ( strncmp(var, "radius_timeout", 14) == 0 ) {
+ timeout = 1;
+ } else if ( strncmp(var, "radius_deadtime", 15) == 0 ) {
+ deadtime = 1;
+ } else if ( strncmp(var, "radius_retries", 14) == 0 ) {
+ retries = 1;
+ } else if ( strncmp(var, "dictionary", 10) == 0 ) {
+ dict = 1;
+ } else if ( strncmp(var, "seqfile", 7) == 0 ) {
+ seq = 1;
+ }
+ }
+
+ if ( serv && timeout && deadtime && retries && dict && seq ) {
+ globals.auth_invite_configs = tmp;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing a require section for radius connections\n");
+ goto err;
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find 'connection' section for acct_start\n");
+ goto err;
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Could not find 'acct_start' section in config file.\n");
+ }
+
+ if ((globals.acct_end_configs = switch_xml_dup(switch_xml_child(cfg, "acct_end"))) == NULL ) {
+ if ( (server = switch_xml_child(xml, "connection")) != NULL) {
+ for (param = switch_xml_child(server, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ if ( strncmp(var, "acctserver", 10) == 0 ) {
+ serv = 1;
+ } else if ( strncmp(var, "radius_timeout", 14) == 0 ) {
+ timeout = 1;
+ } else if ( strncmp(var, "radius_deadtime", 15) == 0 ) {
+ deadtime = 1;
+ } else if ( strncmp(var, "radius_retries", 14) == 0 ) {
+ retries = 1;
+ } else if ( strncmp(var, "dictionary", 10) == 0 ) {
+ dict = 1;
+ } else if ( strncmp(var, "seqfile", 7) == 0 ) {
+ seq = 1;
+ }
+ }
+
+ if ( serv && timeout && deadtime && retries && dict && seq ) {
+ globals.auth_invite_configs = tmp;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing a require section for radius connections\n");
+ goto err;
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find 'connection' section for acct_end\n");
+ goto err;
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Could not find 'acct_end' section in config file.\n");
+ }
+
+ if ( xml ) {
+ switch_xml_free(xml);
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+
+ err:
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: Configuration error\n");
+ if ( xml ) {
+ switch_xml_free(xml);
+ }
+
+ return SWITCH_STATUS_GENERR;
+}
+
+switch_status_t mod_xml_radius_add_params(switch_core_session_t *session, switch_event_t *params, rc_handle *handle, VALUE_PAIR **send, switch_xml_t fields)
+{
+ switch_xml_t param;
+
+ if ( (param = switch_xml_child(fields, "param")) == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to locate a param under the fields section\n");
+ goto err;
+ }
+
+ for (; param; param = param->next) {
+ DICT_ATTR *attribute = NULL;
+ DICT_VENDOR *vendor = NULL;
+ int attr_num = 0, vend_num = 0;
+ void *av_value = NULL;
+
+ char *var = (char *) switch_xml_attr(param, "name");
+ char *vend = (char *) switch_xml_attr(param, "vendor");
+ char *variable = (char *) switch_xml_attr(param, "variable");
+ char *format = (char *) switch_xml_attr(param, "format");
+
+ attribute = rc_dict_findattr(handle, var);
+
+ if ( attribute == NULL ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: Could not locate attribute '%s' in the configured dictionary\n", var);
+ goto err;
+ }
+
+ if ( GLOBAL_DEBUG ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: dict attr '%s' value '%d' type '%d'\n",
+ attribute->name, attribute->value, attribute->type);
+ }
+
+ attr_num = attribute->value;
+
+ if ( vend ) {
+ vendor = rc_dict_findvend(handle, vend);
+
+ if ( vendor == NULL ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: Could not locate vendor '%s' in the configured dictionary %p\n",
+ vend, vend);
+ goto err;
+ }
+
+ if ( GLOBAL_DEBUG ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: dict vend name '%s' vendorpec '%d'\n",
+ vendor->vendorname, vendor->vendorpec);
+ }
+
+ vend_num = vendor->vendorpec;
+ }
+
+ if ( var ) {
+ if ( session ) {
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+
+ /* Accounting only */
+ if ( strncmp( var, "h323-setup-time", 15) == 0 ) {
+ switch_caller_profile_t *profile = switch_channel_get_caller_profile(channel);
+ switch_time_t time = profile->times->created;
+ switch_time_exp_t tm;
+
+ switch_time_exp_lt(&tm, time);
+ av_value = switch_mprintf("%04u-%02u-%02uT%02u:%02u:%02u.%06u%+03d%02d",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec,
+ tm.tm_gmtoff / 3600, tm.tm_gmtoff % 3600);
+
+ if (rc_avpair_add(handle, send, attr_num, av_value, -1, vend_num) == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option to handle\n");
+ goto err;
+ }
+ } else if ( strncmp( var, "h323-connect-time", 17) == 0 ) {
+ switch_caller_profile_t *profile = switch_channel_get_caller_profile(channel);
+ switch_time_t time = profile->times->answered;
+ switch_time_exp_t tm;
+
+ switch_time_exp_lt(&tm, time);
+
+ av_value = switch_mprintf("%04u-%02u-%02uT%02u:%02u:%02u.%06u%+03d%02d",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec,
+ tm.tm_gmtoff / 3600, tm.tm_gmtoff % 3600);
+
+ if (rc_avpair_add(handle, send, attr_num, av_value, -1, vend_num) == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option to handle\n");
+ goto err;
+ }
+ } else if ( strncmp( var, "h323-disconnect-time", 20) == 0 ) {
+ switch_caller_profile_t *profile = switch_channel_get_caller_profile(channel);
+ switch_time_t time = profile->times->hungup;
+ switch_time_exp_t tm;
+
+ switch_time_exp_lt(&tm, time);
+
+ av_value = switch_mprintf("%04u-%02u-%02uT%02u:%02u:%02u.%06u%+03d%02d",
+ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec,
+ tm.tm_gmtoff / 3600, tm.tm_gmtoff % 3600);
+
+ if (rc_avpair_add(handle, send, attr_num, av_value, -1, vend_num) == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option to handle\n");
+ goto err;
+ }
+ } else if ( strncmp( var, "h323-disconnect-cause", 21) == 0 ) {
+ switch_call_cause_t cause = switch_channel_get_cause(channel);
+ av_value = switch_mprintf("h323-disconnect-cause=%x", cause);
+ if (rc_avpair_add(handle, send, 30, av_value, -1, 9) == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add disconnect cause \n");
+ goto err;
+ }
+
+ } else {
+ if ( attribute->type == 0 ) {
+ av_value = switch_mprintf(format, switch_channel_get_variable(channel, variable));
+ if (rc_avpair_add(handle, send, attr_num, av_value, -1, vend_num) == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option with val '%s' to handle\n", (char *) av_value);
+ goto err;
+ }
+ } else if ( attribute->type == 1 ) {
+ int number = atoi(switch_channel_get_variable(channel, variable));
+
+ if (rc_avpair_add(handle, send, attr_num, &number, -1, vend_num) == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option with value '%d' to handle\n", number);
+ goto err;
+ }
+ }
+ }
+ } else if ( params ) {
+ /* Auth only */
+ char *tmp = switch_event_get_header(params, variable);
+
+ if ( GLOBAL_DEBUG ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: param var '%s' val: %s\n", variable, tmp);
+ }
+
+ if ( tmp == NULL ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: Unable to locate '%s' on the event\n", variable);
+ goto err;
+ }
+
+ av_value = switch_mprintf(format, tmp);
+ if (rc_avpair_add(handle, send, attr_num, av_value, -1, vend_num) == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option to handle\n");
+ goto err;
+ }
+ } else {
+ goto err;
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: all params must have a name attribute\n");
+ goto err;
+ }
+ if ( av_value != NULL ) {
+ free(av_value);
+ }
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+ err:
+ return SWITCH_STATUS_GENERR;
+
+}
+
+/* static switch_status_t name (_In_opt_z_ const char *cmd, _In_opt_ switch_core_session_t *session, _In_ switch_stream_handle_t *stream) */
+SWITCH_STANDARD_API(mod_xml_radius_connect_test)
+{
+ int result = 0;
+ VALUE_PAIR *send = NULL, *recv = NULL;
+ char msg[512 * 10 + 1] = {0};
+ uint32_t service = PW_AUTHENTICATE_ONLY;
+ rc_handle *new_handle = NULL;
+ switch_xml_t fields;
+
+ if ( GLOBAL_DEBUG ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: starting connection test\n");
+ }
+
+ mod_xml_radius_new_handle(&new_handle, globals.auth_invite_configs);
+
+ if ((fields = switch_xml_child(globals.auth_invite_configs, "fields")) == NULL ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find 'fields' section in config file.\n");
+ goto err;
+ }
+
+ if ( mod_xml_radius_add_params(NULL, NULL, new_handle, &send, fields) !=SWITCH_STATUS_SUCCESS ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to add params to rc_handle\n");
+ goto err;
+ }
+
+ if (rc_avpair_add(new_handle, &send, PW_SERVICE_TYPE, &service, -1, 0) == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option to handle\n");
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ result = rc_auth(new_handle, 0, send, &recv, msg);
+
+ if ( GLOBAL_DEBUG ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: result(RC=%d) %s \n", result, msg);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: finished connection test\n");
+ }
+
+ err:
+ if ( recv ) {
+ rc_avpair_free(recv);
+ recv = NULL;
+ }
+ rc_destroy(new_handle);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_xml_t mod_xml_radius_auth_invite(switch_event_t *params) {
+ int result = 0, param_idx = 0;
+ VALUE_PAIR *send = NULL, *recv = NULL, *service_vp = NULL;
+ char msg[512 * 10 + 1] = {0};
+ uint32_t service = PW_AUTHENTICATE_ONLY;
+ rc_handle *new_handle = NULL;
+ switch_xml_t fields, xml, dir, dom, usr, vars, var;
+ char name[512], value[512], *strtmp;
+
+ if (GLOBAL_DEBUG ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: starting invite authentication\n");
+ }
+
+ mod_xml_radius_new_handle(&new_handle, globals.auth_invite_configs);
+
+ if ( new_handle == NULL ) {
+ goto err;
+ }
+
+ if ((fields = switch_xml_child(globals.auth_invite_configs, "fields")) == NULL ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find 'fields' section in config file.\n");
+ goto err;
+ }
+
+ if ( mod_xml_radius_add_params(NULL, params, new_handle, &send, fields) != SWITCH_STATUS_SUCCESS ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to add params to rc_handle\n");
+ goto err;
+ }
+
+ if (rc_avpair_add(new_handle, &send, PW_SERVICE_TYPE, &service, -1, 0) == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option to handle\n");
+ goto err;
+ }
+
+ result = rc_auth(new_handle, 0, send, &recv, msg);
+
+ if ( GLOBAL_DEBUG ){
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: result(RC=%d) %s \n", result, msg);
+ }
+
+ if ( result != 0 ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: Failed to authenticate\n");
+ goto err;
+ }
+
+ xml = switch_xml_new("document");
+ switch_xml_set_attr_d(xml, "type", "freeswitch/xml");
+ dir = switch_xml_add_child_d(xml, "section", 0);
+ switch_xml_set_attr_d(dir, "name", "directory");
+ dom = switch_xml_add_child_d(dir, "domain", 0);
+ switch_xml_set_attr_d(dom, "name", switch_event_get_header(params, "domain"));
+ usr = switch_xml_add_child_d(dom, "user", 0);
+ vars = switch_xml_add_child_d(usr, "variables", 0);
+
+ switch_xml_set_attr_d(usr, "id", switch_event_get_header(params, "user"));
+
+ service_vp = recv;
+ while (service_vp != NULL) {
+ rc_avpair_tostr(new_handle, service_vp, name, 512, value, 512);
+ if ( GLOBAL_DEBUG )
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "\tattribute (%s)[%s] found in radius packet\n", name, value);
+ var = switch_xml_add_child_d(vars, "variable", param_idx++);
+ strtmp = strdup(name);
+ switch_xml_set_attr_d(var, "name", strtmp);
+ free(strtmp);
+ strtmp = strdup(value);
+ switch_xml_set_attr_d(var, "value", strtmp);
+ free(strtmp);
+ service_vp = service_vp->next;
+ }
+
+ if ( GLOBAL_DEBUG ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "XML: %s \n", switch_xml_toxml(xml, 1));
+ }
+
+ rc_avpair_free(recv);
+ rc_destroy(new_handle);
+ return xml;
+ err:
+ if ( recv ) {
+ rc_avpair_free(recv);
+ recv = NULL;
+ }
+ if ( new_handle ) {
+ rc_destroy(new_handle);
+ new_handle = NULL;
+ }
+
+ return NULL;
+}
+
+static switch_xml_t mod_xml_radius_directory_search(const char *section, const char *tag_name, const char *key_name, const char *key_value,
+ switch_event_t *params, void *user_data)
+{
+ char *event_buf = NULL;
+ switch_xml_t xml = NULL;
+ char *auth_method = switch_event_get_header(params,"sip_auth_method");
+
+
+ if ( GLOBAL_DEBUG ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: starting authentication\n");
+ switch_event_serialize(params, &event_buf, SWITCH_TRUE);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Event: %s \n", event_buf);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Section: %s \nTag: %s\nKey_name: %s\nKey_value: %s\n",
+ section, tag_name, key_name, key_value);
+ }
+
+ if ( auth_method == NULL) {
+ return NULL;
+ }
+
+ if ( strncmp( "INVITE", auth_method, 6) == 0) {
+ xml = mod_xml_radius_auth_invite(params);
+ } else {
+ xml = NULL;
+ }
+
+ return xml;
+}
+
+switch_status_t mod_xml_radius_accounting_start(switch_core_session_t *session){
+ VALUE_PAIR *send = NULL;
+ uint32_t service = PW_STATUS_START;
+ rc_handle *new_handle = NULL;
+ switch_xml_t fields;
+
+ if (GLOBAL_DEBUG ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: starting accounting start\n");
+ }
+
+ mod_xml_radius_new_handle(&new_handle, globals.acct_start_configs);
+
+ if ((fields = switch_xml_child(globals.acct_start_configs, "fields")) == NULL ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find 'fields' section in config file.\n");
+ goto end;
+ }
+
+ if ( mod_xml_radius_add_params(session, NULL, new_handle, &send, fields) != SWITCH_STATUS_SUCCESS ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to add params to rc_handle\n");
+ goto end;
+ }
+
+ if (rc_avpair_add(new_handle, &send, PW_ACCT_STATUS_TYPE, &service, -1, 0) == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option to handle\n");
+ goto end;
+ }
+
+ if (rc_acct(new_handle, 0, send) == OK_RC) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "mod_xml_radius: Accounting Start success\n");
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: Accounting Start failed\n");
+ }
+
+ end:
+ rc_destroy(new_handle);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t mod_xml_radius_accounting_end(switch_core_session_t *session){
+ VALUE_PAIR *send = NULL;
+ uint32_t service = PW_STATUS_STOP;
+ rc_handle *new_handle = NULL;
+ switch_xml_t fields;
+
+ if (GLOBAL_DEBUG ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: starting accounting stop\n");
+ switch_core_session_execute_application(session, "info", NULL);
+ }
+
+ mod_xml_radius_new_handle(&new_handle, globals.acct_end_configs);
+
+ if ((fields = switch_xml_child(globals.acct_end_configs, "fields")) == NULL ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find 'fields' section in config file.\n");
+ goto end;
+ }
+
+ if ( mod_xml_radius_add_params(session, NULL, new_handle, &send, fields) != SWITCH_STATUS_SUCCESS ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to add params to rc_handle\n");
+ goto end;
+ }
+
+ if (rc_avpair_add(new_handle, &send, PW_ACCT_STATUS_TYPE, &service, -1, 0) == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option to handle\n");
+ goto end;
+ }
+
+ if (rc_acct(new_handle, 0, send) == OK_RC) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "mod_xml_radius: Accounting Stop success\n");
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: Accounting Stop failed\n");
+ }
+
+ end:
+ rc_destroy(new_handle);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_STANDARD_APP(radius_auth_handle)
+{
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+
+ int result = 0;
+ VALUE_PAIR *send = NULL, *recv = NULL, *service_vp = NULL;
+ char msg[512 * 10 + 1] = {0};
+ uint32_t service = PW_AUTHENTICATE_ONLY;
+ rc_handle *new_handle = NULL;
+ switch_xml_t fields;
+ char name[512], value[512];
+
+ if (GLOBAL_DEBUG ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: starting app authentication\n");
+ }
+
+ mod_xml_radius_new_handle(&new_handle, globals.auth_app_configs);
+
+ if ( new_handle == NULL ) {
+ goto err;
+ }
+
+ if ((fields = switch_xml_child(globals.auth_app_configs, "fields")) == NULL ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find 'fields' section in config file.\n");
+ goto err;
+ }
+
+ if ( mod_xml_radius_add_params(session, NULL, new_handle, &send, fields) != SWITCH_STATUS_SUCCESS ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to add params to rc_handle\n");
+ goto err;
+ }
+
+ if (rc_avpair_add(new_handle, &send, PW_SERVICE_TYPE, &service, -1, 0) == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: failed to add option to handle\n");
+ goto err;
+ }
+
+ result = rc_auth(new_handle, 0, send, &recv, msg);
+
+ if ( GLOBAL_DEBUG ){
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: result(RC=%d) %s \n", result, msg);
+ }
+
+ switch_channel_set_variable(channel, "radius_auth_result", switch_mprintf("%d",result));
+
+ if ( result != 0 ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: Failed to authenticate\n");
+ goto err;
+ }
+
+
+ service_vp = recv;
+ while (service_vp != NULL) {
+ rc_avpair_tostr(new_handle, service_vp, name, 512, value, 512);
+ if ( GLOBAL_DEBUG )
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "\tattribute (%s)[%s] found in radius packet\n", name, value);
+
+ switch_channel_set_variable(channel, name, value);
+ service_vp = service_vp->next;
+ }
+
+ rc_avpair_free(recv);
+ rc_destroy(new_handle);
+ return;
+ err:
+ if ( recv ) {
+ rc_avpair_free(recv);
+ recv = NULL;
+ }
+ if ( new_handle ) {
+ rc_destroy(new_handle);
+ new_handle = NULL;
+ }
+
+ return;
+}
+
+static const switch_state_handler_table_t state_handlers = {
+ /*.on_init */ NULL,
+ /*.on_routing */ mod_xml_radius_accounting_start,
+ /*.on_execute */ NULL,
+ /*.on_hangup */ NULL,
+ /*.on_exchange_media */ NULL,
+ /*.on_soft_execute */ NULL,
+ /*.on_consume_media */ NULL,
+ /*.on_hibernate */ NULL,
+ /*.on_reset */ NULL,
+ /*.on_park */ NULL,
+ /*.on_reporting */ mod_xml_radius_accounting_end
+};
+
+
+/* switch_status_t name (switch_loadable_module_interface_t **module_interface, switch_memory_pool_t *pool) */
+SWITCH_MODULE_LOAD_FUNCTION(mod_xml_radius_load)
+{
+ switch_api_interface_t *mod_xml_radius_api_interface;
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
+ switch_application_interface_t *app_interface;
+
+ /* connect my internal structure to the blank pointer passed to me */
+ *module_interface = switch_loadable_module_create_module_interface(pool, modname);
+
+ memset(&globals, 0, sizeof(globals));
+ globals.pool = pool;
+
+ if ( GLOBAL_DEBUG != 0 ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: loading\n");
+ }
+
+ if ( (status = do_config()) != SWITCH_STATUS_SUCCESS ) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: Failed to load configs\n");
+ return SWITCH_STATUS_TERM;
+ }
+
+ if ( globals.auth_invite_configs ) {
+ status = switch_xml_bind_search_function(mod_xml_radius_directory_search, switch_xml_parse_section_string("directory"), NULL);
+ }
+
+ SWITCH_ADD_API(mod_xml_radius_api_interface, "xml_radius_connect_test", "mod_xml_radius connection test", mod_xml_radius_connect_test, NULL);
+
+ switch_core_add_state_handler(&state_handlers);
+
+ SWITCH_ADD_APP(app_interface, "radius_auth", NULL, NULL, radius_auth_handle, "radius_auth", SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
+
+ /* indicate that the module should continue to be loaded */
+ return SWITCH_STATUS_SUCCESS;
+}
+
+SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_xml_radius_shutdown)
+{
+ switch_core_remove_state_handler(&state_handlers);
+ switch_xml_unbind_search_function_ptr(mod_xml_radius_directory_search);
+
+ if ( globals.auth_invite_configs ) {
+ switch_xml_free(globals.auth_invite_configs);
+ }
+ return SWITCH_STATUS_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4:
+ */
diff --git a/src/mod/xml_int/mod_xml_radius/xml_radius.conf.xml b/src/mod/xml_int/mod_xml_radius/xml_radius.conf.xml
new file mode 100644
index 0000000000..3340cf17b4
--- /dev/null
+++ b/src/mod/xml_int/mod_xml_radius/xml_radius.conf.xml
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+