chap.c revision 67912
1/*
2 *			PPP CHAP Module
3 *
4 *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
5 *
6 *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
7 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the Internet Initiative Japan, Inc.  The name of the
14 * IIJ may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 * $FreeBSD: head/usr.sbin/ppp/chap.c 67912 2000-10-30 00:15:29Z brian $
21 *
22 *	TODO:
23 */
24#include <sys/param.h>
25#include <netinet/in.h>
26#include <netinet/in_systm.h>
27#include <netinet/ip.h>
28#include <sys/un.h>
29
30#include <errno.h>
31#include <fcntl.h>
32#ifdef HAVE_DES
33#include <md4.h>
34#endif
35#include <md5.h>
36#include <paths.h>
37#include <signal.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <sys/wait.h>
42#include <termios.h>
43#include <unistd.h>
44
45#include "layer.h"
46#include "mbuf.h"
47#include "log.h"
48#include "defs.h"
49#include "timer.h"
50#include "fsm.h"
51#include "proto.h"
52#include "lqr.h"
53#include "hdlc.h"
54#include "lcp.h"
55#include "auth.h"
56#include "async.h"
57#include "throughput.h"
58#include "descriptor.h"
59#include "chap.h"
60#include "iplist.h"
61#include "slcompress.h"
62#include "ipcp.h"
63#include "filter.h"
64#include "ccp.h"
65#include "link.h"
66#include "physical.h"
67#include "mp.h"
68#ifndef NORADIUS
69#include "radius.h"
70#endif
71#include "bundle.h"
72#include "chat.h"
73#include "cbcp.h"
74#include "command.h"
75#include "datalink.h"
76#ifdef HAVE_DES
77#include "chap_ms.h"
78#include "mppe.h"
79#endif
80#include "id.h"
81
82static const char * const chapcodes[] = {
83  "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE"
84};
85#define MAXCHAPCODE (sizeof chapcodes / sizeof chapcodes[0] - 1)
86
87static void
88ChapOutput(struct physical *physical, u_int code, u_int id,
89	   const u_char *ptr, int count, const char *text)
90{
91  int plen;
92  struct fsmheader lh;
93  struct mbuf *bp;
94
95  plen = sizeof(struct fsmheader) + count;
96  lh.code = code;
97  lh.id = id;
98  lh.length = htons(plen);
99  bp = m_get(plen, MB_CHAPOUT);
100  memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
101  if (count)
102    memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count);
103  log_DumpBp(LogDEBUG, "ChapOutput", bp);
104  if (text == NULL)
105    log_Printf(LogPHASE, "Chap Output: %s\n", chapcodes[code]);
106  else
107    log_Printf(LogPHASE, "Chap Output: %s (%s)\n", chapcodes[code], text);
108  link_PushPacket(&physical->link, bp, physical->dl->bundle,
109                  LINK_QUEUES(&physical->link) - 1, PROTO_CHAP);
110}
111
112static char *
113chap_BuildAnswer(char *name, char *key, u_char id, char *challenge, u_char type
114#ifdef HAVE_DES
115                 , char *peerchallenge, char *authresponse, int lanman
116#endif
117                )
118{
119  char *result, *digest;
120  size_t nlen, klen;
121
122  nlen = strlen(name);
123  klen = strlen(key);
124
125#ifdef HAVE_DES
126  if (type == 0x80) {
127    char expkey[AUTHLEN << 2];
128    MD4_CTX MD4context;
129    int f;
130
131    if ((result = malloc(1 + nlen + MS_CHAP_RESPONSE_LEN)) == NULL)
132      return result;
133
134    digest = result;					/* the response */
135    *digest++ = MS_CHAP_RESPONSE_LEN;			/* 49 */
136    memcpy(digest + MS_CHAP_RESPONSE_LEN, name, nlen);
137    if (lanman) {
138      memset(digest + 24, '\0', 25);
139      mschap_LANMan(digest, challenge + 1, key);	/* LANMan response */
140    } else {
141      memset(digest, '\0', 25);
142      digest += 24;
143
144      for (f = 0; f < klen; f++) {
145        expkey[2*f] = key[f];
146        expkey[2*f+1] = '\0';
147      }
148      /*
149       *           -----------
150       * expkey = | k\0e\0y\0 |
151       *           -----------
152       */
153      MD4Init(&MD4context);
154      MD4Update(&MD4context, expkey, klen << 1);
155      MD4Final(digest, &MD4context);
156
157      /*
158       *           ---- -------- ---------------- ------- ------
159       * result = | 49 | LANMan | 16 byte digest | 9 * ? | name |
160       *           ---- -------- ---------------- ------- ------
161       */
162      mschap_NT(digest, challenge + 1);
163    }
164    /*
165     *           ---- -------- ------------- ----- ------
166     *          |    |  struct MS_ChapResponse24  |      |
167     * result = | 49 | LANMan  |  NT digest | 0/1 | name |
168     *           ---- -------- ------------- ----- ------
169     * where only one of LANMan & NT digest are set.
170     */
171  } else if (type == 0x81) {
172    char expkey[AUTHLEN << 2];
173    char pwdhash[CHAP81_HASH_LEN];
174    char pwdhashhash[CHAP81_HASH_LEN];
175    char *ntresponse;
176    int f;
177
178    if ((result = malloc(1 + nlen + CHAP81_RESPONSE_LEN)) == NULL)
179      return result;
180
181    memset(result, 0, 1 + nlen + CHAP81_RESPONSE_LEN);
182
183    digest = result;
184    *digest++ = CHAP81_RESPONSE_LEN;		/* value size */
185
186    /* Copy our challenge */
187    memcpy(digest, peerchallenge + 1, CHAP81_CHALLENGE_LEN);
188
189    /* Expand password to Unicode XXX */
190    for (f = 0; f < klen; f++) {
191      expkey[2*f] = key[f];
192      expkey[2*f+1] = '\0';
193    }
194
195    ntresponse = digest + CHAP81_NTRESPONSE_OFF;
196
197    /* Get some needed hashes */
198    NtPasswordHash(expkey, klen * 2, pwdhash);
199    HashNtPasswordHash(pwdhash, pwdhashhash);
200
201    /* Generate NTRESPONSE to respond on challenge call */
202    GenerateNTResponse(challenge + 1, peerchallenge + 1, name, nlen,
203                       expkey, klen * 2, ntresponse);
204
205    /* Generate MPPE MASTERKEY */
206    GetMasterKey(pwdhashhash, ntresponse, MPPE_MasterKey);
207
208    /* Generate AUTHRESPONSE to verify on auth success */
209    GenerateAuthenticatorResponse(expkey, klen * 2, ntresponse,
210                                  peerchallenge + 1, challenge + 1, name, nlen,
211                                  authresponse);
212
213    authresponse[CHAP81_AUTHRESPONSE_LEN] = 0;
214
215    memcpy(digest + CHAP81_RESPONSE_LEN, name, nlen);
216  } else
217#endif
218  if ((result = malloc(nlen + 17)) != NULL) {
219    /* Normal MD5 stuff */
220    MD5_CTX MD5context;
221
222    digest = result;
223    *digest++ = 16;				/* value size */
224
225    MD5Init(&MD5context);
226    MD5Update(&MD5context, &id, 1);
227    MD5Update(&MD5context, key, klen);
228    MD5Update(&MD5context, challenge + 1, *challenge);
229    MD5Final(digest, &MD5context);
230
231    memcpy(digest + 16, name, nlen);
232    /*
233     *           ---- -------- ------
234     * result = | 16 | digest | name |
235     *           ---- -------- ------
236     */
237  }
238
239  return result;
240}
241
242static void
243chap_StartChild(struct chap *chap, char *prog, const char *name)
244{
245  char *argv[MAXARGS], *nargv[MAXARGS];
246  int argc, fd;
247  int in[2], out[2];
248  pid_t pid;
249
250  if (chap->child.fd != -1) {
251    log_Printf(LogWARN, "Chap: %s: Program already running\n", prog);
252    return;
253  }
254
255  if (pipe(in) == -1) {
256    log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno));
257    return;
258  }
259
260  if (pipe(out) == -1) {
261    log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno));
262    close(in[0]);
263    close(in[1]);
264    return;
265  }
266
267  pid = getpid();
268  switch ((chap->child.pid = fork())) {
269    case -1:
270      log_Printf(LogERROR, "Chap: fork: %s\n", strerror(errno));
271      close(in[0]);
272      close(in[1]);
273      close(out[0]);
274      close(out[1]);
275      chap->child.pid = 0;
276      return;
277
278    case 0:
279      timer_TermService();
280
281      if ((argc = command_Interpret(prog, strlen(prog), argv)) <= 0) {
282        if (argc < 0) {
283          log_Printf(LogWARN, "CHAP: Invalid command syntax\n");
284          _exit(255);
285        }
286        _exit(0);
287      }
288
289      close(in[1]);
290      close(out[0]);
291      if (out[1] == STDIN_FILENO)
292        out[1] = dup(out[1]);
293      dup2(in[0], STDIN_FILENO);
294      dup2(out[1], STDOUT_FILENO);
295      close(STDERR_FILENO);
296      if (open(_PATH_DEVNULL, O_RDWR) != STDERR_FILENO) {
297        log_Printf(LogALERT, "Chap: Failed to open %s: %s\n",
298                  _PATH_DEVNULL, strerror(errno));
299        exit(1);
300      }
301      for (fd = getdtablesize(); fd > STDERR_FILENO; fd--)
302        fcntl(fd, F_SETFD, 1);
303#ifndef NOSUID
304      setuid(ID0realuid());
305#endif
306      command_Expand(nargv, argc, (char const *const *)argv,
307                     chap->auth.physical->dl->bundle, 0, pid);
308      execvp(nargv[0], nargv);
309      printf("exec() of %s failed: %s\n", nargv[0], strerror(errno));
310      _exit(255);
311
312    default:
313      close(in[0]);
314      close(out[1]);
315      chap->child.fd = out[0];
316      chap->child.buf.len = 0;
317      write(in[1], chap->auth.in.name, strlen(chap->auth.in.name));
318      write(in[1], "\n", 1);
319      write(in[1], chap->challenge.peer + 1, *chap->challenge.peer);
320      write(in[1], "\n", 1);
321      write(in[1], name, strlen(name));
322      write(in[1], "\n", 1);
323      close(in[1]);
324      break;
325  }
326}
327
328static void
329chap_Cleanup(struct chap *chap, int sig)
330{
331  if (chap->child.pid) {
332    int status;
333
334    close(chap->child.fd);
335    chap->child.fd = -1;
336    if (sig)
337      kill(chap->child.pid, SIGTERM);
338    chap->child.pid = 0;
339    chap->child.buf.len = 0;
340
341    if (wait(&status) == -1)
342      log_Printf(LogERROR, "Chap: wait: %s\n", strerror(errno));
343    else if (WIFSIGNALED(status))
344      log_Printf(LogWARN, "Chap: Child received signal %d\n", WTERMSIG(status));
345    else if (WIFEXITED(status) && WEXITSTATUS(status))
346      log_Printf(LogERROR, "Chap: Child exited %d\n", WEXITSTATUS(status));
347  }
348  *chap->challenge.local = *chap->challenge.peer = '\0';
349#ifdef HAVE_DES
350  chap->peertries = 0;
351#endif
352}
353
354static void
355chap_Respond(struct chap *chap, char *name, char *key, u_char type
356#ifdef HAVE_DES
357             , int lm
358#endif
359            )
360{
361  u_char *ans;
362
363  ans = chap_BuildAnswer(name, key, chap->auth.id, chap->challenge.peer, type
364#ifdef HAVE_DES
365                         , chap->challenge.local, chap->authresponse, lm
366#endif
367                        );
368
369  if (ans) {
370    ChapOutput(chap->auth.physical, CHAP_RESPONSE, chap->auth.id,
371               ans, *ans + 1 + strlen(name), name);
372#ifdef HAVE_DES
373    chap->NTRespSent = !lm;
374#endif
375    free(ans);
376  } else
377    ChapOutput(chap->auth.physical, CHAP_FAILURE, chap->auth.id,
378               "Out of memory!", 14, NULL);
379}
380
381static int
382chap_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
383{
384  struct chap *chap = descriptor2chap(d);
385
386  if (r && chap && chap->child.fd != -1) {
387    FD_SET(chap->child.fd, r);
388    if (*n < chap->child.fd + 1)
389      *n = chap->child.fd + 1;
390    log_Printf(LogTIMER, "Chap: fdset(r) %d\n", chap->child.fd);
391    return 1;
392  }
393
394  return 0;
395}
396
397static int
398chap_IsSet(struct fdescriptor *d, const fd_set *fdset)
399{
400  struct chap *chap = descriptor2chap(d);
401
402  return chap && chap->child.fd != -1 && FD_ISSET(chap->child.fd, fdset);
403}
404
405static void
406chap_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
407{
408  struct chap *chap = descriptor2chap(d);
409  int got;
410
411  got = read(chap->child.fd, chap->child.buf.ptr + chap->child.buf.len,
412             sizeof chap->child.buf.ptr - chap->child.buf.len - 1);
413  if (got == -1) {
414    log_Printf(LogERROR, "Chap: Read: %s\n", strerror(errno));
415    chap_Cleanup(chap, SIGTERM);
416  } else if (got == 0) {
417    log_Printf(LogWARN, "Chap: Read: Child terminated connection\n");
418    chap_Cleanup(chap, SIGTERM);
419  } else {
420    char *name, *key, *end;
421
422    chap->child.buf.len += got;
423    chap->child.buf.ptr[chap->child.buf.len] = '\0';
424    name = chap->child.buf.ptr;
425    name += strspn(name, " \t");
426    if ((key = strchr(name, '\n')) == NULL)
427      end = NULL;
428    else
429      end = strchr(++key, '\n');
430
431    if (end == NULL) {
432      if (chap->child.buf.len == sizeof chap->child.buf.ptr - 1) {
433        log_Printf(LogWARN, "Chap: Read: Input buffer overflow\n");
434        chap_Cleanup(chap, SIGTERM);
435      }
436    } else {
437#ifdef HAVE_DES
438      int lanman = chap->auth.physical->link.lcp.his_authtype == 0x80 &&
439                   ((chap->NTRespSent &&
440                     IsAccepted(chap->auth.physical->link.lcp.cfg.chap80lm)) ||
441                    !IsAccepted(chap->auth.physical->link.lcp.cfg.chap80nt));
442#endif
443
444      while (end >= name && strchr(" \t\r\n", *end))
445        *end-- = '\0';
446      end = key - 1;
447      while (end >= name && strchr(" \t\r\n", *end))
448        *end-- = '\0';
449      key += strspn(key, " \t");
450
451      chap_Respond(chap, name, key, chap->auth.physical->link.lcp.his_authtype
452#ifdef HAVE_DES
453                   , lanman
454#endif
455                  );
456      chap_Cleanup(chap, 0);
457    }
458  }
459}
460
461static int
462chap_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
463{
464  /* We never want to write here ! */
465  log_Printf(LogALERT, "chap_Write: Internal error: Bad call !\n");
466  return 0;
467}
468
469static void
470chap_ChallengeInit(struct authinfo *authp)
471{
472  struct chap *chap = auth2chap(authp);
473  int len, i;
474  char *cp;
475
476  len = strlen(authp->physical->dl->bundle->cfg.auth.name);
477
478  if (!*chap->challenge.local) {
479    randinit();
480    cp = chap->challenge.local;
481
482#ifndef NORADIUS
483    if (*authp->physical->dl->bundle->radius.cfg.file) {
484      /* For radius, our challenge is 16 readable NUL terminated bytes :*/
485      *cp++ = 16;
486      for (i = 0; i < 16; i++)
487        *cp++ = (random() % 10) + '0';
488    } else
489#endif
490    {
491#ifdef HAVE_DES
492      if (authp->physical->link.lcp.want_authtype == 0x80)
493        *cp++ = 8;	/* MS does 8 byte callenges :-/ */
494      else if (authp->physical->link.lcp.want_authtype == 0x81)
495        *cp++ = 16;	/* MS-CHAP-V2 does 16 bytes challenges */
496      else
497#endif
498        *cp++ = random() % (CHAPCHALLENGELEN-16) + 16;
499      for (i = 0; i < *chap->challenge.local; i++)
500        *cp++ = random() & 0xff;
501    }
502    memcpy(cp, authp->physical->dl->bundle->cfg.auth.name, len);
503  }
504}
505
506static void
507chap_Challenge(struct authinfo *authp)
508{
509  struct chap *chap = auth2chap(authp);
510  int len;
511
512  log_Printf(LogDEBUG, "CHAP%02X: Challenge\n",
513             authp->physical->link.lcp.want_authtype);
514
515  len = strlen(authp->physical->dl->bundle->cfg.auth.name);
516
517  /* Generate new local challenge value */
518  if (!*chap->challenge.local)
519    chap_ChallengeInit(authp);
520
521#ifdef HAVE_DES
522  if (authp->physical->link.lcp.want_authtype == 0x81)
523    ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id,
524             chap->challenge.local, 1 + *chap->challenge.local, NULL);
525  else
526#endif
527    ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id,
528             chap->challenge.local, 1 + *chap->challenge.local + len, NULL);
529}
530
531static void
532chap_Success(struct authinfo *authp)
533{
534  const char *msg;
535  datalink_GotAuthname(authp->physical->dl, authp->in.name);
536#ifdef HAVE_DES
537  if (authp->physical->link.lcp.want_authtype == 0x81) {
538    msg = auth2chap(authp)->authresponse;
539    MPPE_MasterKeyValid = 1;
540  } else
541#endif
542    msg = "Welcome!!";
543
544  ChapOutput(authp->physical, CHAP_SUCCESS, authp->id, msg, strlen(msg) + 1,
545             NULL);
546
547  authp->physical->link.lcp.auth_ineed = 0;
548  if (Enabled(authp->physical->dl->bundle, OPT_UTMP))
549    physical_Login(authp->physical, authp->in.name);
550
551  if (authp->physical->link.lcp.auth_iwait == 0)
552    /*
553     * Either I didn't need to authenticate, or I've already been
554     * told that I got the answer right.
555     */
556    datalink_AuthOk(authp->physical->dl);
557}
558
559static void
560chap_Failure(struct authinfo *authp)
561{
562#ifdef HAVE_DES
563  char buf[1024];
564#endif
565  const char *msg;
566
567#ifdef HAVE_DES
568  if (authp->physical->link.lcp.want_authtype == 0x81) {
569    char *ptr;
570    int i;
571
572    ptr = buf;
573    ptr += sprintf(buf, "E=691 R=0 C=");
574    for (i=0; i<16; i++)
575      ptr += sprintf(ptr, "%02X", *(auth2chap(authp)->challenge.local+1+i));
576
577    sprintf(ptr, " V=3 M=Invalid!");
578    msg = buf;
579  } else
580#endif
581    msg = "Invalid!!";
582
583  ChapOutput(authp->physical, CHAP_FAILURE, authp->id, msg, strlen(msg) + 1,
584             NULL);
585  datalink_AuthNotOk(authp->physical->dl);
586}
587
588static int
589chap_Cmp(u_char type, char *myans, int mylen, char *hisans, int hislen
590#ifdef HAVE_DES
591         , int lm
592#endif
593        )
594{
595  if (mylen != hislen)
596    return 0;
597#ifdef HAVE_DES
598  else if (type == 0x80) {
599    int off = lm ? 0 : 24;
600
601    if (memcmp(myans + off, hisans + off, 24))
602      return 0;
603  }
604#endif
605  else if (memcmp(myans, hisans, mylen))
606    return 0;
607
608  return 1;
609}
610
611#ifdef HAVE_DES
612static int
613chap_HaveAnotherGo(struct chap *chap)
614{
615  if (++chap->peertries < 3) {
616    /* Give the peer another shot */
617    *chap->challenge.local = '\0';
618    chap_Challenge(&chap->auth);
619    return 1;
620  }
621
622  return 0;
623}
624#endif
625
626void
627chap_Init(struct chap *chap, struct physical *p)
628{
629  chap->desc.type = CHAP_DESCRIPTOR;
630  chap->desc.UpdateSet = chap_UpdateSet;
631  chap->desc.IsSet = chap_IsSet;
632  chap->desc.Read = chap_Read;
633  chap->desc.Write = chap_Write;
634  chap->child.pid = 0;
635  chap->child.fd = -1;
636  auth_Init(&chap->auth, p, chap_Challenge, chap_Success, chap_Failure);
637  *chap->challenge.local = *chap->challenge.peer = '\0';
638#ifdef HAVE_DES
639  chap->NTRespSent = 0;
640  chap->peertries = 0;
641#endif
642}
643
644void
645chap_ReInit(struct chap *chap)
646{
647  chap_Cleanup(chap, SIGTERM);
648}
649
650struct mbuf *
651chap_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
652{
653  struct physical *p = link2physical(l);
654  struct chap *chap = &p->dl->chap;
655  char *name, *key, *ans;
656  int len, nlen;
657  u_char alen;
658#ifdef HAVE_DES
659  int lanman;
660#endif
661
662  if (p == NULL) {
663    log_Printf(LogERROR, "chap_Input: Not a physical link - dropped\n");
664    m_freem(bp);
665    return NULL;
666  }
667
668  if (bundle_Phase(bundle) != PHASE_NETWORK &&
669      bundle_Phase(bundle) != PHASE_AUTHENTICATE) {
670    log_Printf(LogPHASE, "Unexpected chap input - dropped !\n");
671    m_freem(bp);
672    return NULL;
673  }
674
675  m_settype(bp, MB_CHAPIN);
676  if ((bp = auth_ReadHeader(&chap->auth, bp)) == NULL &&
677      ntohs(chap->auth.in.hdr.length) == 0)
678    log_Printf(LogWARN, "Chap Input: Truncated header !\n");
679  else if (chap->auth.in.hdr.code == 0 || chap->auth.in.hdr.code > MAXCHAPCODE)
680    log_Printf(LogPHASE, "Chap Input: %d: Bad CHAP code !\n",
681               chap->auth.in.hdr.code);
682  else {
683    len = m_length(bp);
684    ans = NULL;
685
686    if (chap->auth.in.hdr.code != CHAP_CHALLENGE &&
687        chap->auth.id != chap->auth.in.hdr.id &&
688        Enabled(bundle, OPT_IDCHECK)) {
689      /* Wrong conversation dude ! */
690      log_Printf(LogPHASE, "Chap Input: %s dropped (got id %d, not %d)\n",
691                 chapcodes[chap->auth.in.hdr.code], chap->auth.in.hdr.id,
692                 chap->auth.id);
693      m_freem(bp);
694      return NULL;
695    }
696    chap->auth.id = chap->auth.in.hdr.id;	/* We respond with this id */
697
698#ifdef HAVE_DES
699    lanman = 0;
700#endif
701    switch (chap->auth.in.hdr.code) {
702      case CHAP_CHALLENGE:
703        bp = mbuf_Read(bp, &alen, 1);
704        len -= alen + 1;
705        if (len < 0) {
706          log_Printf(LogERROR, "Chap Input: Truncated challenge !\n");
707          m_freem(bp);
708          return NULL;
709        }
710        *chap->challenge.peer = alen;
711        bp = mbuf_Read(bp, chap->challenge.peer + 1, alen);
712        bp = auth_ReadName(&chap->auth, bp, len);
713#ifdef HAVE_DES
714        lanman = p->link.lcp.his_authtype == 0x80 &&
715                 ((chap->NTRespSent && IsAccepted(p->link.lcp.cfg.chap80lm)) ||
716                  !IsAccepted(p->link.lcp.cfg.chap80nt));
717
718        /* Generate local challenge value */
719        chap_ChallengeInit(&chap->auth);
720#endif
721        break;
722
723      case CHAP_RESPONSE:
724        auth_StopTimer(&chap->auth);
725        bp = mbuf_Read(bp, &alen, 1);
726        len -= alen + 1;
727        if (len < 0) {
728          log_Printf(LogERROR, "Chap Input: Truncated response !\n");
729          m_freem(bp);
730          return NULL;
731        }
732        if ((ans = malloc(alen + 2)) == NULL) {
733          log_Printf(LogERROR, "Chap Input: Out of memory !\n");
734          m_freem(bp);
735          return NULL;
736        }
737        *ans = chap->auth.id;
738        bp = mbuf_Read(bp, ans + 1, alen);
739        ans[alen+1] = '\0';
740        bp = auth_ReadName(&chap->auth, bp, len);
741#ifdef HAVE_DES
742        lanman = p->link.lcp.want_authtype == 0x80 &&
743                 alen == 49 && ans[alen] == 0;
744#endif
745        break;
746
747      case CHAP_SUCCESS:
748      case CHAP_FAILURE:
749        /* chap->auth.in.name is already set up at CHALLENGE time */
750        if ((ans = malloc(len + 1)) == NULL) {
751          log_Printf(LogERROR, "Chap Input: Out of memory !\n");
752          m_freem(bp);
753          return NULL;
754        }
755        bp = mbuf_Read(bp, ans, len);
756        ans[len] = '\0';
757        break;
758    }
759
760    switch (chap->auth.in.hdr.code) {
761      case CHAP_CHALLENGE:
762      case CHAP_RESPONSE:
763        if (*chap->auth.in.name)
764          log_Printf(LogPHASE, "Chap Input: %s (%d bytes from %s%s)\n",
765                     chapcodes[chap->auth.in.hdr.code], alen,
766                     chap->auth.in.name,
767#ifdef HAVE_DES
768                     lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
769                     " - lanman" :
770#endif
771                     "");
772        else
773          log_Printf(LogPHASE, "Chap Input: %s (%d bytes%s)\n",
774                     chapcodes[chap->auth.in.hdr.code], alen,
775#ifdef HAVE_DES
776                     lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
777                     " - lanman" :
778#endif
779                     "");
780        break;
781
782      case CHAP_SUCCESS:
783      case CHAP_FAILURE:
784        if (*ans)
785          log_Printf(LogPHASE, "Chap Input: %s (%s)\n",
786                     chapcodes[chap->auth.in.hdr.code], ans);
787        else
788          log_Printf(LogPHASE, "Chap Input: %s\n",
789                     chapcodes[chap->auth.in.hdr.code]);
790        break;
791    }
792
793    switch (chap->auth.in.hdr.code) {
794      case CHAP_CHALLENGE:
795        if (*bundle->cfg.auth.key == '!' && bundle->cfg.auth.key[1] != '!')
796          chap_StartChild(chap, bundle->cfg.auth.key + 1,
797                          bundle->cfg.auth.name);
798        else
799          chap_Respond(chap, bundle->cfg.auth.name, bundle->cfg.auth.key +
800                       (*bundle->cfg.auth.key == '!' ? 1 : 0),
801                       p->link.lcp.his_authtype
802#ifdef HAVE_DES
803                       , lanman
804#endif
805                      );
806        break;
807
808      case CHAP_RESPONSE:
809        name = chap->auth.in.name;
810        nlen = strlen(name);
811#ifndef NORADIUS
812        if (*bundle->radius.cfg.file) {
813          u_char end;
814
815          end = chap->challenge.local[*chap->challenge.local+1];
816          chap->challenge.local[*chap->challenge.local+1] = '\0';
817          radius_Authenticate(&bundle->radius, &chap->auth,
818                              chap->auth.in.name, ans,
819                              chap->challenge.local + 1);
820          chap->challenge.local[*chap->challenge.local+1] = end;
821        } else
822#endif
823        {
824          key = auth_GetSecret(bundle, name, nlen, p);
825          if (key) {
826            char *myans;
827#ifdef HAVE_DES
828            if (p->link.lcp.want_authtype == 0x80 &&
829                lanman && !IsEnabled(p->link.lcp.cfg.chap80lm)) {
830              log_Printf(LogPHASE, "Auth failure: LANMan not enabled\n");
831              if (chap_HaveAnotherGo(chap))
832                break;
833              key = NULL;
834            } else if (p->link.lcp.want_authtype == 0x80 &&
835                !lanman && !IsEnabled(p->link.lcp.cfg.chap80nt)) {
836              log_Printf(LogPHASE, "Auth failure: mschap not enabled\n");
837              if (chap_HaveAnotherGo(chap))
838                break;
839              key = NULL;
840            } else if (p->link.lcp.want_authtype == 0x81 &&
841                !IsEnabled(p->link.lcp.cfg.chap81)) {
842              log_Printf(LogPHASE, "Auth failure: CHAP81 not enabled\n");
843              key = NULL;
844            } else
845#endif
846            {
847#ifdef HAVE_DES
848              /* Get peer's challenge */
849              if (p->link.lcp.want_authtype == 0x81) {
850                chap->challenge.peer[0] = CHAP81_CHALLENGE_LEN;
851                memcpy(chap->challenge.peer + 1, ans + 1, CHAP81_CHALLENGE_LEN);
852              }
853#endif
854
855              myans = chap_BuildAnswer(name, key, chap->auth.id,
856                                       chap->challenge.local,
857                                       p->link.lcp.want_authtype
858#ifdef HAVE_DES
859                                       , chap->challenge.peer,
860                                       chap->authresponse, lanman
861#endif
862                                      );
863              if (myans == NULL)
864                key = NULL;
865              else {
866                if (!chap_Cmp(p->link.lcp.want_authtype, myans + 1, *myans,
867                              ans + 1, alen
868#ifdef HAVE_DES
869                              , lanman
870#endif
871                             ))
872                  key = NULL;
873                free(myans);
874              }
875            }
876          }
877
878          if (key)
879            chap_Success(&chap->auth);
880          else
881            chap_Failure(&chap->auth);
882        }
883
884        break;
885
886      case CHAP_SUCCESS:
887        if (p->link.lcp.auth_iwait == PROTO_CHAP) {
888          p->link.lcp.auth_iwait = 0;
889          if (p->link.lcp.auth_ineed == 0) {
890#ifdef HAVE_DES
891            if (p->link.lcp.his_authtype == 0x81) {
892              if (strncmp(ans, chap->authresponse, 42)) {
893                datalink_AuthNotOk(p->dl);
894	        log_Printf(LogDEBUG, "CHAP81: AuthenticatorResponse: (%s)"
895                           " != ans: (%s)\n", chap->authresponse, ans);
896
897              } else {
898                /* Successful login */
899                MPPE_MasterKeyValid = 1;
900                datalink_AuthOk(p->dl);
901              }
902            } else
903#endif
904            /*
905             * We've succeeded in our ``login''
906             * If we're not expecting  the peer to authenticate (or he already
907             * has), proceed to network phase.
908             */
909            datalink_AuthOk(p->dl);
910          }
911        }
912        break;
913
914      case CHAP_FAILURE:
915        datalink_AuthNotOk(p->dl);
916        break;
917    }
918    free(ans);
919  }
920
921  m_freem(bp);
922  return NULL;
923}
924