]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Adding functionality to mod_xml_radius. Now you can do conditional accounting. And...
authorWilliam King <william.king@quentustech.com>
Wed, 15 Aug 2012 21:52:02 +0000 (14:52 -0700)
committerWilliam King <william.king@quentustech.com>
Wed, 15 Aug 2012 21:52:13 +0000 (14:52 -0700)
src/mod/xml_int/mod_xml_radius/00_dialplan_auth.xml
src/mod/xml_int/mod_xml_radius/mod_xml_radius.c
src/mod/xml_int/mod_xml_radius/xml_radius.conf.xml

index 4085a68de07fb13f927dfca00b68b4c86050dc35..8b8ceae9cd6c782d69da363238b6b9260318a4de 100644 (file)
@@ -1,7 +1,7 @@
 <include>
 
   <extension name="auth" continue="true">
-    <condition>
+    <condition field="${radius_auth_result}" expression="^$">
       <action application="radius_auth" inline="true"/>
     </condition>
   </extension>
     </condition>
   </extension>
 
+  <extension name="originate_leg" continue="true">
+    <condition>
+      <action application="export" data="nolocal:h323-call-origin=originate"/>
+    </condition>
+  </extension>
 </include>
 
index 9a5176bcee5497a9425d3a60c7415c78f8a377a9..2a74f9cff9ea9b6f7bb9ac4923ffd71d5f0361c6 100644 (file)
@@ -34,6 +34,7 @@
 static struct {
        switch_memory_pool_t *pool;
        switch_xml_t auth_invite_configs;
+       switch_xml_t auth_reg_configs;
        switch_xml_t auth_app_configs;
        switch_xml_t acct_start_configs;
        switch_xml_t acct_end_configs;
@@ -149,7 +150,42 @@ switch_status_t do_config()
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Could not find 'auth_invite' section in config file.\n");               
        }
        
-       if ((tmp = switch_xml_dup(switch_xml_child(cfg, "auth_app"))) == NULL ) {
+       serv = timeout = deadtime = retries = dict = seq = 0;
+       if ((tmp = switch_xml_dup(switch_xml_child(cfg, "auth_reg"))) != NULL ) {
+               if ( (server = switch_xml_child(tmp, "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_reg_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");               
+       }
+       
+       serv = timeout = deadtime = retries = dict = seq = 0;
+       if ((tmp = switch_xml_dup(switch_xml_child(cfg, "auth_app"))) != NULL ) {
                if ( (server = switch_xml_child(tmp, "connection")) != NULL) {
                                for (param = switch_xml_child(server, "param"); param; param = param->next) {
                                        char *var = (char *) switch_xml_attr_soft(param, "name");
@@ -182,7 +218,8 @@ switch_status_t do_config()
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Could not find 'auth_app' section in config file.\n");          
        }
        
-       if (( tmp = switch_xml_dup(switch_xml_child(cfg, "acct_start"))) == NULL ) {
+       serv = timeout = deadtime = retries = dict = seq = 0;
+       if (( tmp = switch_xml_dup(switch_xml_child(cfg, "acct_start"))) != NULL ) {
                if ( (server = switch_xml_child(tmp, "connection")) != NULL) {
                                for (param = switch_xml_child(server, "param"); param; param = param->next) {
                                        char *var = (char *) switch_xml_attr_soft(param, "name");
@@ -215,7 +252,8 @@ switch_status_t do_config()
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Could not find 'acct_start' section in config file.\n");                
        }
        
-       if (( tmp = switch_xml_dup(switch_xml_child(cfg, "acct_end"))) == NULL ) {
+       serv = timeout = deadtime = retries = dict = seq = 0;
+       if (( tmp = switch_xml_dup(switch_xml_child(cfg, "acct_end"))) != NULL ) {
                if ( (server = switch_xml_child(tmp, "connection")) != NULL) {
                                for (param = switch_xml_child(server, "param"); param; param = param->next) {
                                        char *var = (char *) switch_xml_attr_soft(param, "name");
@@ -281,8 +319,11 @@ switch_status_t mod_xml_radius_add_params(switch_core_session_t *session, switch
                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 *variable_secondary = (char *) switch_xml_attr(param, "variable_secondary");
+               char *val_default = (char *) switch_xml_attr(param, "default");
                char *format = (char *) switch_xml_attr(param, "format");
-               
+               char *other_leg = (char *) switch_xml_attr(param, "other_leg");
+
                attribute = rc_dict_findattr(handle, var);
                
                if ( attribute == NULL ) {
@@ -375,8 +416,36 @@ switch_status_t mod_xml_radius_add_params(switch_core_session_t *session, switch
                                        }                       
                                        
                                } else {
+                                       if ( format == NULL ) {
+                                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing format attribute for %s variable\n", variable);
+                                               goto err;
+                                       }
+
                                        if ( attribute->type == 0 ) {
-                                               av_value = switch_mprintf(format, switch_channel_get_variable(channel, variable));
+                                               const char *val = NULL;
+                                               
+                                               if ( other_leg ) {
+                                                       val = switch_channel_get_variable_partner(channel, variable);
+                                                       if ( val == NULL && variable_secondary != NULL) {
+                                                               val = switch_channel_get_variable_partner(channel, variable_secondary);
+                                                       }
+                                               } else {
+                                                       val = switch_channel_get_variable(channel, variable);
+                                                       if ( val == NULL && variable_secondary != NULL) {
+                                                               val = switch_channel_get_variable(channel, variable_secondary);
+                                                       }
+                                               }
+                                               
+                                               if ( val == NULL && val_default != NULL) {
+                                                       av_value = switch_mprintf(format, val_default);                                                 
+                                               } else {
+                                                       av_value = switch_mprintf(format, val);
+                                               }
+                                               
+                                               if ( GLOBAL_DEBUG ) {
+                                                       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: value: %s\n", (char *) av_value);
+                                               }
+                               
                                                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;
@@ -487,7 +556,10 @@ switch_xml_t mod_xml_radius_auth_invite(switch_event_t *params) {
                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 ( mod_xml_radius_new_handle(&new_handle, globals.auth_invite_configs) != SWITCH_STATUS_SUCCESS ) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to load radius handle\n");
+               goto err;               
+       }
 
        if ( new_handle == NULL ) {
                goto err;
@@ -565,6 +637,100 @@ switch_xml_t mod_xml_radius_auth_invite(switch_event_t *params) {
        return NULL;
 }
 
+switch_xml_t mod_xml_radius_auth_reg(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 registration authentication\n");
+       }
+       
+       if ( mod_xml_radius_new_handle(&new_handle, globals.auth_invite_configs) != SWITCH_STATUS_SUCCESS ) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to load radius handle\n");
+               goto err;               
+       }
+
+       if ( new_handle == NULL ) {
+               goto err;
+       }
+       
+       if ((fields = switch_xml_child(globals.auth_reg_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)
 {
@@ -584,9 +750,11 @@ static switch_xml_t mod_xml_radius_directory_search(const char *section, const c
        if ( auth_method == NULL) {
                return NULL;
        }
-
+       
        if ( strncmp( "INVITE", auth_method, 6) == 0) {
                xml = mod_xml_radius_auth_invite(params);
+       } else if ( strncmp( "REGISTER", auth_method, 8) == 0) {
+               xml = mod_xml_radius_auth_reg(params);
        } else {
                xml = NULL;
        }
@@ -622,6 +790,7 @@ switch_status_t mod_xml_radius_check_conditions(switch_channel_t *channel, switc
                        }
                        
                        if ( switch_regex_match( switch_channel_get_variable(channel, channel_var), regex) != SWITCH_STATUS_SUCCESS) {
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Didn't match: %s == %s \n", switch_channel_get_variable(channel, channel_var), regex);
                                all_matched = 0;
                        }
                }
@@ -643,6 +812,7 @@ switch_status_t mod_xml_radius_accounting_start(switch_core_session_t *session){
 
        if (GLOBAL_DEBUG ) {
                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: starting accounting start\n");
+               switch_core_session_execute_application(session, "info", NULL);
        }
 
        /* If there are conditions defined, and none of them pass, then skip this accounting */
@@ -651,7 +821,10 @@ switch_status_t mod_xml_radius_accounting_start(switch_core_session_t *session){
                goto end;
        }
        
-       mod_xml_radius_new_handle(&new_handle, globals.acct_start_configs);
+       if ( mod_xml_radius_new_handle(&new_handle, globals.acct_start_configs) != SWITCH_STATUS_SUCCESS ) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to load radius handle\n");
+               goto end;               
+       }
 
        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");           
@@ -700,7 +873,10 @@ switch_status_t mod_xml_radius_accounting_end(switch_core_session_t *session){
                goto end;
        }
        
-       mod_xml_radius_new_handle(&new_handle, globals.acct_end_configs);
+       if ( mod_xml_radius_new_handle(&new_handle, globals.acct_end_configs) != SWITCH_STATUS_SUCCESS ) {
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to load radius handle\n");
+               goto end;               
+       }
 
        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");           
@@ -724,8 +900,10 @@ switch_status_t mod_xml_radius_accounting_end(switch_core_session_t *session){
        }
 
  end:
-       rc_destroy(new_handle);
-
+       if ( new_handle) {
+               rc_destroy(new_handle);
+       }
+       
        return SWITCH_STATUS_SUCCESS;
 }
 
index cb0ec3a01a67415b62bc4cf34fc461aee84d9460..eb3070c929e47531a7436fe1550665d2f22b4e30 100644 (file)
       <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 vendor="Cisco" name="Cisco-AVPair" variable="ip" format="number"/>
       <param name="Called-Station-Id" variable="sip_to_user" format="%s"/>
       <param name="Calling-Station-Id" variable="sip_from_user" format="%s"/>
+      <param name="User-Name" variable="sip_from_user" format="%s"/>
+      <param name="Digest-Response" variable="sip_auth_response" format="%s"/>
+      <param name="Digest-Realm" variable="sip_auth_realm" format="%s"/>
+      <param name="Digest-Nonce" variable="sip_auth_nonce" format="%s"/>
+      <param name="Digest-Username" variable="sip_auth_username" format="%s"/> 
+      <param name="Digest-URI" variable="sip_auth_uri" format="%s"/>
+      <param name="Digest-Method" variable="sip_auth_method" format="%s"/>
+      <param name="Digest-Algorithm" variable="sip_auth_method" format="MD5"/>
+      <param name="Digest-Qop" variable="sip_auth_qop" format="%s"/>
+      <param name="Digest-CNonce" variable="sip_auth_cnonce" format="%s"/>
+      <param name="Digest-Nonce-Count" variable="sip_auth_nc" format="%s"/> 
     </fields>
   </auth_invite>
+  <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/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="user"/>
+      <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 name="User-Name" variable="sip_from_user" format="%s"/>
+      <param name="Digest-Response" variable="sip_auth_response" format="%s"/>
+      <param name="Digest-Realm" variable="sip_auth_realm" format="%s"/>
+      <param name="Digest-Nonce" variable="sip_auth_nonce" format="%s"/>
+      <param name="Digest-Username" variable="sip_auth_username" format="%s"/>
+      <param name="Digest-URI" variable="sip_auth_uri" format="%s"/>
+      <param name="Digest-Method" variable="sip_auth_method" format="%s"/>
+      <param name="Digest-Algorithm" variable="sip_auth_method" format="MD5"/>
+      <param name="Digest-Qop" variable="sip_auth_qop" format="%s"/>
+      <param name="Digest-CNonce" variable="sip_auth_cnonce" format="%s"/>
+      <param name="Digest-Nonce-Count" variable="sip_auth_nc" format="%s"/>
+    </fields>
+  </auth_reg>
   <auth_app>
     <connection name="testing">
       <param name="authserver" value="127.0.0.1:1812:testing123"/>
@@ -36,7 +74,7 @@
       <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_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="h323-conf-id" variable="Core-UUID" format="%s"/>
       <param name="Called-Station-Id" variable="sip_to_user" format="%s"/>
     <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="Cisco-AVPair" variable="sip_to_host" format="dst-gw-ip=%s"/>  
+      <param vendor="Cisco" name="h323-conf-id" variable_secondary="uuid" variable="originating_leg_uuid" format="%s"/>
       <param vendor="Cisco" name="h323-setup-time"/>
       <param vendor="Cisco" name="h323-connect-time"/>
+      <param vendor="Cisco" name="h323-call-origin" variable="h323-call-origin" default="answer" 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>
-    <conditions>
+<!--    <conditions>
       <condition>
-       <param var="direction" regex="inbound"/>
-      </condition>
-    </conditions>
+       <param var="direction" regex="^outbound$"/>
+      </condition> 
+    </conditions> -->
   </acct_start>
   <acct_end>
     <connection name="testing">
     <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="Cisco-AVPair" variable="sip_to_host" format="dst-gw-ip=%s"/> 
+      <param vendor="Cisco" name="h323-conf-id" variable_secondary="uuid" variable="originating_leg_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 vendor="Cisco" name="h323-call-origin" variable="h323-call-origin" format="%s" default="answer"/>
       <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>
-    <conditions>
+<!--    <conditions>
       <condition>
-       <param var="direction" regex="inbound"/>
-      </condition>
-    </conditions>
+       <param var="direction" regex="^outbound$"/>
+      </condition> 
+    </conditions> -->
   </acct_end>
 </configuration>