source: rtems/cpukit/pppd/chap.c @ 0fe48346

4.104.114.84.95
Last change on this file since 0fe48346 was d0950ad, checked in by Joel Sherrill <joel.sherrill@…>, on 11/30/99 at 22:12:50

Added port of ppp-2.3.5 from Tomasz Domin <dot@…> of ComArch? SA.
Tomasz only tested this on the mpc823.

The official site for the original source for this PPP implementation is:

ftp://cs.anu.edu.au/pub/software/ppp

NOTE: As of 11/30/1999, the current version of this source is 2.3.10.

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