Exemple #1
0
/*
	Radius implementation for the dictionary_find callback

	The return value is:
	0, if the name is found
	1, if the name isn't found
	-1, if an error occured
 */
int rad_find(aaa_conn* rh, aaa_map *map, int flag) {

	DICT_ATTR *attr_result;
	DICT_VALUE *val_result;
	DICT_VENDOR *vend_result;

	if (!rh) {
		LM_ERR("invalid aaa connection argument\n");
		return -1;
	}

	if (!map) {
		LM_ERR("invalid argument\n");
		return -1;
	}

	switch (flag) {
		case AAA_DICT_FIND_VAL:
			val_result = rc_dict_findval(rh, map->name);
			if (val_result) {
				map->value = val_result->value;
				return 0;
			}
			return 1;
		case AAA_DICT_FIND_ATTR:
			attr_result = rc_dict_findattr(rh, map->name);
			if (attr_result) {
				map->value = attr_result->value;
				map->type = attr_result->type;
				return 0;
			}
			return 1;
		case AAA_DICT_FIND_VEND:
			vend_result = rc_dict_findvend(rh, map->name);
			if (vend_result) {
				map->value = vend_result->vendorpec;
				return 0;
			}
			return 1;
	}

	LM_ERR("failure\n");
	return -1;
}
Exemple #2
0
static int mod_init(void)
{
    DICT_VENDOR *vend;
    memset(attrs, 0, sizeof(attrs));
    memset(vals, 0, sizeof(vals));
    
    attrs[A_USER_NAME].n        = "User-Name";
    attrs[A_SER_SERVICE_TYPE].n = "SER-Service-Type";
    attrs[A_SER_ATTR].n	        = "SER-Attr";
    attrs[A_SER_DID].n          = "SER-DID";
    attrs[A_SER_URI_SCHEME].n   = "SER-Uri-Scheme";
    
    vals[V_GET_URI_ATTRS].n  = "Get-URI-Attrs";
    vals[V_GET_USER_ATTRS].n = "Get-User-Attrs";

	 /* open log */
    rc_openlog("ser");
    
	 /* read config */
    if ((rh = rc_read_config(radius_config)) == NULL) {
	LOG(L_ERR, "avp_radius: Error opening radius config file: %s\n",
	    radius_config);
	return -1;
    }
    
	 /* read dictionary */
    if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")) != 0) {
	LOG(L_ERR, "avp_radius: Error reading radius dictionary\n");
	return -1;
    }
    
    vend = rc_dict_findvend(rh, "iptelorg");
    if (vend == NULL) {
	ERR("RADIUS dictionary is missing required vendor 'iptelorg'\n");
	return -1;
    }

    INIT_AV(rh, attrs, vals, "avp", -1, -1);
    return 0;
}
/*
 * Module initialization function
 */
static int mod_init(void)
{
	DICT_VENDOR *vend;
	bind_auth_s_t bind_auth;
	int n;

	if ((rh = rc_read_config(radius_config)) == NULL) {
		LM_ERR("failed to open configuration file \n");
		return -1;
	}

	if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")) != 0) {
		LM_ERR("failed to open dictionary file \n");
		return -2;
	}

	bind_auth = (bind_auth_s_t)find_export("bind_auth_s", 0, 0);
	if (!bind_auth) {
		LM_ERR("unable to find bind_auth function. Check if you load the auth module.\n");
		return -1;
	}

	if (bind_auth(&auth_api) < 0) {
		LM_ERR("cannot bind to auth module\n");
		return -4;
	}

	/* init the extra engine */
	init_extra_engine();

	/* parse extra attributes (if any) */
	if (auth_extra_str &&
	    (auth_extra=parse_extra_str(auth_extra_str)) == 0 ) {
	    LM_ERR("failed to parse auth_extra parameter\n");
	    return -1;
	}

	memset(attrs, 0, sizeof(attrs));
	attrs[A_SERVICE_TYPE].n			= "Service-Type";
	attrs[A_SIP_URI_USER].n			= "Sip-URI-User";
	attrs[A_DIGEST_RESPONSE].n		= "Digest-Response";
	attrs[A_DIGEST_ALGORITHM].n		= "Digest-Algorithm";
	attrs[A_DIGEST_BODY_DIGEST].n		= "Digest-Body-Digest";
	attrs[A_DIGEST_CNONCE].n		= "Digest-CNonce";
	attrs[A_DIGEST_NONCE_COUNT].n		= "Digest-Nonce-Count";
	attrs[A_DIGEST_QOP].n			= "Digest-QOP";
	attrs[A_DIGEST_METHOD].n		= "Digest-Method";
	attrs[A_DIGEST_URI].n			= "Digest-URI";
	attrs[A_DIGEST_NONCE].n			= "Digest-Nonce";
	attrs[A_DIGEST_REALM].n			= "Digest-Realm";
	attrs[A_DIGEST_USER_NAME].n		= "Digest-User-Name";
	attrs[A_USER_NAME].n			= "User-Name";
	attrs[A_SIP_AVP].n			= "SIP-AVP";
	vend = rc_dict_findvend(rh, "Cisco");
	if (vend == NULL) {
	    LM_DBG("no `Cisco' vendor in Radius dictionary\n");
	} else {
	    attrs[A_CISCO_AVPAIR].n		= "Cisco-AVPair";
	}
	n = A_MAX;
	n += extra2attrs(auth_extra, attrs, n);
	memset(vals, 0, sizeof(vals));
	vals[V_SIP_SESSION].n			= "Sip-Session";
	INIT_AV(rh, attrs, n, vals, V_MAX, "auth_radius", -5, -6);

	if (service_type != -1) {
		vals[V_SIP_SESSION].v = service_type;
	}

	return 0;
}
int rc_read_dictionary (rc_handle *rh, const char *filename)
{
  FILE           *dictfd;
  char            dummystr[AUTH_ID_LEN];
  char            namestr[AUTH_ID_LEN];
  char            valstr[AUTH_ID_LEN];
  char            attrstr[AUTH_ID_LEN];
  char            typestr[AUTH_ID_LEN];
  char    optstr[AUTH_ID_LEN];
  char    *cp, *ifilename;
  int             line_no;
  DICT_ATTR      *attr;
  DICT_VALUE     *dval;
  DICT_VENDOR    *dvend;
  char            buffer[256];
  int             value;
  int             type;

  if ((dictfd = fopen (filename, "r")) == NULL) {
    rc_log(LOG_ERR, "rc_read_dictionary: couldn't open dictionary %s: %s",
           filename, strerror(errno));
    return -1;
  }

  line_no = 0;

  while (fgets (buffer, sizeof (buffer), dictfd) != NULL) {
    line_no++;

    /* Skip empty space */
    if (*buffer == '#' || *buffer == '\0' || *buffer == '\n' || \
        *buffer == '\r') {
      continue;
    }

    /* Strip out comments */
    cp = strchr(buffer, '#');

    if (cp != NULL) {
      *cp = '\0';
    }

    if (strncmp (buffer, "ATTRIBUTE", 9) == 0) {
      optstr[0] = '\0';

      /* Read the ATTRIBUTE line */
      if (sscanf (buffer, "%s%s%s%s%s", dummystr, namestr,
                  valstr, typestr, optstr) < 4) {
        rc_log(LOG_ERR, "rc_read_dictionary: invalid attribute on line %d of dictionary %s",
               line_no, filename);
        fclose(dictfd);
        return -1;
      }

      /*
       * Validate all entries
       */
      if (strlen (namestr) > NAME_LENGTH) {
        rc_log(LOG_ERR, "rc_read_dictionary: invalid name length on line %d of dictionary %s",
               line_no, filename);
        fclose(dictfd);
        return -1;
      }

      if (!isdigit (*valstr)) {
        rc_log(LOG_ERR,
               "rc_read_dictionary: invalid value on line %d of dictionary %s",
               line_no, filename);
        fclose(dictfd);
        return -1;
      }

      value = atoi (valstr);

      if (strcmp (typestr, "string") == 0) {
        type = PW_TYPE_STRING;
      } else if (strcmp (typestr, "integer") == 0) {
        type = PW_TYPE_INTEGER;
      } else if (strcmp (typestr, "ipaddr") == 0) {
        type = PW_TYPE_IPADDR;
      } else if (strcmp (typestr, "ipv6addr") == 0) {
        type = PW_TYPE_IPV6ADDR;
      } else if (strcmp (typestr, "date") == 0) {
        type = PW_TYPE_DATE;
      } else {
        rc_log(LOG_ERR,
               "rc_read_dictionary: invalid type on line %d of dictionary %s",
               line_no, filename);
        fclose(dictfd);
        return -1;
      }

      dvend = NULL;

      if (optstr[0] != '\0') {
        char *cp1;

        for (cp1 = optstr; cp1 != NULL; cp1 = cp) {
          cp = strchr(cp1, ',');

          if (cp != NULL) {
            *cp = '\0';
            cp++;
          }

          if (strncmp(cp1, "vendor=", 7) == 0)
            cp1 += 7;

          dvend = rc_dict_findvend(rh, cp1);

          if (dvend == NULL) {
            rc_log(LOG_ERR,
                   "rc_read_dictionary: unknown Vendor-Id %s on line %d of dictionary %s",
                   cp1, line_no, filename);
            fclose(dictfd);
            return -1;
          }
        }
      }

      /* Create a new attribute for the list */
      if ((attr = malloc (sizeof (DICT_ATTR))) == NULL) {
        rc_log(LOG_CRIT, "rc_read_dictionary: out of memory");
        fclose(dictfd);
        return -1;
      }

      strcpy (attr->name, namestr);
      attr->value = value;
      attr->type = type;

      if (dvend != NULL)
        attr->value |= (dvend->vendorpec << 16);

      //rc_log(LOG_ERR, "rc_read_dictionary: ADD ATTRIBUTE Name %s Value %d Type %d",attr->name, attr->value, attr->type);
      /* Insert it into the list */
      attr->next = rh->dictionary_attributes;
      rh->dictionary_attributes = attr;
    } else if (strncmp (buffer, "VALUE", 5) == 0) {
      /* Read the VALUE line */
      if (sscanf (buffer, "%s%s%s%s", dummystr, attrstr,
                  namestr, valstr) != 4) {
        rc_log(LOG_ERR,
               "rc_read_dictionary: invalid value entry on line %d of dictionary %s",
               line_no, filename);
        fclose(dictfd);
        return -1;
      }

      /*
       * Validate all entries
       */
      if (strlen (attrstr) > NAME_LENGTH) {
        rc_log(LOG_ERR,
               "rc_read_dictionary: invalid attribute length on line %d of dictionary %s",
               line_no, filename);
        fclose(dictfd);
        return -1;
      }

      if (strlen (namestr) > NAME_LENGTH) {
        rc_log(LOG_ERR,
               "rc_read_dictionary: invalid name length on line %d of dictionary %s",
               line_no, filename);
        fclose(dictfd);
        return -1;
      }

      if (!isdigit (*valstr)) {
        rc_log(LOG_ERR,
               "rc_read_dictionary: invalid value on line %d of dictionary %s",
               line_no, filename);
        fclose(dictfd);
        return -1;
      }

      value = atoi (valstr);

      /* Create a new VALUE entry for the list */
      if ((dval = malloc (sizeof (DICT_VALUE))) == NULL) {
        rc_log(LOG_CRIT, "rc_read_dictionary: out of memory");
        fclose(dictfd);
        return -1;
      }

      strcpy (dval->attrname, attrstr);
      strcpy (dval->name, namestr);
      dval->value = value;

      //rc_log(LOG_ERR, "rc_read_dictionary: ADD VALUE Name %s Value %s Type %d",dval->attrname, dval->name, dval->value);
      /* Insert it into the list */
      dval->next = rh->dictionary_values;
      rh->dictionary_values = dval;
    } else if (strncmp (buffer, "$INCLUDE", 8) == 0) {
      /* Read the $INCLUDE line */
      if (sscanf (buffer, "%s%s", dummystr, namestr) != 2) {
        rc_log(LOG_ERR,
               "rc_read_dictionary: invalid include entry on line %d of dictionary %s",
               line_no, filename);
        fclose(dictfd);
        return -1;
      }

      ifilename = namestr;

      /* Append directory if necessary */
      if (namestr[0] != '/') {
        cp = strrchr(filename, '/');

        if (cp != NULL) {
          ifilename = alloca(AUTH_ID_LEN);
          *cp = '\0';
          sprintf(ifilename, "%s/%s", filename, namestr);
          *cp = '/';
        }
      }

      if (rc_read_dictionary(rh, ifilename) < 0) {
        fclose(dictfd);
        return -1;
      }
    } else if (strncmp (buffer, "VENDOR", 6) == 0) {
      /* Read the VALUE line */
      if (sscanf (buffer, "%s%s%s", dummystr, attrstr, valstr) != 3) {
        rc_log(LOG_ERR,
               "rc_read_dictionary: invalid Vendor-Id on line %d of dictionary %s",
               line_no, filename);
        fclose(dictfd);
        return -1;
      }

      /* Validate all entries */
      if (strlen (attrstr) > NAME_LENGTH) {
        rc_log(LOG_ERR,
               "rc_read_dictionary: invalid attribute length on line %d of dictionary %s",
               line_no, filename);
        fclose(dictfd);
        return -1;
      }

      if (!isdigit (*valstr)) {
        rc_log(LOG_ERR,
               "rc_read_dictionary: invalid Vendor-Id on line %d of dictionary %s",
               line_no, filename);
        fclose(dictfd);
        return -1;
      }

      value = atoi (valstr);

      /* Create a new VENDOR entry for the list */
      dvend = malloc(sizeof(DICT_VENDOR));

      if (dvend == NULL) {
        rc_log(LOG_CRIT, "rc_read_dictionary: out of memory");
        fclose(dictfd);
        return -1;
      }

      strcpy (dvend->vendorname, attrstr);
      dvend->vendorpec = value;

      /* Insert it into the list */
      dvend->next = rh->dictionary_vendors;
      rh->dictionary_vendors = dvend;
    }
  }

  fclose (dictfd);
  return 0;
}
static int mod_init(void)
{
	DICT_VENDOR *vend;
	load_tm_f load_tm;

	     /* import the TM auto-loading function */
	if ( !(load_tm=(load_tm_f)find_export("load_tm", NO_SCRIPT, 0))) {
		LOG(L_ERR, "ERROR:acc:mod_init: can't import load_tm\n");
		return -1;
	}
	     /* let the auto-loading function load all TM stuff */
	if (load_tm( &tmb )==-1) return -1;
	if (verify_fmt(log_fmt)==-1) return -1;

	     /* register callbacks*/
	     /* listen for all incoming requests  */
	if (tmb.register_tmcb( 0, 0, TMCB_REQUEST_IN, on_req, 0, 0) <= 0) {
		LOG(L_ERR,"ERROR:acc:mod_init: cannot register TMCB_REQUEST_IN "
		    "callback\n");
		return -1;
	}

	memset(attrs, 0, sizeof(attrs));
	memset(vals, 0, sizeof(vals));

	attrs[A_USER_NAME].n		     = "User-Name";
	attrs[A_SERVICE_TYPE].n		     = "Service-Type";
	attrs[A_CALLED_STATION_ID].n	     = "Called-Station-Id";
	attrs[A_CALLING_STATION_ID].n	     = "Calling-Station-Id";
	attrs[A_ACCT_STATUS_TYPE].n	     = "Acct-Status-Type";
	attrs[A_ACCT_SESSION_ID].n	     = "Acct-Session-Id";

	attrs[A_SIP_METHOD].n		     = "Sip-Method";
	attrs[A_SIP_RESPONSE_CODE].n	     = "Sip-Response-Code";
	attrs[A_SIP_CSEQ].n		     = "Sip-CSeq";
	attrs[A_SIP_TO_TAG].n		     = "Sip-To-Tag";
	attrs[A_SIP_FROM_TAG].n		     = "Sip-From-Tag";
	attrs[A_SIP_TRANSLATED_REQUEST_ID].n = "Sip-Translated-Request-Id";
	attrs[A_SIP_SOURCE_IP_ADDRESS].n     = "Sip-Source-IP-Address";
	attrs[A_SIP_SOURCE_PORT].n           = "Sip-Source-Port";

	attrs[A_SER_ATTR].n                  = "SER-Attr";
	attrs[A_SER_FROM].n                  = "SER-From";
	attrs[A_SER_FLAGS].n                 = "SER-Flags";
	attrs[A_SER_ORIGINAL_REQUEST_ID].n   = "SER-Original-Request-Id";
	attrs[A_SER_TO].n                    = "SER-To";
	attrs[A_SER_DIGEST_USERNAME].n       = "SER-Digest-Username";
	attrs[A_SER_DIGEST_REALM].n          = "SER-Digest-Realm";
	attrs[A_SER_REQUEST_TIMESTAMP].n     = "SER-Request-Timestamp";
	attrs[A_SER_TO_DID].n                = "SER-To-DID";
	attrs[A_SER_FROM_UID].n              = "SER-From-UID";
	attrs[A_SER_FROM_DID].n              = "SER-From-DID";
	attrs[A_SER_TO_UID].n                = "SER-To-UID";
	attrs[A_SER_RESPONSE_TIMESTAMP].n    = "SER-Response-Timestamp";
	attrs[A_SER_SERVER_ID].n             = "SER-Server-ID";

	vals[V_START].n			     = "Start";
	vals[V_STOP].n			     = "Stop";
	vals[V_INTERIM_UPDATE].n             = "Interim-Update";
	vals[V_FAILED].n		     = "Failed";
	vals[V_SIP_SESSION].n		     = "Sip-Session";

	     /* open log */
	rc_openlog("ser");
	     /* read config */
	if ((rh = rc_read_config(radius_config)) == NULL) {
		LOG(L_ERR, "ERROR:acc:mod_init: Error opening radius config file: %s\n",
		    radius_config);
		return -1;
	}
	     /* read dictionary */
	if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")) != 0) {
		LOG(L_ERR, "ERROR:acc:mod_init: Error reading radius dictionary\n");
		return -1;
	}

	vend = rc_dict_findvend(rh, "iptelorg");
	if (vend == NULL) {
		ERR("RADIUS dictionary is missing required vendor 'iptelorg'\n");
		return -1;
	}

	INIT_AV(rh, attrs, vals, "acc", -1, -1);

	if (service_type != -1) {
		vals[V_SIP_SESSION].v = service_type;
	}

	if (parse_attrs(&avps, &avps_n, attrs_param) < 0) {
		ERR("Error while parsing 'attrs' module parameter\n");
		return -1;
	}

	return 0;
}
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;
	void *av_value = NULL;
	
	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;
		
		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 ) {
			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;
					
					if ( !time ) {
						goto end_loop;
					}
					
					switch_time_exp_lt(&tm, time);
					
					if ( GLOBAL_TIME_FORMAT == 1 ) {
						av_value = switch_mprintf("%02u:%02u:%02u.%03u %s %s %s %02u %04u",
												  tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec/1000,
												  GLOBAL_TIME_ZONE, radattrdays[tm.tm_wday], radattrmonths[tm.tm_mon],
												  tm.tm_mday, tm.tm_year + 1900);
					} else {
						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;
					} 
					if ( GLOBAL_DEBUG ) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: value: %s\n", (char *) av_value);
					}
				} 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;

					if ( !time ) {
						goto end_loop;
					}
					
					switch_time_exp_lt(&tm, time);

					if ( GLOBAL_TIME_FORMAT == 1 ) {
						av_value = switch_mprintf("%02u:%02u:%02u.%03u %s %s %s %02u %04u",
												  tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec/1000,
												  GLOBAL_TIME_ZONE, radattrdays[tm.tm_wday], radattrmonths[tm.tm_mon],
												  tm.tm_mday, tm.tm_year + 1900);
					} else {
						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;
					} 
					if ( GLOBAL_DEBUG ) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: value: %s\n", (char *) av_value);
					}
				} 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;

					if ( !time ) {
						if ( variable_secondary != NULL && strncmp(variable_secondary, "now", 3) == 0 ) {
							time = switch_time_now();
						} else {
							goto end_loop;
						}
					}
					
					switch_time_exp_lt(&tm, time);

					if ( GLOBAL_TIME_FORMAT == 1 ) {
						av_value = switch_mprintf("%02u:%02u:%02u.%03u %s %s %s %02u %04u",
												  tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_usec/1000,
												  GLOBAL_TIME_FORMAT, radattrdays[tm.tm_wday], radattrmonths[tm.tm_mon],
												  tm.tm_mday, tm.tm_year + 1900);
					} else {
						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;
					} 
					if ( GLOBAL_DEBUG ) {
						switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mod_xml_radius: value: %s\n", (char *) av_value);
					}
				} 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 ( 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 ) {
						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;
						}			
					} 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;
		}

	end_loop:
		if ( av_value != NULL ) {
			free(av_value);
			av_value  = NULL;
		}
	}
	
	return SWITCH_STATUS_SUCCESS;
 err:
	if ( av_value != NULL ) {
		free(av_value);
		av_value  = NULL;
	}
	return SWITCH_STATUS_GENERR;
	
}