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; }
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; }
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; }
VALUE_PAIR *paircreate_raw(int attr, int type, VALUE_PAIR *vp) { char *p = (char *) (vp + 1); if (!vp->flags.unknown_attr) { pairfree(&vp); return NULL; } vp->vendor = VENDOR(attr); vp->attribute = attr; vp->operator = T_OP_EQ; vp->name = p; vp->type = type; vp->length = 0; memset(&vp->flags, 0, sizeof(vp->flags)); vp->flags.unknown_attr = 1; if (!vp_print_name(p, FR_VP_NAME_LEN, vp->attribute)) { free(vp); return NULL; } return vp; }
const char *vp_print_name(char *buffer, size_t bufsize, int attr) { int vendor; size_t len = 0; if (!buffer) return NULL; vendor = VENDOR(attr); if (vendor) { DICT_VENDOR *v; v = dict_vendorbyvalue(vendor); if (v) { snprintf(buffer, bufsize, "%s-", v->name); } else { snprintf(buffer, bufsize, "Vendor-%u-", vendor); } len = strlen(buffer); if (len == bufsize) { return NULL; } } snprintf(buffer + len, bufsize - len, "Attr-%u", attr & 0xffff); len += strlen(buffer + len); if (len == bufsize) { return NULL; } return buffer; }
/* * Create a new valuepair. */ VALUE_PAIR *paircreate(int attr, int type) { VALUE_PAIR *vp; DICT_ATTR *da; da = dict_attrbyvalue(attr); if ((vp = pairalloc(da)) == NULL) { fr_strerror_printf("out of memory"); return NULL; } vp->operator = T_OP_EQ; /* * It isn't in the dictionary: update the name. */ if (!da) { char *p = (char *) (vp + 1); vp->vendor = VENDOR(attr); vp->attribute = attr; vp->name = p; vp->type = type; /* be forgiving */ if (!vp_print_name(p, FR_VP_NAME_LEN, vp->attribute)) { free(vp); return NULL; } } return vp; }
/* * Move one kind of attributes from one list to the other */ void pairmove2(VALUE_PAIR **to, VALUE_PAIR **from, int attr) { VALUE_PAIR *to_tail, *i, *next; VALUE_PAIR *iprev = NULL; /* * Find the last pair in the "to" list and put it in "to_tail". */ if (*to != NULL) { to_tail = *to; for(i = *to; i; i = i->next) to_tail = i; } else to_tail = NULL; for(i = *from; i; i = next) { next = i->next; /* * If the attribute to move is NOT a VSA, then it * ignores any attributes which do not match exactly. */ if ((attr != PW_VENDOR_SPECIFIC) && (i->attribute != attr)) { iprev = i; continue; } /* * If the attribute to move IS a VSA, then it ignores * any non-VSA attribute. */ if ((attr == PW_VENDOR_SPECIFIC) && (VENDOR(i->attribute) == 0)) { iprev = i; continue; } /* * Remove the attribute from the "from" list. */ if (iprev) iprev->next = next; else *from = next; /* * Add the attribute to the "to" list. */ if (to_tail) to_tail->next = i; else *to = i; to_tail = i; i->next = NULL; } }
/** Find the first attribute value-pair (which matches the given attribute) from the specified value-pair list * * @param vp a pointer to a #VALUE_PAIR structure. * @param attrid The attribute of the pair to find (e.g., %PW_USER_NAME). * @param vendorpec The vendor ID in case of a vendor specific value - 0 otherwise. * @return the value pair found. */ VALUE_PAIR *rc_avpair_get (VALUE_PAIR *vp, int attrid, int vendorpec) { for (; vp != NULL && !(ATTRID(vp->attribute) == ATTRID(attrid) && VENDOR(vp->attribute) == vendorpec); vp = vp->next) { continue; } return vp; }
/* 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; }
/* * Get an attribute by its numerical value. */ DICT_ATTR *dict_attrbyvalue(unsigned int attr) { DICT_ATTR dattr; if ((attr > 0) && (attr < 256)) return dict_base_attrs[attr]; dattr.attr = attr; dattr.vendor = VENDOR(attr); return fr_hash_table_finddata(attributes_byvalue, &dattr); }
/* * Generate AVPs from the database result */ static int generate_avps(VALUE_PAIR* received) { int_str name, val; VALUE_PAIR *vp; vp = rc_avpair_get(received, ATTRID(attrs[A_SER_UID].v), VENDOR(attrs[A_SER_UID].v)); if (vp == NULL) { WARN("RADIUS server did not send SER-UID attribute in digest authentication reply\n"); return -1; } val.s.len = vp->lvalue; val.s.s = vp->strvalue; name.s.s = "uid"; name.s.len = 3; if (add_avp(AVP_TRACK_FROM | AVP_CLASS_USER | AVP_NAME_STR | AVP_VAL_STR, name, val) < 0) { ERR("Unable to create UID attribute\n"); return -1; } vp = received; while ((vp = rc_avpair_get(vp, ATTRID(attrs[A_SER_ATTR].v), VENDOR(attrs[A_SER_ATTR].v)))) { attr_name_value(&name.s, &val.s, vp); if (name.s.len == 0) { ERR("Missing attribute name\n"); return -1; } if (add_avp(AVP_TRACK_FROM | AVP_CLASS_USER | AVP_NAME_STR | AVP_VAL_STR, name, val) < 0) { LOG(L_ERR, "generate_avps: Unable to create a new AVP\n"); return -1; } else { DBG("generate_avps: AVP '%.*s'='%.*s' has been added\n", name.s.len, ZSW(name.s.s), val.s.len, ZSW(val.s.s)); } vp = vp->next; } return 0; }
/* * 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; }
/* * Generate AVPs from the database result */ static int generate_avps(unsigned int flags, VALUE_PAIR* received) { int_str name, val; VALUE_PAIR *vp; vp = received; while ((vp = rc_avpair_get(vp, ATTRID(attrs[A_SER_ATTR].v), VENDOR(attrs[A_SER_ATTR].v)))) { attr_name_value(&name.s, &val.s, vp); if (name.s.len == 0) { ERR("Missing attribute name\n"); return -1; } if (add_avp(flags | AVP_NAME_STR | AVP_VAL_STR, name, val) < 0) { ERR("Unable to create a new SER attribute\n"); return -1; } vp = vp->next; } return 0; }
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; }
/* * Reply to the request. Also attach * reply attribute value pairs and any user message provided. */ int rad_send(RADIUS_PACKET *packet, const RADIUS_PACKET *original, const char *secret) { VALUE_PAIR *reply; struct sockaddr_in saremote; struct sockaddr_in *sa; const char *what; uint8_t ip_buffer[16]; if ((packet->code > 0) && (packet->code < 52)) { what = packet_codes[packet->code]; } else { what = "Reply"; } /* * First time through, allocate room for the packet */ if (!packet->data) { radius_packet_t *hdr; uint32_t lvalue; uint8_t *ptr, *length_ptr, *vsa_length_ptr; uint8_t digest[16]; int secretlen; int vendorcode, vendorpec; u_short total_length; int len, allowed; int msg_auth_offset = 0; /* * For simplicity in the following logic, we allow * the attributes to "overflow" the 4k maximum * RADIUS packet size, by one attribute. */ uint8_t data[MAX_PACKET_LEN + 256]; /* * Use memory on the stack, until we know how * large the packet will be. */ hdr = (radius_packet_t *) data; /* * Build standard header */ hdr->code = packet->code; hdr->id = packet->id; if ((packet->code == PW_ACCOUNTING_REQUEST) || (packet->code == PW_DISCONNECT_REQUEST)) { memset(hdr->vector, 0, AUTH_VECTOR_LEN); } else { memcpy(hdr->vector, packet->vector, AUTH_VECTOR_LEN); } DEBUG("Sending %s of id %d to %s:%d\n", what, packet->id, ip_ntoa((char *)ip_buffer, packet->dst_ipaddr), packet->dst_port); total_length = AUTH_HDR_LEN; /* * Load up the configuration values for the user */ ptr = hdr->data; vendorcode = 0; vendorpec = 0; vsa_length_ptr = NULL; for (reply = packet->vps; reply; reply = reply->next) { /* * Ignore non-wire attributes */ if ((VENDOR(reply->attribute) == 0) && ((reply->attribute & 0xFFFF) > 0xff)) { continue; } /* * Check that the packet is no more than * 4k in size, AFTER over-flowing the 4k * boundary. Note that the 'data' * buffer, above, is one attribute longer * than necessary, in order to permit * this overflow. */ if (total_length > MAX_PACKET_LEN) { librad_log("ERROR: Too many attributes for packet, result is larger than RFC maximum of 4k"); return -1; } /* * Do stuff for Message-Authenticator */ if (reply->attribute == PW_MESSAGE_AUTHENTICATOR) { /* * Set it to zero! */ reply->length = AUTH_VECTOR_LEN; memset(reply->strvalue, 0, AUTH_VECTOR_LEN); msg_auth_offset = total_length; } /* * Print out ONLY the attributes which * we're sending over the wire, and print * them out BEFORE they're encrypted. */ debug_pair(reply); /* * We have a different vendor. Re-set * the vendor codes. */ if (vendorcode != VENDOR(reply->attribute)) { vendorcode = 0; vendorpec = 0; vsa_length_ptr = NULL; } /* * If the Vendor-Specific attribute is getting * full, then create a new VSA attribute * * FIXME: Multiple VSA's per Vendor-Specific * SHOULD be configurable. When that's done, * the (1), below, can be changed to point to * a configuration variable which is set TRUE * if the NAS cannot understand multiple VSA's * per Vendor-Specific */ if ((1) || /* ALWAYS create a new Vendor-Specific */ (vsa_length_ptr && (reply->length + *vsa_length_ptr) >= MAX_STRING_LEN)) { vendorcode = 0; vendorpec = 0; vsa_length_ptr = NULL; } /* * Maybe we have the start of a set of * (possibly many) VSA attributes from * one vendor. Set a global VSA wrapper */ if ((vendorcode == 0) && ((vendorcode = VENDOR(reply->attribute)) != 0)) { vendorpec = dict_vendorpec(vendorcode); /* * This is a potentially bad error... * we can't find the vendor ID! */ if (vendorpec == 0) { /* FIXME: log an error */ continue; } /* * Build a VSA header. */ *ptr++ = PW_VENDOR_SPECIFIC; vsa_length_ptr = ptr; *ptr++ = 6; lvalue = htonl(vendorpec); memcpy(ptr, &lvalue, 4); ptr += 4; total_length += 6; } if (vendorpec == VENDORPEC_USR) { lvalue = htonl(reply->attribute & 0xFFFF); memcpy(ptr, &lvalue, 4); length_ptr = vsa_length_ptr; total_length += 4; *length_ptr += 4; ptr += 4; /* * Each USR attribute gets it's own * VSA wrapper, so we re-set the * vendor specific information. */ vendorcode = 0; vendorpec = 0; vsa_length_ptr = NULL; } else { /* * All other attributes are as * per the RFC spec. */ *ptr++ = (reply->attribute & 0xFF); length_ptr = ptr; if (vsa_length_ptr) *vsa_length_ptr += 2; *ptr++ = 2; total_length += 2; } switch(reply->type) { /* * Ascend binary attributes are * stored internally in binary form. */ case PW_TYPE_ABINARY: case PW_TYPE_STRING: case PW_TYPE_OCTETS: /* * FIXME: HACK for non-updated dictionaries. * REMOVE in a future release. */ if ((strcmp(reply->name, "Ascend-Send-Secret") == 0) || (strcmp(reply->name, "Ascend-Receive-Secret") == 0)) { reply->flags.encrypt = FLAG_ENCRYPT_ASCEND_SECRET; } if (reply->attribute == PW_USER_PASSWORD) { reply->flags.encrypt = FLAG_ENCRYPT_USER_PASSWORD; } /* * Encrypt the various password styles */ switch (reply->flags.encrypt) { default: break; case FLAG_ENCRYPT_USER_PASSWORD: rad_pwencode((char *)reply->strvalue, &(reply->length), (const char *)secret, (const char *)packet->vector); break; case FLAG_ENCRYPT_TUNNEL_PASSWORD: rad_tunnel_pwencode(reply->strvalue, &(reply->length), secret, packet->vector); break; case FLAG_ENCRYPT_ASCEND_SECRET: make_secret(digest, packet->vector, secret, reply->strvalue); memcpy(reply->strvalue, digest, AUTH_VECTOR_LEN ); reply->length = AUTH_VECTOR_LEN; } /* switch over encryption flags */ len = reply->length; /* * Set the TAG at the beginning * of the string if tagged. If * tag value is not valid for * tagged attribute, make it 0x00 * per RFC 2868. -cparker */ if (reply->flags.has_tag) { if (TAG_VALID(reply->flags.tag)) { len++; *ptr++ = reply->flags.tag; } else if (reply->flags.encrypt == FLAG_ENCRYPT_TUNNEL_PASSWORD) { /* * Tunnel passwords * REQUIRE a tag, * even if we don't * have a valid * tag. */ len++; *ptr++ = 0x00; } /* else don't write a tag */ } /* else the attribute doesn't have a tag */ /* * Ensure we don't go too far. * The 'length' of the attribute * may be 0..255, minus whatever * octets are used in the attribute * header. */ allowed = 255; if (vsa_length_ptr) { allowed -= *vsa_length_ptr; } else { allowed -= *length_ptr; } if (len > allowed) { len = allowed; } *length_ptr += len; if (vsa_length_ptr) *vsa_length_ptr += len; /* * If we have tagged attributes we can't assume that * len == reply->length. Use reply->length for copying * the string data into the packet. Use len for the * true length of the string+tags. */ memcpy(ptr, reply->strvalue, reply->length); ptr += reply->length; total_length += len; break; case PW_TYPE_INTEGER: case PW_TYPE_IPADDR: *length_ptr += 4; if (vsa_length_ptr) *vsa_length_ptr += 4; if (reply->type == PW_TYPE_INTEGER ) { /* If tagged, the tag becomes the MSB of the value */ if(reply->flags.has_tag) { /* Tag must be ( 0x01 -> 0x1F ) OR 0x00 */ if(!TAG_VALID(reply->flags.tag)) { reply->flags.tag = 0x00; } lvalue = htonl((reply->lvalue & 0xffffff) | ((reply->flags.tag & 0xff) << 24)); } else { lvalue = htonl(reply->lvalue); } } else { /* * IP address is already in * network byte order. */ lvalue = reply->lvalue; } memcpy(ptr, &lvalue, 4); ptr += 4; total_length += 4; break; /* * There are no tagged date attributes. */ case PW_TYPE_DATE: *length_ptr += 4; if (vsa_length_ptr) *vsa_length_ptr += 4; lvalue = htonl(reply->lvalue); memcpy(ptr, &lvalue, 4); ptr += 4; total_length += 4; break; default: break; } } /* done looping over all attributes */ /* * Fill in the rest of the fields, and copy * the data over from the local stack to * the newly allocated memory. * * Yes, all this 'memcpy' is slow, but it means * that we only allocate the minimum amount of * memory for a request. */ packet->data_len = total_length; packet->data = (uint8_t *) malloc(packet->data_len); if (!packet->data) { librad_log("Out of memory"); return -1; } memcpy(packet->data, data, packet->data_len); hdr = (radius_packet_t *) packet->data; total_length = htons(total_length); memcpy(hdr->length, &total_length, sizeof(u_short)); /* * If this is not an authentication request, we * need to calculate the md5 hash over the entire packet * and put it in the vector. */ secretlen = strlen(secret); if (packet->code != PW_AUTHENTICATION_REQUEST && packet->code != PW_STATUS_SERVER) { MD5_CTX context; /* * Set the Message-Authenticator attribute, * BEFORE setting the reply authentication vector * for CHALLENGE, ACCEPT and REJECT. */ if (msg_auth_offset) { uint8_t calc_auth_vector[AUTH_VECTOR_LEN]; switch (packet->code) { default: break; case PW_AUTHENTICATION_ACK: case PW_AUTHENTICATION_REJECT: case PW_ACCESS_CHALLENGE: if (original) { memcpy(hdr->vector, original->vector, AUTH_VECTOR_LEN); } break; } memset(packet->data + msg_auth_offset + 2, 0, AUTH_VECTOR_LEN); lrad_hmac_md5(packet->data, packet->data_len, secret, secretlen, calc_auth_vector); memcpy(packet->data + msg_auth_offset + 2, calc_auth_vector, AUTH_VECTOR_LEN); memcpy(hdr->vector, packet->vector, AUTH_VECTOR_LEN); } MD5Init(&context); MD5Update(&context, packet->data, packet->data_len); MD5Update(&context, secret, strlen(secret)); MD5Final(digest, &context); memcpy(hdr->vector, digest, AUTH_VECTOR_LEN); memcpy(packet->vector, digest, AUTH_VECTOR_LEN); } /* * Set the Message-Authenticator attribute, * AFTER setting the authentication vector * only for ACCESS-REQUESTS */ else if (msg_auth_offset) { uint8_t calc_auth_vector[AUTH_VECTOR_LEN]; switch (packet->code) { default: break; case PW_AUTHENTICATION_ACK: case PW_AUTHENTICATION_REJECT: case PW_ACCESS_CHALLENGE: if (original) { memcpy(hdr->vector, original->vector, AUTH_VECTOR_LEN); } break; } memset(packet->data + msg_auth_offset + 2, 0, AUTH_VECTOR_LEN); lrad_hmac_md5(packet->data, packet->data_len, secret, secretlen, calc_auth_vector); memcpy(packet->data + msg_auth_offset + 2, calc_auth_vector, AUTH_VECTOR_LEN); memcpy(hdr->vector, packet->vector, AUTH_VECTOR_LEN); } /* * If packet->data points to data, then we print out * the VP list again only for debugging. */ } else if (librad_debug) { DEBUG("Re-sending %s of id %d to %s:%d\n", what, packet->id, ip_ntoa((char *)ip_buffer, packet->dst_ipaddr), packet->dst_port); for (reply = packet->vps; reply; reply = reply->next) { /* FIXME: ignore attributes > 0xff */ debug_pair(reply); } } /* * And send it on it's way. */ sa = (struct sockaddr_in *) &saremote; memset ((char *) sa, '\0', sizeof (saremote)); sa->sin_family = AF_INET; sa->sin_addr.s_addr = packet->dst_ipaddr; sa->sin_port = htons(packet->dst_port); return sendto(packet->sockfd, packet->data, (int)packet->data_len, 0, (struct sockaddr *)&saremote, sizeof(struct sockaddr_in)); }
/* 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; }
/* TODO * when timeout mechanism will be available * rc_auth_function shall be called to try another * destination if the current one has timed out * */ int resume_send_auth(int fd, struct sip_msg *msg, void *param) { int res; map_list *mp; pv_value_t pvt; struct rad_ctx *rctx; VALUE_PAIR *recv = NULL, *vp = NULL; rctx = (struct rad_ctx *)param; if (rctx == NULL) { LM_ERR("no context given\n"); return -1; } res = rc_auth_resume(&rctx->ctx, &recv); if (res == OK_RC || res == REJECT_RC) { async_status = ASYNC_DONE; } else if (res == READBLOCK_RC) { async_status = ASYNC_CONTINUE; return 1; } else { LM_ERR("radius authentication message failed with %s\n", ((res==BADRESP_RC)?"BAD REPLY":"ERROR")); goto error; } for ( mp=sets[rctx->index2]->parsed; mp ; mp = mp->next) { vp = recv; while ( (vp=rc_avpair_get(vp, ATTRID(mp->value), VENDOR(mp->value)))!=NULL ) { memset(&pvt, 0, sizeof(pv_value_t)); if (vp->type == PW_TYPE_INTEGER) { pvt.flags = PV_VAL_INT|PV_TYPE_INT; pvt.ri = vp->lvalue; } else if (vp->type == PW_TYPE_STRING) { pvt.flags = PV_VAL_STR; pvt.rs.s = vp->strvalue; pvt.rs.len = vp->lvalue; } if (pv_set_value(msg, mp->pv, (int)EQ_T, &pvt) < 0) { LM_ERR("setting avp failed....skipping\n"); } vp = fetch_all_values ? vp->next : NULL; } } vp = recv; if (attr) for(; (vp = rc_avpair_get(vp, attr->value, 0)); vp = vp->next) extract_avp(vp); if ( res!=OK_RC && res!=REJECT_RC) goto error; if (rctx->send) rc_avpair_free(rctx->send); if (recv) rc_avpair_free(recv); pkg_free(rctx); return (res==OK_RC)?1:-2; error: pkg_free(rctx); if (rctx->send) rc_avpair_free(rctx->send); if (recv) rc_avpair_free(recv); return -1; }
/* create an array of str's for accounting using a formatting string; * this is the heart of the accounting module -- it prints whatever * requested in a way, that can be used for syslog, radius, * sql, whatsoever * tm sip_msg_clones does not clone (shmmem-zed) parsed fields, other then Via1,2. Such fields clone now or use from rq_rp */ static int fmt2rad(char *fmt, struct sip_msg *rq, str* ouri, struct hdr_field *to, unsigned int code, VALUE_PAIR** send, time_t req_time) /* Timestamp of the request */ { static unsigned int cseq_num, src_port, src_ip; static time_t rq_time, rs_time; int cnt; struct to_body* from, *pto; str val, *cr, *at; struct cseq_body *cseq; struct attr* attr; int dir; cnt = 0; dir = -2; /* we don't care about parsing here; either the function * was called from script, in which case the wrapping function * is supposed to parse, or from reply processing in which case * TM should have preparsed from REQUEST_IN callback. */ while(*fmt) { if (cnt == ALL_LOG_FMT_LEN) { LOG(L_ERR, "ERROR:acc:fmt2rad: Formatting string is too long\n"); return 0; } attr = 0; switch(*fmt) { case 'a': /* attr */ at = print_attrs(avps, avps_n, 0); if (at) { attr = &attrs[A_SER_ATTR]; val = *at; } break; case 'c': /* sip_callid */ if (rq->callid && rq->callid->body.len) { attr = &attrs[A_ACCT_SESSION_ID]; val = rq->callid->body; } break; case 'd': /* to_tag */ if (swap_dir && dir == -2) dir = get_direction(rq); if (dir <= 0) { if (to && (pto = (struct to_body*)(to->parsed)) && pto->tag_value.len) { attr = &attrs[A_SIP_TO_TAG]; val = pto->tag_value; } } else { if (rq->from && (from = get_from(rq)) && from->tag_value.len) { attr = &attrs[A_SIP_TO_TAG]; val = from->tag_value; } } break; case 'f': /* sip_from */ if (rq->from && rq->from->body.len) { attr = &attrs[A_SER_FROM]; val = rq->from->body; } break; case 'g': /* flags */ attr = &attrs[A_SER_FLAGS]; val.s = (char*)&rq->flags; val.len = sizeof(unsigned int); break; case 'i': /* inbound_ruri */ attr = &attrs[A_SER_ORIGINAL_REQUEST_ID]; val = rq->first_line.u.request.uri; break; case 'm': /* sip_method */ attr = &attrs[A_SIP_METHOD]; val = rq->first_line.u.request.method; break; case 'n': /* sip_cseq */ if (rq->cseq && (cseq = get_cseq(rq)) && cseq->number.len) { attr = &attrs[A_SIP_CSEQ]; str2int(&cseq->number, &cseq_num); val.s = (char*)&cseq_num; val.len = sizeof(unsigned int); } break; case 'o': /* outbound_ruri */ attr = &attrs[A_SIP_TRANSLATED_REQUEST_ID]; val = *ouri; break; case 'p': /* Source IP address */ attr = &attrs[A_SIP_SOURCE_IP_ADDRESS]; src_ip = ntohl(rq->rcv.src_ip.u.addr32[0]); val.s = (char*)&src_ip; val.len = sizeof(src_ip); break; case 'r': /* from_tag */ if (swap_dir && dir == -2) dir = get_direction(rq); if (dir <= 0) { if (rq->from && (from = get_from(rq)) && from->tag_value.len) { attr = &attrs[A_SIP_FROM_TAG]; val = from->tag_value; } } else { if (to && (pto = (struct to_body*)(to->parsed)) && pto->tag_value.len) { attr = &attrs[A_SIP_FROM_TAG]; val = pto->tag_value; } } break; case 's': /* server_id */ attr = &attrs[A_SER_SERVER_ID]; val.s = (char*)&server_id; val.len = sizeof(int); break; case 't': /* sip_to */ if (to && to->body.len) { attr = &attrs[A_SER_TO]; val = to->body; } break; case 'u': /* digest_username */ cr = cred_user(rq); if (cr) { attr = &attrs[A_SER_DIGEST_USERNAME]; val = *cr; } break; case 'x': /* request_timestamp */ attr = &attrs[A_SER_REQUEST_TIMESTAMP]; rq_time = req_time; val.s = (char*)&rq_time; val.len = sizeof(time_t); break; case 'D': /* to_did */ break; case 'F': /* from_uri */ if (swap_dir && dir == -2) dir = get_direction(rq); if (dir <= 0) { if (rq->from && (from = get_from(rq)) && from->uri.len) { attr = &attrs[A_CALLING_STATION_ID]; val = from->uri; } } else { if (rq->to && (pto = get_to(rq)) && pto->uri.len) { attr = &attrs[A_CALLING_STATION_ID]; val = pto->uri; } } break; case 'I': /* from_uid */ if (get_from_uid(&val, rq) < 0) { attr = &attrs[A_SER_FROM_UID]; } break; case 'M': /* from_did */ break; case 'P': /* Source port */ attr = &attrs[A_SIP_SOURCE_PORT]; src_port = rq->rcv.src_port; val.s = (char*)&src_port; val.len = sizeof(unsigned int); break; case 'R': /* digest_realm */ cr = cred_realm(rq); if (cr) { attr = &attrs[A_SER_DIGEST_REALM]; val = *cr; } break; case 'S': /* sip_status */ attr = &attrs[A_SIP_RESPONSE_CODE]; val.s = (char*)&code; val.len = sizeof(unsigned int); break; case 'T': /* to_uri */ if (swap_dir && dir == -2) dir = get_direction(rq); if (dir <= 0) { if (rq->to && (pto = get_to(rq)) && pto->uri.len) { attr = &attrs[A_CALLED_STATION_ID]; val = pto->uri; } } else { if (rq->from && (from = get_from(rq)) && from->uri.len) { attr = &attrs[A_CALLED_STATION_ID]; val = from->uri; } } break; case 'U': /* to_uid */ if (get_from_uid(&val, rq) < 0) { attr = &attrs[A_SER_TO_UID]; } break; case 'X': /* response_timestamp */ attr = &attrs[A_SER_RESPONSE_TIMESTAMP]; rs_time = time(0); val.s = (char*)&rs_time; val.len = sizeof(time_t); break; default: LOG(L_CRIT, "BUG:acc:fmt2rad: unknown char: %c\n", *fmt); return -1; } /* switch (*fmt) */ if (attr) { if (!rc_avpair_add(rh, send, ATTRID(attr->v), val.s, val.len, VENDOR(attr->v))) { LOG(L_ERR, "ERROR:acc:fmt2rad: Failed to add attribute %s\n", attr->n); return -1; } } fmt++; cnt++; } /* while (*fmt) */ 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(VALUE_PAIR** received, struct sip_msg* _msg, dig_cred_t* _cred, str* _method, str* _user) { static char msg[4096]; VALUE_PAIR *send; UINT4 service, ser_service_type; str method, user, user_name; str *ruri; int i; send = 0; if (!(_cred && _method && _user)) { 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, ATTRID(attrs[A_USER_NAME].v), _cred->username.whole.s, _cred->username.whole.len, VENDOR(attrs[A_USER_NAME].v))) { LOG(L_ERR, "radius_authorize_sterman(): 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) { 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, ATTRID(attrs[A_USER_NAME].v), user_name.s, user_name.len, VENDOR(attrs[A_USER_NAME].v))) { LOG(L_ERR, "sterman(): 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, ATTRID(attrs[A_DIGEST_USER_NAME].v), _cred->username.whole.s, _cred->username.whole.len, VENDOR(attrs[A_DIGEST_USER_NAME].v))) { LOG(L_ERR, "sterman(): Unable to add Digest-User-Name attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_REALM].v), _cred->realm.s, _cred->realm.len, VENDOR(attrs[A_DIGEST_REALM].v))) { LOG(L_ERR, "sterman(): Unable to add Digest-Realm attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_NONCE].v), _cred->nonce.s, _cred->nonce.len, VENDOR(attrs[A_DIGEST_NONCE].v))) { LOG(L_ERR, "sterman(): 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, ATTRID(attrs[A_DIGEST_URI].v), ruri->s, ruri->len, VENDOR(attrs[A_DIGEST_URI].v))) { LOG(L_ERR, "sterman(): Unable to add Digest-URI attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_METHOD].v), method.s, method.len, VENDOR(attrs[A_DIGEST_METHOD].v))) { LOG(L_ERR, "sterman(): 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, ATTRID(attrs[A_DIGEST_QOP].v), "auth", 4, VENDOR(attrs[A_DIGEST_QOP].v))) { LOG(L_ERR, "sterman(): Unable to add Digest-QOP attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_NONCE_COUNT].v), _cred->nc.s, _cred->nc.len, VENDOR(attrs[A_DIGEST_NONCE_COUNT].v))) { LOG(L_ERR, "sterman(): Unable to add Digest-CNonce-Count attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_CNONCE].v), _cred->cnonce.s, _cred->cnonce.len, VENDOR(attrs[A_DIGEST_CNONCE].v))) { LOG(L_ERR, "sterman(): Unable to add Digest-CNonce attribute\n"); goto err; } } else if (_cred->qop.qop_parsed == QOP_AUTHINT) { if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_QOP].v), "auth-int", 8, VENDOR(attrs[A_DIGEST_QOP].v))) { LOG(L_ERR, "sterman(): Unable to add Digest-QOP attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_NONCE_COUNT].v), _cred->nc.s, _cred->nc.len, VENDOR(attrs[A_DIGEST_NONCE_COUNT].v))) { LOG(L_ERR, "sterman(): Unable to add Digest-Nonce-Count attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_CNONCE].v), _cred->cnonce.s, _cred->cnonce.len, VENDOR(attrs[A_DIGEST_CNONCE].v))) { LOG(L_ERR, "sterman(): Unable to add Digest-CNonce attribute\n"); goto err; } if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_DIGEST_BODY_DIGEST].v), _cred->opaque.s, _cred->opaque.len, VENDOR(attrs[A_DIGEST_BODY_DIGEST].v))) { LOG(L_ERR, "sterman(): 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, ATTRID(attrs[A_DIGEST_RESPONSE].v), _cred->response.s, _cred->response.len, VENDOR(attrs[A_DIGEST_RESPONSE].v))) { LOG(L_ERR, "sterman(): 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, ATTRID(attrs[A_SERVICE_TYPE].v), &service, -1, VENDOR(attrs[A_SERVICE_TYPE].v))) { LOG(L_ERR, "sterman(): Unable to add Service-Type attribute\n"); goto err; } /* Indicate the service type, Authenticate only in our case */ ser_service_type = vals[V_DIGEST_AUTHENTICATION].v; if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SER_SERVICE_TYPE].v), &ser_service_type, -1, VENDOR(attrs[A_SER_SERVICE_TYPE].v))) { LOG(L_ERR, "sterman(): Unable to add SER-Service-Type attribute\n"); goto err; } /* Add SIP URI as a check item */ if (!rc_avpair_add(rh, &send, ATTRID(attrs[A_SER_URI_USER].v), user.s, user.len, VENDOR(attrs[A_SER_URI_USER].v))) { LOG(L_ERR, "sterman(): 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; } } /* Send request */ if ((i = rc_auth(rh, SIP_PORT, send, received, msg)) == OK_RC) { DBG("radius_authorize_sterman(): Success\n"); rc_avpair_free(send); send = 0; return 1; } else { DBG("radius_authorize_sterman(): Failure\n"); goto err; } err: if (send) 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(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; } }
/** Packs an attribute value pair list into a buffer * * @param vp a pointer to a VALUE_PAIR. * @param secret the secret used by the server. * @param auth a pointer to AUTH_HDR. * @return The number of octets packed. */ static int rc_pack_list(VALUE_PAIR * vp, char *secret, AUTH_HDR * auth) { int length, i, pc, padded_length; int total_length = 0; size_t secretlen; uint32_t lvalue, vendor; unsigned char passbuf[MAX(AUTH_PASS_LEN, CHAP_VALUE_LENGTH)]; unsigned char md5buf[256]; unsigned char *buf, *vector, *vsa_length_ptr; buf = auth->data; while (vp != NULL) { vsa_length_ptr = NULL; if (VENDOR(vp->attribute) != 0) { *buf++ = PW_VENDOR_SPECIFIC; vsa_length_ptr = buf; *buf++ = 6; vendor = htonl(VENDOR(vp->attribute)); memcpy(buf, &vendor, sizeof(uint32_t)); buf += 4; total_length += 6; } *buf++ = (vp->attribute & 0xff); switch (vp->attribute) { case PW_USER_PASSWORD: /* Encrypt the password */ /* Chop off password at AUTH_PASS_LEN */ length = vp->lvalue; if (length > AUTH_PASS_LEN) length = AUTH_PASS_LEN; /* Calculate the padded length */ padded_length = (length + (AUTH_VECTOR_LEN - 1)) & ~(AUTH_VECTOR_LEN - 1); /* Record the attribute length */ *buf++ = padded_length + 2; if (vsa_length_ptr != NULL) *vsa_length_ptr += padded_length + 2; /* Pad the password with zeros */ memset((char *)passbuf, '\0', AUTH_PASS_LEN); memcpy((char *)passbuf, vp->strvalue, (size_t) length); secretlen = strlen(secret); vector = (unsigned char *)auth->vector; for (i = 0; i < padded_length; i += AUTH_VECTOR_LEN) { /* Calculate the MD5 digest */ strcpy((char *)md5buf, secret); memcpy((char *)md5buf + secretlen, vector, AUTH_VECTOR_LEN); rc_md5_calc(buf, md5buf, secretlen + AUTH_VECTOR_LEN); /* Remeber the start of the digest */ vector = buf; /* Xor the password into the MD5 digest */ for (pc = i; pc < (i + AUTH_VECTOR_LEN); pc++) { *buf++ ^= passbuf[pc]; } } total_length += padded_length + 2; break; default: switch (vp->type) { case PW_TYPE_STRING: length = vp->lvalue; *buf++ = length + 2; if (vsa_length_ptr != NULL) *vsa_length_ptr += length + 2; memcpy(buf, vp->strvalue, (size_t) length); buf += length; total_length += length + 2; break; case PW_TYPE_IPV6ADDR: length = 16; *buf++ = length + 2; if (vsa_length_ptr != NULL) *vsa_length_ptr += length + 2; memcpy(buf, vp->strvalue, (size_t) length); buf += length; total_length += length + 2; break; case PW_TYPE_IPV6PREFIX: length = vp->lvalue; *buf++ = length + 2; if (vsa_length_ptr != NULL) *vsa_length_ptr += length + 2; memcpy(buf, vp->strvalue, (size_t) length); buf += length; total_length += length + 2; break; case PW_TYPE_INTEGER: case PW_TYPE_IPADDR: case PW_TYPE_DATE: *buf++ = sizeof(uint32_t) + 2; if (vsa_length_ptr != NULL) *vsa_length_ptr += sizeof(uint32_t) + 2; lvalue = htonl(vp->lvalue); memcpy(buf, (char *)&lvalue, sizeof(uint32_t)); buf += sizeof(uint32_t); total_length += sizeof(uint32_t) + 2; break; default: break; } break; } vp = vp->next; } return total_length; }
int send_auth_func(struct sip_msg* msg, str* s1, str* s2) { int i, res; int index1 = -1, index2 = -1; map_list *mp; pv_value_t pvt; char mess[1024]; VALUE_PAIR *send = NULL, *recv = NULL, *vp = NULL; if (!rh) { if (init_radius_handle()) { LM_ERR("invalid radius handle\n"); return -1; } } for (i = 0; i < set_size; i++) { if (sets[i]->set_name.len == s1->len && !strncmp(sets[i]->set_name.s, s1->s, s1->len)) index1 = i; if (sets[i]->set_name.len == s2->len && !strncmp(sets[i]->set_name.s, s2->s, s2->len)) index2 = i; } if (index1 == -1) { LM_ERR("the first set was not found\n"); return -1; } if (index2 == -1) { LM_ERR("the second set was not found\n"); return -1; } if (make_send_message(msg, index1, &send) < 0) { LM_ERR("make message failed\n"); return -1; } res = rc_auth(rh, SIP_PORT, send, &recv, mess); if (res!=OK_RC && res!=BADRESP_RC) { LM_ERR("radius authentication message failed with %s\n", (res==TIMEOUT_RC)?"TIMEOUT":"ERROR"); }else{ LM_DBG("radius authentication message sent\n"); } for ( mp=sets[index2]->parsed; mp ; mp = mp->next) { vp = recv; while ( (vp=rc_avpair_get(vp, ATTRID(mp->value), VENDOR(mp->value)))!=NULL ) { memset(&pvt, 0, sizeof(pv_value_t)); if (vp->type == PW_TYPE_INTEGER) { pvt.flags = PV_VAL_INT|PV_TYPE_INT; pvt.ri = vp->lvalue; } else if (vp->type == PW_TYPE_STRING) { pvt.flags = PV_VAL_STR; pvt.rs.s = vp->strvalue; pvt.rs.len = vp->lvalue; } if (pv_set_value(msg, mp->pv, (int)EQ_T, &pvt) < 0) { LM_ERR("setting avp failed....skipping\n"); } vp = fetch_all_values ? vp->next : NULL; } } vp = recv; if (attr) for(; (vp = rc_avpair_get(vp, attr->value, 0)); vp = vp->next) extract_avp(vp); if ( res!=OK_RC && res!=BADRESP_RC) goto error; if (send) rc_avpair_free(send); if (recv) rc_avpair_free(recv); return (res==OK_RC)?1:-2; error: if (send) rc_avpair_free(send); if (recv) rc_avpair_free(recv); return -1; }
/** Takes attribute/value pairs from buffer and builds a value_pair list using allocated memory * * @note Uses recursion. * * @param rh a handle to parsed configuration. * @param pair a pointer to a #VALUE_PAIR structure. * @param ptr the value (e.g., the actual username). * @param length the length of ptr, or -1 if to calculate (in case of strings). * @param vendorpec The vendor ID in case of a vendor specific value - 0 otherwise. * @return value_pair list or %NULL on failure. */ VALUE_PAIR *rc_avpair_gen(rc_handle const *rh, VALUE_PAIR *pair, unsigned char const *ptr, int length, int vendorpec) { int attribute, attrlen, x_len; unsigned char const *x_ptr; uint32_t lvalue; DICT_ATTR *attr; VALUE_PAIR *rpair; char buffer[(AUTH_STRING_LEN * 2) + 1]; /* For hex string conversion. */ char hex[3]; if (length < 2) { rc_log(LOG_ERR, "rc_avpair_gen: received attribute with " "invalid length"); goto shithappens; } attrlen = ptr[1]; if (length < attrlen || attrlen < 2) { rc_log(LOG_ERR, "rc_avpair_gen: received attribute with " "invalid length"); goto shithappens; } /* Advance to the next attribute and process recursively */ if (length != attrlen) { pair = rc_avpair_gen(rh, pair, ptr + attrlen, length - attrlen, vendorpec); if (pair == NULL) return NULL; } /* Actual processing */ attribute = ptr[0] | (vendorpec << 16); ptr += 2; attrlen -= 2; /* VSA */ if (attribute == PW_VENDOR_SPECIFIC) { if (attrlen < 4) { rc_log(LOG_ERR, "rc_avpair_gen: received VSA " "attribute with invalid length"); goto skipit; } memcpy(&lvalue, ptr, 4); vendorpec = ntohl(lvalue); if (rc_dict_getvend(rh, vendorpec) == NULL) { /* Warn and skip over the unknown VSA */ rc_log(LOG_WARNING, "rc_avpair_gen: received VSA " "attribute with unknown Vendor-Id %d", vendorpec); goto skipit; } /* Process recursively */ return rc_avpair_gen(rh, pair, ptr + 4, attrlen - 4, vendorpec); } /* Normal */ attr = rc_dict_getattr(rh, attribute); if (attr == NULL) { buffer[0] = '\0'; /* Initial length. */ x_ptr = ptr; for (x_len = attrlen; x_len > 0; x_len--, x_ptr++) { snprintf(hex, sizeof(hex), "%2.2X", x_ptr[0]); strcat(buffer, hex); } if (vendorpec == 0) { rc_log(LOG_WARNING, "rc_avpair_gen: received " "unknown attribute %d of length %d: 0x%s", attribute, attrlen + 2, buffer); } else { rc_log(LOG_WARNING, "rc_avpair_gen: received " "unknown VSA attribute %d, vendor %d of " "length %d: 0x%s", attribute & 0xffff, VENDOR(attribute), attrlen + 2, buffer); } goto skipit; } rpair = malloc(sizeof(*rpair)); if (rpair == NULL) { rc_log(LOG_CRIT, "rc_avpair_gen: out of memory"); goto shithappens; } memset(rpair, '\0', sizeof(*rpair)); /* Insert this new pair at the beginning of the list */ rpair->next = pair; pair = rpair; strcpy(pair->name, attr->name); pair->attribute = attr->value; pair->type = attr->type; switch (attr->type) { case PW_TYPE_STRING: memcpy(pair->strvalue, (char *)ptr, (size_t)attrlen); pair->strvalue[attrlen] = '\0'; pair->lvalue = attrlen; break; case PW_TYPE_INTEGER: if (attrlen != 4) { rc_log(LOG_ERR, "rc_avpair_gen: received INT " "attribute with invalid length"); goto skipit; } case PW_TYPE_IPADDR: if (attrlen != 4) { rc_log(LOG_ERR, "rc_avpair_gen: received IPADDR" " attribute with invalid length"); goto skipit; } memcpy((char *)&lvalue, (char *)ptr, 4); pair->lvalue = ntohl(lvalue); break; case PW_TYPE_IPV6ADDR: if (attrlen != 16) { rc_log(LOG_ERR, "rc_avpair_gen: received IPV6ADDR" " attribute with invalid length"); goto skipit; } memcpy(pair->strvalue, (char *)ptr, 16); pair->lvalue = attrlen; break; case PW_TYPE_IPV6PREFIX: if (attrlen > 18 || attrlen < 2) { rc_log(LOG_ERR, "rc_avpair_gen: received IPV6PREFIX" " attribute with invalid length: %d", attrlen); goto skipit; } memcpy(pair->strvalue, (char *)ptr, attrlen); pair->lvalue = attrlen; break; case PW_TYPE_DATE: if (attrlen != 4) { rc_log(LOG_ERR, "rc_avpair_gen: received DATE " "attribute with invalid length"); goto skipit; } default: rc_log(LOG_WARNING, "rc_avpair_gen: %s has unknown type", attr->name); goto skipit; } skipit: return pair; shithappens: while (pair != NULL) { rpair = pair->next; free(pair); pair = rpair; } return NULL; }