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