Release bumped to "gts4".
[tac_plus.git] / default_fn.c
1 /*
2    Copyright (c) 1995-1998 by Cisco systems, Inc.
3
4    Permission to use, copy, modify, and distribute this software for
5    any purpose and without fee is hereby granted, provided that this
6    copyright and permission notice appear on all copies of the
7    software and supporting documentation, the name of Cisco Systems,
8    Inc. not be used in advertising or publicity pertaining to
9    distribution of the program without specific prior permission, and
10    notice be given in supporting documentation that modification,
11    copying and distribution is by permission of Cisco Systems, Inc.
12
13    Cisco Systems, Inc. makes no representations about the suitability
14    of this software for any purpose.  THIS SOFTWARE IS PROVIDED ``AS
15    IS'' AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
16    WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
17    FITNESS FOR A PARTICULAR PURPOSE.
18 */
19
20
21 #include "tac_plus.h"
22
23 #include <stdlib.h>
24 #include <string.h>
25 #include <ctype.h>
26
27 #include "default_fn.h"
28 #include "expire.h"
29 #include "md5.h"
30 #include "report.h"
31 #include "utils.h"
32 #include "cfgfile.h"
33 #include "pwlib.h"
34 #include "choose_authen.h"              /* for "struct authen_data" */
35 #include "do_author.h"                  /* for "struct identity" */
36 #include "packet.h"
37 #include "main.h"
38
39 #ifdef MSCHAP
40 #include "md4.h"
41 #include "mschap.h"
42 #ifdef MSCHAP_DES
43 #include "arap_des.h"
44 #endif /* MSCHAP_DES */
45 #endif /* MSCHAP */
46
47 #ifdef ARAP_DES
48 #include "arap_des.h"
49 #endif
50
51
52 struct private_data;
53
54 static void chap_verify TAC_ARGS((struct authen_data *data));
55 static void arap_verify TAC_ARGS((struct authen_data *data));
56 static void pap_verify TAC_ARGS((struct authen_data *data));
57 static void tac_login TAC_ARGS((struct authen_data *data, struct private_data *p));
58
59 #ifdef MSCHAP
60 static void mschap_verify TAC_ARGS((struct authen_data *data));
61 #endif
62
63
64 /* internal state variables */
65 #define STATE_AUTHEN_START   0  /* no requests issued */
66 #define STATE_AUTHEN_GETUSER 1  /* username has been requested */
67 #define STATE_AUTHEN_GETPASS 2  /* password has been requested */
68
69 struct private_data {
70     char password[MAX_PASSWD_LEN + 1];
71     int state;
72 };
73
74
75 /*
76  * Default tacacs login authentication function. Wants a username
77  * and a password, and tries to verify them.
78  *
79  * Choose_authen will ensure that we already have a username before this
80  * gets called.
81  *
82  * We will query for a password and keep it in the method_data.
83  *
84  * Any strings returned via pointers in authen_data must come from the
85  * heap. They will get freed by the caller.
86  *
87  * Return 0 if data->status is valid, otherwise 1
88  */
89
90 int default_fn TAC_ARGS((struct authen_data *data));
91
92 int
93 default_fn(data)
94 struct authen_data *data;
95 {
96     struct private_data *p;
97     char *name = data->NAS_id->username;
98
99     p = (struct private_data *) data->method_data;
100
101     /* An abort has been received. Clean up and return */
102     if (data->flags & TAC_PLUS_CONTINUE_FLAG_ABORT) {
103         if (data->method_data)
104             free(data->method_data);
105         data->method_data = NULL;
106         return (1);
107     }
108     /* Initialise method_data if first time through */
109     if (!p) {
110         p = (struct private_data *) tac_malloc(sizeof(struct private_data));
111         bzero(p, sizeof(struct private_data));
112         data->method_data = p;
113         p->state = STATE_AUTHEN_START;
114     }
115     if (STREQ(name, DEFAULT_USERNAME)) {
116         /* Never authenticate this user. It's for authorization only */
117         data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
118         if (debug) {
119             report(LOG_DEBUG,
120                    "authentication query for '%s' %s from %s rejected",
121                    name && name[0] ? name : "unknown",
122                    session.port, session.peer);
123         }
124         return (0);
125     }
126     if (data->action != TAC_PLUS_AUTHEN_LOGIN) {
127         data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
128     } else {
129         switch (data->type) {
130         case TAC_PLUS_AUTHEN_TYPE_CHAP:
131             /* set status inside chap_verify */
132             chap_verify(data);
133
134             if (debug) {
135                 report(LOG_DEBUG, "chap-login query for '%s' %s from %s %s",
136                        name && name[0] ? name : "unknown",
137                        session.port, session.peer,
138                        (data->status == TAC_PLUS_AUTHEN_STATUS_PASS) ?
139                        "accepted" : "rejected");
140             }
141             break;
142
143 #ifdef MSCHAP
144         case TAC_PLUS_AUTHEN_TYPE_MSCHAP:
145             /* set status inside mschap_verify */
146             mschap_verify(data);
147
148             if (debug) {
149                 report(LOG_DEBUG, "mschap-login query for '%s' %s from %s %s",
150                        name && name[0] ? name : "unknown",
151                        session.port, session.peer,
152                        (data->status == TAC_PLUS_AUTHEN_STATUS_PASS) ?
153                        "accepted" : "rejected");
154             }
155             break;
156 #endif /* MSCHAP */
157
158         case TAC_PLUS_AUTHEN_TYPE_ARAP:
159             /* set status inside arap_verify */
160             arap_verify(data);
161
162             if (debug) {
163                 report(LOG_DEBUG, "arap query for '%s' %s from %s %s",
164                        name && name[0] ? name : "unknown",
165                        session.port, session.peer,
166                        (data->status == TAC_PLUS_AUTHEN_STATUS_PASS) ?
167                        "accepted" : "rejected");
168             }
169             break;
170
171         case TAC_PLUS_AUTHEN_TYPE_PAP:
172             pap_verify(data);
173
174             if (debug) {
175                 report(LOG_INFO, "pap-login query for '%s' %s from %s %s",
176                        name && name[0] ? name : "unknown",
177                        session.port,
178                        session.peer,
179                        (data->status == TAC_PLUS_AUTHEN_STATUS_PASS) ?
180                        "accepted" : "rejected");
181             }
182             break;
183
184         case TAC_PLUS_AUTHEN_TYPE_ASCII:
185             tac_login(data, p);
186             switch (data->status) {
187             case TAC_PLUS_AUTHEN_STATUS_GETPASS:
188             case TAC_PLUS_AUTHEN_STATUS_GETUSER:
189             case TAC_PLUS_AUTHEN_STATUS_GETDATA:
190                 /* Authentication still in progress. More data required */
191                 return (0);
192
193             default:
194                 /* Authentication finished */
195                 if (debug)
196                     report(LOG_INFO, "login query for '%s' %s from %s %s",
197                            name && name[0] ? name : "unknown",
198                            session.port,
199                            session.peer,
200                            (data->status == TAC_PLUS_AUTHEN_STATUS_PASS) ?
201                            "accepted" : "rejected");
202             }
203             break;
204
205         default:
206             data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
207             break;
208         }
209     }
210
211     if (data->method_data)
212         free(data->method_data);
213     data->method_data = NULL;
214
215     switch (data->status) {
216     case TAC_PLUS_AUTHEN_STATUS_ERROR:
217     case TAC_PLUS_AUTHEN_STATUS_FAIL:
218     case TAC_PLUS_AUTHEN_STATUS_PASS:
219         return (0);
220
221     default:
222         report(LOG_ERR, "%s %s: default_fn set bogus status value %d",
223                session.peer, session.port, data->status);
224         data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
225         return (0);
226     }
227 }
228
229 /* Do a login requiring a username & password. We already know the
230  * username. We may return GETPASS to get a password if we need it.
231  * The password will be stored in the private data
232  *
233  */
234
235 static void tac_login TAC_ARGS((struct authen_data *data, struct private_data *p));
236
237 static void
238 tac_login(data, p)
239 struct authen_data *data;
240 struct private_data *p;
241 {
242     char *name, *passwd;
243     int pwlen;
244
245     name = data->NAS_id->username;
246
247     if (!name[0]) {
248         /* something awful has happened. Give up and die */
249         report(LOG_ERR, "%s %s: no username for login",
250                session.peer, session.port);
251         data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
252         return;
253     }
254     /* Do we have a password? */
255     passwd = p->password;
256
257     if (!passwd[0]) {
258
259         /* no password yet. Either we need to ask for one and expect to get
260          * called again when it's supplied, or we already asked for one and
261          * we should have a reply. */
262
263         switch (p->state) {
264         case STATE_AUTHEN_GETPASS:
265             /* We already asked for a password. This should be the reply */
266             if (data->client_msg) {
267                 pwlen = MIN((int) strlen(data->client_msg), MAX_PASSWD_LEN);
268             } else {
269                 pwlen = 0;
270             }
271             strncpy(passwd, data->client_msg, pwlen);
272             passwd[pwlen] = '\0';
273             break;
274
275         case STATE_AUTHEN_START:
276             /* if we're at the username stage, and the user has
277              * nopasswd defined, then return a PASS
278              */
279             if (cfg_get_user_nopasswd(name, TAC_PLUS_RECURSE)) {
280                 data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
281                 return;
282             }
283             /* FALL-THRU */
284         default:
285             data->flags = TAC_PLUS_AUTHEN_FLAG_NOECHO;
286             data->server_msg = tac_strdup("Password: ");
287             data->status = TAC_PLUS_AUTHEN_STATUS_GETPASS;
288             p->state = STATE_AUTHEN_GETPASS;
289             return;
290         }
291     }
292     /* Now we have a username and password. Try validating */
293
294     /* Assume the worst */
295     data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
296     verify(name, passwd, data, TAC_PLUS_RECURSE);
297     return;
298 }
299
300 /*
301  * Process an inbound PAP login. The username & password should be in
302  * the START packet.
303  */
304
305 static void pap_verify TAC_ARGS((struct authen_data *data));
306
307 static void
308 pap_verify(data)
309 struct authen_data *data;
310 {
311     char *name, *passwd;
312
313     name = data->NAS_id->username;
314
315     if (!name[0]) {
316         /* something awful has happened. Give up and die */
317         report(LOG_ERR, "%s %s: no username for inbound PAP login",
318                session.peer, session.port);
319         data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
320         return;
321     }
322     /* get the password */
323     passwd = tac_malloc(data->client_dlen + 1);
324     bcopy(data->client_data, passwd, data->client_dlen);
325     passwd[data->client_dlen] = '\0';
326
327     /* Assume the worst */
328     data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
329     verify(name, passwd, data, TAC_PLUS_RECURSE);
330     free(passwd);
331 }
332
333
334 static void chap_verify TAC_ARGS((struct authen_data *data));
335
336 /* Verify the challenge and id against the response by looking up the
337  * chap secret in the config file. Set data->status appropriately.
338  */
339 static void
340 chap_verify(data)
341 struct authen_data *data;
342 {
343     char *name, *chal, digest[MD5_LEN];
344     const char *secret;
345     const char *exp_date, *p;
346     u_char *mdp;
347     char id;
348     int chal_len, inlen;
349     MD5_CTX mdcontext;
350
351     if (!(char) data->NAS_id->username[0]) {
352         report(LOG_ERR, "%s %s: no username for chap_verify",
353                session.peer, session.port);
354         data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
355         return;
356     }
357     name = data->NAS_id->username;
358
359     id = data->client_data[0];
360
361     chal_len = data->client_dlen - 1 - MD5_LEN;
362     if (chal_len < 0) {
363         data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
364         return;
365     }
366     if (debug & DEBUG_AUTHEN_FLAG) {
367         report(LOG_DEBUG, "%s %s: chap user=%s, id=%d chal_len=%d",
368                session.peer, session.port, name, (int) id, chal_len);
369
370         /* report_hex(LOG_DEBUG, (u_char *)data->client_data + 1, chal_len); */
371     }
372     /* Assume failure */
373     data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
374
375     /* Get the secret */
376     secret = cfg_get_chap_secret(name, TAC_PLUS_RECURSE);
377
378     /* If there is no chap password for this user, see if there is a global
379      * password for her that we can use */
380     if (!secret) {
381         secret = cfg_get_global_secret(name, TAC_PLUS_RECURSE);
382     }
383     if (!secret) {
384         /* No secret. Fail */
385         if (debug & DEBUG_AUTHEN_FLAG) {
386             report(LOG_DEBUG, "%s %s: No chap or global secret for %s",
387                    session.peer, session.port, name);
388         }
389         data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
390         return;
391     }
392     p = tac_find_substring("cleartext ", secret);
393     if (!p) {
394         report(LOG_ERR, "%s %s: %s chap secret %s is not cleartext",
395                session.peer, session.port, name, secret);
396         data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
397         return;
398     }
399     secret = p;
400
401     /* We now have the secret, the id, and the challenge value. Put them all
402      * together, and run them through the MD5 digest algorithm. */
403
404     inlen = sizeof(u_char) + strlen(secret) + chal_len;
405     mdp = (u_char *) tac_malloc(inlen);
406     mdp[0] = id;
407     bcopy(secret, &mdp[1], strlen(secret));
408     chal = data->client_data + 1;
409     bcopy(chal, mdp + strlen(secret) + 1, chal_len);
410     MD5Init(&mdcontext);
411     MD5Update(&mdcontext, mdp, inlen);
412     MD5Final((u_char *) digest, &mdcontext);
413     free(mdp);
414
415     /* Now compare the received response value with the just calculated
416      * digest value.  If they are equal, it's a pass, otherwise it's a
417      * failure */
418
419     if (bcmp(digest, data->client_data + 1 + chal_len, MD5_LEN)) {
420         data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
421     } else {
422         data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
423     }
424
425     exp_date = cfg_get_expires(name, TAC_PLUS_RECURSE);
426     set_expiration_status(exp_date, data);
427 }
428
429
430 static void pw_bitshift TAC_ARGS((char *pw));
431
432 /*
433  * Force the "parity" bit to zero on a password before passing it to
434  * des. This is not documented anywhere. (I believe forcing the parity
435  * to zero reduces the integrity of the encrypted keys but this is
436  * what Apple chose to do).
437  */
438 static void
439 pw_bitshift(pw)
440 char *pw;
441 {
442     int i;
443     unsigned char pws[8];
444
445     /* key is 0 padded */
446     for (i = 0; i < 8; i++)
447         pws[i] = 0;
448
449     /* parity bit is always zero (this seem bogus) */
450     for (i = 0; i < 8 && pw[i]; i++)
451         pws[i] = pw[i] << 1;
452
453     bcopy(pws, pw, 8);
454 }
455
456
457 static void arap_verify TAC_ARGS((struct authen_data *data));
458
459 static void
460 arap_verify(data)
461 struct authen_data *data;
462 {
463     char nas_chal[8], r_chal[8], r_resp[8], secret[8];
464     const char *name, *cfg_secret, *exp_date, *p;
465
466     if (!(char) data->NAS_id->username[0]) {
467         report(LOG_ERR, "%s %s: no username for arap_verify",
468                session.peer, session.port);
469         data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
470         return;
471     }
472     name = data->NAS_id->username;
473
474     bcopy(data->client_data, nas_chal, 8);
475     bcopy(data->client_data + 8, r_chal, 8);
476     bcopy(data->client_data + 8 + 8, r_resp, 8);
477
478     /* Assume failure */
479     data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
480
481     /* Get the secret */
482     cfg_secret = cfg_get_arap_secret(name, TAC_PLUS_RECURSE);
483
484     /* If there is no arap password for this user, see if there is a global
485      * password for her that we can use */
486     if (!cfg_secret) {
487         cfg_secret = cfg_get_global_secret(name, TAC_PLUS_RECURSE);
488     }
489     if (!cfg_secret) {
490         /* No secret. Fail */
491         if (debug & DEBUG_AUTHEN_FLAG) {
492             report(LOG_DEBUG, "%s %s: No arap or global secret for %s",
493                    session.peer, session.port, name);
494         }
495         data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
496         return;
497     }
498     p = tac_find_substring("cleartext ", cfg_secret);
499     if (!p) {
500         report(LOG_ERR, "%s %s: %s arap secret %s is not cleartext",
501                session.peer, session.port, name, cfg_secret);
502         data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
503         return;
504     }
505     /* need to allocate 8 bytes for secret, even if it's actually shorter */
506     bzero(secret, sizeof(secret));
507     strcpy(secret, p);
508
509     pw_bitshift(secret);
510
511 #ifdef ARAP_DES
512     des_init(0);
513     des_setkey(secret);
514     des_endes(nas_chal);
515     des_done();
516 #endif                          /* ARAP_DES */
517
518     /* Now compare the remote's response value with the just calculated one
519      * value.  If they are equal, it's a pass, otherwise it's a failure */
520
521     if (bcmp(nas_chal, r_resp, 8)) {
522         data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
523     } else {
524         data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
525     }
526
527 #ifdef ARAP_DES
528     /* Now calculate the response to the remote's challenge */
529     des_init(0);
530     des_setkey(secret);
531     des_endes(r_chal);
532     des_done();
533 #endif                          /* ARAP_DES */
534
535     data->server_data = tac_malloc(8);
536     data->server_dlen = 8;
537     bcopy(r_chal, data->server_data, 8);
538
539     exp_date = cfg_get_expires(name, TAC_PLUS_RECURSE);
540     set_expiration_status(exp_date, data);
541 }
542
543
544 #ifdef MSCHAP
545
546 /* Following code is added for ms-chap */
547
548 static void mschap_desencrypt TAC_ARGS((const char *clear, unsigned char *str, unsigned char *cypher));
549
550 static void
551 mschap_desencrypt(clear, str, cypher)
552 const char *clear;
553 unsigned char *str;
554 unsigned char *cypher;
555 {
556     unsigned char key[8];
557
558     /* des_state_type *des_state = NULL; */
559
560     memset(key, 0, 8);
561
562     /* Copy the key inserting parity bits */
563
564 #ifdef old
565     /* This method makes it obvious what we are doing */
566
567 #define getbit(bit,array) ((array[bit/8] & (1 <<  (7-(bit%8)))) !=0)
568 #define setbit(bit,array) (array[bit/8] |= (1 <<  (7-(bit%8))))
569
570     {
571         int i, j;
572
573         j = 0;
574         for (i = 0; i < 56; i++) {
575             if (i && (i % 7 == 0)) {
576                 j++;
577             }
578             if (getbit(i, str))
579                 setbit(j, key);
580             j++;
581         }
582     }
583 #else
584     /* this is a little more cryptic, but faster basicly we are insering a
585      * bit into the stream after every 7 bits */
586
587     key[0] = ((str[0] & 0xfe));
588     key[1] = ((str[0] & 0x01) << 7) | ((str[1] & 0x0fc) >> 1);
589     key[2] = ((str[1] & 0x03) << 6) | ((str[2] & 0x0f8) >> 2);
590     key[3] = ((str[2] & 0x07) << 5) | ((str[3] & 0x0f0) >> 3);
591     key[4] = ((str[3] & 0x0f) << 4) | ((str[4] & 0x0e0) >> 4);
592     key[5] = ((str[4] & 0x1f) << 3) | ((str[5] & 0x0c0) >> 5);
593     key[6] = ((str[5] & 0x3f) << 2) | ((str[6] & 0x080) >> 6);
594     key[7] = ((str[6] & 0x7f) << 1);
595
596 #endif
597
598     /* copy clear to cypher, cause our des encrypts in place */
599     memcpy(cypher, clear, 8);
600 /*
601     des_init(0,&des_state);
602     des_setkey(des_state,key);
603     des_endes(des_state,cypher);
604     des_done(des_state);
605 */
606 #ifdef MSCHAP_DES
607     des_init(0);
608     des_setkey(key);
609     des_endes(cypher);
610     des_done();
611 #endif                          /* MSCHAP_DES */
612 }
613
614
615 static void mschap_deshash TAC_ARGS((unsigned char *clear, unsigned char *cypher));
616
617 static void
618 mschap_deshash(clear, cypher)
619 unsigned char *clear;
620 unsigned char *cypher;
621 {
622     mschap_desencrypt(MSCHAP_KEY, clear, cypher);
623 }
624
625
626 static void mschap_lmpasswordhash TAC_ARGS((const char *password, unsigned char *passwordhash));
627
628 static void
629 mschap_lmpasswordhash(password, passwordhash)
630 const char *password;
631 unsigned char *passwordhash;
632 {
633     unsigned char upassword[15];
634     int i = 0;
635
636     memset(upassword, 0, 15);
637     while (password[i]) {
638         upassword[i] = toupper(password[i]);
639         i++;
640     };
641
642     mschap_deshash(&upassword[0], &passwordhash[0]);
643     mschap_deshash(&upassword[7], &passwordhash[8]);
644 }
645
646
647 static void mschap_challengeresponse TAC_ARGS((const char *challenge, unsigned char *passwordhash, unsigned char *response));
648
649 static void
650 mschap_challengeresponse(challenge, passwordhash, response)
651 const char *challenge;
652 unsigned char *passwordhash;
653 unsigned char *response;
654 {
655     unsigned char zpasswordhash[21];
656
657     memset(zpasswordhash, 0, 21);
658     memcpy(zpasswordhash, passwordhash, 16);
659
660     mschap_desencrypt(challenge, &zpasswordhash[0], &response[0]);
661     mschap_desencrypt(challenge, &zpasswordhash[7], &response[8]);
662     mschap_desencrypt(challenge, &zpasswordhash[14], &response[16]);
663 }
664
665
666 void mschap_lmchallengeresponse TAC_ARGS((const char *challenge, const char *password, unsigned char *response));
667
668 void
669 mschap_lmchallengeresponse(challenge, password, response)
670 const char *challenge;
671 const char *password;
672 unsigned char *response;
673 {
674     unsigned char passwordhash[16];
675
676     mschap_lmpasswordhash(password, passwordhash);
677     mschap_challengeresponse(challenge, passwordhash, response);
678 }
679
680
681 static int mschap_unicode_len TAC_ARGS((unsigned char *password));
682
683 static int
684 mschap_unicode_len(password)
685 unsigned char *password;
686 {
687     int i;
688
689     i = 0;
690     while ((password[i] || password[i + 1]) && (i < 512)) {
691         i += 2;
692     }
693
694     return i;
695 }
696
697
698 static void mschap_ntpasswordhash TAC_ARGS((const char *password, unsigned char *passwordhash));
699
700 static void
701 mschap_ntpasswordhash(password, passwordhash)
702 const char *password;
703 unsigned char *passwordhash;
704 {
705     MD4_CTX context;
706     int i;
707     const char *cp;
708     unsigned char unicode_password[512];
709
710     memset(unicode_password, 0, 512);
711
712     i = 0;
713     memset(unicode_password, 0, 512);
714     cp = password;
715     while (*cp) {
716         unicode_password[i++] = *cp++;
717         unicode_password[i++] = '\0';
718     }
719
720     MD4Init(&context);
721     MD4Update(&context, unicode_password,
722               mschap_unicode_len(unicode_password));
723     MD4Final(passwordhash, &context);
724 }
725
726
727 void mschap_ntchallengeresponse TAC_ARGS((const char *challenge, const char *password, unsigned char *response));
728
729 void
730 mschap_ntchallengeresponse(challenge, password, response)
731 const char *challenge;
732 const char *password;
733 unsigned char *response;
734 {
735     unsigned char passwordhash[16];
736
737     mschap_ntpasswordhash(password, passwordhash);
738     mschap_challengeresponse(challenge, passwordhash, response);
739 }
740
741
742 /* Verify the challenge and id against the response by looking up the
743  * ms-chap secret in the config file. Set data->status appropriately.
744  */
745
746 static void mschap_verify TAC_ARGS((struct authen_data *data));
747
748 static void
749 mschap_verify(data)
750 struct authen_data *data;
751 {
752     const char *name, *secret, *chal, *resp;
753     const char *exp_date, *p;
754     char id;
755     int chal_len;
756     unsigned char lmresponse[24];
757     unsigned char ntresponse[24];
758     int bcmp_status;
759
760     if (!(char) data->NAS_id->username[0]) {
761         report(LOG_ERR, "%s %s: no username for mschap_verify",
762                session.peer, session.port);
763         data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
764         return;
765     }
766     name = data->NAS_id->username;
767
768     id = data->client_data[0];
769
770     chal_len = data->client_dlen - 1 - MSCHAP_DIGEST_LEN;
771     if (data->client_dlen <= (MSCHAP_DIGEST_LEN + 2)) {
772         /* Invalid packet or NULL challenge */
773         data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
774         return;
775     }
776     if (debug & DEBUG_AUTHEN_FLAG) {
777         report(LOG_DEBUG, "%s %s: ms-chap user=%s, id=%d chal_len=%d",
778                session.peer, session.port, name, (int) id, chal_len);
779
780         /* report_hex(LOG_DEBUG, (u_char *)data->client_data + 1, chal_len); */
781     }
782     /* Assume failure */
783     data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
784
785     /* Get the secret */
786     secret = cfg_get_mschap_secret(name, TAC_PLUS_RECURSE);
787
788     /* If there is no ms-chap password for this user, see if there is a
789      * global password for her that we can use */
790     if (!secret) {
791         secret = cfg_get_global_secret(name, TAC_PLUS_RECURSE);
792     }
793     if (!secret) {
794         /* No secret. Fail */
795         if (debug & DEBUG_AUTHEN_FLAG) {
796             report(LOG_DEBUG, "%s %s: No ms-chap or global secret for %s",
797                    session.peer, session.port, name);
798         }
799         data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
800         return;
801     }
802     p = tac_find_substring("cleartext ", secret);
803     if (!p) {
804         report(LOG_ERR, "%s %s: %s ms-chap secret %s is not cleartext",
805                session.peer, session.port, name, secret);
806         data->status = TAC_PLUS_AUTHEN_STATUS_ERROR;
807         return;
808     }
809     secret = p;
810
811     /* We now have the secret, the id, and the challenge value. Put them all
812      * together, and run them through the MD4 digest algorithm. */
813     chal = data->client_data + 1;
814     resp = data->client_data + 1 + chal_len;
815
816     mschap_lmchallengeresponse(chal, secret, lmresponse);
817     mschap_ntchallengeresponse(chal, secret, ntresponse);
818
819     /* Now compare the received response value with the just calculated
820      * digest value.  If they are equal, it's a pass, otherwise it's a
821      * failure */
822     if (resp[48])
823         bcmp_status = bcmp(ntresponse, &resp[24], 24);
824     else
825         bcmp_status = bcmp(lmresponse, &resp[0], 24);
826
827     if (bcmp_status) {
828         data->status = TAC_PLUS_AUTHEN_STATUS_FAIL;
829     } else {
830         data->status = TAC_PLUS_AUTHEN_STATUS_PASS;
831     }
832
833     exp_date = cfg_get_expires(name, TAC_PLUS_RECURSE);
834     set_expiration_status(exp_date, data);
835 }
836
837 #endif /* MSCHAP */