X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmodules%2Frlm_eap%2Ftypes%2Frlm_eap_ttls%2Fttls.c;h=fc2aca3f458ecb17e1f41f751ff453298ab6aacb;hb=94dc4bb60ec649ce899c1d5e32b575d9523a48f2;hp=d2ceb6044198de838fc27535c4df5f6c576fdb53;hpb=9f4714693fa4e78b7f9fe6f41e0eb53bb298ca5a;p=freeradius.git diff --git a/src/modules/rlm_eap/types/rlm_eap_ttls/ttls.c b/src/modules/rlm_eap/types/rlm_eap_ttls/ttls.c index d2ceb60..fc2aca3 100644 --- a/src/modules/rlm_eap/types/rlm_eap_ttls/ttls.c +++ b/src/modules/rlm_eap/types/rlm_eap_ttls/ttls.c @@ -15,10 +15,15 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2003 Alan DeKok + * Copyright 2006 The FreeRADIUS server project */ + +#include +RCSID("$Id$") + #include "eap_ttls.h" /* @@ -38,7 +43,8 @@ /* * Verify that the diameter packet is valid. */ -static int diameter_verify(const uint8_t *data, unsigned int data_len) +static int diameter_verify(REQUEST *request, + const uint8_t *data, unsigned int data_len) { uint32_t attr; uint32_t length; @@ -47,7 +53,7 @@ static int diameter_verify(const uint8_t *data, unsigned int data_len) while (data_left > 0) { if (data_len < 12) { - DEBUG2(" rlm_eap_ttls: Diameter attribute is too small to contain a Diameter header"); + RDEBUG2(" Diameter attribute is too small to contain a Diameter header"); return 0; } @@ -56,7 +62,7 @@ static int diameter_verify(const uint8_t *data, unsigned int data_len) data += 4; attr = ntohl(attr); if (attr > 255) { - DEBUG2(" rlm_eap_ttls: Non-RADIUS attribute in tunneled authentication is not supported"); + RDEBUG2(" Non-RADIUS attribute in tunneled authentication is not supported"); return 0; } @@ -70,28 +76,25 @@ static int diameter_verify(const uint8_t *data, unsigned int data_len) */ offset = 8; if ((length & (1 << 31)) != 0) { - int attribute; uint32_t vendor; DICT_ATTR *da; memcpy(&vendor, data, sizeof(vendor)); vendor = ntohl(vendor); - if (vendor > 65535) { - DEBUG2(" rlm_eap_ttls: Vendor codes larger than 65535 are not supported"); + if (vendor > FR_MAX_VENDOR) { + RDEBUG2("Vendor codes larger than 2^24 are not supported"); return 0; } - attribute = (vendor << 16) | attr; - - da = dict_attrbyvalue(attribute); + da = dict_attrbyvalue(attr, vendor); /* * SHOULD check ((length & (1 << 30)) != 0) * for the mandatory bit. */ if (!da) { - DEBUG2(" rlm_eap_ttls: Fatal! Vendor %u, Attribute %u was not found in our dictionary. ", + RDEBUG2("Fatal! Vendor %u, Attribute %u was not found in our dictionary. ", vendor, attr); return 0; } @@ -111,21 +114,24 @@ static int diameter_verify(const uint8_t *data, unsigned int data_len) /* * Too short or too long is bad. - * - * FIXME: EAP-Message */ if (length < offset) { - DEBUG2(" rlm_eap_ttls: Tunneled attribute %d is too short (%d)to contain anything useful.", attr, length); + RDEBUG2("Tunneled attribute %d is too short (%d)to contain anything useful.", attr, length); return 0; } - if (length > (MAX_STRING_LEN + 8)) { - DEBUG2(" rlm_eap_ttls: Tunneled attribute %d is too long (%d) to pack into a RADIUS attribute.", attr, length); + /* + * EAP Messages cane be longer than MAX_STRING_LEN. + * Other attributes cannot be. + */ + if ((attr != PW_EAP_MESSAGE) && + (length > (MAX_STRING_LEN + 8))) { + RDEBUG2("Tunneled attribute %d is too long (%d) to pack into a RADIUS attribute.", attr, length); return 0; } - + if (length > data_left) { - DEBUG2(" rlm_eap_ttls: Tunneled attribute %d is longer than room left in the packet (%d > %d).", attr, length, data_left); + RDEBUG2("Tunneled attribute %d is longer than room left in the packet (%d > %d).", attr, length, data_left); return 0; } @@ -151,10 +157,10 @@ static int diameter_verify(const uint8_t *data, unsigned int data_len) * of the packet, die. */ if (data_left < length) { - DEBUG2(" rlm_eap_ttls: ERROR! Diameter attribute overflows packet!"); + RDEBUG2("ERROR! Diameter attribute overflows packet!"); return 0; } - + /* * Check again for equality, now that we're padded * length to a multiple of 4 octets. @@ -178,14 +184,15 @@ static int diameter_verify(const uint8_t *data, unsigned int data_len) /* * Convert diameter attributes to our VALUE_PAIR's */ -static VALUE_PAIR *diameter2vp(SSL *ssl, - const uint8_t *data, unsigned int data_len) +static VALUE_PAIR *diameter2vp(REQUEST *request, SSL *ssl, + const uint8_t *data, size_t data_len) { uint32_t attr; + uint32_t vendor; uint32_t length; - unsigned int offset; - int size; - unsigned int data_left = data_len; + size_t offset; + size_t size; + size_t data_left = data_len; VALUE_PAIR *first = NULL; VALUE_PAIR **last = &first; VALUE_PAIR *vp; @@ -195,42 +202,51 @@ static VALUE_PAIR *diameter2vp(SSL *ssl, memcpy(&attr, data, sizeof(attr)); data += 4; attr = ntohl(attr); + vendor = 0; memcpy(&length, data, sizeof(length)); data += 4; length = ntohl(length); /* - * Ignore the M bit. We support all RADIUS attributes... - */ - - /* * A "vendor" flag, with a vendor ID of zero, * is equivalent to no vendor. This is stupid. */ offset = 8; if ((length & (1 << 31)) != 0) { - uint32_t vendor; - memcpy(&vendor, data, sizeof(vendor)); vendor = ntohl(vendor); - attr |= (vendor << 16); + if (vendor > FR_MAX_VENDOR) { + RDEBUG2("Cannot handle vendor Id greater than 2^&24"); + pairfree(&first); + return NULL; + } data += 4; /* skip the vendor field, it's zero */ offset += 4; /* offset to value field */ } /* - * Get the length. + * Vendor attributes can be larger than 255. + * Normal attributes cannot be. */ - length &= 0x00ffffff; + if ((attr > 255) && (vendor == 0)) { + RDEBUG2("Cannot handle Diameter attributes"); + pairfree(&first); + return NULL; + } /* - * diameter code + length, and it must fit in - * a VALUE_PAIR. + * FIXME: Handle the M bit. For now, we assume that + * some other module takes care of any attribute + * with the M bit set. */ - rad_assert(length <= (offset + MAX_STRING_LEN)); + + /* + * Get the length. + */ + length &= 0x00ffffff; /* * Get the size of the value portion of the @@ -241,9 +257,9 @@ static VALUE_PAIR *diameter2vp(SSL *ssl, /* * Create it. */ - vp = paircreate(attr, PW_TYPE_OCTETS); + vp = paircreate(attr, vendor, PW_TYPE_OCTETS); if (!vp) { - DEBUG2(" rlm_eap_ttls: Failure in creating VP"); + RDEBUG2("Failure in creating VP"); pairfree(&first); return NULL; } @@ -256,28 +272,30 @@ static VALUE_PAIR *diameter2vp(SSL *ssl, case PW_TYPE_INTEGER: case PW_TYPE_DATE: if (size != vp->length) { - DEBUG2(" rlm_eap_ttls: Invalid length attribute %d", + RDEBUG2("Invalid length attribute %d", attr); pairfree(&first); + pairfree(&vp); return NULL; } - memcpy(&vp->lvalue, data, vp->length); - + memcpy(&vp->vp_integer, data, vp->length); + /* * Stored in host byte order: change it. */ - vp->lvalue = ntohl(vp->lvalue); + vp->vp_integer = ntohl(vp->vp_integer); break; - + case PW_TYPE_IPADDR: if (size != vp->length) { - DEBUG2(" rlm_eap_ttls: Invalid length attribute %d", + RDEBUG2("Invalid length attribute %d", attr); pairfree(&first); + pairfree(&vp); return NULL; } - memcpy(&vp->lvalue, data, vp->length); - + memcpy(&vp->vp_ipaddr, data, vp->length); + /* * Stored in network byte order: don't change it. */ @@ -290,9 +308,42 @@ static VALUE_PAIR *diameter2vp(SSL *ssl, * FIXME: Ipv6 attributes ? * */ + case PW_TYPE_OCTETS: + if (attr == PW_EAP_MESSAGE) { + const uint8_t *eap_message = data; + + /* + * vp exists the first time around. + */ + while (1) { + vp->length = size; + if (vp->length > 253) vp->length = 253; + memcpy(vp->vp_octets, eap_message, + vp->length); + + size -= vp->length; + eap_message += vp->length; + + *last = vp; + last = &(vp->next); + + if (size == 0) break; + + vp = paircreate(attr, vendor, PW_TYPE_OCTETS); + if (!vp) { + RDEBUG2("Failure in creating VP"); + pairfree(&first); + return NULL; + } + } + + goto next_attr; + } /* else it's another kind of attribute */ + /* FALL-THROUGH */ + default: vp->length = size; - memcpy(vp->strvalue, data, vp->length); + memcpy(vp->vp_strvalue, data, vp->length); break; } @@ -306,14 +357,12 @@ static VALUE_PAIR *diameter2vp(SSL *ssl, */ switch (vp->attribute) { case PW_USER_PASSWORD: - rad_assert(vp->length <= 128); /* RFC requirements */ - /* * If the password is exactly 16 octets, * it won't be zero-terminated. */ - vp->strvalue[vp->length] = '\0'; - vp->length = strlen(vp->strvalue); + vp->vp_strvalue[vp->length] = '\0'; + vp->length = strlen(vp->vp_strvalue); break; /* @@ -342,23 +391,23 @@ static VALUE_PAIR *diameter2vp(SSL *ssl, case PW_MSCHAP_CHALLENGE: if ((vp->length < 8) || (vp->length > 16)) { - DEBUG2(" TTLS: Tunneled challenge has invalid length"); + RDEBUG("Tunneled challenge has invalid length"); pairfree(&first); + pairfree(&vp); return NULL; } else { - int i; uint8_t challenge[16]; eapttls_gen_challenge(ssl, challenge, sizeof(challenge)); - for (i = 0; i < vp->length; i++) { - if (challenge[i] != vp->strvalue[i]) { - DEBUG2(" TTLS: Tunneled challenge is incorrect"); - pairfree(&first); - return NULL; - } + if (memcmp(challenge, vp->vp_octets, + vp->length) != 0) { + RDEBUG("Tunneled challenge is incorrect"); + pairfree(&first); + pairfree(&vp); + return NULL; } } break; @@ -373,6 +422,7 @@ static VALUE_PAIR *diameter2vp(SSL *ssl, *last = vp; last = &(vp->next); + next_attr: /* * Catch non-aligned attributes. */ @@ -405,7 +455,7 @@ static VALUE_PAIR *diameter2vp(SSL *ssl, * are ones which can go inside of a RADIUS (i.e. diameter) * packet. So no server-configuration attributes, or the like. */ -static int vp2diameter(tls_session_t *tls_session, VALUE_PAIR *first) +static int vp2diameter(REQUEST *request, tls_session_t *tls_session, VALUE_PAIR *first) { /* * RADIUS packets are no more than 4k in size, so if @@ -428,7 +478,7 @@ static int vp2diameter(tls_session_t *tls_session, VALUE_PAIR *first) * Too much data: die. */ if ((total + vp->length + 12) >= sizeof(buffer)) { - DEBUG2(" TTLS output buffer is full!"); + RDEBUG2("output buffer is full!"); return 0; } @@ -442,7 +492,7 @@ static int vp2diameter(tls_session_t *tls_session, VALUE_PAIR *first) * issues. */ length = vp->length; - vendor = (vp->attribute >> 16) & 0xffff; + vendor = vp->vendor; if (vendor != 0) { attr = vp->attribute & 0xffff; length |= (1 << 31); @@ -485,21 +535,20 @@ static int vp2diameter(tls_session_t *tls_session, VALUE_PAIR *first) switch (vp->type) { case PW_TYPE_INTEGER: case PW_TYPE_DATE: - attr = ntohl(vp->lvalue); /* stored in host order */ + attr = ntohl(vp->vp_integer); /* stored in host order */ memcpy(p, &attr, sizeof(attr)); length = 4; break; case PW_TYPE_IPADDR: - attr = vp->lvalue; /* stored in network order */ - memcpy(p, &attr, sizeof(attr)); + memcpy(p, &vp->vp_ipaddr, 4); /* network order */ length = 4; break; case PW_TYPE_STRING: case PW_TYPE_OCTETS: default: - memcpy(p, vp->strvalue, vp->length); + memcpy(p, vp->vp_strvalue, vp->length); length = vp->length; break; } @@ -514,7 +563,7 @@ static int vp2diameter(tls_session_t *tls_session, VALUE_PAIR *first) * Align the data to a multiple of 4 bytes. */ if ((total & 0x03) != 0) { - unsigned int i; + size_t i; length = 4 - (total & 0x03); for (i = 0; i < length; i++) { @@ -530,17 +579,17 @@ static int vp2diameter(tls_session_t *tls_session, VALUE_PAIR *first) */ if (total > 0) { #ifndef NDEBUG - unsigned int i; + size_t i; - if (debug_flag > 2) { + if ((debug_flag > 2) && fr_log_fp) { for (i = 0; i < total; i++) { - if ((i & 0x0f) == 0) printf(" TTLS tunnel data out %04x: ", i); + if ((i & 0x0f) == 0) fprintf(fr_log_fp, " TTLS tunnel data out %04x: ", (int) i); - printf("%02x ", buffer[i]); + fprintf(fr_log_fp, "%02x ", buffer[i]); - if ((i & 0x0f) == 0x0f) printf("\n"); + if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n"); } - if ((total & 0x0f) != 0) printf("\n"); + if ((total & 0x0f) != 0) fprintf(fr_log_fp, "\n"); } #endif @@ -549,7 +598,7 @@ static int vp2diameter(tls_session_t *tls_session, VALUE_PAIR *first) /* * FIXME: Check the return code. */ - tls_handshake_send(tls_session); + tls_handshake_send(request, tls_session); } /* @@ -569,6 +618,8 @@ static int process_reply(EAP_HANDLER *handler, tls_session_t *tls_session, ttls_tunnel_t *t = tls_session->opaque; handler = handler; /* -Wunused */ + rad_assert(request != NULL); + rad_assert(handler->request == request); /* * If the response packet was Access-Accept, then @@ -593,7 +644,7 @@ static int process_reply(EAP_HANDLER *handler, tls_session_t *tls_session, */ switch (reply->code) { case PW_AUTHENTICATION_ACK: - DEBUG2(" TTLS: Got tunneled Access-Accept"); + RDEBUG("Got tunneled Access-Accept"); rcode = RLM_MODULE_OK; @@ -606,11 +657,29 @@ static int process_reply(EAP_HANDLER *handler, tls_session_t *tls_session, * packet, and we will send EAP-Success. */ vp = NULL; - pairmove2(&vp, &reply->vps, PW_MSCHAP2_SUCCESS); + pairmove2(&vp, &reply->vps, PW_MSCHAP2_SUCCESS, VENDORPEC_MICROSOFT); if (vp) { - DEBUG2(" TTLS: Got MS-CHAP2-Success, tunneling it to the client in a challenge."); + RDEBUG("Got MS-CHAP2-Success, tunneling it to the client in a challenge."); rcode = RLM_MODULE_HANDLED; t->authenticated = TRUE; + + /* + * Delete MPPE keys & encryption policy. We don't + * want these here. + */ + pairdelete(&reply->vps, 7, VENDORPEC_MICROSOFT); + pairdelete(&reply->vps, 8, VENDORPEC_MICROSOFT); + pairdelete(&reply->vps, 16, VENDORPEC_MICROSOFT); + pairdelete(&reply->vps, 17, VENDORPEC_MICROSOFT); + + /* + * Use the tunneled reply, but not now. + */ + if (t->use_tunneled_reply) { + t->accept_vps = reply->vps; + reply->vps = NULL; + } + } else { /* no MS-CHAP2-Success */ /* * Can only have EAP-Message if there's @@ -621,7 +690,7 @@ static int process_reply(EAP_HANDLER *handler, tls_session_t *tls_session, * can figure it out, from the non-tunneled * EAP-Success packet. */ - pairmove2(&vp, &reply->vps, PW_EAP_MESSAGE); + pairmove2(&vp, &reply->vps, PW_EAP_MESSAGE, 0); pairfree(&vp); } @@ -630,7 +699,7 @@ static int process_reply(EAP_HANDLER *handler, tls_session_t *tls_session, * VP's back to the client. */ if (vp) { - vp2diameter(tls_session, vp); + vp2diameter(request, tls_session, vp); pairfree(&vp); } @@ -642,7 +711,7 @@ static int process_reply(EAP_HANDLER *handler, tls_session_t *tls_session, * tunneled user! */ if (t->use_tunneled_reply) { - pairdelete(&reply->vps, PW_PROXY_STATE); + pairdelete(&reply->vps, PW_PROXY_STATE, 0); pairadd(&request->reply->vps, reply->vps); reply->vps = NULL; } @@ -650,7 +719,7 @@ static int process_reply(EAP_HANDLER *handler, tls_session_t *tls_session, case PW_AUTHENTICATION_REJECT: - DEBUG2(" TTLS: Got tunneled Access-Reject"); + RDEBUG("Got tunneled Access-Reject"); rcode = RLM_MODULE_REJECT; break; @@ -661,7 +730,7 @@ static int process_reply(EAP_HANDLER *handler, tls_session_t *tls_session, * a Reply-Message to the client. */ case PW_ACCESS_CHALLENGE: - DEBUG2(" TTLS: Got tunneled Access-Challenge"); + RDEBUG("Got tunneled Access-Challenge"); /* * Keep the State attribute, if necessary. @@ -669,7 +738,7 @@ static int process_reply(EAP_HANDLER *handler, tls_session_t *tls_session, * Get rid of the old State, too. */ pairfree(&t->state); - pairmove2(&t->state, &reply->vps, PW_STATE); + pairmove2(&t->state, &reply->vps, PW_STATE, 0); /* * We should really be a bit smarter about this, @@ -679,7 +748,7 @@ static int process_reply(EAP_HANDLER *handler, tls_session_t *tls_session, * method works in 99.9% of the situations. */ vp = NULL; - pairmove2(&vp, &reply->vps, PW_EAP_MESSAGE); + pairmove2(&vp, &reply->vps, PW_EAP_MESSAGE, 0); /* * There MUST be a Reply-Message in the challenge, @@ -689,21 +758,21 @@ static int process_reply(EAP_HANDLER *handler, tls_session_t *tls_session, * we MUST create one, with an empty string as * it's value. */ - pairmove2(&vp, &reply->vps, PW_REPLY_MESSAGE); + pairmove2(&vp, &reply->vps, PW_REPLY_MESSAGE, 0); /* * Handle the ACK, by tunneling any necessary reply * VP's back to the client. */ if (vp) { - vp2diameter(tls_session, vp); + vp2diameter(request, tls_session, vp); pairfree(&vp); } rcode = RLM_MODULE_HANDLED; break; default: - DEBUG2(" TTLS: Unknown RADIUS packet type %d: rejecting tunneled user", reply->code); + RDEBUG("Unknown RADIUS packet type %d: rejecting tunneled user", reply->code); rcode = RLM_MODULE_INVALID; break; } @@ -712,6 +781,7 @@ static int process_reply(EAP_HANDLER *handler, tls_session_t *tls_session, } +#ifdef WITH_PROXY /* * Do post-proxy processing, */ @@ -719,9 +789,10 @@ static int eapttls_postproxy(EAP_HANDLER *handler, void *data) { int rcode; tls_session_t *tls_session = (tls_session_t *) data; - REQUEST *fake; + REQUEST *fake, *request = handler->request; - DEBUG2(" TTLS: Passing reply from proxy back into the tunnel."); + rad_assert(request != NULL); + RDEBUG("Passing reply from proxy back into the tunnel."); /* * If there was a fake request associated with the proxied @@ -730,43 +801,44 @@ static int eapttls_postproxy(EAP_HANDLER *handler, void *data) fake = (REQUEST *) request_data_get(handler->request, handler->request->proxy, REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK); - + /* * Do the callback, if it exists, and if it was a success. */ if (fake && (handler->request->proxy_reply->code == PW_AUTHENTICATION_ACK)) { - VALUE_PAIR *vp; - REQUEST *request = handler->request; - /* * Terrible hacks. */ rad_assert(fake->packet == NULL); fake->packet = request->proxy; + fake->packet->src_ipaddr = request->packet->src_ipaddr; request->proxy = NULL; rad_assert(fake->reply == NULL); fake->reply = request->proxy_reply; request->proxy_reply = NULL; + if ((debug_flag > 0) && fr_log_fp) { + fprintf(fr_log_fp, "server %s {\n", + (fake->server == NULL) ? "" : fake->server); + } + /* * Perform a post-auth stage for the tunneled * session. */ fake->options &= ~RAD_REQUEST_OPTION_PROXY_EAP; rcode = rad_postauth(fake); - DEBUG2(" POST-AUTH %d", rcode); + RDEBUG2("post-auth returns %d", rcode); -#ifndef NDEBUG - if (debug_flag > 0) { - printf(" TTLS: Final reply from tunneled session code %d\n", - fake->reply->code); + if ((debug_flag > 0) && fr_log_fp) { + fprintf(fr_log_fp, "} # server %s\n", + (fake->server == NULL) ? "" : fake->server); - for (vp = fake->reply->vps; vp != NULL; vp = vp->next) { - putchar('\t');vp_print(stdout, vp);putchar('\n'); - } + RDEBUG("Final reply from tunneled session code %d", + fake->reply->code); + debug_pair_list(fake->reply->vps); } -#endif /* * Terrible hacks. @@ -783,15 +855,15 @@ static int eapttls_postproxy(EAP_HANDLER *handler, void *data) switch (rcode) { case RLM_MODULE_FAIL: request_free(&fake); - eaptls_fail(handler->eap_ds, 0); + eaptls_fail(handler, 0); return 0; break; - + default: /* Don't Do Anything */ - DEBUG2(" TTLS: Got reply %d", + RDEBUG2("Got reply %d", request->proxy_reply->code); break; - } + } } request_free(&fake); /* robust if fake == NULL */ @@ -810,28 +882,28 @@ static int eapttls_postproxy(EAP_HANDLER *handler, void *data) switch (rcode) { case RLM_MODULE_REJECT: - DEBUG2(" TTLS: Reply was rejected"); + RDEBUG("Reply was rejected"); break; case RLM_MODULE_HANDLED: - DEBUG2(" TTLS: Reply was handled"); + RDEBUG("Reply was handled"); eaptls_request(handler->eap_ds, tls_session); return 1; case RLM_MODULE_OK: - DEBUG2(" TTLS: Reply was OK"); - eaptls_success(handler->eap_ds, 0); - eaptls_gen_mppe_keys(&handler->request->reply->vps, - tls_session->ssl, - "ttls keying material"); - return 1; + RDEBUG("Reply was OK"); + + /* + * Success: Automatically return MPPE keys. + */ + return eaptls_success(handler, 0); default: - DEBUG2(" TTLS: Reply was unknown."); + RDEBUG("Reply was unknown."); break; } - eaptls_fail(handler->eap_ds, 0); + eaptls_fail(handler, 0); return 0; } @@ -845,59 +917,30 @@ static void my_request_free(void *data) request_free(&request); } - +#endif /* WITH_PROXY */ /* * Process the "diameter" contents of the tunneled data. */ int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session) { - int err; int rcode = PW_AUTHENTICATION_REJECT; REQUEST *fake; VALUE_PAIR *vp; ttls_tunnel_t *t; const uint8_t *data; - unsigned int data_len; - char buffer[1024]; + size_t data_len; REQUEST *request = handler->request; - /* - * Grab the dirty data, and copy it to our buffer. - * - * I *really* don't like these 'record_t' things... - */ - data_len = (tls_session->record_minus)(&tls_session->dirty_in, buffer, sizeof(buffer)); - data = buffer; + rad_assert(request != NULL); /* - * Write the data from the dirty buffer (i.e. packet - * data) into the buffer which we will give to SSL for - * decoding. - * - * Some of this code COULD technically go into the TLS - * module, in eaptls_process(), where it returns EAPTLS_OK. - * - * Similarly, the writing of data to the SSL context could - * go there, too... + * Just look at the buffer directly, without doing + * record_minus. */ - BIO_write(tls_session->into_ssl, buffer, data_len); - (tls_session->record_init)(&tls_session->clean_out); - - /* - * Read (and decrypt) the tunneled data from the SSL session, - * and put it into the decrypted data buffer. - */ - err = SSL_read(tls_session->ssl, tls_session->clean_out.data, - sizeof(tls_session->clean_out.data)); - if (err < 0) { - /* - * FIXME: Call SSL_get_error() to see what went - * wrong. - */ - radlog(L_INFO, "rlm_eap_ttls: SSL_read Error"); - return PW_AUTHENTICATION_REJECT; - } + data_len = tls_session->clean_out.used; + tls_session->clean_out.used = 0; + data = tls_session->clean_out.data; t = (ttls_tunnel_t *) tls_session->opaque; @@ -905,9 +948,9 @@ int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session) * If there's no data, maybe this is an ACK to an * MS-CHAP2-Success. */ - if (err == 0) { + if (data_len == 0) { if (t->authenticated) { - DEBUG2(" TTLS: Got ACK, and the user was already authenticated."); + RDEBUG("Got ACK, and the user was already authenticated."); return PW_AUTHENTICATION_ACK; } /* else no session, no data, die. */ @@ -915,29 +958,26 @@ int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session) * FIXME: Call SSL_get_error() to see what went * wrong. */ - radlog(L_INFO, "rlm_eap_ttls: SSL_read Error"); + RDEBUG2("SSL_read Error"); return PW_AUTHENTICATION_REJECT; } - data_len = tls_session->clean_out.used = err; - data = tls_session->clean_out.data; - #ifndef NDEBUG - if (debug_flag > 2) { - unsigned int i; + if ((debug_flag > 2) && fr_log_fp) { + size_t i; for (i = 0; i < data_len; i++) { - if ((i & 0x0f) == 0) printf(" TTLS tunnel data in %04x: ", i); + if ((i & 0x0f) == 0) fprintf(fr_log_fp, " TTLS tunnel data in %04x: ", (int) i); - printf("%02x ", data[i]); + fprintf(fr_log_fp, "%02x ", data[i]); - if ((i & 0x0f) == 0x0f) printf("\n"); + if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n"); } - if ((data_len & 0x0f) != 0) printf("\n"); + if ((data_len & 0x0f) != 0) fprintf(fr_log_fp, "\n"); } #endif - if (!diameter_verify(data, data_len)) { + if (!diameter_verify(request, data, data_len)) { return PW_AUTHENTICATION_REJECT; } @@ -951,8 +991,9 @@ int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session) /* * Add the tunneled attributes to the fake request. */ - fake->packet->vps = diameter2vp(tls_session->ssl, data, data_len); + fake->packet->vps = diameter2vp(request, tls_session->ssl, data, data_len); if (!fake->packet->vps) { + request_free(&fake); return PW_AUTHENTICATION_REJECT; } @@ -964,21 +1005,17 @@ int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session) pairadd(&fake->packet->vps, vp); } -#ifndef NDEBUG - if (debug_flag > 0) { - printf(" TTLS: Got tunneled request\n"); - - for (vp = fake->packet->vps; vp != NULL; vp = vp->next) { - putchar('\t');vp_print(stdout, vp);putchar('\n'); - } + if ((debug_flag > 0) && fr_log_fp) { + RDEBUG("Got tunneled request"); + + debug_pair_list(fake->packet->vps); } -#endif /* * Update other items in the REQUEST data structure. */ - fake->username = pairfind(fake->packet->vps, PW_USER_NAME); - fake->password = pairfind(fake->packet->vps, PW_PASSWORD); + fake->username = pairfind(fake->packet->vps, PW_USER_NAME, 0); + fake->password = pairfind(fake->packet->vps, PW_USER_PASSWORD, 0); /* * No User-Name, try to create one from stored data. @@ -989,36 +1026,36 @@ int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session) * an EAP-Identity, and pull it out of there. */ if (!t->username) { - vp = pairfind(fake->packet->vps, PW_EAP_MESSAGE); + vp = pairfind(fake->packet->vps, PW_EAP_MESSAGE, 0); if (vp && (vp->length >= EAP_HEADER_LEN + 2) && - (vp->strvalue[0] == PW_EAP_RESPONSE) && - (vp->strvalue[EAP_HEADER_LEN] == PW_EAP_IDENTITY) && - (vp->strvalue[EAP_HEADER_LEN + 1] != 0)) { + (vp->vp_strvalue[0] == PW_EAP_RESPONSE) && + (vp->vp_strvalue[EAP_HEADER_LEN] == PW_EAP_IDENTITY) && + (vp->vp_strvalue[EAP_HEADER_LEN + 1] != 0)) { /* * Create & remember a User-Name */ t->username = pairmake("User-Name", "", T_OP_EQ); rad_assert(t->username != NULL); - memcpy(t->username->strvalue, vp->strvalue + 5, + memcpy(t->username->vp_strvalue, vp->vp_strvalue + 5, vp->length - 5); t->username->length = vp->length - 5; - t->username->strvalue[t->username->length] = 0; + t->username->vp_strvalue[t->username->length] = 0; - DEBUG2(" TTLS: Got tunneled identity of %s", - t->username->strvalue); + RDEBUG("Got tunneled identity of %s", + t->username->vp_strvalue); /* * If there's a default EAP type, * set it here. */ if (t->default_eap_type != 0) { - DEBUG2(" TTLS: Setting default EAP type for tunneled EAP session."); - vp = paircreate(PW_EAP_TYPE, + RDEBUG("Setting default EAP type for tunneled EAP session."); + vp = paircreate(PW_EAP_TYPE, 0, PW_TYPE_INTEGER); rad_assert(vp != NULL); - vp->lvalue = t->default_eap_type; + vp->vp_integer = t->default_eap_type; pairadd(&fake->config_items, vp); } @@ -1028,14 +1065,14 @@ int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session) * as it's permitted to do EAP without * user-name. */ - DEBUG2(" rlm_eap_ttls: WARNING! No EAP-Identity found to start EAP conversation."); + RDEBUG2("WARNING! No EAP-Identity found to start EAP conversation."); } } /* else there WAS a t->username */ if (t->username) { vp = paircopy(t->username); pairadd(&fake->packet->vps, vp); - fake->username = pairfind(fake->packet->vps, PW_USER_NAME); + fake->username = pairfind(fake->packet->vps, PW_USER_NAME, 0); } } /* else the request ALREADY had a User-Name */ @@ -1043,8 +1080,6 @@ int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session) * Add the State attribute, too, if it exists. */ if (t->state) { - DEBUG2(" TTLS: Adding old state with %02x %02x", - t->state->strvalue[0], t->state->strvalue[1]); vp = paircopy(t->state); if (vp) pairadd(&fake->packet->vps, vp); } @@ -1065,7 +1100,7 @@ int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session) * don't copy it. */ if ((vp->attribute > 255) && - (((vp->attribute >> 16) & 0xffff) == 0)) { + (vp->vendor == 0)) { continue; } @@ -1078,7 +1113,7 @@ int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session) * AND attributes which are copied there * from below. */ - if (pairfind(fake->packet->vps, vp->attribute)) { + if (pairfind(fake->packet->vps, vp->attribute, vp->vendor)) { continue; } @@ -1113,20 +1148,28 @@ int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session) * Don't copy from the head, we've already * checked it. */ - copy = paircopy2(vp, vp->attribute); + copy = paircopy2(vp, vp->attribute, vp->vendor); pairadd(&fake->packet->vps, copy); } } -#ifndef NDEBUG - if (debug_flag > 0) { - printf(" TTLS: Sending tunneled request\n"); + if ((vp = pairfind(request->config_items, PW_VIRTUAL_SERVER, 0)) != NULL) { + fake->server = vp->vp_strvalue; + + } else if (t->virtual_server) { + fake->server = t->virtual_server; + + } /* else fake->server == request->server */ + + + if ((debug_flag > 0) && fr_log_fp) { + RDEBUG("Sending tunneled request"); - for (vp = fake->packet->vps; vp != NULL; vp = vp->next) { - putchar('\t');vp_print(stdout, vp);putchar('\n'); - } + debug_pair_list(fake->packet->vps); + + fprintf(fr_log_fp, "server %s {\n", + (fake->server == NULL) ? "" : fake->server); } -#endif /* * Call authentication recursively, which will @@ -1138,26 +1181,25 @@ int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session) * Note that we don't do *anything* with the reply * attributes. */ -#ifndef NDEBUG - if (debug_flag > 0) { - printf(" TTLS: Got tunneled reply RADIUS code %d\n", - fake->reply->code); + if ((debug_flag > 0) && fr_log_fp) { + fprintf(fr_log_fp, "} # server %s\n", + (fake->server == NULL) ? "" : fake->server); - for (vp = fake->reply->vps; vp != NULL; vp = vp->next) { - putchar('\t');vp_print(stdout, vp);putchar('\n'); - } + RDEBUG("Got tunneled reply code %d", fake->reply->code); + + debug_pair_list(fake->reply->vps); } -#endif /* * Decide what to do with the reply. */ switch (fake->reply->code) { case 0: /* No reply code, must be proxied... */ - vp = pairfind(fake->config_items, PW_PROXY_TO_REALM); +#ifdef WITH_PROXY + vp = pairfind(fake->config_items, PW_PROXY_TO_REALM, 0); if (vp) { eap_tunnel_data_t *tunnel; - DEBUG2(" TTLS: Tunneled authentication will be proxied to %s", vp->strvalue); + RDEBUG("Tunneled authentication will be proxied to %s", vp->vp_strvalue); /* * Tell the original request that it's going @@ -1165,7 +1207,7 @@ int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session) */ pairmove2(&(request->config_items), &(fake->config_items), - PW_PROXY_TO_REALM); + PW_PROXY_TO_REALM, 0); /* * Seed the proxy packet with the @@ -1173,6 +1215,12 @@ int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session) */ rad_assert(request->proxy == NULL); request->proxy = fake->packet; + memset(&request->proxy->src_ipaddr, 0, + sizeof(request->proxy->src_ipaddr)); + memset(&request->proxy->src_ipaddr, 0, + sizeof(request->proxy->src_ipaddr)); + request->proxy->src_port = 0; + request->proxy->dst_port = 0; fake->packet = NULL; rad_free(&fake->reply); fake->reply = NULL; @@ -1194,7 +1242,7 @@ int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session) REQUEST_DATA_EAP_TUNNEL_CALLBACK, tunnel, free); rad_assert(rcode == 0); - + /* * rlm_eap.c has taken care of associating * the handler with the fake request. @@ -1215,8 +1263,10 @@ int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session) */ rcode = PW_STATUS_CLIENT; - } else { - DEBUG2(" TTLS: No tunneled reply was found for request %d , and the request was not proxied: rejecting the user.", + } else +#endif /* WITH_PROXY */ + { + RDEBUG("No tunneled reply was found for request %d , and the request was not proxied: rejecting the user.", request->number); rcode = PW_AUTHENTICATION_REJECT; } @@ -1233,15 +1283,15 @@ int eapttls_process(EAP_HANDLER *handler, tls_session_t *tls_session) case RLM_MODULE_REJECT: rcode = PW_AUTHENTICATION_REJECT; break; - + case RLM_MODULE_HANDLED: rcode = PW_ACCESS_CHALLENGE; break; - + case RLM_MODULE_OK: rcode = PW_AUTHENTICATION_ACK; break; - + default: rcode = PW_AUTHENTICATION_REJECT; break;