source: rtems/cpukit/pppd/chap.c @ 660db8c8

5
Last change on this file since 660db8c8 was 33a1a4db, checked in by Peng Fan <van.freenix@…>, on 04/05/16 at 12:45:55

cpukit: pppd: fix compile warning

rcsid is defined, but not used. So discard it.

Signed-off-by: Peng Fan <van.freenix@…>

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