📄 rlm_eap_mschapv2.c
字号:
/* * Done doing EAP proxy stuff. */ handler->request->options &= ~RAD_REQUEST_OPTION_PROXY_EAP; eapmschapv2_compose(handler, response); data->code = PW_EAP_MSCHAPV2_SUCCESS; /* * Delete MPPE keys & encryption policy * * FIXME: Use intelligent names... */ pairdelete(&handler->request->reply->vps, ((311 << 16) | 7)); pairdelete(&handler->request->reply->vps, ((311 << 16) | 8)); pairdelete(&handler->request->reply->vps, ((311 << 16) | 16)); pairdelete(&handler->request->reply->vps, ((311 << 16) | 17)); /* * And we need to challenge the user, not ack/reject them, * so we re-write the ACK to a challenge. Yuck. */ handler->request->reply->code = PW_ACCESS_CHALLENGE; pairfree(&response); return 1;}/* * Authenticate a previously sent challenge. */static int mschapv2_authenticate(void *arg, EAP_HANDLER *handler){ int rcode; mschapv2_opaque_t *data; EAP_DS *eap_ds = handler->eap_ds; VALUE_PAIR *challenge, *response; /* * Get the User-Password for this user. */ rad_assert(handler->request != NULL); rad_assert(handler->stage == AUTHENTICATE); data = (mschapv2_opaque_t *) handler->opaque; /* * Sanity check the response. */ if (eap_ds->response->length <= 4) { radlog(L_ERR, "rlm_eap_mschapv2: corrupted data"); return 0; } /* * Switch over the MS-CHAP type. */ switch (eap_ds->response->type.data[0]) { /* * We should get an ACK from the client ONLY if we've * sent them a SUCCESS packet. */ case PW_EAP_MSCHAPV2_ACK: if (data->code != PW_EAP_MSCHAPV2_SUCCESS) { radlog(L_ERR, "rlm_eap_mschapv2: Unexpected ACK received"); return 0; } /* * It's a success. Don't proxy it. */ handler->request->options &= ~RAD_REQUEST_OPTION_PROXY_EAP; /* * And upon receiving the clients ACK, we do nothing * other than return EAP-Success, with no EAP-MS-CHAPv2 * data. */ return 1; break; /* * We should get a response ONLY after we've sent * a challenge. */ case PW_EAP_MSCHAPV2_RESPONSE: if (data->code != PW_EAP_MSCHAPV2_CHALLENGE) { radlog(L_ERR, "rlm_eap_mschapv2: Unexpected response received"); return 0; } /* * Ensure that we have at least enough data * to do the following checks. * * EAP header (4), EAP type, MS-CHAP opcode, * MS-CHAP ident, MS-CHAP data length (2), * MS-CHAP value length. */ if (eap_ds->response->length < (4 + 1 + 1 + 1 + 2 + 1)) { radlog(L_ERR, "rlm_eap_mschapv2: Response is too short"); return 0; } /* * The 'value_size' is the size of the response, * which is supposed to be the response (48 * bytes) plus 1 byte of flags at the end. */ if (eap_ds->response->type.data[4] != 49) { radlog(L_ERR, "rlm_eap_mschapv2: Response is of incorrect length %d", eap_ds->response->type.data[4]); return 0; } /* * The MS-Length field is 5 + value_size + length * of name, which is put after the response. */ if (((eap_ds->response->type.data[2] << 8) | eap_ds->response->type.data[3]) < (5 + 49)) { radlog(L_ERR, "rlm_eap_mschapv2: Response contains contradictory length %d %d", (eap_ds->response->type.data[2] << 8) | eap_ds->response->type.data[3], 5 + 49); return 0; } break; case PW_EAP_MSCHAPV2_SUCCESS: /* * It's a success. Don't proxy it. */ handler->request->options &= ~RAD_REQUEST_OPTION_PROXY_EAP; eap_ds->request->code = PW_EAP_SUCCESS; return 1; break; /* * Something else, we don't know what it is. */ default: radlog(L_ERR, "rlm_eap_mschapv2: Invalid response type %d", eap_ds->response->type.data[0]); return 0; } /* * We now know that the user has sent us a response * to the challenge. Let's try to authenticate it. * * We do this by taking the challenge from 'data', * the response from the EAP packet, and creating VALUE_PAIR's * to pass to the 'mschap' module. This is a little wonky, * but it works. */ challenge = pairmake("MS-CHAP-Challenge", "0x00", T_OP_EQ); if (!challenge) { radlog(L_ERR, "rlm_eap_mschapv2: out of memory"); return 0; } challenge->length = MSCHAPV2_CHALLENGE_LEN; memcpy(challenge->strvalue, data->challenge, MSCHAPV2_CHALLENGE_LEN); response = pairmake("MS-CHAP2-Response", "0x00", T_OP_EQ); if (!response) { radlog(L_ERR, "rlm_eap_mschapv2: out of memory"); return 0; } response->length = MSCHAPV2_RESPONSE_LEN; memcpy(response->strvalue + 2, &eap_ds->response->type.data[5], MSCHAPV2_RESPONSE_LEN - 2); response->strvalue[0] = eap_ds->response->type.data[1]; response->strvalue[1] = eap_ds->response->type.data[5 + MSCHAPV2_RESPONSE_LEN]; /* * Add the pairs to the request, and call the 'mschap' * module. */ pairadd(&handler->request->packet->vps, challenge); pairadd(&handler->request->packet->vps, response); /* * If this options is set, then we do NOT authenticate the * user here. Instead, now that we've added the MS-CHAP * attributes to the request, we STOP, and let the outer * tunnel code handle it. * * This means that the outer tunnel code will DELETE the * EAP attributes, and proxy the MS-CHAP attributes to a * home server. */ if (handler->request->options & RAD_REQUEST_OPTION_PROXY_EAP) { char *username = NULL; eap_tunnel_data_t *tunnel; rlm_eap_mschapv2_t *inst = (rlm_eap_mschapv2_t *) arg; /* * Set up the callbacks for the tunnel */ tunnel = rad_malloc(sizeof(*tunnel)); memset(tunnel, 0, sizeof(*tunnel)); tunnel->tls_session = arg; tunnel->callback = mschap_postproxy; /* * Associate the callback with the request. */ rcode = request_data_add(handler->request, handler->request->proxy, REQUEST_DATA_EAP_TUNNEL_CALLBACK, tunnel, free); rad_assert(rcode == 0); /* * The State attribute is NOT supposed to * go into the proxied packet, it will confuse * other RADIUS servers, and they will discard * the request. * * The PEAP module will take care of adding * the State attribute back, before passing * the handler & request back into the tunnel. */ pairdelete(&handler->request->packet->vps, PW_STATE); /* * Fix the User-Name when proxying, to strip off * the NT Domain, if we're told to, and a User-Name * exists, and there's a \\, meaning an NT-Domain * in the user name, THEN discard the user name. */ if (inst->with_ntdomain_hack && ((challenge = pairfind(handler->request->packet->vps, PW_USER_NAME)) != NULL) && ((username = strchr(challenge->strvalue, '\\')) != NULL)) { /* * Wipe out the NT domain. * * FIXME: Put it into MS-CHAP-Domain? */ username++; /* skip the \\ */ memmove(challenge->strvalue, username, strlen(username) + 1); /* include \0 */ challenge->length = strlen(challenge->strvalue); } /* * Remember that in the post-proxy stage, we've got * to do the work below, AFTER the call to MS-CHAP * authentication... */ return 1; } /* * This is a wild & crazy hack. */ rcode = module_authenticate(PW_AUTHTYPE_MS_CHAP, handler->request); /* * Delete MPPE keys & encryption policy. We don't * want these here. */ pairdelete(&handler->request->reply->vps, ((311 << 16) | 7)); pairdelete(&handler->request->reply->vps, ((311 << 16) | 8)); pairdelete(&handler->request->reply->vps, ((311 << 16) | 16)); pairdelete(&handler->request->reply->vps, ((311 << 16) | 17)); /* * Take the response from the mschap module, and * return success or failure, depending on the result. */ if (rcode == RLM_MODULE_OK) { response = paircopy2(handler->request->reply->vps, PW_MSCHAP2_SUCCESS); data->code = PW_EAP_MSCHAPV2_SUCCESS; } else { /* * Don't return anything in the error message. */ eap_ds->request->code = PW_EAP_FAILURE; return 1;#if 0 response = paircopy2(handler->request->reply->vps, PW_MSCHAP_ERROR); data->code = PW_EAP_MSCHAPV2_FAILURE;#endif } /* * No response, die. */ if (!response) { radlog(L_ERR, "rlm_eap_mschapv2: No MS-CHAPv2-Success or MS-CHAP-Error was found."); return 0; } /* * Compose the response (whatever it is), * and return it to the over-lying EAP module. */ eapmschapv2_compose(handler, response); pairfree(&response); return 1;}/* * The module name should be the only globally exported symbol. * That is, everything else should be 'static'. */EAP_TYPE rlm_eap_mschapv2 = { "eap_mschapv2", mschapv2_attach, /* attach */ mschapv2_initiate, /* Start the initial request */ NULL, /* authorization */ mschapv2_authenticate, /* authentication */ mschapv2_detach /* detach */};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -