📄 eap.c
字号:
* i.e. code+id+length+data where data = null/type+typedata * based on code. */static int eap_wireformat(EAP_PACKET *reply){ eap_packet_t *hdr; uint16_t total_length = 0; if (reply == NULL) return EAP_INVALID; total_length = EAP_HEADER_LEN; if (reply->code < 3) { total_length += 1/*EAPtype*/; if (reply->type.data && reply->type.length > 0) { total_length += reply->type.length; } } reply->packet = (unsigned char *)malloc(total_length); hdr = (eap_packet_t *)reply->packet; if (!hdr) { radlog(L_ERR, "rlm_eap: out of memory"); return EAP_INVALID; } hdr->code = (reply->code & 0xFF); hdr->id = (reply->id & 0xFF); total_length = htons(total_length); memcpy(hdr->length, &total_length, sizeof(uint16_t)); /* * Request and Response packets are special. */ if ((reply->code == PW_EAP_REQUEST) || (reply->code == PW_EAP_RESPONSE)) { hdr->data[0] = (reply->type.type & 0xFF); /* * Here since we cannot know the typedata format and length * * Type_data is expected to be wired by each EAP-Type * * Zero length/No typedata is supported as long as * type is defined */ if (reply->type.data && reply->type.length > 0) { memcpy(&hdr->data[1], reply->type.data, reply->type.length); free(reply->type.data); reply->type.data = reply->packet + EAP_HEADER_LEN + 1/*EAPtype*/; } } return EAP_VALID;}/* * compose EAP reply packet in EAP-Message attr of RADIUS. If * EAP exceeds 253, frame it in multiple EAP-Message attrs. * * Set the RADIUS reply codes based on EAP request codes. Append * any additonal VPs to RADIUS reply */int eap_compose(EAP_HANDLER *handler){ uint16_t eap_len, len; VALUE_PAIR *eap_msg; VALUE_PAIR *vp; eap_packet_t *eap_packet; unsigned char *ptr; REQUEST *request = handler->request; EAP_DS *eap_ds = handler->eap_ds; EAP_PACKET *reply = eap_ds->request; int rcode; /* * The Id for the EAP packet to the NAS wasn't set. * Do so now. * * LEAP requires the Id to be incremented on EAP-Success * in Stage 4, so that we can carry on the conversation * where the client asks us to authenticate ourselves * in stage 5. */ if (!eap_ds->set_request_id) { /* * Id serves to suppport request/response * retransmission in the EAP layer and as such * must be different for 'adjacent' packets * except in case of success/failure-replies. * * RFC2716 (EAP-TLS) requires this to be * incremented, RFC2284 only makes the above- * mentioned restriction. */ reply->id = handler->eap_ds->response->id; switch (reply->code) { /* * The Id is a simple "ack" for success * and failure. * * RFC 3748 section 4.2 says * * ... The Identifier field MUST match * the Identifier field of the Response * packet that it is sent in response * to. */ case PW_EAP_SUCCESS: case PW_EAP_FAILURE: break; /* * We've sent a response to their * request, the Id is incremented. */ default: ++reply->id; } } else { DEBUG2(" rlm_eap: Underlying EAP-Type set EAP ID to %d", reply->id); } /* * For Request & Response packets, set the EAP sub-type, * if the EAP sub-module didn't already set it. * * This allows the TLS module to be "morphic", and means * that the TTLS and PEAP modules can call it to do most * of their dirty work. */ if (((eap_ds->request->code == PW_EAP_REQUEST) || (eap_ds->request->code == PW_EAP_RESPONSE)) && (eap_ds->request->type.type == 0)) { rad_assert(handler->eap_type >= PW_EAP_MD5); rad_assert(handler->eap_type <= PW_EAP_MAX_TYPES); eap_ds->request->type.type = handler->eap_type; } if (eap_wireformat(reply) == EAP_INVALID) { return RLM_MODULE_INVALID; } eap_packet = (eap_packet_t *)reply->packet; memcpy(&eap_len, &(eap_packet->length), sizeof(uint16_t)); len = eap_len = ntohs(eap_len); ptr = (unsigned char *)eap_packet; do { if (eap_len > 253) { len = 253; eap_len -= 253; } else { len = eap_len; eap_len = 0; } /* * create a value pair & append it to the request reply list * This memory gets freed up when request is freed up */ eap_msg = paircreate(PW_EAP_MESSAGE, PW_TYPE_OCTETS); memcpy(eap_msg->strvalue, ptr, len); eap_msg->length = len; pairadd(&(request->reply->vps), eap_msg); ptr += len; eap_msg = NULL; } while (eap_len); /* * EAP-Message is always associated with * Message-Authenticator but not vice-versa. * * Don't add a Message-Authenticator if it's already * there. */ vp = pairfind(request->reply->vps, PW_MESSAGE_AUTHENTICATOR); if (!vp) { vp = paircreate(PW_MESSAGE_AUTHENTICATOR, PW_TYPE_OCTETS); memset(vp->strvalue, 0, AUTH_VECTOR_LEN); vp->length = AUTH_VECTOR_LEN; pairadd(&(request->reply->vps), vp); } /* Set request reply code, but only if it's not already set. */ rcode = RLM_MODULE_OK; if (!request->reply->code) switch(reply->code) { case PW_EAP_RESPONSE: request->reply->code = PW_AUTHENTICATION_ACK; rcode = RLM_MODULE_HANDLED; /* leap weirdness */ break; case PW_EAP_SUCCESS: request->reply->code = PW_AUTHENTICATION_ACK; rcode = RLM_MODULE_OK; break; case PW_EAP_FAILURE: request->reply->code = PW_AUTHENTICATION_REJECT; rcode = RLM_MODULE_REJECT; break; case PW_EAP_REQUEST: request->reply->code = PW_ACCESS_CHALLENGE; rcode = RLM_MODULE_HANDLED; break; default: /* * When we're pulling MS-CHAPv2 out of EAP-MS-CHAPv2, * we do so WITHOUT setting a reply code, as the * request is being proxied. */ if (request->options & RAD_REQUEST_OPTION_PROXY_EAP) { return RLM_MODULE_HANDLED; } /* Should never enter here */ radlog(L_ERR, "rlm_eap: reply code %d is unknown, Rejecting the request.", reply->code); request->reply->code = PW_AUTHENTICATION_REJECT; reply->code = PW_EAP_FAILURE; rcode = RLM_MODULE_REJECT; break; } return rcode;}/* * Radius criteria, EAP-Message is invalid without Message-Authenticator * For EAP_START, send Access-Challenge with EAP Identity request. */int eap_start(rlm_eap_t *inst, REQUEST *request){ VALUE_PAIR *vp, *proxy; VALUE_PAIR *eap_msg; eap_msg = pairfind(request->packet->vps, PW_EAP_MESSAGE); if (eap_msg == NULL) { DEBUG2(" rlm_eap: No EAP-Message, not doing EAP"); return EAP_NOOP; } /* * Look for EAP-Type = None (FreeRADIUS specific attribute) * this allows you to NOT do EAP for some users. */ vp = pairfind(request->packet->vps, PW_EAP_TYPE); if (vp && vp->lvalue == 0) { DEBUG2(" rlm_eap: Found EAP-Message, but EAP-Type = None, so we're not doing EAP."); return EAP_NOOP; } /* * http://www.freeradius.org/rfc/rfc2869.html#EAP-Message * * Checks for Message-Authenticator are handled by rad_recv(). */ /* * Check for a Proxy-To-Realm. Don't get excited over LOCAL * realms (sigh). */ proxy = pairfind(request->config_items, PW_PROXY_TO_REALM); if (proxy) { REALM *realm; /* * If it's a LOCAL realm, then we're not proxying * to it. */ realm = realm_find(proxy->strvalue, 0); if (realm && (realm->ipaddr == htonl(INADDR_NONE))) { proxy = NULL; } } /* * Check the length before de-referencing the contents. * * Lengths of zero are required by the RFC for EAP-Start, * but we've never seen them in practice. * * Lengths of two are what we see in practice as * EAP-Starts. */ if ((eap_msg->length == 0) || (eap_msg->length == 2)) { EAP_DS *eap_ds; EAP_HANDLER handler; /* * It's a valid EAP-Start, but the request * was marked as being proxied. So we don't * do EAP, as the home server will do it. */ if (proxy) { do_proxy: DEBUG2(" rlm_eap: Request is supposed to be proxied to Realm %s. Not doing EAP.", proxy->strvalue); return EAP_NOOP; } DEBUG2(" rlm_eap: Got EAP_START message"); if ((eap_ds = eap_ds_alloc()) == NULL) { DEBUG2(" rlm_eap: EAP Start failed in allocation"); return EAP_FAIL; } /* * It's an EAP-Start packet. Tell them to stop wasting * our time, and give us an EAP-Identity packet. * * Hmm... we should probably check the contents of the * EAP-Start packet for something... */ eap_ds->request->code = PW_EAP_REQUEST; eap_ds->request->type.type = PW_EAP_IDENTITY; /* * We don't have a handler, but eap_compose needs one, * (for various reasons), so we fake it out here. */ memset(&handler, 0, sizeof(handler)); handler.request = request; handler.eap_ds = eap_ds; eap_compose(&handler); eap_ds_free(&eap_ds); return EAP_FOUND; } /* end of handling EAP-Start */ /* * The EAP packet header is 4 bytes, plus one byte of * EAP sub-type. Short packets are discarded, unless * we're proxying. */ if (eap_msg->length < (EAP_HEADER_LEN + 1)) { if (proxy) goto do_proxy; DEBUG2(" rlm_eap: Ignoring EAP-Message which is too short to be meaningful."); return EAP_FAIL; } /* * Create an EAP-Type containing the EAP-type * from the packet. */ vp = paircreate(PW_EAP_TYPE, PW_TYPE_INTEGER); if (vp) { vp->lvalue = eap_msg->strvalue[4]; pairadd(&(request->packet->vps), vp); } /* * If the request was marked to be proxied, do it now. * This is done after checking for a valid length * (which may not be good), and after adding the EAP-Type * attribute. This lets other modules selectively cancel * proxying based on EAP-Type. */ if (proxy) goto do_proxy; /* * From now on, we're supposed to be handling the * EAP packet. We better understand it... */ /* * We're allowed only a few codes. Request, Response, * Success, or Failure. */ if ((eap_msg->strvalue[0] == 0) || (eap_msg->strvalue[0] > PW_EAP_MAX_CODES)) { DEBUG2(" rlm_eap: Unknown EAP packet"); } else { DEBUG2(" rlm_eap: EAP packet type %s id %d length %d", eap_codes[eap_msg->strvalue[0]],
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -