chap.c revision 67910
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 67910 2000-10-30 00:15:04Z 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", authp->physical->link.lcp.want_authtype);
513
514  len = strlen(authp->physical->dl->bundle->cfg.auth.name);
515
516  /* Generate new local challenge value */
517  if (!*chap->challenge.local)
518    chap_ChallengeInit(authp);
519
520#ifdef HAVE_DES
521  if (authp->physical->link.lcp.want_authtype == 0x81)
522    ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id,
523             chap->challenge.local, 1 + *chap->challenge.local, NULL);
524  else
525#endif
526    ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id,
527             chap->challenge.local, 1 + *chap->challenge.local + len, NULL);
528}
529
530static void
531chap_Success(struct authinfo *authp)
532{
533  char *msg;
534  datalink_GotAuthname(authp->physical->dl, authp->in.name);
535#ifdef HAVE_DES
536  if (authp->physical->link.lcp.want_authtype == 0x81) {
537    msg = auth2chap(authp)->authresponse;
538    MPPE_MasterKeyValid = 1;
539  } else
540#endif
541    msg = "Welcome!!";
542
543  ChapOutput(authp->physical, CHAP_SUCCESS, authp->id, msg, strlen(msg) + 1,
544             NULL);
545
546  authp->physical->link.lcp.auth_ineed = 0;
547  if (Enabled(authp->physical->dl->bundle, OPT_UTMP))
548    physical_Login(authp->physical, authp->in.name);
549
550  if (authp->physical->link.lcp.auth_iwait == 0)
551    /*
552     * Either I didn't need to authenticate, or I've already been
553     * told that I got the answer right.
554     */
555    datalink_AuthOk(authp->physical->dl);
556}
557
558static void
559chap_Failure(struct authinfo *authp)
560{
561#ifdef HAVE_DES
562  char buf[1024];
563#endif
564  char *msg;
565
566#ifdef HAVE_DES
567  if (authp->physical->link.lcp.want_authtype == 0x81) {
568    int i;
569
570    msg = buf;
571    msg += sprintf(buf, "E=691 R=0 C=");
572    for (i=0; i<16; i++)
573      msg += sprintf(msg, "%02X", *(auth2chap(authp)->challenge.local+1+i));
574
575    sprintf(msg, " V=3 M=Invalid!");
576    msg = buf;
577  } else
578#endif
579    msg = "Invalid!!";
580
581  ChapOutput(authp->physical, CHAP_FAILURE, authp->id, msg, strlen(msg) + 1,
582             NULL);
583  datalink_AuthNotOk(authp->physical->dl);
584}
585
586static int
587chap_Cmp(u_char type, char *myans, int mylen, char *hisans, int hislen
588#ifdef HAVE_DES
589         , int lm
590#endif
591        )
592{
593  if (mylen != hislen)
594    return 0;
595#ifdef HAVE_DES
596  else if (type == 0x80) {
597    int off = lm ? 0 : 24;
598
599    if (memcmp(myans + off, hisans + off, 24))
600      return 0;
601  }
602#endif
603  else if (memcmp(myans, hisans, mylen))
604    return 0;
605
606  return 1;
607}
608
609#ifdef HAVE_DES
610static int
611chap_HaveAnotherGo(struct chap *chap)
612{
613  if (++chap->peertries < 3) {
614    /* Give the peer another shot */
615    *chap->challenge.local = '\0';
616    chap_Challenge(&chap->auth);
617    return 1;
618  }
619
620  return 0;
621}
622#endif
623
624void
625chap_Init(struct chap *chap, struct physical *p)
626{
627  chap->desc.type = CHAP_DESCRIPTOR;
628  chap->desc.UpdateSet = chap_UpdateSet;
629  chap->desc.IsSet = chap_IsSet;
630  chap->desc.Read = chap_Read;
631  chap->desc.Write = chap_Write;
632  chap->child.pid = 0;
633  chap->child.fd = -1;
634  auth_Init(&chap->auth, p, chap_Challenge, chap_Success, chap_Failure);
635  *chap->challenge.local = *chap->challenge.peer = '\0';
636#ifdef HAVE_DES
637  chap->NTRespSent = 0;
638  chap->peertries = 0;
639#endif
640}
641
642void
643chap_ReInit(struct chap *chap)
644{
645  chap_Cleanup(chap, SIGTERM);
646}
647
648struct mbuf *
649chap_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
650{
651  struct physical *p = link2physical(l);
652  struct chap *chap = &p->dl->chap;
653  char *name, *key, *ans;
654  int len, nlen;
655  u_char alen;
656#ifdef HAVE_DES
657  int lanman;
658#endif
659
660  if (p == NULL) {
661    log_Printf(LogERROR, "chap_Input: Not a physical link - dropped\n");
662    m_freem(bp);
663    return NULL;
664  }
665
666  if (bundle_Phase(bundle) != PHASE_NETWORK &&
667      bundle_Phase(bundle) != PHASE_AUTHENTICATE) {
668    log_Printf(LogPHASE, "Unexpected chap input - dropped !\n");
669    m_freem(bp);
670    return NULL;
671  }
672
673  m_settype(bp, MB_CHAPIN);
674  if ((bp = auth_ReadHeader(&chap->auth, bp)) == NULL &&
675      ntohs(chap->auth.in.hdr.length) == 0)
676    log_Printf(LogWARN, "Chap Input: Truncated header !\n");
677  else if (chap->auth.in.hdr.code == 0 || chap->auth.in.hdr.code > MAXCHAPCODE)
678    log_Printf(LogPHASE, "Chap Input: %d: Bad CHAP code !\n",
679               chap->auth.in.hdr.code);
680  else {
681    len = m_length(bp);
682    ans = NULL;
683
684    if (chap->auth.in.hdr.code != CHAP_CHALLENGE &&
685        chap->auth.id != chap->auth.in.hdr.id &&
686        Enabled(bundle, OPT_IDCHECK)) {
687      /* Wrong conversation dude ! */
688      log_Printf(LogPHASE, "Chap Input: %s dropped (got id %d, not %d)\n",
689                 chapcodes[chap->auth.in.hdr.code], chap->auth.in.hdr.id,
690                 chap->auth.id);
691      m_freem(bp);
692      return NULL;
693    }
694    chap->auth.id = chap->auth.in.hdr.id;	/* We respond with this id */
695
696#ifdef HAVE_DES
697    lanman = 0;
698#endif
699    switch (chap->auth.in.hdr.code) {
700      case CHAP_CHALLENGE:
701        bp = mbuf_Read(bp, &alen, 1);
702        len -= alen + 1;
703        if (len < 0) {
704          log_Printf(LogERROR, "Chap Input: Truncated challenge !\n");
705          m_freem(bp);
706          return NULL;
707        }
708        *chap->challenge.peer = alen;
709        bp = mbuf_Read(bp, chap->challenge.peer + 1, alen);
710        bp = auth_ReadName(&chap->auth, bp, len);
711#ifdef HAVE_DES
712        lanman = p->link.lcp.his_authtype == 0x80 &&
713                 ((chap->NTRespSent && IsAccepted(p->link.lcp.cfg.chap80lm)) ||
714                  !IsAccepted(p->link.lcp.cfg.chap80nt));
715
716        /* Generate local challenge value */
717        chap_ChallengeInit(&chap->auth);
718#endif
719        break;
720
721      case CHAP_RESPONSE:
722        auth_StopTimer(&chap->auth);
723        bp = mbuf_Read(bp, &alen, 1);
724        len -= alen + 1;
725        if (len < 0) {
726          log_Printf(LogERROR, "Chap Input: Truncated response !\n");
727          m_freem(bp);
728          return NULL;
729        }
730        if ((ans = malloc(alen + 2)) == NULL) {
731          log_Printf(LogERROR, "Chap Input: Out of memory !\n");
732          m_freem(bp);
733          return NULL;
734        }
735        *ans = chap->auth.id;
736        bp = mbuf_Read(bp, ans + 1, alen);
737        ans[alen+1] = '\0';
738        bp = auth_ReadName(&chap->auth, bp, len);
739#ifdef HAVE_DES
740        lanman = p->link.lcp.want_authtype == 0x80 &&
741                 alen == 49 && ans[alen] == 0;
742#endif
743        break;
744
745      case CHAP_SUCCESS:
746      case CHAP_FAILURE:
747        /* chap->auth.in.name is already set up at CHALLENGE time */
748        if ((ans = malloc(len + 1)) == NULL) {
749          log_Printf(LogERROR, "Chap Input: Out of memory !\n");
750          m_freem(bp);
751          return NULL;
752        }
753        bp = mbuf_Read(bp, ans, len);
754        ans[len] = '\0';
755        break;
756    }
757
758    switch (chap->auth.in.hdr.code) {
759      case CHAP_CHALLENGE:
760      case CHAP_RESPONSE:
761        if (*chap->auth.in.name)
762          log_Printf(LogPHASE, "Chap Input: %s (%d bytes from %s%s)\n",
763                     chapcodes[chap->auth.in.hdr.code], alen,
764                     chap->auth.in.name,
765#ifdef HAVE_DES
766                     lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
767                     " - lanman" :
768#endif
769                     "");
770        else
771          log_Printf(LogPHASE, "Chap Input: %s (%d bytes%s)\n",
772                     chapcodes[chap->auth.in.hdr.code], alen,
773#ifdef HAVE_DES
774                     lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
775                     " - lanman" :
776#endif
777                     "");
778        break;
779
780      case CHAP_SUCCESS:
781      case CHAP_FAILURE:
782        if (*ans)
783          log_Printf(LogPHASE, "Chap Input: %s (%s)\n",
784                     chapcodes[chap->auth.in.hdr.code], ans);
785        else
786          log_Printf(LogPHASE, "Chap Input: %s\n",
787                     chapcodes[chap->auth.in.hdr.code]);
788        break;
789    }
790
791    switch (chap->auth.in.hdr.code) {
792      case CHAP_CHALLENGE:
793        if (*bundle->cfg.auth.key == '!' && bundle->cfg.auth.key[1] != '!')
794          chap_StartChild(chap, bundle->cfg.auth.key + 1,
795                          bundle->cfg.auth.name);
796        else
797          chap_Respond(chap, bundle->cfg.auth.name, bundle->cfg.auth.key +
798                       (*bundle->cfg.auth.key == '!' ? 1 : 0),
799                       p->link.lcp.his_authtype
800#ifdef HAVE_DES
801                       , lanman
802#endif
803                      );
804        break;
805
806      case CHAP_RESPONSE:
807        name = chap->auth.in.name;
808        nlen = strlen(name);
809#ifndef NORADIUS
810        if (*bundle->radius.cfg.file) {
811          u_char end;
812
813          end = chap->challenge.local[*chap->challenge.local+1];
814          chap->challenge.local[*chap->challenge.local+1] = '\0';
815          radius_Authenticate(&bundle->radius, &chap->auth,
816                              chap->auth.in.name, ans,
817                              chap->challenge.local + 1);
818          chap->challenge.local[*chap->challenge.local+1] = end;
819        } else
820#endif
821        {
822          key = auth_GetSecret(bundle, name, nlen, p);
823          if (key) {
824            char *myans;
825#ifdef HAVE_DES
826            if (p->link.lcp.want_authtype == 0x80 &&
827                lanman && !IsEnabled(p->link.lcp.cfg.chap80lm)) {
828              log_Printf(LogPHASE, "Auth failure: LANMan not enabled\n");
829              if (chap_HaveAnotherGo(chap))
830                break;
831              key = NULL;
832            } else if (p->link.lcp.want_authtype == 0x80 &&
833                !lanman && !IsEnabled(p->link.lcp.cfg.chap80nt)) {
834              log_Printf(LogPHASE, "Auth failure: mschap not enabled\n");
835              if (chap_HaveAnotherGo(chap))
836                break;
837              key = NULL;
838            } else if (p->link.lcp.want_authtype == 0x81 &&
839                !IsEnabled(p->link.lcp.cfg.chap81)) {
840              log_Printf(LogPHASE, "Auth failure: CHAP81 not enabled\n");
841              key = NULL;
842            } else
843#endif
844            {
845#ifdef HAVE_DES
846              /* Get peer's challenge */
847              if (p->link.lcp.want_authtype == 0x81) {
848                chap->challenge.peer[0] = CHAP81_CHALLENGE_LEN;
849                memcpy(chap->challenge.peer + 1, ans + 1, CHAP81_CHALLENGE_LEN);
850              }
851#endif
852
853              myans = chap_BuildAnswer(name, key, chap->auth.id,
854                                       chap->challenge.local,
855                                       p->link.lcp.want_authtype
856#ifdef HAVE_DES
857                                       , chap->challenge.peer,
858                                       chap->authresponse, lanman
859#endif
860                                      );
861              if (myans == NULL)
862                key = NULL;
863              else {
864                if (!chap_Cmp(p->link.lcp.want_authtype, myans + 1, *myans,
865                              ans + 1, alen
866#ifdef HAVE_DES
867                              , lanman
868#endif
869                             ))
870                  key = NULL;
871                free(myans);
872              }
873            }
874          }
875
876          if (key)
877            chap_Success(&chap->auth);
878          else
879            chap_Failure(&chap->auth);
880        }
881
882        break;
883
884      case CHAP_SUCCESS:
885        if (p->link.lcp.auth_iwait == PROTO_CHAP) {
886          p->link.lcp.auth_iwait = 0;
887          if (p->link.lcp.auth_ineed == 0) {
888#ifdef HAVE_DES
889            if (p->link.lcp.his_authtype == 0x81) {
890              if (strncmp(ans, chap->authresponse, 42)) {
891                datalink_AuthNotOk(p->dl);
892	        log_Printf(LogDEBUG, "CHAP81: AuthenticatorResponse: (%s) != ans: (%s)\n", chap->authresponse, ans);
893
894              } else {
895                /* Successful login */
896                MPPE_MasterKeyValid = 1;
897                datalink_AuthOk(p->dl);
898              }
899            } else
900#endif
901            /*
902             * We've succeeded in our ``login''
903             * If we're not expecting  the peer to authenticate (or he already
904             * has), proceed to network phase.
905             */
906            datalink_AuthOk(p->dl);
907          }
908        }
909        break;
910
911      case CHAP_FAILURE:
912        datalink_AuthNotOk(p->dl);
913        break;
914    }
915    free(ans);
916  }
917
918  m_freem(bp);
919  return NULL;
920}
921