Adding a new configurable radius module that will support both authentication based on a dialplan app, as well as digest based radius authentication by hooking into the directory. It is also fully configurable on which fields to send by the config file.

This commit is contained in:
William King 2012-08-04 19:19:04 -04:00
parent d1c3f910a6
commit d648a05ed1
8 changed files with 1408 additions and 0 deletions

View File

@ -0,0 +1 @@
freeradius-client*

View File

@ -0,0 +1,22 @@
<include>
<extension name="auth" continue="true">
<condition field="radius_auth_result" expression="^$">
<action application="radius_auth" inline="true"/>
</condition>
</extension>
<extension name="rejctions">
<condition field="${radius_auth_result}" expression="2">
<action application="hangup" data="CALL_REJECTED"/>
</condition>
</extension>
<extension name="timedouts">
<condition field="${radius_auth_result}" expression="1">
<action application="hangup" data="SWITCH_CONGESTION"/>
</condition>
</extension>
</include>

View File

@ -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)

View File

@ -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

View File

@ -0,0 +1,161 @@
# -*- text -*-
#
# dictionary.cisco
#
# Accounting VSAs originally by
# "Marcelo M. Sosa Lugones" <marcelo@sosa.com.ar>
#
# 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

View File

@ -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

View File

@ -0,0 +1,824 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2012, Anthony Minessale II <anthm@freeswitch.org>
*
* 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 <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* William King <william.king@quentustech.com>
*
* mod_xml_radius.c -- Radius authentication and authorization
*
*/
#include <switch.h>
#include <freeradius-client.h>
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:
*/

View File

@ -0,0 +1,103 @@
<configuration name="xml_radius.conf" description="Radius XML Gateway">
<!--
auth_invite is only called when a directory lookup is done on an inbound invite. Usually that means a digest auth challenge on the invite.
auth_reg is only called on the actual registration.
auth_app is used when an invite is in the dialplan. If your profile requires digest auth then this isn't needed.
but if your profile is doing only ip authentication this allows you to authenticate the call without the need for digest auth.
acct_start happens when the call goes into the state 'routing' which means it is starting the dialplan
-->
<auth_invite>
<connection name="testing">
<param name="authserver" value="127.0.0.1:1812:testing123"/>
<param name="radius_timeout" value="10"/>
<param name="radius_retries" value="2"/>
<param name="radius_deadtime" value="0"/>
<param name="dictionary" value="/usr/local/src/freeswitch/src/mod/xml_int/mod_xml_radius/dictionaries/dictionary"/>
<param name="seqfile" value="/var/run/radius.seq"/>
</connection>
<fields>
<param vendor="Cisco" name="Cisco-AVPair" variable="ip" format="src-gw-ip=%s"/>
<param vendor="Cisco" name="Cisco-AVPair" variable="sip_from_user" format="src-gw-name=%s"/>
<param vendor="Cisco" name="h323-conf-id" variable="Core-UUID" format="%s"/>
<param name="Called-Station-Id" variable="sip_to_user" format="%s"/>
<param name="Calling-Station-Id" variable="sip_from_user" format="%s"/>
</fields>
</auth_invite>
<auth_app>
<connection name="testing">
<param name="authserver" value="127.0.0.1:1812:testing123"/>
<param name="radius_timeout" value="10"/>
<param name="radius_retries" value="2"/>
<param name="radius_deadtime" value="0"/>
<param name="dictionary" value="/usr/local/src/freeswitch/src/mod/xml_int/mod_xml_radius/dictionaries/dictionary"/>
<param name="seqfile" value="/var/run/radius.seq"/>
</connection>
<fields>
<param vendor="Cisco" name="Cisco-AVPair" variable="sip_network_ip" format="src-gw-ip=%s"/>
<param vendor="Cisco" name="Cisco-AVPair" variable="sip_from_user" format="src-gw-name=%s"/>
<param vendor="Cisco" name="h323-conf-id" variable="Core-UUID" format="%s"/>
<param name="Called-Station-Id" variable="sip_to_user" format="%s"/>
<param name="Calling-Station-Id" variable="sip_from_user" format="%s"/>
</fields>
</auth_app>
<auth_reg>
<connection name="testing">
<param name="authserver" value="127.0.0.1:1812:testing123"/>
<param name="radius_timeout" value="10"/>
<param name="radius_retries" value="2"/>
<param name="radius_deadtime" value="0"/>
<param name="dictionary" value="/usr/share/freeradius/dictionary.cisco"/>
<param name="seqfile" value="/var/run/radius.seq"/>
</connection>
<fields>
</fields>
</auth_reg>
<acct_start>
<connection name="testing">
<param name="acctserver" value="127.0.0.1:1813:testing123"/>
<param name="radius_timeout" value="10"/>
<param name="radius_retries" value="0"/>
<param name="radius_deadtime" value="0"/>
<param name="dictionary" value="/usr/local/src/freeswitch/src/mod/xml_int/mod_xml_radius/dictionaries/dictionary"/>
<param name="seqfile" value="/var/run/radius.seq"/>
</connection>
<fields>
<param vendor="Cisco" name="Cisco-AVPair" variable="sip_from_host" format="src-gw-ip=%s"/>
<param vendor="Cisco" name="Cisco-AVPair" variable="sip_from_user" format="src-gw-name=%s"/>
<param vendor="Cisco" name="Cisco-AVPair" variable="sip_to_host" format="dst-gw-ip=%s"/>
<param vendor="Cisco" name="h323-conf-id" variable="uuid" format="%s"/>
<param vendor="Cisco" name="h323-setup-time"/>
<param vendor="Cisco" name="h323-connect-time"/>
<param name="Called-Station-Id" variable="sip_to_user" format="%s"/>
<param name="Calling-Station-Id" variable="sip_from_user" format="%s"/>
</fields>
</acct_start>
<acct_end>
<connection name="testing">
<param name="acctserver" value="127.0.0.1:1813:testing123"/>
<param name="radius_timeout" value="10"/>
<param name="radius_retries" value="0"/>
<param name="radius_deadtime" value="0"/>
<param name="dictionary" value="/usr/local/src/freeswitch/src/mod/xml_int/mod_xml_radius/dictionaries/dictionary"/>
<param name="seqfile" value="/var/run/radius.seq"/>
</connection>
<fields>
<param vendor="Cisco" name="Cisco-AVPair" variable="sip_from_host" format="src-gw-ip=%s"/>
<param vendor="Cisco" name="Cisco-AVPair" variable="sip_from_user" format="src-gw-name=%s"/>
<param vendor="Cisco" name="Cisco-AVPair" variable="sip_to_host" format="dst-gw-ip=%s"/>
<param vendor="Cisco" name="h323-conf-id" variable="uuid" format="%s"/>
<param vendor="Cisco" name="h323-setup-time"/>
<param vendor="Cisco" name="h323-connect-time"/>
<param vendor="Cisco" name="h323-disconnect-time"/>
<param vendor="Cisco" name="h323-disconnect-cause"/>
<param name="Called-Station-Id" variable="sip_to_user" format="%s"/>
<param name="Acct-Session-Time" variable="billsec" format="%s"/>
<param name="Calling-Station-Id" variable="sip_from_user" format="%s"/>
<param vendor="Cisco" name="Cisco-AVPair" variable="sip_from_user" format="src-number-out=%s"/>
<param vendor="Cisco" name="Cisco-AVPair" variable="sip_to_user" format="dst-number-out=%s"/>
</fields>
</acct_end>
</configuration>