OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rtems-20020807/] [c/] [src/] [libnetworking/] [pppd/] [chap.c] - Blame information for rev 1780

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.