+ MPPE support by Takahiro Wagatsuma <waga@sic.shibaura-it.ac.jp> added
[freeradius.git] / src / modules / rlm_mschap / rlm_mschap.c
1 /*
2  * rlm_mschap.c 
3  *
4  * Version:     $Id$
5  *
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.
10  *
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.
15  *
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
19  *
20  * Copyright 2000,2001  The FreeRADIUS server project
21  */
22
23
24 /*
25  *  mschap.c    MS-CHAP module
26  *
27  *  Jay Miller  jaymiller@socket.net
28  *
29  *  This implements MS-CHAP, as described in RFC 2548
30  *
31  *  http://www.freeradius.org/rfc/rfc2548.txt
32  *
33  */
34
35 /*
36  *  If you have any questions on NTLM (Samba) passwords
37  *  support, LM authentication and MS-CHAP v2 support
38  *  please contact
39  *
40  *  Vladimir Dubrovin   vlad@sandy.ru
41  *  aka
42  *  ZARAZA              3APA3A@security.nnov.ru
43  */
44  
45 #include        "autoconf.h"
46 #include        "libradius.h"
47
48 #include        <stdio.h>
49 #include        <stdlib.h>
50 #include        <string.h>
51 #include        <ctype.h>
52
53 #include        "radiusd.h"
54 #include        "modules.h"
55
56 #include        "des.h"
57 #include        "md5.h"
58 #include        "sha1.h"
59 #include        "smbpass.h"
60
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
67
68
69 typedef enum {
70         NONE,
71         CLEARTEXT,
72         MSCHAP1,
73         MSCHAP2} AUTHTYPE;
74
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,
83                 char *response);
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);
90
91 static void mppe_add_reply(VALUE_PAIR** vp,
92                const char* name, const char* value, int len);
93
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);
97
98 static void mppe_chap2_get_keys128(uint8_t *nt_hashhash,uint8_t *nt_response,
99                                uint8_t *sendkey,uint8_t *recvkey);
100
101 static void mppe_GetMasterKey(uint8_t *nt_hashhash,uint8_t *nt_response,
102                        uint8_t *masterkey);
103
104 static void mppe_GetAsymmetricStartKey(uint8_t *masterkey,uint8_t *sesskey,
105                                int keylen,int issend);
106
107 static void mppe_gen_respkey(uint8_t* secret,uint8_t* vector,
108                        uint8_t* salt,uint8_t* enckey,uint8_t* key);
109
110 void md4_calc (unsigned char *, unsigned char *, unsigned int);
111
112
113
114 /* 
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.
118  */
119 static void parity_key(char * szOut, const char * szIn)
120 {
121         int i;
122         unsigned char cNext = 0;
123         unsigned char cWorking = 0;
124         
125         for (i = 0; i < 7; i++) {
126                 /* Shift operator works in place.  Copy the char out */
127                 cWorking = szIn[i];
128                 szOut[i] = (cWorking >> i) | cNext | 1;
129                 cWorking = szIn[i];
130                 cNext = (cWorking << (7 - i));
131         }
132         szOut[i] = cNext | 1;
133 }
134
135 /*
136  *      des_encrypt takes an 8-byte string and a 7-byte key and
137  *      returns an 8-byte DES encrypted string in szOut
138  */
139 static void des_encrypt(const char *szClear, const char *szKey, char *szOut)
140 {
141         char szParityKey[9];
142         unsigned long ulK[16][2];
143         
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 */
148 }
149
150
151
152 /*
153  *      ntpwdhash converts Unicode password to 16-byte NT hash
154  *      with MD4
155  */
156 static void ntpwdhash (char *szHash, const char *szPassword)
157 {
158         char szUnicodePass[513];
159         char nPasswordLen;
160         int i;
161
162         /*
163          *      NT passwords are unicode.  Convert plain text password
164          *      to unicode by inserting a zero every other byte
165          */
166         nPasswordLen = strlen(szPassword);
167         for (i = 0; i < nPasswordLen; i++) {
168                 szUnicodePass[i << 1] = szPassword[i];
169                 szUnicodePass[(i << 1) + 1] = 0;
170         }
171
172         /* Encrypt Unicode password to a 16-byte MD4 hash */
173         md4_calc(szHash, szUnicodePass, (nPasswordLen<<1) );
174 }
175
176
177
178 /*
179  *      lmpwdhash converts 14-byte null-padded uppercase OEM
180  *      password to 16-byte DES hash with predefined salt string
181  */
182 static void lmpwdhash (char *szHash, const char *szPassword)
183 {
184         char szOEMPass[14];
185         char stdText[] = "KGS!@#$%";
186         int i;
187
188         memset(szOEMPass, 0, 14);
189         for (i = 0; i < 14 && szPassword[i]; i++)
190                 szOEMPass[i] = toupper(szPassword[i]);
191
192         /* Obtain DES hash of OEM password */
193         des_encrypt(stdText, szOEMPass, szHash); 
194         des_encrypt(stdText, szOEMPass+7, szHash+8);
195 }
196
197 /*
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
201  *      allowed
202  */
203 static struct smb_passwd *createsmbpw(char * username, char *password)
204 {
205         static struct smb_passwd pw_buf;
206         static unsigned char smbpwd[16];
207         static unsigned char smbntpwd[16];
208
209
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;
214   
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;
220         }
221         return &pw_buf;
222 }
223
224
225
226 /*
227  *      mschap takes an 8-byte challenge string and SMB password
228  *      and returns a 24-byte response string in szResponse
229  */
230 static void mschap(const char *szChallenge, struct smb_passwd * smbPasswd,
231         char *szResponse, int bUseNT) {
232
233         char szMD4[21];
234         
235         /* initialize hash string */
236         memset(szMD4, 0, 21);
237         
238         memcpy(szMD4, (bUseNT)?
239                 smbPasswd->smb_nt_passwd : smbPasswd->smb_passwd, 16);
240         
241         /*
242          *
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
246          */
247         des_encrypt(szChallenge, szMD4, szResponse);
248         des_encrypt(szChallenge, szMD4 + 7, szResponse + 8);
249         des_encrypt(szChallenge, szMD4 + 14, szResponse + 16);
250 }   
251
252
253 /*
254  *      challenge_hash() is used by mschap2() and auth_response()
255  *      implements RFC2759 ChallengeHash()
256  *      generates 64 bit challenge
257  */
258 static void challenge_hash( const char* peer_challenge, const char* auth_challenge,
259                      const char* user_name, char * challenge )
260 {
261         SHA1_CTX Context;
262         char hash[20];
263         
264         SHA1Init(&Context);
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);
270 }
271
272 static void mschap2( const char *peer_challenge, const char *auth_challenge,
273                 struct smb_passwd * smbPasswd, char *response)
274 {
275         char challenge[8];
276         
277         challenge_hash(peer_challenge, auth_challenge, smbPasswd->smb_name,
278                 challenge);
279         mschap(challenge, smbPasswd, response, 1);
280 }
281
282 /*
283  *      auth_response() generates MS-CHAP v2 SUCCESS response
284  *      according to RFC 2759 GenerateAuthenticatorResponse()
285  *      returns 42-octet response string
286  */
287 static void auth_response(struct smb_passwd * smbPasswd, char *ntresponse,
288                 char *peer_challenge, char *auth_challenge,
289                 char *response)
290 {
291         SHA1_CTX Context;
292         char hashhash[16];
293         char magic1[39] =
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};
298                                              
299         char magic2[41] =
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,
304                 0x6E};
305         char challenge[8];
306         char digest[20];
307
308         /*
309          * Hash password hash into hashhash
310          */
311
312         md4_calc(hashhash, smbPasswd->smb_nt_passwd, 16);
313
314         SHA1Init(&Context);
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,
320                 challenge);
321         SHA1Init(&Context);
322         SHA1Update(&Context, digest, 20);
323         SHA1Update(&Context, challenge, 8);
324         SHA1Update(&Context, magic2, 41);
325         SHA1Final(digest, &Context);
326
327         /*
328          * Encode the value of 'Digest' as "S=" followed by
329          * 40 ASCII hexadecimal digits and return it in
330          * AuthenticatorResponse.
331          * For example,
332          *   "S=0123456789ABCDEF0123456789ABCDEF01234567"
333          */
334  
335         response[0] = 'S';
336         response[1] = '=';
337         bin2hex(digest, response + 2, 20);
338 }
339
340 struct mschap_instance {
341         int ignore_password;
342         int use_mppe;
343         char *passwd_file;
344         char *auth_type;
345 };
346
347 static CONF_PARSER module_config[] = {
348         /*
349          *      Cache the password by default.
350          */
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 },
359         
360         { NULL, -1, 0, NULL, NULL }             /* end the list */
361 };
362
363 /*
364  *      Create instance for our module. Allocate space for
365  *      instance structure and read configuration parameters
366  */
367 static int mschap_instantiate(CONF_SECTION *conf, void **instance)
368 {
369         struct mschap_instance *inst;
370
371         inst = *instance = rad_malloc(sizeof(struct mschap_instance));
372         if (cf_section_parse(conf, inst, module_config) < 0) {
373                 free(inst);
374                 return -1;
375         }
376         return 0;
377 }
378
379 /*
380  *      deinstantiate module, free all memory allocated during
381  *      mschap_instantiate()
382  */
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);
387         free(instance);
388         return 0;
389 #undef inst
390 }
391         
392 /*
393  *      add_reply() adds either MS-CHAP2-Success or MS-CHAP-Error
394  *      attribute to reply packet
395  */
396 static void add_reply(VALUE_PAIR** vp, unsigned char ident,
397                 const char* name, const char* value, int len)
398 {
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);
405 }
406
407 static void mppe_add_reply(VALUE_PAIR** vp,
408                        const char* name, const char* value, int len)
409 {
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);
415 }
416
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)
420 {
421        uint8_t enckey1[16];
422        uint8_t enckey2[16];
423        uint8_t salt[2];
424        uint8_t nt_hashhash[16];
425
426        md4_calc(nt_hashhash,nt_hash,16);
427
428        mppe_chap2_get_keys128(nt_hashhash,response,enckey1,enckey2);
429
430        salt[0] = (vector[0] ^ vector[1]) | 0x80;
431        salt[1] = (vector[2] ^ vector[3]);
432
433        mppe_gen_respkey(secret,vector,salt,enckey1,sendkey);
434
435        salt[0] = (vector[4] ^ vector[5]) | 0x80;
436        salt[1] = (vector[6] ^ vector[7]);
437
438        mppe_gen_respkey(secret,vector,salt,enckey2,recvkey);
439 }
440
441 static void mppe_chap2_get_keys128(uint8_t *nt_hashhash,uint8_t *nt_response,
442                                uint8_t *sendkey,uint8_t *recvkey)
443 {
444        uint8_t masterkey[16];
445
446        mppe_GetMasterKey(nt_hashhash,nt_response,masterkey);
447
448        mppe_GetAsymmetricStartKey(masterkey,sendkey,16,1);
449        mppe_GetAsymmetricStartKey(masterkey,recvkey,16,0);
450 }
451
452 static void mppe_GetMasterKey(uint8_t *nt_hashhash,uint8_t *nt_response,
453                        uint8_t *masterkey)
454 {
455        uint8_t digest[20];
456        uint8_t magic1[27] =
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 };
460
461        SHA1_CTX Context;
462
463        SHA1Init(&Context);
464        SHA1Update(&Context,nt_hashhash,16);
465        SHA1Update(&Context,nt_response,24);
466        SHA1Update(&Context,magic1,27);
467        SHA1Final(digest,&Context);
468
469        memcpy(masterkey,digest,16);
470 }
471
472 static void mppe_GetAsymmetricStartKey(uint8_t *masterkey,uint8_t *sesskey,
473                                int keylen,int issend)
474 {
475        uint8_t digest[20];
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 };
481
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 };
487
488        uint8_t magic2[84] =
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 };
498
499       uint8_t magic3[84] =
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 };
509
510        uint8_t *s;
511        SHA1_CTX Context;
512
513        memset(digest,0,20);
514
515        if(issend) {
516                s = magic3;
517        } else {
518                s = magic2;
519        }
520
521        SHA1Init(&Context);
522        SHA1Update(&Context,masterkey,16);
523        SHA1Update(&Context,SHSpad1,40);
524        SHA1Update(&Context,s,84);
525        SHA1Update(&Context,SHSpad2,40);
526        SHA1Final(digest,&Context);
527
528        memcpy(sesskey,digest,keylen);
529 }
530
531 static void mppe_gen_respkey(uint8_t* secret,uint8_t* vector,
532                        uint8_t* salt,uint8_t* enckey,uint8_t* key)
533 {
534        uint8_t plain[32];
535        uint8_t buf[16];
536        int i;
537        MD5_CTX Context;
538        int slen;
539
540        for(slen=0;slen < 32;slen++) {
541                if(secret[slen] == 0) break;
542        }
543
544        memset(key,0,34);
545
546        memset(plain,0,32);
547        plain[0] = 16;
548        memcpy(plain + 1,enckey,16);
549
550        MD5Init(&Context);
551        MD5Update(&Context,secret,slen);
552        MD5Update(&Context,vector,AUTH_VECTOR_LEN);
553        MD5Update(&Context,salt,2);
554        MD5Final(buf,&Context);
555
556        for(i=0;i < 16;i++) {
557                plain[i] ^= buf[i];
558        }
559
560        MD5Init(&Context);
561        MD5Update(&Context,secret,slen);
562        MD5Update(&Context,plain,16);
563        MD5Final(buf,&Context);
564
565        for(i=0;i < 16;i++) {
566                plain[i + 16] ^= buf[i];
567        }
568
569        memcpy(key,salt,2);
570        memcpy(key + 2,plain,32);
571 }
572
573
574 /*
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")
578  */
579 static int mschap_authorize(void * instance, REQUEST *request)
580 {
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;
586         
587         
588         password = pairfind(request->config_items, PW_PASSWORD);
589         challenge = pairfind(request->packet->vps, PW_MSCHAP_CHALLENGE);
590         if (challenge) {
591                 response = pairfind(request->packet->vps, PW_MSCHAP_RESPONSE);
592                 if (!response)
593                         response = pairfind(request->packet->vps, PW_MSCHAP2_RESPONSE);
594         }
595         if (password && (!challenge || !response)) {
596                 /*  We have nothing related to MS-CHAP or NTLM */
597                 return RLM_MODULE_NOOP;
598         }
599         if (!request->username || *request->username->strvalue == 0) {
600                 /* Usernam must present */
601                 return RLM_MODULE_NOOP;
602         }
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);
607         }
608         if (!smbPasswd) {
609                 if(challenge && response){
610                         add_reply( &request->reply->vps, *response->strvalue,
611                                 "MS-CHAP-Error", "E=691 R=1", 9);
612                 }
613                 return RLM_MODULE_NOTFOUND;
614         }
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);
619         }
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);
625         }
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);
631         }
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);
638                 }
639                 return RLM_MODULE_USERLOCK;
640         }
641
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;
646 #undef inst
647 }
648
649
650 /*
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.
656  *
657  *      If PW_SMB_ACCOUNT_CTRL is not set to ACB_PWNOTREQ we must have 
658  *      one of:
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
665  *      PW_MSCHAP2_SUCCESS
666  */
667 static int mschap_authenticate(void * instance, REQUEST *request)
668 {
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;
676         AUTHTYPE at = NONE;
677         int res = 0;
678         
679         
680         
681         smbPasswd.smb_name = request->username->strvalue;
682         password = pairfind(request->config_items, PW_SMB_ACCOUNT_CTRL);
683         if(password){
684                 smbPasswd.acct_ctrl = password->lvalue;
685                 if (smbPasswd.acct_ctrl&ACB_PWNOTREQ) return RLM_MODULE_OK;
686         }
687         password = pairfind(request->config_items, PW_LM_PASSWORD);
688         if(password){
689                 res++;
690                 smbPasswd.smb_passwd = password->strvalue;
691         }
692         password = pairfind(request->config_items, PW_NT_PASSWORD);
693         if(password){
694                 res++;
695                 smbPasswd.smb_nt_passwd = password->strvalue;
696         }
697         if (!res) {
698                 /*
699                  * We have neither NT nor LM passwords configured
700                  */
701                 return RLM_MODULE_INVALID;
702          }
703         
704         /*
705          *      If NAS sent cleartext password - encode it and check
706          *      only against passwd file. If either NT or LM hash match
707          *      return OK.
708          */
709
710         password = pairfind(request->packet->vps, PW_PASSWORD);
711         if (password && request->username && *request->username->strvalue!= 0) {
712                 at = CLEARTEXT;
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;
718         }
719         else if ( (challenge = pairfind(request->packet->vps, PW_MSCHAP_CHALLENGE)) ){
720                 res = RLM_MODULE_REJECT;
721                 /*
722                  *      We need an MS-CHAP-Challenge attribute to calculate
723                  *      the response.
724                  */
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;
729                         }
730                         /*
731                          *      We are doing MS-CHAP
732                          *      Calculate the MS-CHAP response
733                          */
734                         if (smbPasswd.smb_nt_passwd && (response->strvalue[1] & 0x01)) {
735                         /*
736                          * Try NT response first if UseNT flag is set
737                          */
738                                 mschap(challenge->strvalue, &smbPasswd, calculated, 1);
739                                 if (memcmp(response->strvalue + 26, calculated, 24) == 0) {
740                                         res = RLM_MODULE_OK;
741                                 }
742                          }
743
744                         if (res != RLM_MODULE_OK && smbPasswd.smb_passwd) {
745                         /*
746                          *      Use LM response.
747                          */
748                                 mschap(challenge->strvalue, &smbPasswd, 
749                                         calculated, 0);
750                                 if (memcmp(response->strvalue + 2, calculated, 24) == 0) {
751                                         res = RLM_MODULE_OK;
752                                 }
753                         }
754                 }
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;
759                         }
760                         /*
761                          *      We are doing MS-CHAPv2
762                          *      We need NT hash for it to calculate response
763                          */
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,
770                                                 challenge->strvalue,
771                                                 msch2resp);
772                                         add_reply( &request->reply->vps, *response->strvalue,
773                                                 "MS-CHAP2-Success", msch2resp, 42);
774                                         res = RLM_MODULE_OK;
775                                 }
776                         }
777                 }
778                 else {
779                         radlog(L_AUTH, "rlm_mschap: Response attribute not found");
780                         return RLM_MODULE_INVALID;
781                 }
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);
792                         }
793
794                         return RLM_MODULE_OK;
795                 }
796         }
797         
798         add_reply( &request->reply->vps, *response->strvalue,
799                 "MS-CHAP-Error", "E=691 R=1", 9);
800         return RLM_MODULE_REJECT;
801
802 }
803
804 module_t rlm_mschap = {
805   "MS-CHAP",
806   0,                            /* type */
807   NULL,                         /* initialize */
808   mschap_instantiate,           /* instantiation */
809   {
810           mschap_authenticate,  /* authenticate */
811           mschap_authorize,     /* authorize */
812           NULL,                 /* pre-accounting */
813           NULL,                 /* accounting */
814           NULL                  /* checksimul */
815   },
816   mschap_detach,                /* detach */
817   NULL,                         /* destroy */
818 };