/* * Find the named user in this modules database. Create the set * of attribute-value pairs to check and reply with for this user * from the database. The authentication code only needs to check * the password, the rest is done here. */ static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(UNUSED void *instance, REQUEST *request) { VALUE_PAIR *passwd_item, *chap; uint8_t pass_str[MAX_STRING_LEN]; if (!request->username) { RWDEBUG("Attribute 'User-Name' is required for authentication.\n"); return RLM_MODULE_INVALID; } chap = pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY); if (!chap) { REDEBUG("You set 'Auth-Type = CHAP' for a request that does not contain a CHAP-Password attribute!"); return RLM_MODULE_INVALID; } if (chap->length == 0) { REDEBUG("CHAP-Password is empty"); return RLM_MODULE_INVALID; } if (chap->length != CHAP_VALUE_LENGTH + 1) { REDEBUG("CHAP-Password has invalid length"); return RLM_MODULE_INVALID; } /* * Don't print out the CHAP password here. It's binary crap. */ RDEBUG("Login attempt by \"%s\" with CHAP password", request->username->vp_strvalue); if ((passwd_item = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) == NULL){ if (pairfind(request->config_items, PW_USER_PASSWORD, 0, TAG_ANY) != NULL){ REDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); REDEBUG("!!! Please update your configuration so that the \"known !!!"); REDEBUG("!!! good\" cleartext password is in Cleartext-Password, !!!"); REDEBUG("!!! and NOT in User-Password. !!!"); REDEBUG("!!! !!!"); REDEBUG("!!! Authentication will fail because of this. !!!"); REDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); } REDEBUG("Cleartext password is required for authentication"); return RLM_MODULE_INVALID; } rad_chap_encode(request->packet, pass_str, chap->vp_octets[0], passwd_item); if (RDEBUG_ENABLED3) { uint8_t const *p; size_t length; VALUE_PAIR *vp; char buffer[CHAP_VALUE_LENGTH * 2 + 1]; RDEBUG3("Comparing with \"known good\" Cleartext-Password \"%s\"", passwd_item->vp_strvalue); vp = pairfind(request->packet->vps, PW_CHAP_CHALLENGE, 0, TAG_ANY); if (vp) { p = vp->vp_octets; length = vp->length; } else { p = request->packet->vector; length = sizeof(request->packet->vector); } fr_bin2hex(buffer, p, length); RINDENT(); RDEBUG3("CHAP challenge : %s", buffer); fr_bin2hex(buffer, chap->vp_octets + 1, CHAP_VALUE_LENGTH); RDEBUG3("Client sent : %s", buffer); fr_bin2hex(buffer, pass_str + 1, CHAP_VALUE_LENGTH); RDEBUG3("We calculated : %s", buffer); REXDENT(); } else { RDEBUG2("Comparing with \"known good\" Cleartext-Password"); } if (rad_digest_cmp(pass_str + 1, chap->vp_octets + 1, CHAP_VALUE_LENGTH) != 0) { REDEBUG("Password is comparison failed: password is incorrect"); return RLM_MODULE_REJECT; } RDEBUG("CHAP user \"%s\" authenticated successfully", request->username->vp_strvalue); return RLM_MODULE_OK; }
/* * Find the named user in this modules database. Create the set * of attribute-value pairs to check and reply with for this user * from the database. The authentication code only needs to check * the password, the rest is done here. */ static rlm_rcode_t CC_HINT(nonnull) mod_authenticate(UNUSED void *instance, REQUEST *request) { VALUE_PAIR *password, *chap; uint8_t pass_str[MAX_STRING_LEN]; if (!request->username) { REDEBUG("&request:User-Name attribute is required for authentication"); return RLM_MODULE_INVALID; } chap = fr_pair_find_by_num(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY); if (!chap) { REDEBUG("You set '&control:Auth-Type = CHAP' for a request that " "does not contain a CHAP-Password attribute!"); return RLM_MODULE_INVALID; } if (chap->vp_length == 0) { REDEBUG("&request:CHAP-Password is empty"); return RLM_MODULE_INVALID; } if (chap->vp_length != CHAP_VALUE_LENGTH + 1) { REDEBUG("&request:CHAP-Password has invalid length"); return RLM_MODULE_INVALID; } password = fr_pair_find_by_num(request->config, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY); if (password == NULL) { if (fr_pair_find_by_num(request->config, PW_USER_PASSWORD, 0, TAG_ANY) != NULL){ REDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); REDEBUG("!!! Please update your configuration so that the \"known !!!"); REDEBUG("!!! good\" cleartext password is in Cleartext-Password, !!!"); REDEBUG("!!! and NOT in User-Password. !!!"); REDEBUG("!!! !!!"); REDEBUG("!!! Authentication will fail because of this. !!!"); REDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); } REDEBUG("&control:Cleartext-Password is required for authentication"); return RLM_MODULE_FAIL; } rad_chap_encode(request->packet, pass_str, chap->vp_octets[0], password); if (RDEBUG_ENABLED3) { uint8_t const *p; size_t length; VALUE_PAIR *vp; char buffer[MAX_STRING_LEN * 2 + 1]; RDEBUG3("Comparing with \"known good\" &control:Cleartext-Password value \"%s\"", password->vp_strvalue); vp = fr_pair_find_by_num(request->packet->vps, PW_CHAP_CHALLENGE, 0, TAG_ANY); if (vp) { RDEBUG2("Using challenge from &request:CHAP-Challenge"); p = vp->vp_octets; length = vp->vp_length; } else { RDEBUG2("Using challenge from authenticator field"); p = request->packet->vector; length = sizeof(request->packet->vector); } fr_bin2hex(buffer, p, length); RINDENT(); RDEBUG3("CHAP challenge : %s", buffer); fr_bin2hex(buffer, chap->vp_octets + 1, CHAP_VALUE_LENGTH); RDEBUG3("Client sent : %s", buffer); fr_bin2hex(buffer, pass_str + 1, CHAP_VALUE_LENGTH); RDEBUG3("We calculated : %s", buffer); REXDENT(); } else { RDEBUG2("Comparing with \"known good\" Cleartext-Password"); } if (rad_digest_cmp(pass_str + 1, chap->vp_octets + 1, CHAP_VALUE_LENGTH) != 0) { REDEBUG("Password comparison failed: password is incorrect"); return RLM_MODULE_REJECT; } RDEBUG("CHAP user \"%s\" authenticated successfully", request->username->vp_strvalue); return RLM_MODULE_OK; }
/* * Find the named user in this modules database. Create the set * of attribute-value pairs to check and reply with for this user * from the database. The authentication code only needs to check * the password, the rest is done here. */ static rlm_rcode_t mod_authenticate(UNUSED void *instance, UNUSED REQUEST *request) { VALUE_PAIR *passwd_item, *chap; uint8_t pass_str[MAX_STRING_LEN]; if (!request->username) { RWDEBUG("Attribute 'User-Name' is required for authentication.\n"); return RLM_MODULE_INVALID; } chap = pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY); if (!chap) { REDEBUG("You set 'Auth-Type = CHAP' for a request that does not contain a CHAP-Password attribute!"); return RLM_MODULE_INVALID; } if (chap->length == 0) { REDEBUG("CHAP-Password is empty"); return RLM_MODULE_INVALID; } if (chap->length != CHAP_VALUE_LENGTH + 1) { REDEBUG("CHAP-Password has invalid length"); return RLM_MODULE_INVALID; } /* * Don't print out the CHAP password here. It's binary crap. */ RDEBUG("Login attempt by \"%s\" with CHAP password", request->username->vp_strvalue); if ((passwd_item = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD, 0, TAG_ANY)) == NULL){ if (pairfind(request->config_items, PW_USER_PASSWORD, 0, TAG_ANY) != NULL){ REDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); REDEBUG("!!! Please update your configuration so that the \"known !!!"); REDEBUG("!!! good\" clear text password is in Cleartext-Password, !!!"); REDEBUG("!!! and NOT in User-Password. !!!"); REDEBUG("!!! !!!"); REDEBUG("!!! Authentication will fail because of this. !!!"); REDEBUG("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"); } REDEBUG("Clear-Text password is required for authentication"); return RLM_MODULE_INVALID; } RDEBUG("Using Clear-Text password \"%s\" for user %s authentication.", passwd_item->vp_strvalue, request->username->vp_strvalue); rad_chap_encode(request->packet,pass_str, chap->vp_octets[0],passwd_item); if (rad_digest_cmp(pass_str + 1, chap->vp_octets + 1, CHAP_VALUE_LENGTH) != 0) { REDEBUG("Password is comparison failed: password is incorrect"); return RLM_MODULE_REJECT; } RDEBUG("CHAP user \"%s\" authenticated successfully", request->username->vp_strvalue); return RLM_MODULE_OK; }
/* * Do the MS-CHAP stuff. * * This function is here so that all of the MS-CHAP related * authentication is in one place, and we can perhaps later replace * it with code to call winbindd, or something similar. */ static int do_mschap(rlm_mschap_t *inst, REQUEST *request, VALUE_PAIR *password, uint8_t *challenge, uint8_t *response, uint8_t *nthashhash, int do_ntlm_auth) { uint8_t calculated[24]; /* * Do normal authentication. */ if (!do_ntlm_auth) { /* * No password: can't do authentication. */ if (!password) { RDEBUG2("FAILED: No NT/LM-Password. Cannot perform authentication."); return -1; } smbdes_mschap(password->vp_strvalue, challenge, calculated); if (rad_digest_cmp(response, calculated, 24) != 0) { return -1; } /* * If the password exists, and is an NT-Password, * then calculate the hash of the NT hash. Doing this * here minimizes work for later. */ if (password && (password->attribute == PW_NT_PASSWORD)) { fr_md4_calc(nthashhash, password->vp_octets, 16); } else { memset(nthashhash, 0, 16); } } else { /* run ntlm_auth */ int result; char buffer[256]; memset(nthashhash, 0, 16); /* * Run the program, and expect that we get 16 */ result = radius_exec_program(inst->ntlm_auth, request, TRUE, /* wait */ buffer, sizeof(buffer), NULL, NULL, 1); if (result != 0) { char *p; VALUE_PAIR *vp = NULL; RDEBUG2("External script failed."); vp = pairmake("Module-Failure-Message", "", T_OP_EQ); if (!vp) { radlog_request(L_ERR, 0, request, "No memory to allocate Module-Failure-Message"); return RLM_MODULE_FAIL; } p = strchr(buffer, '\n'); if (p) *p = '\0'; snprintf(vp->vp_strvalue, sizeof(vp->vp_strvalue), "%s: External script says %s", inst->xlat_name, buffer); vp->length = strlen(vp->vp_strvalue); pairadd(&request->packet->vps, vp); return -1; } /* * Parse the answer as an nthashhash. * * ntlm_auth currently returns: * NT_KEY: 000102030405060708090a0b0c0d0e0f */ if (memcmp(buffer, "NT_KEY: ", 8) != 0) { RDEBUG2("Invalid output from ntlm_auth: expecting NT_KEY"); return -1; } /* * Check the length. It should be at least 32, * with an LF at the end. */ if (strlen(buffer + 8) < 32) { RDEBUG2("Invalid output from ntlm_auth: NT_KEY has unexpected length"); return -1; } /* * Update the NT hash hash, from the NT key. */ if (fr_hex2bin(buffer + 8, nthashhash, 16) != 16) { RDEBUG2("Invalid output from ntlm_auth: NT_KEY has non-hex values"); return -1; } } return 0; }
/* * Find the named user in this modules database. Create the set * of attribute-value pairs to check and reply with for this user * from the database. The authentication code only needs to check * the password, the rest is done here. */ static int chap_authenticate(void *instance, REQUEST *request) { VALUE_PAIR *passwd_item, *chap; uint8_t pass_str[MAX_STRING_LEN]; VALUE_PAIR *module_fmsg_vp; char module_fmsg[MAX_STRING_LEN]; /* quiet the compiler */ instance = instance; request = request; if (!request->username) { radlog_request(L_AUTH, 0, request, "rlm_chap: Attribute \"User-Name\" is required for authentication.\n"); return RLM_MODULE_INVALID; } chap = pairfind(request->packet->vps, PW_CHAP_PASSWORD); if (!chap) { RDEBUG("ERROR: You set 'Auth-Type = CHAP' for a request that does not contain a CHAP-Password attribute!"); return RLM_MODULE_INVALID; } if (chap->length == 0) { RDEBUG("ERROR: CHAP-Password is empty"); return RLM_MODULE_INVALID; } if (chap->length != CHAP_VALUE_LENGTH + 1) { RDEBUG("ERROR: CHAP-Password has invalid length"); return RLM_MODULE_INVALID; } /* * Don't print out the CHAP password here. It's binary crap. */ RDEBUG("login attempt by \"%s\" with CHAP password", request->username->vp_strvalue); if ((passwd_item = pairfind(request->config_items, PW_CLEARTEXT_PASSWORD)) == NULL){ RDEBUG("Cleartext-Password is required for authentication"); snprintf(module_fmsg, sizeof(module_fmsg), "rlm_chap: Clear text password not available"); module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ); pairadd(&request->packet->vps, module_fmsg_vp); return RLM_MODULE_INVALID; } RDEBUG("Using clear text password \"%s\" for user %s authentication.", passwd_item->vp_strvalue, request->username->vp_strvalue); rad_chap_encode(request->packet,pass_str, chap->vp_octets[0],passwd_item); if (rad_digest_cmp(pass_str + 1, chap->vp_octets + 1, CHAP_VALUE_LENGTH) != 0) { RDEBUG("Password check failed"); snprintf(module_fmsg, sizeof(module_fmsg), "rlm_chap: Wrong user password"); module_fmsg_vp = pairmake("Module-Failure-Message", module_fmsg, T_OP_EQ); pairadd(&request->packet->vps, module_fmsg_vp); return RLM_MODULE_REJECT; } RDEBUG("chap user %s authenticated succesfully", request->username->vp_strvalue); return RLM_MODULE_OK; }