📄 rlm_mschap.c
字号:
return 0; } /* * Hack. This is simpler than the alternatives. */ *p = '\0'; strlcpy(out, user_name->vp_strvalue, outlen); *p = '\\'; } return strlen(out); /* * Pull the User-Name out of the User-Name... */ } else if (strncasecmp(fmt, "User-Name", 9) == 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; } /* * First check to see if this is a host/ style User-Name * (a la Kerberos host principal) */ if (strncmp(user_name->vp_strvalue, "host/", 5) == 0) { /* * If we're getting a User-Name formatted in this way, * it's likely due to PEAP. When authenticating this against * a Domain, Windows will expect the User-Name to be in the * format of hostname$, the SAM version of the name, so we * have to convert it to that here. We do so by stripping * off the first 5 characters (host/), and copying everything * from that point to the first period into a string and appending * a $ to the end. */ p = strchr(user_name->vp_strvalue, '.'); /* * use the same hack as above * only if a period was found */ if (p) *p = '\0'; snprintf(out, outlen, "%s$", user_name->vp_strvalue + 5); if (p) *p = '.'; } else { p = strchr(user_name->vp_strvalue, '\\'); if (p) { p++; /* skip the backslash */ } else { p = user_name->vp_strvalue; /* use the whole User-Name */ } strlcpy(out, p, outlen); } return strlen(out); /* * Return the NT-Hash of the passed string */ } else if (strncasecmp(fmt, "NT-Hash ", 8) == 0) { char *p; p = fmt + 8; /* 7 is the length of 'NT-Hash' */ if ((p == '\0') || (outlen <= 32)) return 0; DEBUG("rlm_mschap: NT-Hash: %s",p); ntpwdhash(buffer,p); fr_bin2hex(buffer, out, 16); out[32] = '\0'; DEBUG("rlm_mschap: NT-Hash: Result: %s",out); return 32; /* * Return the LM-Hash of the passed string */ } else if (strncasecmp(fmt, "LM-Hash ", 8) == 0) { char *p; p = fmt + 8; /* 7 is the length of 'LM-Hash' */ if ((p == '\0') || (outlen <= 32)) return 0; DEBUG("rlm_mschap: LM-Hash: %s",p); smbdes_lmpwdhash(p, buffer); fr_bin2hex(buffer, out, 16); out[32] = '\0'; DEBUG("rlm_mschap: LM-Hash: Result: %s",out); return 32; } 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 const 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 }, { "ntlm_auth", PW_TYPE_STRING_PTR, offsetof(rlm_mschap_t, ntlm_auth), NULL, NULL },#ifdef __APPLE__ { "use_open_directory", PW_TYPE_BOOLEAN, offsetof(rlm_mschap_t,open_directory), NULL, "yes" },#endif { 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->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){ 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. */ inst->xlat_name = cf_section_name2(conf); if (!inst->xlat_name) inst->xlat_name = cf_section_name1(conf); inst->xlat_name = strdup(inst->xlat_name); xlat_register(inst->xlat_name, mschap_xlat, inst); /* * For backwards compatibility */ if (!dict_valbyname(PW_AUTH_TYPE, inst->xlat_name)) { inst->auth_type = "MS-CHAP"; } else { inst->auth_type = inst->xlat_name; } return 0;}/* * add_reply() adds either MS-CHAP2-Success or MS-CHAP-Error * attribute to reply packet */void mschap_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->vp_octets[0] = ident; memcpy(reply_attr->vp_octets + 1, value, len); reply_attr->length = len + 1; pairadd(vp, reply_attr);}/* * Add MPPE attributes to the reply. */static void mppe_add_reply(REQUEST *request, const char* name, const uint8_t * value, int len){ VALUE_PAIR *vp; vp = radius_pairmake(request, &request->reply->vps, name, "", T_OP_EQ); if (!vp) { DEBUG("rlm_mschap: mppe_add_reply failed to create attribute %s: %s\n", name, librad_errstr); return; } memcpy(vp->vp_octets, value, len); vp->length = len;}/* * 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->vp_integer; /* * 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->vp_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)) { 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) { 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 (fr_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]; fr_SHA1_CTX Context; fr_SHA1Init(&Context); fr_SHA1Update(&Context,nt_hashhash,16); fr_SHA1Update(&Context,nt_response,24); fr_SHA1Update(&Context,magic1,27); fr_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; fr_SHA1_CTX Context; memset(digest,0,20); if(issend) { s = magic3; } else { s = magic2; } fr_SHA1Init(&Context); fr_SHA1Update(&Context,masterkey,16); fr_SHA1Update(&Context,SHSpad1,40); fr_SHA1Update(&Context,s,84); fr_SHA1Update(&Context,SHSpad2,40); fr_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);}/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -