chap.c revision 68461
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 68461 2000-11-07 23:19:11Z 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);    /* XXX Global ! */
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    MPPE_IsServer = 0;		/* XXX Global ! */
375#endif
376    free(ans);
377  } else
378    ChapOutput(chap->auth.physical, CHAP_FAILURE, chap->auth.id,
379               "Out of memory!", 14, NULL);
380}
381
382static int
383chap_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
384{
385  struct chap *chap = descriptor2chap(d);
386
387  if (r && chap && chap->child.fd != -1) {
388    FD_SET(chap->child.fd, r);
389    if (*n < chap->child.fd + 1)
390      *n = chap->child.fd + 1;
391    log_Printf(LogTIMER, "Chap: fdset(r) %d\n", chap->child.fd);
392    return 1;
393  }
394
395  return 0;
396}
397
398static int
399chap_IsSet(struct fdescriptor *d, const fd_set *fdset)
400{
401  struct chap *chap = descriptor2chap(d);
402
403  return chap && chap->child.fd != -1 && FD_ISSET(chap->child.fd, fdset);
404}
405
406static void
407chap_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
408{
409  struct chap *chap = descriptor2chap(d);
410  int got;
411
412  got = read(chap->child.fd, chap->child.buf.ptr + chap->child.buf.len,
413             sizeof chap->child.buf.ptr - chap->child.buf.len - 1);
414  if (got == -1) {
415    log_Printf(LogERROR, "Chap: Read: %s\n", strerror(errno));
416    chap_Cleanup(chap, SIGTERM);
417  } else if (got == 0) {
418    log_Printf(LogWARN, "Chap: Read: Child terminated connection\n");
419    chap_Cleanup(chap, SIGTERM);
420  } else {
421    char *name, *key, *end;
422
423    chap->child.buf.len += got;
424    chap->child.buf.ptr[chap->child.buf.len] = '\0';
425    name = chap->child.buf.ptr;
426    name += strspn(name, " \t");
427    if ((key = strchr(name, '\n')) == NULL)
428      end = NULL;
429    else
430      end = strchr(++key, '\n');
431
432    if (end == NULL) {
433      if (chap->child.buf.len == sizeof chap->child.buf.ptr - 1) {
434        log_Printf(LogWARN, "Chap: Read: Input buffer overflow\n");
435        chap_Cleanup(chap, SIGTERM);
436      }
437    } else {
438#ifdef HAVE_DES
439      int lanman = chap->auth.physical->link.lcp.his_authtype == 0x80 &&
440                   ((chap->NTRespSent &&
441                     IsAccepted(chap->auth.physical->link.lcp.cfg.chap80lm)) ||
442                    !IsAccepted(chap->auth.physical->link.lcp.cfg.chap80nt));
443#endif
444
445      while (end >= name && strchr(" \t\r\n", *end))
446        *end-- = '\0';
447      end = key - 1;
448      while (end >= name && strchr(" \t\r\n", *end))
449        *end-- = '\0';
450      key += strspn(key, " \t");
451
452      chap_Respond(chap, name, key, chap->auth.physical->link.lcp.his_authtype
453#ifdef HAVE_DES
454                   , lanman
455#endif
456                  );
457      chap_Cleanup(chap, 0);
458    }
459  }
460}
461
462static int
463chap_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
464{
465  /* We never want to write here ! */
466  log_Printf(LogALERT, "chap_Write: Internal error: Bad call !\n");
467  return 0;
468}
469
470static void
471chap_ChallengeInit(struct authinfo *authp)
472{
473  struct chap *chap = auth2chap(authp);
474  int len, i;
475  char *cp;
476
477  len = strlen(authp->physical->dl->bundle->cfg.auth.name);
478
479  if (!*chap->challenge.local) {
480    randinit();
481    cp = chap->challenge.local;
482
483#ifndef NORADIUS
484    if (*authp->physical->dl->bundle->radius.cfg.file) {
485      /* For radius, our challenge is 16 readable NUL terminated bytes :*/
486      *cp++ = 16;
487      for (i = 0; i < 16; i++)
488        *cp++ = (random() % 10) + '0';
489    } else
490#endif
491    {
492#ifdef HAVE_DES
493      if (authp->physical->link.lcp.want_authtype == 0x80)
494        *cp++ = 8;	/* MS does 8 byte callenges :-/ */
495      else if (authp->physical->link.lcp.want_authtype == 0x81)
496        *cp++ = 16;	/* MS-CHAP-V2 does 16 bytes challenges */
497      else
498#endif
499        *cp++ = random() % (CHAPCHALLENGELEN-16) + 16;
500      for (i = 0; i < *chap->challenge.local; i++)
501        *cp++ = random() & 0xff;
502    }
503    memcpy(cp, authp->physical->dl->bundle->cfg.auth.name, len);
504  }
505}
506
507static void
508chap_Challenge(struct authinfo *authp)
509{
510  struct chap *chap = auth2chap(authp);
511  int len;
512
513  log_Printf(LogDEBUG, "CHAP%02X: Challenge\n",
514             authp->physical->link.lcp.want_authtype);
515
516  len = strlen(authp->physical->dl->bundle->cfg.auth.name);
517
518  /* Generate new local challenge value */
519  if (!*chap->challenge.local)
520    chap_ChallengeInit(authp);
521
522#ifdef HAVE_DES
523  if (authp->physical->link.lcp.want_authtype == 0x81)
524    ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id,
525             chap->challenge.local, 1 + *chap->challenge.local, NULL);
526  else
527#endif
528    ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id,
529             chap->challenge.local, 1 + *chap->challenge.local + len, NULL);
530}
531
532static void
533chap_Success(struct authinfo *authp)
534{
535  const char *msg;
536  datalink_GotAuthname(authp->physical->dl, authp->in.name);
537#ifdef HAVE_DES
538  if (authp->physical->link.lcp.want_authtype == 0x81) {
539    msg = auth2chap(authp)->authresponse;
540    MPPE_MasterKeyValid = 1;		/* XXX Global ! */
541  } else
542#endif
543    msg = "Welcome!!";
544
545  ChapOutput(authp->physical, CHAP_SUCCESS, authp->id, msg, strlen(msg) + 1,
546             NULL);
547
548  authp->physical->link.lcp.auth_ineed = 0;
549  if (Enabled(authp->physical->dl->bundle, OPT_UTMP))
550    physical_Login(authp->physical, authp->in.name);
551
552  if (authp->physical->link.lcp.auth_iwait == 0)
553    /*
554     * Either I didn't need to authenticate, or I've already been
555     * told that I got the answer right.
556     */
557    datalink_AuthOk(authp->physical->dl);
558}
559
560static void
561chap_Failure(struct authinfo *authp)
562{
563#ifdef HAVE_DES
564  char buf[1024];
565#endif
566  const char *msg;
567
568#ifdef HAVE_DES
569  if (authp->physical->link.lcp.want_authtype == 0x81) {
570    char *ptr;
571    int i;
572
573    ptr = buf;
574    ptr += sprintf(buf, "E=691 R=0 C=");
575    for (i=0; i<16; i++)
576      ptr += sprintf(ptr, "%02X", *(auth2chap(authp)->challenge.local+1+i));
577
578    sprintf(ptr, " V=3 M=Invalid!");
579    msg = buf;
580  } else
581#endif
582    msg = "Invalid!!";
583
584  ChapOutput(authp->physical, CHAP_FAILURE, authp->id, msg, strlen(msg) + 1,
585             NULL);
586  datalink_AuthNotOk(authp->physical->dl);
587}
588
589static int
590chap_Cmp(u_char type, char *myans, int mylen, char *hisans, int hislen
591#ifdef HAVE_DES
592         , int lm
593#endif
594        )
595{
596  if (mylen != hislen)
597    return 0;
598#ifdef HAVE_DES
599  else if (type == 0x80) {
600    int off = lm ? 0 : 24;
601
602    if (memcmp(myans + off, hisans + off, 24))
603      return 0;
604  }
605#endif
606  else if (memcmp(myans, hisans, mylen))
607    return 0;
608
609  return 1;
610}
611
612#ifdef HAVE_DES
613static int
614chap_HaveAnotherGo(struct chap *chap)
615{
616  if (++chap->peertries < 3) {
617    /* Give the peer another shot */
618    *chap->challenge.local = '\0';
619    chap_Challenge(&chap->auth);
620    return 1;
621  }
622
623  return 0;
624}
625#endif
626
627void
628chap_Init(struct chap *chap, struct physical *p)
629{
630  chap->desc.type = CHAP_DESCRIPTOR;
631  chap->desc.UpdateSet = chap_UpdateSet;
632  chap->desc.IsSet = chap_IsSet;
633  chap->desc.Read = chap_Read;
634  chap->desc.Write = chap_Write;
635  chap->child.pid = 0;
636  chap->child.fd = -1;
637  auth_Init(&chap->auth, p, chap_Challenge, chap_Success, chap_Failure);
638  *chap->challenge.local = *chap->challenge.peer = '\0';
639#ifdef HAVE_DES
640  chap->NTRespSent = 0;
641  chap->peertries = 0;
642#endif
643}
644
645void
646chap_ReInit(struct chap *chap)
647{
648  chap_Cleanup(chap, SIGTERM);
649}
650
651struct mbuf *
652chap_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
653{
654  struct physical *p = link2physical(l);
655  struct chap *chap = &p->dl->chap;
656  char *name, *key, *ans;
657  int len, nlen;
658  u_char alen;
659#ifdef HAVE_DES
660  int lanman;
661#endif
662
663  if (p == NULL) {
664    log_Printf(LogERROR, "chap_Input: Not a physical link - dropped\n");
665    m_freem(bp);
666    return NULL;
667  }
668
669  if (bundle_Phase(bundle) != PHASE_NETWORK &&
670      bundle_Phase(bundle) != PHASE_AUTHENTICATE) {
671    log_Printf(LogPHASE, "Unexpected chap input - dropped !\n");
672    m_freem(bp);
673    return NULL;
674  }
675
676  m_settype(bp, MB_CHAPIN);
677  if ((bp = auth_ReadHeader(&chap->auth, bp)) == NULL &&
678      ntohs(chap->auth.in.hdr.length) == 0)
679    log_Printf(LogWARN, "Chap Input: Truncated header !\n");
680  else if (chap->auth.in.hdr.code == 0 || chap->auth.in.hdr.code > MAXCHAPCODE)
681    log_Printf(LogPHASE, "Chap Input: %d: Bad CHAP code !\n",
682               chap->auth.in.hdr.code);
683  else {
684    len = m_length(bp);
685    ans = NULL;
686
687    if (chap->auth.in.hdr.code != CHAP_CHALLENGE &&
688        chap->auth.id != chap->auth.in.hdr.id &&
689        Enabled(bundle, OPT_IDCHECK)) {
690      /* Wrong conversation dude ! */
691      log_Printf(LogPHASE, "Chap Input: %s dropped (got id %d, not %d)\n",
692                 chapcodes[chap->auth.in.hdr.code], chap->auth.in.hdr.id,
693                 chap->auth.id);
694      m_freem(bp);
695      return NULL;
696    }
697    chap->auth.id = chap->auth.in.hdr.id;	/* We respond with this id */
698
699#ifdef HAVE_DES
700    lanman = 0;
701#endif
702    switch (chap->auth.in.hdr.code) {
703      case CHAP_CHALLENGE:
704        bp = mbuf_Read(bp, &alen, 1);
705        len -= alen + 1;
706        if (len < 0) {
707          log_Printf(LogERROR, "Chap Input: Truncated challenge !\n");
708          m_freem(bp);
709          return NULL;
710        }
711        *chap->challenge.peer = alen;
712        bp = mbuf_Read(bp, chap->challenge.peer + 1, alen);
713        bp = auth_ReadName(&chap->auth, bp, len);
714#ifdef HAVE_DES
715        lanman = p->link.lcp.his_authtype == 0x80 &&
716                 ((chap->NTRespSent && IsAccepted(p->link.lcp.cfg.chap80lm)) ||
717                  !IsAccepted(p->link.lcp.cfg.chap80nt));
718
719        /* Generate local challenge value */
720        chap_ChallengeInit(&chap->auth);
721#endif
722        break;
723
724      case CHAP_RESPONSE:
725        auth_StopTimer(&chap->auth);
726        bp = mbuf_Read(bp, &alen, 1);
727        len -= alen + 1;
728        if (len < 0) {
729          log_Printf(LogERROR, "Chap Input: Truncated response !\n");
730          m_freem(bp);
731          return NULL;
732        }
733        if ((ans = malloc(alen + 2)) == NULL) {
734          log_Printf(LogERROR, "Chap Input: Out of memory !\n");
735          m_freem(bp);
736          return NULL;
737        }
738        *ans = chap->auth.id;
739        bp = mbuf_Read(bp, ans + 1, alen);
740        ans[alen+1] = '\0';
741        bp = auth_ReadName(&chap->auth, bp, len);
742#ifdef HAVE_DES
743        lanman = p->link.lcp.want_authtype == 0x80 &&
744                 alen == 49 && ans[alen] == 0;
745#endif
746        break;
747
748      case CHAP_SUCCESS:
749      case CHAP_FAILURE:
750        /* chap->auth.in.name is already set up at CHALLENGE time */
751        if ((ans = malloc(len + 1)) == NULL) {
752          log_Printf(LogERROR, "Chap Input: Out of memory !\n");
753          m_freem(bp);
754          return NULL;
755        }
756        bp = mbuf_Read(bp, ans, len);
757        ans[len] = '\0';
758        break;
759    }
760
761    switch (chap->auth.in.hdr.code) {
762      case CHAP_CHALLENGE:
763      case CHAP_RESPONSE:
764        if (*chap->auth.in.name)
765          log_Printf(LogPHASE, "Chap Input: %s (%d bytes from %s%s)\n",
766                     chapcodes[chap->auth.in.hdr.code], alen,
767                     chap->auth.in.name,
768#ifdef HAVE_DES
769                     lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
770                     " - lanman" :
771#endif
772                     "");
773        else
774          log_Printf(LogPHASE, "Chap Input: %s (%d bytes%s)\n",
775                     chapcodes[chap->auth.in.hdr.code], alen,
776#ifdef HAVE_DES
777                     lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
778                     " - lanman" :
779#endif
780                     "");
781        break;
782
783      case CHAP_SUCCESS:
784      case CHAP_FAILURE:
785        if (*ans)
786          log_Printf(LogPHASE, "Chap Input: %s (%s)\n",
787                     chapcodes[chap->auth.in.hdr.code], ans);
788        else
789          log_Printf(LogPHASE, "Chap Input: %s\n",
790                     chapcodes[chap->auth.in.hdr.code]);
791        break;
792    }
793
794    switch (chap->auth.in.hdr.code) {
795      case CHAP_CHALLENGE:
796        if (*bundle->cfg.auth.key == '!' && bundle->cfg.auth.key[1] != '!')
797          chap_StartChild(chap, bundle->cfg.auth.key + 1,
798                          bundle->cfg.auth.name);
799        else
800          chap_Respond(chap, bundle->cfg.auth.name, bundle->cfg.auth.key +
801                       (*bundle->cfg.auth.key == '!' ? 1 : 0),
802                       p->link.lcp.his_authtype
803#ifdef HAVE_DES
804                       , lanman
805#endif
806                      );
807        break;
808
809      case CHAP_RESPONSE:
810        name = chap->auth.in.name;
811        nlen = strlen(name);
812#ifndef NORADIUS
813        if (*bundle->radius.cfg.file) {
814          u_char end;
815
816          end = chap->challenge.local[*chap->challenge.local+1];
817          chap->challenge.local[*chap->challenge.local+1] = '\0';
818          radius_Authenticate(&bundle->radius, &chap->auth,
819                              chap->auth.in.name, ans,
820                              chap->challenge.local + 1);
821          chap->challenge.local[*chap->challenge.local+1] = end;
822        } else
823#endif
824        {
825          key = auth_GetSecret(bundle, name, nlen, p);
826          if (key) {
827            char *myans;
828#ifdef HAVE_DES
829            if (p->link.lcp.want_authtype == 0x80 &&
830                lanman && !IsEnabled(p->link.lcp.cfg.chap80lm)) {
831              log_Printf(LogPHASE, "Auth failure: LANMan not enabled\n");
832              if (chap_HaveAnotherGo(chap))
833                break;
834              key = NULL;
835            } else if (p->link.lcp.want_authtype == 0x80 &&
836                !lanman && !IsEnabled(p->link.lcp.cfg.chap80nt)) {
837              log_Printf(LogPHASE, "Auth failure: mschap not enabled\n");
838              if (chap_HaveAnotherGo(chap))
839                break;
840              key = NULL;
841            } else if (p->link.lcp.want_authtype == 0x81 &&
842                !IsEnabled(p->link.lcp.cfg.chap81)) {
843              log_Printf(LogPHASE, "Auth failure: CHAP81 not enabled\n");
844              key = NULL;
845            } else
846#endif
847            {
848#ifdef HAVE_DES
849              /* Get peer's challenge */
850              if (p->link.lcp.want_authtype == 0x81) {
851                chap->challenge.peer[0] = CHAP81_CHALLENGE_LEN;
852                memcpy(chap->challenge.peer + 1, ans + 1, CHAP81_CHALLENGE_LEN);
853              }
854#endif
855
856              myans = chap_BuildAnswer(name, key, chap->auth.id,
857                                       chap->challenge.local,
858                                       p->link.lcp.want_authtype
859#ifdef HAVE_DES
860                                       , chap->challenge.peer,
861                                       chap->authresponse, lanman);
862              MPPE_IsServer = 1;		/* XXX Global ! */
863#else
864                                      );
865#endif
866              if (myans == NULL)
867                key = NULL;
868              else {
869                if (!chap_Cmp(p->link.lcp.want_authtype, myans + 1, *myans,
870                              ans + 1, alen
871#ifdef HAVE_DES
872                              , lanman
873#endif
874                             ))
875                  key = NULL;
876                free(myans);
877              }
878            }
879          }
880
881          if (key)
882            chap_Success(&chap->auth);
883          else
884            chap_Failure(&chap->auth);
885        }
886
887        break;
888
889      case CHAP_SUCCESS:
890        if (p->link.lcp.auth_iwait == PROTO_CHAP) {
891          p->link.lcp.auth_iwait = 0;
892          if (p->link.lcp.auth_ineed == 0) {
893#ifdef HAVE_DES
894            if (p->link.lcp.his_authtype == 0x81) {
895              if (strncmp(ans, chap->authresponse, 42)) {
896                datalink_AuthNotOk(p->dl);
897	        log_Printf(LogDEBUG, "CHAP81: AuthenticatorResponse: (%s)"
898                           " != ans: (%s)\n", chap->authresponse, ans);
899
900              } else {
901                /* Successful login */
902                MPPE_MasterKeyValid = 1;		/* XXX Global ! */
903                datalink_AuthOk(p->dl);
904              }
905            } else
906#endif
907            /*
908             * We've succeeded in our ``login''
909             * If we're not expecting  the peer to authenticate (or he already
910             * has), proceed to network phase.
911             */
912            datalink_AuthOk(p->dl);
913          }
914        }
915        break;
916
917      case CHAP_FAILURE:
918        datalink_AuthNotOk(p->dl);
919        break;
920    }
921    free(ans);
922  }
923
924  m_freem(bp);
925  return NULL;
926}
927