]> Joshua Wise's Git repositories - netwatch.git/blob - lwip/src/netif/ppp/chap.c
Rewrap README and GUIDE.
[netwatch.git] / lwip / src / 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 */
This page took 0.07153 seconds and 4 git commands to generate.