Пример #1
0
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;
}
Пример #2
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;
}
Пример #3
0
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;
}
Пример #4
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;
}
Пример #5
0
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;
}
Пример #6
0
/*
 *	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;
}
Пример #7
0
/*
 *	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;
	}
}
Пример #8
0
/** 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;
}
Пример #9
0
/* 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;
}
Пример #10
0
/*
 *	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);
}
Пример #11
0
/*
 * 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;
}
Пример #12
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;
}
Пример #13
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;
}
Пример #14
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;
}
Пример #15
0
/*
 *	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));
}
Пример #16
0
/*
	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;
}
Пример #17
0
/* 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;

}
Пример #18
0
/* 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;
}
Пример #19
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;
}
Пример #20
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;
	}
}
Пример #21
0
/** 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;
}
Пример #22
0
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;
}
Пример #23
0
/** 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;
}