Esempio n. 1
0
static FR_CODE eap_fast_eap_payload(REQUEST *request, eap_session_t *eap_session,
				    tls_session_t *tls_session, VALUE_PAIR *tlv_eap_payload)
{
	FR_CODE			code = FR_CODE_ACCESS_REJECT;
	rlm_rcode_t		rcode;
	VALUE_PAIR		*vp;
	eap_fast_tunnel_t	*t;
	REQUEST			*fake;

	RDEBUG2("Processing received EAP Payload");

	/*
	 * Allocate a fake REQUEST structure.
	 */
	fake = request_alloc_fake(request, NULL);
	rad_assert(!fake->packet->vps);

	t = talloc_get_type_abort(tls_session->opaque, eap_fast_tunnel_t);

	/*
	 * Add the tunneled attributes to the fake request.
	 */

	fake->packet->vps = fr_pair_afrom_da(fake->packet, attr_eap_message);
	fr_pair_value_memcpy(fake->packet->vps, tlv_eap_payload->vp_octets, tlv_eap_payload->vp_length, false);

	RDEBUG2("Got tunneled request");
	log_request_pair_list(L_DBG_LVL_1, request, fake->packet->vps, NULL);

	/*
	 * Tell the request that it's a fake one.
	 */
	MEM(fr_pair_add_by_da(fake->packet, &vp, &fake->packet->vps, attr_freeradius_proxied_to) >= 0);
	fr_pair_value_from_str(vp, "127.0.0.1", sizeof("127.0.0.1"), '\0', false);

	/*
	 * Update other items in the REQUEST data structure.
	 */
	fake->username = fr_pair_find_by_da(fake->packet->vps, attr_user_name, TAG_ANY);
	fake->password = fr_pair_find_by_da(fake->packet->vps, attr_user_password, 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 = fr_pair_find_by_da(fake->packet->vps, attr_eap_message, TAG_ANY);
			if (vp &&
			    (vp->vp_length >= EAP_HEADER_LEN + 2) &&
			    (vp->vp_strvalue[0] == FR_EAP_CODE_RESPONSE) &&
			    (vp->vp_strvalue[EAP_HEADER_LEN] == FR_EAP_METHOD_IDENTITY) &&
			    (vp->vp_strvalue[EAP_HEADER_LEN + 1] != 0)) {
				/*
				 * Create & remember a User-Name
				 */
				MEM(t->username = fr_pair_afrom_da(t, attr_user_name));
				t->username->vp_tainted = true;
				fr_pair_value_bstrncpy(t->username, vp->vp_octets + 5, vp->vp_length - 5);

				RDEBUG2("Got tunneled identity of %pV", &t->username->data);
			} else {
				/*
				 * Don't reject the request outright,
				 * as it's permitted to do EAP without
				 * user-name.
				 */
				RWDEBUG2("No EAP-Identity found to start EAP conversation");
			}
		} /* else there WAS a t->username */

		if (t->username) {
			vp = fr_pair_copy(fake->packet, t->username);
			fr_pair_add(&fake->packet->vps, vp);
			fake->username = vp;
		}
	} /* else the request ALREADY had a User-Name */

	if (t->stage == EAP_FAST_AUTHENTICATION) {	/* FIXME do this only for MSCHAPv2 */
		VALUE_PAIR *tvp;

		tvp = fr_pair_afrom_da(fake, attr_eap_type);
		tvp->vp_uint32 = t->default_provisioning_method;
		fr_pair_add(&fake->control, tvp);

		/*
		 * RFC 5422 section 3.2.3 - Authenticating Using EAP-FAST-MSCHAPv2
		 */
		if (t->mode == EAP_FAST_PROVISIONING_ANON) {
			tvp = fr_pair_afrom_da(fake, attr_ms_chap_challenge);
			fr_pair_value_memcpy(tvp, t->keyblock->server_challenge, RADIUS_CHAP_CHALLENGE_LENGTH, false);
			fr_pair_add(&fake->control, tvp);
			RHEXDUMP(L_DBG_LVL_MAX, t->keyblock->server_challenge, RADIUS_CHAP_CHALLENGE_LENGTH, "MSCHAPv2 auth_challenge");

			tvp = fr_pair_afrom_da(fake, attr_ms_chap_peer_challenge);
			fr_pair_value_memcpy(tvp, t->keyblock->client_challenge, RADIUS_CHAP_CHALLENGE_LENGTH, false);
			fr_pair_add(&fake->control, tvp);
			RHEXDUMP(L_DBG_LVL_MAX, t->keyblock->client_challenge, RADIUS_CHAP_CHALLENGE_LENGTH, "MSCHAPv2 peer_challenge");
		}
	}

	/*
	 * Call authentication recursively, which will
	 * do PAP, CHAP, MS-CHAP, etc.
	 */
	eap_virtual_server(request, fake, eap_session, t->virtual_server);

	/*
	 * Decide what to do with the reply.
	 */
	switch (fake->reply->code) {
	case 0:			/* No reply code, must be proxied... */
#ifdef WITH_PROXY
		vp = fr_pair_find_by_da(fake->control, attr_proxy_to_realm, TAG_ANY);
		if (vp) {
			int			ret;
			eap_tunnel_data_t	*tunnel;

			RDEBUG2("Tunneled authentication will be proxied to %pV", &vp->data);

			/*
			 *	Tell the original request that it's going to be proxied.
			 */
			fr_pair_list_copy_by_da(request, &request->control, fake->control, attr_proxy_to_realm);

			/*
			 *	Seed the proxy packet with the tunneled request.
			 */
			rad_assert(!request->proxy);

			/*
			 *	FIXME: Actually proxy stuff
			 */
			request->proxy = request_alloc_fake(request, NULL);

			request->proxy->packet = talloc_steal(request->proxy, fake->packet);
			memset(&request->proxy->packet->src_ipaddr, 0,
			       sizeof(request->proxy->packet->src_ipaddr));
			memset(&request->proxy->packet->src_ipaddr, 0,
			       sizeof(request->proxy->packet->src_ipaddr));
			request->proxy->packet->src_port = 0;
			request->proxy->packet->dst_port = 0;
			fake->packet = NULL;
			fr_radius_packet_free(&fake->reply);
			fake->reply = NULL;

			/*
			 *	Set up the callbacks for the tunnel
			 */
			tunnel = talloc_zero(request, eap_tunnel_data_t);
			tunnel->tls_session = tls_session;

			/*
			 *	Associate the callback with the request.
			 */
			ret = request_data_add(request, request->proxy, REQUEST_DATA_EAP_TUNNEL_CALLBACK,
					       tunnel, false, false, false);
			fr_cond_assert(ret == 0);

			/*
			 *	rlm_eap.c has taken care of associating the eap_session
			 *	with the fake request.
			 *
			 *	So we associate the fake request with this request.
			 */
			ret = request_data_add(request, request->proxy, REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK,
					       fake, true, false, false);
			fr_cond_assert(ret == 0);

			fake = NULL;

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

		} else
#endif	/* WITH_PROXY */
		  {
			  REDEBUG("No tunneled reply was found, and the request was not proxied: rejecting the user");
			  code = FR_CODE_ACCESS_REJECT;
		  }
		break;

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

		case RLM_MODULE_HANDLED:
			code = FR_CODE_ACCESS_CHALLENGE;
			break;

		case RLM_MODULE_OK:
			code = FR_CODE_ACCESS_ACCEPT;
			break;

		default:
			code = FR_CODE_ACCESS_REJECT;
			break;
		}
		break;
	}

	talloc_free(fake);

	return code;
}
Esempio n. 2
0
/*
 *	Initialize the request.
 */
static RADIUS_PACKET *request_init(char const *filename)
{
	FILE *fp;
	fr_cursor_t cursor;
	VALUE_PAIR *vp;
	bool filedone = false;
	RADIUS_PACKET *request;

	/*
	 *	Determine where to read the VP's from.
	 */
	if (filename) {
		fp = fopen(filename, "r");
		if (!fp) {
			ERROR("Error opening %s: %s", filename, fr_syserror(errno));
			return NULL;
		}
	} else {
		fp = stdin;
	}

	request = fr_radius_alloc(NULL, false);
	/*
	 *	Read the VP's.
	 */
	if (fr_pair_list_afrom_file(NULL, dict_dhcpv4, &request->vps, fp, &filedone) < 0) {
		fr_perror("dhcpclient");
		fr_radius_packet_free(&request);
		if (fp != stdin) fclose(fp);
		return NULL;
	}

	/*
	 *	Fix / set various options
	 */
	for (vp = fr_cursor_init(&cursor, &request->vps);
	     vp;
	     vp = fr_cursor_next(&cursor)) {

		/*
		 *	Xlat expansions are not supported. Convert xlat to value box (if possible).
		 */
		if (vp->type == VT_XLAT) {
			fr_type_t type = vp->da->type;
			if (fr_value_box_from_str(vp, &vp->data, &type, NULL, vp->xlat, -1, '\0', false) < 0) {
				fr_perror("dhcpclient");
				fr_radius_packet_free(&request);
				if (fp != stdin) fclose(fp);
				return NULL;
			}
			vp->type = VT_DATA;
		}

		/*
		 *	Allow to set packet type using DHCP-Message-Type
		 */
	     	if (vp->da == attr_dhcp_message_type) {
	     		request->code = vp->vp_uint8;

		/*
		 *	Allow it to set the packet type in
		 *	the attributes read from the file.
		 *	(this takes precedence over the command argument.)
		 */
	     	} else if (vp->da == attr_packet_type) {
	     		request->code = vp->vp_uint32;

		} else if (vp->da == attr_packet_dst_port) {
			request->dst_port = vp->vp_uint16;

		} else if ((vp->da == attr_packet_dst_ip_address) ||
			   (vp->da == attr_packet_dst_ipv6_address)) {
			memcpy(&request->dst_ipaddr, &vp->vp_ip, sizeof(request->src_ipaddr));

		} else if (vp->da == attr_packet_src_port) {
			request->src_port = vp->vp_uint16;

		} else if ((vp->da == attr_packet_src_ip_address) ||
			   (vp->da == attr_packet_src_ipv6_address)) {
			memcpy(&request->src_ipaddr, &vp->vp_ip, sizeof(request->src_ipaddr));
		} /* switch over the attribute */

	} /* loop over the VP's we read in */

	if (fp != stdin) fclose(fp);

	/*
	 *	And we're done.
	 */
	return request;
}
Esempio n. 3
0
/*
 *	For a client, receive a DHCP packet from a raw packet
 *	socket. Make sure it matches the ongoing request.
 *
 *	FIXME: split this into two, recv_raw_packet, and verify(packet, original)
 */
RADIUS_PACKET *fr_dhcv4_raw_packet_recv(int sockfd, struct sockaddr_ll *link_layer, RADIUS_PACKET *request)
{
	VALUE_PAIR		*vp;
	RADIUS_PACKET		*packet;
	uint8_t const		*code;
	uint32_t		magic, xid;
	ssize_t			data_len;

	uint8_t			*raw_packet;
	ethernet_header_t	*eth_hdr;
	ip_header_t		*ip_hdr;
	udp_header_t		*udp_hdr;
	dhcp_packet_t		*dhcp_hdr;
	uint16_t		udp_src_port;
	uint16_t		udp_dst_port;
	size_t			dhcp_data_len;
	socklen_t		sock_len;

	packet = fr_radius_alloc(NULL, false);
	if (!packet) {
		fr_strerror_printf("Failed allocating packet");
		return NULL;
	}

	raw_packet = talloc_zero_array(packet, uint8_t, MAX_PACKET_SIZE);
	if (!raw_packet) {
		fr_strerror_printf("Out of memory");
		fr_radius_packet_free(&packet);
		return NULL;
	}

	packet->sockfd = sockfd;

	/* a packet was received (but maybe it is not for us) */
	sock_len = sizeof(struct sockaddr_ll);
	data_len = recvfrom(sockfd, raw_packet, MAX_PACKET_SIZE, 0, (struct sockaddr *)link_layer, &sock_len);

	uint8_t data_offset = ETH_HDR_SIZE + IP_HDR_SIZE + UDP_HDR_SIZE; /* DHCP data datas after Ethernet, IP, UDP */

	if (data_len <= data_offset) DISCARD_RP("Payload (%d) smaller than required for layers 2+3+4", (int)data_len);

	/* map raw packet to packet header of the different layers (Ethernet, IP, UDP) */
	eth_hdr = (ethernet_header_t *)raw_packet;

	/*
	 *	Check Ethernet layer data (L2)
	 */
	if (ntohs(eth_hdr->ether_type) != ETH_TYPE_IP) DISCARD_RP("Ethernet type (%d) != IP",
	    ntohs(eth_hdr->ether_type));

	/*
	 *	If Ethernet destination is not broadcast (ff:ff:ff:ff:ff:ff)
	 *	Check if it matches the source HW address used (DHCP-Client-Hardware-Address = 267)
	 */
	if ((memcmp(&eth_bcast, &eth_hdr->ether_dst, ETH_ADDR_LEN) != 0) &&
	    (vp = fr_pair_find_by_da(request->vps, attr_dhcp_client_hardware_address, TAG_ANY)) &&
	    ((vp->vp_type == FR_TYPE_ETHERNET) && (memcmp(vp->vp_ether, &eth_hdr->ether_dst, ETH_ADDR_LEN) != 0))) {

		/* No match. */
		DISCARD_RP("Ethernet destination (%pV) is not broadcast and doesn't match request source (%pV)",
			   fr_box_ether(eth_hdr->ether_dst), &vp->data);
	}

	/*
	 *	Ethernet is OK.  Now look at IP.
	 */
	ip_hdr = (ip_header_t *)(raw_packet + ETH_HDR_SIZE);

	/*
	 *	Check IPv4 layer data (L3)
	 */
	if (ip_hdr->ip_p != IPPROTO_UDP) DISCARD_RP("IP protocol (%d) != UDP", ip_hdr->ip_p);

	/*
	 *	note: checking the destination IP address is not
	 *	useful (it would be the offered IP address - which we
	 *	don't know beforehand, or the broadcast address).
	 */

	/*
	 *	Now check UDP.
	 */
	udp_hdr = (udp_header_t *)(raw_packet + ETH_HDR_SIZE + IP_HDR_SIZE);

	/*
	 *	Check UDP layer data (L4)
	 */
	udp_src_port = ntohs(udp_hdr->src);
	udp_dst_port = ntohs(udp_hdr->dst);

	/*
	 *	Check DHCP layer data
	 */
	dhcp_data_len = data_len - data_offset;

	if (dhcp_data_len < MIN_PACKET_SIZE) DISCARD_RP("DHCP packet is too small (%zu < %i)",
							dhcp_data_len, MIN_PACKET_SIZE);
	if (dhcp_data_len > MAX_PACKET_SIZE) DISCARD_RP("DHCP packet is too large (%zu > %i)",
							dhcp_data_len, MAX_PACKET_SIZE);

	dhcp_hdr = (dhcp_packet_t *)(raw_packet + ETH_HDR_SIZE + IP_HDR_SIZE + UDP_HDR_SIZE);

	if (dhcp_hdr->htype != 1) DISCARD_RP("DHCP hardware type (%d) != Ethernet (1)", dhcp_hdr->htype);
	if (dhcp_hdr->hlen != 6) DISCARD_RP("DHCP hardware address length (%d) != 6", dhcp_hdr->hlen);

	magic = ntohl(dhcp_hdr->option_format);

	if (magic != DHCP_OPTION_MAGIC_NUMBER) DISCARD_RP("DHCP magic cookie (0x%04x) != DHCP (0x%04x)",
							  magic, DHCP_OPTION_MAGIC_NUMBER);

	/*
	 *	Reply transaction id must match value from request.
	 */
	xid = ntohl(dhcp_hdr->xid);
	if (xid != (uint32_t)request->id) DISCARD_RP("DHCP transaction ID (0x%04x) != xid from request (0x%04x)",
						     xid, request->id)

	/* all checks ok! this is a DHCP reply we're interested in. */
	packet->data_len = dhcp_data_len;
	packet->data = talloc_memdup(packet, raw_packet + data_offset, dhcp_data_len);
	TALLOC_FREE(raw_packet);
	packet->id = xid;

	code = fr_dhcpv4_packet_get_option((dhcp_packet_t const *) packet->data,
					   packet->data_len, attr_dhcp_message_type);
	if (!code) {
		fr_strerror_printf("No message-type option was found in the packet");
		fr_radius_packet_free(&packet);
		return NULL;
	}

	if ((code[1] < 1) || (code[2] == 0) || (code[2] > 8)) {
		fr_strerror_printf("Unknown value for message-type option");
		fr_radius_packet_free(&packet);
		return NULL;
	}

	packet->code = code[2];

	/*
	 *	Create a unique vector from the MAC address and the
	 *	DHCP opcode.  This is a hack for the RADIUS
	 *	infrastructure in the rest of the server.
	 *
	 *	Note: packet->data[2] == 6, which is smaller than
	 *	sizeof(packet->vector)
	 *
	 *	FIXME:  Look for client-identifier in packet,
	 *      and use that, too?
	 */
	memset(packet->vector, 0, sizeof(packet->vector));
	memcpy(packet->vector, packet->data + 28, packet->data[2]);
	packet->vector[packet->data[2]] = packet->code & 0xff;

	packet->src_port = udp_src_port;
	packet->dst_port = udp_dst_port;

	packet->src_ipaddr.af = AF_INET;
	packet->src_ipaddr.addr.v4.s_addr = ip_hdr->ip_src.s_addr;
	packet->dst_ipaddr.af = AF_INET;
	packet->dst_ipaddr.addr.v4.s_addr = ip_hdr->ip_dst.s_addr;

	return packet;
}
Esempio n. 4
0
/*
 *	Check if an incoming request is "ok"
 *
 *	It takes packets, not requests.  It sees if the packet looks
 *	OK.  If so, it does a number of sanity checks on it.
 */
static int arp_socket_recv(rad_listen_t *listener)
{
	int ret;
	arp_socket_t *sock = listener->data;
	pcap_t *handle = sock->lsock.pcap->handle;

	const uint8_t *data;
	struct pcap_pkthdr *header;
	ssize_t link_len;

	arp_over_ether_t const *arp;
	RADIUS_PACKET *packet;

	ret = pcap_next_ex(handle, &header, &data);
	if (ret == 0) {
		DEBUG("No packet retrieved from pcap.");
		return 0; /* no packet */
	}

	if (ret < 0) {
		ERROR("Error requesting next packet, got (%i): %s", ret, pcap_geterr(handle));
		return 0;
	}

	link_len = fr_pcap_link_layer_offset(data, header->caplen, sock->lsock.pcap->link_layer);
	if (link_len < 0) {
		PERROR("Failed determining link layer header offset");
		return 0;
	}

	/*
	 *	Silently ignore it if it's too small to be ARP.
	 *
	 *	This can happen when pcap gets overloaded and starts truncating packets.
	 */
	if (header->caplen < (link_len + sizeof(*arp))) {
		ERROR("Packet too small, we require at least %zu bytes, got %i bytes",
		      link_len + sizeof(*arp), header->caplen);
		return 0;
	}

	data += link_len;
	arp = (arp_over_ether_t const *) data;

	if (ntohs(arp->htype) != ARPHRD_ETHER) return 0;

	if (ntohs(arp->ptype) != 0x0800) return 0;

	if (arp->hlen != ETHER_ADDR_LEN) return 0; /* FIXME: malformed error */

	if (arp->plen != 4) return 0; /* FIXME: malformed packet error */

	packet = talloc_zero(NULL, RADIUS_PACKET);
	if (!packet) return 0;

	packet->dst_port = 1;	/* so it's not a "fake" request */
	packet->data_len = header->caplen - link_len;
	packet->data = talloc_memdup(packet, arp, packet->data_len);
	talloc_set_type(packet->data, uint8_t);

	DEBUG("ARP received on interface %s", sock->lsock.interface);

	if (!request_receive(NULL, listener, packet, &sock->client, arp_process)) {
		fr_radius_packet_free(&packet);
		return 0;
	}

	return 1;
}