int init_radius_handle(void) { int i; DICT_ATTR *da; char name[256]; map_list *mp; if (!config_file) { LM_ERR("radius configuration file not set\n"); return -1; } if ( syslog_name!=NULL && syslog_name[0]!=0 ) rc_openlog(syslog_name); if (!(rh = rc_read_config(config_file))) { LM_ERR("failed to open radius config file: %s\n", config_file); return -1; } if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary"))) { LM_ERR("failed to read radius dictionary\n"); return -1; } attr = rc_dict_findattr(rh, "SIP-AVP"); /* initialize values for the attributes in sets */ for (i = 0; i < set_size; i++) { mp = sets[i]->parsed; while (mp) { sprintf(name,"%.*s", mp->name.len, mp->name.s); da = rc_dict_findattr(rh, name); if (!da) { LM_ERR("attribute not found %s\n", name); return -1; } else mp->value = da->value; mp = mp->next; } } return 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; }
/* Radius implementation for the send_message callback */ int rad_send_message(aaa_conn* rh, aaa_message* request, aaa_message** reply) { char msg[4096]; VALUE_PAIR *vp; DICT_ATTR *attr; int result; if (!rh) { LM_ERR("invalid aaa connection argument\n"); return -1; } if (!request) { LM_ERR("invalid argument\n"); return -1; } if (request->type == AAA_AUTH) { *reply = (aaa_message*) pkg_malloc (sizeof(aaa_message)); if (!(*reply)) { LM_ERR("no pkg memory left \n"); return -1; } (*reply)->type = AAA_RECV; (*reply)->avpair = NULL; (*reply)->last_found = NULL; result = rc_auth(rh, SIP_PORT, (VALUE_PAIR*) request->avpair, (VALUE_PAIR**)(void*)&(*reply)->avpair, msg); if (result == OK_RC) { attr = rc_dict_findattr(rh, "SIP-AVP"); if (attr) { vp = (*reply)->avpair; for(; (vp = rc_avpair_get(vp, attr->value, 0)); vp = vp->next) if (extract_avp(vp)) { LM_ERR("extract_avp failed\n"); return -1; } return 0; } else { LM_ERR("SIP-AVP was not found in the radius dictionary\n"); return -1; } } else if (result == REJECT_RC) { LM_DBG("rc_auth function succeded with result REJECT_RC\n"); return result; } else { LM_ERR("rc_auth function failed\n"); return -1; } } if (request->type == AAA_ACCT) { return rc_acct(rh, SIP_PORT, (VALUE_PAIR*) request->avpair); } LM_ERR("send message failure\n"); return -1; }
/** Parses the buffer to extract the attribute-value pairs * * @param rh a handle to parsed configuration. * @param buffer the buffer to be parsed. * @param first_pair an allocated array of values. * @return 0 on successful parse of attribute-value pair, or -1 on syntax (or other) error detected. */ int rc_avpair_parse (rc_handle const *rh, char const *buffer, VALUE_PAIR **first_pair) { int mode; char attrstr[AUTH_ID_LEN]; char valstr[AUTH_STRING_LEN + 1], *p; DICT_ATTR *attr = NULL; DICT_VALUE *dval; VALUE_PAIR *pair; VALUE_PAIR *link; struct tm *tm; time_t timeval; mode = PARSE_MODE_NAME; while (*buffer != '\n' && *buffer != '\0') { if (*buffer == ' ' || *buffer == '\t') { buffer++; continue; } switch (mode) { case PARSE_MODE_NAME: /* Attribute Name */ rc_fieldcpy (attrstr, &buffer, " \t\n=,", sizeof(attrstr)); if ((attr = rc_dict_findattr (rh, attrstr)) == NULL) { rc_log(LOG_ERR, "rc_avpair_parse: unknown attribute"); if (*first_pair) { rc_avpair_free(*first_pair); *first_pair = NULL; } return -1; } mode = PARSE_MODE_EQUAL; break; case PARSE_MODE_EQUAL: /* Equal sign */ if (*buffer == '=') { mode = PARSE_MODE_VALUE; buffer++; } else { rc_log(LOG_ERR, "rc_avpair_parse: missing or misplaced equal sign"); if (*first_pair) { rc_avpair_free(*first_pair); *first_pair = NULL; } return -1; } break; case PARSE_MODE_VALUE: /* Value */ rc_fieldcpy (valstr, &buffer, " \t\n,", sizeof(valstr)); if ((pair = malloc (sizeof (VALUE_PAIR))) == NULL) { rc_log(LOG_CRIT, "rc_avpair_parse: out of memory"); if (*first_pair) { rc_avpair_free(*first_pair); *first_pair = NULL; } return -1; } strcpy (pair->name, attr->name); pair->attribute = attr->value; pair->type = attr->type; switch (pair->type) { case PW_TYPE_STRING: strcpy (pair->strvalue, valstr); pair->lvalue = (uint32_t)strlen(valstr); break; case PW_TYPE_INTEGER: if (isdigit (*valstr)) { pair->lvalue = atoi (valstr); } else { if ((dval = rc_dict_findval (rh, valstr)) == NULL) { rc_log(LOG_ERR, "rc_avpair_parse: unknown attribute value: %s", valstr); if (*first_pair) { rc_avpair_free(*first_pair); *first_pair = NULL; } free (pair); return -1; } else { pair->lvalue = dval->value; } } break; case PW_TYPE_IPADDR: if (inet_pton(AF_INET, valstr, &pair->lvalue) == 0) { rc_log(LOG_ERR, "rc_avpair_parse: invalid IPv4 address %s", valstr); free(pair); return -1; } pair->lvalue = ntohl(pair->lvalue); break; case PW_TYPE_IPV6ADDR: if (inet_pton(AF_INET6, valstr, pair->strvalue) == 0) { rc_log(LOG_ERR, "rc_avpair_parse: invalid IPv6 address %s", valstr); free(pair); return -1; } pair->lvalue = 16; break; case PW_TYPE_IPV6PREFIX: p = strchr(valstr, '/'); if (p == NULL) { rc_log(LOG_ERR, "rc_avpair_parse: invalid IPv6 prefix %s", valstr); free(pair); return -1; } *p = 0; p++; pair->strvalue[0] = 0; pair->strvalue[1] = atoi(p); if (inet_pton(AF_INET6, valstr, pair->strvalue+2) == 0) { rc_log(LOG_ERR, "rc_avpair_parse: invalid IPv6 prefix %s", valstr); free(pair); return -1; } pair->lvalue = 2+16; break; case PW_TYPE_DATE: timeval = time (0); tm = localtime (&timeval); tm->tm_hour = 0; tm->tm_min = 0; tm->tm_sec = 0; rc_str2tm (valstr, tm); #ifdef TIMELOCAL pair->lvalue = (uint32_t) timelocal (tm); #else /* TIMELOCAL */ pair->lvalue = (uint32_t) mktime (tm); #endif /* TIMELOCAL */ break; default: rc_log(LOG_ERR, "rc_avpair_parse: unknown attribute type %d", pair->type); if (*first_pair) { rc_avpair_free(*first_pair); *first_pair = NULL; } free (pair); return -1; } /* XXX: Fix up Digest-Attributes */ switch (pair->attribute) { case PW_DIGEST_REALM: case PW_DIGEST_NONCE: case PW_DIGEST_METHOD: case PW_DIGEST_URI: case PW_DIGEST_QOP: case PW_DIGEST_ALGORITHM: case PW_DIGEST_BODY_DIGEST: case PW_DIGEST_CNONCE: case PW_DIGEST_NONCE_COUNT: case PW_DIGEST_USER_NAME: /* overlapping! */ if (pair->lvalue > AUTH_STRING_LEN - 2) pair->lvalue = AUTH_STRING_LEN - 2; memmove(&pair->strvalue[2], &pair->strvalue[0], pair->lvalue); pair->strvalue[0] = pair->attribute - PW_DIGEST_REALM + 1; pair->lvalue += 2; pair->strvalue[1] = pair->lvalue; pair->strvalue[pair->lvalue] = '\0'; pair->attribute = PW_DIGEST_ATTRIBUTES; } pair->next = NULL; if (*first_pair == NULL) { *first_pair = pair; } else { link = *first_pair; while (link->next != NULL) { link = link->next; } link->next = pair; } mode = PARSE_MODE_NAME; break; default: mode = PARSE_MODE_NAME; break; } } return 0; }
int rc_avpair_parse (char *buffer, VALUE_PAIR **first_pair) { int mode; char attrstr[AUTH_ID_LEN]; char valstr[AUTH_ID_LEN]; DICT_ATTR *attr = NULL; DICT_VALUE *dval; VALUE_PAIR *pair; VALUE_PAIR *link; struct tm *tm; time_t timeval; mode = PARSE_MODE_NAME; while (*buffer != '\n' && *buffer != '\0') { if (*buffer == ' ' || *buffer == '\t') { buffer++; continue; } switch (mode) { case PARSE_MODE_NAME: /* Attribute Name */ rc_fieldcpy (attrstr, &buffer); if ((attr = rc_dict_findattr (attrstr)) == (DICT_ATTR *) NULL) { error("rc_avpair_parse: unknown attribute"); if (*first_pair) { rc_avpair_free(*first_pair); *first_pair = (VALUE_PAIR *) NULL; } return (-1); } mode = PARSE_MODE_EQUAL; break; case PARSE_MODE_EQUAL: /* Equal sign */ if (*buffer == '=') { mode = PARSE_MODE_VALUE; buffer++; } else { error("rc_avpair_parse: missing or misplaced equal sign"); if (*first_pair) { rc_avpair_free(*first_pair); *first_pair = (VALUE_PAIR *) NULL; } return (-1); } break; case PARSE_MODE_VALUE: /* Value */ rc_fieldcpy (valstr, &buffer); if ((pair = (VALUE_PAIR *) malloc (sizeof (VALUE_PAIR))) == (VALUE_PAIR *) NULL) { novm("rc_avpair_parse"); if (*first_pair) { rc_avpair_free(*first_pair); *first_pair = (VALUE_PAIR *) NULL; } return (-1); } strcpy (pair->name, attr->name); pair->attribute = attr->value; pair->type = attr->type; pair->vendorcode = attr->vendorcode; switch (pair->type) { case PW_TYPE_STRING: strcpy ((char *)pair->strvalue, valstr); pair->lvalue = strlen(valstr); break; case PW_TYPE_INTEGER: if (isdigit (*valstr)) { pair->lvalue = atoi (valstr); } else { if ((dval = rc_dict_findval (valstr)) == (DICT_VALUE *) NULL) { error("rc_avpair_parse: unknown attribute value: %s", valstr); if (*first_pair) { rc_avpair_free(*first_pair); *first_pair = (VALUE_PAIR *) NULL; } free (pair); return (-1); } else { pair->lvalue = dval->value; } } break; case PW_TYPE_IPADDR: pair->lvalue = rc_get_ipaddr(valstr); break; case PW_TYPE_DATE: timeval = time (0); tm = localtime (&timeval); tm->tm_hour = 0; tm->tm_min = 0; tm->tm_sec = 0; rc_str2tm (valstr, tm); #ifdef TIMELOCAL pair->lvalue = (UINT4) timelocal (tm); #else /* TIMELOCAL */ pair->lvalue = (UINT4) mktime (tm); #endif /* TIMELOCAL */ break; default: error("rc_avpair_parse: unknown attribute type %d", pair->type); if (*first_pair) { rc_avpair_free(*first_pair); *first_pair = (VALUE_PAIR *) NULL; } free (pair); return (-1); } pair->next = (VALUE_PAIR *) NULL; if (*first_pair == (VALUE_PAIR *) NULL) { *first_pair = pair; } else { link = *first_pair; while (link->next != (VALUE_PAIR *) NULL) { link = link->next; } link->next = pair; } mode = PARSE_MODE_NAME; break; default: mode = PARSE_MODE_NAME; break; } } 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; }