1 /*
2  * rlm_eap_ttls.c  contains the interfaces that are called from eap
3  *
4  * Version:     $Id: cbe423951a7a27f5da1ded6eb12fd7e9587ccaed $
5  *
6  *   This program is free software; you can redistribute it and/or modify
7  *   it under the terms of the GNU General Public License as published by
8  *   the Free Software Foundation; either version 2 of the License, or
9  *   (at your option) any later version.
10  *
11  *   This program is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *   GNU General Public License for more details.
15  *
16  *   You should have received a copy of the GNU General Public License
17  *   along with this program; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  *   Copyright 2003 Alan DeKok <aland@freeradius.org>
21  *   Copyright 2006 The FreeRADIUS server project
22  */
23 
24 RCSID("$Id: cbe423951a7a27f5da1ded6eb12fd7e9587ccaed $")
25 
26 #include "eap_ttls.h"
27 #include "eap_chbind.h"
28 
29 /*
30  *    0                   1                   2                   3
31  *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
32  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33  *   |                           AVP Code                            |
34  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
35  *   |V M r r r r r r|                  AVP Length                   |
36  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
37  *   |                        Vendor-ID (opt)                        |
38  *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39  *   |    Data ...
40  *   +-+-+-+-+-+-+-+-+
41  */
42 
43 /*
44  *	Verify that the diameter packet is valid.
45  */
diameter_verify(REQUEST * request,uint8_t const * data,unsigned int data_len)46 static int diameter_verify(REQUEST *request, uint8_t const *data, unsigned int data_len)
47 {
48 	uint32_t attr;
49 	uint32_t length;
50 	unsigned int hdr_len;
51 	unsigned int remaining = data_len;
52 
53 	while (remaining > 0) {
54 		hdr_len = 12;
55 
56 		if (remaining < hdr_len) {
57 		  RDEBUG2("Diameter attribute is too small (%u) to contain a Diameter header", remaining);
58 			return 0;
59 		}
60 
61 		memcpy(&attr, data, sizeof(attr));
62 		attr = ntohl(attr);
63 		memcpy(&length, data + 4, sizeof(length));
64 		length = ntohl(length);
65 
66 		if ((data[4] & 0x80) != 0) {
67 			if (remaining < 16) {
68 				RDEBUG2("Diameter attribute is too small to contain a Diameter header with Vendor-Id");
69 				return 0;
70 			}
71 
72 			hdr_len = 16;
73 		}
74 
75 		/*
76 		 *	Get the length.  If it's too big, die.
77 		 */
78 		length &= 0x00ffffff;
79 
80 		/*
81 		 *	Too short or too long is bad.
82 		 */
83 		if (length <= (hdr_len - 4)) {
84 			RDEBUG2("Tunneled attribute %u is too short (%u < %u) to contain anything useful.", attr,
85 				length, hdr_len);
86 			return 0;
87 		}
88 
89 		if (length > remaining) {
90 			RDEBUG2("Tunneled attribute %u is longer than room remaining in the packet (%u > %u).", attr,
91 				length, remaining);
92 			return 0;
93 		}
94 
95 		/*
96 		 *	Check for broken implementations, which don't
97 		 *	pad the AVP to a 4-octet boundary.
98 		 */
99 		if (remaining == length) break;
100 
101 		/*
102 		 *	The length does NOT include the padding, so
103 		 *	we've got to account for it here by rounding up
104 		 *	to the nearest 4-byte boundary.
105 		 */
106 		length += 0x03;
107 		length &= ~0x03;
108 
109 		/*
110 		 *	If the rest of the diameter packet is larger than
111 		 *	this attribute, continue.
112 		 *
113 		 *	Otherwise, if the attribute over-flows the end
114 		 *	of the packet, die.
115 		 */
116 		if (remaining < length) {
117 			REDEBUG2("Diameter attribute overflows packet!");
118 			return 0;
119 		}
120 
121 		/*
122 		 *	remaining > length, continue.
123 		 */
124 		remaining -= length;
125 		data += length;
126 	}
127 
128 	/*
129 	 *	We got this far.  It looks OK.
130 	 */
131 	return 1;
132 }
133 
134 
135 /*
136  *	Convert diameter attributes to our VALUE_PAIR's
137  */
diameter2vp(REQUEST * request,REQUEST * fake,SSL * ssl,uint8_t const * data,size_t data_len)138 static VALUE_PAIR *diameter2vp(REQUEST *request, REQUEST *fake, SSL *ssl,
139 			       uint8_t const *data, size_t data_len)
140 {
141 	uint32_t	attr;
142 	uint32_t	vendor;
143 	uint32_t	length;
144 	size_t		offset;
145 	size_t		size;
146 	size_t		data_left = data_len;
147 	VALUE_PAIR	*first = NULL;
148 	VALUE_PAIR	*vp = NULL;
149 	RADIUS_PACKET	*packet = fake->packet; /* FIXME: api issues */
150 	vp_cursor_t	out;
151 	DICT_ATTR const *da;
152 
153 	fr_cursor_init(&out, &first);
154 
155 	/*
156 	 *	Parse while there's still data.
157 	 */
158 	while (data_left >= 9) {
159 		size_t attr_len;
160 
161 		rad_assert(data_left <= data_len);
162 		memcpy(&attr, data, sizeof(attr));
163 		data += 4;
164 		attr = ntohl(attr);
165 		vendor = 0;
166 
167 		memcpy(&length, data, sizeof(length));
168 		data += 4;
169 		length = ntohl(length);
170 
171 		/*
172 		 *	Length is *value* length.  The actual
173 		 *	attributes are aligned on 4 octets.
174 		 */
175 		attr_len = length & 0x00ffffff;
176 		attr_len += 0x03;
177 		attr_len &= ~(uint32_t) 0x03;
178 
179 		/*
180 		 *	A "vendor" flag, with a vendor ID of zero,
181 		 *	is equivalent to no vendor.  This is stupid.
182 		 */
183 		offset = 8;
184 		if ((length & ((uint32_t)1 << 31)) != 0) {
185 			memcpy(&vendor, data, sizeof(vendor));
186 			vendor = ntohl(vendor);
187 
188 			data += 4; /* skip the vendor field, it's zero */
189 			offset += 4; /* offset to value field */
190 
191 			if (attr > 65535) {
192 				DEBUG("Skipping Diameter attribute %08x", attr);
193 				goto next_attr;
194 			}
195 			if (vendor > FR_MAX_VENDOR) {
196 				DEBUG("Skipping large vendor ID %08x", vendor);
197 				goto next_attr;
198 			}
199 		}
200 
201 		/*
202 		 *	FIXME: Handle the M bit.  For now, we assume that
203 		 *	some other module takes care of any attribute
204 		 *	with the M bit set.
205 		 */
206 
207 		/*
208 		 *	Get the length.
209 		 */
210 		length &= 0x00ffffff;
211 
212 		/*
213 		 *	Get the size of the value portion of the
214 		 *	attribute.
215 		 */
216 		size = length - offset;
217 
218 		/*
219 		 *	Vendor attributes can be larger than 255.
220 		 *	Normal attributes cannot be.
221 		 */
222 		if ((attr > 255) && (vendor == 0)) {
223 			RWDEBUG2("Skipping Diameter attribute %u", attr);
224 			goto next_attr;
225 		}
226 
227 		/*
228 		 *	EAP-Message AVPs can be larger than 253 octets.
229 		 *
230 		 *	For now, we rely on the main decoder in
231 		 *	src/lib/radius to decode data into VPs.  This
232 		 *	means putting the data into a RADIUS attribute
233 		 *	format.  It also means that we can't handle
234 		 *	"extended" attributes in the Diameter space.  Oh well...
235 		 */
236 		if ((size > 253) && !((vendor == 0) && (attr == PW_EAP_MESSAGE))) {
237 			RWDEBUG2("diameter2vp skipping long attribute %u", attr);
238 			goto next_attr;
239 		}
240 
241 		/*
242 		 *	RADIUS VSAs are handled as Diameter attributes
243 		 *	with Vendor-Id == 0, and the VSA data packed
244 		 *	into the "String" field as per normal.
245 		 *
246 		 *	EXCEPT for the MS-CHAP attributes.
247 		 */
248 		if ((vendor == 0) && (attr == PW_VENDOR_SPECIFIC)) {
249 			ssize_t decoded;
250 			uint8_t buffer[256];
251 
252 			buffer[0] = PW_VENDOR_SPECIFIC;
253 			buffer[1] = size + 2;
254 			memcpy(buffer + 2, data, size);
255 
256 			vp = NULL;
257 			decoded = rad_attr2vp(packet, NULL, NULL, NULL,
258 					      buffer, size + 2, &vp);
259 			if (decoded < 0) {
260 				REDEBUG2("diameter2vp failed decoding attr: %s",
261 					fr_strerror());
262 				goto raw;
263 			}
264 
265 			if ((size_t) decoded != size + 2) {
266 				REDEBUG2("diameter2vp failed to entirely decode VSA");
267 				fr_pair_list_free(&vp);
268 				goto raw;
269 			}
270 
271 			fr_cursor_merge(&out, vp);
272 
273 			goto next_attr;
274 		}
275 
276 		/*
277 		 *	Create it.  If this fails, it's because we're OOM.
278 		 */
279 		da = dict_attrbyvalue(attr, vendor);
280 		if (!da) goto raw;
281 
282 		vp = fr_pair_afrom_da(packet, da);
283 		if (!vp) {
284 			RDEBUG2("Failure in creating VP");
285 			fr_pair_list_free(&first);
286 			return NULL;
287 		}
288 
289 		/*
290 		 *	If it's a type from our dictionary, then
291 		 *	we need to put the data in a relevant place.
292 		 *
293 		 *	@todo: Export the lib/radius.c decoder, and use it here!
294 		 */
295 		switch (vp->da->type) {
296 		case PW_TYPE_INTEGER:
297 		case PW_TYPE_DATE:
298 			if (size != vp->vp_length) {
299 				/*
300 				 *	Bad format.  Create a "raw"
301 				 *	attribute.
302 				 */
303 		raw:
304 				if (vp) fr_pair_list_free(&vp);
305 				da = dict_unknown_afrom_fields(packet, attr, vendor);
306 				if (!da) return NULL;
307 				vp = fr_pair_afrom_da(packet, da);
308 				if (!vp) return NULL;
309 				fr_pair_value_memcpy(vp, data, size);
310 				break;
311 			}
312 			memcpy(&vp->vp_integer, data, vp->vp_length);
313 
314 			/*
315 			 *	Stored in host byte order: change it.
316 			 */
317 			vp->vp_integer = ntohl(vp->vp_integer);
318 			break;
319 
320 		case PW_TYPE_INTEGER64:
321 			if (size != vp->vp_length) goto raw;
322 			memcpy(&vp->vp_integer64, data, vp->vp_length);
323 
324 			/*
325 			 *	Stored in host byte order: change it.
326 			 */
327 			vp->vp_integer64 = ntohll(vp->vp_integer64);
328 			break;
329 
330 		case PW_TYPE_IPV4_ADDR:
331 			if (size != vp->vp_length) {
332 				RDEBUG2("Invalid length attribute %d",
333 				       attr);
334 				fr_pair_list_free(&first);
335 				fr_pair_list_free(&vp);
336 				return NULL;
337 			}
338 			memcpy(&vp->vp_ipaddr, data, vp->vp_length);
339 
340 			/*
341 			 *	Stored in network byte order: don't change it.
342 			 */
343 			break;
344 
345 		case PW_TYPE_BYTE:
346 			if (size != vp->vp_length) goto raw;
347 			vp->vp_byte = data[0];
348 			break;
349 
350 		case PW_TYPE_SHORT:
351 			if (size != vp->vp_length) goto raw;
352 			vp->vp_short = (data[0] * 256) + data[1];
353 			break;
354 
355 		case PW_TYPE_SIGNED:
356 			if (size != vp->vp_length) goto raw;
357 			memcpy(&vp->vp_signed, data, vp->vp_length);
358 			vp->vp_signed = ntohl(vp->vp_signed);
359 			break;
360 
361 		case PW_TYPE_IPV6_ADDR:
362 			if (size != vp->vp_length) goto raw;
363 			memcpy(&vp->vp_ipv6addr, data, vp->vp_length);
364 			break;
365 
366 		case PW_TYPE_IPV6_PREFIX:
367 			if (size != vp->vp_length) goto raw;
368 			memcpy(vp->vp_ipv6prefix, data, vp->vp_length);
369 			break;
370 
371 		case PW_TYPE_STRING:
372 			fr_pair_value_bstrncpy(vp, data, size);
373 			vp->vp_length = strlen(vp->vp_strvalue); /* embedded zeros are NOT allowed */
374 			break;
375 
376 			/*
377 			 *	Copy it over verbatim.
378 			 */
379 		case PW_TYPE_OCTETS:
380 		default:
381 			fr_pair_value_memcpy(vp, data, size);
382 			break;
383 		}
384 
385 		/*
386 		 *	Ensure that the client is using the
387 		 *	correct challenge.  This weirdness is
388 		 *	to protect against against replay
389 		 *	attacks, where anyone observing the
390 		 *	CHAP exchange could pose as that user,
391 		 *	by simply choosing to use the same
392 		 *	challenge.
393 		 *
394 		 *	By using a challenge based on
395 		 *	information from the current session,
396 		 *	we can guarantee that the client is
397 		 *	not *choosing* a challenge.
398 		 *
399 		 *	We're a little forgiving in that we
400 		 *	have loose checks on the length, and
401 		 *	we do NOT check the Id (first octet of
402 		 *	the response to the challenge)
403 		 *
404 		 *	But if the client gets the challenge correct,
405 		 *	we're not too worried about the Id.
406 		 */
407 		if (((vp->da->vendor == 0) && (vp->da->attr == PW_CHAP_CHALLENGE)) ||
408 		    ((vp->da->vendor == VENDORPEC_MICROSOFT) && (vp->da->attr == PW_MSCHAP_CHALLENGE))) {
409 			uint8_t	challenge[17];
410 
411 			if ((vp->vp_length < 8) ||
412 			    (vp->vp_length > 16)) {
413 				RDEBUG("Tunneled challenge has invalid length");
414 				fr_pair_list_free(&first);
415 				fr_pair_list_free(&vp);
416 				return NULL;
417 			}
418 
419 			/*
420 			 *	TLSv1.3 exports a different key depending on the length
421 			 *	requested so ask for *exactly* what the spec requires
422 			 */
423 			eapttls_gen_challenge(ssl, challenge, vp->vp_length + 1);
424 
425 			if (memcmp(challenge, vp->vp_octets,
426 				   vp->vp_length) != 0) {
427 				RDEBUG("Tunneled challenge is incorrect");
428 				fr_pair_list_free(&first);
429 				fr_pair_list_free(&vp);
430 				return NULL;
431 			}
432 		}
433 
434 		/*
435 		 *	Update the list.
436 		 */
437 		fr_cursor_insert(&out, vp);
438 
439 	next_attr:
440 		if (data_left <= attr_len) break;
441 
442 		data_left -= attr_len;
443 		data += (attr_len - offset);
444 	}
445 
446 	/*
447 	 *	We got this far.  It looks OK.
448 	 */
449 	return first;
450 }
451 
452 /*
453  *	Convert VALUE_PAIR's to diameter attributes, and write them
454  *	to an SSL session.
455  *
456  *	The ONLY VALUE_PAIR's which may be passed to this function
457  *	are ones which can go inside of a RADIUS (i.e. diameter)
458  *	packet.  So no server-configuration attributes, or the like.
459  */
vp2diameter(REQUEST * request,tls_session_t * tls_session,VALUE_PAIR * first)460 static int vp2diameter(REQUEST *request, tls_session_t *tls_session, VALUE_PAIR *first)
461 {
462 	/*
463 	 *	RADIUS packets are no more than 4k in size, so if
464 	 *	we've got more than 4k of data to write, it's very
465 	 *	bad.
466 	 */
467 	uint8_t		buffer[4096];
468 	uint8_t		*p;
469 	uint32_t	attr;
470 	uint32_t	length;
471 	uint32_t	vendor;
472 	size_t		total;
473 	uint64_t	attr64;
474 	VALUE_PAIR	*vp;
475 	vp_cursor_t	cursor;
476 
477 	p = buffer;
478 	total = 0;
479 
480 	for (vp = fr_cursor_init(&cursor, &first); vp; vp = fr_cursor_next(&cursor)) {
481 		/*
482 		 *	Too much data: die.
483 		 */
484 		if ((total + vp->vp_length + 12) >= sizeof(buffer)) {
485 			RDEBUG2("output buffer is full!");
486 			return 0;
487 		}
488 
489 		/*
490 		 *	Hmm... we don't group multiple EAP-Messages
491 		 *	together.  Maybe we should...
492 		 */
493 
494 		length = vp->vp_length;
495 		vendor = vp->da->vendor;
496 		if (vendor != 0) {
497 			attr = vp->da->attr & 0xffff;
498 			length |= ((uint32_t)1 << 31);
499 		} else {
500 			attr = vp->da->attr;
501 		}
502 
503 		/*
504 		 *	Hmm... set the M bit for all attributes?
505 		 */
506 		length |= (1 << 30);
507 
508 		attr = ntohl(attr);
509 
510 		memcpy(p, &attr, sizeof(attr));
511 		p += 4;
512 		total += 4;
513 
514 		length += 8;	/* includes 8 bytes of attr & length */
515 
516 		if (vendor != 0) {
517 			length += 4; /* include 4 bytes of vendor */
518 
519 			length = ntohl(length);
520 			memcpy(p, &length, sizeof(length));
521 			p += 4;
522 			total += 4;
523 
524 			vendor = ntohl(vendor);
525 			memcpy(p, &vendor, sizeof(vendor));
526 			p += 4;
527 			total += 4;
528 		} else {
529 			length = ntohl(length);
530 			memcpy(p, &length, sizeof(length));
531 			p += 4;
532 			total += 4;
533 		}
534 
535 		switch (vp->da->type) {
536 		case PW_TYPE_INTEGER:
537 		case PW_TYPE_DATE:
538 			attr = htonl(vp->vp_integer); /* stored in host order */
539 			memcpy(p, &attr, sizeof(attr));
540 			length = 4;
541 			break;
542 
543 		case PW_TYPE_INTEGER64:
544 			attr64 = htonll(vp->vp_integer64); /* stored in host order */
545 			memcpy(p, &attr64, sizeof(attr64));
546 			length = 8;
547 			break;
548 
549 		case PW_TYPE_IPV4_ADDR:
550 			memcpy(p, &vp->vp_ipaddr, 4); /* network order */
551 			length = 4;
552 			break;
553 
554 		case PW_TYPE_STRING:
555 		case PW_TYPE_OCTETS:
556 		default:
557 			memcpy(p, vp->vp_strvalue, vp->vp_length);
558 			length = vp->vp_length;
559 			break;
560 		}
561 
562 		/*
563 		 *	Skip to the end of the data.
564 		 */
565 		p += length;
566 		total += length;
567 
568 		/*
569 		 *	Align the data to a multiple of 4 bytes.
570 		 */
571 		if ((total & 0x03) != 0) {
572 			size_t i;
573 
574 			length = 4 - (total & 0x03);
575 			for (i = 0; i < length; i++) {
576 				*p = '\0';
577 				p++;
578 				total++;
579 			}
580 		}
581 	} /* loop over the VP's to write. */
582 
583 	/*
584 	 *	Write the data in the buffer to the SSL session.
585 	 */
586 	if (total > 0) {
587 #ifndef NDEBUG
588 		size_t i;
589 
590 		if ((rad_debug_lvl > 2) && fr_log_fp) {
591 			for (i = 0; i < total; i++) {
592 				if ((i & 0x0f) == 0) fprintf(fr_log_fp, "  TTLS tunnel data out %04x: ", (int) i);
593 
594 				fprintf(fr_log_fp, "%02x ", buffer[i]);
595 
596 				if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
597 			}
598 			if ((total & 0x0f) != 0) fprintf(fr_log_fp, "\n");
599 		}
600 #endif
601 
602 		(tls_session->record_plus)(&tls_session->clean_in, buffer, total);
603 
604 		/*
605 		 *	FIXME: Check the return code.
606 		 */
607 		tls_handshake_send(request, tls_session);
608 	}
609 
610 	/*
611 	 *	Everything's OK.
612 	 */
613 	return 1;
614 }
615 
616 /*
617  *	Use a reply packet to determine what to do.
618  */
CC_HINT(nonnull)619 static rlm_rcode_t CC_HINT(nonnull) process_reply(eap_handler_t *handler, tls_session_t *tls_session,
620 						  REQUEST *request, RADIUS_PACKET *reply)
621 {
622 	rlm_rcode_t rcode = RLM_MODULE_REJECT;
623 	VALUE_PAIR *vp;
624 	ttls_tunnel_t *t = tls_session->opaque;
625 
626 	rad_assert(handler->request == request);
627 
628 	/*
629 	 *	If the response packet was Access-Accept, then
630 	 *	we're OK.  If not, die horribly.
631 	 *
632 	 *	FIXME: Take MS-CHAP2-Success attribute, and
633 	 *	tunnel it back to the client, to authenticate
634 	 *	ourselves to the client.
635 	 *
636 	 *	FIXME: If we have an Access-Challenge, then
637 	 *	the Reply-Message is tunneled back to the client.
638 	 *
639 	 *	FIXME: If we have an EAP-Message, then that message
640 	 *	must be tunneled back to the client.
641 	 *
642 	 *	FIXME: If we have an Access-Challenge with a State
643 	 *	attribute, then do we tunnel that to the client, or
644 	 *	keep track of it ourselves?
645 	 *
646 	 *	FIXME: EAP-Messages can only start with 'identity',
647 	 *	NOT 'eap start', so we should check for that....
648 	 */
649 	switch (reply->code) {
650 	case PW_CODE_ACCESS_ACCEPT:
651 		tls_session->authentication_success = true;
652 		RDEBUG("Got tunneled Access-Accept");
653 
654 		rcode = RLM_MODULE_OK;
655 
656 		/*
657 		 *	Always delete MPPE keys & encryption policy
658 		 *	from the tunneled reply.  These never get sent
659 		 *	back to the user.
660 		 */
661 		fr_pair_delete_by_num(&reply->vps, 7, VENDORPEC_MICROSOFT, TAG_ANY);
662 		fr_pair_delete_by_num(&reply->vps, 8, VENDORPEC_MICROSOFT, TAG_ANY);
663 		fr_pair_delete_by_num(&reply->vps, 16, VENDORPEC_MICROSOFT, TAG_ANY);
664 		fr_pair_delete_by_num(&reply->vps, 17, VENDORPEC_MICROSOFT, TAG_ANY);
665 
666 		/*
667 		 *	MS-CHAP2-Success means that we do NOT return
668 		 *	an Access-Accept, but instead tunnel that
669 		 *	attribute to the client, and keep going with
670 		 *	the TTLS session.  Once the client accepts
671 		 *	our identity, it will respond with an empty
672 		 *	packet, and we will send EAP-Success.
673 		 */
674 		vp = NULL;
675 		fr_pair_list_mcopy_by_num(tls_session, &vp, &reply->vps, PW_MSCHAP2_SUCCESS, VENDORPEC_MICROSOFT, TAG_ANY);
676 		if (vp) {
677 			RDEBUG("Got MS-CHAP2-Success, tunneling it to the client in a challenge");
678 			rcode = RLM_MODULE_HANDLED;
679 			t->authenticated = true;
680 
681 			/*
682 			 *	Use the tunneled reply, but not now.
683 			 */
684 			if (t->use_tunneled_reply) {
685 				rad_assert(!t->accept_vps);
686 				fr_pair_list_mcopy_by_num(t, &t->accept_vps, &reply->vps,
687 					  0, 0, TAG_ANY);
688 				rad_assert(!reply->vps);
689 			}
690 
691 		} else { /* no MS-CHAP2-Success */
692 			/*
693 			 *	Can only have EAP-Message if there's
694 			 *	no MS-CHAP2-Success.
695 			 *
696 			 *	We also do NOT tunnel the EAP-Success
697 			 *	attribute back to the client, as the client
698 			 *	can figure it out, from the non-tunneled
699 			 *	EAP-Success packet.
700 			 */
701 			fr_pair_list_mcopy_by_num(tls_session, &vp, &reply->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
702 			fr_pair_list_free(&vp);
703 		}
704 
705 		/* move channel binding responses; we need to send them */
706 		fr_pair_list_mcopy_by_num(tls_session, &vp, &reply->vps, PW_UKERNA_CHBIND, VENDORPEC_UKERNA, TAG_ANY);
707 		if (fr_pair_find_by_num(vp, PW_UKERNA_CHBIND, VENDORPEC_UKERNA, TAG_ANY) != NULL) {
708 			t->authenticated = true;
709 			/*
710 			 *	Use the tunneled reply, but not now.
711 			 */
712 			if (t->use_tunneled_reply) {
713 				rad_assert(!t->accept_vps);
714 				fr_pair_list_mcopy_by_num(t, &t->accept_vps, &reply->vps,
715 					  0, 0, TAG_ANY);
716 				rad_assert(!reply->vps);
717 			}
718 			rcode = RLM_MODULE_HANDLED;
719 		}
720 
721 		/*
722 		 *	Handle the ACK, by tunneling any necessary reply
723 		 *	VP's back to the client.
724 		 */
725 		if (vp) {
726 			RDEBUG("Sending tunneled reply attributes");
727 			rdebug_pair_list(L_DBG_LVL_1, request, vp, NULL);
728 
729 			vp2diameter(request, tls_session, vp);
730 			fr_pair_list_free(&vp);
731 		}
732 
733 		/*
734 		 *	If we've been told to use the attributes from
735 		 *	the reply, then do so.
736 		 *
737 		 *	WARNING: This may leak information about the
738 		 *	tunneled user!
739 		 */
740 		if (t->use_tunneled_reply) {
741 			fr_pair_delete_by_num(&reply->vps, PW_PROXY_STATE, 0, TAG_ANY);
742 			fr_pair_list_mcopy_by_num(request->reply, &request->reply->vps,
743 				  &reply->vps, 0, 0, TAG_ANY);
744 		}
745 		break;
746 
747 
748 	case PW_CODE_ACCESS_REJECT:
749 		RDEBUG("Got tunneled Access-Reject");
750 		rcode = RLM_MODULE_REJECT;
751 		break;
752 
753 		/*
754 		 *	Handle Access-Challenge, but only if we
755 		 *	send tunneled reply data.  This is because
756 		 *	an Access-Challenge means that we MUST tunnel
757 		 *	a Reply-Message to the client.
758 		 */
759 	case PW_CODE_ACCESS_CHALLENGE:
760 		RDEBUG("Got tunneled Access-Challenge");
761 
762 		/*
763 		 *	Keep the State attribute, if necessary.
764 		 *
765 		 *	Get rid of the old State, too.
766 		 */
767 		fr_pair_list_free(&t->state);
768 		fr_pair_list_mcopy_by_num(t, &t->state, &reply->vps, PW_STATE, 0, TAG_ANY);
769 
770 		/*
771 		 *	We should really be a bit smarter about this,
772 		 *	and move over only those attributes which
773 		 *	are relevant to the authentication request,
774 		 *	but that's a lot more work, and this "dumb"
775 		 *	method works in 99.9% of the situations.
776 		 */
777 		vp = NULL;
778 		fr_pair_list_mcopy_by_num(t, &vp, &reply->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
779 
780 		/*
781 		 *	There MUST be a Reply-Message in the challenge,
782 		 *	which we tunnel back to the client.
783 		 *
784 		 *	If there isn't one in the reply VP's, then
785 		 *	we MUST create one, with an empty string as
786 		 *	it's value.
787 		 */
788 		fr_pair_list_mcopy_by_num(t, &vp, &reply->vps, PW_REPLY_MESSAGE, 0, TAG_ANY);
789 
790 		/* also move chbind messages, if any */
791 		fr_pair_list_mcopy_by_num(t, &vp, &reply->vps, PW_UKERNA_CHBIND, VENDORPEC_UKERNA,
792 			  TAG_ANY);
793 
794 		/*
795 		 *	Handle the ACK, by tunneling any necessary reply
796 		 *	VP's back to the client.
797 		 */
798 		if (vp) {
799 			vp2diameter(request, tls_session, vp);
800 			fr_pair_list_free(&vp);
801 		}
802 		rcode = RLM_MODULE_HANDLED;
803 		break;
804 
805 	default:
806 		RDEBUG("Unknown RADIUS packet type %d: rejecting tunneled user", reply->code);
807 		rcode = RLM_MODULE_INVALID;
808 		break;
809 	}
810 
811 	return rcode;
812 }
813 
814 
815 #ifdef WITH_PROXY
816 /*
817  *	Do post-proxy processing,
818  */
CC_HINT(nonnull)819 static int CC_HINT(nonnull) eapttls_postproxy(eap_handler_t *handler, void *data)
820 {
821 	int rcode;
822 	tls_session_t *tls_session = (tls_session_t *) data;
823 	REQUEST *fake, *request = handler->request;
824 
825 	RDEBUG("Passing reply from proxy back into the tunnel");
826 
827 	/*
828 	 *	If there was a fake request associated with the proxied
829 	 *	request, do more processing of it.
830 	 */
831 	fake = (REQUEST *) request_data_get(handler->request,
832 					    handler->request->proxy,
833 					    REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK);
834 
835 	/*
836 	 *	Do the callback, if it exists, and if it was a success.
837 	 */
838 	if (fake && (handler->request->proxy_reply->code == PW_CODE_ACCESS_ACCEPT)) {
839 		/*
840 		 *	Terrible hacks.
841 		 */
842 		rad_assert(!fake->packet);
843 		fake->packet = talloc_steal(fake, request->proxy);
844 		fake->packet->src_ipaddr = request->packet->src_ipaddr;
845 		request->proxy = NULL;
846 
847 		rad_assert(!fake->reply);
848 		fake->reply = talloc_steal(fake, request->proxy_reply);
849 		request->proxy_reply = NULL;
850 
851 		if ((rad_debug_lvl > 0) && fr_log_fp) {
852 			fprintf(fr_log_fp, "server %s {\n",
853 				(!fake->server) ? "" : fake->server);
854 		}
855 
856 		/*
857 		 *	Perform a post-auth stage for the tunneled
858 		 *	session.
859 		 */
860 		fake->options &= ~RAD_REQUEST_OPTION_PROXY_EAP;
861 		rcode = rad_postauth(fake);
862 		RDEBUG2("post-auth returns %d", rcode);
863 
864 		if ((rad_debug_lvl > 0) && fr_log_fp) {
865 			fprintf(fr_log_fp, "} # server %s\n",
866 				(!fake->server) ? "" : fake->server);
867 
868 			RDEBUG("Final reply from tunneled session code %d", fake->reply->code);
869 			rdebug_pair_list(L_DBG_LVL_1, request, fake->reply->vps, NULL);
870 		}
871 
872 		/*
873 		 *	Terrible hacks.
874 		 */
875 		request->proxy = talloc_steal(request, fake->packet);
876 		fake->packet = NULL;
877 		request->proxy_reply = talloc_steal(request, fake->reply);
878 		fake->reply = NULL;
879 
880 		/*
881 		 *	And we're done with this request.
882 		 */
883 
884 		switch (rcode) {
885 		case RLM_MODULE_FAIL:
886 			talloc_free(fake);
887 			eaptls_fail(handler, 0);
888 			return 0;
889 
890 		default:  /* Don't Do Anything */
891 			RDEBUG2("Got reply %d",
892 			       request->proxy_reply->code);
893 			break;
894 		}
895 	}
896 	talloc_free(fake);	/* robust if !fake */
897 
898 	/*
899 	 *	Process the reply from the home server.
900 	 */
901 	rcode = process_reply(handler, tls_session, handler->request, handler->request->proxy_reply);
902 
903 	/*
904 	 *	The proxy code uses the reply from the home server as
905 	 *	the basis for the reply to the NAS.  We don't want that,
906 	 *	so we toss it, after we've had our way with it.
907 	 */
908 	fr_pair_list_free(&handler->request->proxy_reply->vps);
909 
910 	switch (rcode) {
911 	case RLM_MODULE_REJECT:
912 		RDEBUG("Reply was rejected");
913 		break;
914 
915 	case RLM_MODULE_HANDLED:
916 		RDEBUG("Reply was handled");
917 		eaptls_request(handler->eap_ds, tls_session);
918 		request->proxy_reply->code = PW_CODE_ACCESS_CHALLENGE;
919 		return 1;
920 
921 	case RLM_MODULE_OK:
922 		RDEBUG("Reply was OK");
923 
924 		/*
925 		 *	Success: Automatically return MPPE keys.
926 		 */
927 		return eaptls_success(handler, 0);
928 
929 	default:
930 		RDEBUG("Reply was unknown");
931 		break;
932 	}
933 
934 	eaptls_fail(handler, 0);
935 	return 0;
936 }
937 
938 #endif	/* WITH_PROXY */
939 
940 /*
941  *	Process the "diameter" contents of the tunneled data.
942  */
eapttls_process(eap_handler_t * handler,tls_session_t * tls_session)943 int eapttls_process(eap_handler_t *handler, tls_session_t *tls_session)
944 {
945 	PW_CODE code = PW_CODE_ACCESS_REJECT;
946 	rlm_rcode_t rcode;
947 	REQUEST *fake;
948 	VALUE_PAIR *vp;
949 	ttls_tunnel_t *t;
950 	uint8_t const *data;
951 	size_t data_len;
952 	REQUEST *request = handler->request;
953 	chbind_packet_t *chbind;
954 
955 	/*
956 	 *	Just look at the buffer directly, without doing
957 	 *	record_minus.
958 	 */
959 	data_len = tls_session->clean_out.used;
960 	tls_session->clean_out.used = 0;
961 	data = tls_session->clean_out.data;
962 
963 	t = (ttls_tunnel_t *) tls_session->opaque;
964 
965 	/*
966 	 *	If there's no data, maybe this is an ACK to an
967 	 *	MS-CHAP2-Success.
968 	 */
969 	if (data_len == 0) {
970 		if (t->authenticated) {
971 			RDEBUG("Got ACK, and the user was already authenticated");
972 			return PW_CODE_ACCESS_ACCEPT;
973 		} /* else no session, no data, die. */
974 
975 		/*
976 		 *	FIXME: Call SSL_get_error() to see what went
977 		 *	wrong.
978 		 */
979 		RDEBUG2("SSL_read Error");
980 		return PW_CODE_ACCESS_REJECT;
981 	}
982 
983 #ifndef NDEBUG
984 	if ((rad_debug_lvl > 2) && fr_log_fp) {
985 		size_t i;
986 
987 		for (i = 0; i < data_len; i++) {
988 			if ((i & 0x0f) == 0) fprintf(fr_log_fp, "  TTLS tunnel data in %04x: ", (int) i);
989 
990 			fprintf(fr_log_fp, "%02x ", data[i]);
991 
992 			if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
993 		}
994 		if ((data_len & 0x0f) != 0) fprintf(fr_log_fp, "\n");
995 	}
996 #endif
997 
998 	if (!diameter_verify(request, data, data_len)) {
999 		return PW_CODE_ACCESS_REJECT;
1000 	}
1001 
1002 	/*
1003 	 *	Allocate a fake REQUEST structure.
1004 	 */
1005 	fake = request_alloc_fake(request);
1006 
1007 	rad_assert(!fake->packet->vps);
1008 
1009 	/*
1010 	 *	Add the tunneled attributes to the fake request.
1011 	 */
1012 	fake->packet->vps = diameter2vp(request, fake, tls_session->ssl, data, data_len);
1013 	if (!fake->packet->vps) {
1014 		talloc_free(fake);
1015 		return PW_CODE_ACCESS_REJECT;
1016 	}
1017 
1018 	/*
1019 	 *	Tell the request that it's a fake one.
1020 	 */
1021 	fr_pair_make(fake->packet, &fake->packet->vps, "Freeradius-Proxied-To", "127.0.0.1", T_OP_EQ);
1022 
1023 	RDEBUG("Got tunneled request");
1024 	rdebug_pair_list(L_DBG_LVL_1, request, fake->packet->vps, NULL);
1025 
1026 	/*
1027 	 *	Update other items in the REQUEST data structure.
1028 	 */
1029 	fake->username = fr_pair_find_by_num(fake->packet->vps, PW_USER_NAME, 0, TAG_ANY);
1030 	fake->password = fr_pair_find_by_num(fake->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY);
1031 
1032 	/*
1033 	 *	No User-Name, try to create one from stored data.
1034 	 */
1035 	if (!fake->username) {
1036 		/*
1037 		 *	No User-Name in the stored data, look for
1038 		 *	an EAP-Identity, and pull it out of there.
1039 		 */
1040 		if (!t->username) {
1041 			vp = fr_pair_find_by_num(fake->packet->vps, PW_EAP_MESSAGE, 0, TAG_ANY);
1042 			if (vp &&
1043 			    (vp->vp_length >= EAP_HEADER_LEN + 2) &&
1044 			    (vp->vp_strvalue[0] == PW_EAP_RESPONSE) &&
1045 			    (vp->vp_strvalue[EAP_HEADER_LEN] == PW_EAP_IDENTITY) &&
1046 			    (vp->vp_strvalue[EAP_HEADER_LEN + 1] != 0)) {
1047 				/*
1048 				 *	Create & remember a User-Name
1049 				 */
1050 				t->username = fr_pair_make(t, NULL, "User-Name", NULL, T_OP_EQ);
1051 				rad_assert(t->username != NULL);
1052 
1053 				fr_pair_value_bstrncpy(t->username, vp->vp_octets + 5, vp->vp_length - 5);
1054 
1055 				RDEBUG("Got tunneled identity of %s",
1056 				       t->username->vp_strvalue);
1057 
1058 				/*
1059 				 *	If there's a default EAP type,
1060 				 *	set it here.
1061 				 */
1062 				if (t->default_method != 0) {
1063 					RDEBUG("Setting default EAP type for tunneled EAP session");
1064 					vp = fr_pair_afrom_num(fake, PW_EAP_TYPE, 0);
1065 					rad_assert(vp != NULL);
1066 					vp->vp_integer = t->default_method;
1067 					fr_pair_add(&fake->config, vp);
1068 				}
1069 
1070 			} else {
1071 				/*
1072 				 *	Don't reject the request outright,
1073 				 *	as it's permitted to do EAP without
1074 				 *	user-name.
1075 				 */
1076 				RWDEBUG2("No EAP-Identity found to start EAP conversation");
1077 			}
1078 		} /* else there WAS a t->username */
1079 
1080 		if (t->username) {
1081 			vp = fr_pair_list_copy(fake->packet, t->username);
1082 			fr_pair_add(&fake->packet->vps, vp);
1083 			fake->username = fr_pair_find_by_num(fake->packet->vps, PW_USER_NAME, 0, TAG_ANY);
1084 		}
1085 	} /* else the request ALREADY had a User-Name */
1086 
1087 	/*
1088 	 *	Add the State attribute, too, if it exists.
1089 	 */
1090 	if (t->state) {
1091 		vp = fr_pair_list_copy(fake->packet, t->state);
1092 		if (vp) fr_pair_add(&fake->packet->vps, vp);
1093 	}
1094 
1095 	/*
1096 	 *	If this is set, we copy SOME of the request attributes
1097 	 *	from outside of the tunnel to inside of the tunnel.
1098 	 *
1099 	 *	We copy ONLY those attributes which do NOT already
1100 	 *	exist in the tunneled request.
1101 	 */
1102 	if (t->copy_request_to_tunnel) {
1103 		VALUE_PAIR *copy;
1104 		vp_cursor_t cursor;
1105 
1106 		for (vp = fr_cursor_init(&cursor, &request->packet->vps); vp; vp = fr_cursor_next(&cursor)) {
1107 			/*
1108 			 *	The attribute is a server-side thingy,
1109 			 *	don't copy it.
1110 			 */
1111 			if ((vp->da->attr > 255) &&
1112 			    (vp->da->vendor == 0)) {
1113 				continue;
1114 			}
1115 
1116 			/*
1117 			 *	The outside attribute is already in the
1118 			 *	tunnel, don't copy it.
1119 			 *
1120 			 *	This works for BOTH attributes which
1121 			 *	are originally in the tunneled request,
1122 			 *	AND attributes which are copied there
1123 			 *	from below.
1124 			 */
1125 			if (fr_pair_find_by_da(fake->packet->vps, vp->da, TAG_ANY)) {
1126 				continue;
1127 			}
1128 
1129 			/*
1130 			 *	Some attributes are handled specially.
1131 			 */
1132 			if (!vp->da->vendor) switch (vp->da->attr) {
1133 			/*
1134 			 *	NEVER copy Message-Authenticator,
1135 			 *	EAP-Message, or State.  They're
1136 			 *	only for outside of the tunnel.
1137 			 */
1138 			case PW_USER_NAME:
1139 			case PW_USER_PASSWORD:
1140 			case PW_CHAP_PASSWORD:
1141 			case PW_CHAP_CHALLENGE:
1142 			case PW_PROXY_STATE:
1143 			case PW_MESSAGE_AUTHENTICATOR:
1144 			case PW_EAP_MESSAGE:
1145 			case PW_STATE:
1146 				continue;
1147 
1148 			/*
1149 			 *	By default, copy it over.
1150 			 */
1151 			default:
1152 				break;
1153 			}
1154 
1155 			/*
1156 			 *	Don't copy from the head, we've already
1157 			 *	checked it.
1158 			 */
1159 			copy = fr_pair_list_copy_by_num(fake->packet, vp, vp->da->attr, vp->da->vendor, TAG_ANY);
1160 			fr_pair_add(&fake->packet->vps, copy);
1161 		}
1162 	}
1163 
1164 	if ((vp = fr_pair_find_by_num(request->config, PW_VIRTUAL_SERVER, 0, TAG_ANY)) != NULL) {
1165 		fake->server = vp->vp_strvalue;
1166 
1167 	} else if (t->virtual_server) {
1168 		fake->server = t->virtual_server;
1169 
1170 	} /* else fake->server == request->server */
1171 
1172 
1173 	if ((rad_debug_lvl > 0) && fr_log_fp) {
1174 		RDEBUG("Sending tunneled request");
1175 	}
1176 
1177 	/*
1178 	 *	Process channel binding.
1179 	 */
1180 	chbind = eap_chbind_vp2packet(fake, fake->packet->vps);
1181 	if (chbind) {
1182 		PW_CODE chbind_code;
1183 		CHBIND_REQ *req = talloc_zero(fake, CHBIND_REQ);
1184 
1185 		RDEBUG("received chbind request");
1186 		req->request = chbind;
1187 		if (fake->username) {
1188 			req->username = fake->username;
1189 		} else {
1190 			req->username = NULL;
1191 		}
1192 		chbind_code = chbind_process(request, req);
1193 
1194 		/* encapsulate response here */
1195 		if (req->response) {
1196 			RDEBUG("sending chbind response");
1197 			fr_pair_add(&fake->reply->vps,
1198 				    eap_chbind_packet2vp(fake->reply, req->response));
1199 		} else {
1200 			RDEBUG("no chbind response");
1201 		}
1202 
1203 		/* clean up chbind req */
1204 		talloc_free(req);
1205 
1206 		if (chbind_code != PW_CODE_ACCESS_ACCEPT) {
1207 			return chbind_code;
1208 		}
1209 	}
1210 
1211 	/*
1212 	 *	Call authentication recursively, which will
1213 	 *	do PAP, CHAP, MS-CHAP, etc.
1214 	 */
1215 	rad_virtual_server(fake);
1216 
1217 	/*
1218 	 *	Decide what to do with the reply.
1219 	 */
1220 	switch (fake->reply->code) {
1221 	case 0:			/* No reply code, must be proxied... */
1222 #ifdef WITH_PROXY
1223 		vp = fr_pair_find_by_num(fake->config, PW_PROXY_TO_REALM, 0, TAG_ANY);
1224 		if (vp) {
1225 			eap_tunnel_data_t *tunnel;
1226 			RDEBUG("Tunneled authentication will be proxied to %s", vp->vp_strvalue);
1227 
1228 			/*
1229 			 *	Tell the original request that it's going
1230 			 *	to be proxied.
1231 			 */
1232 			fr_pair_list_mcopy_by_num(request, &request->config,
1233 				  &fake->config,
1234 				  PW_PROXY_TO_REALM, 0, TAG_ANY);
1235 
1236 			/*
1237 			 *	Seed the proxy packet with the
1238 			 *	tunneled request.
1239 			 */
1240 			rad_assert(!request->proxy);
1241 			request->proxy = talloc_steal(request, fake->packet);
1242 			memset(&request->proxy->src_ipaddr, 0,
1243 			       sizeof(request->proxy->src_ipaddr));
1244 			memset(&request->proxy->src_ipaddr, 0,
1245 			       sizeof(request->proxy->src_ipaddr));
1246 			request->proxy->src_port = 0;
1247 			request->proxy->dst_port = 0;
1248 			fake->packet = NULL;
1249 			rad_free(&fake->reply);
1250 			fake->reply = NULL;
1251 
1252 			/*
1253 			 *	Set up the callbacks for the tunnel
1254 			 */
1255 			tunnel = talloc_zero(request, eap_tunnel_data_t);
1256 			tunnel->tls_session = tls_session;
1257 			tunnel->callback = eapttls_postproxy;
1258 
1259 			/*
1260 			 *	Associate the callback with the request.
1261 			 */
1262 			code = request_data_add(request, request->proxy, REQUEST_DATA_EAP_TUNNEL_CALLBACK,
1263 						tunnel, false);
1264 			rad_assert(code == 0);
1265 
1266 			/*
1267 			 *	rlm_eap.c has taken care of associating
1268 			 *	the handler with the fake request.
1269 			 *
1270 			 *	So we associate the fake request with
1271 			 *	this request.
1272 			 */
1273 			code = request_data_add(request, request->proxy, REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK,
1274 						fake, true);
1275 			rad_assert(code == 0);
1276 			fake = NULL;
1277 
1278 			/*
1279 			 *	Didn't authenticate the packet, but
1280 			 *	we're proxying it.
1281 			 */
1282 			code = PW_CODE_STATUS_CLIENT;
1283 
1284 		} else
1285 #endif	/* WITH_PROXY */
1286 		  {
1287 			RDEBUG("No tunneled reply was found for request %d , and the request was not proxied: rejecting the user.",
1288 			       request->number);
1289 			code = PW_CODE_ACCESS_REJECT;
1290 		}
1291 		break;
1292 
1293 	default:
1294 		/*
1295 		 *	Returns RLM_MODULE_FOO, and we want to return PW_FOO
1296 		 */
1297 		rcode = process_reply(handler, tls_session, request, fake->reply);
1298 		switch (rcode) {
1299 		case RLM_MODULE_REJECT:
1300 			code = PW_CODE_ACCESS_REJECT;
1301 			break;
1302 
1303 		case RLM_MODULE_HANDLED:
1304 			code = PW_CODE_ACCESS_CHALLENGE;
1305 			break;
1306 
1307 		case RLM_MODULE_OK:
1308 			code = PW_CODE_ACCESS_ACCEPT;
1309 			break;
1310 
1311 		default:
1312 			code = PW_CODE_ACCESS_REJECT;
1313 			break;
1314 		}
1315 		break;
1316 	}
1317 
1318 	talloc_free(fake);
1319 
1320 	return code;
1321 }
1322