"Fossies" - the Fresh Open Source Software Archive

Member "freeradius-server-3.0.23/src/modules/rlm_eap/types/rlm_eap_ttls/ttls.c" (10 Jun 2021, 32994 Bytes) of package /linux/misc/freeradius-server-3.0.23.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "ttls.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 3.0.22_vs_3.0.23.

    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  */
   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  */
  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  */
  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  */
  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  */
  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  */
  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 }