source: rtems/cpukit/pppd/chap.c @ 63a88eb

4.104.114.84.95
Last change on this file since 63a88eb was bdf2c0e4, checked in by Ralf Corsepius <ralf.corsepius@…>, on 10/26/05 at 17:40:12

Misc. minor fixes.

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