📄 ttls.c
字号:
* The length does NOT include the padding, so * we've got to account for it here by rounding up * to the nearest 4-byte boundary. */ length += 0x03; length &= ~0x03; rad_assert(data_left >= length); data_left -= length; data += length - offset; /* already updated */ } /* * We got this far. It looks OK. */ return first;}/* * Convert VALUE_PAIR's to diameter attributes, and write them * to an SSL session. * * The ONLY VALUE_PAIR's which may be passed to this function * 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){ /* * RADIUS packets are no more than 4k in size, so if * we've got more than 4k of data to write, it's very * bad. */ uint8_t buffer[4096]; uint8_t *p; uint32_t attr; uint32_t length; uint32_t vendor; size_t total; VALUE_PAIR *vp; p = buffer; total = 0; for (vp = first; vp != NULL; vp = vp->next) { /* * Too much data: die. */ if ((total + vp->length + 12) >= sizeof(buffer)) { DEBUG2(" TTLS output buffer is full!"); return 0; } /* * Hmm... we don't group multiple EAP-Messages * together. Maybe we should... */ /* * Length is no more than 253, due to RADIUS * issues. */ length = vp->length; vendor = (vp->attribute >> 16) & 0xffff; if (vendor != 0) { attr = vp->attribute & 0xffff; length |= (1 << 31); } else { attr = vp->attribute; } /* * Hmm... set the M bit for all attributes? */ length |= (1 << 30); attr = ntohl(attr); memcpy(p, &attr, sizeof(attr)); p += 4; total += 4; length += 8; /* includes 8 bytes of attr & length */ if (vendor != 0) { length += 4; /* include 4 bytes of vendor */ length = ntohl(length); memcpy(p, &length, sizeof(length)); p += 4; total += 4; vendor = ntohl(vendor); memcpy(p, &vendor, sizeof(vendor)); p += 4; total += 4; } else { length = ntohl(length); memcpy(p, &length, sizeof(length)); p += 4; total += 4; } switch (vp->type) { case PW_TYPE_INTEGER: case PW_TYPE_DATE: attr = ntohl(vp->vp_integer); /* stored in host order */ memcpy(p, &attr, sizeof(attr)); length = 4; break; case PW_TYPE_IPADDR: memcpy(p, &vp->vp_ipaddr, 4); /* network order */ length = 4; break; case PW_TYPE_STRING: case PW_TYPE_OCTETS: default: memcpy(p, vp->vp_strvalue, vp->length); length = vp->length; break; } /* * Skip to the end of the data. */ p += length; total += length; /* * Align the data to a multiple of 4 bytes. */ if ((total & 0x03) != 0) { size_t i; length = 4 - (total & 0x03); for (i = 0; i < length; i++) { *p = '\0'; p++; total++; } } } /* loop over the VP's to write. */ /* * Write the data in the buffer to the SSL session. */ if (total > 0) {#ifndef NDEBUG size_t i; if ((debug_flag > 2) && fr_log_fp) { for (i = 0; i < total; i++) { if ((i & 0x0f) == 0) fprintf(fr_log_fp, " TTLS tunnel data out %04x: ", i); fprintf(fr_log_fp, "%02x ", buffer[i]); if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n"); } if ((total & 0x0f) != 0) fprintf(fr_log_fp, "\n"); }#endif (tls_session->record_plus)(&tls_session->clean_in, buffer, total); /* * FIXME: Check the return code. */ tls_handshake_send(tls_session); } /* * Everything's OK. */ return 1;}/* * Use a reply packet to determine what to do. */static int process_reply(EAP_HANDLER *handler, tls_session_t *tls_session, REQUEST *request, RADIUS_PACKET *reply){ int rcode = RLM_MODULE_REJECT; VALUE_PAIR *vp; ttls_tunnel_t *t = tls_session->opaque; handler = handler; /* -Wunused */ /* * If the response packet was Access-Accept, then * we're OK. If not, die horribly. * * FIXME: Take MS-CHAP2-Success attribute, and * tunnel it back to the client, to authenticate * ourselves to the client. * * FIXME: If we have an Access-Challenge, then * the Reply-Message is tunneled back to the client. * * FIXME: If we have an EAP-Message, then that message * must be tunneled back to the client. * * FIXME: If we have an Access-Challenge with a State * attribute, then do we tunnel that to the client, or * keep track of it ourselves? * * FIXME: EAP-Messages can only start with 'identity', * NOT 'eap start', so we should check for that.... */ switch (reply->code) { case PW_AUTHENTICATION_ACK: DEBUG2(" TTLS: Got tunneled Access-Accept"); rcode = RLM_MODULE_OK; /* * MS-CHAP2-Success means that we do NOT return * an Access-Accept, but instead tunnel that * attribute to the client, and keep going with * the TTLS session. Once the client accepts * our identity, it will respond with an empty * packet, and we will send EAP-Success. */ vp = NULL; pairmove2(&vp, &reply->vps, PW_MSCHAP2_SUCCESS); if (vp) { DEBUG2(" TTLS: 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, ((311 << 16) | 7)); pairdelete(&reply->vps, ((311 << 16) | 8)); pairdelete(&reply->vps, ((311 << 16) | 16)); pairdelete(&reply->vps, ((311 << 16) | 17)); /* * Use the tunneled reply, but not now. */ if (t->use_tunneled_reply) { t->reply = reply->vps; reply->vps = NULL; } } else { /* no MS-CHAP2-Success */ /* * Can only have EAP-Message if there's * no MS-CHAP2-Success. (FIXME: EAP-MSCHAP?) * * We also do NOT tunnel the EAP-Success * attribute back to the client, as the client * can figure it out, from the non-tunneled * EAP-Success packet. */ pairmove2(&vp, &reply->vps, PW_EAP_MESSAGE); pairfree(&vp); } /* * Handle the ACK, by tunneling any necessary reply * VP's back to the client. */ if (vp) { vp2diameter(tls_session, vp); pairfree(&vp); } /* * If we've been told to use the attributes from * the reply, then do so. * * WARNING: This may leak information about the * tunneled user! */ if (t->use_tunneled_reply) { pairdelete(&reply->vps, PW_PROXY_STATE); pairadd(&request->reply->vps, reply->vps); reply->vps = NULL; } break; case PW_AUTHENTICATION_REJECT: DEBUG2(" TTLS: Got tunneled Access-Reject"); rcode = RLM_MODULE_REJECT; break; /* * Handle Access-Challenge, but only if we * send tunneled reply data. This is because * an Access-Challenge means that we MUST tunnel * a Reply-Message to the client. */ case PW_ACCESS_CHALLENGE: DEBUG2(" TTLS: Got tunneled Access-Challenge"); /* * Keep the State attribute, if necessary. * * Get rid of the old State, too. */ pairfree(&t->state); pairmove2(&t->state, &reply->vps, PW_STATE); /* * We should really be a bit smarter about this, * and move over only those attributes which * are relevant to the authentication request, * but that's a lot more work, and this "dumb" * method works in 99.9% of the situations. */ vp = NULL; pairmove2(&vp, &reply->vps, PW_EAP_MESSAGE); /* * There MUST be a Reply-Message in the challenge, * which we tunnel back to the client. * * If there isn't one in the reply VP's, then * we MUST create one, with an empty string as * it's value. */ pairmove2(&vp, &reply->vps, PW_REPLY_MESSAGE); /* * Handle the ACK, by tunneling any necessary reply * VP's back to the client. */ if (vp) { vp2diameter(tls_session, vp); pairfree(&vp); } rcode = RLM_MODULE_HANDLED; break; default: DEBUG2(" TTLS: Unknown RADIUS packet type %d: rejecting tunneled user", reply->code); rcode = RLM_MODULE_INVALID; break; } return rcode;}/* * Do post-proxy processing, */static int eapttls_postproxy(EAP_HANDLER *handler, void *data){ int rcode; tls_session_t *tls_session = (tls_session_t *) data; REQUEST *fake; DEBUG2(" TTLS: Passing reply from proxy back into the tunnel."); /* * If there was a fake request associated with the proxied * request, do more processing of it. */ 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; /* * 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);#ifndef NDEBUG if ((debug_flag > 0) && fr_log_fp) { fprintf(fr_log_fp, " TTLS: Final reply from tunneled session code %d\n", fake->reply->code); for (vp = fake->reply->vps; vp != NULL; vp = vp->next) { fputc('\t', fr_log_fp); vp_print(fr_log_fp, vp); fputc('\n', fr_log_fp); } }#endif /* * Terrible hacks. */ request->proxy = fake->packet; fake->packet = NULL; request->proxy_reply = fake->reply; fake->reply = NULL; /* * And we're done with this request. */ switch (rcode) { case RLM_MODULE_FAIL: request_free(&fake); eaptls_fail(handler->eap_ds, 0); return 0; break; default: /* Don't Do Anything */ DEBUG2(" TTLS: Got reply %d", request->proxy_reply->code); break; } } request_free(&fake); /* robust if fake == NULL */ /* * Process the reply from the home server. */ rcode = process_reply(handler, tls_session, handler->request,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -