Пример #1
0
static void cleanresp(RADIUS_PACKET *resp)
{
	VALUE_PAIR *vpnext, *vp, **last;


	/*
	 * maybe should just copy things we care about, or keep
	 * a copy of the original input and start from there again?
	 */
	pairdelete(&resp->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
	pairdelete(&resp->vps, ATTRIBUTE_EAP_BASE+PW_EAP_IDENTITY, 0, TAG_ANY);

	last = &resp->vps;
	for(vp = *last; vp != NULL; vp = vpnext)
	{
		vpnext = vp->next;

		if((vp->da->attr > ATTRIBUTE_EAP_BASE &&
		    vp->da->attr <= ATTRIBUTE_EAP_BASE+256) ||
		   (vp->da->attr > ATTRIBUTE_EAP_SIM_BASE &&
		    vp->da->attr <= ATTRIBUTE_EAP_SIM_BASE+256))
		{
			*last = vpnext;
			talloc_free(vp);
		} else {
			last = &vp->next;
		}
	}
}
/*
 *	Add hints to the info sent by the terminal server
 *	based on the pattern of the username, and other attributes.
 */
static int hints_setup(PAIR_LIST *hints, REQUEST *request)
{
	char const     	*name;
	VALUE_PAIR	*add;
	VALUE_PAIR	*tmp;
	PAIR_LIST	*i;
	VALUE_PAIR	*request_pairs;
	int		updated = 0, ft;

	request_pairs = request->packet->vps;

	if (!hints || !request_pairs)
		return RLM_MODULE_NOOP;

	/*
	 *	Check for valid input, zero length names not permitted
	 */
	name = (tmp = pairfind(request_pairs, PW_USER_NAME, 0, TAG_ANY)) ?
		tmp->vp_strvalue : NULL;
	if (!name || name[0] == 0) {
		/*
		 *	No name, nothing to do.
		 */
		return RLM_MODULE_NOOP;
	}

	for (i = hints; i; i = i->next) {
		/*
		 *	Use "paircompare", which is a little more general...
		 */
		if (((strcmp(i->name, "DEFAULT") == 0) || (strcmp(i->name, name) == 0)) &&
		    (paircompare(request, request_pairs, i->check, NULL) == 0)) {
			RDEBUG2("  hints: Matched %s at %d", i->name, i->lineno);
			/*
			 *	Now add all attributes to the request list,
			 *	except PW_STRIP_USER_NAME and PW_FALL_THROUGH
			 *	and xlat them.
			 */
			add = paircopy(request->packet, i->reply);
			ft = fallthrough(add);

			pairdelete(&add, PW_STRIP_USER_NAME, 0, TAG_ANY);
			pairdelete(&add, PW_FALL_THROUGH, 0, TAG_ANY);
			radius_xlat_move(request, &request->packet->vps, &add);

			pairfree(&add);
			updated = 1;
			if (!ft) {
				break;
			}
		}
	}

	if (updated == 0) {
		return RLM_MODULE_NOOP;
	}

	return RLM_MODULE_UPDATED;
}
Пример #3
0
static int eap_req2vp(EAP_HANDLER *handler)
{
	int		encoded, total, size;
	const uint8_t	*ptr;
	VALUE_PAIR	*head = NULL;
	VALUE_PAIR	**tail = &head;
	VALUE_PAIR	*vp;

	ptr = wpabuf_head(handler->server_ctx.eap_if->eapReqData);
	encoded = total = wpabuf_len(handler->server_ctx.eap_if->eapReqData);

	do {
		size = total;
		if (size > 253) size = 253;

		vp = paircreate(PW_EAP_MESSAGE, PW_TYPE_OCTETS);
		if (!vp) {
			pairfree(&head);
			return -1;
		}
		memcpy(vp->vp_octets, ptr, size);
		vp->length = size;

		*tail = vp;
		tail = &(vp->next);

		ptr += size;
		total -= size;
	} while (total > 0);

	pairdelete(&handler->request->reply->vps, PW_EAP_MESSAGE, TAG_ANY);
	pairadd(&handler->request->reply->vps, head);

	return encoded;
}
Пример #4
0
/*
 *	Run a virtual server auth and postauth
 *
 */
int rad_virtual_server(REQUEST *request)
{
	VALUE_PAIR *vp;
	int result;

	RDEBUG("server %s {", request->server);
	RDEBUG("  Request:");
	debug_pair_list(request->packet->vps);

	/*
	 *	We currently only handle AUTH packets here.
	 *	This could be expanded to handle other packets as well if required.
	 */
	rad_assert(request->packet->code == PW_CODE_ACCESS_REQUEST);

	result = rad_authenticate(request);

	if (request->reply->code == PW_CODE_ACCESS_REJECT) {
		pairdelete(&request->config_items, PW_POST_AUTH_TYPE, 0, TAG_ANY);
		vp = pairmake_config("Post-Auth-Type", "Reject", T_OP_SET);
		if (vp) rad_postauth(request);
	}

	if (request->reply->code == PW_CODE_ACCESS_ACCEPT) {
		rad_postauth(request);
	}

	RDEBUG("  Reply:");
	debug_pair_list(request->reply->vps);
	RDEBUG("} # server %s", request->server);

	return result;
}
Пример #5
0
/*
 *	Set the SQL user name.
 *
 *	We don't call the escape function here. The resulting string
 *	will be escaped later in the queries xlat so we don't need to
 *	escape it twice. (it will make things wrong if we have an
 *	escape candidate character in the username)
 */
static int sql_set_user(SQL_INST *inst, REQUEST *request, char *sqlusername, const char *username)
{
	VALUE_PAIR *vp=NULL;
	char tmpuser[MAX_STRING_LEN];

	tmpuser[0] = '\0';
	sqlusername[0]= '\0';

	/* Remove any user attr we added previously */
	pairdelete(&request->packet->vps, PW_SQL_USER_NAME);

	if (username != NULL) {
		strNcpy(tmpuser, username, MAX_STRING_LEN);
	} else if (strlen(inst->config->query_user)) {
		radius_xlat(tmpuser, sizeof(tmpuser), inst->config->query_user, request, NULL);
	} else {
		return 0;
	}

	if (*tmpuser) {
		strNcpy(sqlusername, tmpuser, MAX_STRING_LEN);
		DEBUG2("rlm_sql (%s): sql_set_user escaped user --> '%s'",
		       inst->config->xlat_name, sqlusername);
		vp = pairmake("SQL-User-Name", sqlusername, 0);
		if (vp == NULL) {
			radlog(L_ERR, "%s", librad_errstr);
			return -1;
		}

		pairadd(&request->packet->vps, vp);
		return 0;
	}
	return -1;
}
Пример #6
0
/*
 *	Set the REDISN user name.
 *
 *	We don't call the escape function here. The resulting string
 *	will be escaped later in the queries xlat so we don't need to
 *	escape it twice. (it will make things wrong if we have an
 *	escape candidate character in the username)
 */
int redisn_set_user(REDIS_INST *inst, REQUEST *request, char *redisnusername, const char *username)
{
	VALUE_PAIR *vp=NULL;
	char tmpuser[MAX_STRING_LEN];

	tmpuser[0] = '\0';
	redisnusername[0]= '\0';

	/* Remove any user attr we added previously */
	pairdelete(&request->packet->vps, PW_REDIS_USER_NAME, 0, TAG_ANY);

	if (username != NULL) {
		strlcpy(tmpuser, username, sizeof(tmpuser));
	} else if (strlen(inst->query_user)) {
		radius_xlat(tmpuser, sizeof(tmpuser), inst->query_user, request, NULL, inst);
	} else {
		return 0;
	}

	strlcpy(redisnusername, tmpuser, MAX_STRING_LEN);
	RDEBUG2("redisn_set_user escaped user --> '%s'", redisnusername);
	vp = radius_pairmake(request, &request->packet->vps,
			     "REDISN-User-Name", NULL, 0);
	if (!vp) {
		radlog(L_ERR, "%s", fr_strerror());
		return -1;
	}

	strlcpy(vp->vp_strvalue, tmpuser, sizeof(vp->vp_strvalue));
	vp->length = strlen(vp->vp_strvalue);

	return 0;

}
Пример #7
0
/*
 *	Run a virtual server auth and postauth
 *
 */
int rad_virtual_server(REQUEST *request)
{
	VALUE_PAIR *vp;
	int result;

	/*
	 *	We currently only handle AUTH packets here.
	 *	This could be expanded to handle other packets as well if required.
	 */
	rad_assert(request->packet->code == PW_AUTHENTICATION_REQUEST);

	result = rad_authenticate(request);

        if (request->reply->code == PW_AUTHENTICATION_REJECT) {
                pairdelete(&request->config_items, PW_POST_AUTH_TYPE, 0, TAG_ANY);
                vp = radius_pairmake(request, &request->config_items,
                                     "Post-Auth-Type", "Reject",
                                     T_OP_SET);
                if (vp) rad_postauth(request);
        }

        if (request->reply->code == PW_AUTHENTICATION_ACK) {
                rad_postauth(request);
        }

	return result;
}
Пример #8
0
/*
 *	compose EAP reply packet in EAP-Message attr of RADIUS.  If
 *	EAP exceeds 253, frame it in multiple EAP-Message attrs.
 */
int eap_basic_compose(RADIUS_PACKET *packet, eap_packet_t *reply)
{
	VALUE_PAIR *vp;
	eap_packet_raw_t *eap_packet;
	int rcode;

	if (eap_wireformat(reply) == EAP_INVALID) {
		return RLM_MODULE_INVALID;
	}
	eap_packet = (eap_packet_raw_t *)reply->packet;

	pairdelete(&(packet->vps), PW_EAP_MESSAGE, 0, TAG_ANY);

	vp = eap_packet2vp(packet, eap_packet);
	if (!vp) return RLM_MODULE_INVALID;
	pairadd(&(packet->vps), vp);

	/*
	 *	EAP-Message is always associated with
	 *	Message-Authenticator but not vice-versa.
	 *
	 *	Don't add a Message-Authenticator if it's already
	 *	there.
	 */
	vp = pairfind(packet->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY);
	if (!vp) {
		vp = paircreate(packet, PW_MESSAGE_AUTHENTICATOR, 0);
		vp->vp_length = AUTH_VECTOR_LEN;
		vp->vp_octets = talloc_zero_array(vp, uint8_t, vp->vp_length);

		pairadd(&(packet->vps), vp);
	}

	/* Set request reply code, but only if it's not already set. */
	rcode = RLM_MODULE_OK;
	if (!packet->code) switch (reply->code) {
	case PW_EAP_RESPONSE:
	case PW_EAP_SUCCESS:
		packet->code = PW_CODE_ACCESS_ACCEPT;
		rcode = RLM_MODULE_HANDLED;
		break;
	case PW_EAP_FAILURE:
		packet->code = PW_CODE_ACCESS_REJECT;
		rcode = RLM_MODULE_REJECT;
		break;
	case PW_EAP_REQUEST:
		packet->code = PW_CODE_ACCESS_CHALLENGE;
		rcode = RLM_MODULE_HANDLED;
		break;
	default:
		/* Should never enter here */
		ERROR("rlm_eap: reply code %d is unknown, Rejecting the request.", reply->code);
		packet->code = PW_CODE_ACCESS_REJECT;
		break;
	}

	return rcode;
}
Пример #9
0
/*
 *	compose EAP reply packet in EAP-Message attr of RADIUS.  If
 *	EAP exceeds 253, frame it in multiple EAP-Message attrs.
 */
int eap_basic_compose(RADIUS_PACKET *packet, EAP_PACKET *reply)
{
	VALUE_PAIR *vp;
	eap_packet_t *eap_packet;
	int rcode;

	if (eap_wireformat(reply) == EAP_INVALID) {
		return RLM_MODULE_INVALID;
	}
	eap_packet = (eap_packet_t *)reply->packet;

	pairdelete(&(packet->vps), PW_EAP_MESSAGE);

	vp = eap_packet2vp(eap_packet);
	if (!vp) return RLM_MODULE_INVALID;
	pairadd(&(packet->vps), vp);

	/*
	 *	EAP-Message is always associated with
	 *	Message-Authenticator but not vice-versa.
	 *
	 *	Don't add a Message-Authenticator if it's already
	 *	there.
	 */
	vp = pairfind(packet->vps, PW_MESSAGE_AUTHENTICATOR);
	if (!vp) {
		vp = paircreate(PW_MESSAGE_AUTHENTICATOR, PW_TYPE_OCTETS);
		memset(vp->vp_strvalue, 0, AUTH_VECTOR_LEN);
		vp->length = AUTH_VECTOR_LEN;
		pairadd(&(packet->vps), vp);
	}

	/* Set request reply code, but only if it's not already set. */
	rcode = RLM_MODULE_OK;
	if (!packet->code) switch(reply->code) {
	case PW_EAP_RESPONSE:
	case PW_EAP_SUCCESS:
		packet->code = PW_AUTHENTICATION_ACK;
		rcode = RLM_MODULE_HANDLED;
		break;
	case PW_EAP_FAILURE:
		packet->code = PW_AUTHENTICATION_REJECT;
		rcode = RLM_MODULE_REJECT;
		break;
	case PW_EAP_REQUEST:
		packet->code = PW_ACCESS_CHALLENGE;
		rcode = RLM_MODULE_HANDLED;
		break;
	default:
		/* Should never enter here */
		packet->code = PW_AUTHENTICATION_REJECT;
		break;
	}

	return rcode;
}
Пример #10
0
/*
 *	We received a response from a remote radius server.
 *	Find the original request, then return.
 *	Returns:   1 replication don't reply
 *	           0 proxy found
 *		  -1 error don't reply
 */
int proxy_receive(REQUEST *request)
{
	VALUE_PAIR *proxypair;
	VALUE_PAIR *replicatepair;
        int rcode;

	proxypair = pairfind(request->config_items, PW_PROXY_TO_REALM);
	replicatepair = pairfind(request->config_items, PW_REPLICATE_TO_REALM);
        if (proxypair) {
            /* Don't do anything*/

        } else if (replicatepair) {
            /*
             *  The request was replicated, so we don't process the response.
             */
            return RLM_MODULE_HANDLED;

        } else {
		radlog(L_PROXY, "Proxy reply to packet with no Realm");
		return RLM_MODULE_FAIL;
	}

        /*
         *	Delete any reply we had accumulated until now.
	 */
        pairfree(&request->reply->vps);

	/*
	 *	Run the packet through the post-proxy stage,
	 *	BEFORE playing games with the attributes.
	 */
        rcode = module_post_proxy(request);

        /*
         *	Delete the Proxy-State Attributes from the reply.
         *	These include Proxy-State attributes from us and
         *	remote server.
	 */
        pairdelete(&request->proxy_reply->vps, PW_PROXY_STATE);

	/*
	 *	Add the attributes left in the proxy reply to
	 *	the reply list.
	 */
        pairadd(&request->reply->vps, request->proxy_reply->vps);
        request->proxy_reply->vps = NULL;

        /*
         *	Free any other configuration items and proxy pairs
         */
        pairfree(&request->config_items);
        pairfree(&request->proxy->vps);

        return rcode;
}
Пример #11
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;
	}
}
Пример #12
0
/*
 *	Find the named user in this modules database.  Create the set
 *	of attribute-value pairs to check and reply with for this user
 *	from the database. The authentication code only needs to check
 *	the password, the rest is done here.
 */
static rlm_rcode_t CC_HINT(nonnull) mod_authorize(void *instance, REQUEST *request)
{
	VALUE_PAIR *state;
	rlm_smsotp_t *inst = instance;

	/*
	 *  Look for the 'state' attribute.
	 */
	state = pairfind(request->packet->vps, PW_STATE, 0, TAG_ANY);
	if (state != NULL) {
		DEBUG("rlm_smsotp: Found reply to access challenge (AUTZ), Adding Auth-Type '%s'",inst->authtype);

		pairdelete(&request->config, PW_AUTH_TYPE, 0, TAG_ANY); /* delete old auth-type */
		pairmake_config("Auth-Type", inst->authtype, T_OP_SET);
	}

	return RLM_MODULE_OK;
}
Пример #13
0
/*
 *	We received a response from a remote radius server.
 *	Find the original request, then return.
 *	Returns:   1 replication don't reply
 *	           0 proxy found
 *		  -1 error don't reply
 */
int proxy_receive(REQUEST *request)
{
        int rcode;
	int post_proxy_type = 0;
	VALUE_PAIR *vp;

        /*
         *	Delete any reply we had accumulated until now.
	 */
        pairfree(&request->reply->vps);

	/*
	 *	Run the packet through the post-proxy stage,
	 *	BEFORE playing games with the attributes.
	 */
	vp = pairfind(request->config_items, PW_POST_PROXY_TYPE);
	if (vp) {
		DEBUG2("  Found Post-Proxy-Type %s", vp->strvalue);
		post_proxy_type = vp->lvalue;
	}
	rcode = module_post_proxy(post_proxy_type, request);

        /*
         *	Delete the Proxy-State Attributes from the reply.
         *	These include Proxy-State attributes from us and
         *	remote server.
	 */
        pairdelete(&request->proxy_reply->vps, PW_PROXY_STATE);

	/*
	 *	Add the attributes left in the proxy reply to
	 *	the reply list.
	 */
        pairadd(&request->reply->vps, request->proxy_reply->vps);
        request->proxy_reply->vps = NULL;

        /*
	 *	Free proxy request pairs.
         */
        pairfree(&request->proxy->vps);

        return rcode;
}
Пример #14
0
/*
 *	Before sending an Access-Reject, call the modules in the
 *	Post-Auth-Type REJECT stanza.
 */
static int rad_postauth_reject(REQUEST *request)
{
	int		result;
	VALUE_PAIR	*tmp;
	DICT_VALUE	*dval;

	dval = dict_valbyname(PW_POST_AUTH_TYPE, "REJECT");
	if (dval) {
		/* Overwrite the Post-Auth-Type with the value REJECT */
		pairdelete(&request->config_items, PW_POST_AUTH_TYPE);
		tmp = paircreate(PW_POST_AUTH_TYPE, PW_TYPE_INTEGER);
		tmp->lvalue = dval->value;
		pairadd(&request->config_items, tmp);
		result = rad_postauth(request);
	} else {
		/* No REJECT stanza */
		result = RLM_MODULE_OK;
	}
	return result;
}
/*
 *	Find the named user in this modules database.  Create the set
 *	of attribute-value pairs to check and reply with for this user
 *	from the database. The authentication code only needs to check
 *	the password, the rest is done here.
 */
static rlm_rcode_t smsotp_authorize(void *instance, REQUEST *request)
{
	VALUE_PAIR *state;
	rlm_smsotp_t *opt = instance;

	/* quiet the compiler */
	instance = instance;
	request = request;

	/*
	 *  Look for the 'state' attribute.
	 */
	state = pairfind(request->packet->vps, PW_STATE, 0, TAG_ANY);
	if (state != NULL) {
		DEBUG("rlm_smsotp: Found reply to access challenge (AUTZ), Adding Auth-Type '%s'",opt->smsotp_authtype);
		
		pairdelete(&request->config_items, PW_AUTH_TYPE, 0, TAG_ANY); /* delete old auth-type */
		pairadd(&request->config_items, pairmake("Auth-Type", opt->smsotp_authtype, T_OP_SET));
	}

	return RLM_MODULE_OK;
}
Пример #16
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;
	}
}
Пример #17
0
/*
 *	Add the 'SQL-User-Name' attribute to the packet.
 */
static int sql_set_user(rlm_sql_log_t *inst, REQUEST *request, char *sqlusername, const char *username)
{
	VALUE_PAIR *vp=NULL;
	char tmpuser[MAX_STRING_LEN];

	tmpuser[0] = '\0';
	sqlusername[0] = '\0';

	rad_assert(request != NULL);
	rad_assert(request->packet != NULL);

	/* Remove any user attr we added previously */
	pairdelete(&request->packet->vps, PW_SQL_USER_NAME);

	if (username != NULL) {
		strlcpy(tmpuser, username, MAX_STRING_LEN);
	} else if (inst->sql_user_name[0] != '\0') {
		radius_xlat(tmpuser, sizeof(tmpuser), inst->sql_user_name,
			    request, NULL);
	} else {
		return 0;
	}

	if (tmpuser[0] != '\0') {
		strlcpy(sqlusername, tmpuser, sizeof(tmpuser));
		RDEBUG2("sql_set_user escaped user --> '%s'", sqlusername);
		vp = pairmake("SQL-User-Name", sqlusername, 0);
		if (vp == NULL) {
			radlog(L_ERR, "%s", fr_strerror());
			return -1;
		}

		pairadd(&request->packet->vps, vp);
		return 0;
	}
	return -1;
}
Пример #18
0
/*
 * given a radius request with some attributes in the EAP range, build
 * them all into a single EAP-Message body.
 *
 * Note that this function will build multiple EAP-Message bodies
 * if there are multiple eligible EAP-types. This is incorrect, as the
 * recipient will in fact concatenate them.
 *
 * XXX - we could break the loop once we process one type. Maybe this
 *       just deserves an assert?
 *
 */
static void map_eap_methods(RADIUS_PACKET *req)
{
	VALUE_PAIR *vp, *vpnext;
	int id, eapcode;
	int eap_method;

	eap_packet_t *pt_ep = talloc_zero(req, eap_packet_t);

	vp = pairfind(req->vps, ATTRIBUTE_EAP_ID, 0, TAG_ANY);
	if(!vp) {
		id = ((int)getpid() & 0xff);
	} else {
		id = vp->vp_integer;
	}

	vp = pairfind(req->vps, ATTRIBUTE_EAP_CODE, 0, TAG_ANY);
	if(!vp) {
		eapcode = PW_EAP_REQUEST;
	} else {
		eapcode = vp->vp_integer;
	}

	for(vp = req->vps; vp != NULL; vp = vpnext) {
		/* save it in case it changes! */
		vpnext = vp->next;

		if(vp->da->attr >= ATTRIBUTE_EAP_BASE &&
		   vp->da->attr < ATTRIBUTE_EAP_BASE+256) {
			break;
		}
	}

	if(!vp) {
		return;
	}

	eap_method = vp->da->attr - ATTRIBUTE_EAP_BASE;

	switch(eap_method) {
	case PW_EAP_IDENTITY:
	case PW_EAP_NOTIFICATION:
	case PW_EAP_NAK:
	case PW_EAP_MD5:
	case PW_EAP_OTP:
	case PW_EAP_GTC:
	case PW_EAP_TLS:
	case PW_EAP_LEAP:
	case PW_EAP_TTLS:
	case PW_EAP_PEAP:
	default:
		/*
		 * no known special handling, it is just encoded as an
		 * EAP-message with the given type.
		 */

		/* nuke any existing EAP-Messages */
		pairdelete(&req->vps, PW_EAP_MESSAGE, 0, TAG_ANY);

		pt_ep->code = eapcode;
		pt_ep->id = id;
		pt_ep->type.num = eap_method;
		pt_ep->type.length = vp->length;

		pt_ep->type.data = talloc_memdup(vp, vp->vp_octets, vp->length);
		talloc_set_type(pt_ep->type.data, uint8_t);

		eap_basic_compose(req, pt_ep);
	}
}
Пример #19
0
/*
 *	Common code called by everything below.
 */
static rlm_rcode_t file_common(rlm_files_t *inst, REQUEST *request,
		       char const *filename, fr_hash_table_t *ht,
		       VALUE_PAIR *request_pairs, VALUE_PAIR **reply_pairs)
{
	char const	*name, *match;
	VALUE_PAIR	*check_tmp;
	VALUE_PAIR	*reply_tmp;
	const PAIR_LIST	*user_pl, *default_pl;
	int		found = 0;
	PAIR_LIST	my_pl;
	char		buffer[256];

	if (!inst->key) {
		VALUE_PAIR	*namepair;

		namepair = request->username;
		name = namepair ? namepair->vp_strvalue : "NONE";
	} else {
		int len;

		len = radius_xlat(buffer, sizeof(buffer), request, inst->key, NULL, NULL);
		if (len < 0) {
			return RLM_MODULE_FAIL;
		}
		
		name = len ? buffer : "NONE";
	}

	if (!ht) return RLM_MODULE_NOOP;

	my_pl.name = name;
	user_pl = fr_hash_table_finddata(ht, &my_pl);
	my_pl.name = "DEFAULT";
	default_pl = fr_hash_table_finddata(ht, &my_pl);

	/*
	 *	Find the entry for the user.
	 */
	while (user_pl || default_pl) {
		const PAIR_LIST *pl;

		if (!default_pl && user_pl) {
			pl = user_pl;
			match = name;
			user_pl = user_pl->next;

		} else if (!user_pl && default_pl) {
			pl = default_pl;
			match = "DEFAULT";
			default_pl = default_pl->next;

		} else if (user_pl->order < default_pl->order) {
			pl = user_pl;
			match = name;
			user_pl = user_pl->next;

		} else {
			pl = default_pl;
			match = "DEFAULT";
			default_pl = default_pl->next;
		}

		if (paircompare(request, request_pairs, pl->check, reply_pairs) == 0) {
			RDEBUG2("%s: Matched entry %s at line %d",
			       filename, match, pl->lineno);
			found = 1;
			check_tmp = paircopy(request, pl->check);

			/* ctx may be reply or proxy */
			reply_tmp = paircopy(request, pl->reply);
			radius_xlat_move(request, reply_pairs, &reply_tmp);
			pairmove(request, &request->config_items, &check_tmp);
			pairfree(&reply_tmp);
			pairfree(&check_tmp);

			/*
			 *	Fallthrough?
			 */
			if (!fallthrough(pl->reply))
				break;
		}
	}

	/*
	 *	Remove server internal parameters.
	 */
	pairdelete(reply_pairs, PW_FALL_THROUGH, 0, TAG_ANY);

	/*
	 *	See if we succeeded.
	 */
	if (!found)
		return RLM_MODULE_NOOP; /* on to the next module */

	return RLM_MODULE_OK;

}
Пример #20
0
/**
 * @brief Move pairs, replacing/over-writing them, and doing xlat.
 *
 *	Move attributes from one list to the other
 *	if not already present.
 */
void pairxlatmove(REQUEST *req, VALUE_PAIR **to, VALUE_PAIR **from)
{
	VALUE_PAIR **tailto, *i, *j, *next;
	VALUE_PAIR *tailfrom = NULL;
	VALUE_PAIR *found;

	/*
	 *	Point "tailto" to the end of the "to" list.
	 */
	tailto = to;
	for(i = *to; i; i = i->next) {
		tailto = &i->next;
	}

	/*
	 *	Loop over the "from" list.
	 */
	for(i = *from; i; i = next) {
		next = i->next;

		/*
		 *	Don't move 'fallthrough' over.
		 */
		if (i->attribute == PW_FALL_THROUGH) {
			tailfrom = i;
			continue;
		}

		/*
		 *	We've got to xlat the string before moving
		 *	it over.
		 */
		if (i->flags.do_xlat) {
			int rcode;
			char buffer[sizeof(i->vp_strvalue)];

			i->flags.do_xlat = 0;
			rcode = radius_xlat(buffer, sizeof(buffer),
					    i->vp_strvalue,
					    req, NULL);

			/*
			 *	Parse the string into a new value.
			 */
			pairparsevalue(i, buffer);
		}

		found = pairfind(*to, i->attribute, i->vendor);
		switch (i->operator) {

			/*
			 *  If a similar attribute is found,
			 *  delete it.
			 */
		case T_OP_SUB:		/* -= */
			if (found) {
				if (!i->vp_strvalue[0] ||
				    (strcmp((char *)found->vp_strvalue,
					    (char *)i->vp_strvalue) == 0)){
				  pairdelete(to, found->attribute, found->vendor);

					/*
					 *	'tailto' may have been
					 *	deleted...
					 */
					tailto = to;
					for(j = *to; j; j = j->next) {
						tailto = &j->next;
					}
				}
			}
			tailfrom = i;
			continue;
			break;

			/*
			 *  Add it, if it's not already there.
			 */
		case T_OP_EQ:		/* = */
			if (found) {
				tailfrom = i;
				continue; /* with the loop */
			}
			break;

			/*
			 *  If a similar attribute is found,
			 *  replace it with the new one.  Otherwise,
			 *  add the new one to the list.
			 */
		case T_OP_SET:		/* := */
			if (found) {
				VALUE_PAIR *vp;

				vp = found->next;
				memcpy(found, i, sizeof(*found));
				found->next = vp;
				tailfrom = i;
				continue;
			}
			break;

			/*
			 *  FIXME: Add support for <=, >=, <, >
			 *
			 *  which will mean (for integers)
			 *  'make the attribute the smaller, etc'
			 */

			/*
			 *  Add the new element to the list, even
			 *  if similar ones already exist.
			 */
		default:
		case T_OP_ADD:		/* += */
			break;
		}

		if (tailfrom)
			tailfrom->next = next;
		else
			*from = next;

		/*
		 *	If ALL of the 'to' attributes have been deleted,
		 *	then ensure that the 'tail' is updated to point
		 *	to the head.
		 */
		if (!*to) {
			tailto = to;
		}
		*tailto = i;
		if (i) {
			i->next = NULL;
			tailto = &i->next;
		}
	} /* loop over the 'from' list */
}
Пример #21
0
static rlm_rcode_t rlm_sql_process_groups(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t *handle,
					  bool *dofallthrough)
{
	rlm_rcode_t		rcode = RLM_MODULE_NOOP;
	VALUE_PAIR		*check_tmp = NULL, *reply_tmp = NULL, *sql_group = NULL;
	rlm_sql_grouplist_t	*head = NULL, *entry = NULL;

	char			*expanded = NULL;
	int			rows;

	rad_assert(request != NULL);
	rad_assert(request->packet != NULL);

	/*
	 *	Get the list of groups this user is a member of
	 */
	rows = sql_get_grouplist(inst, handle, request, &head);
	if (rows < 0) {
		REDEBUG("Error retrieving group list");

		return RLM_MODULE_FAIL;
	}
	if (rows == 0) {
		RDEBUG2("User not found in any groups");
		rcode = RLM_MODULE_NOTFOUND;
		goto finish;
	}

	RDEBUG2("User found in the group table");

	for (entry = head; entry != NULL && (*dofallthrough != 0); entry = entry->next) {
		/*
		 *	Add the Sql-Group attribute to the request list so we know
		 *	which group we're retrieving attributes for
		 */
		sql_group = pairmake_packet("Sql-Group", entry->name, T_OP_EQ);
		if (!sql_group) {
			REDEBUG("Error creating Sql-Group attribute");
			rcode = RLM_MODULE_FAIL;
			goto finish;
		}

		if (inst->config->authorize_group_check_query && (inst->config->authorize_group_check_query != '\0')) {
			/*
			 *	Expand the group query
			 */
			if (radius_axlat(&expanded, request, inst->config->authorize_group_check_query,
					 sql_escape_func, inst) < 0) {
				REDEBUG("Error generating query");
				rcode = RLM_MODULE_FAIL;
				goto finish;
			}

			rows = sql_getvpdata(inst, &handle, request, &check_tmp, expanded);
			TALLOC_FREE(expanded);
			if (rows < 0) {
				REDEBUG("Error retrieving check pairs for group %s", entry->name);
				rcode = RLM_MODULE_FAIL;
				goto finish;
			}

			/*
			 *	If we got check rows we need to process them before we decide to process the reply rows
			 */
			if ((rows > 0) &&
			    (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) != 0)) {
				pairfree(&check_tmp);
				pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);

				continue;
			}

			RDEBUG2("Group \"%s\" check items matched", entry->name);
			rcode = RLM_MODULE_OK;

			radius_pairmove(request, &request->config_items, check_tmp, true);
			check_tmp = NULL;
		}

		if (inst->config->authorize_group_reply_query && (inst->config->authorize_group_reply_query != '\0')) {
			/*
			 *	Now get the reply pairs since the paircompare matched
			 */
			if (radius_axlat(&expanded, request, inst->config->authorize_group_reply_query,
					 sql_escape_func, inst) < 0) {
				REDEBUG("Error generating query");
				rcode = RLM_MODULE_FAIL;
				goto finish;
			}

			rows = sql_getvpdata(inst, &handle, request->reply, &reply_tmp, expanded);
			TALLOC_FREE(expanded);
			if (rows < 0) {
				REDEBUG("Error retrieving reply pairs for group %s", entry->name);
				rcode = RLM_MODULE_FAIL;
				goto finish;
			}

			*dofallthrough = fallthrough(reply_tmp);

			RDEBUG2("Group \"%s\" reply items processed", entry->name);
			rcode = RLM_MODULE_OK;

			radius_pairmove(request, &request->reply->vps, reply_tmp, true);
			reply_tmp = NULL;
		}

		pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
	}

	finish:

	talloc_free(head);
	pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);

	return rcode;
}
Пример #22
0
/*
 *	Move attributes from one list to the other
 *	if not already present.
 */
void pairmove(VALUE_PAIR **to, VALUE_PAIR **from)
{
	VALUE_PAIR **tailto, *i, *j, *next;
	VALUE_PAIR *tailfrom = NULL;
	VALUE_PAIR *found;
	int has_password = 0;

	/*
	 *	First, see if there are any passwords here, and
	 *	point "tailto" to the end of the "to" list.
	 */
	tailto = to;
	for(i = *to; i; i = i->next) {
		if (i->attribute == PW_USER_PASSWORD ||
		    i->attribute == PW_CRYPT_PASSWORD)
			has_password = 1;
		tailto = &i->next;
	}

	/*
	 *	Loop over the "from" list.
	 */
	for(i = *from; i; i = next) {
		next = i->next;

		/*
		 *	If there was a password in the "to" list,
		 *	do not move any other password from the
		 *	"from" to the "to" list.
		 */
		if (has_password &&
		    (i->attribute == PW_USER_PASSWORD ||
		     i->attribute == PW_CRYPT_PASSWORD)) {
			tailfrom = i;
			continue;
		}

		switch (i->operator) {
			/*
			 *	These are COMPARISON attributes
			 *	from a check list, and are not
			 *	supposed to be copied!
			 */
			case T_OP_NE:
			case T_OP_GE:
			case T_OP_GT:
			case T_OP_LE:
			case T_OP_LT:
			case T_OP_CMP_TRUE:
			case T_OP_CMP_FALSE:
			case T_OP_CMP_EQ:
			case T_OP_REG_EQ:
			case T_OP_REG_NE:
				tailfrom = i;
				continue;

			default:
				break;
		}

		/*
		 *	If the attribute is already present in "to",
		 *	do not move it from "from" to "to". We make
		 *	an exception for "Hint" which can appear multiple
		 *	times, and we never move "Fall-Through".
		 */
		if (i->attribute == PW_FALL_THROUGH ||
		    (i->attribute != PW_HINT && i->attribute != PW_FRAMED_ROUTE)) {

			found = pairfind(*to, i->attribute);
			switch (i->operator) {

			  /*
			   *	If matching attributes are found,
			   *	delete them.
			   */
			case T_OP_SUB:		/* -= */
				if (found) {
					if (!i->vp_strvalue[0] ||
					    (strcmp((char *)found->vp_strvalue,
						    (char *)i->vp_strvalue) == 0)){
						pairdelete(to, found->attribute);

						/*
						 *	'tailto' may have been
						 *	deleted...
						 */
						tailto = to;
						for(j = *to; j; j = j->next) {
							tailto = &j->next;
						}
					}
				}
				tailfrom = i;
				continue;
				break;

/* really HAVE_REGEX_H */
#if 0
				/*
				 *  Attr-Name =~ "s/find/replace/"
				 *
				 *  Very bad code.  Barely working,
				 *  if at all.
				 */

			case T_OP_REG_EQ:
			  if (found &&
			      (i->vp_strvalue[0] == 's')) {
			    regex_t		reg;
			    regmatch_t		match[1];

			    char *str;
			    char *p, *q;

			    p = i->vp_strvalue + 1;
			    q = strchr(p + 1, *p);
			    if (!q || (q[strlen(q) - 1] != *p)) {
			      tailfrom = i;
			      continue;
			    }
			    str = strdup(i->vp_strvalue + 2);
			    q = strchr(str, *p);
			    *(q++) = '\0';
			    q[strlen(q) - 1] = '\0';

			    regcomp(&reg, str, 0);
			    if (regexec(&reg, found->vp_strvalue,
					1, match, 0) == 0) {
			      fprintf(stderr, "\"%s\" will have %d to %d replaced with %s\n",
				      found->vp_strvalue, match[0].rm_so,
				      match[0].rm_eo, q);

			    }
			    regfree(&reg);
			    free(str);
			  }
			  tailfrom = i;	/* don't copy it over */
			  continue;
			  break;
#endif
			case T_OP_EQ:		/* = */
				/*
				 *  FIXME: Tunnel attributes with
				 *  different tags are different
				 *  attributes.
				 */
				if (found) {
					tailfrom = i;
					continue; /* with the loop */
				}
				break;

			  /*
			   *  If a similar attribute is found,
			   *  replace it with the new one.  Otherwise,
			   *  add the new one to the list.
			   */
			case T_OP_SET:		/* := */
				if (found) {
					VALUE_PAIR *mynext = found->next;

					/*
					 *	Do NOT call pairdelete()
					 *	here, due to issues with
					 *	re-writing "request->username".
					 *
					 *	Everybody calls pairmove,
					 *	and expects it to work.
					 *	We can't update request->username
					 *	here, so instead we over-write
					 *	the vp that it's pointing to.
					 */
					memcpy(found, i, sizeof(*found));
					found->next = mynext;

					pairdelete(&found->next, found->attribute);

					/*
					 *	'tailto' may have been
					 *	deleted...
					 */
					for(j = found; j; j = j->next) {
						tailto = &j->next;
					}
					continue;
				}
				break;

			  /*
			   *  Add the new element to the list, even
			   *  if similar ones already exist.
			   */
			default:
			case T_OP_ADD: /* += */
				break;
			}
		}
		if (tailfrom)
			tailfrom->next = next;
		else
			*from = next;

		/*
		 *	If ALL of the 'to' attributes have been deleted,
		 *	then ensure that the 'tail' is updated to point
		 *	to the head.
		 */
		if (!*to) {
			tailto = to;
		}
		*tailto = i;
		if (i) {
			i->next = NULL;
			tailto = &i->next;
		}
	}
}
Пример #23
0
/*
 *	Move attributes from one list to the other
 *	if not already present.
 */
void pairmove(VALUE_PAIR **to, VALUE_PAIR **from)
{
	VALUE_PAIR **tailto, *i, *j, *next;
	VALUE_PAIR *tailfrom = NULL;
	VALUE_PAIR *found;
	int has_password = 0;

	/*
	 *	First, see if there are any passwords here, and
	 *	point "tailto" to the end of the "to" list.
	 */
	tailto = to;
	for(i = *to; i; i = i->next) {
		if (i->attribute == PW_USER_PASSWORD ||
		    i->attribute == PW_CRYPT_PASSWORD)
			has_password = 1;
		tailto = &i->next;
	}

	/*
	 *	Loop over the "from" list.
	 */
	for(i = *from; i; i = next) {
		next = i->next;

		/*
		 *	If there was a password in the "to" list,
		 *	do not move any other password from the
		 *	"from" to the "to" list.
		 */
		if (has_password &&
		    (i->attribute == PW_USER_PASSWORD ||
		     i->attribute == PW_CRYPT_PASSWORD)) {
			tailfrom = i;
			continue;
		}

		switch (i->operator) {
			/*
			 *	These are COMPARISON attributes
			 *	from a check list, and are not
			 *	supposed to be copied!
			 */
			case T_OP_NE:
			case T_OP_GE:
			case T_OP_GT:
			case T_OP_LE:
			case T_OP_LT:
			case T_OP_CMP_TRUE:
			case T_OP_CMP_FALSE:
			case T_OP_CMP_EQ:
			case T_OP_REG_EQ:
			case T_OP_REG_NE:
				tailfrom = i;
				continue;

			default:
				break;
		}

		/*
		 *	If the attribute is already present in "to",
		 *	do not move it from "from" to "to". We make
		 *	an exception for "Hint" which can appear multiple
		 *	times, and we never move "Fall-Through".
		 */
		if (i->attribute == PW_FALL_THROUGH ||
		    (i->attribute != PW_HINT && i->attribute != PW_FRAMED_ROUTE)) {

			found = pairfind(*to, i->attribute, i->vendor);
			switch (i->operator) {

			  /*
			   *	If matching attributes are found,
			   *	delete them.
			   */
			case T_OP_SUB:		/* -= */
				if (found) {
					if (!i->vp_strvalue[0] ||
					    (strcmp((char *)found->vp_strvalue,
						    (char *)i->vp_strvalue) == 0)){
						pairdelete(to, found->attribute, found->vendor, found->flags.tag);

						/*
						 *	'tailto' may have been
						 *	deleted...
						 */
						tailto = to;
						for(j = *to; j; j = j->next) {
							tailto = &j->next;
						}
					}
				}
				tailfrom = i;
				continue;
				break;

			case T_OP_EQ:		/* = */
				/*
				 *  FIXME: Tunnel attributes with
				 *  different tags are different
				 *  attributes.
				 */
				if (found) {
					tailfrom = i;
					continue; /* with the loop */
				}
				break;

			  /*
			   *  If a similar attribute is found,
			   *  replace it with the new one.  Otherwise,
			   *  add the new one to the list.
			   */
			case T_OP_SET:		/* := */
				if (found) {
					VALUE_PAIR *mynext = found->next;

					/*
					 *	Do NOT call pairdelete()
					 *	here, due to issues with
					 *	re-writing "request->username".
					 *
					 *	Everybody calls pairmove,
					 *	and expects it to work.
					 *	We can't update request->username
					 *	here, so instead we over-write
					 *	the vp that it's pointing to.
					 */
					memcpy(found, i, sizeof(*found));
					found->next = mynext;

					pairdelete(&found->next, found->attribute, found->vendor, found->flags.tag);

					/*
					 *	'tailto' may have been
					 *	deleted...
					 */
					for(j = found; j; j = j->next) {
						tailto = &j->next;
					}
					continue;
				}
				break;

			  /*
			   *  Add the new element to the list, even
			   *  if similar ones already exist.
			   */
			default:
			case T_OP_ADD: /* += */
				break;
			}
		}
		if (tailfrom)
			tailfrom->next = next;
		else
			*from = next;

		/*
		 *	If ALL of the 'to' attributes have been deleted,
		 *	then ensure that the 'tail' is updated to point
		 *	to the head.
		 */
		if (!*to) {
			tailto = to;
		}
		*tailto = i;
		if (i) {
			i->next = NULL;
			tailto = &i->next;
		}
	}
}
Пример #24
0
/*
 *	Process and reply to an authentication request
 *
 *	The return value of this function isn't actually used right now, so
 *	it's not entirely clear if it is returning the right things. --Pac.
 */
int rad_authenticate(REQUEST *request)
{
	VALUE_PAIR	*namepair;
#ifdef WITH_SESSION_MGMT
	VALUE_PAIR	*check_item;
#endif
	VALUE_PAIR	*auth_item = NULL;
	VALUE_PAIR	*module_msg;
	VALUE_PAIR	*tmp = NULL;
	int		result;
	const char	*password;
	char		autz_retry = 0;
	int		autz_type = 0;

	password = "";

#ifdef WITH_PROXY
	/*
	 *	If this request got proxied to another server, we need
	 *	to check whether it authenticated the request or not.
	 */
	if (request->proxy_reply) {
		switch (request->proxy_reply->code) {
		/*
		 *	Reply of ACCEPT means accept, thus set Auth-Type
		 *	accordingly.
		 */
		case PW_AUTHENTICATION_ACK:
			tmp = radius_paircreate(request,
						&request->config_items,
						PW_AUTH_TYPE, PW_TYPE_INTEGER);
			if (tmp) tmp->vp_integer = PW_AUTHTYPE_ACCEPT;
#ifdef WITH_POST_PROXY_AUTHORIZE
			if (mainconfig.post_proxy_authorize) break;
#endif
			goto authenticate;

		/*
		 *	Challenges are punted back to the NAS without any
		 *	further processing.
		 */
		case PW_ACCESS_CHALLENGE:
			request->reply->code = PW_ACCESS_CHALLENGE;
			return RLM_MODULE_OK;
		/*
		 *	ALL other replies mean reject. (this is fail-safe)
		 *
		 *	Do NOT do any authorization or authentication. They
		 *	are being rejected, so we minimize the amount of work
		 *	done by the server, by rejecting them here.
		 */
		case PW_AUTHENTICATION_REJECT:
			rad_authlog("Login incorrect (Home Server says so)",
				    request, 0);
			request->reply->code = PW_AUTHENTICATION_REJECT;
			return RLM_MODULE_REJECT;

		default:
			rad_authlog("Login incorrect (Home Server failed to respond)",
				    request, 0);
			return RLM_MODULE_REJECT;
		}
	}
#endif

	/*
	 *	Get the username from the request.
	 *
	 *	Note that namepair MAY be NULL, in which case there
	 *	is no User-Name attribute in the request.
	 */
	namepair = request->username;

	/*
	 *	Look for, and cache, passwords.
	 */
	if (!request->password) {
		request->password = pairfind(request->packet->vps,
					     PW_USER_PASSWORD);
	}

	/*
	 *	Discover which password we want to use.
	 */
	auth_item = request->password;
	if (auth_item) {
		password = (const char *)auth_item->vp_strvalue;

	} else {
		/*
		 *	Maybe there's a CHAP-Password?
		 */
		if ((auth_item = pairfind(request->packet->vps,
					  PW_CHAP_PASSWORD)) != NULL) {
			password = "******";

		} else {
			/*
			 *	No password we recognize.
			 */
			password = "******";
		}
	}
	request->password = auth_item;

	/*
	 *	Get the user's authorization information from the database
	 */
autz_redo:
	result = module_authorize(autz_type, request);
	switch (result) {
		case RLM_MODULE_NOOP:
		case RLM_MODULE_NOTFOUND:
		case RLM_MODULE_OK:
		case RLM_MODULE_UPDATED:
			break;
		case RLM_MODULE_HANDLED:
			return result;
		case RLM_MODULE_FAIL:
		case RLM_MODULE_INVALID:
		case RLM_MODULE_REJECT:
		case RLM_MODULE_USERLOCK:
		default:
			if ((module_msg = pairfind(request->packet->vps,
					PW_MODULE_FAILURE_MESSAGE)) != NULL) {
				char msg[MAX_STRING_LEN + 16];
				snprintf(msg, sizeof(msg), "Invalid user (%s)",
					 module_msg->vp_strvalue);
				rad_authlog(msg,request,0);
			} else {
				rad_authlog("Invalid user", request, 0);
			}
			request->reply->code = PW_AUTHENTICATION_REJECT;
			return result;
	}
	if (!autz_retry) {
		tmp = pairfind(request->config_items, PW_AUTZ_TYPE);
		if (tmp) {
			autz_type = tmp->vp_integer;
			RDEBUG2("Using Autz-Type %s",
				dict_valnamebyattr(PW_AUTZ_TYPE, autz_type));
			autz_retry = 1;
			goto autz_redo;
		}
	}

	/*
	 *	If we haven't already proxied the packet, then check
	 *	to see if we should.  Maybe one of the authorize
	 *	modules has decided that a proxy should be used. If
	 *	so, get out of here and send the packet.
	 */
	if (
#ifdef WITH_PROXY
	    (request->proxy == NULL) &&
#endif
	    ((tmp = pairfind(request->config_items, PW_PROXY_TO_REALM)) != NULL)) {
		REALM *realm;

		realm = realm_find2(tmp->vp_strvalue);

		/*
		 *	Don't authenticate, as the request is going to
		 *	be proxied.
		 */
		if (realm && realm->auth_pool) {
			return RLM_MODULE_OK;
		}

		/*
		 *	Catch users who set Proxy-To-Realm to a LOCAL
		 *	realm (sigh).  But don't complain if it is
		 *	*the* LOCAL realm.
		 */
		if (realm &&(strcmp(realm->name, "LOCAL") != 0)) {
			RDEBUG2("WARNING: You set Proxy-To-Realm = %s, but it is a LOCAL realm!  Cancelling proxy request.", realm->name);
		}

		if (!realm) {
			RDEBUG2("WARNING: You set Proxy-To-Realm = %s, but the realm does not exist!  Cancelling invalid proxy request.", tmp->vp_strvalue);
		}
	}

#ifdef WITH_PROXY
 authenticate:
#endif

	/*
	 *	Perhaps there is a Stripped-User-Name now.
	 */
	namepair = request->username;

	/*
	 *	Validate the user
	 */
	do {
		result = rad_check_password(request);
		if (result > 0) {
			/* don't reply! */
			return RLM_MODULE_HANDLED;
		}
	} while(0);

	/*
	 *	Failed to validate the user.
	 *
	 *	We PRESUME that the code which failed will clean up
	 *	request->reply->vps, to be ONLY the reply items it
	 *	wants to send back.
	 */
	if (result < 0) {
		RDEBUG2("Failed to authenticate the user.");
		request->reply->code = PW_AUTHENTICATION_REJECT;

		if ((module_msg = pairfind(request->packet->vps,PW_MODULE_FAILURE_MESSAGE)) != NULL){
			char msg[MAX_STRING_LEN+19];

			snprintf(msg, sizeof(msg), "Login incorrect (%s)",
				 module_msg->vp_strvalue);
			rad_authlog(msg, request, 0);
		} else {
			rad_authlog("Login incorrect", request, 0);
		}

		/* double check: maybe the secret is wrong? */
		if ((debug_flag > 1) && (auth_item != NULL) &&
				(auth_item->attribute == PW_USER_PASSWORD)) {
			uint8_t *p;

			p = (uint8_t *) auth_item->vp_strvalue;
			while (*p) {
				int size;

				size = fr_utf8_char(p);
				if (!size) {
					log_debug("  WARNING: Unprintable characters in the password.  Double-check the shared secret on the server and the NAS!");
					break;
				}
				p += size;
			}
		}
	}

#ifdef WITH_SESSION_MGMT
	if (result >= 0 &&
	    (check_item = pairfind(request->config_items, PW_SIMULTANEOUS_USE)) != NULL) {
		int r, session_type = 0;
		char		logstr[1024];
		char		umsg[MAX_STRING_LEN + 1];
		const char	*user_msg = NULL;

		tmp = pairfind(request->config_items, PW_SESSION_TYPE);
		if (tmp) {
			session_type = tmp->vp_integer;
			RDEBUG2("Using Session-Type %s",
				dict_valnamebyattr(PW_SESSION_TYPE, session_type));
		}

		/*
		 *	User authenticated O.K. Now we have to check
		 *	for the Simultaneous-Use parameter.
		 */
		if (namepair &&
		    (r = module_checksimul(session_type, request, check_item->vp_integer)) != 0) {
			char mpp_ok = 0;

			if (r == 2){
				/* Multilink attempt. Check if port-limit > simultaneous-use */
				VALUE_PAIR *port_limit;

				if ((port_limit = pairfind(request->reply->vps, PW_PORT_LIMIT)) != NULL &&
					port_limit->vp_integer > check_item->vp_integer){
					RDEBUG2("MPP is OK");
					mpp_ok = 1;
				}
			}
			if (!mpp_ok){
				if (check_item->vp_integer > 1) {
		  		snprintf(umsg, sizeof(umsg),
							"\r\nYou are already logged in %d times  - access denied\r\n\n",
							(int)check_item->vp_integer);
					user_msg = umsg;
				} else {
					user_msg = "\r\nYou are already logged in - access denied\r\n\n";
				}

				request->reply->code = PW_AUTHENTICATION_REJECT;

				/*
				 *	They're trying to log in too many times.
				 *	Remove ALL reply attributes.
				 */
				pairfree(&request->reply->vps);
				radius_pairmake(request, &request->reply->vps,
						"Reply-Message",
						user_msg, T_OP_SET);

				snprintf(logstr, sizeof(logstr), "Multiple logins (max %d) %s",
					check_item->vp_integer,
					r == 2 ? "[MPP attempt]" : "");
				rad_authlog(logstr, request, 1);

				result = -1;
			}
		}
	}
#endif

	/*
	 *	Result should be >= 0 here - if not, it means the user
	 *	is rejected, so we just process post-auth and return.
	 */
	if (result < 0) {
		return RLM_MODULE_REJECT;
	}

	/*
	 *	Add the port number to the Framed-IP-Address if
	 *	vp->addport is set.
	 */
	if (((tmp = pairfind(request->reply->vps,
			     PW_FRAMED_IP_ADDRESS)) != NULL) &&
	    (tmp->flags.addport != 0)) {
		VALUE_PAIR *vpPortId;

		/*
		 *  Find the NAS port ID.
		 */
		if ((vpPortId = pairfind(request->packet->vps,
					 PW_NAS_PORT)) != NULL) {
		  unsigned long tvalue = ntohl(tmp->vp_integer);
		  tmp->vp_integer = htonl(tvalue + vpPortId->vp_integer);
		  tmp->flags.addport = 0;
		  ip_ntoa(tmp->vp_strvalue, tmp->vp_integer);
		} else {
			RDEBUG2("WARNING: No NAS-Port attribute in request.  CANNOT return a Framed-IP-Address + NAS-Port.\n");
			pairdelete(&request->reply->vps, PW_FRAMED_IP_ADDRESS);
		}
	}

	/*
	 *	Set the reply to Access-Accept, if it hasn't already
	 *	been set to something.  (i.e. Access-Challenge)
	 */
	if (request->reply->code == 0)
	  request->reply->code = PW_AUTHENTICATION_ACK;

	if ((module_msg = pairfind(request->packet->vps,PW_MODULE_SUCCESS_MESSAGE)) != NULL){
		char msg[MAX_STRING_LEN+12];

		snprintf(msg, sizeof(msg), "Login OK (%s)",
			 module_msg->vp_strvalue);
		rad_authlog(msg, request, 1);
	} else {
		rad_authlog("Login OK", request, 1);
	}

	/*
	 *	Run the modules in the 'post-auth' section.
	 */
	result = rad_postauth(request);

	return result;
}
Пример #25
0
/*
 *	Check password.
 *
 *	Returns:	0  OK
 *			-1 Password fail
 *			-2 Rejected (Auth-Type = Reject, send Port-Message back)
 *			1  End check & return, don't reply
 *
 *	NOTE: NOT the same as the RLM_ values !
 */
static int rad_check_password(REQUEST *request)
{
	VALUE_PAIR *auth_type_pair;
	VALUE_PAIR *cur_config_item;
	VALUE_PAIR *password_pair;
	VALUE_PAIR *auth_item;
	uint8_t my_chap[MAX_STRING_LEN];
	int auth_type = -1;
	int result;
	int auth_type_count = 0;
	result = 0;

	/*
	 *	Look for matching check items. We skip the whole lot
	 *	if the authentication type is PW_AUTHTYPE_ACCEPT or
	 *	PW_AUTHTYPE_REJECT.
	 */
	cur_config_item = request->config_items;
	while(((auth_type_pair = pairfind(cur_config_item, PW_AUTH_TYPE))) != NULL) {

		auth_type = auth_type_pair->vp_integer;
		auth_type_count++;

		RDEBUG2("Found Auth-Type = %s",
			dict_valnamebyattr(PW_AUTH_TYPE,
					   auth_type_pair->vp_integer));
		cur_config_item = auth_type_pair->next;

		if (auth_type == PW_AUTHTYPE_REJECT) {
			RDEBUG2("Auth-Type = Reject, rejecting user");
			return -2;
		}
	}

	if (( auth_type_count > 1) && (debug_flag)) {
		radlog_request(L_ERR, 0, request, "Warning:  Found %d auth-types on request for user '%s'",
			auth_type_count, request->username->vp_strvalue);
	}

	/*
	 *	This means we have a proxy reply or an accept
	 *  and it wasn't rejected in the above loop.  So
	 *  that means it is accepted and we do no further
	 *  authentication
	 */
	if ((auth_type == PW_AUTHTYPE_ACCEPT)
#ifdef WITH_PROXY
	    || (request->proxy)
#endif
	    ) {
		RDEBUG2("Auth-Type = Accept, accepting the user");
		return 0;
	}

	password_pair =  pairfind(request->config_items, PW_USER_PASSWORD);
	if (password_pair &&
	    pairfind(request->config_items, PW_CLEARTEXT_PASSWORD)) {
		pairdelete(&request->config_items, PW_USER_PASSWORD);
		password_pair = NULL;
	}

	if (password_pair) {
		DICT_ATTR *da;

		RDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
		RDEBUG("!!!    Replacing User-Password in config items with Cleartext-Password.     !!!");
		RDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
		RDEBUG("!!! Please update your configuration so that the \"known good\"               !!!");
		RDEBUG("!!! clear text password is in Cleartext-Password, and not in User-Password. !!!");
		RDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!");
		password_pair->attribute = PW_CLEARTEXT_PASSWORD;
		da = dict_attrbyvalue(PW_CLEARTEXT_PASSWORD);
		if (!da) {
			radlog_request(L_ERR, 0, request, "FATAL: You broke the dictionaries.  Please use the default dictionaries!");
			_exit(1);
		}

		password_pair->name = da->name;
	}

	/*
	 *	Find the "known good" password.
	 *
	 *	FIXME: We should get rid of these hacks, and replace
	 *	them with a module.
	 */
	if ((password_pair = pairfind(request->config_items, PW_CRYPT_PASSWORD)) != NULL) {
		/*
		 *	Re-write Auth-Type, but ONLY if it isn't already
		 *	set.
		 */
		if (auth_type == -1) auth_type = PW_AUTHTYPE_CRYPT;
	} else {
		password_pair = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD);
	}

	if (auth_type < 0) {
		if (password_pair) {
			auth_type = PW_AUTHTYPE_LOCAL;
		} else {
			/*
		 	*	The admin hasn't told us how to
		 	*	authenticate the user, so we reject them!
		 	*
		 	*	This is fail-safe.
		 	*/
			RDEBUG2("ERROR: No authenticate method (Auth-Type) found for the request: Rejecting the user");
			return -2;
		}
	}

	switch(auth_type) {
		case PW_AUTHTYPE_CRYPT:
			RDEBUG2("WARNING: Please update your configuration, and remove 'Auth-Type = Crypt'");
			RDEBUG2("WARNING: Use the PAP module instead.");

			/*
			 *	Find the password sent by the user. It
			 *	SHOULD be there, if it's not
			 *	authentication fails.
			 */
			auth_item = request->password;
			if (auth_item == NULL) {
				RDEBUG2("No User-Password or CHAP-Password attribute in the request");
				return -1;
			}

			if (password_pair == NULL) {
				RDEBUG2("No Crypt-Password configured for the user");
				rad_authlog("Login incorrect "
					"(No Crypt-Password configured for the user)", request, 0);
				return -1;
			}

			switch (fr_crypt_check((char *)auth_item->vp_strvalue,
									 (char *)password_pair->vp_strvalue)) {
			case -1:
			  rad_authlog("Login incorrect "
						  "(system failed to supply an encrypted password for comparison)", request, 0);
			  /* FALL-THROUGH */
			case 1:
			  return -1;
			}
			break;
		case PW_AUTHTYPE_LOCAL:
			RDEBUG2("WARNING: Please update your configuration, and remove 'Auth-Type = Local'");
			RDEBUG2("WARNING: Use the PAP or CHAP modules instead.");

			/*
			 *	Find the password sent by the user. It
			 *	SHOULD be there, if it's not
			 *	authentication fails.
			 */
			auth_item = request->password;
			if (!auth_item)
				auth_item = pairfind(request->packet->vps,
						     PW_CHAP_PASSWORD);
			if (!auth_item) {
				RDEBUG2("No User-Password or CHAP-Password attribute in the request.");
				RDEBUG2("Cannot perform authentication.");
				return -1;
			}

			/*
			 *	Plain text password.
			 */
			if (password_pair == NULL) {
				RDEBUG2("No \"known good\" password was configured for the user.");
				RDEBUG2("As a result, we cannot authenticate the user.");
				rad_authlog("Login incorrect "
					"(No password configured for the user)", request, 0);
				return -1;
			}

			/*
			 *	Local password is just plain text.
	 		 */
			if (auth_item->attribute == PW_USER_PASSWORD) {
				if (strcmp((char *)password_pair->vp_strvalue,
					   (char *)auth_item->vp_strvalue) != 0) {
					RDEBUG2("User-Password in the request does NOT match \"known good\" password.");
					return -1;
				}
				RDEBUG2("User-Password in the request is correct.");
				break;

			} else if (auth_item->attribute != PW_CHAP_PASSWORD) {
				RDEBUG2("The user did not supply a User-Password or a CHAP-Password attribute");
				rad_authlog("Login incorrect "
					"(no User-Password or CHAP-Password attribute)", request, 0);
				return -1;
			}

			rad_chap_encode(request->packet, my_chap,
					auth_item->vp_octets[0], password_pair);

			/*
			 *	Compare them
			 */
			if (memcmp(my_chap + 1, auth_item->vp_strvalue + 1,
				   CHAP_VALUE_LENGTH) != 0) {
				RDEBUG2("CHAP-Password is incorrect.");
				return -1;
			}
			RDEBUG2("CHAP-Password is correct.");
			break;
		default:
			/*
			 *	See if there is a module that handles
			 *	this type, and turn the RLM_ return
			 *	status into the values as defined at
			 *	the top of this function.
			 */
			result = module_authenticate(auth_type, request);
			switch (result) {
				/*
				 *	An authentication module FAIL
				 *	return code, or any return code that
				 *	is not expected from authentication,
				 *	is the same as an explicit REJECT!
				 */
				case RLM_MODULE_FAIL:
				case RLM_MODULE_INVALID:
				case RLM_MODULE_NOOP:
				case RLM_MODULE_NOTFOUND:
				case RLM_MODULE_REJECT:
				case RLM_MODULE_UPDATED:
				case RLM_MODULE_USERLOCK:
				default:
					result = -1;
					break;
				case RLM_MODULE_OK:
					result = 0;
					break;
				case RLM_MODULE_HANDLED:
					result = 1;
					break;
			}
			break;
	}

	return result;
}
Пример #26
0
static int dhcp_process(REQUEST *request)
{
	int rcode;
	VALUE_PAIR *vp;

	vp = pairfind(request->packet->vps, 53, DHCP_MAGIC_VENDOR); /* DHCP-Message-Type */
	if (vp) {
		DICT_VALUE *dv = dict_valbyattr(53, DHCP_MAGIC_VENDOR, vp->vp_integer);
		DEBUG("Trying sub-section dhcp %s {...}",
		      dv->name ? dv->name : "<unknown>");
		rcode = module_post_auth(vp->vp_integer, request);
	} else {
		DEBUG("DHCP: Failed to find DHCP-Message-Type in packet!");
		rcode = RLM_MODULE_FAIL;
	}

	/*
	 *	For messages from a client, look for Relay attribute,
	 *	and forward it if necessary.
	 */
	vp = NULL;
	if (request->packet->data[0] == 1) {
		vp = pairfind(request->config_items, 270, DHCP_MAGIC_VENDOR);
	}
	if (vp) {
		VALUE_PAIR *giaddr;
		
		/*
		 *	Find the original giaddr.
		 *	FIXME: Maybe look in the original packet?
		 *
		 *	It's invalid to have giaddr=0 AND a relay option
		 */
		giaddr = pairfind(request->packet->vps, 266, DHCP_MAGIC_VENDOR);
		if (giaddr && (giaddr->vp_ipaddr == htonl(INADDR_ANY))) {
			if (pairfind(request->packet->vps, 82, DHCP_MAGIC_VENDOR)) {
				RDEBUG("DHCP: Received packet with giaddr = 0 and containing relay option: Discarding packet");
				return 1;
			}
		}

		if (request->packet->data[3] > 10) {
			RDEBUG("DHCP: Number of hops is greater than 10: not relaying");
			return 1;
		}

		/*
		 *	Forward a reply...
		 */
		pairfree(&request->reply->vps);
		request->reply->vps = paircopy(request->packet->vps);
		request->reply->code = request->packet->code;
		request->reply->id = request->packet->id;
		request->reply->src_ipaddr = request->packet->dst_ipaddr;
		request->reply->src_port = request->packet->dst_port;
		request->reply->dst_ipaddr.af = AF_INET;
		request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
		/*
		 *	Don't change the destination port.  It's the
		 *	server port.
		 */

		/*
		 *	Hop count goes up.
		 */
		vp = pairfind(request->reply->vps, 259, DHCP_MAGIC_VENDOR);
		if (vp) vp->vp_integer++;
		
		return 1;
	}

	/*
	 *	Responses from a server.  Handle them differently.
	 */
	if (request->packet->data[0] == 2) {
		pairfree(&request->reply->vps);
		request->reply->vps = paircopy(request->packet->vps);
		request->reply->code = request->packet->code;
		request->reply->id = request->packet->id;

		/*
		 *	Delete any existing giaddr.  If we received a
		 *	message from the server, then we're NOT the
		 *	server.  So we must be the destination of the
		 *	giaddr field.
		 */
		pairdelete(&request->packet->vps, 266, DHCP_MAGIC_VENDOR);

		/*
		 *	Search for client IP address.
		 */
		vp = pairfind(request->packet->vps, 264, DHCP_MAGIC_VENDOR);
		if (!vp) {
			request->reply->code = 0;
			RDEBUG("DHCP: No YIAddr in the reply. Discarding packet");
			return 1;
		}

		/*
		 *	FROM us, TO the client's IP, OUR port + 1.
		 */
		request->reply->src_ipaddr = request->packet->dst_ipaddr;
		request->reply->src_port = request->packet->dst_port;
		request->reply->dst_ipaddr.af = AF_INET;
		request->reply->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
		request->reply->dst_port = request->packet->dst_port + 1;

		/*
		 *	Hop count goes down.
		 */
		vp = pairfind(request->reply->vps, 259, DHCP_MAGIC_VENDOR);
		if (vp && (vp->vp_integer > 0)) vp->vp_integer--;

		/*
		 *	FIXME: Keep original somewhere?  If the
		 *	broadcast flags are set, use them here?
		 */
		
		return 1;
	}

	vp = pairfind(request->reply->vps, 53, DHCP_MAGIC_VENDOR); /* DHCP-Message-Type */
	if (vp) {
		request->reply->code = vp->vp_integer;
		if ((request->reply->code != 0) &&
		    (request->reply->code < PW_DHCP_OFFSET)) {
			request->reply->code += PW_DHCP_OFFSET;
		}
	}
	else switch (rcode) {
	case RLM_MODULE_OK:
	case RLM_MODULE_UPDATED:
		if (request->packet->code == PW_DHCP_DISCOVER) {
			request->reply->code = PW_DHCP_OFFER;
			break;

		} else if (request->packet->code == PW_DHCP_REQUEST) {
			request->reply->code = PW_DHCP_ACK;
			break;
		}
		request->reply->code = PW_DHCP_NAK;
		break;

	default:
	case RLM_MODULE_REJECT:
	case RLM_MODULE_FAIL:
	case RLM_MODULE_INVALID:
	case RLM_MODULE_NOOP:
	case RLM_MODULE_NOTFOUND:	
		if (request->packet->code == PW_DHCP_DISCOVER) {
			request->reply->code = 0; /* ignore the packet */
		} else {
			request->reply->code = PW_DHCP_NAK;
		}
		break;

	case RLM_MODULE_HANDLED:
		break;
	}

	/*
	 *	Releases don't get replies.
	 */
	if (request->packet->code == PW_DHCP_RELEASE) {
		request->reply->code = 0;
	}

	return 1;
}
Пример #27
0
int main(int argc, char **argv)
{
	RADIUS_PACKET *req;
	char *p;
	int c;
	uint16_t port = 0;
	char *filename = NULL;
	FILE *fp;
	int id;
	int force_af = AF_UNSPEC;

	static fr_log_t radclient_log = {
		.colourise = true,
		.fd = STDOUT_FILENO,
		.dst = L_DST_STDOUT,
		.file = NULL,
		.debug_file = NULL,
	};

	radlog_init(&radclient_log, false);

	/*
	 *	We probably don't want to free the talloc autofree context
	 *	directly, so we'll allocate a new context beneath it, and
	 *	free that before any leak reports.
	 */
	TALLOC_CTX *autofree = talloc_init("main");

	id = ((int)getpid() & 0xff);
	fr_debug_flag = 0;

	set_radius_dir(autofree, RADIUS_DIR);

	while ((c = getopt(argc, argv, "46c:d:D:f:hi:qst:r:S:xXv")) != EOF)
	{
		switch(c) {
		case '4':
			force_af = AF_INET;
			break;
		case '6':
			force_af = AF_INET6;
			break;
		case 'd':
			set_radius_dir(autofree, optarg);
			break;
		case 'D':
			main_config.dictionary_dir = talloc_typed_strdup(NULL, optarg);
			break;
		case 'f':
			filename = optarg;
			break;
		case 'q':
			do_output = 0;
			break;
		case 'x':
			debug_flag++;
			fr_debug_flag++;
			break;

		case 'X':
#if 0
		  sha1_data_problems = 1; /* for debugging only */
#endif
		  break;



		case 'r':
			if (!isdigit((int) *optarg))
				usage();
			retries = atoi(optarg);
			break;
		case 'i':
			if (!isdigit((int) *optarg))
				usage();
			id = atoi(optarg);
			if ((id < 0) || (id > 255)) {
				usage();
			}
			break;
		case 's':
			do_summary = 1;
			break;
		case 't':
			if (!isdigit((int) *optarg))
				usage();
			timeout = atof(optarg);
			break;
		case 'v':
			printf("radeapclient: $Id: 69643e042c5a7c9053977756a5623e3c07598f2e $ built on " __DATE__ " at " __TIME__ "\n");
			exit(0);
			break;
	       case 'S':
		       fp = fopen(optarg, "r");
		       if (!fp) {
			       fprintf(stderr, "radclient: Error opening %s: %s\n",
				       optarg, fr_syserror(errno));
			       exit(1);
		       }
		       if (fgets(filesecret, sizeof(filesecret), fp) == NULL) {
			       fprintf(stderr, "radclient: Error reading %s: %s\n",
				       optarg, fr_syserror(errno));
			       exit(1);
		       }
		       fclose(fp);

		       /* truncate newline */
		       p = filesecret + strlen(filesecret) - 1;
		       while ((p >= filesecret) &&
			      (*p < ' ')) {
			       *p = '\0';
			       --p;
		       }

		       if (strlen(filesecret) < 2) {
			       fprintf(stderr, "radclient: Secret in %s is too short\n", optarg);
			       exit(1);
		       }
		       secret = filesecret;
		       break;
		case 'h':
		default:
			usage();
			break;
		}
	}
	argc -= (optind - 1);
	argv += (optind - 1);

	if ((argc < 3)  ||
	    ((!secret) && (argc < 4))) {
		usage();
	}

	if (!main_config.dictionary_dir) {
		main_config.dictionary_dir = DICTDIR;
	}

	/*
	 *	Read the distribution dictionaries first, then
	 *	the ones in raddb.
	 */
	DEBUG2("including dictionary file %s/%s", main_config.dictionary_dir, RADIUS_DICTIONARY);
	if (dict_init(main_config.dictionary_dir, RADIUS_DICTIONARY) != 0) {
		ERROR("Errors reading dictionary: %s",
		      fr_strerror());
		exit(1);
	}

	/*
	 *	It's OK if this one doesn't exist.
	 */
	int rcode = dict_read(radius_dir, RADIUS_DICTIONARY);
	if (rcode == -1) {
		ERROR("Errors reading %s/%s: %s", radius_dir, RADIUS_DICTIONARY,
		      fr_strerror());
		exit(1);
	}

	/*
	 *	We print this after reading it.  That way if
	 *	it doesn't exist, it's OK, and we don't print
	 *	anything.
	 */
	if (rcode == 0) {
		DEBUG2("including dictionary file %s/%s", radius_dir, RADIUS_DICTIONARY);
	}

	req = rad_alloc(NULL, 1);
	if (!req) {
		fr_perror("radclient");
		exit(1);
	}

#if 0
	{
		FILE *randinit;

		if((randinit = fopen("/dev/urandom", "r")) == NULL)
		{
			perror("/dev/urandom");
		} else {
			fread(randctx.randrsl, 256, 1, randinit);
			fclose(randinit);
		}
	}
	fr_randinit(&randctx, 1);
#endif

	req->id = id;

	/*
	 *	Resolve hostname.
	 */
	if (force_af == AF_UNSPEC) force_af = AF_INET;
	req->dst_ipaddr.af = force_af;
	if (strcmp(argv[1], "-") != 0) {
		char const *hostname = argv[1];
		char const *portname = argv[1];
		char buffer[256];

		if (*argv[1] == '[') { /* IPv6 URL encoded */
			p = strchr(argv[1], ']');
			if ((size_t) (p - argv[1]) >= sizeof(buffer)) {
				usage();
			}

			memcpy(buffer, argv[1] + 1, p - argv[1] - 1);
			buffer[p - argv[1] - 1] = '\0';

			hostname = buffer;
			portname = p + 1;

		}
		p = strchr(portname, ':');
		if (p && (strchr(p + 1, ':') == NULL)) {
			*p = '\0';
			portname = p + 1;
		} else {
			portname = NULL;
		}

		if (ip_hton(&req->dst_ipaddr, force_af, hostname, false) < 0) {
			fprintf(stderr, "radclient: Failed to find IP address for host %s: %s\n", hostname, fr_syserror(errno));
			exit(1);
		}

		/*
		 *	Strip port from hostname if needed.
		 */
		if (portname) port = atoi(portname);
	}

	/*
	 *	See what kind of request we want to send.
	 */
	if (strcmp(argv[2], "auth") == 0) {
		if (port == 0) port = getport("radius");
		if (port == 0) port = PW_AUTH_UDP_PORT;
		req->code = PW_CODE_AUTHENTICATION_REQUEST;

	} else if (strcmp(argv[2], "acct") == 0) {
		if (port == 0) port = getport("radacct");
		if (port == 0) port = PW_ACCT_UDP_PORT;
		req->code = PW_CODE_ACCOUNTING_REQUEST;
		do_summary = 0;

	} else if (strcmp(argv[2], "status") == 0) {
		if (port == 0) port = getport("radius");
		if (port == 0) port = PW_AUTH_UDP_PORT;
		req->code = PW_CODE_STATUS_SERVER;

	} else if (strcmp(argv[2], "disconnect") == 0) {
		if (port == 0) port = PW_POD_UDP_PORT;
		req->code = PW_CODE_DISCONNECT_REQUEST;

	} else if (isdigit((int) argv[2][0])) {
		if (port == 0) port = getport("radius");
		if (port == 0) port = PW_AUTH_UDP_PORT;
		req->code = atoi(argv[2]);
	} else {
		usage();
	}
	req->dst_port = port;

	/*
	 *	Add the secret.
	 */
	if (argv[3]) secret = argv[3];

	/*
	 *	Read valuepairs.
	 *	Maybe read them, from stdin, if there's no
	 *	filename, or if the filename is '-'.
	 */
	if (filename && (strcmp(filename, "-") != 0)) {
		fp = fopen(filename, "r");
		if (!fp) {
			fprintf(stderr, "radclient: Error opening %s: %s\n",
				filename, fr_syserror(errno));
			exit(1);
		}
	} else {
		fp = stdin;
	}

	/*
	 *	Send request.
	 */
	if ((req->sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
		perror("radclient: socket: ");
		exit(1);
	}

	while(!filedone) {
		if (req->vps) pairfree(&req->vps);
		if (readvp2(&req->vps, NULL, fp, &filedone) < 0) {
			fr_perror("radeapclient");
			break;
		}

		sendrecv_eap(req);
	}

	if(do_summary) {
		printf("\n\t   Total approved auths:  %d\n", totalapp);
		printf("\t     Total denied auths:  %d\n", totaldeny);
	}

	talloc_free(autofree);

	return 0;
}

/*
 * given a radius request with some attributes in the EAP range, build
 * them all into a single EAP-Message body.
 *
 * Note that this function will build multiple EAP-Message bodies
 * if there are multiple eligible EAP-types. This is incorrect, as the
 * recipient will in fact concatenate them.
 *
 * XXX - we could break the loop once we process one type. Maybe this
 *       just deserves an assert?
 *
 */
static void map_eap_methods(RADIUS_PACKET *req)
{
	VALUE_PAIR *vp, *vpnext;
	int id, eapcode;
	int eap_method;

	eap_packet_t *pt_ep = talloc_zero(req, eap_packet_t);

	vp = pairfind(req->vps, ATTRIBUTE_EAP_ID, 0, TAG_ANY);
	if(!vp) {
		id = ((int)getpid() & 0xff);
	} else {
		id = vp->vp_integer;
	}

	vp = pairfind(req->vps, ATTRIBUTE_EAP_CODE, 0, TAG_ANY);
	if(!vp) {
		eapcode = PW_EAP_REQUEST;
	} else {
		eapcode = vp->vp_integer;
	}

	for(vp = req->vps; vp != NULL; vp = vpnext) {
		/* save it in case it changes! */
		vpnext = vp->next;

		if(vp->da->attr >= ATTRIBUTE_EAP_BASE &&
		   vp->da->attr < ATTRIBUTE_EAP_BASE+256) {
			break;
		}
	}

	if(!vp) {
		return;
	}

	eap_method = vp->da->attr - ATTRIBUTE_EAP_BASE;

	switch(eap_method) {
	case PW_EAP_IDENTITY:
	case PW_EAP_NOTIFICATION:
	case PW_EAP_NAK:
	case PW_EAP_MD5:
	case PW_EAP_OTP:
	case PW_EAP_GTC:
	case PW_EAP_TLS:
	case PW_EAP_LEAP:
	case PW_EAP_TTLS:
	case PW_EAP_PEAP:
	default:
		/*
		 * no known special handling, it is just encoded as an
		 * EAP-message with the given type.
		 */

		/* nuke any existing EAP-Messages */
		pairdelete(&req->vps, PW_EAP_MESSAGE, 0, TAG_ANY);

		pt_ep->code = eapcode;
		pt_ep->id = id;
		pt_ep->type.num = eap_method;
		pt_ep->type.length = vp->length;

		pt_ep->type.data = talloc_memdup(vp, vp->vp_octets, vp->length);
		talloc_set_type(pt_ep->type.data, uint8_t);

		eap_basic_compose(req, pt_ep);
	}
}
/*
 *  	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;
	}
}
Пример #29
0
static int rlm_sql_process_groups(rlm_sql_t *inst, REQUEST *request, rlm_sql_handle_t *handle, int *dofallthrough)
{
	VALUE_PAIR *check_tmp = NULL;
	VALUE_PAIR *reply_tmp = NULL;
	rlm_sql_grouplist_t *group_list, *group_list_tmp;
	VALUE_PAIR *sql_group = NULL;
	char    querystr[MAX_QUERY_LEN];
	int found = 0;
	int rows;

	/*
	 *	Get the list of groups this user is a member of
	 */
	if (sql_get_grouplist(inst, handle, request, &group_list) < 0) {
		radlog_request(L_ERR, 0, request, "Error retrieving group list");
		return -1;
	}

	for (group_list_tmp = group_list; group_list_tmp != NULL && *dofallthrough != 0; group_list_tmp = group_list_tmp->next) {
		/*
		 *	Add the Sql-Group attribute to the request list so we know
		 *	which group we're retrieving attributes for
		 */
		sql_group = pairmake("Sql-Group", group_list_tmp->groupname, T_OP_EQ);
		if (!sql_group) {
			radlog_request(L_ERR, 0, request,
				       "Error creating Sql-Group attribute");
			sql_grouplist_free(&group_list);
			return -1;
		}
		pairadd(&request->packet->vps, sql_group);
		if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_check_query, request, sql_escape_func, inst)) {
			radlog_request(L_ERR, 0, request,
				       "Error generating query; rejecting user");
			/* Remove the grouup we added above */
			pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
			sql_grouplist_free(&group_list);
			return -1;
		}
		rows = sql_getvpdata(inst, &handle, &check_tmp, querystr);
		if (rows < 0) {
			radlog_request(L_ERR, 0, request, "Error retrieving check pairs for group %s",
			       group_list_tmp->groupname);
			/* Remove the grouup we added above */
			pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
			pairfree(&check_tmp);
			sql_grouplist_free(&group_list);
			return -1;
		} else if (rows > 0) {
			/*
			 *	Only do this if *some* check pairs were returned
			 */
			if (paircompare(request, request->packet->vps, check_tmp, &request->reply->vps) == 0) {
				found = 1;
				RDEBUG2("User found in group %s",
					group_list_tmp->groupname);
				/*
				 *	Now get the reply pairs since the paircompare matched
				 */
				if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_reply_query, request, sql_escape_func, inst)) {
					radlog_request(L_ERR, 0, request, "Error generating query; rejecting user");
					/* Remove the grouup we added above */
					pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
					pairfree(&check_tmp);
					sql_grouplist_free(&group_list);
					return -1;
				}
				if (sql_getvpdata(inst, &handle, &reply_tmp, querystr) < 0) {
					radlog_request(L_ERR, 0, request, "Error retrieving reply pairs for group %s",
					       group_list_tmp->groupname);
					/* Remove the grouup we added above */
					pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
					pairfree(&check_tmp);
					pairfree(&reply_tmp);
					sql_grouplist_free(&group_list);
					return -1;
				}
				*dofallthrough = fallthrough(reply_tmp);
				radius_xlat_move(request, &request->reply->vps, &reply_tmp);
				radius_xlat_move(request, &request->config_items, &check_tmp);
			}
		} else {
			/*
			 *	rows == 0.  This is like having the username on a line
			 * 	in the user's file with no check vp's.  As such, we treat
			 *	it as found and add the reply attributes, so that we
			 *	match expected behavior
			 */
			found = 1;
			RDEBUG2("User found in group %s",
				group_list_tmp->groupname);
			/*
			 *	Now get the reply pairs since the paircompare matched
			 */
			if (!radius_xlat(querystr, sizeof(querystr), inst->config->authorize_group_reply_query, request, sql_escape_func, inst)) {
				radlog_request(L_ERR, 0, request, "Error generating query; rejecting user");
				/* Remove the grouup we added above */
				pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
				pairfree(&check_tmp);
				sql_grouplist_free(&group_list);
				return -1;
			}
			if (sql_getvpdata(inst, &handle, &reply_tmp, querystr) < 0) {
				radlog_request(L_ERR, 0, request, "Error retrieving reply pairs for group %s",
				       group_list_tmp->groupname);
				/* Remove the grouup we added above */
				pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
				pairfree(&check_tmp);
				pairfree(&reply_tmp);
				sql_grouplist_free(&group_list);
				return -1;
			}
			*dofallthrough = fallthrough(reply_tmp);
			radius_xlat_move(request, &request->reply->vps, &reply_tmp);
			radius_xlat_move(request, &request->config_items, &check_tmp);
		}

		/*
		 * Delete the Sql-Group we added above
		 * And clear out the pairlists
		 */
		pairdelete(&request->packet->vps, PW_SQL_GROUP, 0, TAG_ANY);
		pairfree(&check_tmp);
		pairfree(&reply_tmp);
	}

	sql_grouplist_free(&group_list);
	return found;
}
Пример #30
0
/*
 *	Generate the keys after the user has been authenticated.
 */
static int wimax_postauth(void *instance, REQUEST *request)
{
    rlm_wimax_t *inst = instance;
    VALUE_PAIR *msk, *emsk, *vp;
    VALUE_PAIR *mn_nai, *ip, *fa_rk;
    HMAC_CTX hmac;
    unsigned int rk1_len, rk2_len, rk_len;
    int rk_lifetime = 3600;	/* ? */
    uint32_t mip_spi;
    uint8_t usage_data[24];
    uint8_t mip_rk_1[EVP_MAX_MD_SIZE], mip_rk_2[EVP_MAX_MD_SIZE];
    uint8_t mip_rk[2 * EVP_MAX_MD_SIZE];

    msk = pairfind(request->reply->vps, 1129);
    emsk = pairfind(request->reply->vps, 1130);
    if (!msk || !emsk) {
        RDEBUG("No EAP-MSK or EAP-EMSK.  Cannot create WiMAX keys.");
        return RLM_MODULE_NOOP;
    }

    /*
     *	If we delete the MS-MPPE-*-Key attributes, then add in
     *	the WiMAX-MSK so that the client has a key available.
     */
    if (inst->delete_mppe_keys) {
        pairdelete(&request->reply->vps, ((311 << 16) | 16));
        pairdelete(&request->reply->vps, ((311 << 16) | 17));

        vp = radius_pairmake(request, &request->reply->vps, "WiMAX-MSK", "0x00", T_OP_EQ);
        if (vp) {
            memcpy(vp->vp_octets, msk->vp_octets, msk->length);
            vp->length = msk->length;
        }
    }

    /*
     *	Initialize usage data.
     */
    memcpy(usage_data, "*****@*****.**", 21);	/* with trailing \0 */
    usage_data[21] = 0x02;
    usage_data[22] = 0x00;
    usage_data[23] = 0x01;

    /*
     *	MIP-RK-1 = HMAC-SSHA256(EMSK, usage-data | 0x01)
     */
    HMAC_CTX_init(&hmac);
    HMAC_Init_ex(&hmac, emsk->vp_octets, emsk->length, EVP_sha256(), NULL);

    HMAC_Update(&hmac, &usage_data[0], sizeof(usage_data));
    HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);

    /*
     *	MIP-RK-2 = HMAC-SSHA256(EMSK, MIP-RK-1 | usage-data | 0x01)
     */
    HMAC_CTX_init(&hmac);
    HMAC_Init_ex(&hmac, emsk->vp_octets, emsk->length, EVP_sha256(), NULL);

    HMAC_Update(&hmac, (const uint8_t *) &mip_rk_1, rk1_len);
    HMAC_Update(&hmac, &usage_data[0], sizeof(usage_data));
    HMAC_Final(&hmac, &mip_rk_2[0], &rk2_len);

    vp = pairfind(request->reply->vps, PW_SESSION_TIMEOUT);
    if (vp) rk_lifetime = vp->vp_integer;

    memcpy(mip_rk, mip_rk_1, rk1_len);
    memcpy(mip_rk + rk1_len, mip_rk_2, rk2_len);
    rk_len = rk1_len + rk2_len;

    /*
     *	MIP-SPI = HMAC-SSHA256(MIP-RK, "SPI CMIP PMIP");
     */
    HMAC_CTX_init(&hmac);
    HMAC_Init_ex(&hmac, mip_rk, rk_len, EVP_sha256(), NULL);

    HMAC_Update(&hmac, (const uint8_t *) "SPI CMIP PMIP", 12);
    HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);

    /*
     *	Take the 4 most significant octets.
     *	If less than 256, add 256.
     */
    mip_spi = ((mip_rk_1[0] << 24) | (mip_rk_1[1] << 16) |
               (mip_rk_1[2] << 8) | mip_rk_1[3]);
    if (mip_spi < 256) mip_spi += 256;

    if (debug_flag) {
        int len = rk_len;
        char buffer[512];

        if (len > 128) len = 128; /* buffer size */

        fr_bin2hex(mip_rk, buffer, len);
        radlog_request(L_DBG, 0, request, "MIP-RK = 0x%s", buffer);
        radlog_request(L_DBG, 0, request, "MIP-SPI = %08x",
                       ntohl(mip_spi));
    }

    /*
     *	FIXME: Perform SPI collision prevention
     */

    /*
     *	Calculate mobility keys
     */
    mn_nai = pairfind(request->packet->vps, 1900);
    if (!mn_nai) mn_nai = pairfind(request->reply->vps, 1900);
    if (!mn_nai) {
        RDEBUG("WARNING: WiMAX-MN-NAI was not found in the request or in the reply.");
        RDEBUG("WARNING: We cannot calculate MN-HA keys.");
    }

    /*
     *	WiMAX-IP-Technology
     */
    vp = NULL;
    if (mn_nai) vp = pairfind(request->reply->vps, WIMAX2ATTR(23));
    if (!vp) {
        RDEBUG("WARNING: WiMAX-IP-Technology not found in reply.");
        RDEBUG("WARNING: Not calculating MN-HA keys");
    }

    if (vp) switch (vp->vp_integer) {
        case 2:			/* PMIP4 */
            /*
             *	Look for WiMAX-hHA-IP-MIP4
             */
            ip = pairfind(request->reply->vps, WIMAX2ATTR(6));
            if (!ip) {
                RDEBUG("WARNING: WiMAX-hHA-IP-MIP4 not found.  Cannot calculate MN-HA-PMIP4 key");
                break;
            }

            /*
             *	MN-HA-PMIP4 =
             *	   H(MIP-RK, "PMIP4 MN HA" | HA-IPv4 | MN-NAI);
             */
            HMAC_CTX_init(&hmac);
            HMAC_Init_ex(&hmac, mip_rk, rk_len, EVP_sha1(), NULL);

            HMAC_Update(&hmac, (const uint8_t *) "PMIP4 MN HA", 11);
            HMAC_Update(&hmac, (const uint8_t *) &ip->vp_ipaddr, 4);
            HMAC_Update(&hmac, (const uint8_t *) &mn_nai->vp_strvalue, mn_nai->length);
            HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);

            /*
             *	Put MN-HA-PMIP4 into WiMAX-MN-hHA-MIP4-Key
             */
            vp = pairfind(request->reply->vps, WIMAX2ATTR(10));
            if (!vp) {
                vp = radius_paircreate(request, &request->reply->vps,
                                       WIMAX2ATTR(10), PW_TYPE_OCTETS);
            }
            if (!vp) {
                RDEBUG("WARNING: Failed creating WiMAX-MN-hHA-MIP4-Key");
                break;
            }
            memcpy(vp->vp_octets, &mip_rk_1[0], rk1_len);
            vp->length = rk1_len;

            /*
             *	Put MN-HA-PMIP4-SPI into WiMAX-MN-hHA-MIP4-SPI
             */
            vp = pairfind(request->reply->vps, WIMAX2ATTR(11));
            if (!vp) {
                vp = radius_paircreate(request, &request->reply->vps,
                                       WIMAX2ATTR(11), PW_TYPE_INTEGER);
            }
            if (!vp) {
                RDEBUG("WARNING: Failed creating WiMAX-MN-hHA-MIP4-SPI");
                break;
            }
            vp->vp_integer = mip_spi + 1;
            break;

        case 3:			/* CMIP4 */
            /*
             *	Look for WiMAX-hHA-IP-MIP4
             */
            ip = pairfind(request->reply->vps, WIMAX2ATTR(6));
            if (!ip) {
                RDEBUG("WARNING: WiMAX-hHA-IP-MIP4 not found.  Cannot calculate MN-HA-CMIP4 key");
                break;
            }

            /*
             *	MN-HA-CMIP4 =
             *	   H(MIP-RK, "CMIP4 MN HA" | HA-IPv4 | MN-NAI);
             */
            HMAC_CTX_init(&hmac);
            HMAC_Init_ex(&hmac, mip_rk, rk_len, EVP_sha1(), NULL);

            HMAC_Update(&hmac, (const uint8_t *) "CMIP4 MN HA", 11);
            HMAC_Update(&hmac, (const uint8_t *) &ip->vp_ipaddr, 4);
            HMAC_Update(&hmac, (const uint8_t *) &mn_nai->vp_strvalue, mn_nai->length);
            HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);

            /*
             *	Put MN-HA-CMIP4 into WiMAX-MN-hHA-MIP4-Key
             */
            vp = pairfind(request->reply->vps, WIMAX2ATTR(10));
            if (!vp) {
                vp = radius_paircreate(request, &request->reply->vps,
                                       WIMAX2ATTR(10), PW_TYPE_OCTETS);
            }
            if (!vp) {
                RDEBUG("WARNING: Failed creating WiMAX-MN-hHA-MIP4-Key");
                break;
            }
            memcpy(vp->vp_octets, &mip_rk_1[0], rk1_len);
            vp->length = rk1_len;

            /*
             *	Put MN-HA-CMIP4-SPI into WiMAX-MN-hHA-MIP4-SPI
             */
            vp = pairfind(request->reply->vps, WIMAX2ATTR(11));
            if (!vp) {
                vp = radius_paircreate(request, &request->reply->vps,
                                       WIMAX2ATTR(11), PW_TYPE_INTEGER);
            }
            if (!vp) {
                RDEBUG("WARNING: Failed creating WiMAX-MN-hHA-MIP4-SPI");
                break;
            }
            vp->vp_integer = mip_spi;
            break;

        case 4:			/* CMIP6 */
            /*
             *	Look for WiMAX-hHA-IP-MIP6
             */
            ip = pairfind(request->reply->vps, WIMAX2ATTR(7));
            if (!ip) {
                RDEBUG("WARNING: WiMAX-hHA-IP-MIP6 not found.  Cannot calculate MN-HA-CMIP6 key");
                break;
            }

            /*
             *	MN-HA-CMIP6 =
             *	   H(MIP-RK, "CMIP6 MN HA" | HA-IPv6 | MN-NAI);
             */
            HMAC_CTX_init(&hmac);
            HMAC_Init_ex(&hmac, mip_rk, rk_len, EVP_sha1(), NULL);

            HMAC_Update(&hmac, (const uint8_t *) "CMIP6 MN HA", 11);
            HMAC_Update(&hmac, (const uint8_t *) &ip->vp_ipv6addr, 16);
            HMAC_Update(&hmac, (const uint8_t *) &mn_nai->vp_strvalue, mn_nai->length);
            HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);

            /*
             *	Put MN-HA-CMIP6 into WiMAX-MN-hHA-MIP6-Key
             */
            vp = pairfind(request->reply->vps, WIMAX2ATTR(12));
            if (!vp) {
                vp = radius_paircreate(request, &request->reply->vps,
                                       WIMAX2ATTR(12), PW_TYPE_OCTETS);
            }
            if (!vp) {
                RDEBUG("WARNING: Failed creating WiMAX-MN-hHA-MIP6-Key");
                break;
            }
            memcpy(vp->vp_octets, &mip_rk_1[0], rk1_len);
            vp->length = rk1_len;

            /*
             *	Put MN-HA-CMIP6-SPI into WiMAX-MN-hHA-MIP6-SPI
             */
            vp = pairfind(request->reply->vps, WIMAX2ATTR(13));
            if (!vp) {
                vp = radius_paircreate(request, &request->reply->vps,
                                       WIMAX2ATTR(13), PW_TYPE_INTEGER);
            }
            if (!vp) {
                RDEBUG("WARNING: Failed creating WiMAX-MN-hHA-MIP6-SPI");
                break;
            }
            vp->vp_integer = mip_spi + 2;
            break;

        default:
            break;		/* do nothing */
        }

    /*
     *	Generate FA-RK, if requested.
     *
     *	FA-RK= H(MIP-RK, "FA-RK")
     */
    fa_rk = pairfind(request->reply->vps, WIMAX2ATTR(14));
    if (fa_rk && (fa_rk->length == 0)) {
        HMAC_CTX_init(&hmac);
        HMAC_Init_ex(&hmac, mip_rk, rk_len, EVP_sha1(), NULL);

        HMAC_Update(&hmac, (const uint8_t *) "FA-RK", 5);

        HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);

        memcpy(fa_rk->vp_octets, &mip_rk_1[0], rk1_len);
        fa_rk->length = rk1_len;
    }

    /*
     *	Create FA-RK-SPI, which is really SPI-CMIP4, which is
     *	really MIP-SPI.  Clear?  Of course.  This is WiMAX.
     */
    if (fa_rk) {
        vp = pairfind(request->reply->vps, WIMAX2ATTR(61));
        if (!vp) {
            vp = radius_paircreate(request, &request->reply->vps,
                                   WIMAX2ATTR(61), PW_TYPE_INTEGER);
        }
        if (!vp) {
            RDEBUG("WARNING: Failed creating WiMAX-FA-RK-SPI");
        } else {
            vp->vp_integer = mip_spi;
        }
    }

    /*
     *	Generate MN-FA = H(FA-RK, "MN FA" | FA-IP | MN-NAI)
     */
    ip = pairfind(request->reply->vps, 1901);
    if (fa_rk && ip && mn_nai) {
        HMAC_CTX_init(&hmac);
        HMAC_Init_ex(&hmac, fa_rk->vp_octets, fa_rk->length,
                     EVP_sha1(), NULL);

        HMAC_Update(&hmac, (const uint8_t *) "MN FA", 5);
        HMAC_Update(&hmac, (const uint8_t *) &ip->vp_ipaddr, 4);
        HMAC_Update(&hmac, (const uint8_t *) &mn_nai->vp_strvalue, mn_nai->length);

        HMAC_Final(&hmac, &mip_rk_1[0], &rk1_len);

        vp = radius_paircreate(request, &request->reply->vps,
                               1902, PW_TYPE_OCTETS);
        if (!vp) {
            RDEBUG("WARNING: Failed creating WiMAX-MN-FA");
        } else {
            memcpy(vp->vp_octets, &mip_rk_1[0], rk1_len);
            vp->length = rk1_len;
        }
    }

    /*
     *	Give additional information about requests && responses
     *
     *	WiMAX-RRQ-MN-HA-SPI
     */
    vp = pairfind(request->packet->vps, WIMAX2ATTR(20));
    if (vp) {
        RDEBUG("Client requested MN-HA key: Should use SPI to look up key from storage.");
        if (!mn_nai) {
            RDEBUG("WARNING: MN-NAI was not found!");
        }

        /*
         *	WiMAX-RRQ-HA-IP
         */
        if (!pairfind(request->packet->vps, WIMAX2ATTR(18))) {
            RDEBUG("WARNING: HA-IP was not found!");
        }


        /*
         *	WiMAX-HA-RK-Key-Requested
         */
        vp = pairfind(request->packet->vps, WIMAX2ATTR(58));
        if (vp && (vp->vp_integer == 1)) {
            RDEBUG("Client requested HA-RK: Should use IP to look it up from storage.");
        }
    }

    /*
     *	Wipe the context of all sensitive information.
     */
    HMAC_CTX_cleanup(&hmac);

    return RLM_MODULE_UPDATED;
}