📄 rlm_mschap.c
字号:
return 0; } data = response->strvalue + 2; data_len = 24; /* * Pull the NT-Domain out of the User-Name, if it exists. */ } else if (strcasecmp(fmt, "NT-Domain") == 0) { char *p; user_name = pairfind(request->packet->vps, PW_USER_NAME); if (!user_name) { DEBUG2(" rlm_mschap: No User-Name was found in the request."); return 0; } p = strchr(user_name->strvalue, '\\'); if (!p) { DEBUG2(" rlm_mschap: No NT-Domain was found in the User-Name."); return 0; } /* * Hack. This is simpler than the alternatives. */ *p = '\0'; strNcpy(out, user_name->strvalue, outlen); *p = '\\'; return strlen(out); /* * Pull the User-Name out of the User-Name... */ } else if (strcasecmp(fmt, "User-Name") == 0) { char *p; user_name = pairfind(request->packet->vps, PW_USER_NAME); if (!user_name) { DEBUG2(" rlm_mschap: No User-Name was found in the request."); return 0; } p = strchr(user_name->strvalue, '\\'); if (p) { p++; /* skip the backslash */ } else { p = user_name->strvalue; /* use the whole User-Name */ } strNcpy(out, p, outlen); return strlen(out); } else { DEBUG2(" rlm_mschap: Unknown expansion string \"%s\"", fmt); return 0; } if (outlen == 0) return 0; /* nowhere to go, don't do anything */ /* * Didn't set anything: this is bad. */ if (!data) { DEBUG2(" rlm_mschap: Failed to do anything intelligent"); return 0; } /* * Check the output length. */ if (outlen < ((data_len * 2) + 1)) { data_len = (outlen - 1) / 2; } /* * */ for (i = 0; i < data_len; i++) { sprintf(out + (2 * i), "%02x", data[i]); } out[data_len * 2] = '\0'; return data_len * 2;}static CONF_PARSER module_config[] = { /* * Cache the password by default. */ { "use_mppe", PW_TYPE_BOOLEAN, offsetof(rlm_mschap_t,use_mppe), NULL, "yes" }, { "require_encryption", PW_TYPE_BOOLEAN, offsetof(rlm_mschap_t,require_encryption), NULL, "no" }, { "require_strong", PW_TYPE_BOOLEAN, offsetof(rlm_mschap_t,require_strong), NULL, "no" }, { "with_ntdomain_hack", PW_TYPE_BOOLEAN, offsetof(rlm_mschap_t,with_ntdomain_hack), NULL, "no" }, { "passwd", PW_TYPE_STRING_PTR, offsetof(rlm_mschap_t, passwd_file), NULL, NULL }, { "authtype", PW_TYPE_STRING_PTR, offsetof(rlm_mschap_t, auth_type), NULL, NULL }, { "ntlm_auth", PW_TYPE_STRING_PTR, offsetof(rlm_mschap_t, ntlm_auth), NULL, NULL }, { NULL, -1, 0, NULL, NULL } /* end the list */};/* * deinstantiate module, free all memory allocated during * mschap_instantiate() */static int mschap_detach(void *instance){#define inst ((rlm_mschap_t *)instance) if (inst->passwd_file) free(inst->passwd_file); if (inst->auth_type) free(inst->auth_type); if (inst->ntlm_auth) free(inst->ntlm_auth); if (inst->xlat_name) { xlat_unregister(inst->xlat_name, mschap_xlat); free(inst->xlat_name); } free(instance); return 0;#undef inst}/* * Create instance for our module. Allocate space for * instance structure and read configuration parameters */static int mschap_instantiate(CONF_SECTION *conf, void **instance){ const char *xlat_name; rlm_mschap_t *inst; inst = *instance = rad_malloc(sizeof(*inst)); if (!inst) { return -1; } memset(inst, 0, sizeof(*inst)); if (cf_section_parse(conf, inst, module_config) < 0) { free(inst); return -1; } /* * This module used to support SMB Password files, but it * made it too complicated. If the user tries to * configure an SMB Password file, then die, with an * error message. */ if (inst->passwd_file) { radlog(L_ERR, "rlm_mschap: SMB password file is no longer supported in this module. Use rlm_passwd module instead"); mschap_detach(inst); return -1; } /* * Create the dynamic translation. */ xlat_name = cf_section_name2(conf); if (xlat_name == NULL) xlat_name = cf_section_name1(conf); if (xlat_name){ inst->xlat_name = strdup(xlat_name); xlat_register(xlat_name, mschap_xlat, inst); } return 0;}/* * add_reply() adds either MS-CHAP2-Success or MS-CHAP-Error * attribute to reply packet */static void add_reply(VALUE_PAIR** vp, unsigned char ident, const char* name, const char* value, int len){ VALUE_PAIR *reply_attr; reply_attr = pairmake(name, "", T_OP_EQ); if (!reply_attr) { DEBUG(" rlm_mschap: Failed to create attribute %s: %s\n", name, librad_errstr); return; } reply_attr->strvalue[0] = ident; memcpy(reply_attr->strvalue + 1, value, len); reply_attr->length = len + 1; pairadd(vp, reply_attr);}/* * Add MPPE attributes to the reply. */static void mppe_add_reply(VALUE_PAIR **vp, const char* name, const char* value, int len){ VALUE_PAIR *reply_attr; reply_attr = pairmake(name, "", T_OP_EQ); if (!reply_attr) { DEBUG("rlm_mschap: mppe_add_reply failed to create attribute %s: %s\n", name, librad_errstr); return; } memcpy(reply_attr->strvalue, value, len); reply_attr->length = len; pairadd(vp, reply_attr);}/* * 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 = 0; uint8_t calculated[24]; VALUE_PAIR *vp = NULL; /* * If we have ntlm_auth configured, use it unless told * otherwise */ if (inst->ntlm_auth) do_ntlm_auth = 1; /* * If we have an ntlm_auth configuration, then we may * want to use it. */ vp = pairfind(request->config_items, PW_MS_CHAP_USE_NTLM_AUTH); if (vp) do_ntlm_auth = vp->lvalue; /* * No ntlm_auth configured, attribute to tell us to * use it exists, and we're told to use it. We don't * know what to do... */ if (!inst->ntlm_auth && do_ntlm_auth) { DEBUG2(" rlm_mschap: Asked to use ntlm_auth, but it was not configured in the mschap{} section."); return -1; } /* * Do normal authentication. */ if (!do_ntlm_auth) { /* * No password: can't do authentication. */ if (!password) { DEBUG2(" rlm_mschap: FAILED: No NT/LM-Password. Cannot perform authentication."); return -1; } smbdes_mschap(password->strvalue, challenge, calculated); if (memcmp(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)) { md4_calc(nthashhash, password->strvalue, 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); if (result != 0) { DEBUG2(" rlm_mschap: External script failed."); return -1; } /* * Parse the answer as an nthashhash. * * ntlm_auth currently returns: * NT_KEY: 000102030405060708090a0b0c0d0e0f */ if (memcmp(buffer, "NT_KEY: ", 8) != 0) { DEBUG2(" rlm_mschap: 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) { DEBUG2(" rlm_mschap: Invalid output from ntlm_auth: NT_KEY has unexpected length"); return -1; } /* * Update the NT hash hash, from the NT key. */ if (hex2bin(buffer + 8, nthashhash, 16) != 16) { DEBUG2(" rlm_mschap: Invalid output from ntlm_auth: NT_KEY has non-hex values"); return -1; } } return 0;}/* * Data for the hashes. */static const uint8_t SHSpad1[40] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };static const uint8_t SHSpad2[40] = { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };static const uint8_t magic1[27] = { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d, 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };static const uint8_t magic2[84] = { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x2e };static const uint8_t magic3[84] = { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20, 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79, 0x2e };static void mppe_GetMasterKey(uint8_t *nt_hashhash,uint8_t *nt_response, uint8_t *masterkey){ uint8_t digest[20]; SHA1_CTX Context; SHA1Init(&Context); SHA1Update(&Context,nt_hashhash,16); SHA1Update(&Context,nt_response,24); SHA1Update(&Context,magic1,27); SHA1Final(digest,&Context); memcpy(masterkey,digest,16);}static void mppe_GetAsymmetricStartKey(uint8_t *masterkey,uint8_t *sesskey, int keylen,int issend){ uint8_t digest[20]; const uint8_t *s; SHA1_CTX Context; memset(digest,0,20); if(issend) { s = magic3; } else { s = magic2; } SHA1Init(&Context); SHA1Update(&Context,masterkey,16); SHA1Update(&Context,SHSpad1,40); SHA1Update(&Context,s,84); SHA1Update(&Context,SHSpad2,40); SHA1Final(digest,&Context); memcpy(sesskey,digest,keylen);}static void mppe_chap2_get_keys128(uint8_t *nt_hashhash,uint8_t *nt_response, uint8_t *sendkey,uint8_t *recvkey){ uint8_t masterkey[16]; mppe_GetMasterKey(nt_hashhash,nt_response,masterkey); mppe_GetAsymmetricStartKey(masterkey,sendkey,16,1); mppe_GetAsymmetricStartKey(masterkey,recvkey,16,0);}/* * Generate MPPE keys. */static void mppe_chap2_gen_keys128(uint8_t *nt_hashhash,uint8_t *response, uint8_t *sendkey,uint8_t *recvkey){ uint8_t enckey1[16]; uint8_t enckey2[16]; mppe_chap2_get_keys128(nt_hashhash,response,enckey1,enckey2); /* * dictionary.microsoft defines these attributes as * 'encrypt=2'. The functions in src/lib/radius.c will * take care of encrypting/decrypting them as appropriate, * so that we don't have to. */ memcpy (sendkey, enckey1, 16);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -