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