http://downloads.netgear.com/files/GPL/GPL_Source_V361j_DM111PSP_series_consumer_rele...
[bcm963xx.git] / userapps / opensource / ppp / pppoe / chap.c
1 /*
2  * chap.c - Challenge Handshake Authentication Protocol.
3  *
4  * Copyright (c) 1993 The Australian National University.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms are permitted
8  * provided that the above copyright notice and this paragraph are
9  * duplicated in all such forms and that any documentation,
10  * advertising materials, and other materials related to such
11  * distribution and use acknowledge that the software was developed
12  * by the Australian National University.  The name of the University
13  * may not be used to endorse or promote products derived from this
14  * software without specific prior written permission.
15  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18  *
19  * Copyright (c) 1991 Gregory M. Christy.
20  * All rights reserved.
21  *
22  * Redistribution and use in source and binary forms are permitted
23  * provided that the above copyright notice and this paragraph are
24  * duplicated in all such forms and that any documentation,
25  * advertising materials, and other materials related to such
26  * distribution and use acknowledge that the software was developed
27  * by Gregory M. Christy.  The name of the author may not be used to
28  * endorse or promote products derived from this software without
29  * specific prior written permission.
30  *
31  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
32  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
33  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
34  */
35
36 #define RCSID   "$Id: chap.c,v 1.2 2006/05/31 09:34:26 andylin Exp $"
37
38 /*
39  * TODO:
40  */
41
42 #include <stdio.h>
43 #include <string.h>
44 #include <sys/types.h>
45 #include <sys/time.h>
46
47 #include "pppd.h"
48 #include "chap.h"
49 #include "md5.h"
50 /*wilson add for MS-CHAPv2, 05/26/2005*/
51 #include "fsm.h"
52 #include "lcp.h"
53 /*wilson add end*/
54 #ifdef CHAPMS
55 #include "chap_ms.h"
56 #endif
57
58 static const char rcsid[] = RCSID;
59 extern int authfailcount;
60 /*
61  * Command-line options.
62  */
63 static option_t chap_option_list[] = {
64     { "chap-restart", o_int, &chap[0].timeouttime,
65       "Set timeout for CHAP", OPT_PRIO },
66     { "chap-max-challenge", o_int, &chap[0].max_transmits,
67       "Set max #xmits for challenge", OPT_PRIO },
68     { "chap-interval", o_int, &chap[0].chal_interval,
69       "Set interval for rechallenge", OPT_PRIO },
70 #ifdef MSLANMAN
71     { "ms-lanman", o_bool, &ms_lanman,
72       "Use LanMan passwd when using MS-CHAP", 1 },
73 #endif
74 /*wilson add for MS-CHAPv2, 05/26/2005*/
75 #ifdef CHAPMS
76      { "chapms-strip-domain", o_bool, &chapms_strip_domain,
77        "Strip the domain prefix before the Username", 1 },
78 #endif
79 /*wilson add end*/
80     { NULL }
81 };
82
83 /*
84  * Protocol entry points.
85  */
86 static void ChapInit __P((int));
87 static void ChapLowerUp __P((int));
88 static void ChapLowerDown __P((int));
89 static void ChapInput __P((int, u_char *, int));
90 static void ChapProtocolReject __P((int));
91 static int  ChapPrintPkt __P((u_char *, int,
92                               void (*) __P((void *, char *, ...)), void *));
93
94 struct protent chap_protent = {
95     PPP_CHAP,
96     ChapInit,
97     ChapInput,
98     ChapProtocolReject,
99     ChapLowerUp,
100     ChapLowerDown,
101     NULL,
102     NULL,
103     ChapPrintPkt,
104     NULL,
105     1,
106     "CHAP",
107     NULL,
108     chap_option_list,
109     NULL,
110     NULL,
111     NULL
112 };
113
114 chap_state chap[NUM_PPP];               /* CHAP state; one for each unit */
115
116 static void ChapChallengeTimeout __P((void *));
117 static void ChapResponseTimeout __P((void *));
118 static void ChapReceiveChallenge __P((chap_state *, u_char *, int, int));
119 static void ChapRechallenge __P((void *));
120 static void ChapReceiveResponse __P((chap_state *, u_char *, int, int));
121 static void ChapReceiveSuccess __P((chap_state *, u_char *, int, int));
122 static void ChapReceiveFailure __P((chap_state *, u_char *, int, int));
123 static void ChapSendStatus __P((chap_state *, int));
124 static void ChapSendChallenge __P((chap_state *));
125 static void ChapSendResponse __P((chap_state *));
126 /*wilson modify for MS-CHAPv2, 05/26/2005*/
127 //static void ChapGenChallenge __P((chap_state *));
128 void ChapGenChallenge __P((chap_state *));
129 /*wilson modify end*/
130
131 extern double drand48 __P((void));
132 extern void srand48 __P((long));
133
134 /*
135  * ChapInit - Initialize a CHAP unit.
136  */
137 static void
138 ChapInit(unit)
139     int unit;
140 {
141     chap_state *cstate = &chap[unit];
142
143     BZERO(cstate, sizeof(*cstate));
144     cstate->unit = unit;
145     cstate->clientstate = CHAPCS_INITIAL;
146     cstate->serverstate = CHAPSS_INITIAL;
147     cstate->timeouttime = CHAP_DEFTIMEOUT;
148     cstate->max_transmits = CHAP_DEFTRANSMITS;
149 #if defined(ODM_LANG_LLL)
150         cstate->retries = 1;
151 #else    
152     //cstate->retries = CHAP_AUTH_RETRIES;
153     cstate->retries = 1;
154 #endif    
155     /* random number generator is initialized in magic_init */
156 }
157
158
159 /*
160  * ChapAuthWithPeer - Authenticate us with our peer (start client).
161  *
162  */
163 void
164 ChapAuthWithPeer(unit, our_name, digest)
165     int unit;
166     char *our_name;
167     int digest;
168 {
169     chap_state *cstate = &chap[unit];
170
171     cstate->resp_name = our_name;
172     cstate->resp_type = digest;
173
174     if (cstate->clientstate == CHAPCS_INITIAL || cstate->clientstate == CHAPCS_PENDING) {
175         /* lower layer isn't up - wait until later */
176         cstate->clientstate = CHAPCS_PENDING;
177         return;
178     }
179
180     /*
181      * We get here as a result of LCP coming up.
182      * So even if CHAP was open before, we will 
183      * have to re-authenticate ourselves.
184      */
185     cstate->clientstate = CHAPCS_LISTEN;
186 }
187
188
189 /*
190  * ChapAuthPeer - Authenticate our peer (start server).
191  */
192 void
193 ChapAuthPeer(unit, our_name, digest)
194     int unit;
195     char *our_name;
196     int digest;
197 {
198     chap_state *cstate = &chap[unit];
199   
200     cstate->chal_name = our_name;
201     cstate->chal_type = digest;
202
203     if (cstate->serverstate == CHAPSS_INITIAL || cstate->serverstate == CHAPSS_PENDING) {
204         /* lower layer isn't up - wait until later */
205         cstate->serverstate = CHAPSS_PENDING;
206         return;
207     }
208
209     ChapGenChallenge(cstate);
210     ChapSendChallenge(cstate);          /* crank it up dude! */
211     cstate->serverstate = CHAPSS_INITIAL_CHAL;
212 }
213
214
215 /*
216  * ChapChallengeTimeout - Timeout expired on sending challenge.
217  */
218 static void
219 ChapChallengeTimeout(arg)
220     void *arg;
221 {
222     chap_state *cstate = (chap_state *) arg;
223   
224     /* if we aren't sending challenges, don't worry.  then again we */
225     /* probably shouldn't be here either */
226     if (cstate->serverstate != CHAPSS_INITIAL_CHAL && cstate->serverstate != CHAPSS_RECHALLENGE)
227         return;
228
229     if (cstate->chal_transmits >= cstate->max_transmits) {
230         /* give up on peer */
231         error("Peer failed to respond to CHAP challenge");
232         cstate->serverstate = CHAPSS_BADAUTH;
233         auth_peer_fail(cstate->unit, PPP_CHAP);
234         return;
235     }
236
237     ChapSendChallenge(cstate);          /* Re-send challenge */
238 }
239
240
241 /*
242  * ChapResponseTimeout - Timeout expired on sending response.
243  */
244 static void
245 ChapResponseTimeout(arg)
246     void *arg;
247 {
248     chap_state *cstate = (chap_state *) arg;
249
250     /* if we aren't sending a response, don't worry. */
251     if (cstate->clientstate != CHAPCS_RESPONSE)
252         return;
253
254         //cstate->retries--;
255     ChapSendResponse(cstate);           /* re-send response */
256 }
257
258
259 /*
260  * ChapRechallenge - Time to challenge the peer again.
261  */
262 static void
263 ChapRechallenge(arg)
264     void *arg;
265 {
266     chap_state *cstate = (chap_state *) arg;
267
268     /* if we aren't sending a response, don't worry. */
269     if (cstate->serverstate != CHAPSS_OPEN)
270         return;
271
272     ChapGenChallenge(cstate);
273     ChapSendChallenge(cstate);
274     cstate->serverstate = CHAPSS_RECHALLENGE;
275 }
276
277
278 /*
279  * ChapLowerUp - The lower layer is up.
280  *
281  * Start up if we have pending requests.
282  */
283 static void
284 ChapLowerUp(unit)
285     int unit;
286 {
287     chap_state *cstate = &chap[unit];
288   
289     if (cstate->clientstate == CHAPCS_INITIAL)
290         cstate->clientstate = CHAPCS_CLOSED;
291     else if (cstate->clientstate == CHAPCS_PENDING)
292         cstate->clientstate = CHAPCS_LISTEN;
293
294     if (cstate->serverstate == CHAPSS_INITIAL)
295         cstate->serverstate = CHAPSS_CLOSED;
296     else if (cstate->serverstate == CHAPSS_PENDING) {
297         ChapGenChallenge(cstate);
298         ChapSendChallenge(cstate);
299         cstate->serverstate = CHAPSS_INITIAL_CHAL;
300     }
301 }
302
303
304 /*
305  * ChapLowerDown - The lower layer is down.
306  *
307  * Cancel all timeouts.
308  */
309 static void
310 ChapLowerDown(unit)
311     int unit;
312 {
313     chap_state *cstate = &chap[unit];
314   
315     /* Timeout(s) pending?  Cancel if so. */
316     if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
317         cstate->serverstate == CHAPSS_RECHALLENGE)
318         UNTIMEOUT(ChapChallengeTimeout, cstate);
319     else if (cstate->serverstate == CHAPSS_OPEN
320              && cstate->chal_interval != 0)
321         UNTIMEOUT(ChapRechallenge, cstate);
322     if (cstate->clientstate == CHAPCS_RESPONSE)
323         UNTIMEOUT(ChapResponseTimeout, cstate);
324
325     cstate->clientstate = CHAPCS_INITIAL;
326     cstate->serverstate = CHAPSS_INITIAL;
327 }
328
329
330 /*
331  * ChapProtocolReject - Peer doesn't grok CHAP.
332  */
333 static void
334 ChapProtocolReject(unit)
335     int unit;
336 {
337     chap_state *cstate = &chap[unit];
338
339     if (cstate->serverstate != CHAPSS_INITIAL && cstate->serverstate != CHAPSS_CLOSED) 
340         auth_peer_fail(unit, PPP_CHAP);
341
342     if (cstate->clientstate != CHAPCS_INITIAL && cstate->clientstate != CHAPCS_CLOSED) {
343                 cstate->retries--;
344                 authfailcount--;
345         auth_withpeer_fail(unit, PPP_CHAP);
346         }
347     ChapLowerDown(unit);                /* shutdown chap */
348 }
349
350
351 /*
352  * ChapInput - Input CHAP packet.
353  */
354 static void
355 ChapInput(unit, inpacket, packet_len)
356     int unit;
357     u_char *inpacket;
358     int packet_len;
359 {
360     chap_state *cstate = &chap[unit];
361     u_char *inp;
362     u_char code, id;
363     int len;
364   
365     /*
366      * Parse header (code, id and length).
367      * If packet too short, drop it.
368      */
369     inp = inpacket;
370     if (packet_len < CHAP_HEADERLEN) {
371         CHAPDEBUG(("ChapInput: rcvd short header."));
372         return;
373     }
374     GETCHAR(code, inp);
375     GETCHAR(id, inp);
376     GETSHORT(len, inp);
377     if (len < CHAP_HEADERLEN) {
378         CHAPDEBUG(("ChapInput: rcvd illegal length."));
379         return;
380     }
381     if (len > packet_len) {
382         CHAPDEBUG(("ChapInput: rcvd short packet."));
383         return;
384     }
385     len -= CHAP_HEADERLEN;
386   
387     /*
388      * Action depends on code (as in fact it usually does :-).
389      */
390     switch (code) {
391     case CHAP_CHALLENGE:
392         ChapReceiveChallenge(cstate, inp, id, len);
393         break;
394     
395     case CHAP_RESPONSE:
396         ChapReceiveResponse(cstate, inp, id, len);
397         break;
398     
399     case CHAP_FAILURE:
400         ChapReceiveFailure(cstate, inp, id, len);
401         break;
402
403     case CHAP_SUCCESS:
404         ChapReceiveSuccess(cstate, inp, id, len);
405         break;
406
407     default:                            /* Need code reject? */
408         warn("Unknown CHAP code (%d) received.", code);
409         break;
410     }
411 }
412
413
414 /*
415  * ChapReceiveChallenge - Receive Challenge and send Response.
416  */
417 static void
418 ChapReceiveChallenge(cstate, inp, id, len)
419     chap_state *cstate;
420     u_char *inp;
421     int id;
422     int len;
423 {
424     int rchallenge_len;
425     u_char *rchallenge;
426     int secret_len;
427     char secret[MAXSECRETLEN];
428     char rhostname[256];
429     MD5_CTX mdContext;
430     u_char hash[MD5_SIGNATURE_SIZE];
431  
432     if (cstate->clientstate == CHAPCS_CLOSED || cstate->clientstate == CHAPCS_PENDING) {
433         CHAPDEBUG(("ChapReceiveChallenge: in state %d", cstate->clientstate));
434         return;
435     }
436
437     if (len < 2) {
438         CHAPDEBUG(("ChapReceiveChallenge: rcvd short packet."));
439         return;
440     }
441
442     GETCHAR(rchallenge_len, inp);
443     len -= sizeof (u_char) + rchallenge_len;    /* now name field length */
444     if (len < 0) {
445         CHAPDEBUG(("ChapReceiveChallenge: rcvd short packet."));
446         return;
447     }
448     rchallenge = inp;
449     INCPTR(rchallenge_len, inp);
450
451     if (len >= sizeof(rhostname))
452         len = sizeof(rhostname) - 1;
453     BCOPY(inp, rhostname, len);
454     rhostname[len] = '\000';
455
456     /* Microsoft doesn't send their name back in the PPP packet */
457     if (explicit_remote || (remote_name[0] != 0 && rhostname[0] == 0)) {
458         strlcpy(rhostname, remote_name, sizeof(rhostname));
459                 CHAPDEBUG(("ChapReceiveChallenge: using '%q' as remote name", rhostname));
460     }
461
462     /* get secret for authenticating ourselves with the specified host */
463     if (!get_secret(cstate->unit, cstate->resp_name, rhostname, secret, &secret_len, 0)) {
464         secret_len = 0;         /* assume null secret if can't find one */
465         warn("No CHAP secret found for authenticating us to %q", rhostname);
466     }
467
468     /* cancel response send timeout if necessary */
469     if (cstate->clientstate == CHAPCS_RESPONSE)
470         UNTIMEOUT(ChapResponseTimeout, cstate);
471
472     cstate->resp_id = id;
473     cstate->resp_transmits = 0;
474
475     /*  generate MD based on negotiated type */
476     switch (cstate->resp_type) { 
477
478     case CHAP_DIGEST_MD5:
479         MD5Init(&mdContext);
480         MD5Update(&mdContext, &cstate->resp_id, 1);
481         MD5Update(&mdContext, secret, secret_len);
482         MD5Update(&mdContext, rchallenge, rchallenge_len);
483         MD5Final(hash, &mdContext);
484         BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);
485         cstate->resp_length = MD5_SIGNATURE_SIZE;
486         break;
487
488 #ifdef CHAPMS
489 /*wilson modify for MS-CHAPv2, 05/26/2005*/
490     case CHAP_MICROSOFT:
491                CHAPDEBUG(("ChapReceiveChallenge: rcvd type MS-CHAP-V1."));
492                if(rchallenge_len != 8)
493                {
494                    CHAPDEBUG(("Invalid challenge length for MS-CHAP-V1"));
495                    return;
496                }
497         ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
498         break;
499  
500     case CHAP_MICROSOFT_V2:
501             CHAPDEBUG(("ChapReceiveChallenge: rcvd type MS-CHAP-V2."));
502             if(rchallenge_len != 16)
503             {
504                 CHAPDEBUG(("Invalid challenge length for MS-CHAP-V2"));
505                 return;
506             }
507             ChapMS_v2(cstate, rchallenge, rchallenge_len, secret, secret_len);
508             break;
509 /*wilson modify end*/
510 #endif
511
512     default:
513         CHAPDEBUG(("unknown digest type %d", cstate->resp_type));
514         return;
515     }
516
517 #if defined(ODM_LANG_LLL)
518         if ((strlen(rhostname))>0){
519                 char cmd[320]="";
520                 sprintf(cmd, "echo %s > /var/pppoebasname", rhostname); 
521                 system(cmd);
522         }
523 #endif 
524
525     BZERO(secret, sizeof(secret));
526     ChapSendResponse(cstate);
527 }
528
529
530 /*
531  * ChapReceiveResponse - Receive and process response.
532  */
533 static void
534 ChapReceiveResponse(cstate, inp, id, len)
535     chap_state *cstate;
536     u_char *inp;
537     int id;
538     int len;
539 {
540     u_char *remmd, remmd_len;
541     int secret_len, old_state;
542     int code;
543     char rhostname[256];
544     MD5_CTX mdContext;
545     char secret[MAXSECRETLEN];
546     u_char hash[MD5_SIGNATURE_SIZE];
547
548     if (cstate->serverstate == CHAPSS_CLOSED || cstate->serverstate == CHAPSS_PENDING) {
549         CHAPDEBUG(("ChapReceiveResponse: in state %d", cstate->serverstate));
550         return;
551     }
552
553     if (id != cstate->chal_id)
554         return;                 /* doesn't match ID of last challenge */
555
556     /*
557      * If we have received a duplicate or bogus Response,
558      * we have to send the same answer (Success/Failure)
559      * as we did for the first Response we saw.
560      */
561     if (cstate->serverstate == CHAPSS_OPEN) {
562 /*wilson modify for MS-CHAPv2, 05/26/2005*/
563         //ChapSendStatus(cstate, CHAP_SUCCESS);
564         ChapSendStatus(cstate, cstate->chal_type == CHAP_MICROSOFT_V2 ? CHAP_SUCCESS_R : CHAP_SUCCESS);
565 /*wilson modify end*/
566         return;
567     }
568     if (cstate->serverstate == CHAPSS_BADAUTH) {
569         ChapSendStatus(cstate, CHAP_FAILURE);
570         return;
571     }
572
573     if (len < 2) {
574         CHAPDEBUG(("ChapReceiveResponse: rcvd short packet."));
575         return;
576     }
577     GETCHAR(remmd_len, inp);            /* get length of MD */
578     remmd = inp;                        /* get pointer to MD */
579     INCPTR(remmd_len, inp);
580
581     len -= sizeof (u_char) + remmd_len;
582     if (len < 0) {
583         CHAPDEBUG(("ChapReceiveResponse: rcvd short packet."));
584         return;
585     }
586
587     UNTIMEOUT(ChapChallengeTimeout, cstate);
588
589     if (len >= sizeof(rhostname))
590         len = sizeof(rhostname) - 1;
591     BCOPY(inp, rhostname, len);
592     rhostname[len] = '\000';
593
594 /*wilson add for MS-CHAPv2, 05/26/2005*/
595     if (chapms_strip_domain) {
596         char *p, *q;
597         if ((q = strrchr(rhostname, '\\'))) {
598             q++;
599             for (p = rhostname; *q; *p++ = *q++) ;
600                 *p = 0;
601         }
602     }
603 /*wilson add end*/
604
605     /*
606      * Get secret for authenticating them with us,
607      * do the hash ourselves, and compare the result.
608      */
609     code = CHAP_FAILURE;
610     if (!get_secret(cstate->unit, (explicit_remote? remote_name: rhostname), cstate->chal_name, secret, &secret_len, 1)) {
611         warn("No CHAP secret found for authenticating %q", rhostname);
612     } else {
613
614         /*  generate MD based on negotiated type */
615         switch (cstate->chal_type) { 
616
617         case CHAP_DIGEST_MD5:           /* only MD5 is defined for now */
618             if (remmd_len != MD5_SIGNATURE_SIZE)
619                 break;                  /* it's not even the right length */
620             MD5Init(&mdContext);
621             MD5Update(&mdContext, &cstate->chal_id, 1);
622             MD5Update(&mdContext, secret, secret_len);
623             MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
624             MD5Final(hash, &mdContext); 
625
626             /* compare local and remote MDs and send the appropriate status */
627             if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0)
628                 code = CHAP_SUCCESS;    /* they are the same! */
629             break;
630
631 /*wilson add for MS-CHAPv2, 05/26/2005*/
632 #ifdef CHAPMS
633         case CHAP_MICROSOFT:
634             CHAPDEBUG(("ChapReceiveResponse: rcvd type MS-CHAP-V1"));
635             if(remmd_len != MS_CHAP_RESPONSE_LEN)
636                 break;
637             if(ChapMS_Resp(cstate, secret, secret_len, remmd) == 0)
638                 code = CHAP_SUCCESS;
639             break;
640  
641         case CHAP_MICROSOFT_V2:
642             CHAPDEBUG(("ChapReceiveResponse: rcvd type MS-CHAP-V2"));
643             if(remmd_len != MS_CHAP_RESPONSE_LEN)
644                 break;
645             if(ChapMS_v2_Resp(cstate,secret,secret_len,remmd,rhostname) == 0)
646             {
647                 code = CHAP_SUCCESS_R;
648                 ChapMS_v2_Auth(cstate, secret, secret_len, remmd, rhostname);
649             }
650             break;
651 #endif
652 /*wilson add end*/
653         default:
654             CHAPDEBUG(("unknown digest type %d", cstate->chal_type));
655         }
656     }
657
658     BZERO(secret, sizeof(secret));
659     ChapSendStatus(cstate, code);
660
661     if ((code == CHAP_SUCCESS) || (code == CHAP_SUCCESS_R)) {   /*wilson modify for MS-CHAPv2, 05/26/2005*/
662         old_state = cstate->serverstate;
663         cstate->serverstate = CHAPSS_OPEN;
664         if (old_state == CHAPSS_INITIAL_CHAL) {
665             auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);
666         }
667         if (cstate->chal_interval != 0)
668             TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);
669        /*wilson modify for MS-CHAPv2, 05/26/2005*/
670         //notice("CHAP peer authentication succeeded for %q", rhostname);
671             switch (cstate->chal_type) { 
672                 case CHAP_DIGEST_MD5:
673         notice("CHAP peer authentication succeeded for %q", rhostname);
674                     break;
675 #ifdef CHAPMS
676                 case CHAP_MICROSOFT:
677                     notice("MSCHAP peer authentication succeeded for %q", rhostname);
678                     break;
679                 case CHAP_MICROSOFT_V2:
680                     notice("MSCHAP-v2 peer authentication succeeded for %q", rhostname);
681                     break;
682 #endif
683                 default:
684                     notice("CHAP (unknown) peer authentication succeeded for %q", 
685                         rhostname);
686                     break;
687             }
688         /*wilson modify end*/
689     } else {
690        /*wilson modify for MS-CHAPv2, 05/26/2005*/
691         switch (cstate->chal_type) { 
692           case CHAP_DIGEST_MD5:
693             error("CHAP peer authentication failed for remote host %q", 
694                   rhostname);
695             break;
696 #ifdef CHAPMS
697           case CHAP_MICROSOFT:
698             error("MSCHAP peer authentication failed for remote host %q", 
699                   rhostname);
700             break;
701           case CHAP_MICROSOFT_V2:
702             error("MSCHAP-v2 peer authentication failed for remote host %q", 
703                   rhostname);
704             break;
705 #endif
706           default:
707             error("CHAP (unknown) peer authentication failed for remote host %q", rhostname);
708             break;
709         }
710         //error("CHAP peer authentication failed for remote host %q", rhostname);
711         /*wilson modify end*/
712         cstate->serverstate = CHAPSS_BADAUTH;
713         auth_peer_fail(cstate->unit, PPP_CHAP);
714     }
715 }
716
717 /*
718  * ChapReceiveSuccess - Receive Success
719  */
720 static void
721 ChapReceiveSuccess(cstate, inp, id, len)
722     chap_state *cstate;
723     u_char *inp;
724     u_char id;
725     int len;
726 {
727
728     if (cstate->clientstate == CHAPCS_OPEN)
729         /* presumably an answer to a duplicate response */
730         return;
731
732     if (cstate->clientstate != CHAPCS_RESPONSE) {
733         /* don't know what this is */
734         CHAPDEBUG(("ChapReceiveSuccess: in state %d\n", cstate->clientstate));
735         return;
736     }
737
738     UNTIMEOUT(ChapResponseTimeout, cstate);
739
740     /*
741      * Print message.
742      */
743     if (len > 0)
744         PRINTMSG(inp, len);
745
746     cstate->clientstate = CHAPCS_OPEN;
747 #if defined(ODM_LANG_LLL)
748         cstate->retries = 1;
749         authfailcount = 1;
750 #else
751     //cstate->retries = CHAP_AUTH_RETRIES;
752     cstate->retries = 1;
753     authfailcount = 1;
754 #endif    
755     auth_withpeer_success(cstate->unit, PPP_CHAP);
756 }
757
758
759 /*
760  * ChapReceiveFailure - Receive failure.
761  */
762 static void
763 ChapReceiveFailure(cstate, inp, id, len)
764     chap_state *cstate;
765     u_char *inp;
766     u_char id;
767     int len;
768 {
769     if (cstate->clientstate != CHAPCS_RESPONSE) {
770         /* don't know what this is */
771         CHAPDEBUG(("ChapReceiveFailure: in state %d\n", cstate->clientstate));
772         return;
773     }
774
775     UNTIMEOUT(ChapResponseTimeout, cstate);
776
777     /*
778      * Print message.
779      */
780     if (len > 0)
781         PRINTMSG(inp, len);
782
783
784     error("CHAP authentication failed");
785
786         cstate->retries--;
787         authfailcount--;
788     auth_withpeer_fail(cstate->unit, PPP_CHAP);
789 }
790
791
792 /*
793  * ChapSendChallenge - Send an Authenticate challenge.
794  */
795 static void
796 ChapSendChallenge(cstate)
797     chap_state *cstate;
798 {
799     u_char *outp;
800     int chal_len, name_len;
801     int outlen;
802
803     chal_len = cstate->chal_len;
804     name_len = strlen(cstate->chal_name);
805     outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
806     outp = outpacket_buf;
807
808     MAKEHEADER(outp, PPP_CHAP);         /* paste in a CHAP header */
809
810     PUTCHAR(CHAP_CHALLENGE, outp);
811     PUTCHAR(cstate->chal_id, outp);
812     PUTSHORT(outlen, outp);
813
814     PUTCHAR(chal_len, outp);            /* put length of challenge */
815     BCOPY(cstate->challenge, outp, chal_len);
816     INCPTR(chal_len, outp);
817
818     BCOPY(cstate->chal_name, outp, name_len);   /* append hostname */
819
820     output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
821   
822     TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
823     ++cstate->chal_transmits;
824 }
825
826
827 /*
828  * ChapSendStatus - Send a status response (ack or nak).
829  */
830 static void
831 ChapSendStatus(cstate, code)
832     chap_state *cstate;
833     int code;
834 {
835     u_char *outp;
836     int outlen, msglen;
837     char msg[256];
838
839     /*wilson modify for MS-CHAPv2, 05/26/2005*/
840     if (code == CHAP_SUCCESS)
841         slprintf(msg, sizeof(msg), "Welcome to %s.", hostname);
842     else if(code == CHAP_SUCCESS_R)
843         strcpy(msg, cstate->response);
844     else
845         slprintf(msg, sizeof(msg), "I don't like you.  Go 'way.");
846     /*wilson modify end*/
847     msglen = strlen(msg);
848
849     outlen = CHAP_HEADERLEN + msglen;
850     outp = outpacket_buf;
851
852     MAKEHEADER(outp, PPP_CHAP); /* paste in a header */
853   
854     /*wilson modify for MS-CHAPv2, 05/26/2005*/
855     PUTCHAR(code == CHAP_SUCCESS_R ? CHAP_SUCCESS : code, outp);
856     //PUTCHAR(code, outp);
857     /*wilson modify end*/
858     PUTCHAR(cstate->chal_id, outp);
859     PUTSHORT(outlen, outp);
860     BCOPY(msg, outp, msglen);
861     output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
862 }
863
864 /*
865  * ChapGenChallenge is used to generate a pseudo-random challenge string of
866  * a pseudo-random length between min_len and max_len.  The challenge
867  * string and its length are stored in *cstate, and various other fields of
868  * *cstate are initialized.
869  */
870
871 //static void   /*wilson modify for MS-CHAPv2, 05/26/2005*/
872 void
873 ChapGenChallenge(cstate)
874     chap_state *cstate;
875 {
876     int chal_len;
877     u_char *ptr = cstate->challenge;
878     int i;
879
880 /*wilson modify for MS-CHAPv2, 05/26/2005*/
881 #ifdef CHAPMS
882     if(cstate->chal_type == CHAP_MICROSOFT)
883         chal_len = 8;
884     else if(cstate->chal_type == CHAP_MICROSOFT_V2)
885         chal_len = 16;
886     else
887 #endif
888 /*wilson modify end*/
889     /* pick a random challenge length between MIN_CHALLENGE_LENGTH and 
890        MAX_CHALLENGE_LENGTH */  
891     chal_len =  (unsigned) ((drand48() *
892                              (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) +
893                             MIN_CHALLENGE_LENGTH);
894     cstate->chal_len = chal_len;
895     cstate->chal_id = ++cstate->id;
896     cstate->chal_transmits = 0;
897
898     /* generate a random string */
899     for (i = 0; i < chal_len; i++)
900         *ptr++ = (char) (drand48() * 0xff);
901 }
902
903 /*
904  * ChapSendResponse - send a response packet with values as specified
905  * in *cstate.
906  */
907 /* ARGSUSED */
908 static void
909 ChapSendResponse(cstate)
910     chap_state *cstate;
911 {
912     u_char *outp;
913     int outlen, md_len, name_len;
914
915     md_len = cstate->resp_length;
916     name_len = strlen(cstate->resp_name);
917     outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
918     outp = outpacket_buf;
919
920     MAKEHEADER(outp, PPP_CHAP);
921
922     PUTCHAR(CHAP_RESPONSE, outp);       /* we are a response */
923     PUTCHAR(cstate->resp_id, outp);     /* copy id from challenge packet */
924     PUTSHORT(outlen, outp);             /* packet length */
925
926     PUTCHAR(md_len, outp);              /* length of MD */
927     BCOPY(cstate->response, outp, md_len);      /* copy MD to buffer */
928     INCPTR(md_len, outp);
929
930     BCOPY(cstate->resp_name, outp, name_len); /* append our name */
931
932     /* send the packet */
933     output(cstate->unit, outpacket_buf, outlen + PPP_HDRLEN);
934
935     cstate->clientstate = CHAPCS_RESPONSE;
936     TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
937     ++cstate->resp_transmits;
938 }
939
940 /*
941  * ChapPrintPkt - print the contents of a CHAP packet.
942  */
943 static char *ChapCodenames[] = {
944     "Challenge", "Response", "Success", "Failure"
945 };
946
947 static int
948 ChapPrintPkt(p, plen, printer, arg)
949     u_char *p;
950     int plen;
951     void (*printer) __P((void *, char *, ...));
952     void *arg;
953 {
954     int code, id, len;
955     int clen, nlen;
956     u_char x;
957
958     if (plen < CHAP_HEADERLEN)
959         return 0;
960     GETCHAR(code, p);
961     GETCHAR(id, p);
962     GETSHORT(len, p);
963     if (len < CHAP_HEADERLEN || len > plen)
964         return 0;
965
966     if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *))
967         printer(arg, " %s", ChapCodenames[code-1]);
968     else
969         printer(arg, " code=0x%x", code);
970     printer(arg, " id=0x%x", id);
971     len -= CHAP_HEADERLEN;
972     switch (code) {
973     case CHAP_CHALLENGE:
974     case CHAP_RESPONSE:
975         if (len < 1)
976             break;
977         clen = p[0];
978         if (len < clen + 1)
979             break;
980         ++p;
981         nlen = len - clen - 1;
982         printer(arg, " <");
983         for (; clen > 0; --clen) {
984             GETCHAR(x, p);
985             printer(arg, "%.2x", x);
986         }
987         printer(arg, ">, name = ");
988         print_string((char *)p, nlen, printer, arg);
989         break;
990     case CHAP_FAILURE:
991     case CHAP_SUCCESS:
992         printer(arg, " ");
993         print_string((char *)p, len, printer, arg);
994         break;
995     default:
996         for (clen = len; clen > 0; --clen) {
997             GETCHAR(x, p);
998             printer(arg, " %.2x", x);
999         }
1000     }
1001
1002     return len + CHAP_HEADERLEN;
1003 }
1004
1005 /*wilson add for MS-CHAPv2, 05/26/2005*/
1006 int
1007 reqchap(argv)
1008          char **argv;
1009 {
1010      lcp_wantoptions[0].neg_chap = 1;
1011      lcp_wantoptions[0].use_digest = 1;
1012      auth_required = 1;
1013      return 1;
1014 }
1015 /*wilson add end*/
1016