178189Sbrian/*-
2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3330449Seadler *
478189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
578189Sbrian *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
678189Sbrian *                           Internet Initiative Japan, Inc (IIJ)
778189Sbrian * All rights reserved.
86059Samurai *
978189Sbrian * Redistribution and use in source and binary forms, with or without
1078189Sbrian * modification, are permitted provided that the following conditions
1178189Sbrian * are met:
1278189Sbrian * 1. Redistributions of source code must retain the above copyright
1378189Sbrian *    notice, this list of conditions and the following disclaimer.
1478189Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1578189Sbrian *    notice, this list of conditions and the following disclaimer in the
1678189Sbrian *    documentation and/or other materials provided with the distribution.
176059Samurai *
1878189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1978189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2078189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2178189Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2278189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2378189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2478189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2578189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2678189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2778189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2878189Sbrian * SUCH DAMAGE.
296059Samurai *
3050479Speter * $FreeBSD: stable/11/usr.sbin/ppp/chap.c 330449 2018-03-05 07:26:05Z eadler $
316059Samurai */
3278189Sbrian
3343313Sbrian#include <sys/param.h>
3430715Sbrian#include <netinet/in.h>
3536285Sbrian#include <netinet/in_systm.h>
3636285Sbrian#include <netinet/ip.h>
3781634Sbrian#include <sys/socket.h>
3836285Sbrian#include <sys/un.h>
3930715Sbrian
40134789Sbrian#include <ctype.h>
4143888Sbrian#include <errno.h>
4243888Sbrian#include <fcntl.h>
4393418Sbrian#ifndef NODES
4436287Sbrian#include <md4.h>
4537192Sbrian#endif
4630715Sbrian#include <md5.h>
4743888Sbrian#include <paths.h>
4843888Sbrian#include <signal.h>
4949976Sbrian#include <stdio.h>
5030715Sbrian#include <stdlib.h>
5144106Sbrian#include <string.h>
5243888Sbrian#include <sys/wait.h>
5336285Sbrian#include <termios.h>
5443888Sbrian#include <unistd.h>
5529840Sbrian
5646686Sbrian#include "layer.h"
5730715Sbrian#include "mbuf.h"
5830715Sbrian#include "log.h"
5930715Sbrian#include "defs.h"
6030715Sbrian#include "timer.h"
616059Samurai#include "fsm.h"
6246686Sbrian#include "proto.h"
6336285Sbrian#include "lqr.h"
646059Samurai#include "hdlc.h"
6563484Sbrian#include "lcp.h"
666735Samurai#include "auth.h"
6736285Sbrian#include "async.h"
6836285Sbrian#include "throughput.h"
6936285Sbrian#include "descriptor.h"
7043888Sbrian#include "chap.h"
7136285Sbrian#include "iplist.h"
7236285Sbrian#include "slcompress.h"
7381634Sbrian#include "ncpaddr.h"
7436285Sbrian#include "ipcp.h"
7536285Sbrian#include "filter.h"
7636285Sbrian#include "ccp.h"
7736285Sbrian#include "link.h"
7836285Sbrian#include "physical.h"
7936285Sbrian#include "mp.h"
8043313Sbrian#ifndef NORADIUS
8143313Sbrian#include "radius.h"
8243313Sbrian#endif
8381634Sbrian#include "ipv6cp.h"
8481634Sbrian#include "ncp.h"
8536285Sbrian#include "bundle.h"
8636285Sbrian#include "chat.h"
8738174Sbrian#include "cbcp.h"
8843888Sbrian#include "command.h"
8936285Sbrian#include "datalink.h"
9093418Sbrian#ifndef NODES
9136287Sbrian#include "chap_ms.h"
9267910Sbrian#include "mppe.h"
9337192Sbrian#endif
9455253Sbrian#include "id.h"
956059Samurai
9655146Sbrianstatic const char * const chapcodes[] = {
9719866Sphk  "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE"
986059Samurai};
9943693Sbrian#define MAXCHAPCODE (sizeof chapcodes / sizeof chapcodes[0] - 1)
1006059Samurai
10130715Sbrianstatic void
10236285SbrianChapOutput(struct physical *physical, u_int code, u_int id,
10343693Sbrian	   const u_char *ptr, int count, const char *text)
1046059Samurai{
1056059Samurai  int plen;
1066059Samurai  struct fsmheader lh;
1076059Samurai  struct mbuf *bp;
1086059Samurai
10928679Sbrian  plen = sizeof(struct fsmheader) + count;
1106059Samurai  lh.code = code;
1116059Samurai  lh.id = id;
1126059Samurai  lh.length = htons(plen);
11354912Sbrian  bp = m_get(plen, MB_CHAPOUT);
11430715Sbrian  memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
1156059Samurai  if (count)
11630715Sbrian    memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count);
11736285Sbrian  log_DumpBp(LogDEBUG, "ChapOutput", bp);
11837926Sbrian  if (text == NULL)
11937926Sbrian    log_Printf(LogPHASE, "Chap Output: %s\n", chapcodes[code]);
12037926Sbrian  else
12137926Sbrian    log_Printf(LogPHASE, "Chap Output: %s (%s)\n", chapcodes[code], text);
12246686Sbrian  link_PushPacket(&physical->link, bp, physical->dl->bundle,
12350867Sbrian                  LINK_QUEUES(&physical->link) - 1, PROTO_CHAP);
1246059Samurai}
1256059Samurai
12643693Sbrianstatic char *
127134789Sbrianchap_BuildAnswer(char *name, char *key, u_char id, char *challenge
12893418Sbrian#ifndef NODES
129134789Sbrian		 , u_char type, char *peerchallenge, char *authresponse,
130134789Sbrian		 int lanman
13144123Sbrian#endif
13244123Sbrian                )
1336059Samurai{
13443693Sbrian  char *result, *digest;
13543693Sbrian  size_t nlen, klen;
13643693Sbrian
13743693Sbrian  nlen = strlen(name);
13843693Sbrian  klen = strlen(key);
13943693Sbrian
14093418Sbrian#ifndef NODES
14144106Sbrian  if (type == 0x80) {
14243693Sbrian    char expkey[AUTHLEN << 2];
14343693Sbrian    MD4_CTX MD4context;
144134789Sbrian    size_t f;
14543693Sbrian
14643693Sbrian    if ((result = malloc(1 + nlen + MS_CHAP_RESPONSE_LEN)) == NULL)
14743693Sbrian      return result;
14843693Sbrian
14944106Sbrian    digest = result;					/* the response */
15044106Sbrian    *digest++ = MS_CHAP_RESPONSE_LEN;			/* 49 */
15144106Sbrian    memcpy(digest + MS_CHAP_RESPONSE_LEN, name, nlen);
15244106Sbrian    if (lanman) {
15344106Sbrian      memset(digest + 24, '\0', 25);
15444106Sbrian      mschap_LANMan(digest, challenge + 1, key);	/* LANMan response */
15544106Sbrian    } else {
15644106Sbrian      memset(digest, '\0', 25);
15744106Sbrian      digest += 24;
15843693Sbrian
15944106Sbrian      for (f = 0; f < klen; f++) {
16044106Sbrian        expkey[2*f] = key[f];
16144106Sbrian        expkey[2*f+1] = '\0';
16244106Sbrian      }
16344106Sbrian      /*
16444106Sbrian       *           -----------
16544106Sbrian       * expkey = | k\0e\0y\0 |
16644106Sbrian       *           -----------
16744106Sbrian       */
16844106Sbrian      MD4Init(&MD4context);
16944106Sbrian      MD4Update(&MD4context, expkey, klen << 1);
17044106Sbrian      MD4Final(digest, &MD4context);
17144106Sbrian
17244106Sbrian      /*
17344106Sbrian       *           ---- -------- ---------------- ------- ------
17444106Sbrian       * result = | 49 | LANMan | 16 byte digest | 9 * ? | name |
17544106Sbrian       *           ---- -------- ---------------- ------- ------
17644106Sbrian       */
17744106Sbrian      mschap_NT(digest, challenge + 1);
17843693Sbrian    }
17943693Sbrian    /*
18044106Sbrian     *           ---- -------- ------------- ----- ------
18144106Sbrian     *          |    |  struct MS_ChapResponse24  |      |
18244106Sbrian     * result = | 49 | LANMan  |  NT digest | 0/1 | name |
18344106Sbrian     *           ---- -------- ------------- ----- ------
18444106Sbrian     * where only one of LANMan & NT digest are set.
18543693Sbrian     */
18667910Sbrian  } else if (type == 0x81) {
18767910Sbrian    char expkey[AUTHLEN << 2];
18867910Sbrian    char pwdhash[CHAP81_HASH_LEN];
18967910Sbrian    char pwdhashhash[CHAP81_HASH_LEN];
19067910Sbrian    char *ntresponse;
191134789Sbrian    size_t f;
19267910Sbrian
19367910Sbrian    if ((result = malloc(1 + nlen + CHAP81_RESPONSE_LEN)) == NULL)
19467910Sbrian      return result;
19567910Sbrian
19667910Sbrian    memset(result, 0, 1 + nlen + CHAP81_RESPONSE_LEN);
19767910Sbrian
19867910Sbrian    digest = result;
19967910Sbrian    *digest++ = CHAP81_RESPONSE_LEN;		/* value size */
20067910Sbrian
20167910Sbrian    /* Copy our challenge */
20267910Sbrian    memcpy(digest, peerchallenge + 1, CHAP81_CHALLENGE_LEN);
20367910Sbrian
20467910Sbrian    /* Expand password to Unicode XXX */
20567910Sbrian    for (f = 0; f < klen; f++) {
20667910Sbrian      expkey[2*f] = key[f];
20767910Sbrian      expkey[2*f+1] = '\0';
20867910Sbrian    }
20967910Sbrian
21067910Sbrian    ntresponse = digest + CHAP81_NTRESPONSE_OFF;
21167910Sbrian
21267910Sbrian    /* Get some needed hashes */
21367910Sbrian    NtPasswordHash(expkey, klen * 2, pwdhash);
21467910Sbrian    HashNtPasswordHash(pwdhash, pwdhashhash);
21567910Sbrian
21667910Sbrian    /* Generate NTRESPONSE to respond on challenge call */
217134789Sbrian    GenerateNTResponse(challenge + 1, peerchallenge + 1, name,
21867910Sbrian                       expkey, klen * 2, ntresponse);
21967910Sbrian
22067910Sbrian    /* Generate MPPE MASTERKEY */
22168461Sbrian    GetMasterKey(pwdhashhash, ntresponse, MPPE_MasterKey);    /* XXX Global ! */
22267910Sbrian
22367910Sbrian    /* Generate AUTHRESPONSE to verify on auth success */
22498243Sbrian    GenerateAuthenticatorResponse(expkey, klen * 2, ntresponse,
225134789Sbrian                                  peerchallenge + 1, challenge + 1, name,
22667910Sbrian                                  authresponse);
22767910Sbrian
22867910Sbrian    authresponse[CHAP81_AUTHRESPONSE_LEN] = 0;
22967910Sbrian
23067910Sbrian    memcpy(digest + CHAP81_RESPONSE_LEN, name, nlen);
23143693Sbrian  } else
23243693Sbrian#endif
23343693Sbrian  if ((result = malloc(nlen + 17)) != NULL) {
23443693Sbrian    /* Normal MD5 stuff */
23543693Sbrian    MD5_CTX MD5context;
23643693Sbrian
23743693Sbrian    digest = result;
23843693Sbrian    *digest++ = 16;				/* value size */
23943693Sbrian
24043693Sbrian    MD5Init(&MD5context);
24143693Sbrian    MD5Update(&MD5context, &id, 1);
24243693Sbrian    MD5Update(&MD5context, key, klen);
24343693Sbrian    MD5Update(&MD5context, challenge + 1, *challenge);
24443693Sbrian    MD5Final(digest, &MD5context);
24543693Sbrian
24643693Sbrian    memcpy(digest + 16, name, nlen);
24743693Sbrian    /*
24843693Sbrian     *           ---- -------- ------
24943693Sbrian     * result = | 16 | digest | name |
25043693Sbrian     *           ---- -------- ------
25143693Sbrian     */
25243693Sbrian  }
25343693Sbrian
25443693Sbrian  return result;
25543693Sbrian}
25643693Sbrian
25743693Sbrianstatic void
25843888Sbrianchap_StartChild(struct chap *chap, char *prog, const char *name)
25943888Sbrian{
26043888Sbrian  char *argv[MAXARGS], *nargv[MAXARGS];
26143888Sbrian  int argc, fd;
26243888Sbrian  int in[2], out[2];
26347849Sbrian  pid_t pid;
26443888Sbrian
26543888Sbrian  if (chap->child.fd != -1) {
26643888Sbrian    log_Printf(LogWARN, "Chap: %s: Program already running\n", prog);
26743888Sbrian    return;
26843888Sbrian  }
26943888Sbrian
27043888Sbrian  if (pipe(in) == -1) {
27143888Sbrian    log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno));
27243888Sbrian    return;
27343888Sbrian  }
27443888Sbrian
27543888Sbrian  if (pipe(out) == -1) {
27643888Sbrian    log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno));
27743888Sbrian    close(in[0]);
27843888Sbrian    close(in[1]);
27943888Sbrian    return;
28043888Sbrian  }
28143888Sbrian
28247849Sbrian  pid = getpid();
28343888Sbrian  switch ((chap->child.pid = fork())) {
28443888Sbrian    case -1:
28543888Sbrian      log_Printf(LogERROR, "Chap: fork: %s\n", strerror(errno));
28643888Sbrian      close(in[0]);
28743888Sbrian      close(in[1]);
28843888Sbrian      close(out[0]);
28943888Sbrian      close(out[1]);
29043888Sbrian      chap->child.pid = 0;
29143888Sbrian      return;
29243888Sbrian
29343888Sbrian    case 0:
29443888Sbrian      timer_TermService();
29554914Sbrian
29654914Sbrian      if ((argc = command_Interpret(prog, strlen(prog), argv)) <= 0) {
29754914Sbrian        if (argc < 0) {
29854914Sbrian          log_Printf(LogWARN, "CHAP: Invalid command syntax\n");
29954914Sbrian          _exit(255);
30054914Sbrian        }
30154914Sbrian        _exit(0);
30254914Sbrian      }
30354914Sbrian
30443888Sbrian      close(in[1]);
30543888Sbrian      close(out[0]);
30649976Sbrian      if (out[1] == STDIN_FILENO)
30749976Sbrian        out[1] = dup(out[1]);
30843888Sbrian      dup2(in[0], STDIN_FILENO);
30943888Sbrian      dup2(out[1], STDOUT_FILENO);
31049976Sbrian      close(STDERR_FILENO);
31149976Sbrian      if (open(_PATH_DEVNULL, O_RDWR) != STDERR_FILENO) {
31243888Sbrian        log_Printf(LogALERT, "Chap: Failed to open %s: %s\n",
31343888Sbrian                  _PATH_DEVNULL, strerror(errno));
31443888Sbrian        exit(1);
31543888Sbrian      }
31649976Sbrian      for (fd = getdtablesize(); fd > STDERR_FILENO; fd--)
31749976Sbrian        fcntl(fd, F_SETFD, 1);
31864802Sbrian#ifndef NOSUID
31955252Sbrian      setuid(ID0realuid());
32064802Sbrian#endif
32143888Sbrian      command_Expand(nargv, argc, (char const *const *)argv,
32247849Sbrian                     chap->auth.physical->dl->bundle, 0, pid);
32343888Sbrian      execvp(nargv[0], nargv);
32449976Sbrian      printf("exec() of %s failed: %s\n", nargv[0], strerror(errno));
32549976Sbrian      _exit(255);
32643888Sbrian
32743888Sbrian    default:
32843888Sbrian      close(in[0]);
32943888Sbrian      close(out[1]);
33043888Sbrian      chap->child.fd = out[0];
33143888Sbrian      chap->child.buf.len = 0;
33243888Sbrian      write(in[1], chap->auth.in.name, strlen(chap->auth.in.name));
33343888Sbrian      write(in[1], "\n", 1);
33445907Sbrian      write(in[1], chap->challenge.peer + 1, *chap->challenge.peer);
33543888Sbrian      write(in[1], "\n", 1);
33643888Sbrian      write(in[1], name, strlen(name));
33743888Sbrian      write(in[1], "\n", 1);
33843888Sbrian      close(in[1]);
33943888Sbrian      break;
34043888Sbrian  }
34143888Sbrian}
34243888Sbrian
34343888Sbrianstatic void
34443888Sbrianchap_Cleanup(struct chap *chap, int sig)
34543888Sbrian{
34643888Sbrian  if (chap->child.pid) {
34743888Sbrian    int status;
34843888Sbrian
34943888Sbrian    close(chap->child.fd);
35043888Sbrian    chap->child.fd = -1;
35143888Sbrian    if (sig)
35243888Sbrian      kill(chap->child.pid, SIGTERM);
35343888Sbrian    chap->child.pid = 0;
35443888Sbrian    chap->child.buf.len = 0;
35543888Sbrian
35643888Sbrian    if (wait(&status) == -1)
35743888Sbrian      log_Printf(LogERROR, "Chap: wait: %s\n", strerror(errno));
35843888Sbrian    else if (WIFSIGNALED(status))
35943888Sbrian      log_Printf(LogWARN, "Chap: Child received signal %d\n", WTERMSIG(status));
36043888Sbrian    else if (WIFEXITED(status) && WEXITSTATUS(status))
36143888Sbrian      log_Printf(LogERROR, "Chap: Child exited %d\n", WEXITSTATUS(status));
36243888Sbrian  }
36345907Sbrian  *chap->challenge.local = *chap->challenge.peer = '\0';
36493418Sbrian#ifndef NODES
36544106Sbrian  chap->peertries = 0;
36644123Sbrian#endif
36743888Sbrian}
36843888Sbrian
36943888Sbrianstatic void
370134789Sbrianchap_Respond(struct chap *chap, char *name, char *key
37193418Sbrian#ifndef NODES
372134789Sbrian             , u_char type, int lm
37344123Sbrian#endif
37444123Sbrian            )
37543888Sbrian{
37644106Sbrian  u_char *ans;
37743888Sbrian
378134789Sbrian  ans = chap_BuildAnswer(name, key, chap->auth.id, chap->challenge.peer
37993418Sbrian#ifndef NODES
380134789Sbrian                         , type, chap->challenge.local, chap->authresponse, lm
38144123Sbrian#endif
38244123Sbrian                        );
38343888Sbrian
38443888Sbrian  if (ans) {
38543888Sbrian    ChapOutput(chap->auth.physical, CHAP_RESPONSE, chap->auth.id,
38643888Sbrian               ans, *ans + 1 + strlen(name), name);
38793418Sbrian#ifndef NODES
38844106Sbrian    chap->NTRespSent = !lm;
38968461Sbrian    MPPE_IsServer = 0;		/* XXX Global ! */
39044123Sbrian#endif
39143888Sbrian    free(ans);
39243888Sbrian  } else
39343888Sbrian    ChapOutput(chap->auth.physical, CHAP_FAILURE, chap->auth.id,
39443888Sbrian               "Out of memory!", 14, NULL);
39543888Sbrian}
39643888Sbrian
39743888Sbrianstatic int
398134789Sbrianchap_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w __unused,
399134789Sbrian	       fd_set *e __unused, int *n)
40043888Sbrian{
40143888Sbrian  struct chap *chap = descriptor2chap(d);
40243888Sbrian
40343888Sbrian  if (r && chap && chap->child.fd != -1) {
40443888Sbrian    FD_SET(chap->child.fd, r);
40543888Sbrian    if (*n < chap->child.fd + 1)
40643888Sbrian      *n = chap->child.fd + 1;
40743888Sbrian    log_Printf(LogTIMER, "Chap: fdset(r) %d\n", chap->child.fd);
40843888Sbrian    return 1;
40943888Sbrian  }
41043888Sbrian
41143888Sbrian  return 0;
41243888Sbrian}
41343888Sbrian
41443888Sbrianstatic int
41558028Sbrianchap_IsSet(struct fdescriptor *d, const fd_set *fdset)
41643888Sbrian{
41743888Sbrian  struct chap *chap = descriptor2chap(d);
41843888Sbrian
41943888Sbrian  return chap && chap->child.fd != -1 && FD_ISSET(chap->child.fd, fdset);
42043888Sbrian}
42143888Sbrian
42243888Sbrianstatic void
423134789Sbrianchap_Read(struct fdescriptor *d, struct bundle *bundle __unused,
424134789Sbrian	  const fd_set *fdset __unused)
42543888Sbrian{
42643888Sbrian  struct chap *chap = descriptor2chap(d);
42743888Sbrian  int got;
42843888Sbrian
42943888Sbrian  got = read(chap->child.fd, chap->child.buf.ptr + chap->child.buf.len,
43043888Sbrian             sizeof chap->child.buf.ptr - chap->child.buf.len - 1);
43143888Sbrian  if (got == -1) {
43243888Sbrian    log_Printf(LogERROR, "Chap: Read: %s\n", strerror(errno));
43343888Sbrian    chap_Cleanup(chap, SIGTERM);
43443888Sbrian  } else if (got == 0) {
43543888Sbrian    log_Printf(LogWARN, "Chap: Read: Child terminated connection\n");
43643888Sbrian    chap_Cleanup(chap, SIGTERM);
43743888Sbrian  } else {
43843888Sbrian    char *name, *key, *end;
43943888Sbrian
44043888Sbrian    chap->child.buf.len += got;
44143888Sbrian    chap->child.buf.ptr[chap->child.buf.len] = '\0';
44243888Sbrian    name = chap->child.buf.ptr;
44343888Sbrian    name += strspn(name, " \t");
44443888Sbrian    if ((key = strchr(name, '\n')) == NULL)
44543888Sbrian      end = NULL;
44643888Sbrian    else
44743888Sbrian      end = strchr(++key, '\n');
44843888Sbrian
44943888Sbrian    if (end == NULL) {
45043888Sbrian      if (chap->child.buf.len == sizeof chap->child.buf.ptr - 1) {
45143888Sbrian        log_Printf(LogWARN, "Chap: Read: Input buffer overflow\n");
45243888Sbrian        chap_Cleanup(chap, SIGTERM);
45343888Sbrian      }
45443888Sbrian    } else {
45593418Sbrian#ifndef NODES
45644106Sbrian      int lanman = chap->auth.physical->link.lcp.his_authtype == 0x80 &&
45744106Sbrian                   ((chap->NTRespSent &&
45844106Sbrian                     IsAccepted(chap->auth.physical->link.lcp.cfg.chap80lm)) ||
45944106Sbrian                    !IsAccepted(chap->auth.physical->link.lcp.cfg.chap80nt));
46044123Sbrian#endif
46144106Sbrian
46243888Sbrian      while (end >= name && strchr(" \t\r\n", *end))
46343888Sbrian        *end-- = '\0';
46443888Sbrian      end = key - 1;
46543888Sbrian      while (end >= name && strchr(" \t\r\n", *end))
46643888Sbrian        *end-- = '\0';
46743888Sbrian      key += strspn(key, " \t");
46843888Sbrian
469134789Sbrian      chap_Respond(chap, name, key
47093418Sbrian#ifndef NODES
471134789Sbrian                   , chap->auth.physical->link.lcp.his_authtype, lanman
47244123Sbrian#endif
47344123Sbrian                  );
47443888Sbrian      chap_Cleanup(chap, 0);
47543888Sbrian    }
47643888Sbrian  }
47743888Sbrian}
47843888Sbrian
47943888Sbrianstatic int
480134789Sbrianchap_Write(struct fdescriptor *d __unused, struct bundle *bundle __unused,
481134789Sbrian	   const fd_set *fdset __unused)
48243888Sbrian{
48343888Sbrian  /* We never want to write here ! */
48443888Sbrian  log_Printf(LogALERT, "chap_Write: Internal error: Bad call !\n");
48543888Sbrian  return 0;
48643888Sbrian}
48743888Sbrian
48843888Sbrianstatic void
48967910Sbrianchap_ChallengeInit(struct authinfo *authp)
49043693Sbrian{
49143693Sbrian  struct chap *chap = auth2chap(authp);
49213379Sphk  int len, i;
4936059Samurai  char *cp;
4946059Samurai
49543888Sbrian  len = strlen(authp->physical->dl->bundle->cfg.auth.name);
49643401Sbrian
49745907Sbrian  if (!*chap->challenge.local) {
49843888Sbrian    randinit();
49945907Sbrian    cp = chap->challenge.local;
50043888Sbrian
50143313Sbrian#ifndef NORADIUS
50243888Sbrian    if (*authp->physical->dl->bundle->radius.cfg.file) {
50343888Sbrian      /* For radius, our challenge is 16 readable NUL terminated bytes :*/
50443888Sbrian      *cp++ = 16;
50543888Sbrian      for (i = 0; i < 16; i++)
50643888Sbrian        *cp++ = (random() % 10) + '0';
50743888Sbrian    } else
50843313Sbrian#endif
50943888Sbrian    {
51093418Sbrian#ifndef NODES
51144106Sbrian      if (authp->physical->link.lcp.want_authtype == 0x80)
51244106Sbrian        *cp++ = 8;	/* MS does 8 byte callenges :-/ */
51367910Sbrian      else if (authp->physical->link.lcp.want_authtype == 0x81)
51467910Sbrian        *cp++ = 16;	/* MS-CHAP-V2 does 16 bytes challenges */
51544106Sbrian      else
51644106Sbrian#endif
51744106Sbrian        *cp++ = random() % (CHAPCHALLENGELEN-16) + 16;
51845907Sbrian      for (i = 0; i < *chap->challenge.local; i++)
51943888Sbrian        *cp++ = random() & 0xff;
52043888Sbrian    }
52143888Sbrian    memcpy(cp, authp->physical->dl->bundle->cfg.auth.name, len);
52243313Sbrian  }
5236059Samurai}
5246059Samurai
52530715Sbrianstatic void
52667910Sbrianchap_Challenge(struct authinfo *authp)
52767910Sbrian{
52867910Sbrian  struct chap *chap = auth2chap(authp);
52967910Sbrian  int len;
53067910Sbrian
53167912Sbrian  log_Printf(LogDEBUG, "CHAP%02X: Challenge\n",
53267912Sbrian             authp->physical->link.lcp.want_authtype);
53367910Sbrian
53467910Sbrian  len = strlen(authp->physical->dl->bundle->cfg.auth.name);
53567910Sbrian
53667910Sbrian  /* Generate new local challenge value */
53767910Sbrian  if (!*chap->challenge.local)
53867910Sbrian    chap_ChallengeInit(authp);
53967910Sbrian
54093418Sbrian#ifndef NODES
54167910Sbrian  if (authp->physical->link.lcp.want_authtype == 0x81)
54267910Sbrian    ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id,
54367910Sbrian             chap->challenge.local, 1 + *chap->challenge.local, NULL);
54467910Sbrian  else
54567910Sbrian#endif
54667910Sbrian    ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id,
54767910Sbrian             chap->challenge.local, 1 + *chap->challenge.local + len, NULL);
54867910Sbrian}
54967910Sbrian
55067910Sbrianstatic void
55143693Sbrianchap_Success(struct authinfo *authp)
5526059Samurai{
55396324Sbrian  struct bundle *bundle = authp->physical->dl->bundle;
55467912Sbrian  const char *msg;
55596324Sbrian
55643693Sbrian  datalink_GotAuthname(authp->physical->dl, authp->in.name);
55793418Sbrian#ifndef NODES
55867910Sbrian  if (authp->physical->link.lcp.want_authtype == 0x81) {
55996730Sbrian#ifndef NORADIUS
56096730Sbrian    if (*bundle->radius.cfg.file && bundle->radius.msrepstr)
56196730Sbrian      msg = bundle->radius.msrepstr;
56296730Sbrian    else
56396731Sbrian#endif
56496730Sbrian      msg = auth2chap(authp)->authresponse;
56568461Sbrian    MPPE_MasterKeyValid = 1;		/* XXX Global ! */
56667910Sbrian  } else
56767910Sbrian#endif
56896324Sbrian#ifndef NORADIUS
56996324Sbrian  if (*bundle->radius.cfg.file && bundle->radius.repstr)
57096324Sbrian    msg = bundle->radius.repstr;
57196324Sbrian  else
57296324Sbrian#endif
57367910Sbrian    msg = "Welcome!!";
57467910Sbrian
57580763Sbrian  ChapOutput(authp->physical, CHAP_SUCCESS, authp->id, msg, strlen(msg),
57667910Sbrian             NULL);
57767910Sbrian
57843693Sbrian  authp->physical->link.lcp.auth_ineed = 0;
57996324Sbrian  if (Enabled(bundle, OPT_UTMP))
58043693Sbrian    physical_Login(authp->physical, authp->in.name);
5816059Samurai
58243693Sbrian  if (authp->physical->link.lcp.auth_iwait == 0)
58343693Sbrian    /*
58443693Sbrian     * Either I didn't need to authenticate, or I've already been
58543693Sbrian     * told that I got the answer right.
58643693Sbrian     */
58743693Sbrian    datalink_AuthOk(authp->physical->dl);
58843693Sbrian}
5896059Samurai
59043693Sbrianstatic void
59143693Sbrianchap_Failure(struct authinfo *authp)
59243693Sbrian{
59393418Sbrian#ifndef NODES
59496324Sbrian  char buf[1024], *ptr;
59567910Sbrian#endif
59667912Sbrian  const char *msg;
59767910Sbrian
59896324Sbrian#ifndef NORADIUS
59996324Sbrian  struct bundle *bundle = authp->physical->link.lcp.fsm.bundle;
60096324Sbrian  if (*bundle->radius.cfg.file && bundle->radius.errstr)
60196324Sbrian    msg = bundle->radius.errstr;
60296324Sbrian  else
60396324Sbrian#endif
60493418Sbrian#ifndef NODES
60596324Sbrian  if (authp->physical->link.lcp.want_authtype == 0x80) {
60696324Sbrian    sprintf(buf, "E=691 R=1 M=Invalid!");
60796324Sbrian    msg = buf;
60896324Sbrian  } else if (authp->physical->link.lcp.want_authtype == 0x81) {
60967910Sbrian    int i;
61067910Sbrian
61167912Sbrian    ptr = buf;
61267912Sbrian    ptr += sprintf(buf, "E=691 R=0 C=");
61367910Sbrian    for (i=0; i<16; i++)
61467912Sbrian      ptr += sprintf(ptr, "%02X", *(auth2chap(authp)->challenge.local+1+i));
61598243Sbrian
61667912Sbrian    sprintf(ptr, " V=3 M=Invalid!");
61767910Sbrian    msg = buf;
61867910Sbrian  } else
61967910Sbrian#endif
62067910Sbrian    msg = "Invalid!!";
62167910Sbrian
62267910Sbrian  ChapOutput(authp->physical, CHAP_FAILURE, authp->id, msg, strlen(msg) + 1,
62367910Sbrian             NULL);
62443693Sbrian  datalink_AuthNotOk(authp->physical->dl);
62543693Sbrian}
62637926Sbrian
62744106Sbrianstatic int
628134789Sbrianchap_Cmp(char *myans, int mylen, char *hisans, int hislen
62993418Sbrian#ifndef NODES
630134789Sbrian         , u_char type, int lm
63144123Sbrian#endif
63244123Sbrian        )
63344106Sbrian{
634122440Sbrian  int off;
635122440Sbrian
63644106Sbrian  if (mylen != hislen)
63744106Sbrian    return 0;
638122440Sbrian
639122440Sbrian  off = 0;
640122440Sbrian
64193418Sbrian#ifndef NODES
642122440Sbrian  if (type == 0x80) {
643122440Sbrian    off = lm ? 0 : 24;
644122440Sbrian    mylen = 24;
64544123Sbrian  }
64644123Sbrian#endif
64744106Sbrian
648122440Sbrian  for (; mylen; off++, mylen--)
649122440Sbrian    if (toupper(myans[off]) != toupper(hisans[off]))
650122440Sbrian      return 0;
651122440Sbrian
65244106Sbrian  return 1;
65344106Sbrian}
65444106Sbrian
65593418Sbrian#ifndef NODES
65644106Sbrianstatic int
65744106Sbrianchap_HaveAnotherGo(struct chap *chap)
65844106Sbrian{
65944106Sbrian  if (++chap->peertries < 3) {
66044106Sbrian    /* Give the peer another shot */
66145907Sbrian    *chap->challenge.local = '\0';
66244106Sbrian    chap_Challenge(&chap->auth);
66344106Sbrian    return 1;
66444106Sbrian  }
66544106Sbrian
66644106Sbrian  return 0;
66744106Sbrian}
66844123Sbrian#endif
66944106Sbrian
67043693Sbrianvoid
67143693Sbrianchap_Init(struct chap *chap, struct physical *p)
67243693Sbrian{
67343888Sbrian  chap->desc.type = CHAP_DESCRIPTOR;
67443888Sbrian  chap->desc.UpdateSet = chap_UpdateSet;
67543888Sbrian  chap->desc.IsSet = chap_IsSet;
67643888Sbrian  chap->desc.Read = chap_Read;
67743888Sbrian  chap->desc.Write = chap_Write;
67843888Sbrian  chap->child.pid = 0;
67943888Sbrian  chap->child.fd = -1;
68043693Sbrian  auth_Init(&chap->auth, p, chap_Challenge, chap_Success, chap_Failure);
68145907Sbrian  *chap->challenge.local = *chap->challenge.peer = '\0';
68293418Sbrian#ifndef NODES
68344106Sbrian  chap->NTRespSent = 0;
68444106Sbrian  chap->peertries = 0;
68544123Sbrian#endif
68643693Sbrian}
68729840Sbrian
68843693Sbrianvoid
68943888Sbrianchap_ReInit(struct chap *chap)
69043888Sbrian{
69143888Sbrian  chap_Cleanup(chap, SIGTERM);
69243888Sbrian}
69343888Sbrian
69446686Sbrianstruct mbuf *
69546686Sbrianchap_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
69643693Sbrian{
69746686Sbrian  struct physical *p = link2physical(l);
69843693Sbrian  struct chap *chap = &p->dl->chap;
69944106Sbrian  char *name, *key, *ans;
700134789Sbrian  int len;
701134789Sbrian  size_t nlen;
70248817Sbrian  u_char alen;
70393418Sbrian#ifndef NODES
70444123Sbrian  int lanman;
70544123Sbrian#endif
70629840Sbrian
70746686Sbrian  if (p == NULL) {
70846686Sbrian    log_Printf(LogERROR, "chap_Input: Not a physical link - dropped\n");
70954912Sbrian    m_freem(bp);
71046686Sbrian    return NULL;
71146686Sbrian  }
71246686Sbrian
71346686Sbrian  if (bundle_Phase(bundle) != PHASE_NETWORK &&
71446686Sbrian      bundle_Phase(bundle) != PHASE_AUTHENTICATE) {
71545220Sbrian    log_Printf(LogPHASE, "Unexpected chap input - dropped !\n");
71654912Sbrian    m_freem(bp);
71746686Sbrian    return NULL;
71845220Sbrian  }
71945220Sbrian
72054912Sbrian  m_settype(bp, MB_CHAPIN);
72144159Sbrian  if ((bp = auth_ReadHeader(&chap->auth, bp)) == NULL &&
72244159Sbrian      ntohs(chap->auth.in.hdr.length) == 0)
72344159Sbrian    log_Printf(LogWARN, "Chap Input: Truncated header !\n");
72443693Sbrian  else if (chap->auth.in.hdr.code == 0 || chap->auth.in.hdr.code > MAXCHAPCODE)
72543693Sbrian    log_Printf(LogPHASE, "Chap Input: %d: Bad CHAP code !\n",
72643693Sbrian               chap->auth.in.hdr.code);
72743693Sbrian  else {
72854912Sbrian    len = m_length(bp);
72943693Sbrian    ans = NULL;
73043693Sbrian
73143693Sbrian    if (chap->auth.in.hdr.code != CHAP_CHALLENGE &&
73243693Sbrian        chap->auth.id != chap->auth.in.hdr.id &&
73346686Sbrian        Enabled(bundle, OPT_IDCHECK)) {
73443693Sbrian      /* Wrong conversation dude ! */
73543693Sbrian      log_Printf(LogPHASE, "Chap Input: %s dropped (got id %d, not %d)\n",
73643693Sbrian                 chapcodes[chap->auth.in.hdr.code], chap->auth.in.hdr.id,
73743693Sbrian                 chap->auth.id);
73854912Sbrian      m_freem(bp);
73946686Sbrian      return NULL;
74025630Sbrian    }
74143693Sbrian    chap->auth.id = chap->auth.in.hdr.id;	/* We respond with this id */
74229840Sbrian
74393418Sbrian#ifndef NODES
74444106Sbrian    lanman = 0;
74544123Sbrian#endif
74643693Sbrian    switch (chap->auth.in.hdr.code) {
74743693Sbrian      case CHAP_CHALLENGE:
74844106Sbrian        bp = mbuf_Read(bp, &alen, 1);
74944106Sbrian        len -= alen + 1;
75043693Sbrian        if (len < 0) {
75143693Sbrian          log_Printf(LogERROR, "Chap Input: Truncated challenge !\n");
75254912Sbrian          m_freem(bp);
75346686Sbrian          return NULL;
75443693Sbrian        }
75545907Sbrian        *chap->challenge.peer = alen;
75645907Sbrian        bp = mbuf_Read(bp, chap->challenge.peer + 1, alen);
75743693Sbrian        bp = auth_ReadName(&chap->auth, bp, len);
75893418Sbrian#ifndef NODES
75944106Sbrian        lanman = p->link.lcp.his_authtype == 0x80 &&
76044106Sbrian                 ((chap->NTRespSent && IsAccepted(p->link.lcp.cfg.chap80lm)) ||
76144106Sbrian                  !IsAccepted(p->link.lcp.cfg.chap80nt));
76267910Sbrian
76367910Sbrian        /* Generate local challenge value */
76467910Sbrian        chap_ChallengeInit(&chap->auth);
76544123Sbrian#endif
76643693Sbrian        break;
76743313Sbrian
76843693Sbrian      case CHAP_RESPONSE:
76943693Sbrian        auth_StopTimer(&chap->auth);
77043693Sbrian        bp = mbuf_Read(bp, &alen, 1);
77143693Sbrian        len -= alen + 1;
77243693Sbrian        if (len < 0) {
77343693Sbrian          log_Printf(LogERROR, "Chap Input: Truncated response !\n");
77454912Sbrian          m_freem(bp);
77546686Sbrian          return NULL;
77643693Sbrian        }
77798311Sbrian        if ((ans = malloc(alen + 1)) == NULL) {
77843693Sbrian          log_Printf(LogERROR, "Chap Input: Out of memory !\n");
77954912Sbrian          m_freem(bp);
78046686Sbrian          return NULL;
78143693Sbrian        }
78243693Sbrian        *ans = chap->auth.id;
78343693Sbrian        bp = mbuf_Read(bp, ans + 1, alen);
78443693Sbrian        bp = auth_ReadName(&chap->auth, bp, len);
78593418Sbrian#ifndef NODES
78698243Sbrian        lanman = p->link.lcp.want_authtype == 0x80 &&
78767910Sbrian                 alen == 49 && ans[alen] == 0;
78844123Sbrian#endif
78943693Sbrian        break;
79043313Sbrian
79143693Sbrian      case CHAP_SUCCESS:
79243693Sbrian      case CHAP_FAILURE:
79343693Sbrian        /* chap->auth.in.name is already set up at CHALLENGE time */
79443693Sbrian        if ((ans = malloc(len + 1)) == NULL) {
79543693Sbrian          log_Printf(LogERROR, "Chap Input: Out of memory !\n");
79654912Sbrian          m_freem(bp);
79746686Sbrian          return NULL;
79843693Sbrian        }
79943693Sbrian        bp = mbuf_Read(bp, ans, len);
80043693Sbrian        ans[len] = '\0';
80143693Sbrian        break;
80243401Sbrian    }
80336285Sbrian
80443693Sbrian    switch (chap->auth.in.hdr.code) {
80543693Sbrian      case CHAP_CHALLENGE:
80643693Sbrian      case CHAP_RESPONSE:
80743693Sbrian        if (*chap->auth.in.name)
80844106Sbrian          log_Printf(LogPHASE, "Chap Input: %s (%d bytes from %s%s)\n",
80944106Sbrian                     chapcodes[chap->auth.in.hdr.code], alen,
81044106Sbrian                     chap->auth.in.name,
81193418Sbrian#ifndef NODES
81244106Sbrian                     lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
81344123Sbrian                     " - lanman" :
81444123Sbrian#endif
81544123Sbrian                     "");
81643693Sbrian        else
81744106Sbrian          log_Printf(LogPHASE, "Chap Input: %s (%d bytes%s)\n",
81844106Sbrian                     chapcodes[chap->auth.in.hdr.code], alen,
81993418Sbrian#ifndef NODES
82044106Sbrian                     lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
82144123Sbrian                     " - lanman" :
82244123Sbrian#endif
82344123Sbrian                     "");
82443693Sbrian        break;
82536285Sbrian
82643693Sbrian      case CHAP_SUCCESS:
82743693Sbrian      case CHAP_FAILURE:
82843693Sbrian        if (*ans)
82943693Sbrian          log_Printf(LogPHASE, "Chap Input: %s (%s)\n",
83043693Sbrian                     chapcodes[chap->auth.in.hdr.code], ans);
83143693Sbrian        else
83243693Sbrian          log_Printf(LogPHASE, "Chap Input: %s\n",
83343693Sbrian                     chapcodes[chap->auth.in.hdr.code]);
83443693Sbrian        break;
8356059Samurai    }
8366059Samurai
83743693Sbrian    switch (chap->auth.in.hdr.code) {
83843693Sbrian      case CHAP_CHALLENGE:
83964465Sbrian        if (*bundle->cfg.auth.key == '!' && bundle->cfg.auth.key[1] != '!')
84046686Sbrian          chap_StartChild(chap, bundle->cfg.auth.key + 1,
84146686Sbrian                          bundle->cfg.auth.name);
84243888Sbrian        else
84364465Sbrian          chap_Respond(chap, bundle->cfg.auth.name, bundle->cfg.auth.key +
844134789Sbrian                       (*bundle->cfg.auth.key == '!' ? 1 : 0)
845134789Sbrian
84693418Sbrian#ifndef NODES
847134789Sbrian                       , p->link.lcp.his_authtype, lanman
84844123Sbrian#endif
84944123Sbrian                      );
85043693Sbrian        break;
8516059Samurai
85243693Sbrian      case CHAP_RESPONSE:
85343693Sbrian        name = chap->auth.in.name;
85443693Sbrian        nlen = strlen(name);
85596730Sbrian#ifndef NODES
85696730Sbrian        if (p->link.lcp.want_authtype == 0x81) {
85798311Sbrian          struct MSCHAPv2_resp *resp = (struct MSCHAPv2_resp *)(ans + 1);
85898311Sbrian
85998311Sbrian          chap->challenge.peer[0] = sizeof resp->PeerChallenge;
86098311Sbrian          memcpy(chap->challenge.peer + 1, resp->PeerChallenge,
86198311Sbrian                 sizeof resp->PeerChallenge);
86296730Sbrian        }
86396730Sbrian#endif
86496730Sbrian
86543693Sbrian#ifndef NORADIUS
86696730Sbrian        if (*bundle->radius.cfg.file) {
86796730Sbrian          if (!radius_Authenticate(&bundle->radius, &chap->auth,
86896730Sbrian                                   chap->auth.in.name, ans, alen + 1,
86996730Sbrian                                   chap->challenge.local + 1,
87098311Sbrian                                   *chap->challenge.local))
87196730Sbrian            chap_Failure(&chap->auth);
87296730Sbrian        } else
87343693Sbrian#endif
87443693Sbrian        {
87598311Sbrian          if (p->link.lcp.want_authtype == 0x81 && ans[alen] != '\0' &&
87698311Sbrian              alen == sizeof(struct MSCHAPv2_resp)) {
87798311Sbrian            struct MSCHAPv2_resp *resp = (struct MSCHAPv2_resp *)(ans + 1);
87898311Sbrian
87998311Sbrian            log_Printf(LogWARN, "%s: Compensating for corrupt (Win98/WinME?) "
88098311Sbrian                       "CHAP81 RESPONSE\n", l->name);
88198311Sbrian            resp->Flags = '\0';	/* rfc2759 says it *MUST* be zero */
88298311Sbrian          }
883134789Sbrian          key = auth_GetSecret(name, nlen);
88443693Sbrian          if (key) {
88593418Sbrian#ifndef NODES
88667910Sbrian            if (p->link.lcp.want_authtype == 0x80 &&
88767910Sbrian                lanman && !IsEnabled(p->link.lcp.cfg.chap80lm)) {
88844106Sbrian              log_Printf(LogPHASE, "Auth failure: LANMan not enabled\n");
88944106Sbrian              if (chap_HaveAnotherGo(chap))
89044106Sbrian                break;
89143693Sbrian              key = NULL;
89267910Sbrian            } else if (p->link.lcp.want_authtype == 0x80 &&
89367910Sbrian                !lanman && !IsEnabled(p->link.lcp.cfg.chap80nt)) {
89444106Sbrian              log_Printf(LogPHASE, "Auth failure: mschap not enabled\n");
89544106Sbrian              if (chap_HaveAnotherGo(chap))
89644106Sbrian                break;
89744106Sbrian              key = NULL;
89867910Sbrian            } else if (p->link.lcp.want_authtype == 0x81 &&
89967910Sbrian                !IsEnabled(p->link.lcp.cfg.chap81)) {
90067910Sbrian              log_Printf(LogPHASE, "Auth failure: CHAP81 not enabled\n");
90167910Sbrian              key = NULL;
90244123Sbrian            } else
90344123Sbrian#endif
90444123Sbrian            {
90598311Sbrian              char *myans = chap_BuildAnswer(name, key, chap->auth.id,
906134789Sbrian                                             chap->challenge.local
90793418Sbrian#ifndef NODES
908134789Sbrian					     , p->link.lcp.want_authtype,
909134789Sbrian					     chap->challenge.peer,
910134789Sbrian					     chap->authresponse, lanman);
91168461Sbrian              MPPE_IsServer = 1;		/* XXX Global ! */
91268461Sbrian#else
91368461Sbrian                                      );
91444123Sbrian#endif
91544106Sbrian              if (myans == NULL)
91643693Sbrian                key = NULL;
91744106Sbrian              else {
918134789Sbrian                if (!chap_Cmp(myans + 1, *myans, ans + 1, alen
91993418Sbrian#ifndef NODES
920134789Sbrian                              , p->link.lcp.want_authtype, lanman
92144123Sbrian#endif
92244123Sbrian                             ))
92344106Sbrian                  key = NULL;
92444106Sbrian                free(myans);
92544106Sbrian              }
92643693Sbrian            }
92743693Sbrian          }
9286059Samurai
92943693Sbrian          if (key)
93043693Sbrian            chap_Success(&chap->auth);
93143693Sbrian          else
93243693Sbrian            chap_Failure(&chap->auth);
93343693Sbrian        }
9346059Samurai
93543693Sbrian        break;
9366059Samurai
9376059Samurai      case CHAP_SUCCESS:
93843693Sbrian        if (p->link.lcp.auth_iwait == PROTO_CHAP) {
93943693Sbrian          p->link.lcp.auth_iwait = 0;
94067910Sbrian          if (p->link.lcp.auth_ineed == 0) {
94193418Sbrian#ifndef NODES
94267910Sbrian            if (p->link.lcp.his_authtype == 0x81) {
943100916Sbrian              if (strncasecmp(ans, chap->authresponse, 42)) {
94467910Sbrian                datalink_AuthNotOk(p->dl);
94581094Sbrian	        log_Printf(LogWARN, "CHAP81: AuthenticatorResponse: (%.42s)"
94681094Sbrian                           " != ans: (%.42s)\n", chap->authresponse, ans);
94798243Sbrian
94867910Sbrian              } else {
94967910Sbrian                /* Successful login */
95068461Sbrian                MPPE_MasterKeyValid = 1;		/* XXX Global ! */
95167910Sbrian                datalink_AuthOk(p->dl);
95267910Sbrian              }
95367910Sbrian            } else
95467910Sbrian#endif
95543693Sbrian            /*
95643693Sbrian             * We've succeeded in our ``login''
95743693Sbrian             * If we're not expecting  the peer to authenticate (or he already
95843693Sbrian             * has), proceed to network phase.
95943693Sbrian             */
96043693Sbrian            datalink_AuthOk(p->dl);
96167910Sbrian          }
96243693Sbrian        }
96343693Sbrian        break;
96443693Sbrian
9656059Samurai      case CHAP_FAILURE:
96643693Sbrian        datalink_AuthNotOk(p->dl);
96743693Sbrian        break;
9686059Samurai    }
96943693Sbrian    free(ans);
9706059Samurai  }
97143693Sbrian
97254912Sbrian  m_freem(bp);
97346686Sbrian  return NULL;
9746059Samurai}
975