int rc_get_nas_id(VALUE_PAIR **sendpairs) { UINT4 client_id; char *nasid; nasid = rc_conf_str("nas_identifier"); if (strlen(nasid)) { /* * Fill in NAS-Identifier */ if (rc_avpair_add(sendpairs, PW_NAS_IDENTIFIER, nasid, 0, VENDOR_NONE) == NULL) return (ERROR_RC); return (OK_RC); } else { /* * Fill in NAS-IP-Address */ if ((client_id = rc_own_ipaddress()) == 0) return (ERROR_RC); if (rc_avpair_add(sendpairs, PW_NAS_IP_ADDRESS, &client_id, 0, VENDOR_NONE) == NULL) return (ERROR_RC); } return (OK_RC); }
int rc_acct_using_server(SERVER *acctserver, UINT4 client_port, VALUE_PAIR *send) { SEND_DATA data; VALUE_PAIR *adt_vp; int result; time_t start_time, dtime; char msg[4096]; int i; int timeout = rc_conf_int("radius_timeout"); int retries = rc_conf_int("radius_retries"); data.send_pairs = send; data.receive_pairs = NULL; /* * Fill in NAS-IP-Address or NAS-Identifier */ if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC) return (ERROR_RC); /* * Fill in NAS-Port */ if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL) return (ERROR_RC); /* * Fill in Acct-Delay-Time */ dtime = 0; if ((adt_vp = rc_avpair_add(&(data.send_pairs), PW_ACCT_DELAY_TIME, &dtime, 0, VENDOR_NONE)) == NULL) return (ERROR_RC); start_time = time(NULL); result = ERROR_RC; for(i=0; (i<acctserver->max) && (result != OK_RC) && (result != BADRESP_RC) ; i++) { if (data.receive_pairs != NULL) { rc_avpair_free(data.receive_pairs); data.receive_pairs = NULL; } rc_buildreq(&data, PW_ACCOUNTING_REQUEST, acctserver->name[i], acctserver->port[i], timeout, retries); dtime = time(NULL) - start_time; rc_avpair_assign(adt_vp, &dtime, 0); result = rc_send_server (&data, msg, NULL); } rc_avpair_free(data.receive_pairs); return result; }
int make_send_message(struct sip_msg* msg, int index, VALUE_PAIR **send) { pv_value_t pt; map_list *mp = sets[index]->parsed; for (; mp; mp = mp->next) { pv_get_spec_value(msg, mp->pv, &pt); if (pt.flags & PV_VAL_INT) { //LM_DBG("%.*s---->%d---->%d---->%d\n",mp->name.len, mp->name.s, // pt.ri, mp->value, pt.flags); if (!rc_avpair_add(rh, send, ATTRID(mp->value), &pt.ri, -1, VENDOR(mp->value))) return -1; } else if (pt.flags & PV_VAL_STR) { //LM_DBG("%.*s----->%.*s---->%d---->%d---->%d\n",mp->name.len, // mp->name.s, pt.rs.len, pt.rs.s, mp->value, pt.flags, pt.rs.len); if (rc_dict_getattr(rh,mp->value)->type == PW_TYPE_IPADDR) { uint32_t ipaddr=rc_get_ipaddr(pt.rs.s); if (!rc_avpair_add(rh, send, ATTRID(mp->value), &ipaddr, -1, VENDOR(mp->value))) return -1; } else { if (!rc_avpair_add(rh, send, ATTRID(mp->value), pt.rs.s, pt.rs.len, VENDOR(mp->value))) return -1; } } } return 0; }
/* * Check from Radius if request URI belongs to a local user. * User-Name is user@host of request Uri and Service-Type is Call-Check. */ int radius_does_uri_exist(struct sip_msg* _m, char* _s1, char* _s2) { static char msg[4096]; VALUE_PAIR *send, *received; UINT4 service; char* at, *uri; send = received = 0; if (parse_sip_msg_uri(_m) < 0) { LM_ERR("parsing URI failed\n"); return -1; } uri = (char*)pkg_malloc(_m->parsed_uri.user.len + _m->parsed_uri.host.len + 2); if (!uri) { LM_ERR("no more pkg memory\n"); return -2; } at = uri; memcpy(at, _m->parsed_uri.user.s, _m->parsed_uri.user.len); at += _m->parsed_uri.user.len; *at = '@'; at++; memcpy(at , _m->parsed_uri.host.s, _m->parsed_uri.host.len); at += _m->parsed_uri.host.len; *at = '\0'; if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, uri, -1, 0)) { LM_ERR("adding User-Name failed\n"); rc_avpair_free(send); pkg_free(uri); return -3; } service = vals[V_CALL_CHECK].v; if (!rc_avpair_add(rh, &send, attrs[A_SERVICE_TYPE].v, &service, -1, 0)) { LM_ERR("adding service type failed\n"); rc_avpair_free(send); pkg_free(uri); return -4; } if (rc_auth(rh, 0, send, &received, msg) == OK_RC) { LM_DBG("success\n"); rc_avpair_free(send); generate_avps(received); rc_avpair_free(received); pkg_free(uri); return 1; } else { LM_DBG("failure\n"); rc_avpair_free(send); rc_avpair_free(received); pkg_free(uri); return -5; } }
static int load_user_attrs(struct sip_msg* msg, unsigned long flags, fparam_t* fp) { static char rad_msg[4096]; str uid; UINT4 service; VALUE_PAIR* send, *received; send = NULL; received = NULL; if (get_str_fparam(&uid, msg, (fparam_t*)fp) < 0) { ERR("Unable to get UID\n"); return -1; } service = vals[V_GET_USER_ATTRS].v; if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_USER_NAME].v), uid.s, uid.len, VENDOR(attrs[A_USER_NAME].v))) { ERR("Error while adding A_USER_NAME\n"); goto error; } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SER_SERVICE_TYPE].v), &vals[V_GET_USER_ATTRS].v, -1, VENDOR(attrs[A_SER_SERVICE_TYPE].v))) { ERR("Error adding A_SERVICE_TYPE\n"); goto error; } if (rc_auth(rh, 0, send, &received, rad_msg) != OK_RC) { DBG("load_user_attrs: Failure\n"); goto error; } DBG("load_user_attrs: Success\n"); rc_avpair_free(send); if (generate_avps(flags, received) < 0) { rc_avpair_free(received); goto error; } rc_avpair_free(received); return 1; error: if (send) rc_avpair_free(send); if (received) rc_avpair_free(send); return -1; }
/** Asks the server hostname on the specified port for a status message * * @param rh a handle to parsed configuration. * @param host the name of the server. * @param secret the secret used by the server. * @param port the server's port number. * @param msg must be an array of PW_MAX_MSG_SIZE or NULL; will contain the concatenation of any * PW_REPLY_MESSAGE received. * @return OK_RC (0) on success, negative on failure as return value. */ int rc_check(rc_handle *rh, char *host, char *secret, unsigned short port, char *msg) { SEND_DATA data; int result; uint32_t service_type; int timeout = rc_conf_int(rh, "radius_timeout"); int retries = rc_conf_int(rh, "radius_retries"); rc_type type; data.send_pairs = data.receive_pairs = NULL; if (rh->so_type == RC_SOCKET_TLS || rh->so_type == RC_SOCKET_DTLS) type = AUTH; else type = ACCT; /* * Fill in Service-Type */ service_type = PW_ADMINISTRATIVE; rc_avpair_add(rh, &(data.send_pairs), PW_SERVICE_TYPE, &service_type, 0, 0); rc_buildreq(rh, &data, PW_STATUS_SERVER, host, port, secret, timeout, retries); result = rc_send_server (rh, &data, msg, type); rc_avpair_free(data.receive_pairs); return result; }
static int add_cisco_vsa(VALUE_PAIR** send, struct sip_msg* msg) { str callid; if (!msg->callid && parse_headers(msg, HDR_CALLID_F, 0) == -1) { LM_ERR("cannot parse Call-ID header field\n"); return -1; } if (!msg->callid) { LM_ERR("call-ID header field not found\n"); return -1; } callid.len = msg->callid->body.len + 8; callid.s = pkg_malloc(callid.len); if (callid.s == NULL) { LM_ERR("no pkg memory left\n"); return -1; } memcpy(callid.s, "call-id=", 8); memcpy(callid.s + 8, msg->callid->body.s, msg->callid->body.len); if (rc_avpair_add(rh, send, attrs[A_CISCO_AVPAIR].v, callid.s, callid.len, VENDOR(attrs[A_CISCO_AVPAIR].v)) == 0) { LM_ERR("unable to add Cisco-AVPair attribute\n"); pkg_free(callid.s); return -1; } pkg_free(callid.s); return 0; }
int rc_check(char *host, unsigned short port, char *msg) { SEND_DATA data; int result; UINT4 service_type; int timeout = rc_conf_int("radius_timeout"); int retries = rc_conf_int("radius_retries"); data.send_pairs = data.receive_pairs = NULL; /* * Fill in NAS-IP-Address or NAS-Identifier, * although it isn't neccessary */ if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC) return (ERROR_RC); /* * Fill in Service-Type */ service_type = PW_ADMINISTRATIVE; rc_avpair_add(&(data.send_pairs), PW_SERVICE_TYPE, &service_type, 0, VENDOR_NONE); rc_buildreq(&data, PW_STATUS_SERVER, host, port, timeout, retries); result = rc_send_server (&data, msg, NULL); rc_avpair_free(data.receive_pairs); return result; }
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 = NULL, conditions = NULL; switch_channel_t *channel = switch_core_session_get_channel(session); 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); } /* If there are conditions defined, and none of them pass, then skip this accounting */ if ((conditions = switch_xml_child(globals.acct_start_configs, "conditions")) != NULL && mod_xml_radius_check_conditions(channel, conditions) != SWITCH_STATUS_SUCCESS ) { goto end; } if ( mod_xml_radius_new_handle(&new_handle, globals.acct_end_configs) != SWITCH_STATUS_SUCCESS || new_handle == NULL ) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to create new accounting_end handle for call: %s\n", switch_channel_get_variable(channel, "uuid")); 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"); 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: if ( send ) { rc_avpair_free(send); send = NULL; } if ( new_handle) { rc_destroy(new_handle); new_handle = NULL; } return SWITCH_STATUS_SUCCESS; }
/* skip leading text and begin with first item's * separator ", " which will be overwritten by the * leading text later * */ static int log_request(struct sip_msg* rq, str* ouri, struct hdr_field* to, unsigned int code, time_t req_time) { VALUE_PAIR *send; UINT4 av_type; send = NULL; if (skip_cancel(rq)) return 1; if (fmt2rad(log_fmt, rq, ouri, to, code, &send, req_time) < 0) goto error; /* Add Acct-Status-Type attribute */ av_type = rad_status(rq, code); if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_ACCT_STATUS_TYPE].v), &av_type, -1, VENDOR(attrs[A_ACCT_STATUS_TYPE].v))) { ERR("Add Status-Type\n"); goto error; } /* Add Service-Type attribute */ av_type = (service_type != -1) ? service_type : vals[V_SIP_SESSION].v; if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SERVICE_TYPE].v), &av_type, -1, VENDOR(attrs[A_SERVICE_TYPE].v))) { ERR("add STATUS_TYPE\n"); goto error; } /* Add User-Name attribute */ if (add_user_name(rq, rh, &send) < 0) goto error; /* Send the request out */ if (rc_acct(rh, SIP_PORT, send) != OK_RC) { ERR("RADIUS accounting request failed\n"); goto error; } rc_avpair_free(send); return 1; error: rc_avpair_free(send); return -1; }
/** * Perform authenticate request. * @param[in] radh Radius handle. * @param[out] reply_attr Reply attributes. * @param[in,out] reply_msg Reply message. * @return One of ZRAD_* codes. */ static zrad_status_t zrad_auth_request(rc_handle *radh, const zrad_auth_req_t *req, VALUE_PAIR **reply_attrs, char *reply_msg) { zrad_status_t ret = ZRAD_OTHER; VALUE_PAIR *request_attrs = NULL; int success = rc_avpair_add(radh, &request_attrs, PW_USER_NAME, req->username, -1, 0) && rc_avpair_add(radh, &request_attrs, PW_USER_PASSWORD, req->password, -1, 0) && rc_avpair_add(radh, &request_attrs, PW_NAS_IDENTIFIER, req->nas_id, -1, 0) && rc_avpair_add(radh, &request_attrs, PW_CALLING_STATION_ID, req->calling_station_id, -1, 0); if (likely(success)) { ret = (zrad_status_t) rc_auth(radh, 0, request_attrs, reply_attrs, reply_msg); } if (likely(request_attrs)) { rc_avpair_free(request_attrs); } return ret; }
int rc_auth_using_server(SERVER *authserver, UINT4 client_port, VALUE_PAIR *send, VALUE_PAIR **received, char *msg, REQUEST_INFO *info) { SEND_DATA data; int result; int i; int timeout = rc_conf_int("radius_timeout"); int retries = rc_conf_int("radius_retries"); data.send_pairs = send; data.receive_pairs = NULL; /* * Fill in NAS-IP-Address or NAS-Identifier */ if (rc_get_nas_id(&(data.send_pairs)) == ERROR_RC) return (ERROR_RC); /* * Fill in NAS-Port */ if (rc_avpair_add(&(data.send_pairs), PW_NAS_PORT, &client_port, 0, VENDOR_NONE) == NULL) return (ERROR_RC); result = ERROR_RC; for(i=0; (i<authserver->max) && (result != OK_RC) && (result != BADRESP_RC) ; i++) { if (data.receive_pairs != NULL) { rc_avpair_free(data.receive_pairs); data.receive_pairs = NULL; } rc_buildreq(&data, PW_ACCESS_REQUEST, authserver->name[i], authserver->port[i], timeout, retries); result = rc_send_server (&data, msg, info); } *received = data.receive_pairs; return result; }
/* * Add User-Name attribute */ static inline int add_user_name(struct sip_msg* rq, void* rh, VALUE_PAIR** send) { struct sip_uri puri; str* user, *realm; str user_name; struct to_body* from; user = cred_user(rq); /* try to take it from credentials */ realm = cred_realm(rq); if (!user || !realm) { if (rq->from && (from = get_from(rq)) && from->uri.len) { if (parse_uri(from->uri.s, from->uri.len, &puri) < 0 ) { LOG(L_ERR, "ERROR:acc:add_user_name: Bad From URI\n"); return -1; } user = &puri.user; realm = &puri.host; } else { DBG("acc:add_user_name: Neither digest nor From found, mandatory attribute User-Name not added\n"); return -1; } } user_name.len = user->len + 1 + realm->len; user_name.s = pkg_malloc(user_name.len); if (!user_name.s) { LOG(L_ERR, "ERROR:acc:add_user_name: no memory\n"); return -1; } memcpy(user_name.s, user->s, user->len); user_name.s[user->len] = '@'; memcpy(user_name.s + user->len + 1, realm->s, realm->len); if (!rc_avpair_add(rh, send, ATTRID(attrs[A_USER_NAME].v), user_name.s, user_name.len, VENDOR(attrs[A_USER_NAME].v))) { LOG(L_ERR, "ERROR:acc:add_user_name: Failed to add User-Name attribute\n"); pkg_free(user_name.s); return -1; } pkg_free(user_name.s); return 0; }
/* * This function creates and submits radius authentication request as per * draft-sterman-aaa-sip-00.txt. In addition, _user parameter is included * in the request as value of a SER specific attribute type SIP-URI-User, * which can be be used as a check item in the request. Service type of * the request is Authenticate-Only. */ int radius_authorize_sterman(struct sip_msg* _msg, dig_cred_t* _cred, str* _method, str* _user, str* _rpid) { static char msg[4096]; VALUE_PAIR *send, *received, *vp; UINT4 service; str method, user, user_name, callid; int i; send = received = 0; if (!(_cred && _method && _user && _rpid)) { LOG(L_ERR, "radius_authorize_sterman(): Invalid parameter value\n"); return -1; } method = *_method; user = *_user; /* * Add all the user digest parameters according to the qop defined. * Most devices tested only offer support for the simplest digest. */ if (_cred->username.domain.len) { if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, _cred->username.whole.s, _cred->username.whole.len, 0)) { LOG(L_ERR, "sterman(): Unable to add User-Name attribute\n"); rc_avpair_free(send); return -2; } } else { user_name.len = _cred->username.user.len + _cred->realm.len + 1; user_name.s = pkg_malloc(user_name.len); if (!user_name.s) { LOG(L_ERR, "radius_authorize_sterman(): No memory left\n"); return -3; } memcpy(user_name.s, _cred->username.whole.s, _cred->username.whole.len); user_name.s[_cred->username.whole.len] = '@'; memcpy(user_name.s + _cred->username.whole.len + 1, _cred->realm.s, _cred->realm.len); if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, user_name.s, user_name.len, 0)) { LOG(L_ERR, "sterman(): Unable to add User-Name attribute\n"); pkg_free(user_name.s); rc_avpair_free(send); return -4; } pkg_free(user_name.s); } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_USER_NAME].v, _cred->username.whole.s, _cred->username.whole.len, 0)) { LOG(L_ERR, "sterman(): Unable to add Digest-User-Name attribute\n"); rc_avpair_free(send); return -5; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_REALM].v, _cred->realm.s, _cred->realm.len, 0)) { LOG(L_ERR, "sterman(): Unable to add Digest-Realm attribute\n"); rc_avpair_free(send); return -6; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_NONCE].v, _cred->nonce.s, _cred->nonce.len, 0)) { LOG(L_ERR, "sterman(): Unable to add Digest-Nonce attribute\n"); rc_avpair_free(send); return -7; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_URI].v, _cred->uri.s, _cred->uri.len, 0)) { LOG(L_ERR, "sterman(): Unable to add Digest-URI attribute\n"); rc_avpair_free(send); return -8; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_METHOD].v, method.s, method.len, 0)) { LOG(L_ERR, "sterman(): Unable to add Digest-Method attribute\n"); rc_avpair_free(send); return -9; } /* * Add the additional authentication fields according to the QOP. */ if (_cred->qop.qop_parsed == QOP_AUTH) { if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_QOP].v, "auth", 4, 0)) { LOG(L_ERR, "sterman(): Unable to add Digest-QOP attribute\n"); rc_avpair_free(send); return -10; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_NONCE_COUNT].v, _cred->nc.s, _cred->nc.len, 0)) { LOG(L_ERR, "sterman(): Unable to add Digest-CNonce-Count attribute\n"); rc_avpair_free(send); return -11; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_CNONCE].v, _cred->cnonce.s, _cred->cnonce.len, 0)) { LOG(L_ERR, "sterman(): Unable to add Digest-CNonce attribute\n"); rc_avpair_free(send); return -12; } } else if (_cred->qop.qop_parsed == QOP_AUTHINT) { if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_QOP].v, "auth-int", 8, 0)) { LOG(L_ERR, "sterman(): Unable to add Digest-QOP attribute\n"); rc_avpair_free(send); return -13; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_NONCE_COUNT].v, _cred->nc.s, _cred->nc.len, 0)) { LOG(L_ERR, "sterman(): Unable to add Digest-Nonce-Count attribute\n"); rc_avpair_free(send); return -14; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_CNONCE].v, _cred->cnonce.s, _cred->cnonce.len, 0)) { LOG(L_ERR, "sterman(): Unable to add Digest-CNonce attribute\n"); rc_avpair_free(send); return -15; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_BODY_DIGEST].v, _cred->opaque.s, _cred->opaque.len, 0)) { LOG(L_ERR, "sterman(): Unable to add Digest-Body-Digest attribute\n"); rc_avpair_free(send); return -16; } } else { /* send nothing for qop == "" */ } /* Add the response... What to calculate against... */ if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_RESPONSE].v, _cred->response.s, _cred->response.len, 0)) { LOG(L_ERR, "sterman(): Unable to add Digest-Response attribute\n"); rc_avpair_free(send); return -17; } /* Indicate the service type, Authenticate only in our case */ service = vals[V_SIP_SESSION].v; if (!rc_avpair_add(rh, &send, attrs[A_SERVICE_TYPE].v, &service, -1, 0)) { LOG(L_ERR, "sterman(): Unable to add Service-Type attribute\n"); rc_avpair_free(send); return -18; } /* Add SIP URI as a check item */ if (!rc_avpair_add(rh, &send, attrs[A_SIP_URI_USER].v, user.s, user.len, 0)) { LOG(L_ERR, "sterman(): Unable to add Sip-URI-User attribute\n"); rc_avpair_free(send); return -19; } if (attrs[A_CISCO_AVPAIR].n != NULL) { /* Add SIP Call-ID as a Cisco VSA, like IOS does */ if (_msg->callid == NULL || _msg->callid->body.s == NULL) { LOG(L_ERR, "sterman(): Call-ID is missed\n"); rc_avpair_free(send); return -20; } callid.len = _msg->callid->body.len + 8; callid.s = alloca(callid.len); if (callid.s == NULL) { LOG(L_ERR, "sterman(): No memory left\n"); rc_avpair_free(send); return -21; } memcpy(callid.s, "call-id=", 8); memcpy(callid.s + 8, _msg->callid->body.s, _msg->callid->body.len); if (rc_avpair_add(rh, &send, attrs[A_CISCO_AVPAIR].v, callid.s, callid.len, VENDOR(attrs[A_CISCO_AVPAIR].v)) == 0) { LOG(L_ERR, "sterman(): Unable to add Cisco-AVPair attribute\n"); rc_avpair_free(send); return -22; } } /* Send request */ if ((i = rc_auth(rh, SIP_PORT, send, &received, msg)) == OK_RC) { DBG("radius_authorize_sterman(): Success\n"); rc_avpair_free(send); /* Make a copy of rpid if available */ if ((vp = rc_avpair_get(received, attrs[A_SIP_RPID].v, 0))) { if (MAX_RPID_LEN < vp->lvalue) { LOG(L_ERR, "radius_authorize_sterman(): rpid buffer too small\n"); return -23; } memcpy(_rpid->s, vp->strvalue, vp->lvalue); _rpid->len = vp->lvalue; } rc_avpair_free(received); return 1; } else { DBG("res: %d\n", i); DBG("radius_authorize_sterman(): Failure\n"); rc_avpair_free(send); rc_avpair_free(received); return -24; } }
/** * Authenticate and set client info. * @param[in] sess Client session. * @return Zero on success (or one of *_RC). */ static int session_authenticate(struct zsession *sess) { int ret = OTHER_RC; VALUE_PAIR *request_attrs = NULL, *response_attrs = NULL, *attrs = NULL; char msg[8192]; // WARNING: libfreeradius-client has unsafe working with this buffer. rc_handle *rh = zinst()->radh; struct in_addr ip_addr; char ip_str[INET_ADDRSTRLEN]; struct zcrules rules; crules_init(&rules); ip_addr.s_addr = htonl(sess->ip); if (unlikely(NULL == inet_ntop(AF_INET, &ip_addr, ip_str, sizeof(ip_str)))) { goto end; } if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_USER_NAME, ip_str, -1, 0))) { goto end; } if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_USER_PASSWORD, "", -1, 0))) { goto end; } if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_NAS_IDENTIFIER, zcfg()->radius_nas_identifier, -1, 0))) { goto end; } if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_CALLING_STATION_ID, ip_str, -1, 0))) { goto end; } ret = rc_auth(rh, 0, request_attrs, &response_attrs, msg); if (OK_RC != ret) { ZERO_LOG(LOG_ERR, "Session authentication failed for %s (code:%d)", ip_str, ret); goto end; } attrs = response_attrs; while (likely(NULL != attrs)) { switch (attrs->attribute) { case PW_FILTER_ID: crules_parse(&rules, attrs->strvalue); break; case PW_SESSION_TIMEOUT: atomic_store_explicit(&sess->max_duration, SEC2USEC(attrs->lvalue), memory_order_release); break; case PW_ACCT_INTERIM_INTERVAL: atomic_store_explicit(&sess->acct_interval, SEC2USEC(attrs->lvalue), memory_order_release); break; } attrs = attrs->next; } if (likely(rules.have.user_id && rules.have.login)) { struct zclient *client = sess->client; client_db_find_or_set_id(zinst()->client_db, rules.user_id, &client); if (client != sess->client) { // found pthread_rwlock_wrlock(&sess->lock_client); atomic_fetch_add_explicit(&client->refcnt, 1, memory_order_relaxed); client_release(sess->client); sess->client = client; client_session_add(sess->client, sess); pthread_rwlock_unlock(&sess->lock_client); } else { client_apply_rules(sess->client, &rules); } atomic_fetch_sub_explicit(&zinst()->unauth_sessions_cnt, 1, memory_order_release); // log successful authentication { UT_string rules_str; utstring_init(&rules_str); utstring_reserve(&rules_str, 1024); attrs = response_attrs; while (likely(NULL != attrs)) { switch (attrs->attribute) { case PW_FILTER_ID: utstring_printf(&rules_str, " %s", attrs->strvalue); break; default: break; } attrs = attrs->next; } zero_syslog(LOG_INFO, "Authenticated session %s (rules:%s)", ip_str, utstring_body(&rules_str)); utstring_done(&rules_str); } } else { ret = OTHER_RC; ZERO_LOG(LOG_ERR, "Session authentication failed for %s (code:%d)", ip_str, ret); } end: crules_free(&rules); if (request_attrs) rc_avpair_free(request_attrs); if (response_attrs) rc_avpair_free(response_attrs); return ret; }
/** * Send radius accounting packet. * @param[in] sess Session * @param[in] status Accounting status (PW_STATUS_START, PW_STATUS_STOP, PW_STATUS_ALIVE) * @param[in] cause Accounting termination cause (used only in case of PW_STATUS_STOP) * @return Zero on success (one of *_RC codes). */ static int session_accounting(struct zsession *sess, uint32_t status, uint32_t term_cause) { int ret = OTHER_RC; VALUE_PAIR *request_attrs = NULL; rc_handle *rh = zinst()->radh; struct in_addr ip_addr; char ip_str[INET_ADDRSTRLEN]; uint64_t traff_down = atomic_load_explicit(&sess->traff_down, memory_order_acquire); uint64_t traff_up = atomic_load_explicit(&sess->traff_up, memory_order_acquire); uint32_t octets_down = (uint32_t) (traff_down % UINT32_MAX); uint32_t octets_up = (uint32_t) (traff_up % UINT32_MAX); uint32_t packets_down = atomic_load_explicit(&sess->packets_down, memory_order_acquire) % UINT32_MAX; uint32_t packets_up = atomic_load_explicit(&sess->packets_up, memory_order_acquire) % UINT32_MAX; uint32_t gigawords_down = 0; uint32_t gigawords_up = 0; char session_id[255]; snprintf(session_id, sizeof(session_id), "%s-%" PRIu32, sess->client->login, sess->ip); ip_addr.s_addr = htonl(sess->ip); if (unlikely(NULL == inet_ntop(AF_INET, &ip_addr, ip_str, sizeof(ip_str)))) { goto end; } if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_CALLING_STATION_ID, ip_str, -1, 0))) { goto end; } if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_FRAMED_IP_ADDRESS, &sess->ip, -1, 0))) { goto end; } if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_USER_NAME, sess->client->login, -1, 0))) { goto end; } if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_ACCT_SESSION_ID, session_id, -1, 0))) { goto end; } if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_NAS_IDENTIFIER, zcfg()->radius_nas_identifier, -1, 0))) { goto end; } if (PW_STATUS_STOP == status) { if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_ACCT_TERMINATE_CAUSE, &term_cause, -1, 0))) { goto end; } } if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_ACCT_STATUS_TYPE, &status, -1, 0))) { goto end; } if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_ACCT_INPUT_OCTETS, &octets_down, -1, 0))) { goto end; } if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_ACCT_INPUT_PACKETS, &packets_down, -1, 0))) { goto end; } if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_ACCT_OUTPUT_OCTETS, &octets_up, -1, 0))) { goto end; } if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_ACCT_OUTPUT_PACKETS, &packets_down, -1, 0))) { goto end; } if (unlikely(UINT32_MAX < traff_down)) { gigawords_down = (uint32_t) (traff_down / UINT32_MAX); if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_ACCT_INPUT_GIGAWORDS, &gigawords_down, -1, 0))) { goto end; } } if (unlikely(UINT32_MAX < traff_up)) { gigawords_up = (uint32_t) (traff_up / UINT32_MAX); if (unlikely(NULL == rc_avpair_add(rh, &request_attrs, PW_ACCT_OUTPUT_GIGAWORDS, &gigawords_up, -1, 0))) { goto end; } } ret = rc_acct(rh, 0, request_attrs); if (unlikely(OK_RC != ret)) { ZERO_LOG(LOG_ERR, "radius accounting failed %s (code:%d)", ip_str, ret); goto end; } atomic_fetch_sub_explicit(&sess->traff_down, traff_down, memory_order_release); atomic_fetch_sub_explicit(&sess->traff_up, traff_up, memory_order_release); atomic_fetch_sub_explicit(&sess->packets_down, packets_down, memory_order_release); atomic_fetch_sub_explicit(&sess->packets_up, packets_up, memory_order_release); end: if (request_attrs) { rc_avpair_free(request_attrs); } return ret; }
/* * Check from Radius if URI user given as argument belongs to a local user. * If so, loads AVPs based on reply items returned from Radius. */ int radius_does_uri_user_exist(struct sip_msg* _m, str user) { static char msg[4096]; VALUE_PAIR *send, *received; uint32_t service; int res, extra_cnt, offset, i; send = received = 0; if (!rc_avpair_add(rh, &send, uri_attrs[SA_USER_NAME].v, user.s, user.len, 0)) { LM_ERR("in adding SA_USER_NAME\n"); return -1; } service = uri_vals[UV_CALL_CHECK].v; if (!rc_avpair_add(rh, &send, uri_attrs[SA_SERVICE_TYPE].v, &service, -1, 0)) { LM_ERR("in adding SA_SERVICE_TYPE <%u>\n", service); goto error; } /* Add extra attributes */ extra_cnt = extra2strar(uri_extra, _m, val_arr); if (extra_cnt == -1) { LM_ERR("in getting values of group extra attributes\n"); goto error; } offset = SA_STATIC_MAX; for (i = 0; i < extra_cnt; i++) { if (val_arr[i].len == -1) { /* Add integer attribute */ ADD_EXTRA_AVPAIR(uri_attrs, offset+i, &(val_arr[i].s), val_arr[i].len ); } else { /* Add string attribute */ ADD_EXTRA_AVPAIR(uri_attrs, offset+i, val_arr[i].s, val_arr[i].len ); } } if ((res = rc_auth(rh, 0, send, &received, msg)) == OK_RC) { LM_DBG("success\n"); rc_avpair_free(send); generate_avps(uri_attrs, received); rc_avpair_free(received); return 1; } else { rc_avpair_free(send); rc_avpair_free(received); #ifdef REJECT_RC if (res == REJECT_RC) { LM_DBG("rejected\n"); return -1; } else { LM_ERR("failure\n"); return -2; } #else LM_DBG("failure\n"); return -1; #endif } error: rc_avpair_free(send); return -1; }
/* * Check from Radius if URI, whose user and host parts are given as * arguments, exists. If so, loads AVPs based on reply items returned * from Radius. If use_sip_uri_host module parameter has non-zero value, * user is send in SA_USER_NAME attribute and host in SA_SIP_URI_HOST * attribute. If is has zero value, user@host is send in SA_USER_NAME * attribute. */ int radius_does_uri_user_host_exist(struct sip_msg* _m, str user, str host) { char* at, *user_host; VALUE_PAIR *send, *received; uint32_t service; static char msg[4096]; int extra_cnt, offset, i, res; send = received = 0; user_host = 0; if (!use_sip_uri_host) { /* Send user@host in SA_USER_NAME attr */ user_host = (char*)pkg_malloc(user.len + host.len + 2); if (!user_host) { LM_ERR("no more pkg memory\n"); return -1; } at = user_host; memcpy(at, user.s, user.len); at += user.len; *at = '@'; at++; memcpy(at , host.s, host.len); at += host.len; *at = '\0'; if (!rc_avpair_add(rh, &send, uri_attrs[SA_USER_NAME].v, user_host, -1, 0)) { LM_ERR("in adding SA_USER_NAME\n"); pkg_free(user_host); return -1; } } else { /* Send user in SA_USER_NAME attribute and host in SA_SIP_URI_HOST attribute */ if (!rc_avpair_add(rh, &send, uri_attrs[SA_USER_NAME].v, user.s, user.len, 0)) { LM_ERR("adding User-Name failed\n"); return -1; } if (!rc_avpair_add(rh, &send, uri_attrs[SA_SIP_URI_HOST].v, host.s, host.len, 0)) { LM_ERR("adding SIP-URI-Host failed\n"); goto error; } } service = uri_vals[UV_CALL_CHECK].v; if (!rc_avpair_add(rh, &send, uri_attrs[SA_SERVICE_TYPE].v, &service, -1, 0)) { LM_ERR("in adding SA_SERVICE_TYPE <%u>\n", service); goto error; } /* Add extra attributes */ extra_cnt = extra2strar(uri_extra, _m, val_arr); if (extra_cnt == -1) { LM_ERR("in getting values of group extra attributes\n"); goto error; } offset = SA_STATIC_MAX; for (i = 0; i < extra_cnt; i++) { if (val_arr[i].len == -1) { /* Add integer attribute */ ADD_EXTRA_AVPAIR(uri_attrs, offset+i, &(val_arr[i].s), val_arr[i].len ); } else { /* Add string attribute */ ADD_EXTRA_AVPAIR(uri_attrs, offset+i, val_arr[i].s, val_arr[i].len ); } } if ((res = rc_auth(rh, 0, send, &received, msg)) == OK_RC) { LM_DBG("success\n"); if (user_host) pkg_free(user_host); rc_avpair_free(send); generate_avps(uri_attrs, received); rc_avpair_free(received); return 1; } else { if (user_host) pkg_free(user_host); rc_avpair_free(send); rc_avpair_free(received); #ifdef REJECT_RC if (res == REJECT_RC) { LM_DBG("rejected\n"); return -1; } else { LM_ERR("failure\n"); return -2; } #else LM_DBG("failure\n"); return -1; #endif } error: rc_avpair_free(send); if (user_host) pkg_free(user_host); return -1; }
/* Radius implementation for the avp_add callback */ int rad_avp_add(aaa_conn* rh, aaa_message* message, aaa_map* name, void* value, int val_length, int vendor) { uint32_t int4_val; str s; if (!rh) { LM_ERR("invalid aaa connection argument\n"); return -1; } if (!message) { LM_ERR("invalid message argument\n"); return -1; } if (!name) { LM_ERR("invalid name argument\n"); return -1; } if (!value) { LM_ERR("invalid value argument\n"); return -1; } if (vendor) vendor = VENDOR(vendor); /* check if this might be a string, we might have to do some conversions */ if (val_length > -1) { if (name->type == PW_TYPE_IPADDR) { char ipstr[val_length + 1]; memcpy( ipstr, value, val_length); ipstr[val_length] = 0; int4_val = rc_get_ipaddr((char*)&ipstr); LM_DBG("detected TYPE_IPADDR attribute %s = %s (%u)\n", name->name, ipstr, (unsigned int)int4_val); value = (void *)&int4_val; val_length = -1; } else if (name->type == PW_TYPE_INTEGER) { LM_DBG("detected TYPE_INTEGER attribute %s = %s\n", name->name, (char*)value); s.s = (char*)value; s.len = val_length; if (str2int( &s, (unsigned int*)(void*)&int4_val) != 0 ) { LM_ERR("error converting string to integer"); return -1; } value = (void*)&int4_val; val_length = -1; } } if (rc_avpair_add (rh, (VALUE_PAIR**)(void*)&message->avpair, name->value, value, val_length, vendor)) { return 0; } LM_ERR("failure\n"); return -1; }
/** Sends a request to a RADIUS server and waits for the reply * * @param rh a handle to parsed configuration * @param ctx if non-NULL it will contain the context of sent request; It must be released using rc_aaa_ctx_free(). * @param data a pointer to a SEND_DATA structure * @param msg must be an array of %PW_MAX_MSG_SIZE or NULL; will contain the concatenation of * any %PW_REPLY_MESSAGE received. * @param type must be %AUTH or %ACCT * @return OK_RC (0) on success, TIMEOUT_RC on timeout REJECT_RC on acess reject, or negative * on failure as return value. */ int rc_send_server_ctx(rc_handle * rh, RC_AAA_CTX ** ctx, SEND_DATA * data, char *msg, rc_type type) { int sockfd = -1; AUTH_HDR *auth, *recv_auth; char *server_name, *p; /* Name of server to query */ struct sockaddr_storage our_sockaddr; struct addrinfo *auth_addr = NULL; socklen_t salen; int result = 0; int total_length; int length, pos; int retry_max; const rc_sockets_override *sfuncs; unsigned discover_local_ip; size_t secretlen; char secret[MAX_SECRET_LENGTH + 1]; unsigned char vector[AUTH_VECTOR_LEN]; uint8_t recv_buffer[BUFFER_LEN]; uint8_t send_buffer[BUFFER_LEN]; uint8_t *attr; int retries; VALUE_PAIR *vp; struct pollfd pfd; double start_time, timeout; struct sockaddr_storage *ss_set = NULL; char *server_type = "auth"; server_name = data->server; if (server_name == NULL || server_name[0] == '\0') return ERROR_RC; if ((vp = rc_avpair_get(data->send_pairs, PW_SERVICE_TYPE, 0)) && (vp->lvalue == PW_ADMINISTRATIVE)) { strcpy(secret, MGMT_POLL_SECRET); auth_addr = rc_getaddrinfo(server_name, type == AUTH ? PW_AI_AUTH : PW_AI_ACCT); if (auth_addr == NULL) return ERROR_RC; } else { if (data->secret != NULL) { strlcpy(secret, data->secret, MAX_SECRET_LENGTH); } /* else { */ if (rc_find_server_addr (rh, server_name, &auth_addr, secret, type) != 0) { rc_log(LOG_ERR, "rc_send_server: unable to find server: %s", server_name); return ERROR_RC; } /*} */ } sfuncs = &rh->so; if (sfuncs->static_secret) { /* any static secret set in sfuncs overrides the configured */ strlcpy(secret, sfuncs->static_secret, MAX_SECRET_LENGTH); } if (sfuncs->lock) { if (sfuncs->lock(sfuncs->ptr) != 0) { rc_log(LOG_ERR, "%s: lock error", __func__); return ERROR_RC; } } rc_own_bind_addr(rh, &our_sockaddr); discover_local_ip = 0; if (our_sockaddr.ss_family == AF_INET) { if (((struct sockaddr_in *)(&our_sockaddr))->sin_addr.s_addr == INADDR_ANY) { discover_local_ip = 1; } } DEBUG(LOG_ERR, "DEBUG: rc_send_server: creating socket to: %s", server_name); if (discover_local_ip) { result = rc_get_srcaddr(SA(&our_sockaddr), auth_addr->ai_addr); if (result != 0) { memset(secret, '\0', sizeof(secret)); rc_log(LOG_ERR, "rc_send_server: cannot figure our own address"); result = ERROR_RC; goto cleanup; } } if (sfuncs->get_fd) { sockfd = sfuncs->get_fd(sfuncs->ptr, SA(&our_sockaddr)); if (sockfd < 0) { memset(secret, '\0', sizeof(secret)); rc_log(LOG_ERR, "rc_send_server: socket: %s", strerror(errno)); result = ERROR_RC; goto cleanup; } } retry_max = data->retries; /* Max. numbers to try for reply */ retries = 0; /* Init retry cnt for blocking call */ if (data->svc_port) { if (our_sockaddr.ss_family == AF_INET) ((struct sockaddr_in *)auth_addr->ai_addr)->sin_port = htons((unsigned short)data->svc_port); else ((struct sockaddr_in6 *)auth_addr->ai_addr)->sin6_port = htons((unsigned short)data->svc_port); } /* * Fill in NAS-IP-Address (if needed) */ if (rh->nas_addr_set) { rc_avpair_remove(&(data->send_pairs), PW_NAS_IP_ADDRESS, 0); rc_avpair_remove(&(data->send_pairs), PW_NAS_IPV6_ADDRESS, 0); ss_set = &rh->nas_addr; } else if (rc_avpair_get(data->send_pairs, PW_NAS_IP_ADDRESS, 0) == NULL && rc_avpair_get(data->send_pairs, PW_NAS_IPV6_ADDRESS, 0) == NULL) { ss_set = &our_sockaddr; } if (ss_set) { if (ss_set->ss_family == AF_INET) { uint32_t ip; ip = *((uint32_t *) (&((struct sockaddr_in *)ss_set)-> sin_addr)); ip = ntohl(ip); rc_avpair_add(rh, &(data->send_pairs), PW_NAS_IP_ADDRESS, &ip, 0, 0); } else { void *p; p = &((struct sockaddr_in6 *)ss_set)->sin6_addr; rc_avpair_add(rh, &(data->send_pairs), PW_NAS_IPV6_ADDRESS, p, 16, 0); } } /* * Fill in NAS-Identifier (if needed) */ p = rc_conf_str(rh, "nas-identifier"); if (p != NULL) { rc_avpair_remove(&(data->send_pairs), PW_NAS_IDENTIFIER, 0); rc_avpair_add(rh, &(data->send_pairs), PW_NAS_IDENTIFIER, p, -1, 0); } /* Build a request */ auth = (AUTH_HDR *) send_buffer; auth->code = data->code; auth->id = data->seq_nbr; if (data->code == PW_ACCOUNTING_REQUEST) { server_type = "acct"; total_length = rc_pack_list(data->send_pairs, secret, auth) + AUTH_HDR_LEN; auth->length = htons((unsigned short)total_length); memset((char *)auth->vector, 0, AUTH_VECTOR_LEN); secretlen = strlen(secret); memcpy((char *)auth + total_length, secret, secretlen); rc_md5_calc(vector, (unsigned char *)auth, total_length + secretlen); memcpy((char *)auth->vector, (char *)vector, AUTH_VECTOR_LEN); } else { rc_random_vector(vector); memcpy((char *)auth->vector, (char *)vector, AUTH_VECTOR_LEN); total_length = rc_pack_list(data->send_pairs, secret, auth) + AUTH_HDR_LEN; auth->length = htons((unsigned short)total_length); } if (radcli_debug) { char our_addr_txt[50] = ""; /* hold a text IP */ char auth_addr_txt[50] = ""; /* hold a text IP */ getnameinfo(SA(&our_sockaddr), SS_LEN(&our_sockaddr), NULL, 0, our_addr_txt, sizeof(our_addr_txt), NI_NUMERICHOST); getnameinfo(auth_addr->ai_addr, auth_addr->ai_addrlen, NULL, 0, auth_addr_txt, sizeof(auth_addr_txt), NI_NUMERICHOST); DEBUG(LOG_ERR, "DEBUG: timeout=%d retries=%d local %s : 0, remote %s : %u\n", data->timeout, retry_max, our_addr_txt, auth_addr_txt, data->svc_port); } for (;;) { do { result = sfuncs->sendto(sfuncs->ptr, sockfd, (char *)auth, (unsigned int)total_length, (int)0, SA(auth_addr->ai_addr), auth_addr->ai_addrlen); } while (result == -1 && errno == EINTR); if (result == -1) { rc_log(LOG_ERR, "%s: socket: %s", __FUNCTION__, strerror(errno)); result = ERROR_RC; goto cleanup; } pfd.fd = sockfd; pfd.events = POLLIN; pfd.revents = 0; start_time = rc_getmtime(); for (timeout = data->timeout; timeout > 0; timeout -= rc_getmtime() - start_time) { result = poll(&pfd, 1, timeout * 1000); if (result != -1 || errno != EINTR) break; } if (result == -1) { rc_log(LOG_ERR, "rc_send_server: poll: %s", strerror(errno)); memset(secret, '\0', sizeof(secret)); SCLOSE(sockfd); result = ERROR_RC; goto cleanup; } if (result == 1 && (pfd.revents & POLLIN) != 0) { salen = auth_addr->ai_addrlen; do { length = sfuncs->recvfrom(sfuncs->ptr, sockfd, (char *)recv_buffer, (int) sizeof(recv_buffer), (int)0, SA(auth_addr-> ai_addr), &salen); } while (length == -1 && errno == EINTR); if (length <= 0) { int e = errno; rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: %s", server_name, data->svc_port, strerror(e)); if (length == -1 && (e == EAGAIN || e == EINTR)) continue; SCLOSE(sockfd); memset(secret, '\0', sizeof(secret)); result = ERROR_RC; goto cleanup; } recv_auth = (AUTH_HDR *) recv_buffer; if (length < AUTH_HDR_LEN || length < ntohs(recv_auth->length)) { rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: reply is too short", server_name, data->svc_port); SCLOSE(sockfd); memset(secret, '\0', sizeof(secret)); result = ERROR_RC; goto cleanup; } result = rc_check_reply(recv_auth, BUFFER_LEN, secret, vector, data->seq_nbr); if (result != BADRESPID_RC) { /* if a message that doesn't match our ID was received, then ignore * it, and try to receive more, until timeout. That is because in * DTLS the channel is shared, and we may receive duplicates or * out-of-order packets. */ break; } } /* * Timed out waiting for response. Retry "retry_max" times * before giving up. If retry_max = 0, don't retry at all. */ if (retries++ >= retry_max) { char radius_server_ip[128]; struct sockaddr_in *si = (struct sockaddr_in *)auth_addr->ai_addr; inet_ntop(auth_addr->ai_family, &si->sin_addr, radius_server_ip, sizeof(radius_server_ip)); rc_log(LOG_ERR, "rc_send_server: no reply from RADIUS %s server %s:%u", server_type, radius_server_ip, data->svc_port); SCLOSE(sockfd); memset(secret, '\0', sizeof(secret)); result = TIMEOUT_RC; goto cleanup; } } /* * If UDP is larger than RADIUS, shorten it to RADIUS. */ if (length > ntohs(recv_auth->length)) length = ntohs(recv_auth->length); /* * Verify that it's a valid RADIUS packet before doing ANYTHING with it. */ attr = recv_buffer + AUTH_HDR_LEN; while (attr < (recv_buffer + length)) { if (attr[0] == 0) { rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: attribute zero is invalid", server_name, data->svc_port); SCLOSE(sockfd); memset(secret, '\0', sizeof(secret)); result = ERROR_RC; goto cleanup; } if (attr[1] < 2) { rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: attribute length is too small", server_name, data->svc_port); SCLOSE(sockfd); memset(secret, '\0', sizeof(secret)); result = ERROR_RC; goto cleanup; } if ((attr + attr[1]) > (recv_buffer + length)) { rc_log(LOG_ERR, "rc_send_server: recvfrom: %s:%d: attribute overflows the packet", server_name, data->svc_port); SCLOSE(sockfd); memset(secret, '\0', sizeof(secret)); result = ERROR_RC; goto cleanup; } attr += attr[1]; } length = ntohs(recv_auth->length) - AUTH_HDR_LEN; if (length > 0) { data->receive_pairs = rc_avpair_gen(rh, NULL, recv_auth->data, length, 0); } else { data->receive_pairs = NULL; } SCLOSE(sockfd); result = populate_ctx(ctx, secret, vector); if (result != OK_RC) { memset(secret, '\0', sizeof(secret)); goto cleanup; } memset(secret, '\0', sizeof(secret)); if (msg) { *msg = '\0'; pos = 0; vp = data->receive_pairs; while (vp) { if ((vp = rc_avpair_get(vp, PW_REPLY_MESSAGE, 0))) { strappend(msg, PW_MAX_MSG_SIZE, &pos, vp->strvalue); strappend(msg, PW_MAX_MSG_SIZE, &pos, "\n"); vp = vp->next; } } } if ((recv_auth->code == PW_ACCESS_ACCEPT) || (recv_auth->code == PW_PASSWORD_ACK) || (recv_auth->code == PW_ACCOUNTING_RESPONSE)) { result = OK_RC; } else if ((recv_auth->code == PW_ACCESS_REJECT) || (recv_auth->code == PW_PASSWORD_REJECT)) { result = REJECT_RC; } else { rc_log(LOG_ERR, "rc_send_server: received RADIUS server response neither ACCEPT nor REJECT, invalid"); result = BADRESP_RC; } cleanup: if (auth_addr) freeaddrinfo(auth_addr); if (sfuncs->unlock) { if (sfuncs->unlock(sfuncs->ptr) != 0) { rc_log(LOG_ERR, "%s: unlock error", __func__); } } return result; }
static int load_uri_attrs(struct sip_msg* msg, unsigned long flags, fparam_t* fp) { static char rad_msg[4096]; struct sip_uri puri; str uri, did, scheme; UINT4 service; VALUE_PAIR* send, *received; send = NULL; received = NULL; if (get_str_fparam(&uri, msg, (fparam_t*)fp) != 0) { ERR("Unable to get URI\n"); return -1; } if (parse_uri(uri.s, uri.len, &puri) < 0) { ERR("Error while parsing URI '%.*s'\n", uri.len, uri.s); return -1; } if (puri.host.len) { /* domain name is present */ if (dm_get_did(&did, &puri.host) < 0) { DBG("Cannot lookup DID for domain %.*s, using default value\n", puri.host.len, ZSW(puri.host.s)); did.s = DEFAULT_DID; did.len = sizeof(DEFAULT_DID) - 1; } } else { /* domain name is missing -- can be caused by tel: URI */ DBG("There is no domain name, using default value\n"); did.s = DEFAULT_DID; did.len = sizeof(DEFAULT_DID) - 1; } uri_type_to_str(puri.type, &scheme); service = vals[V_GET_URI_ATTRS].v; if (scheme.len) { if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SER_URI_SCHEME].v), scheme.s, scheme.len, VENDOR(attrs[A_SER_URI_SCHEME].v))) { ERR("Error while adding A_SER_URI_SCHEME\n"); goto error; } } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_USER_NAME].v), puri.user.s, puri.user.len, VENDOR(attrs[A_USER_NAME].v))) { ERR("Error while adding A_USER_NAME\n"); goto error; } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SER_DID].v), did.s, did.len, VENDOR(attrs[A_SER_DID].v))) { ERR("Error while adding A_SER_DID\n"); goto error; } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SER_SERVICE_TYPE].v), &vals[V_GET_URI_ATTRS].v, -1, VENDOR(attrs[A_SER_SERVICE_TYPE].v))) { ERR("Error adding A_SERVICE_TYPE\n"); goto error; } if (rc_auth(rh, 0, send, &received, rad_msg) != OK_RC) { DBG("load_uri_attrs: Failure\n"); goto error; } DBG("load_uri_attrs: Success\n"); rc_avpair_free(send); if (generate_avps(flags, received) < 0) { rc_avpair_free(received); goto error; } rc_avpair_free(received); return 1; error: if (send) rc_avpair_free(send); if (received) rc_avpair_free(send); return -1; }
/* * This function creates and submits radius authentication request as per * draft-sterman-aaa-sip-00.txt. In addition, _user parameter is included * in the request as value of a SER specific attribute type SIP-URI-User, * which can be be used as a check item in the request. Service type of * the request is Authenticate-Only. */ int radius_authorize_sterman(dig_cred_t* _cred, str* _method, str* _user, str* _rpid) { static char msg[4096]; VALUE_PAIR *send, *received, *vp; UINT4 service; str method, user, user_name; int i; send = received = 0; if (!(_cred && _method && _user && _rpid)) { LOG(L_ERR, "radius_authorize_sterman(): Invalid parameter value\n"); return -1; } method = *_method; user = *_user; /* * Add all the user digest parameters according to the qop defined. * Most devices tested only offer support for the simplest digest. */ if (_cred->username.domain.len) { if (!rc_avpair_add(&send, PW_USER_NAME, _cred->username.whole.s, _cred->username.whole.len)) { LOG(L_ERR, "sterman(): Unable to add PW_USER_NAME attribute\n"); rc_avpair_free(send); return -2; } } else { user_name.len = _cred->username.user.len + _cred->realm.len + 1; user_name.s = pkg_malloc(user_name.len); if (!user_name.s) { LOG(L_ERR, "radius_authorize_sterman(): No memory left\n"); return -3; } memcpy(user_name.s, _cred->username.whole.s, _cred->username.whole.len); user_name.s[_cred->username.whole.len] = '@'; memcpy(user_name.s + _cred->username.whole.len + 1, _cred->realm.s, _cred->realm.len); if (!rc_avpair_add(&send, PW_USER_NAME, user_name.s, user_name.len)) { LOG(L_ERR, "sterman(): Unable to add PW_USER_NAME attribute\n"); pkg_free(user_name.s); rc_avpair_free(send); return -4; } pkg_free(user_name.s); } if (!rc_avpair_add(&send, PW_DIGEST_USER_NAME, _cred->username.whole.s, _cred->username.whole.len)) { LOG(L_ERR, "sterman(): Unable to add PW_DIGEST_USER_NAME attribute\n"); rc_avpair_free(send); return -5; } if (!rc_avpair_add(&send, PW_DIGEST_REALM, _cred->realm.s, _cred->realm.len)) { LOG(L_ERR, "sterman(): Unable to add PW_DIGEST_REALM attribute\n"); rc_avpair_free(send); return -6; } if (!rc_avpair_add(&send, PW_DIGEST_NONCE, _cred->nonce.s, _cred->nonce.len)) { LOG(L_ERR, "sterman(): Unable to add PW_DIGEST_NONCE attribute\n"); rc_avpair_free(send); return -7; } if (!rc_avpair_add(&send, PW_DIGEST_URI, _cred->uri.s, _cred->uri.len)) { LOG(L_ERR, "sterman(): Unable to add PW_DIGEST_URI attribute\n"); rc_avpair_free(send); return -8; } if (!rc_avpair_add(&send, PW_DIGEST_METHOD, method.s, method.len)) { LOG(L_ERR, "sterman(): Unable to add PW_DIGEST_METHOD attribute\n"); rc_avpair_free(send); return -9; } /* * Add the additional authentication fields according to the QOP. */ if (_cred->qop.qop_parsed == QOP_AUTH) { if (!rc_avpair_add(&send, PW_DIGEST_QOP, "auth", 4)) { LOG(L_ERR, "sterman(): Unable to add PW_DIGEST_QOP attribute\n"); rc_avpair_free(send); return -10; } if (!rc_avpair_add(&send, PW_DIGEST_NONCE_COUNT, _cred->nc.s, _cred->nc.len)) { LOG(L_ERR, "sterman(): Unable to add PW_DIGEST_NONCE_COUNT attribute\n"); rc_avpair_free(send); return -11; } if (!rc_avpair_add(&send, PW_DIGEST_CNONCE, _cred->cnonce.s, _cred->cnonce.len)) { LOG(L_ERR, "sterman(): Unable to add PW_DIGEST_CNONCE attribute\n"); rc_avpair_free(send); return -12; } } else if (_cred->qop.qop_parsed == QOP_AUTHINT) { if (!rc_avpair_add(&send, PW_DIGEST_QOP, "auth-int", 8)) { LOG(L_ERR, "sterman(): Unable to add PW_DIGEST_QOP attribute\n"); rc_avpair_free(send); return -13; } if (!rc_avpair_add(&send, PW_DIGEST_NONCE_COUNT, _cred->nc.s, _cred->nc.len)) { LOG(L_ERR, "sterman(): Unable to add PW_DIGEST_NONCE_COUNT attribute\n"); rc_avpair_free(send); return -14; } if (!rc_avpair_add(&send, PW_DIGEST_CNONCE, _cred->cnonce.s, _cred->cnonce.len)) { LOG(L_ERR, "sterman(): Unable to add PW_DIGEST_CNONCE attribute\n"); rc_avpair_free(send); return -15; } if (!rc_avpair_add(&send, PW_DIGEST_BODY_DIGEST, _cred->opaque.s, _cred->opaque.len)) { LOG(L_ERR, "sterman(): Unable to add PW_DIGEST_BODY_DIGEST attribute\n"); rc_avpair_free(send); return -16; } } else { /* send nothing for qop == "" */ } /* * Now put everything place all the previous attributes into the * PW_DIGEST_ATTRIBUTES */ /* * Fix up Digest-Attributes issues see draft-sterman-aaa-sip-00 */ for (vp = send; vp; vp = vp->next) { switch (vp->attribute) { default: break; /* Fall thru the know values */ 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! */ memmove(&vp->strvalue[2], &vp->strvalue[0], vp->lvalue); vp->strvalue[0] = vp->attribute - PW_DIGEST_REALM + 1; vp->lvalue += 2; vp->strvalue[1] = vp->lvalue; vp->attribute = PW_DIGEST_ATTRIBUTES; break; } } /* Add the response... What to calculate against... */ if (!rc_avpair_add(&send, PW_DIGEST_RESPONSE, _cred->response.s, _cred->response.len)) { LOG(L_ERR, "sterman(): Unable to add PW_DIGEST_RESPONSE attribute\n"); rc_avpair_free(send); return -17; } /* Indicate the service type, Authenticate only in our case */ service = service_type; if (!rc_avpair_add(&send, PW_SERVICE_TYPE, &service, 0)) { LOG(L_ERR, "sterman(): Unable to add PW_SERVICE_TYPE attribute\n"); rc_avpair_free(send); return -18; } /* Add SIP URI as a check item */ if (!rc_avpair_add(&send, PW_SIP_URI_USER, user.s, user.len)) { LOG(L_ERR, "sterman(): Unable to add PW_SIP_URI_USER attribute\n"); rc_avpair_free(send); return -19; } /* Send request */ if ((i = rc_auth(SIP_PORT, send, &received, msg)) == OK_RC) { DBG("radius_authorize_sterman(): Success\n"); rc_avpair_free(send); /* Make a copy of rpid if available */ if ((vp = rc_avpair_get(received, PW_SIP_RPID))) { if (MAX_RPID_LEN < vp->lvalue) { LOG(L_ERR, "radius_authorize_sterman(): rpid buffer too small\n"); return -20; } memcpy(_rpid->s, vp->strvalue, vp->lvalue); _rpid->len = vp->lvalue; } rc_avpair_free(received); return 1; } else { DBG("res: %d\n", i); DBG("radius_authorize_sterman(): Failure\n"); rc_avpair_free(send); rc_avpair_free(received); return -21; } }
static int load_avp_user(struct sip_msg* msg, str* prefix, load_avp_param_t type) { static char rad_msg[4096]; str user_domain, buffer; str* user, *domain, *uri; struct hdr_field* h; dig_cred_t* cred = 0; int_str name, val; unsigned short flags; VALUE_PAIR* send, *received, *vp; UINT4 service; struct sip_uri puri; send = received = 0; user_domain.s = 0; switch(type) { case LOAD_CALLER: /* Use From header field */ if (parse_from_header(msg) < 0) { LOG(L_ERR, "ERROR:avp_radius:load_avp_user: Error while " "parsing From header field\n"); return -1; } uri = &get_from(msg)->uri; if (parse_uri(uri->s, uri->len, &puri) == -1) { LOG(L_ERR, "ERROR:avp_radius:load_avp_user: Error while " "parsing From URI\n"); return -1; } user = &puri.user; domain = &puri.host; service = vals[V_SIP_CALLER_AVPS].v; break; case LOAD_CALLEE: /* Use the Request-URI */ if (parse_sip_msg_uri(msg) < 0) { LOG(L_ERR, "ERROR:avp_radius:load_avp_user: Error while " "parsing Request-URI\n"); return -1; } if (msg->parsed_uri.user.len == 0) { LOG(L_ERR, "ERROR:avp_radius:load_avp_user: Request-URI user " "is missing\n"); return -1; } user = &msg->parsed_uri.user; domain = &msg->parsed_uri.host; service = vals[V_SIP_CALLEE_AVPS].v; break; case LOAD_DIGEST: /* Use digest credentials */ get_authorized_cred(msg->proxy_auth, &h); if (!h) { LOG(L_ERR, "ERROR:avp_radius:load_avp_user: No authoried " "credentials\n"); return -1; } cred = &((auth_body_t*)(h->parsed))->digest; user = &cred->username.user; domain = &cred->realm; service = vals[V_SIP_CALLER_AVPS].v; break; default: LOG(L_ERR, "ERROR:avp_radius:avp_load_user: Unknown user type\n"); return -1; } user_domain.len = user->len + 1 + domain->len; user_domain.s = (char*)pkg_malloc(user_domain.len); if (!user_domain.s) { LOG(L_ERR, "ERROR:avp_radius:avp_load_user: No pkg memory left\n"); return -1; } memcpy(user_domain.s, user->s, user->len); user_domain.s[user->len] = '@'; memcpy(user_domain.s + user->len + 1, domain->s, domain->len); if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, user_domain.s, user_domain.len, 0)) { LOG(L_ERR, "ERROR:avp_radius:avp_load_user: Error adding " "PW_USER_NAME\n"); goto error; } if (!rc_avpair_add(rh, &send, attrs[A_SERVICE_TYPE].v, &service, -1, 0)) { LOG(L_ERR, "ERROR:avp_radius:avp_load_user: Error adding " "PW_SERVICE_TYPE\n"); goto error; } if (rc_auth(rh, 0, send, &received, rad_msg) == OK_RC) { DBG("DEBUG:avp_radius:avp_load_user: rc_auth Success\n"); rc_avpair_free(send); pkg_free(user_domain.s); vp = received; for( ; (vp=rc_avpair_get(vp,attrs[A_SIP_AVP].v,0)) ; vp=vp->next) { flags = 0; if (extract_avp( vp, &flags, &name, &val)!=0 ) continue; /* append prefix only if AVP has name */ if (flags&AVP_NAME_STR) { buffer.len = prefix->len + name.s->len; buffer.s = (char*)pkg_malloc(buffer.len); if (!buffer.s) { LOG(L_ERR, "ERROR:avp_radius:avp_load_user: "******"No pkg memory left\n"); return -1; } memcpy(buffer.s, prefix->s, prefix->len); memcpy(buffer.s + prefix->len, name.s->s, name.s->len); name.s = &buffer; } else { buffer.s = 0; } if (add_avp( flags, name, val) < 0) { LOG(L_ERR, "ERROR:avp_radius:avp_load_user: Unable to create " "a new AVP\n"); } else { DBG("DEBUG:avp_radius:generate_avps: " "AVP '%.*s'/%d='%.*s'/%d has been added\n", (flags&AVP_NAME_STR)?name.s->len:4, (flags&AVP_NAME_STR)?name.s->s:"null", (flags&AVP_NAME_STR)?0:name.n, (flags&AVP_VAL_STR)?val.s->len:4, (flags&AVP_VAL_STR)?val.s->s:"null", (flags&AVP_VAL_STR)?0:val.n ); } if (buffer.s) pkg_free(buffer.s); } rc_avpair_free(received); return 1; } else { LOG(L_ERR,"ERROR:avp_radius:avp_load_user: rc_auth failed\n"); } error: if (send) rc_avpair_free(send); if (received) rc_avpair_free(received); if (user_domain.s) pkg_free(user_domain.s); return -1; }
/** Builds an authentication/accounting request for port id client_port with the value_pairs send and submits it to a server * * @param rh a handle to parsed configuration. * @param client_port the client port number to use (may be zero to use any available). * @param send a #VALUE_PAIR array of values (e.g., %PW_USER_NAME). * @param received an allocated array of received values. * @param msg must be an array of %PW_MAX_MSG_SIZE or %NULL; will contain the concatenation of any * %PW_REPLY_MESSAGE received. * @param add_nas_port if non-zero it will include %PW_NAS_PORT in sent pairs. * @param request_type one of standard RADIUS codes (e.g., %PW_ACCESS_REQUEST). * @return received value_pairs in received, messages from the server in msg and %OK_RC (0) on success, negative * on failure as return value. */ int rc_aaa(rc_handle *rh, uint32_t client_port, VALUE_PAIR *send, VALUE_PAIR **received, char *msg, int add_nas_port, int request_type) { SEND_DATA data; VALUE_PAIR *adt_vp = NULL; int result; int i, skip_count; SERVER *aaaserver; int timeout = rc_conf_int(rh, "radius_timeout"); int retries = rc_conf_int(rh, "radius_retries"); int radius_deadtime = rc_conf_int(rh, "radius_deadtime"); double start_time = 0; double now = 0; time_t dtime; unsigned type; if (request_type != PW_ACCOUNTING_REQUEST) { aaaserver = rc_conf_srv(rh, "authserver"); type = AUTH; } else { aaaserver = rc_conf_srv(rh, "acctserver"); type = ACCT; } if (aaaserver == NULL) return ERROR_RC; data.send_pairs = send; data.receive_pairs = NULL; if (add_nas_port != 0) { /* * Fill in NAS-Port */ if (rc_avpair_add(rh, &(data.send_pairs), PW_NAS_PORT, &client_port, 0, 0) == NULL) return ERROR_RC; } if (request_type == PW_ACCOUNTING_REQUEST) { /* * Fill in Acct-Delay-Time */ dtime = 0; now = rc_getctime(); adt_vp = rc_avpair_get(data.send_pairs, PW_ACCT_DELAY_TIME, 0); if (adt_vp == NULL) { adt_vp = rc_avpair_add(rh, &(data.send_pairs), PW_ACCT_DELAY_TIME, &dtime, 0, 0); if (adt_vp == NULL) return ERROR_RC; start_time = now; } else { start_time = now - adt_vp->lvalue; } } skip_count = 0; result = ERROR_RC; for (i=0; (i < aaaserver->max) && (result != OK_RC) && (result != REJECT_RC) ; i++, now = rc_getctime()) { if (aaaserver->deadtime_ends[i] != -1 && aaaserver->deadtime_ends[i] > start_time) { skip_count++; continue; } if (data.receive_pairs != NULL) { rc_avpair_free(data.receive_pairs); data.receive_pairs = NULL; } rc_buildreq(rh, &data, request_type, aaaserver->name[i], aaaserver->port[i], aaaserver->secret[i], timeout, retries); if (request_type == PW_ACCOUNTING_REQUEST) { dtime = now - start_time; rc_avpair_assign(adt_vp, &dtime, 0); } result = rc_send_server (rh, &data, msg, type); if (result == TIMEOUT_RC && radius_deadtime > 0) aaaserver->deadtime_ends[i] = start_time + (double)radius_deadtime; } if (result == OK_RC || result == REJECT_RC || skip_count == 0) goto exit; result = ERROR_RC; for (i=0; (i < aaaserver->max) && (result != OK_RC) && (result != REJECT_RC) ; i++) { if (aaaserver->deadtime_ends[i] == -1 || aaaserver->deadtime_ends[i] <= start_time) { continue; } if (data.receive_pairs != NULL) { rc_avpair_free(data.receive_pairs); data.receive_pairs = NULL; } rc_buildreq(rh, &data, request_type, aaaserver->name[i], aaaserver->port[i], aaaserver->secret[i], timeout, retries); if (request_type == PW_ACCOUNTING_REQUEST) { dtime = rc_getctime() - start_time; rc_avpair_assign(adt_vp, &dtime, 0); } result = rc_send_server (rh, &data, msg, type); if (result != TIMEOUT_RC) aaaserver->deadtime_ends[i] = -1; } exit: if (request_type != PW_ACCOUNTING_REQUEST) { *received = data.receive_pairs; } else { rc_avpair_free(data.receive_pairs); } return result; }
/* * This function creates and submits radius authentication request as per * draft-sterman-aaa-sip-00.txt. In addition, _user parameter is included * in the request as value of a SER specific attribute type SIP-URI-User, * which can be be used as a check item in the request. Service type of * the request is Authenticate-Only. */ int radius_authorize_sterman(struct sip_msg* _msg, dig_cred_t* _cred, str* _method, str* _user) { static char msg[4096]; VALUE_PAIR *send, *received; uint32_t service; str method, user, user_name; str *ruri; int extra_cnt, offset, i; send = received = 0; if (!(_cred && _method && _user)) { LM_ERR("invalid parameter value\n"); return -1; } method = *_method; user = *_user; /* * Add all the user digest parameters according to the qop defined. * Most devices tested only offer support for the simplest digest. */ if (_cred->username.domain.len || !append_realm_to_username) { if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, _cred->username.whole.s, _cred->username.whole.len, 0)) { LM_ERR("unable to add User-Name attribute\n"); goto err; } } else { user_name.len = _cred->username.user.len + _cred->realm.len + 1; user_name.s = pkg_malloc(user_name.len); if (!user_name.s) { LM_ERR("no pkg memory left\n"); return -3; } memcpy(user_name.s, _cred->username.whole.s, _cred->username.whole.len); user_name.s[_cred->username.whole.len] = '@'; memcpy(user_name.s + _cred->username.whole.len + 1, _cred->realm.s, _cred->realm.len); if (!rc_avpair_add(rh, &send, attrs[A_USER_NAME].v, user_name.s, user_name.len, 0)) { LM_ERR("unable to add User-Name attribute\n"); pkg_free(user_name.s); goto err; } pkg_free(user_name.s); } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_USER_NAME].v, _cred->username.whole.s, _cred->username.whole.len, 0)) { LM_ERR("unable to add Digest-User-Name attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_REALM].v, _cred->realm.s, _cred->realm.len, 0)) { LM_ERR("unable to add Digest-Realm attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_NONCE].v, _cred->nonce.s, _cred->nonce.len, 0)) { LM_ERR("unable to add Digest-Nonce attribute\n"); goto err; } if (use_ruri_flag < 0 || isflagset(_msg, use_ruri_flag) != 1) { ruri = &_cred->uri; } else { ruri = GET_RURI(_msg); } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_URI].v, ruri->s, ruri->len, 0)) { LM_ERR("unable to add Digest-URI attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_METHOD].v, method.s, method.len, 0)) { LM_ERR("unable to add Digest-Method attribute\n"); goto err; } /* * Add the additional authentication fields according to the QOP. */ if (_cred->qop.qop_parsed == QOP_AUTH) { if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_QOP].v, "auth", 4, 0)) { LM_ERR("unable to add Digest-QOP attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_NONCE_COUNT].v, _cred->nc.s, _cred->nc.len, 0)) { LM_ERR("unable to add Digest-CNonce-Count attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_CNONCE].v, _cred->cnonce.s, _cred->cnonce.len, 0)) { LM_ERR("unable to add Digest-CNonce attribute\n"); goto err; } } else if (_cred->qop.qop_parsed == QOP_AUTHINT) { if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_QOP].v, "auth-int", 8, 0)) { LM_ERR("unable to add Digest-QOP attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_NONCE_COUNT].v, _cred->nc.s, _cred->nc.len, 0)) { LM_ERR("unable to add Digest-Nonce-Count attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_CNONCE].v, _cred->cnonce.s, _cred->cnonce.len, 0)) { LM_ERR("unable to add Digest-CNonce attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_BODY_DIGEST].v, _cred->opaque.s, _cred->opaque.len, 0)) { LM_ERR("unable to add Digest-Body-Digest attribute\n"); goto err; } } else { /* send nothing for qop == "" */ } /* Add the response... What to calculate against... */ if (!rc_avpair_add(rh, &send, attrs[A_DIGEST_RESPONSE].v, _cred->response.s, _cred->response.len, 0)) { LM_ERR("unable to add Digest-Response attribute\n"); goto err; } /* Indicate the service type, Authenticate only in our case */ service = vals[V_SIP_SESSION].v; if (!rc_avpair_add(rh, &send, attrs[A_SERVICE_TYPE].v, &service, -1, 0)) { LM_ERR("unable to add Service-Type attribute\n"); goto err; } /* Add SIP URI as a check item */ if (!rc_avpair_add(rh,&send,attrs[A_SIP_URI_USER].v,user.s,user.len,0)) { LM_ERR("unable to add Sip-URI-User attribute\n"); goto err; } if (attrs[A_CISCO_AVPAIR].n != NULL) { if (add_cisco_vsa(&send, _msg)) { goto err; } } /* Add extra attributes */ extra_cnt = extra2strar(auth_extra, _msg, val_arr); if (extra_cnt == -1) { LM_ERR("in getting values of extra attributes\n"); goto err; } offset = A_MAX; for (i = 0; i < extra_cnt; i++) { if (val_arr[i].len == -1) { /* Add integer attribute */ ADD_EXTRA_AVPAIR(attrs, offset+i, &(val_arr[i].s), val_arr[i].len ); } else { /* Add string attribute */ ADD_EXTRA_AVPAIR(attrs, offset+i, val_arr[i].s, val_arr[i].len ); } } /* Send request */ if ((i = rc_auth(rh, SIP_PORT, send, &received, msg)) == OK_RC) { LM_DBG("Success\n"); rc_avpair_free(send); send = 0; generate_avps(received); rc_avpair_free(received); return 1; } else { #ifdef REJECT_RC if (i == REJECT_RC) { LM_DBG("Failure\n"); goto err; } #endif LM_ERR("authorization failed. RC auth returned %d\n", i); } err: if (send) rc_avpair_free(send); if (received) rc_avpair_free(received); return -1; }
/** * @param[in] session Session * @param[in] status Accounting status (PW_STATUS_START, PW_STATUS_STOP, PW_STATUS_ALIVE) * @param[in] cause Accounting termination cause (used only in case of PW_STATUS_STOP) * @param[in] req Accounting request data. */ static zrad_status_t zrad_acct_request(rc_handle *radh, const zrad_acct_req_t *req) { zrad_status_t ret; VALUE_PAIR *request_attrs = NULL; int success = rc_avpair_add(radh, &request_attrs, PW_CALLING_STATION_ID, req->calling_station_id, -1, 0) && rc_avpair_add(radh, &request_attrs, PW_ACCT_AUTHENTIC, &req->authentic, -1, 0) && rc_avpair_add(radh, &request_attrs, PW_FRAMED_IP_ADDRESS, &req->framed_ip_addr, -1, 0) && rc_avpair_add(radh, &request_attrs, PW_USER_NAME, req->username, -1, 0) && rc_avpair_add(radh, &request_attrs, PW_ACCT_SESSION_ID, req->session_id, -1, 0) && rc_avpair_add(radh, &request_attrs, PW_NAS_IDENTIFIER, req->nas_id, -1, 0) && rc_avpair_add(radh, &request_attrs, PW_ACCT_INPUT_OCTETS, &req->octets_down, -1, 0) && rc_avpair_add(radh, &request_attrs, PW_ACCT_INPUT_PACKETS, &req->packets_down, -1, 0) && rc_avpair_add(radh, &request_attrs, PW_ACCT_OUTPUT_OCTETS, &req->octets_up, -1, 0) && rc_avpair_add(radh, &request_attrs, PW_ACCT_OUTPUT_PACKETS, &req->packets_down, -1, 0) && (!req->gigawords_down || rc_avpair_add(radh, &request_attrs, PW_ACCT_OUTPUT_GIGAWORDS, &req->gigawords_up, -1, 0)) && (!req->gigawords_down || rc_avpair_add(radh, &request_attrs, PW_ACCT_INPUT_GIGAWORDS, &req->gigawords_down, -1, 0)) && rc_avpair_add(radh, &request_attrs, PW_ACCT_STATUS_TYPE, &req->status, -1, 0); if (success && PW_STATUS_STOP == req->status) { success = success && rc_avpair_add(radh, &request_attrs, PW_ACCT_SESSION_TIME, &req->session_time, -1, 0) && rc_avpair_add(radh, &request_attrs, PW_ACCT_TERMINATE_CAUSE, &req->term_cause, -1, 0); } if (likely(success)) { ret = (zrad_status_t) rc_acct(radh, 0, request_attrs); } else { ret = ZRAD_OTHER; } if (likely(request_attrs)) rc_avpair_free(request_attrs); return ret; }
/* * Loads from Radius callee's AVPs based on pvar argument. * Returns 1 if Radius request succeeded and -1 otherwise. */ int radius_load_callee_avps(struct sip_msg* _m, char* _callee, char* _s2) { str user; VALUE_PAIR *send, *received; uint32_t service; static char msg[4096]; int extra_cnt, offset, i, res; send = received = 0; if ((_callee == NULL) || (fixup_get_svalue(_m, (gparam_p)_callee, &user) != 0)) { LM_ERR("invalid callee parameter"); return -1; } if (!rc_avpair_add(rh, &send, callee_attrs[SA_USER_NAME].v, user.s, user.len, 0)) { LM_ERR("in adding SA_USER_NAME\n"); return -1; } service = callee_vals[EV_SIP_CALLEE_AVPS].v; if (!rc_avpair_add(rh, &send, callee_attrs[SA_SERVICE_TYPE].v, &service, -1, 0)) { LM_ERR("in adding SA_SERVICE_TYPE <%u>\n", service); goto error; } /* Add extra attributes */ extra_cnt = extra2strar(callee_extra, _m, val_arr); if (extra_cnt == -1) { LM_ERR("in getting values of callee extra attributes\n"); goto error; } offset = SA_STATIC_MAX; for (i = 0; i < extra_cnt; i++) { if (val_arr[i].len == -1) { /* Add integer attribute */ ADD_EXTRA_AVPAIR(callee_attrs, offset+i, &(val_arr[i].s), val_arr[i].len ); } else { /* Add string attribute */ ADD_EXTRA_AVPAIR(callee_attrs, offset+i, val_arr[i].s, val_arr[i].len ); } } if ((res = rc_auth(rh, 0, send, &received, msg)) == OK_RC) { LM_DBG("success\n"); rc_avpair_free(send); generate_avps(callee_attrs, received); rc_avpair_free(received); return 1; } else { rc_avpair_free(send); rc_avpair_free(received); #ifdef REJECT_RC if (res == REJECT_RC) { LM_DBG("rejected\n"); return -1; } else { LM_ERR("failure\n"); return -2; } #else LM_DBG("failure\n"); return -1; #endif } error: rc_avpair_free(send); return -1; }
static int build_radius_record(VALUE_PAIR **send, struct ast_cel_event_record *record) { int recordtype = PW_STATUS_STOP; struct ast_tm tm; char timestr[128]; char *amaflags; int left_len; char *left_value; int send_len; if (!rc_avpair_add(rh, send, PW_ACCT_STATUS_TYPE, &recordtype, 0, 0)) { return -1; } /* Account code */ if (!ADD_VENDOR_CODE(PW_AST_ACCT_CODE, record->account_code)) { return -1; } /* Source */ if (!ADD_VENDOR_CODE(PW_AST_CIDNUM, record->caller_id_num)) { return -1; } /* Destination */ if (!ADD_VENDOR_CODE(PW_AST_EXTEN, record->extension)) { return -1; } /* Destination context */ if (!ADD_VENDOR_CODE(PW_AST_CONTEXT, record->context)) { return -1; } /* Caller ID */ if (!ADD_VENDOR_CODE(PW_AST_CIDNAME, record->caller_id_name)) { return -1; } /* Caller ID ani */ if (!ADD_VENDOR_CODE(PW_AST_CIDANI, record->caller_id_ani)) { return -1; } /* Caller ID rdnis */ if (!ADD_VENDOR_CODE(PW_AST_CIDRDNIS, record->caller_id_rdnis)) { return -1; } /* Caller ID dnid */ if (!ADD_VENDOR_CODE(PW_AST_CIDDNID, record->caller_id_dnid)) { return -1; } /* Channel */ if (!ADD_VENDOR_CODE(PW_AST_CHANNAME, record->channel_name)) { return -1; } /* Last Application */ if (!ADD_VENDOR_CODE(PW_AST_APPNAME, record->application_name)) { return -1; } /* Last Data */ if (!ADD_VENDOR_CODE(PW_AST_APPDATA, record->application_data)) { return -1; } /* Extra */ left_len = strlen(record->extra); left_value = (char *)record->extra; while(left_len > 0){ if(left_len > 240){ send_len = 240; }else{ send_len = left_len; } if(!rc_avpair_add(rh, send, PW_AST_EXTRA, left_value, send_len, VENDOR_CODE )) { return -1; } left_len-=send_len; left_value+=send_len; } /* Event Time */ ast_localtime(&record->event_time, &tm, ast_test_flag(&global_flags, RADIUS_FLAG_USEGMTIME) ? "GMT" : NULL); ast_strftime(timestr, sizeof(timestr), DATE_FORMAT, &tm); if (!rc_avpair_add(rh, send, PW_AST_EVENT_TIME, timestr, strlen(timestr), VENDOR_CODE)) { return -1; } /* AMA Flags */ amaflags = ast_strdupa(ast_channel_amaflags2string(record->amaflag)); if (!rc_avpair_add(rh, send, PW_AST_AMA_FLAGS, amaflags, strlen(amaflags), VENDOR_CODE)) { return -1; } if (ast_test_flag(&global_flags, RADIUS_FLAG_LOGUNIQUEID)) { /* Unique ID */ if (!ADD_VENDOR_CODE(PW_AST_UNIQUE_ID, record->unique_id)) { return -1; } } /* LinkedID */ if (!ADD_VENDOR_CODE(PW_AST_LINKED_ID, record->linked_id)) { return -1; } /* Setting Acct-Session-Id & User-Name attributes for proper generation of Acct-Unique-Session-Id on server side */ /* Channel */ if (!rc_avpair_add(rh, send, PW_USER_NAME, (void *)record->channel_name, strlen(record->channel_name), 0)) { return -1; } return 0; }
LFUNC auth_radius(UINT4 client_port, char *username, char *passwd) { VALUE_PAIR *send, *received, *vp, *service_vp; UINT4 service, ftype, ctype; char msg[4096], *p, username_realm[256]; char name[2048], value[2048]; /* more than enough */ int result; char *default_realm, *service_str, *ftype_str; DICT_VALUE *dval; send = received = NULL; /* * Determine and fill in Service-Type */ #ifdef SCP /* determine based on the username what kind of service is requested. this allows you to use one password for all accounts, but the Merit radiusd supplies you just with the right information you need for the specified service type -lf, 03/15/96 */ switch (*username) { case 'S': service = PW_FRAMED; ftype = PW_SLIP; ctype = 0; username++; break; case 'C': service = PW_FRAMED; ftype = PW_SLIP; ctype = PW_VAN_JACOBSON_TCP_IP; username++; break; case 'P': service = PW_FRAMED; ftype = PW_PPP; ctype = 0; username++; break; default: service = PW_LOGIN; ftype = 0; ctype = 0; break; } #else service = PW_LOGIN; ftype = 0; ctype = 0; #endif if (rc_avpair_add(&send, PW_SERVICE_TYPE, &service, 0, VENDOR_NONE) == NULL) return (LFUNC) NULL; /* Fill in Framed-Protocol, if neccessary */ if (ftype != 0) { if (rc_avpair_add(&send, PW_FRAMED_PROTOCOL, &ftype, 0, VENDOR_NONE) == NULL) return (LFUNC) NULL; } /* Fill in Framed-Compression, if neccessary */ if (ctype != 0) { if (rc_avpair_add(&send, PW_FRAMED_COMPRESSION, &ctype, 0, VENDOR_NONE) == NULL) return (LFUNC) NULL; } /* * Fill in User-Name */ strncpy(username_realm, username, sizeof(username_realm)); /* Append default realm */ default_realm = rc_conf_str("default_realm"); if ((strchr(username_realm, '@') == NULL) && default_realm && ((*default_realm) != '\0')) { strncat(username_realm, "@", sizeof(username_realm)); strncat(username_realm, default_realm, sizeof(username_realm)); } if (rc_avpair_add(&send, PW_USER_NAME, username_realm, 0, VENDOR_NONE) == NULL) return (LFUNC) NULL; /* * Fill in User-Password */ if (rc_avpair_add(&send, PW_USER_PASSWORD, passwd, 0, VENDOR_NONE) == NULL) return (LFUNC) NULL; result = rc_auth(client_port, send, &received, msg, NULL); if (result == OK_RC) { /* Set up a running count of attributes saved. */ int acount[256], attr; memset(acount, 0, sizeof(acount)); rc_add_env(env, "RADIUS_USER_NAME", username); vp = received; /* map-- keep track of the attributes so that we know when to add the delimiters. Note that we can only handle attributes < 256, which is the standard anyway. */ while (vp) { strcpy(name, "RADIUS_"); if (rc_avpair_tostr(vp, name+7, sizeof(name)-7, value, sizeof(value)) < 0) { rc_avpair_free(send); rc_avpair_free(received); return (LFUNC) NULL; } /* Translate "-" => "_" and uppercase*/ for(p = name; *p; p++) { *p = toupper(*p); if (*p == '-') *p = '_'; } /* Add to the attribute count and append the var if necessary. */ if ((attr = vp->attribute) < 256) { int count; if ((count = acount[attr]++) > 0) { char buf[10]; sprintf(buf, "_%d", count); strcat(name,buf); } } if (rc_add_env(env, name, value) < 0) { rc_avpair_free(send); rc_avpair_free(received); return (LFUNC) NULL; } vp = vp->next; } service_str = "(unknown)"; ftype_str = NULL; if ((service_vp = rc_avpair_get(received, PW_SERVICE_TYPE)) != NULL) if ((dval = rc_dict_getval(service_vp->lvalue, service_vp->name)) != NULL) { service_str = dval->name; } if (service_vp && (service_vp->lvalue == PW_FRAMED) && ((vp = rc_avpair_get(received, PW_FRAMED_PROTOCOL)) != NULL)) if ((dval = rc_dict_getval(vp->lvalue, vp->name)) != NULL) { ftype_str = dval->name; } rc_log(LOG_NOTICE, "authentication OK, username %s, service %s%s%s", username, service_str,(ftype_str)?"/":"", (ftype_str)?ftype_str:""); if (msg && (*msg != '\0')) printf(SC_SERVER_REPLY, msg); else printf(SC_RADIUS_OK); rc_avpair_free(send); rc_avpair_free(received); return radius_login; } else { rc_log(LOG_NOTICE, "authentication FAILED, type RADIUS, username %s", username_realm); if (msg && (*msg != '\0')) printf(SC_SERVER_REPLY, msg); else printf(SC_RADIUS_FAILED); } rc_avpair_free(send); if (received) rc_avpair_free(received); return (LFUNC) NULL; }
/* * Check from Radius if a user belongs to a group. User-Name is given in * first string argment that may contain pseudo variables. SIP-Group is * given in second string variable that may not contain pseudo variables. * Service-Type is Group-Check. */ int radius_is_user_in(struct sip_msg* _m, char* _user, char* _group) { str user, *group; VALUE_PAIR *send, *received; uint32_t service; static char msg[4096]; int extra_cnt, offset, i, res; send = received = 0; if ((_user == NULL) || (fixup_get_svalue(_m, (gparam_p)_user, &user) != 0)) { LM_ERR("invalid user parameter"); return -1; } if (!rc_avpair_add(rh, &send, group_attrs[SA_USER_NAME].v, user.s, user.len, 0)) { LM_ERR("in adding SA_USER_NAME\n"); return -1; } group = (str*)_group; if ((group == NULL) || (group->len == 0)) { LM_ERR("invalid group parameter"); goto error; } if (!rc_avpair_add(rh, &send, group_attrs[SA_SIP_GROUP].v, group->s, group->len, 0)) { LM_ERR("in adding SA_SIP_GROUP\n"); goto error; } service = group_vals[GV_GROUP_CHECK].v; if (!rc_avpair_add(rh, &send, group_attrs[SA_SERVICE_TYPE].v, &service, -1, 0)) { LM_ERR("in adding SA_SERVICE_TYPE <%u>\n", service); goto error; } /* Add extra attributes */ extra_cnt = extra2strar(group_extra, _m, val_arr); if (extra_cnt == -1) { LM_ERR("in getting values of group extra attributes\n"); goto error; } offset = SA_STATIC_MAX; for (i = 0; i < extra_cnt; i++) { if (val_arr[i].len == -1) { /* Add integer attribute */ ADD_EXTRA_AVPAIR(group_attrs, offset+i, &(val_arr[i].s), val_arr[i].len ); } else { /* Add string attribute */ ADD_EXTRA_AVPAIR(group_attrs, offset+i, val_arr[i].s, val_arr[i].len ); } } if ((res = rc_auth(rh, 0, send, &received, msg)) == OK_RC) { LM_DBG("success\n"); rc_avpair_free(send); generate_avps(group_attrs, received); rc_avpair_free(received); return 1; } else { rc_avpair_free(send); rc_avpair_free(received); #ifdef REJECT_RC if (res == REJECT_RC) { LM_DBG("rejected\n"); return -1; } else { LM_ERR("failure\n"); return -2; } #else LM_DBG("failure\n"); return -1; #endif } error: rc_avpair_free(send); return -1; }