Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Release 1.0
[palacios.git] / geekos / src / lwip / netif / ppp / chap.c
1 /*** WARNING - THIS HAS NEVER BEEN FINISHED ***/
2 /*****************************************************************************
3 * chap.c - Network Challenge Handshake Authentication Protocol program file.
4 *
5 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
6 * portions Copyright (c) 1997 by Global Election Systems Inc.
7 *
8 * The authors hereby grant permission to use, copy, modify, distribute,
9 * and license this software and its documentation for any purpose, provided
10 * that existing copyright notices are retained in all copies and that this
11 * notice and the following disclaimer are included verbatim in any 
12 * distributions. No written agreement, license, or royalty fee is required
13 * for any of the authorized uses.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 
18 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 ******************************************************************************
27 * REVISION HISTORY
28 *
29 * 03-01-01 Marc Boucher <marc@mbsi.ca>
30 *   Ported to lwIP.
31 * 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.
32 *   Original based on BSD chap.c.
33 *****************************************************************************/
34 /*
35  * chap.c - Challenge Handshake Authentication Protocol.
36  *
37  * Copyright (c) 1993 The Australian National University.
38  * All rights reserved.
39  *
40  * Redistribution and use in source and binary forms are permitted
41  * provided that the above copyright notice and this paragraph are
42  * duplicated in all such forms and that any documentation,
43  * advertising materials, and other materials related to such
44  * distribution and use acknowledge that the software was developed
45  * by the Australian National University.  The name of the University
46  * may not be used to endorse or promote products derived from this
47  * software without specific prior written permission.
48  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
49  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
50  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
51  *
52  * Copyright (c) 1991 Gregory M. Christy.
53  * All rights reserved.
54  *
55  * Redistribution and use in source and binary forms are permitted
56  * provided that the above copyright notice and this paragraph are
57  * duplicated in all such forms and that any documentation,
58  * advertising materials, and other materials related to such
59  * distribution and use acknowledge that the software was developed
60  * by Gregory M. Christy.  The name of the author may not be used to
61  * endorse or promote products derived from this software without
62  * specific prior written permission.
63  *
64  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
65  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
66  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
67  */
68
69 #include "lwip/opt.h"
70
71 #if PPP_SUPPORT  /* don't build if not configured for use in lwipopts.h */
72
73 #if CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
74
75 #include "ppp.h"
76 #include "pppdebug.h"
77
78 #include "magic.h"
79 #include "randm.h"
80 #include "auth.h"
81 #include "md5.h"
82 #include "chap.h"
83 #include "chpms.h"
84
85
86 /*************************/
87 /*** LOCAL DEFINITIONS ***/
88 /*************************/
89
90
91 /************************/
92 /*** LOCAL DATA TYPES ***/
93 /************************/
94
95
96 /***********************************/
97 /*** LOCAL FUNCTION DECLARATIONS ***/
98 /***********************************/
99 /*
100  * Protocol entry points.
101  */
102 static void ChapInit (int);
103 static void ChapLowerUp (int);
104 static void ChapLowerDown (int);
105 static void ChapInput (int, u_char *, int);
106 static void ChapProtocolReject (int);
107 #if 0
108 static int  ChapPrintPkt (u_char *, int, void (*) (void *, char *, ...), void *);
109 #endif
110
111 static void ChapChallengeTimeout (void *);
112 static void ChapResponseTimeout (void *);
113 static void ChapReceiveChallenge (chap_state *, u_char *, int, int);
114 static void ChapRechallenge (void *);
115 static void ChapReceiveResponse (chap_state *, u_char *, int, int);
116 static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len);
117 static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len);
118 static void ChapSendStatus (chap_state *, int);
119 static void ChapSendChallenge (chap_state *);
120 static void ChapSendResponse (chap_state *);
121 static void ChapGenChallenge (chap_state *);
122
123
124 /******************************/
125 /*** PUBLIC DATA STRUCTURES ***/
126 /******************************/
127 chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */
128
129 struct protent chap_protent = {
130   PPP_CHAP,
131   ChapInit,
132   ChapInput,
133   ChapProtocolReject,
134   ChapLowerUp,
135   ChapLowerDown,
136   NULL,
137   NULL,
138 #if 0
139   ChapPrintPkt,
140   NULL,
141 #endif
142   1,
143   "CHAP",
144 #if 0
145   NULL,
146   NULL,
147   NULL
148 #endif
149 };
150
151
152 /***********************************/
153 /*** PUBLIC FUNCTION DEFINITIONS ***/
154 /***********************************/
155 /*
156  * ChapAuthWithPeer - Authenticate us with our peer (start client).
157  *
158  */
159 void
160 ChapAuthWithPeer(int unit, char *our_name, int digest)
161 {
162   chap_state *cstate = &chap[unit];
163
164   cstate->resp_name = our_name;
165   cstate->resp_type = digest;
166
167   if (cstate->clientstate == CHAPCS_INITIAL ||
168       cstate->clientstate == CHAPCS_PENDING) {
169     /* lower layer isn't up - wait until later */
170     cstate->clientstate = CHAPCS_PENDING;
171     return;
172   }
173
174   /*
175    * We get here as a result of LCP coming up.
176    * So even if CHAP was open before, we will 
177    * have to re-authenticate ourselves.
178    */
179   cstate->clientstate = CHAPCS_LISTEN;
180 }
181
182
183 /*
184  * ChapAuthPeer - Authenticate our peer (start server).
185  */
186 void
187 ChapAuthPeer(int unit, char *our_name, int digest)
188 {
189   chap_state *cstate = &chap[unit];
190
191   cstate->chal_name = our_name;
192   cstate->chal_type = digest;
193   
194   if (cstate->serverstate == CHAPSS_INITIAL ||
195       cstate->serverstate == CHAPSS_PENDING) {
196     /* lower layer isn't up - wait until later */
197     cstate->serverstate = CHAPSS_PENDING;
198     return;
199   }
200
201   ChapGenChallenge(cstate);
202   ChapSendChallenge(cstate);    /* crank it up dude! */
203   cstate->serverstate = CHAPSS_INITIAL_CHAL;
204 }
205
206
207 /**********************************/
208 /*** LOCAL FUNCTION DEFINITIONS ***/
209 /**********************************/
210 /*
211  * ChapInit - Initialize a CHAP unit.
212  */
213 static void
214 ChapInit(int unit)
215 {
216   chap_state *cstate = &chap[unit];
217
218   BZERO(cstate, sizeof(*cstate));
219   cstate->unit = unit;
220   cstate->clientstate = CHAPCS_INITIAL;
221   cstate->serverstate = CHAPSS_INITIAL;
222   cstate->timeouttime = CHAP_DEFTIMEOUT;
223   cstate->max_transmits = CHAP_DEFTRANSMITS;
224   /* random number generator is initialized in magic_init */
225 }
226
227
228 /*
229  * ChapChallengeTimeout - Timeout expired on sending challenge.
230  */
231 static void
232 ChapChallengeTimeout(void *arg)
233 {
234   chap_state *cstate = (chap_state *) arg;
235
236   /* if we aren't sending challenges, don't worry.  then again we */
237   /* probably shouldn't be here either */
238   if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&
239       cstate->serverstate != CHAPSS_RECHALLENGE) {
240     return;
241   }
242
243   if (cstate->chal_transmits >= cstate->max_transmits) {
244     /* give up on peer */
245     CHAPDEBUG((LOG_ERR, "Peer failed to respond to CHAP challenge\n"));
246     cstate->serverstate = CHAPSS_BADAUTH;
247     auth_peer_fail(cstate->unit, PPP_CHAP);
248     return;
249   }
250
251   ChapSendChallenge(cstate); /* Re-send challenge */
252 }
253
254
255 /*
256  * ChapResponseTimeout - Timeout expired on sending response.
257  */
258 static void
259 ChapResponseTimeout(void *arg)
260 {
261   chap_state *cstate = (chap_state *) arg;
262
263   /* if we aren't sending a response, don't worry. */
264   if (cstate->clientstate != CHAPCS_RESPONSE) {
265     return;
266   }
267
268   ChapSendResponse(cstate);    /* re-send response */
269 }
270
271
272 /*
273  * ChapRechallenge - Time to challenge the peer again.
274  */
275 static void
276 ChapRechallenge(void *arg)
277 {
278   chap_state *cstate = (chap_state *) arg;
279   
280   /* if we aren't sending a response, don't worry. */
281   if (cstate->serverstate != CHAPSS_OPEN) {
282     return;
283   }
284
285   ChapGenChallenge(cstate);
286   ChapSendChallenge(cstate);
287   cstate->serverstate = CHAPSS_RECHALLENGE;
288 }
289
290
291 /*
292  * ChapLowerUp - The lower layer is up.
293  *
294  * Start up if we have pending requests.
295  */
296 static void
297 ChapLowerUp(int unit)
298 {
299   chap_state *cstate = &chap[unit];
300
301   if (cstate->clientstate == CHAPCS_INITIAL) {
302     cstate->clientstate = CHAPCS_CLOSED;
303   } else if (cstate->clientstate == CHAPCS_PENDING) {
304     cstate->clientstate = CHAPCS_LISTEN;
305   }
306
307   if (cstate->serverstate == CHAPSS_INITIAL) {
308     cstate->serverstate = CHAPSS_CLOSED;
309   } else if (cstate->serverstate == CHAPSS_PENDING) {
310     ChapGenChallenge(cstate);
311     ChapSendChallenge(cstate);
312     cstate->serverstate = CHAPSS_INITIAL_CHAL;
313   }
314 }
315
316
317 /*
318  * ChapLowerDown - The lower layer is down.
319  *
320  * Cancel all timeouts.
321  */
322 static void
323 ChapLowerDown(int unit)
324 {
325   chap_state *cstate = &chap[unit];
326
327   /* Timeout(s) pending?  Cancel if so. */
328   if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||
329       cstate->serverstate == CHAPSS_RECHALLENGE) {
330     UNTIMEOUT(ChapChallengeTimeout, cstate);
331   } else if (cstate->serverstate == CHAPSS_OPEN
332       && cstate->chal_interval != 0) {
333     UNTIMEOUT(ChapRechallenge, cstate);
334   }
335   if (cstate->clientstate == CHAPCS_RESPONSE) {
336     UNTIMEOUT(ChapResponseTimeout, cstate);
337   }
338   cstate->clientstate = CHAPCS_INITIAL;
339   cstate->serverstate = CHAPSS_INITIAL;
340 }
341
342
343 /*
344  * ChapProtocolReject - Peer doesn't grok CHAP.
345  */
346 static void
347 ChapProtocolReject(int unit)
348 {
349   chap_state *cstate = &chap[unit];
350   
351   if (cstate->serverstate != CHAPSS_INITIAL &&
352       cstate->serverstate != CHAPSS_CLOSED) {
353     auth_peer_fail(unit, PPP_CHAP);
354   }
355   if (cstate->clientstate != CHAPCS_INITIAL &&
356       cstate->clientstate != CHAPCS_CLOSED) {
357     auth_withpeer_fail(unit, PPP_CHAP);
358   }
359   ChapLowerDown(unit); /* shutdown chap */
360 }
361
362
363 /*
364  * ChapInput - Input CHAP packet.
365  */
366 static void
367 ChapInput(int unit, u_char *inpacket, int packet_len)
368 {
369   chap_state *cstate = &chap[unit];
370   u_char *inp;
371   u_char code, id;
372   int len;
373   
374   /*
375    * Parse header (code, id and length).
376    * If packet too short, drop it.
377    */
378   inp = inpacket;
379   if (packet_len < CHAP_HEADERLEN) {
380     CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header.\n"));
381     return;
382   }
383   GETCHAR(code, inp);
384   GETCHAR(id, inp);
385   GETSHORT(len, inp);
386   if (len < CHAP_HEADERLEN) {
387     CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length.\n"));
388     return;
389   }
390   if (len > packet_len) {
391     CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet.\n"));
392     return;
393   }
394   len -= CHAP_HEADERLEN;
395   
396   /*
397    * Action depends on code (as in fact it usually does :-).
398    */
399   switch (code) {
400     case CHAP_CHALLENGE:
401       ChapReceiveChallenge(cstate, inp, id, len);
402       break;
403     
404     case CHAP_RESPONSE:
405       ChapReceiveResponse(cstate, inp, id, len);
406       break;
407     
408     case CHAP_FAILURE:
409       ChapReceiveFailure(cstate, inp, id, len);
410       break;
411     
412     case CHAP_SUCCESS:
413       ChapReceiveSuccess(cstate, inp, id, len);
414       break;
415     
416     default:        /* Need code reject? */
417       CHAPDEBUG((LOG_WARNING, "Unknown CHAP code (%d) received.\n", code));
418       break;
419   }
420 }
421
422
423 /*
424  * ChapReceiveChallenge - Receive Challenge and send Response.
425  */
426 static void
427 ChapReceiveChallenge(chap_state *cstate, u_char *inp, int id, int len)
428 {
429   int rchallenge_len;
430   u_char *rchallenge;
431   int secret_len;
432   char secret[MAXSECRETLEN];
433   char rhostname[256];
434   MD5_CTX mdContext;
435   u_char hash[MD5_SIGNATURE_SIZE];
436   
437   CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.\n", id));
438   if (cstate->clientstate == CHAPCS_CLOSED ||
439     cstate->clientstate == CHAPCS_PENDING) {
440     CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d\n",
441          cstate->clientstate));
442     return;
443   }
444
445   if (len < 2) {
446     CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n"));
447     return;
448   }
449
450   GETCHAR(rchallenge_len, inp);
451   len -= sizeof (u_char) + rchallenge_len;  /* now name field length */
452   if (len < 0) {
453     CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n"));
454     return;
455   }
456   rchallenge = inp;
457   INCPTR(rchallenge_len, inp);
458
459   if (len >= sizeof(rhostname)) {
460     len = sizeof(rhostname) - 1;
461   }
462   BCOPY(inp, rhostname, len);
463   rhostname[len] = '\000';
464
465   CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field '%s'\n", rhostname));
466
467   /* Microsoft doesn't send their name back in the PPP packet */
468   if (ppp_settings.remote_name[0] != 0 && (ppp_settings.explicit_remote || rhostname[0] == 0)) {
469     strncpy(rhostname, ppp_settings.remote_name, sizeof(rhostname));
470     rhostname[sizeof(rhostname) - 1] = 0;
471     CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: using '%s' as remote name\n", rhostname));
472   }
473
474   /* get secret for authenticating ourselves with the specified host */
475   if (!get_secret(cstate->unit, cstate->resp_name, rhostname, secret, &secret_len, 0)) {
476     secret_len = 0;    /* assume null secret if can't find one */
477     CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating us to %s\n", rhostname));
478   }
479
480   /* cancel response send timeout if necessary */
481   if (cstate->clientstate == CHAPCS_RESPONSE) {
482     UNTIMEOUT(ChapResponseTimeout, cstate);
483   }
484
485   cstate->resp_id = id;
486   cstate->resp_transmits = 0;
487
488   /*  generate MD based on negotiated type */
489   switch (cstate->resp_type) { 
490
491   case CHAP_DIGEST_MD5:
492     MD5Init(&mdContext);
493     MD5Update(&mdContext, &cstate->resp_id, 1);
494     MD5Update(&mdContext, (u_char*)secret, secret_len);
495     MD5Update(&mdContext, rchallenge, rchallenge_len);
496     MD5Final(hash, &mdContext);
497     BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);
498     cstate->resp_length = MD5_SIGNATURE_SIZE;
499     break;
500   
501 #ifdef CHAPMS
502   case CHAP_MICROSOFT:
503     ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);
504     break;
505 #endif
506
507   default:
508     CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->resp_type));
509     return;
510   }
511
512   BZERO(secret, sizeof(secret));
513   ChapSendResponse(cstate);
514 }
515
516
517 /*
518  * ChapReceiveResponse - Receive and process response.
519  */
520 static void
521 ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len)
522 {
523   u_char *remmd, remmd_len;
524   int secret_len, old_state;
525   int code;
526   char rhostname[256];
527   MD5_CTX mdContext;
528   char secret[MAXSECRETLEN];
529   u_char hash[MD5_SIGNATURE_SIZE];
530   
531   CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.\n", id));
532   
533   if (cstate->serverstate == CHAPSS_CLOSED ||
534       cstate->serverstate == CHAPSS_PENDING) {
535     CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d\n",
536     cstate->serverstate));
537     return;
538   }
539
540   if (id != cstate->chal_id) {
541     return;      /* doesn't match ID of last challenge */
542   }
543
544   /*
545   * If we have received a duplicate or bogus Response,
546   * we have to send the same answer (Success/Failure)
547   * as we did for the first Response we saw.
548   */
549   if (cstate->serverstate == CHAPSS_OPEN) {
550     ChapSendStatus(cstate, CHAP_SUCCESS);
551     return;
552   }
553   if (cstate->serverstate == CHAPSS_BADAUTH) {
554     ChapSendStatus(cstate, CHAP_FAILURE);
555     return;
556   }
557   
558   if (len < 2) {
559     CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n"));
560     return;
561   }
562   GETCHAR(remmd_len, inp); /* get length of MD */
563   remmd = inp;             /* get pointer to MD */
564   INCPTR(remmd_len, inp);
565   
566   len -= sizeof (u_char) + remmd_len;
567   if (len < 0) {
568     CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n"));
569     return;
570   }
571
572   UNTIMEOUT(ChapChallengeTimeout, cstate);
573   
574   if (len >= sizeof(rhostname)) {
575     len = sizeof(rhostname) - 1;
576   }
577   BCOPY(inp, rhostname, len);
578   rhostname[len] = '\000';
579
580   CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s\n", rhostname));
581
582   /*
583   * Get secret for authenticating them with us,
584   * do the hash ourselves, and compare the result.
585   */
586   code = CHAP_FAILURE;
587   if (!get_secret(cstate->unit, rhostname, cstate->chal_name, secret, &secret_len, 1)) {
588     /* CHAPDEBUG((LOG_WARNING, TL_CHAP, "No CHAP secret found for authenticating %s\n", rhostname)); */
589     CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating %s\n",
590     rhostname));
591   } else {
592     /*  generate MD based on negotiated type */
593     switch (cstate->chal_type) {
594
595       case CHAP_DIGEST_MD5:    /* only MD5 is defined for now */
596         if (remmd_len != MD5_SIGNATURE_SIZE) {
597           break;      /* it's not even the right length */
598         }
599         MD5Init(&mdContext);
600         MD5Update(&mdContext, &cstate->chal_id, 1);
601         MD5Update(&mdContext, (u_char*)secret, secret_len);
602         MD5Update(&mdContext, cstate->challenge, cstate->chal_len);
603         MD5Final(hash, &mdContext); 
604         
605         /* compare local and remote MDs and send the appropriate status */
606         if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0) {
607           code = CHAP_SUCCESS;  /* they are the same! */
608         }
609         break;
610       
611       default:
612         CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->chal_type));
613     }
614   }
615   
616   BZERO(secret, sizeof(secret));
617   ChapSendStatus(cstate, code);
618
619   if (code == CHAP_SUCCESS) {
620     old_state = cstate->serverstate;
621     cstate->serverstate = CHAPSS_OPEN;
622     if (old_state == CHAPSS_INITIAL_CHAL) {
623       auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);
624     }
625     if (cstate->chal_interval != 0) {
626       TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);
627     }
628   } else {
629     CHAPDEBUG((LOG_ERR, "CHAP peer authentication failed\n"));
630     cstate->serverstate = CHAPSS_BADAUTH;
631     auth_peer_fail(cstate->unit, PPP_CHAP);
632   }
633 }
634
635 /*
636  * ChapReceiveSuccess - Receive Success
637  */
638 static void
639 ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len)
640 {
641   LWIP_UNUSED_ARG(id);
642   LWIP_UNUSED_ARG(inp);
643
644   CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.\n", id));
645
646   if (cstate->clientstate == CHAPCS_OPEN) {
647     /* presumably an answer to a duplicate response */
648     return;
649   }
650
651   if (cstate->clientstate != CHAPCS_RESPONSE) {
652     /* don't know what this is */
653     CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n", cstate->clientstate));
654     return;
655   }
656   
657   UNTIMEOUT(ChapResponseTimeout, cstate);
658   
659   /*
660    * Print message.
661    */
662   if (len > 0) {
663     PRINTMSG(inp, len);
664   }
665
666   cstate->clientstate = CHAPCS_OPEN;
667
668   auth_withpeer_success(cstate->unit, PPP_CHAP);
669 }
670
671
672 /*
673  * ChapReceiveFailure - Receive failure.
674  */
675 static void
676 ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len)
677 {
678   LWIP_UNUSED_ARG(id);
679   LWIP_UNUSED_ARG(inp);
680
681   CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.\n", id));
682
683   if (cstate->clientstate != CHAPCS_RESPONSE) {
684     /* don't know what this is */
685     CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n", cstate->clientstate));
686     return;
687   }
688
689   UNTIMEOUT(ChapResponseTimeout, cstate);
690
691   /*
692    * Print message.
693    */
694   if (len > 0) {
695     PRINTMSG(inp, len);
696   }
697
698   CHAPDEBUG((LOG_ERR, "CHAP authentication failed\n"));
699   auth_withpeer_fail(cstate->unit, PPP_CHAP);
700 }
701
702
703 /*
704  * ChapSendChallenge - Send an Authenticate challenge.
705  */
706 static void
707 ChapSendChallenge(chap_state *cstate)
708 {
709   u_char *outp;
710   int chal_len, name_len;
711   int outlen;
712   
713   chal_len = cstate->chal_len;
714   name_len = strlen(cstate->chal_name);
715   outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;
716   outp = outpacket_buf[cstate->unit];
717   
718   MAKEHEADER(outp, PPP_CHAP);    /* paste in a CHAP header */
719   
720   PUTCHAR(CHAP_CHALLENGE, outp);
721   PUTCHAR(cstate->chal_id, outp);
722   PUTSHORT(outlen, outp);
723   
724   PUTCHAR(chal_len, outp);    /* put length of challenge */
725   BCOPY(cstate->challenge, outp, chal_len);
726   INCPTR(chal_len, outp);
727   
728   BCOPY(cstate->chal_name, outp, name_len);  /* append hostname */
729   
730   pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
731   
732   CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.\n", cstate->chal_id));
733   
734   TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);
735   ++cstate->chal_transmits;
736 }
737
738
739 /*
740  * ChapSendStatus - Send a status response (ack or nak).
741  */
742 static void
743 ChapSendStatus(chap_state *cstate, int code)
744 {
745   u_char *outp;
746   int outlen, msglen;
747   char msg[256];
748   
749   if (code == CHAP_SUCCESS) {
750     strcpy(msg, "Welcome!");
751   } else {
752     strcpy(msg, "I don't like you.  Go 'way.");
753   }
754   msglen = strlen(msg);
755   
756   outlen = CHAP_HEADERLEN + msglen;
757   outp = outpacket_buf[cstate->unit];
758   
759   MAKEHEADER(outp, PPP_CHAP);    /* paste in a header */
760   
761   PUTCHAR(code, outp);
762   PUTCHAR(cstate->chal_id, outp);
763   PUTSHORT(outlen, outp);
764   BCOPY(msg, outp, msglen);
765   pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
766   
767   CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.\n", code, cstate->chal_id));
768 }
769
770 /*
771  * ChapGenChallenge is used to generate a pseudo-random challenge string of
772  * a pseudo-random length between min_len and max_len.  The challenge
773  * string and its length are stored in *cstate, and various other fields of
774  * *cstate are initialized.
775  */
776
777 static void
778 ChapGenChallenge(chap_state *cstate)
779 {
780   int chal_len;
781   u_char *ptr = cstate->challenge;
782   int i;
783   
784   /* pick a random challenge length between MIN_CHALLENGE_LENGTH and 
785      MAX_CHALLENGE_LENGTH */  
786   chal_len = (unsigned)
787         ((((magic() >> 16) *
788               (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) >> 16)
789            + MIN_CHALLENGE_LENGTH);
790   cstate->chal_len = chal_len;
791   cstate->chal_id = ++cstate->id;
792   cstate->chal_transmits = 0;
793   
794   /* generate a random string */
795   for (i = 0; i < chal_len; i++ ) {
796     *ptr++ = (char) (magic() & 0xff);
797   }
798 }
799
800 /*
801  * ChapSendResponse - send a response packet with values as specified
802  * in *cstate.
803  */
804 /* ARGSUSED */
805 static void
806 ChapSendResponse(chap_state *cstate)
807 {
808   u_char *outp;
809   int outlen, md_len, name_len;
810   
811   md_len = cstate->resp_length;
812   name_len = strlen(cstate->resp_name);
813   outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;
814   outp = outpacket_buf[cstate->unit];
815   
816   MAKEHEADER(outp, PPP_CHAP);
817   
818   PUTCHAR(CHAP_RESPONSE, outp);  /* we are a response */
819   PUTCHAR(cstate->resp_id, outp);  /* copy id from challenge packet */
820   PUTSHORT(outlen, outp);      /* packet length */
821   
822   PUTCHAR(md_len, outp);      /* length of MD */
823   BCOPY(cstate->response, outp, md_len);    /* copy MD to buffer */
824   INCPTR(md_len, outp);
825   
826   BCOPY(cstate->resp_name, outp, name_len);  /* append our name */
827   
828   /* send the packet */
829   pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);
830   
831   cstate->clientstate = CHAPCS_RESPONSE;
832   TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);
833   ++cstate->resp_transmits;
834 }
835
836 #if 0
837 static char *ChapCodenames[] = {
838   "Challenge", "Response", "Success", "Failure"
839 };
840 /*
841  * ChapPrintPkt - print the contents of a CHAP packet.
842  */
843 static int
844 ChapPrintPkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg)
845 {
846   int code, id, len;
847   int clen, nlen;
848   u_char x;
849   
850   if (plen < CHAP_HEADERLEN) {
851     return 0;
852   }
853   GETCHAR(code, p);
854   GETCHAR(id, p);
855   GETSHORT(len, p);
856   if (len < CHAP_HEADERLEN || len > plen) {
857     return 0;
858   }
859   if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *)) {
860     printer(arg, " %s", ChapCodenames[code-1]);
861   } else {
862     printer(arg, " code=0x%x", code);
863   }
864   printer(arg, " id=0x%x", id);
865   len -= CHAP_HEADERLEN;
866   switch (code) {
867     case CHAP_CHALLENGE:
868     case CHAP_RESPONSE:
869       if (len < 1) {
870         break;
871       }
872       clen = p[0];
873       if (len < clen + 1) {
874         break;
875       }
876       ++p;
877       nlen = len - clen - 1;
878       printer(arg, " <");
879       for (; clen > 0; --clen) {
880         GETCHAR(x, p);
881         printer(arg, "%.2x", x);
882       }
883       printer(arg, ">, name = %.*Z", nlen, p);
884       break;
885     case CHAP_FAILURE:
886     case CHAP_SUCCESS:
887       printer(arg, " %.*Z", len, p);
888       break;
889     default:
890       for (clen = len; clen > 0; --clen) {
891         GETCHAR(x, p);
892         printer(arg, " %.2x", x);
893       }
894   }
895
896   return len + CHAP_HEADERLEN;
897 }
898 #endif
899
900 #endif /* CHAP_SUPPORT */
901
902 #endif /* PPP_SUPPORT */