📄 eap.c
字号:
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); } /* * Generate State, only if it not Identity request */ if ((eap_packet->code == PW_EAP_REQUEST) && (eap_packet->data[0] >= PW_EAP_MD5)) { vp = generate_state(); pairadd(&(request->reply->vps), vp); } /* Set request reply code, but only if it's not already set. */ if (!request->reply->code) switch(reply->code) { case PW_EAP_RESPONSE: case PW_EAP_SUCCESS: request->reply->code = PW_AUTHENTICATION_ACK; break; case PW_EAP_FAILURE: request->reply->code = PW_AUTHENTICATION_REJECT; break; case PW_EAP_REQUEST: request->reply->code = PW_ACCESS_CHALLENGE; break; default: /* 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; break; } return 0;}/* * Radius criteria, EAP-Message is invalid without Message-Authenticator * For EAP_START, send Access-Challenge with EAP Identity request. */int eap_start(REQUEST *request){ VALUE_PAIR *vp; VALUE_PAIR *eap_msg; EAP_DS *eapstart; eap_msg = pairfind(request->packet->vps, PW_EAP_MESSAGE); if (eap_msg == NULL) { radlog(L_ERR, "rlm_eap: EAP-Message not found"); return EAP_NOOP; } /* * http://www.freeradius.org/rfc/rfc2869.html#EAP-Message */ vp = pairfind(request->packet->vps, PW_MESSAGE_AUTHENTICATOR); if (!vp) { radlog(L_ERR, "rlm_eap: EAP-Message without Message-Authenticator: Ignoring the request due to RFC 2869 Section 5.13 requirements"); return EAP_NOOP; } if ((eap_msg->strvalue[0] == 0) || (eap_msg->strvalue[0] > PW_EAP_MAX_TYPES)) { DEBUG2(" rlm_eap: Unknown EAP packet"); } else { DEBUG2(" rlm_eap: EAP packet type %s id %d length %d", eap_types[eap_msg->strvalue[0]], eap_msg->strvalue[1], (eap_msg->strvalue[2] << 8) | eap_msg->strvalue[3]); } /* * If we've been configured to proxy, do nothing. * * Note that we don't check if the realm is local. * We figure that anyone bright enough to add * Proxy-To-Realm is bright enough to NOT do so * when it's a local realm. */ if (pairfind(request->config_items, PW_PROXY_TO_REALM) != NULL) { return EAP_NOOP; } /* * Not a start message. Don't start anything. * * Later EAP messages are longer than the 'start' message, * so this function returns 'no start found', so that * the rest of the EAP code can use the State attribute * to match this EAP-Message to an ongoing conversation. */ if (eap_msg->length != EAP_START) { DEBUG2(" rlm_eap: EAP Start not found"); return EAP_NOTFOUND; } DEBUG2(" rlm_eap: Got EAP_START message"); if ((eapstart = eap_ds_alloc()) == NULL) { DEBUG2(" rlm_eap: EAP Start failed in allocation"); return EAP_FAIL; } /* * Hmm... why isn't this taken from the eap_msg? */ eapstart->request->code = PW_EAP_REQUEST; eapstart->request->type.type = PW_EAP_IDENTITY; eap_compose(request, eapstart); eap_ds_free(&eapstart); return EAP_FOUND;}/* * compose EAP FAILURE packet in EAP-Message */void eap_fail(REQUEST *request, EAP_DS *eap_ds){ eap_ds->request->code = PW_EAP_FAILURE; eap_compose(request, eap_ds);}/* * compose EAP SUCCESS packet in EAP-Message */void eap_success(REQUEST *request, EAP_DS *eap_ds){ eap_ds->request->code = PW_EAP_SUCCESS; eap_compose(request, eap_ds);}/* * Basic EAP packet verfications & validations */int eap_validation(eap_packet_t *eap_packet){ uint16_t len; memcpy(&len, eap_packet->length, sizeof(uint16_t)); len = ntohs(len); /* High level EAP packet checks */ if ((len <= EAP_HEADER_LEN) || ((eap_packet->code != PW_EAP_RESPONSE) && (eap_packet->code != PW_EAP_REQUEST)) || (eap_packet->data[0] <= 0) || (eap_packet->data[0] > PW_EAP_MAX_TYPES)) { radlog(L_AUTH, "rlm_eap: Incorrect EAP Message, " "Ignoring the packet"); return EAP_INVALID; } /* we don't expect notification, but we send it */ if (eap_packet->data[0] == PW_EAP_NOTIFICATION) { radlog(L_AUTH, "rlm_eap: Got NOTIFICATION, " "Ignoring the packet"); return EAP_INVALID; } return EAP_VALID;}/* * Get the user Identity if at all it is available with us. */VALUE_PAIR *eap_useridentity(EAP_HANDLER *list, eap_packet_t *eap_packet, unsigned char id[]){ char *un; VALUE_PAIR *username; EAP_HANDLER *handler; if ((un = eap_identity(eap_packet)) != NULL) { username = pairmake("User-Name", un, T_OP_EQ); free(un); return username; } /* Get the handler from the list, if present */ handler = eaplist_findhandler(list, id); if (handler) return pairmake("User-Name", handler->identity, T_OP_EQ); return NULL;}/* * Get the user Identity only from EAP-Identity packets */char *eap_identity(eap_packet_t *eap_packet){ int size; uint16_t len; char *identity; if ((eap_packet == NULL) || (eap_packet->code != PW_EAP_RESPONSE) || (eap_packet->data[0] != PW_EAP_IDENTITY)) { return NULL; } memcpy(&len, eap_packet->length, sizeof(uint16_t)); len = ntohs(len); if ((len <= 5) || (eap_packet->data[1] == 0x00)) { radlog(L_ERR, "rlm_eap: UserIdentity Unknown "); return NULL; } size = len - 5; identity = (char *)malloc(size + 1); if (identity == NULL) { radlog(L_ERR, "rlm_eap: out of memory"); return NULL; } memcpy(identity, &eap_packet->data[1], size); identity[size] = '\0'; return identity;}/* * Create our Request-Response data structure with the eap packet */static EAP_DS *eap_buildds(eap_packet_t **eap_packet_p){ EAP_DS *eap_ds = NULL; eap_packet_t *eap_packet = NULL; int typelen; uint16_t len; eap_packet = *eap_packet_p; if (eap_packet == NULL) { return NULL; } if ((eap_ds = eap_ds_alloc()) == NULL) { return NULL; } eap_ds->response->packet = (unsigned char *)eap_packet; eap_ds->response->code = eap_packet->code; eap_ds->response->id = eap_packet->id; eap_ds->response->type.type = eap_packet->data[0]; memcpy(&len, eap_packet->length, sizeof(uint16_t)); len = ntohs(len); eap_ds->response->length = len; /* First byte in eap_packet->data is *EAP-Type* */ /* * First 5 bytes, in eap, are code+id+length(2)+type * The rest is TypeData * skip *type* while getting typedata from data */ typelen = len - 5/*code+id+length+type*/; if (typelen > 0) { /* * Since packet contians the complete eap_packet, * typedata will be a ptr in packet to its typedata */ eap_ds->response->type.data = eap_ds->response->packet + 5/*code+id+length+type*/; eap_ds->response->type.length = typelen; } else { eap_ds->response->type.length = 0; eap_ds->response->type.data = NULL; } *eap_packet_p = NULL; return eap_ds;}/* * If identity response then create a fresh handler & fill the identity * else handler MUST be in our list, get that. * This handler creation cannot fail * * username contains REQUEST->username which might have been stripped. * identity contains the one sent in EAP-Identity response */EAP_HANDLER *eap_handler(EAP_HANDLER **list, eap_packet_t **eap_packet_p, REQUEST *request){ EAP_HANDLER *handler = NULL; unsigned char *unique; eap_packet_t *eap_packet = NULL; eap_packet = *eap_packet_p; if (eap_validation(eap_packet) == EAP_INVALID) { return NULL; } /* * EAP_HANDLER MUST be found in the list if it is not EAP-Identity response */ if (eap_packet->data[0] != PW_EAP_IDENTITY) { unique = eap_regenerateid(request, eap_packet->id); if (unique == NULL) { return NULL; } handler = eaplist_isreply(list, unique); free(unique); unique = NULL; if (handler == NULL) { /* Either send EAP_Identity or EAP-Fail */ radlog(L_ERR, "rlm_eap: Either EAP-request timed out OR" " EAP-response to an unknown EAP-request"); return NULL; } } else { handler = eap_handler_alloc(); if (handler == NULL) { radlog(L_ERR, "rlm_eap: out of memory"); return NULL; } handler->id = NULL; handler->prev_eapds = NULL; handler->eap_ds = NULL; handler->configured = NULL; handler->opaque = NULL; handler->free_opaque = NULL; handler->next = NULL; handler->identity = eap_identity(eap_packet); if (handler->identity == NULL) { radlog(L_ERR, "rlm_eap: Identity Unknown, authentication failed"); eap_handler_free(&handler); return NULL; } /* Get the User-Name */ if (request->username == NULL) { handler->username = pairmake("User-Name", handler->identity, T_OP_EQ); } else { handler->username = paircopy(request->username); } /* No User-Name, No authentication */ /* if (handler->username == NULL) { radlog(L_ERR, "rlm_eap: Unknown User, authentication failed"); eap_handler_free(&handler); return NULL; } */ /* * Always get the configured values, for each user. * to pass it to the specific EAP-Type * * No Configured information found for a user, means * there is no such user in the database. * * Every user should have, atleast, one item configured * This is required for Authentication purpose. */ handler->configured = paircopy(request->config_items); if (handler->configured == NULL) { DEBUG2(" rlm_eap: No configured information for this user"); /* * FIXME: If there is no config info then * config_items should provide the same username * if the user is present in the database. */ /* eap_handler_free(&handler); return NULL; */ } } handler->eap_ds = eap_buildds(eap_packet_p); if (handler->eap_ds == NULL) { eap_handler_free(&handler); return NULL; } handler->timestamp = time(NULL); handler->reply_vps = &(request->reply->vps); handler->request = request; /* LEAP needs this */ return handler;}/* * Regenerate the ID to match the ID stored in the list. * This ID is created based on the NAS, State & EAP-Response */unsigned char *eap_regenerateid(REQUEST *request, unsigned char response_id){ VALUE_PAIR *state = NULL; unsigned char *id = NULL; state = pairfind(request->packet->vps, PW_STATE); if (state == NULL) { DEBUG2(" rlm_eap: NO State Attribute found: Cannot match EAP packet to any existing conversation."); return NULL; } if (verify_state(state) != 0) { radlog(L_ERR, "rlm_eap: State verification failed."); return NULL; } id = (unsigned char *)malloc(1/*Length*/ + 1/*Id*/ + state->length + sizeof(request->packet->src_ipaddr)); if (id == NULL) { radlog(L_ERR, "rlm_eap: out of memory"); return NULL; } /* * Generate unique-id to check for the reply * id = Length + ID + State + Client IP Address * * Note that we do NOT use NAS-IP-Address, or NAS-Identifier, * as they may lie to us! */ id[0] = (1 + 1 + state->length + sizeof(request->packet->src_ipaddr)) & 0xFF; memcpy(id+1, &response_id, sizeof(unsigned char)); memcpy(id+2, state->strvalue, state->length); memcpy(id+2+state->length, &request->packet->src_ipaddr, sizeof(request->packet->src_ipaddr)); return id;}/* * Generate the ID that is used as the search criteria in the list. * This ID is created based on the NAS, State & EAP-Request */unsigned char *eap_generateid(REQUEST *request, unsigned char response_id){ VALUE_PAIR *state = NULL; unsigned char *id = NULL; state = pairfind(request->reply->vps, PW_STATE); if (state == NULL) { DEBUG2(" rlm_eap: NO State Attribute found. Cannot match the EAP packet to any existing conversation."); return NULL; } id = (unsigned char *)malloc(1/*Length*/ + 1/*Id*/ + state->length + sizeof(request->packet->src_ipaddr)); if (id == NULL) { radlog(L_ERR, "rlm_eap: out of memory"); return NULL; } /* * Generate unique-id to check for the reply * id = Length + ID + State + Client IP Address * * Note that we do NOT use NAS-IP-Address, or NAS-Identifier, * as they may lie to us! */ id[0] = (1 + 1 + state->length + sizeof(request->packet->src_ipaddr)) & 0xFF; memcpy(id+1, &response_id, sizeof(unsigned char)); memcpy(id+2, state->strvalue, state->length); memcpy(id+2+state->length, &request->packet->src_ipaddr, sizeof(request->packet->src_ipaddr)); return id;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -