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