Example #1
0
/*
 *  	get the vps and put them in perl hash
 *  	If one VP have multiple values it is added as array_ref
 *  	Example for this is Cisco-AVPair that holds multiple values.
 *  	Which will be available as array_ref in $RAD_REQUEST{'Cisco-AVPair'}
 */
static void perl_store_vps(VALUE_PAIR *vp, HV *rad_hv)
{
        VALUE_PAIR	*nvp, *vpa, *vpn;
	AV		*av;
	char		namebuf[256], *name;
	char            buffer[1024];
	int		attr, vendor, len;

	hv_undef(rad_hv);
	nvp = paircopy(vp);

	while (nvp != NULL) {
		name = nvp->name;
		attr = nvp->attribute;
		vendor = nvp->vendor;
		vpa = paircopy2(nvp, attr, vendor);

		if (vpa->next) {
			av = newAV();
			vpn = vpa;
			while (vpn) {
				len = vp_prints_value(buffer, sizeof(buffer),
						vpn, FALSE);
				av_push(av, newSVpv(buffer, len));
				vpn = vpn->next;
			}
			hv_store(rad_hv, nvp->name, strlen(nvp->name),
					newRV_noinc((SV *) av), 0);
		} else {
			if ((vpa->flags.has_tag) &&
			    (vpa->flags.tag != 0)) {
				snprintf(namebuf, sizeof(namebuf), "%s:%d",
					 nvp->name, nvp->flags.tag);
				name = namebuf;
			}

			len = vp_prints_value(buffer, sizeof(buffer),
					      vpa, FALSE);
			hv_store(rad_hv, name, strlen(name),
				 newSVpv(buffer, len), 0);
		}

		pairfree(&vpa);
		vpa = nvp; while ((vpa != NULL) && (vpa->attribute == attr) && (vpa->vendor == vendor))
			vpa = vpa->next;
		pairdelete(&nvp, attr, vendor);
		nvp = vpa;
	}
}
Example #2
0
/** Copy pairs matching a VPT in the current request
 *
 * @param out where to write the copied vps.
 * @param request current request.
 * @param vpt the value pair template
 * @return -1 if VP could not be found, -2 if list could not be found, -3 if context could not be found.
 */
int radius_vpt_copy_vp(VALUE_PAIR **out, REQUEST *request, value_pair_tmpl_t const *vpt)
{
	VALUE_PAIR **vps, *vp;
	REQUEST *current = request;

	if (out) *out = NULL;

	if (radius_request(&current, vpt->request) < 0) {
		return -3;
	}

	vps = radius_list(request, vpt->list);
	if (!vps) {
		return -2;
	}

	switch (vpt->type) {
	/*
	 *	May not may not be found, but it *is* a known name.
	 */
	case VPT_TYPE_ATTR:
		vp = paircopy2(request, *vps, vpt->da->attr, vpt->da->vendor, TAG_ANY);
		if (!vp) {
			return -1;
		}
		break;

	case VPT_TYPE_LIST:
		vp = paircopy(request, *vps);

		break;

	default:
		/*
		 *	literal, xlat, regex, exec, data.
		 *	no attribute.
		 */
		return -1;
	}

	if (out) {
		*out = vp;
	}

	return 0;
}
Example #3
0
/*
 *  	get the vps and put them in perl hash
 *  	If one VP have multiple values it is added as array_ref
 *  	Example for this is Cisco-AVPair that holds multiple values.
 *  	Which will be available as array_ref in $RAD_REQUEST{'Cisco-AVPair'}
 */
static void perl_store_vps(VALUE_PAIR *vp, HV *rad_hv)
{
        VALUE_PAIR	*nvp, *vpa, *vpn;
	AV		*av;
	char            buffer[1024];
	int		attr, len;

	hv_undef(rad_hv);
	nvp = paircopy(vp);

	while (nvp != NULL) {
		attr = nvp->attribute;
		vpa = paircopy2(nvp,attr);
		if (vpa->next) {
			av = newAV();
			vpn = vpa;
			while (vpn) {
				len = vp_prints_value(buffer, sizeof(buffer),
						vpn, FALSE);
				av_push(av, newSVpv(buffer, len));
				vpn = vpn->next;
			}
			hv_store(rad_hv, nvp->name, strlen(nvp->name),
					newRV_noinc((SV *) av), 0);
		} else {
			len = vp_prints_value(buffer, sizeof(buffer),
					vpa, FALSE);
			hv_store(rad_hv, vpa->name, strlen(vpa->name),
					newSVpv(buffer, len), 0);
		}

		pairfree(&vpa);
		vpa = nvp; while ((vpa != NULL) && (vpa->attribute == attr))
			vpa = vpa->next;
		pairdelete(&nvp, attr);
		nvp = vpa;
	}
}
static int respond_eap_md5(RADIUS_PACKET *req,
			   RADIUS_PACKET *rep)
{
	VALUE_PAIR *vp, *id, *state;
	size_t valuesize;
	uint8_t identifier;
	uint8_t const *value;
	FR_MD5_CTX	context;
	uint8_t    response[16];

	cleanresp(rep);

	if ((state = paircopy2(NULL, req->vps, PW_STATE, 0, TAG_ANY)) == NULL)
	{
		fprintf(stderr, "radeapclient: no state attribute found\n");
		return 0;
	}

	if ((id = paircopy2(NULL, req->vps, ATTRIBUTE_EAP_ID, 0, TAG_ANY)) == NULL)
	{
		fprintf(stderr, "radeapclient: no EAP-ID attribute found\n");
		return 0;
	}
	identifier = id->vp_integer;

	if ((vp = pairfind(req->vps, ATTRIBUTE_EAP_BASE+PW_EAP_MD5, 0, TAG_ANY)) == NULL)
	{
		fprintf(stderr, "radeapclient: no EAP-MD5 attribute found\n");
		return 0;
	}

	/* got the details of the MD5 challenge */
	valuesize = vp->vp_octets[0];
	value = &vp->vp_octets[1];

	/* sanitize items */
	if(valuesize > vp->length)
	{
		fprintf(stderr, "radeapclient: md5 valuesize if too big (%u > %u)\n",
			(unsigned int) valuesize, (unsigned int) vp->length);
		return 0;
	}

	/* now do the CHAP operation ourself, rather than build the
	 * buffer. We could also call rad_chap_encode, but it wants
	 * a CHAP-Challenge, which we don't want to bother with.
	 */
	fr_md5_init(&context);
	fr_md5_update(&context, &identifier, 1);
	fr_md5_update(&context, (uint8_t *) password, strlen(password));
	fr_md5_update(&context, value, valuesize);
	fr_md5_final(response, &context);

	{
		uint8_t *p;
		uint8_t lg_response;

		vp = paircreate(rep, ATTRIBUTE_EAP_BASE+PW_EAP_MD5, 0);
		vp->length = 17;

		p = talloc_zero_array(vp, uint8_t, 17);
		lg_response = 16;
		memcpy(p, &lg_response, 1);
		memcpy(p + 1, response, 16);
		pairmemsteal(vp, p);
	}
	pairreplace(&(rep->vps), vp);

	pairreplace(&(rep->vps), id);

	/* copy the state object in */
	pairreplace(&(rep->vps), state);

	return 1;
}
/*
 * this code runs the EAP-SIM client state machine.
 * the *request* is from the server.
 * the *reponse* is to the server.
 *
 */
static int respond_eap_sim(RADIUS_PACKET *req,
			   RADIUS_PACKET *resp)
{
	enum eapsim_clientstates state, newstate;
	enum eapsim_subtype subtype;
	VALUE_PAIR *vp, *statevp, *radstate, *eapid;
	char statenamebuf[32], subtypenamebuf[32];

	if ((radstate = paircopy2(NULL, req->vps, PW_STATE, 0, TAG_ANY)) == NULL)
	{
		return 0;
	}

	if ((eapid = paircopy2(NULL, req->vps, ATTRIBUTE_EAP_ID, 0, TAG_ANY)) == NULL)
	{
		return 0;
	}

	/* first, dig up the state from the request packet, setting
	 * outselves to be in EAP-SIM-Start state if there is none.
	 */

	if((statevp = pairfind(resp->vps, ATTRIBUTE_EAP_SIM_STATE, 0, TAG_ANY)) == NULL)
	{
		/* must be initial request */
		statevp = paircreate(resp, ATTRIBUTE_EAP_SIM_STATE, 0);
		statevp->vp_integer = eapsim_client_init;
		pairreplace(&(resp->vps), statevp);
	}
	state = statevp->vp_integer;

	/*
	 * map the attributes, and authenticate them.
	 */
	unmap_eapsim_types(req);

	if((vp = pairfind(req->vps, ATTRIBUTE_EAP_SIM_SUBTYPE, 0, TAG_ANY)) == NULL)
	{
		return 0;
	}
	subtype = vp->vp_integer;

	/*
	 * look for the appropriate state, and process incoming message
	 */
	switch(state) {
	case eapsim_client_init:
		switch(subtype) {
		case eapsim_start:
			newstate = process_eap_start(req, resp);
			break;

		case eapsim_challenge:
		case eapsim_notification:
		case eapsim_reauth:
		default:
			fprintf(stderr, "radeapclient: sim in state %s message %s is illegal. Reply dropped.\n",
				sim_state2name(state, statenamebuf, sizeof(statenamebuf)),
				sim_subtype2name(subtype, subtypenamebuf, sizeof(subtypenamebuf)));
			/* invalid state, drop message */
			return 0;
		}
		break;

	case eapsim_client_start:
		switch(subtype) {
		case eapsim_start:
			/* NOT SURE ABOUT THIS ONE, retransmit, I guess */
			newstate = process_eap_start(req, resp);
			break;

		case eapsim_challenge:
			newstate = process_eap_challenge(req, resp);
			break;

		default:
			fprintf(stderr, "radeapclient: sim in state %s message %s is illegal. Reply dropped.\n",
				sim_state2name(state, statenamebuf, sizeof(statenamebuf)),
				sim_subtype2name(subtype, subtypenamebuf, sizeof(subtypenamebuf)));
			/* invalid state, drop message */
			return 0;
		}
		break;


	default:
		fprintf(stderr, "radeapclient: sim in illegal state %s\n",
			sim_state2name(state, statenamebuf, sizeof(statenamebuf)));
		return 0;
	}

	/* copy the eap state object in */
	pairreplace(&(resp->vps), eapid);

	/* update stete info, and send new packet */
	map_eapsim_types(resp);

	/* copy the radius state object in */
	pairreplace(&(resp->vps), radstate);

	statevp->vp_integer = newstate;
	return 1;
}
/*
 *  	get the vps and put them in perl hash
 *  	If one VP have multiple values it is added as array_ref
 *  	Example for this is Cisco-AVPair that holds multiple values.
 *  	Which will be available as array_ref in $RAD_REQUEST{'Cisco-AVPair'}
 */
static void perl_store_vps(VALUE_PAIR *vp, HV *rad_hv)
{
	VALUE_PAIR *nvp, *vpa, *vpn;
	AV *av;
	const char *name;
	char namebuf[256];
	char buffer[1024];
	int len;

	hv_undef(rad_hv);
	
	/*
	 *	Copy the valuepair list so we can remove attributes we've
	 *	already processed.
	 */
	nvp = paircopy(vp);

	while (nvp != NULL) {
		/*
		 *	Tagged attributes are added to the hash with name 
		 *	<attribute>:<tag>, others just use the normal attribute
		 *	name as the key.
		 */
		if (nvp->flags.has_tag && (nvp->flags.tag != 0)) {
			snprintf(namebuf, sizeof(namebuf), "%s:%d",
			         nvp->name, nvp->flags.tag);
			name = namebuf;
		} else {
			name = nvp->name;
		}

		/*
		 *	Create a new list with all the attributes like this one
		 *	which are in the same tag group.
		 */
		vpa = paircopy2(nvp, nvp->attribute, nvp->vendor, nvp->flags.tag);

		/*
		 *	Attribute has multiple values
		 */
		if (vpa->next) {
			av = newAV();
			for (vpn = vpa; vpn; vpn = vpn->next) {
				len = vp_prints_value(buffer, sizeof(buffer), vpn, FALSE);
				av_push(av, newSVpv(buffer, len));
			}
			(void)hv_store(rad_hv, name, strlen(name), newRV_noinc((SV *)av), 0);
		
		/*
		 *	Attribute has a single value, so its value just gets
		 *	added to the hash.
		 */
		} else {
			len = vp_prints_value(buffer, sizeof(buffer), vpa, FALSE);
			(void)hv_store(rad_hv, name, strlen(name), newSVpv(buffer, len), 0);
		}

		pairfree(&vpa);
		
		/*
		 *	Find the next attribute which we won't have processed,
		 *	we need to do this so we know it won't be freed on
		 *	pairdelete.
		 */		
		vpa = nvp->next;
		
		while ((vpa != NULL) &&
		       (vpa->attribute == nvp->attribute) &&
		       (vpa->vendor == nvp->vendor) &&
		       (vpa->flags.tag == nvp->flags.tag)) {
			vpa = vpa->next;
		}
		
		/*
		 *	Finally remove all the VPs we processed from our copy
		 *	of the list.
		 */
		pairdelete(&nvp, nvp->attribute, nvp->vendor, nvp->flags.tag);
		
		nvp = vpa;
	}
}
Example #7
0
int eaptls_success(EAP_HANDLER *handler, int peap_flag)
{
	EAPTLS_PACKET	reply;
	VALUE_PAIR *vp, *vps = NULL;
	REQUEST *request = handler->request;
	tls_session_t *tls_session = handler->opaque;

	reply.code = EAPTLS_SUCCESS;
	reply.length = TLS_HEADER_LEN;
	reply.flags = peap_flag;
	reply.data = NULL;
	reply.dlen = 0;

	/*
	 *	If there's no session resumption, delete the entry
	 *	from the cache.  This means either it's disabled
	 *	globally for this SSL context, OR we were told to
	 *	disable it for this user.
	 *
	 *	This also means you can't turn it on just for one
	 *	user.
	 */
	if ((!tls_session->allow_session_resumption) ||
	    (((vp = pairfind(request->config_items, 1127)) != NULL) &&
	     (vp->vp_integer == 0))) {
		SSL_CTX_remove_session(tls_session->ctx,
				       tls_session->ssl->session);
		tls_session->allow_session_resumption = 0;

		/*
		 *	If we're in a resumed session and it's
		 *	not allowed, 
		 */
		if (SSL_session_reused(tls_session->ssl)) {
			RDEBUG("FAIL: Forcibly stopping session resumption as it is not allowed.");
			return eaptls_fail(handler, peap_flag);
		}
		
		/*
		 *	Else resumption IS allowed, so we store the
		 *	user data in the cache.
		 */
	} else if (!SSL_session_reused(tls_session->ssl)) {
		RDEBUG2("Saving response in the cache");
		
		vp = paircopy2(request->reply->vps, PW_USER_NAME);
		pairadd(&vps, vp);
		
		vp = paircopy2(request->packet->vps, PW_STRIPPED_USER_NAME);
		pairadd(&vps, vp);
		
		if (vps) {
			SSL_SESSION_set_ex_data(tls_session->ssl->session,
						eaptls_session_idx, vps);
		} else {
			RDEBUG2("WARNING: No information to cache: session caching will be disabled for this session.");
			SSL_CTX_remove_session(tls_session->ctx,
					       tls_session->ssl->session);
		}

		/*
		 *	Else the session WAS allowed.  Copy the cached
		 *	reply.
		 */
	} else {
	       
		vp = SSL_SESSION_get_ex_data(tls_session->ssl->session,
					     eaptls_session_idx);
		if (!vp) {
			RDEBUG("WARNING: No information in cached session!");
			return eaptls_fail(handler, peap_flag);
		} else {
			RDEBUG("Adding cached attributes to the reply:");
			debug_pair_list(vp);
			pairadd(&request->reply->vps, paircopy(vp));

			/*
			 *	Mark the request as resumed.
			 */
			vp = pairmake("EAP-Session-Resumed", "1", T_OP_SET);
			if (vp) pairadd(&request->packet->vps, vp);
		}
	}

	/*
	 *	Call compose AFTER checking for cached data.
	 */
	eaptls_compose(handler->eap_ds, &reply);

	/*
	 *	Automatically generate MPPE keying material.
	 */
	if (tls_session->prf_label) {
		eaptls_gen_mppe_keys(&handler->request->reply->vps,
				     tls_session->ssl, tls_session->prf_label);
	} else {
		RDEBUG("WARNING: Not adding MPPE keys because there is no PRF label");
	}

	return 1;
}
Example #8
0
/** Convert a map to a VALUE_PAIR.
 *
 * @param[out] out Where to write the VALUE_PAIR(s).
 * @param[in] request structure (used only for talloc)
 * @param[in] map the map. The LHS (dst) has to be VPT_TYPE_ATTR or VPT_TYPE_LIST.
 * @param[in] ctx unused
 * @return 0 on success, -1 on failure, -2 on attribute not found/equivalent
 */
int radius_map2vp(VALUE_PAIR **out, REQUEST *request, value_pair_map_t const *map, UNUSED void *ctx)
{
	int rcode = 0;
	VALUE_PAIR *vp = NULL, *found, **from = NULL;
	DICT_ATTR const *da;
	REQUEST *context;
	vp_cursor_t cursor;

	rad_assert(request != NULL);
	rad_assert(map != NULL);

	*out = NULL;

	/*
	 *	Special case for !*, we don't need to parse the value, just allocate an attribute with
	 *	the right operator.
	 */
	if (map->op == T_OP_CMP_FALSE) {
		vp = pairalloc(request, map->dst->da);
		if (!vp) return -1;
		vp->op = map->op;
		*out = vp;

		return 0;
	}

	/*
	 *	List to list found, this is a special case because we don't need
	 *	to allocate any attributes, just found the current list, and change
	 *	the op.
	 */
	if ((map->dst->type == VPT_TYPE_LIST) && (map->src->type == VPT_TYPE_LIST)) {
		from = radius_list(request, map->src->list);
		if (!from) return -2;

		found = paircopy(request, *from);
		/*
		 *	List to list copy is invalid if the src list has no attributes.
		 */
		if (!found) return -2;

		for (vp = paircursor(&cursor, &found);
		     vp;
		     vp = pairnext(&cursor)) {
		 	vp->op = T_OP_ADD;
		}

		*out = found;

		return 0;
	}

	/*
	 *	Deal with all non-list founding operations.
	 */
	da = map->dst->da ? map->dst->da : map->src->da;

	switch (map->src->type) {
	case VPT_TYPE_XLAT:
	case VPT_TYPE_LITERAL:
	case VPT_TYPE_DATA:
		vp = pairalloc(request, da);
		if (!vp) return -1;
		vp->op = map->op;
		break;
	default:
		break;
	}


	/*
	 *	And parse the RHS
	 */
	switch (map->src->type) {
	case VPT_TYPE_XLAT:
		rad_assert(map->dst->da);	/* Need to know where were going to write the new attribute */
		/*
		 *	Don't call unnecessary expansions
		 */
		if (strchr(map->src->name, '%') != NULL) {
			ssize_t slen;
			char *str = NULL;

			slen = radius_axlat(&str, request, map->src->name, NULL, NULL);
			if (slen < 0) {
				rcode = slen;
				goto error;
			}
			rcode = pairparsevalue(vp, str);
			talloc_free(str);
			if (!rcode) {
				pairfree(&vp);
				rcode = -1;
				goto error;
			}

			break;
		}
		/* FALL-THROUGH */

	case VPT_TYPE_LITERAL:
		if (!pairparsevalue(vp, map->src->name)) {
			rcode = -2;
			goto error;
		}
		break;

	case VPT_TYPE_ATTR:
		rad_assert(!map->dst->da ||
			   (map->src->da->type == map->dst->da->type) ||
			   (map->src->da->type == PW_TYPE_OCTETS) ||
			   (map->dst->da->type == PW_TYPE_OCTETS));
		context = request;

		if (radius_request(&context, map->src->request) == 0) {
			from = radius_list(context, map->src->list);
		}

		/*
		 *	Can't add the attribute if the list isn't
		 *	valid.
		 */
		if (!from) {
			rcode = -2;
			goto error;
		}

		/*
		 *	Special case, destination is a list, found all instance of an attribute.
		 */
		if (map->dst->type == VPT_TYPE_LIST) {
			found = paircopy2(request, *from, map->src->da->attr, map->src->da->vendor, TAG_ANY);
			if (!found) {
				REDEBUG("Attribute \"%s\" not found in request", map->src->name);
				rcode = -2;
				goto error;
			}

			for (vp = paircursor(&cursor, &found);
			     vp;
			     vp = pairnext(&cursor)) {
				vp->op = T_OP_ADD;
			}

			*out = found;
			return 0;
		}

		/*
		 *	FIXME: allow tag references?
		 */
		found = pairfind(*from, map->src->da->attr, map->src->da->vendor, TAG_ANY);
		if (!found) {
			REDEBUG("Attribute \"%s\" not found in request", map->src->name);
			rcode = -2;
			goto error;
		}

		/*
		 *	Copy the data over verbatim, assuming it's
		 *	actually data.
		 */
//		rad_assert(found->type == VT_DATA);
		vp = paircopyvpdata(request, da, found);
		if (!vp) {
			return -1;
		}
		vp->op = map->op;

		break;

	case VPT_TYPE_DATA:
		rad_assert(map->src->da->type == map->dst->da->type);
		memcpy(&vp->data, map->src->vpd, sizeof(vp->data));
		vp->length = map->src->length;
		break;

	/*
	 *	This essentially does the same as rlm_exec xlat, except it's non-configurable.
	 *	It's only really here as a convenience for people who expect the contents of
	 *	backticks to be executed in a shell.
	 *
	 *	exec string is xlat expanded and arguments are shell escaped.
	 */
	case VPT_TYPE_EXEC:
		return radius_mapexec(out, request, map);
	default:
		rad_assert(0);	/* Should of been caught at parse time */
	error:
		pairfree(&vp);
		return rcode;
	}

	*out = vp;
	return 0;
}
Example #9
0
static int respond_eap_md5(RADIUS_PACKET *req,
			   RADIUS_PACKET *rep)
{
	VALUE_PAIR *vp, *id, *state;
	int valuesize, namesize;
	unsigned char identifier;
	unsigned char *value;
	unsigned char *name;
	MD5_CTX	context;
	char    response[16];

	cleanresp(rep);

	if ((state = paircopy2(req->vps, PW_STATE)) == NULL)
	{
		fprintf(stderr, "radeapclient: no state attribute found\n");
		return 0;
	}

	if ((id = paircopy2(req->vps, ATTRIBUTE_EAP_ID)) == NULL)
	{
		fprintf(stderr, "radeapclient: no EAP-ID attribute found\n");
		return 0;
	}
	identifier = id->lvalue;

	if ((vp = pairfind(req->vps, ATTRIBUTE_EAP_BASE+PW_EAP_MD5)) == NULL)
	{
		fprintf(stderr, "radeapclient: no EAP-MD5 attribute found\n");
		return 0;
	}

	/* got the details of the MD5 challenge */
	valuesize = vp->strvalue[0];
	value = &vp->strvalue[1];
	name  = &vp->strvalue[valuesize+1];
	namesize = vp->length - (valuesize + 1);

	/* sanitize items */
	if(valuesize > vp->length)
	{
		fprintf(stderr, "radeapclient: md5 valuesize if too big (%d > %d)\n",
			valuesize, vp->length);
		return 0;
	}

	/* now do the CHAP operation ourself, rather than build the
	 * buffer. We could also call rad_chap_encode, but it wants
	 * a CHAP-Challenge, which we don't want to bother with.
	 */
	librad_MD5Init(&context);
	librad_MD5Update(&context, &identifier, 1);
	librad_MD5Update(&context, password, strlen(password));
	librad_MD5Update(&context, value, valuesize);
	librad_MD5Final(response, &context);

	vp = paircreate(ATTRIBUTE_EAP_BASE+PW_EAP_MD5, PW_TYPE_OCTETS);
	vp->strvalue[0]=16;
	memcpy(&vp->strvalue[1], response, 16);
	vp->length = 17;

	pairreplace(&(rep->vps), vp);

	pairreplace(&(rep->vps), id);

	/* copy the state object in */
	pairreplace(&(rep->vps), state);

	return 1;
}
Example #10
0
/** Convert a map to a VALUE_PAIR.
 *
 * @param[out] out Where to write the VALUE_PAIR(s).
 * @param[in] request structure (used only for talloc)
 * @param[in] map the map. The LHS (dst) has to be VPT_TYPE_ATTR or VPT_TYPE_LIST.
 * @param[in] ctx unused
 * @return 0 on success, -1 on failure, -2 on attribute not found/equivalent
 */
int radius_map2vp(VALUE_PAIR **out, REQUEST *request, value_pair_map_t const *map, UNUSED void *ctx)
{
	int rcode = 0;
	VALUE_PAIR *vp = NULL, *found, **from = NULL;
	DICT_ATTR const *da;
	REQUEST *context = request;
	vp_cursor_t cursor;

	rad_assert(request != NULL);
	rad_assert(map != NULL);

	*out = NULL;

	/*
	 *	Special case for !*, we don't need to parse RHS as this is a unary operator.
	 */
	if (map->op == T_OP_CMP_FALSE) {
		/*
		 *  Were deleting all the attributes in a list. This isn't like the other
		 *  mappings because lists aren't represented as attributes (yet),
		 *  so we can't return a <list> attribute with the !* operator for
		 *  radius_pairmove() to consume, and need to do the work here instead.
		 */
		if (map->dst->type == VPT_TYPE_LIST) {
			if (radius_request(&context, map->dst->request) == 0) {
				from = radius_list(context, map->dst->list);
			}
			if (!from) return -2;

			pairfree(from);

			/* @fixme hacky! */
			if (map->dst->list == PAIR_LIST_REQUEST) {
				context->username = NULL;
				context->password = NULL;
			}

			return 0;
		}

		/* Not a list, but an attribute, radius_pairmove() will perform that actual delete */
		vp = pairalloc(request, map->dst->da);
		if (!vp) return -1;
		vp->op = map->op;
		*out = vp;

		return 0;
	}

	/*
	 *	List to list found, this is a special case because we don't need
	 *	to allocate any attributes, just finding the current list, and change
	 *	the op.
	 */
	if ((map->dst->type == VPT_TYPE_LIST) && (map->src->type == VPT_TYPE_LIST)) {
		if (radius_request(&context, map->src->request) == 0) {
			from = radius_list(context, map->src->list);
		}
		if (!from) return -2;

		found = paircopy(request, *from);
		/*
		 *	List to list copy is invalid if the src list has no attributes.
		 */
		if (!found) return -2;

		for (vp = fr_cursor_init(&cursor, &found);
		     vp;
		     vp = fr_cursor_next(&cursor)) {
		 	vp->op = T_OP_ADD;
		}

		*out = found;

		return 0;
	}

	/*
	 *	Deal with all non-list operations.
	 */
	da = map->dst->da ? map->dst->da : map->src->da;

	switch (map->src->type) {
	case VPT_TYPE_XLAT:
	case VPT_TYPE_XLAT_STRUCT:
	case VPT_TYPE_LITERAL:
	case VPT_TYPE_DATA:
		vp = pairalloc(request, da);
		if (!vp) return -1;
		vp->op = map->op;
		break;
	default:
		break;
	}


	/*
	 *	And parse the RHS
	 */
	switch (map->src->type) {
		ssize_t slen;
		char *str;

	case VPT_TYPE_XLAT_STRUCT:
		rad_assert(map->dst->da);	/* Need to know where were going to write the new attribute */
		rad_assert(map->src->xlat != NULL);

		str = NULL;
		slen = radius_axlat_struct(&str, request, map->src->xlat, NULL, NULL);
		if (slen < 0) {
			rcode = slen;
			goto error;
		}

		/*
		 *	We do the debug printing because radius_axlat_struct
		 *	doesn't have access to the original string.  It's been
		 *	mangled during the parsing to xlat_exp_t
		 */
		RDEBUG2("EXPAND %s", map->src->name);
		RDEBUG2("   --> %s", str);

		rcode = pairparsevalue(vp, str);
		talloc_free(str);
		if (!rcode) {
			pairfree(&vp);
			rcode = -1;
			goto error;
		}
		break;

	case VPT_TYPE_XLAT:
		rad_assert(map->dst->da);	/* Need to know where were going to write the new attribute */

		str = NULL;
		slen = radius_axlat(&str, request, map->src->name, NULL, NULL);
		if (slen < 0) {
			rcode = slen;
			goto error;
		}
		rcode = pairparsevalue(vp, str);
		talloc_free(str);
		if (!rcode) {
			pairfree(&vp);
			rcode = -1;
			goto error;
		}
		break;

	case VPT_TYPE_LITERAL:
		if (!pairparsevalue(vp, map->src->name)) {
			rcode = -2;
			goto error;
		}
		break;

	case VPT_TYPE_ATTR:
		rad_assert(!map->dst->da ||
			   (map->src->da->type == map->dst->da->type) ||
			   (map->src->da->type == PW_TYPE_OCTETS) ||
			   (map->dst->da->type == PW_TYPE_OCTETS));

		/*
		 *	Special case, destination is a list, found all instance of an attribute.
		 */
		if (map->dst->type == VPT_TYPE_LIST) {
			context = request;

			if (radius_request(&context, map->src->request) == 0) {
				from = radius_list(context, map->src->list);
			}

			/*
			 *	Can't add the attribute if the list isn't
			 *	valid.
			 */
			if (!from) {
				rcode = -2;
				goto error;
			}

			found = paircopy2(request, *from, map->src->da->attr, map->src->da->vendor, TAG_ANY);
			if (!found) {
				REDEBUG("Attribute \"%s\" not found in request", map->src->name);
				rcode = -2;
				goto error;
			}

			for (vp = fr_cursor_init(&cursor, &found);
			     vp;
			     vp = fr_cursor_next(&cursor)) {
				vp->op = T_OP_ADD;
			}

			*out = found;
			return 0;
		}

		if (radius_vpt_get_vp(&found, request, map->src) < 0) {
			REDEBUG("Attribute \"%s\" not found in request", map->src->name);
			rcode = -2;
			goto error;
		}

		/*
		 *	Copy the data over verbatim, assuming it's
		 *	actually data.
		 */
		vp = paircopyvpdata(request, da, found);
		if (!vp) {
			return -1;
		}
		vp->op = map->op;

		break;

	case VPT_TYPE_DATA:
		rad_assert(map->src && map->src->da);
		rad_assert(map->dst && map->dst->da);
		rad_assert(map->src->da->type == map->dst->da->type);
		memcpy(&vp->data, map->src->vpd, sizeof(vp->data));
		vp->length = map->src->length;
		break;

	/*
	 *	This essentially does the same as rlm_exec xlat, except it's non-configurable.
	 *	It's only really here as a convenience for people who expect the contents of
	 *	backticks to be executed in a shell.
	 *
	 *	exec string is xlat expanded and arguments are shell escaped.
	 */
	case VPT_TYPE_EXEC:
		return radius_mapexec(out, request, map);
	default:
		rad_assert(0);	/* Should of been caught at parse time */
	error:
		pairfree(&vp);
		return rcode;
	}

	*out = vp;
	return 0;
}
Example #11
0
/*
 *	Process the "diameter" contents of the tunneled data.
 */
int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session)
{
	int rcode = PW_AUTHENTICATION_REJECT;
	REQUEST *fake;
	VALUE_PAIR *vp;
	ttls_tunnel_t *t;
	const uint8_t *data;
	size_t data_len;
	REQUEST *request = handler->request;

	rad_assert(request != NULL);

	/*
	 *	Just look at the buffer directly, without doing
	 *	record_minus.
	 */
	data_len = tls_session->clean_out.used;
	tls_session->clean_out.used = 0;
	data = tls_session->clean_out.data;

	t = (ttls_tunnel_t *) tls_session->opaque;

	/*
	 *	If there's no data, maybe this is an ACK to an
	 *	MS-CHAP2-Success.
	 */
	if (data_len == 0) {
		if (t->authenticated) {
			RDEBUG("Got ACK, and the user was already authenticated.");
			return PW_AUTHENTICATION_ACK;
		} /* else no session, no data, die. */

		/*
		 *	FIXME: Call SSL_get_error() to see what went
		 *	wrong.
		 */
		RDEBUG2("SSL_read Error");
		return PW_AUTHENTICATION_REJECT;
	}

#ifndef NDEBUG
	if ((debug_flag > 2) && fr_log_fp) {
		size_t i;

		for (i = 0; i < data_len; i++) {
			if ((i & 0x0f) == 0) fprintf(fr_log_fp, "  TTLS tunnel data in %04x: ", (int) i);

			fprintf(fr_log_fp, "%02x ", data[i]);

			if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
		}
		if ((data_len & 0x0f) != 0) fprintf(fr_log_fp, "\n");
	}
#endif

	if (!diameter_verify(request, data, data_len)) {
		return PW_AUTHENTICATION_REJECT;
	}

	/*
	 *	Allocate a fake REQUEST structe.
	 */
	fake = request_alloc_fake(request);

	rad_assert(fake->packet->vps == NULL);

	/*
	 *	Add the tunneled attributes to the fake request.
	 */
	fake->packet->vps = diameter2vp(request, tls_session->ssl, data, data_len);
	if (!fake->packet->vps) {
		request_free(&fake);
		return PW_AUTHENTICATION_REJECT;
	}

	/*
	 *	Tell the request that it's a fake one.
	 */
	vp = pairmake("Freeradius-Proxied-To", "127.0.0.1", T_OP_EQ);
	if (vp) {
		pairadd(&fake->packet->vps, vp);
	}

	if ((debug_flag > 0) && fr_log_fp) {
		RDEBUG("Got tunneled request");

		debug_pair_list(fake->packet->vps);
	}

	/*
	 *	Update other items in the REQUEST data structure.
	 */
	fake->username = pairfind(fake->packet->vps, PW_USER_NAME, 0, TAG_ANY);
	fake->password = pairfind(fake->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);

	/*
	 *	No User-Name, try to create one from stored data.
	 */
	if (!fake->username) {
		/*
		 *	No User-Name in the stored data, look for
		 *	an EAP-Identity, and pull it out of there.
		 */
		if (!t->username) {
			vp = pairfind(fake->packet->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
			if (vp &&
			    (vp->length >= EAP_HEADER_LEN + 2) &&
			    (vp->vp_strvalue[0] == PW_EAP_RESPONSE) &&
			    (vp->vp_strvalue[EAP_HEADER_LEN] == PW_EAP_IDENTITY) &&
			    (vp->vp_strvalue[EAP_HEADER_LEN + 1] != 0)) {
				/*
				 *	Create & remember a User-Name
				 */
				t->username = pairmake("User-Name", "", T_OP_EQ);
				rad_assert(t->username != NULL);

				memcpy(t->username->vp_strvalue, vp->vp_strvalue + 5,
				       vp->length - 5);
				t->username->length = vp->length - 5;
				t->username->vp_strvalue[t->username->length] = 0;

				RDEBUG("Got tunneled identity of %s",
				       t->username->vp_strvalue);

				/*
				 *	If there's a default EAP type,
				 *	set it here.
				 */
				if (t->default_eap_type != 0) {
					RDEBUG("Setting default EAP type for tunneled EAP session.");
					vp = paircreate(PW_EAP_TYPE, 0);
					rad_assert(vp != NULL);
					vp->vp_integer = t->default_eap_type;
					pairadd(&fake->config_items, vp);
				}

			} else {
				/*
				 *	Don't reject the request outright,
				 *	as it's permitted to do EAP without
				 *	user-name.
				 */
				RDEBUG2W("No EAP-Identity found to start EAP conversation.");
			}
		} /* else there WAS a t->username */

		if (t->username) {
			vp = paircopy(t->username);
			pairadd(&fake->packet->vps, vp);
			fake->username = pairfind(fake->packet->vps, PW_USER_NAME, 0, TAG_ANY);
		}
	} /* else the request ALREADY had a User-Name */

	/*
	 *	Add the State attribute, too, if it exists.
	 */
	if (t->state) {
		vp = paircopy(t->state);
		if (vp) pairadd(&fake->packet->vps, vp);
	}

	/*
	 *	If this is set, we copy SOME of the request attributes
	 *	from outside of the tunnel to inside of the tunnel.
	 *
	 *	We copy ONLY those attributes which do NOT already
	 *	exist in the tunneled request.
	 */
	if (t->copy_request_to_tunnel) {
		VALUE_PAIR *copy;

		for (vp = request->packet->vps; vp != NULL; vp = vp->next) {
			/*
			 *	The attribute is a server-side thingy,
			 *	don't copy it.
			 */
			if ((vp->da->attr > 255) &&
			    (vp->da->vendor == 0)) {
				continue;
			}

			/*
			 *	The outside attribute is already in the
			 *	tunnel, don't copy it.
			 *
			 *	This works for BOTH attributes which
			 *	are originally in the tunneled request,
			 *	AND attributes which are copied there
			 *	from below.
			 */
			if (pairfind(fake->packet->vps, vp->da->attr, vp->da->vendor, TAG_ANY)) {
				continue;
			}

			/*
			 *	Some attributes are handled specially.
			 */
			switch (vp->da->attr) {
				/*
				 *	NEVER copy Message-Authenticator,
				 *	EAP-Message, or State.  They're
				 *	only for outside of the tunnel.
				 */
			case PW_USER_NAME:
			case PW_USER_PASSWORD:
			case PW_CHAP_PASSWORD:
			case PW_CHAP_CHALLENGE:
			case PW_PROXY_STATE:
			case PW_MESSAGE_AUTHENTICATOR:
			case PW_EAP_MESSAGE:
			case PW_STATE:
				continue;
				break;

				/*
				 *	By default, copy it over.
				 */
			default:
				break;
			}

			/*
			 *	Don't copy from the head, we've already
			 *	checked it.
			 */
			copy = paircopy2(vp, vp->da->attr, vp->da->vendor, TAG_ANY);
			pairadd(&fake->packet->vps, copy);
		}
	}

	if ((vp = pairfind(request->config_items, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) {
		fake->server = vp->vp_strvalue;

	} else if (t->virtual_server) {
		fake->server = t->virtual_server;

	} /* else fake->server == request->server */


	if ((debug_flag > 0) && fr_log_fp) {
		RDEBUG("Sending tunneled request");

		debug_pair_list(fake->packet->vps);

		fprintf(fr_log_fp, "server %s {\n",
			(fake->server == NULL) ? "" : fake->server);
	}

	/*
	 *	Call authentication recursively, which will
	 *	do PAP, CHAP, MS-CHAP, etc.
	 */
	rad_virtual_server(fake);

	/*
	 *	Note that we don't do *anything* with the reply
	 *	attributes.
	 */
	if ((debug_flag > 0) && fr_log_fp) {
		fprintf(fr_log_fp, "} # server %s\n",
			(fake->server == NULL) ? "" : fake->server);

		RDEBUG("Got tunneled reply code %d", fake->reply->code);
		
		debug_pair_list(fake->reply->vps);
	}

	/*
	 *	Decide what to do with the reply.
	 */
	switch (fake->reply->code) {
	case 0:			/* No reply code, must be proxied... */
#ifdef WITH_PROXY
	  vp = pairfind(fake->config_items, PW_PROXY_TO_REALM, 0, TAG_ANY);
		if (vp) {
			eap_tunnel_data_t *tunnel;
			RDEBUG("Tunneled authentication will be proxied to %s", vp->vp_strvalue);

			/*
			 *	Tell the original request that it's going
			 *	to be proxied.
			 */
			pairmove2(&(request->config_items),
				  &(fake->config_items),
				  PW_PROXY_TO_REALM, 0, TAG_ANY);

			/*
			 *	Seed the proxy packet with the
			 *	tunneled request.
			 */
			rad_assert(request->proxy == NULL);
			request->proxy = fake->packet;
			memset(&request->proxy->src_ipaddr, 0,
			       sizeof(request->proxy->src_ipaddr));
			memset(&request->proxy->src_ipaddr, 0,
			       sizeof(request->proxy->src_ipaddr));
			request->proxy->src_port = 0;
			request->proxy->dst_port = 0;
			fake->packet = NULL;
			rad_free(&fake->reply);
			fake->reply = NULL;

			/*
			 *	Set up the callbacks for the tunnel
			 */
			tunnel = rad_malloc(sizeof(*tunnel));
			memset(tunnel, 0, sizeof(*tunnel));

			tunnel->tls_session = tls_session;
			tunnel->callback = eapttls_postproxy;

			/*
			 *	Associate the callback with the request.
			 */
			rcode = request_data_add(request,
						 request->proxy,
						 REQUEST_DATA_EAP_TUNNEL_CALLBACK,
						 tunnel, free);
			rad_assert(rcode == 0);

			/*
			 *	rlm_eap.c has taken care of associating
			 *	the handler with the fake request.
			 *
			 *	So we associate the fake request with
			 *	this request.
			 */
			rcode = request_data_add(request,
						 request->proxy,
						 REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK,
						 fake, my_request_free);
			rad_assert(rcode == 0);
			fake = NULL;

			/*
			 *	Didn't authenticate the packet, but
			 *	we're proxying it.
			 */
			rcode = PW_STATUS_CLIENT;

		} else
#endif	/* WITH_PROXY */
		  {
			RDEBUG("No tunneled reply was found for request %d , and the request was not proxied: rejecting the user.",
			       request->number);
			rcode = PW_AUTHENTICATION_REJECT;
		}
		break;

	default:
		/*
		 *	Returns RLM_MODULE_FOO, and we want to return
		 *	PW_FOO
		 */
		rcode = process_reply(handler, tls_session, request,
				      fake->reply);
		switch (rcode) {
		case RLM_MODULE_REJECT:
			rcode = PW_AUTHENTICATION_REJECT;
			break;

		case RLM_MODULE_HANDLED:
			rcode = PW_ACCESS_CHALLENGE;
			break;

		case RLM_MODULE_OK:
			rcode = PW_AUTHENTICATION_ACK;
			break;

		default:
			rcode = PW_AUTHENTICATION_REJECT;
			break;
		}
		break;
	}

	request_free(&fake);

	return rcode;
}
Example #12
0
/*
 *	Copy a pairlist.
 */
VALUE_PAIR *paircopy(TALLOC_CTX *ctx, VALUE_PAIR *vp)
{
	return paircopy2(ctx, vp, 0, 0, TAG_ANY);
}
Example #13
0
/*
 *	Copy a pairlist.
 */
VALUE_PAIR *paircopy(VALUE_PAIR *vp)
{
	return paircopy2(vp, 0, 0, TAG_ANY);
}
Example #14
0
static int 
respond_eap_md5(RADIUS_PACKET *req,
			   RADIUS_PACKET *rep,const char* pwd)
{
	VALUE_PAIR *vp, *id, *state;
	size_t valuesize;
	uint8_t identifier;
	uint8_t *value;
	FR_MD5_CTX	context;
	uint8_t    response[16];

	cleanresp(rep);

	if ((state = paircopy2(req->vps, PW_STATE)) == NULL)
	{
		fr_strerror_printf("radeapclient: no state attribute found");
		return 0;
	}

	if ((id = paircopy2(req->vps, ATTRIBUTE_EAP_ID)) == NULL)
	{
		fr_strerror_printf("radeapclient: no EAP-ID attribute found");
		return 0;
	}
	identifier = id->vp_integer;

	if ((vp = pairfind(req->vps, ATTRIBUTE_EAP_BASE+PW_EAP_MD5)) == NULL)
	{
		fr_strerror_printf("radeapclient: no EAP-MD5 attribute found");
		return 0;
	}

	/* got the details of the MD5 challenge */
	valuesize = vp->vp_octets[0];
	value = &vp->vp_octets[1];

	/* sanitize items */
	if(valuesize > vp->length)
	{
		fr_strerror_printf("radeapclient: md5 valuesize if too big (%u > %u)\n",
			(unsigned int) valuesize, (unsigned int) vp->length);
		return 0;
	}

	/* now do the CHAP operation ourself, rather than build the
	 * buffer. We could also call rad_chap_encode, but it wants
	 * a CHAP-Challenge, which we don't want to bother with.
	 */
	fr_MD5Init(&context);
	fr_MD5Update(&context, &identifier, 1);
	fr_MD5Update(&context, (uint8_t *) pwd, strlen(pwd));
	fr_MD5Update(&context, value, valuesize);
	fr_MD5Final(response, &context);

	vp = paircreate(ATTRIBUTE_EAP_BASE+PW_EAP_MD5, PW_TYPE_OCTETS);
	vp->vp_octets[0]=16;
	memcpy(&vp->vp_strvalue[1], response, 16);
	vp->length = 17;

	pairreplace(&(rep->vps), vp);

	pairreplace(&(rep->vps), id);

	/* copy the state object in */
	pairreplace(&(rep->vps), state);

	return 1;
}
Example #15
0
main(int argc, char *argv[])
{
	int filedone;
	RADIUS_PACKET *req,*req2;
	VALUE_PAIR *vp, *vpkey, *vpextra;
	extern unsigned int sha1_data_problems;

	req = NULL;
	req2 = NULL;
	filedone = 0;

	if(argc>1) {
	  sha1_data_problems = 1;
	}

	if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) {
		librad_perror("radclient");
		return 1;
	}

	if ((req = rad_alloc(1)) == NULL) {
		librad_perror("radclient");
		exit(1);
	}

	if ((req2 = rad_alloc(1)) == NULL) {
		librad_perror("radclient");
		exit(1);
	}

	while(!filedone) {
		if(req->vps) pairfree(&req->vps);
		if(req2->vps) pairfree(&req2->vps);

		if ((req->vps = readvp2(stdin, &filedone, "eapsimlib:")) == NULL) {
			break;
		}

		printf("\nRead:\n");
		vp_printlist(stdout, req->vps);

		map_eapsim_types(req);
		map_eap_types(req);
		printf("Mapped to:\n");
		vp_printlist(stdout, req->vps);

		/* find the EAP-Message, copy it to req2 */
		vp = paircopy2(req->vps, PW_EAP_MESSAGE);

		if(vp == NULL) continue;

		pairadd(&req2->vps, vp);

		/* only call unmap for sim types here */
		unmap_eap_types(req2);
		unmap_eapsim_types(req2);

		printf("Unmapped to:\n");
		vp_printlist(stdout, req2->vps);

		vp = pairfind(req2->vps,
			      ATTRIBUTE_EAP_SIM_BASE+PW_EAP_SIM_MAC);
		vpkey   = pairfind(req->vps, ATTRIBUTE_EAP_SIM_KEY);
		vpextra = pairfind(req->vps, ATTRIBUTE_EAP_SIM_EXTRA);

		if(vp != NULL && vpkey != NULL && vpextra!=NULL) {
			uint8_t calcmac[16];

			/* find the EAP-Message, copy it to req2 */

			memset(calcmac, 0, sizeof(calcmac));
			printf("Confirming MAC...");
			if(eapsim_checkmac(req2->vps, vpkey->strvalue,
					   vpextra->strvalue, vpextra->length,
					   calcmac)) {
				printf("succeed\n");
			} else {
				int i, j;

				printf("calculated MAC (");
				for (i = 0; i < 20; i++) {
					if(j==4) {
						printf("_");
						j=0;
					}
					j++;

					printf("%02x", calcmac[i]);
				}
				printf(" did not match\n");
			}
		}

		fflush(stdout);
	}
}
Example #16
0
/*
 *	Copy a pairlist.
 */
VALUE_PAIR *paircopy(VALUE_PAIR *vp)
{
	return paircopy2(vp, -1);
}
Example #17
0
main(int argc, char *argv[])
{
	int filedone;
	RADIUS_PACKET *req,*req2;
	VALUE_PAIR *vp, *vpkey, *vpextra;
	extern unsigned int sha1_data_problems;

	req = NULL;
	req2 = NULL;
	filedone = 0;

	if(argc>1) {
	  sha1_data_problems = 1;
	}

	if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) {
		ERROR("%s", fr_strerror());
		return 1;
	}

	req = rad_alloc(NULL, true)
	if (!req) {
		ERROR("%s", fr_strerror());
		exit(1);
	}

	req2 = rad_alloc(NULL, true);
	if (!req2) {
		ERROR("%s", fr_strerror());
		exit(1);
	}

	while(!filedone) {
		if (req->vps) pairfree(&req->vps);
		if (req2->vps) pairfree(&req2->vps);

		if (readvp2(&req->vps, NULL, stdin, &filedone) < 0) {
			ERROR("%s", fr_strerror());
			break;
		}

		if (fr_debug_flag > 1) {
			DEBUG("Read:");
			vp_printlist(stdout, req->vps);
		}

		map_eapsim_types(req);
		map_eap_methods(req);

		if (fr_debug_flag > 1) {
			DEBUG("Mapped to:");
			vp_printlist(stdout, req->vps);
		}

		/* find the EAP-Message, copy it to req2 */
		vp = paircopy2(NULL, req->vps, PW_EAP_MESSAGE, 0, TAG_ANY);

		if(!vp) continue;

		pairadd(&req2->vps, vp);

		/* only call unmap for sim types here */
		unmap_eap_methods(req2);
		unmap_eapsim_types(req2);

		if (fr_debug_flag > 1) {
			DEBUG("Unmapped to:");
			vp_printlist(stdout, req2->vps);
		}

		vp = pairfind(req2->vps, PW_EAP_SIM_MAC, 0, TAG_ANY);
		vpkey   = pairfind(req->vps, PW_EAP_SIM_KEY, 0, TAG_ANY);
		vpextra = pairfind(req->vps, PW_EAP_SIM_EXTRA, 0, TAG_ANY);

		if(vp != NULL && vpkey != NULL && vpextra!=NULL) {
			uint8_t calcmac[16];

			/* find the EAP-Message, copy it to req2 */

			memset(calcmac, 0, sizeof(calcmac));
			DEBUG("Confirming MAC...");
			if(eapsim_checkmac(req2->vps, vpkey->vp_strvalue,
					   vpextra->vp_strvalue, vpextra->length,
					   calcmac)) {
				DEBUG("succeed");
			} else {
				int i, j;

				DEBUG("calculated MAC (");
				for (i = 0; i < 20; i++) {
					if(j==4) {
						DEBUG("_");
						j=0;
					}
					j++;

					DEBUG("%02x", calcmac[i]);
				}
				DEBUG("did not match");
			}
		}

		fflush(stdout);
	}
}