6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Copyright 2000,2001 The FreeRADIUS server project
25 * mschap.c MS-CHAP module
27 * Jay Miller jaymiller@socket.net
29 * This implements MS-CHAP, as described in RFC 2548
31 * http://www.freeradius.org/rfc/rfc2548.txt
36 * If you have any questions on NTLM (Samba) passwords
37 * support, LM authentication and MS-CHAP v2 support
40 * Vladimir Dubrovin vlad@sandy.ru
42 * ZARAZA 3APA3A@security.nnov.ru
46 #include "libradius.h"
61 #define PW_MSCHAP_RESPONSE ((311 << 16) | 1)
62 #define PW_MSCHAP_CHALLENGE ((311 << 16) | 11)
63 #define PW_MSCHAP2_RESPONSE ((311 << 16) | 25)
64 #define PW_LM_PASSWORD 1057
65 #define PW_NT_PASSWORD 1058
66 #define PW_SMB_ACCOUNT_CTRL 1059
75 static void parity_key(char * szOut, const char * szIn);
76 static void des_encrypt(const char *szClear, const char *szKey, char *szOut);
77 static void mschap(const char *szChallenge, struct smb_passwd * smbPasswd, char *szResponse, int bUseNT);
78 static void ntpwdhash (char *szHash, const char *szPassword);
79 static void lmpwdhash (char *szHash, const char *szPassword);
80 static struct smb_passwd *createsmbpw(char* username, char *password);
81 static void auth_response(struct smb_passwd * smbPasswd, char *ntresponse,
82 char *peer_challenge, char *auth_challenge,
84 static void challenge_hash( const char* peer_challenge, const char* auth_challenge,
85 const char* user_name, char * challenge );
86 static void mschap2( const char *peer_challenge, const char *auth_challenge,
87 struct smb_passwd * smbPasswd, char *response);
88 static void add_reply(VALUE_PAIR** vp, unsigned char ident,
89 const char* name, const char* value, int len);
91 static void mppe_add_reply(VALUE_PAIR** vp,
92 const char* name, const char* value, int len);
94 static void mppe_chap2_gen_keys128(uint8_t *secret,uint8_t *vector,
95 uint8_t *nt_hash,uint8_t *response,
96 uint8_t *sendkey,uint8_t *recvkey);
98 static void mppe_chap2_get_keys128(uint8_t *nt_hashhash,uint8_t *nt_response,
99 uint8_t *sendkey,uint8_t *recvkey);
101 static void mppe_GetMasterKey(uint8_t *nt_hashhash,uint8_t *nt_response,
104 static void mppe_GetAsymmetricStartKey(uint8_t *masterkey,uint8_t *sesskey,
105 int keylen,int issend);
107 static void mppe_gen_respkey(uint8_t* secret,uint8_t* vector,
108 uint8_t* salt,uint8_t* enckey,uint8_t* key);
110 void md4_calc (unsigned char *, unsigned char *, unsigned int);
115 * parity_key takes a 7-byte string in szIn and returns an
116 * 8-byte string in szOut. It inserts a 1 into every 8th bit.
117 * DES just strips these back out.
119 static void parity_key(char * szOut, const char * szIn)
122 unsigned char cNext = 0;
123 unsigned char cWorking = 0;
125 for (i = 0; i < 7; i++) {
126 /* Shift operator works in place. Copy the char out */
128 szOut[i] = (cWorking >> i) | cNext | 1;
130 cNext = (cWorking << (7 - i));
132 szOut[i] = cNext | 1;
136 * des_encrypt takes an 8-byte string and a 7-byte key and
137 * returns an 8-byte DES encrypted string in szOut
139 static void des_encrypt(const char *szClear, const char *szKey, char *szOut)
142 unsigned long ulK[16][2];
144 parity_key(szParityKey, szKey); /* Insert parity bits */
145 strncpy(szOut, szClear, 8); /* des encrypts in place */
146 deskey(ulK, (unsigned char *) szParityKey, 0); /* generate keypair */
147 des(ulK, szOut); /* encrypt */
153 * ntpwdhash converts Unicode password to 16-byte NT hash
156 static void ntpwdhash (char *szHash, const char *szPassword)
158 char szUnicodePass[513];
163 * NT passwords are unicode. Convert plain text password
164 * to unicode by inserting a zero every other byte
166 nPasswordLen = strlen(szPassword);
167 for (i = 0; i < nPasswordLen; i++) {
168 szUnicodePass[i << 1] = szPassword[i];
169 szUnicodePass[(i << 1) + 1] = 0;
172 /* Encrypt Unicode password to a 16-byte MD4 hash */
173 md4_calc(szHash, szUnicodePass, (nPasswordLen<<1) );
179 * lmpwdhash converts 14-byte null-padded uppercase OEM
180 * password to 16-byte DES hash with predefined salt string
182 static void lmpwdhash (char *szHash, const char *szPassword)
185 char stdText[] = "KGS!@#$%";
188 memset(szOEMPass, 0, 14);
189 for (i = 0; i < 14 && szPassword[i]; i++)
190 szOEMPass[i] = toupper(szPassword[i]);
192 /* Obtain DES hash of OEM password */
193 des_encrypt(stdText, szOEMPass, szHash);
194 des_encrypt(stdText, szOEMPass+7, szHash+8);
198 * createsmbpw() creates smb_passwd structure from given
199 * user name and cleartext or ntlm-encrypter password
200 * if encrypted flag is not set only cleartext password
203 static struct smb_passwd *createsmbpw(char * username, char *password)
205 static struct smb_passwd pw_buf;
206 static unsigned char smbpwd[16];
207 static unsigned char smbntpwd[16];
210 pdb_init_smb(&pw_buf);
211 pw_buf.acct_ctrl = ACB_NORMAL;
212 pw_buf.smb_userid = 0;
213 pw_buf.smb_name = username;
215 if (pw_buf.smb_passwd==NULL && pw_buf.smb_nt_passwd==NULL) {
216 ntpwdhash(smbntpwd, password);
217 lmpwdhash(smbpwd, password);
218 pw_buf.smb_passwd=smbpwd;
219 pw_buf.smb_nt_passwd = smbntpwd;
227 * mschap takes an 8-byte challenge string and SMB password
228 * and returns a 24-byte response string in szResponse
230 static void mschap(const char *szChallenge, struct smb_passwd * smbPasswd,
231 char *szResponse, int bUseNT) {
235 /* initialize hash string */
236 memset(szMD4, 0, 21);
238 memcpy(szMD4, (bUseNT)?
239 smbPasswd->smb_nt_passwd : smbPasswd->smb_passwd, 16);
243 * challenge_response takes an 8-byte challenge string and a
244 * 21-byte hash (16-byte hash padded to 21 bytes with zeros) and
245 * returns a 24-byte response in szResponse
247 des_encrypt(szChallenge, szMD4, szResponse);
248 des_encrypt(szChallenge, szMD4 + 7, szResponse + 8);
249 des_encrypt(szChallenge, szMD4 + 14, szResponse + 16);
254 * challenge_hash() is used by mschap2() and auth_response()
255 * implements RFC2759 ChallengeHash()
256 * generates 64 bit challenge
258 static void challenge_hash( const char* peer_challenge, const char* auth_challenge,
259 const char* user_name, char * challenge )
265 SHA1Update(&Context, peer_challenge, 16);
266 SHA1Update(&Context, auth_challenge, 16);
267 SHA1Update(&Context, user_name, strlen(user_name));
268 SHA1Final(hash, &Context);
269 memcpy(challenge, hash, 8);
272 static void mschap2( const char *peer_challenge, const char *auth_challenge,
273 struct smb_passwd * smbPasswd, char *response)
277 challenge_hash(peer_challenge, auth_challenge, smbPasswd->smb_name,
279 mschap(challenge, smbPasswd, response, 1);
283 * auth_response() generates MS-CHAP v2 SUCCESS response
284 * according to RFC 2759 GenerateAuthenticatorResponse()
285 * returns 42-octet response string
287 static void auth_response(struct smb_passwd * smbPasswd, char *ntresponse,
288 char *peer_challenge, char *auth_challenge,
294 {0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
295 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
296 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
297 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74};
300 {0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
301 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
302 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
303 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
309 * Hash password hash into hashhash
312 md4_calc(hashhash, smbPasswd->smb_nt_passwd, 16);
315 SHA1Update(&Context, hashhash, 16);
316 SHA1Update(&Context, ntresponse, 24);
317 SHA1Update(&Context, magic1, 39);
318 SHA1Final(digest, &Context);
319 challenge_hash(peer_challenge, auth_challenge, smbPasswd->smb_name,
322 SHA1Update(&Context, digest, 20);
323 SHA1Update(&Context, challenge, 8);
324 SHA1Update(&Context, magic2, 41);
325 SHA1Final(digest, &Context);
328 * Encode the value of 'Digest' as "S=" followed by
329 * 40 ASCII hexadecimal digits and return it in
330 * AuthenticatorResponse.
332 * "S=0123456789ABCDEF0123456789ABCDEF01234567"
337 bin2hex(digest, response + 2, 20);
340 struct mschap_instance {
347 static CONF_PARSER module_config[] = {
349 * Cache the password by default.
351 { "ignore_password", PW_TYPE_BOOLEAN,
352 offsetof(struct mschap_instance,ignore_password), NULL, "no" },
353 { "use_mppe", PW_TYPE_BOOLEAN,
354 offsetof(struct mschap_instance,use_mppe), NULL, "yes" },
355 { "passwd", PW_TYPE_STRING_PTR,
356 offsetof(struct mschap_instance, passwd_file), NULL, NULL },
357 { "authtype", PW_TYPE_STRING_PTR,
358 offsetof(struct mschap_instance, auth_type), NULL, NULL },
360 { NULL, -1, 0, NULL, NULL } /* end the list */
364 * Create instance for our module. Allocate space for
365 * instance structure and read configuration parameters
367 static int mschap_instantiate(CONF_SECTION *conf, void **instance)
369 struct mschap_instance *inst;
371 inst = *instance = rad_malloc(sizeof(struct mschap_instance));
372 if (cf_section_parse(conf, inst, module_config) < 0) {
380 * deinstantiate module, free all memory allocated during
381 * mschap_instantiate()
383 static int mschap_detach(void *instance){
384 #define inst ((struct mschap_instance *)instance)
385 if (inst->passwd_file) free(inst->passwd_file);
386 if (inst->auth_type) free(inst->auth_type);
393 * add_reply() adds either MS-CHAP2-Success or MS-CHAP-Error
394 * attribute to reply packet
396 static void add_reply(VALUE_PAIR** vp, unsigned char ident,
397 const char* name, const char* value, int len)
399 VALUE_PAIR *reply_attr;
400 reply_attr = pairmake(name, "", T_OP_EQ);
401 *reply_attr->strvalue = ident;
402 memcpy(reply_attr->strvalue + 1, value, len);
403 reply_attr->length = len + 1;
404 pairadd(vp, reply_attr);
407 static void mppe_add_reply(VALUE_PAIR** vp,
408 const char* name, const char* value, int len)
410 VALUE_PAIR *reply_attr;
411 reply_attr = pairmake(name, "", T_OP_EQ);
412 memcpy(reply_attr->strvalue, value, len);
413 reply_attr->length = len;
414 pairadd(vp, reply_attr);
417 static void mppe_chap2_gen_keys128(uint8_t *secret,uint8_t *vector,
418 uint8_t *nt_hash,uint8_t *response,
419 uint8_t *sendkey,uint8_t *recvkey)
424 uint8_t nt_hashhash[16];
426 md4_calc(nt_hashhash,nt_hash,16);
428 mppe_chap2_get_keys128(nt_hashhash,response,enckey1,enckey2);
430 salt[0] = (vector[0] ^ vector[1]) | 0x80;
431 salt[1] = (vector[2] ^ vector[3]);
433 mppe_gen_respkey(secret,vector,salt,enckey1,sendkey);
435 salt[0] = (vector[4] ^ vector[5]) | 0x80;
436 salt[1] = (vector[6] ^ vector[7]);
438 mppe_gen_respkey(secret,vector,salt,enckey2,recvkey);
441 static void mppe_chap2_get_keys128(uint8_t *nt_hashhash,uint8_t *nt_response,
442 uint8_t *sendkey,uint8_t *recvkey)
444 uint8_t masterkey[16];
446 mppe_GetMasterKey(nt_hashhash,nt_response,masterkey);
448 mppe_GetAsymmetricStartKey(masterkey,sendkey,16,1);
449 mppe_GetAsymmetricStartKey(masterkey,recvkey,16,0);
452 static void mppe_GetMasterKey(uint8_t *nt_hashhash,uint8_t *nt_response,
457 { 0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
458 0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
459 0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79 };
464 SHA1Update(&Context,nt_hashhash,16);
465 SHA1Update(&Context,nt_response,24);
466 SHA1Update(&Context,magic1,27);
467 SHA1Final(digest,&Context);
469 memcpy(masterkey,digest,16);
472 static void mppe_GetAsymmetricStartKey(uint8_t *masterkey,uint8_t *sesskey,
473 int keylen,int issend)
476 uint8_t SHSpad1[40] =
477 { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
478 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
479 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
480 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
482 uint8_t SHSpad2[40] =
483 { 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
484 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
485 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
486 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2 };
489 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
490 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
491 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
492 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
493 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
494 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
495 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
496 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
497 0x6b, 0x65, 0x79, 0x2e };
500 { 0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
501 0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
502 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
503 0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
504 0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
505 0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
506 0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
507 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
508 0x6b, 0x65, 0x79, 0x2e };
522 SHA1Update(&Context,masterkey,16);
523 SHA1Update(&Context,SHSpad1,40);
524 SHA1Update(&Context,s,84);
525 SHA1Update(&Context,SHSpad2,40);
526 SHA1Final(digest,&Context);
528 memcpy(sesskey,digest,keylen);
531 static void mppe_gen_respkey(uint8_t* secret,uint8_t* vector,
532 uint8_t* salt,uint8_t* enckey,uint8_t* key)
540 for(slen=0;slen < 32;slen++) {
541 if(secret[slen] == 0) break;
548 memcpy(plain + 1,enckey,16);
551 MD5Update(&Context,secret,slen);
552 MD5Update(&Context,vector,AUTH_VECTOR_LEN);
553 MD5Update(&Context,salt,2);
554 MD5Final(buf,&Context);
556 for(i=0;i < 16;i++) {
561 MD5Update(&Context,secret,slen);
562 MD5Update(&Context,plain,16);
563 MD5Final(buf,&Context);
565 for(i=0;i < 16;i++) {
566 plain[i + 16] ^= buf[i];
570 memcpy(key + 2,plain,32);
575 * mschap_authorize() - authorize user if we can authenticate
576 * it later. Add Auth-Type attribute if present in module
577 * configuration (usually Auth-Type must be "MS-CHAP")
579 static int mschap_authorize(void * instance, REQUEST *request)
581 #define inst ((struct mschap_instance *)instance)
582 VALUE_PAIR *challenge = NULL, *response = NULL;
583 VALUE_PAIR *reply_attr;
584 VALUE_PAIR *password = NULL;
585 struct smb_passwd *smbPasswd = NULL;
588 password = pairfind(request->config_items, PW_PASSWORD);
589 challenge = pairfind(request->packet->vps, PW_MSCHAP_CHALLENGE);
591 response = pairfind(request->packet->vps, PW_MSCHAP_RESPONSE);
593 response = pairfind(request->packet->vps, PW_MSCHAP2_RESPONSE);
595 if (password && (!challenge || !response)) {
596 /* We have nothing related to MS-CHAP or NTLM */
597 return RLM_MODULE_NOOP;
599 if (!request->username || *request->username->strvalue == 0) {
600 /* Usernam must present */
601 return RLM_MODULE_NOOP;
603 if (password && !inst->ignore_password)
604 smbPasswd = createsmbpw(request->username->strvalue, password->strvalue);
605 else if (inst->passwd_file) {
606 smbPasswd = getsmbfilepwname (inst->passwd_file, request->username->strvalue);
609 if(challenge && response){
610 add_reply( &request->reply->vps, *response->strvalue,
611 "MS-CHAP-Error", "E=691 R=1", 9);
613 return RLM_MODULE_NOTFOUND;
615 if (inst->auth_type){
616 pairdelete(&request->config_items, PW_AUTHTYPE);
617 reply_attr = pairmake("Auth-Type", inst->auth_type, T_OP_EQ);
618 pairadd(&request->config_items, reply_attr);
620 if (smbPasswd->smb_passwd){
621 reply_attr = pairmake("LM-Password", "", T_OP_EQ);
622 reply_attr->length = 16;
623 memcpy(reply_attr->strvalue, smbPasswd->smb_passwd, 16);
624 pairadd(&request->config_items, reply_attr);
626 if (smbPasswd->smb_nt_passwd){
627 reply_attr = pairmake("NT-Password", "", T_OP_EQ);
628 reply_attr->length = 16;
629 memcpy(reply_attr->strvalue, smbPasswd->smb_nt_passwd, 16);
630 pairadd(&request->config_items, reply_attr);
632 if (smbPasswd->acct_ctrl&ACB_DISABLED ||
633 smbPasswd->acct_ctrl&ACB_AUTOLOCK ||
634 !smbPasswd->acct_ctrl&ACB_NORMAL) {
635 if(challenge && response) {
636 add_reply( &request->reply->vps, *response->strvalue,
637 "MS-CHAP-Error", "E=647 R=0", 9);
639 return RLM_MODULE_USERLOCK;
642 reply_attr = pairmake("SMB-Account-CTRL", "0", T_OP_EQ);
643 reply_attr->lvalue = smbPasswd->acct_ctrl;
644 pairadd(&request->config_items, reply_attr);
645 return RLM_MODULE_OK;
651 * mschap_authenticate() - authenticate user based on given
652 * attributes and configuration.
653 * We will try to find out password in configuration
654 * or in configured passwd file.
655 * If one is found we will check paraneters given by NAS.
657 * If PW_SMB_ACCOUNT_CTRL is not set to ACB_PWNOTREQ we must have
659 * PAP: PW_PASSWORD or
660 * MS-CHAP: PW_MSCHAP_CHALLENGE and PW_MSCHAP_RESPONSE or
661 * MS-CHAP2: PW_MSCHAP_CHALLENGE and PW_MSCHAP2_RESPONSE
662 * In case of password mismatch or locked account we MAY return
663 * PW_MSCHAP_ERROR for MS-CHAP or MS-CHAP v2
664 * If MS-CHAP2 succeeds we MUST return
667 static int mschap_authenticate(void * instance, REQUEST *request)
669 VALUE_PAIR *challenge = NULL, *response = NULL;
670 VALUE_PAIR *password = NULL;
671 uint8_t calculated[32];
672 uint8_t msch2resp[42];
673 uint8_t mppe_sendkey[34];
674 uint8_t mppe_recvkey[34];
675 struct smb_passwd smbPasswd, *smbPasswd1 = NULL;
681 smbPasswd.smb_name = request->username->strvalue;
682 password = pairfind(request->config_items, PW_SMB_ACCOUNT_CTRL);
684 smbPasswd.acct_ctrl = password->lvalue;
685 if (smbPasswd.acct_ctrl&ACB_PWNOTREQ) return RLM_MODULE_OK;
687 password = pairfind(request->config_items, PW_LM_PASSWORD);
690 smbPasswd.smb_passwd = password->strvalue;
692 password = pairfind(request->config_items, PW_NT_PASSWORD);
695 smbPasswd.smb_nt_passwd = password->strvalue;
699 * We have neither NT nor LM passwords configured
701 return RLM_MODULE_INVALID;
705 * If NAS sent cleartext password - encode it and check
706 * only against passwd file. If either NT or LM hash match
710 password = pairfind(request->packet->vps, PW_PASSWORD);
711 if (password && request->username && *request->username->strvalue!= 0) {
713 smbPasswd1 = createsmbpw(request->username->strvalue, password->strvalue);
714 if ( (smbPasswd.smb_passwd && !memcmp(smbPasswd1->smb_passwd, smbPasswd.smb_passwd, 16)) ||
715 (smbPasswd.smb_nt_passwd && !memcmp(smbPasswd1->smb_nt_passwd, smbPasswd.smb_nt_passwd, 16)) )
716 return RLM_MODULE_OK;
717 else return RLM_MODULE_REJECT;
719 else if ( (challenge = pairfind(request->packet->vps, PW_MSCHAP_CHALLENGE)) ){
720 res = RLM_MODULE_REJECT;
722 * We need an MS-CHAP-Challenge attribute to calculate
725 if ( (response = pairfind(request->packet->vps, PW_MSCHAP_RESPONSE)) ){
726 if (response->length < 50 || challenge->length < 8) {
727 radlog(L_AUTH, "rlm_mschap: Attribute \"MS-CHAP-Response\" has wrong format.");
728 return RLM_MODULE_INVALID;
731 * We are doing MS-CHAP
732 * Calculate the MS-CHAP response
734 if (smbPasswd.smb_nt_passwd && (response->strvalue[1] & 0x01)) {
736 * Try NT response first if UseNT flag is set
738 mschap(challenge->strvalue, &smbPasswd, calculated, 1);
739 if (memcmp(response->strvalue + 26, calculated, 24) == 0) {
744 if (res != RLM_MODULE_OK && smbPasswd.smb_passwd) {
748 mschap(challenge->strvalue, &smbPasswd,
750 if (memcmp(response->strvalue + 2, calculated, 24) == 0) {
755 else if ( (response = pairfind(request->packet->vps, PW_MSCHAP2_RESPONSE)) ){
756 if (response->length < 50 || challenge->length < 16) {
757 radlog(L_AUTH, "rlm_mschap: Attribute \"MS-CHAP2-Response\" has wrong format.");
758 return RLM_MODULE_INVALID;
761 * We are doing MS-CHAPv2
762 * We need NT hash for it to calculate response
764 if (smbPasswd.smb_nt_passwd) {
765 mschap2(response->strvalue + 2, challenge->strvalue,
766 &smbPasswd, calculated);
767 if (memcmp(response->strvalue + 26, calculated, 24) == 0) {
768 auth_response(&smbPasswd, calculated,
769 response->strvalue + 2,
772 add_reply( &request->reply->vps, *response->strvalue,
773 "MS-CHAP2-Success", msch2resp, 42);
779 radlog(L_AUTH, "rlm_mschap: Response attribute not found");
780 return RLM_MODULE_INVALID;
782 if (res == RLM_MODULE_OK){
783 if (((struct mschap_instance *)instance)->use_mppe) {
784 mppe_chap2_gen_keys128(request->secret,request->packet->vector,
785 smbPasswd.smb_nt_passwd,
786 response->strvalue + 26,
787 mppe_sendkey,mppe_recvkey);
788 mppe_add_reply( &request->reply->vps,
789 "MS-MPPE-Recv-Key",mppe_recvkey,34);
790 mppe_add_reply( &request->reply->vps,
791 "MS-MPPE-Send-Key",mppe_sendkey,34);
794 return RLM_MODULE_OK;
798 add_reply( &request->reply->vps, *response->strvalue,
799 "MS-CHAP-Error", "E=691 R=1", 9);
800 return RLM_MODULE_REJECT;
804 module_t rlm_mschap = {
807 NULL, /* initialize */
808 mschap_instantiate, /* instantiation */
810 mschap_authenticate, /* authenticate */
811 mschap_authorize, /* authorize */
812 NULL, /* pre-accounting */
813 NULL, /* accounting */
814 NULL /* checksimul */
816 mschap_detach, /* detach */