chap.c revision 98311
178189Sbrian/*-
278189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
378189Sbrian *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
478189Sbrian *                           Internet Initiative Japan, Inc (IIJ)
578189Sbrian * All rights reserved.
66059Samurai *
778189Sbrian * Redistribution and use in source and binary forms, with or without
878189Sbrian * modification, are permitted provided that the following conditions
978189Sbrian * are met:
1078189Sbrian * 1. Redistributions of source code must retain the above copyright
1178189Sbrian *    notice, this list of conditions and the following disclaimer.
1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1378189Sbrian *    notice, this list of conditions and the following disclaimer in the
1478189Sbrian *    documentation and/or other materials provided with the distribution.
156059Samurai *
1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1978189Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2678189Sbrian * SUCH DAMAGE.
276059Samurai *
2850479Speter * $FreeBSD: head/usr.sbin/ppp/chap.c 98311 2002-06-17 01:12:38Z brian $
296059Samurai */
3078189Sbrian
3143313Sbrian#include <sys/param.h>
3230715Sbrian#include <netinet/in.h>
3336285Sbrian#include <netinet/in_systm.h>
3436285Sbrian#include <netinet/ip.h>
3581634Sbrian#include <sys/socket.h>
3636285Sbrian#include <sys/un.h>
3730715Sbrian
3843888Sbrian#include <errno.h>
3943888Sbrian#include <fcntl.h>
4093418Sbrian#ifndef NODES
4136287Sbrian#include <md4.h>
4237192Sbrian#endif
4330715Sbrian#include <md5.h>
4443888Sbrian#include <paths.h>
4543888Sbrian#include <signal.h>
4649976Sbrian#include <stdio.h>
4730715Sbrian#include <stdlib.h>
4844106Sbrian#include <string.h>
4943888Sbrian#include <sys/wait.h>
5036285Sbrian#include <termios.h>
5143888Sbrian#include <unistd.h>
5229840Sbrian
5346686Sbrian#include "layer.h"
5430715Sbrian#include "mbuf.h"
5530715Sbrian#include "log.h"
5630715Sbrian#include "defs.h"
5730715Sbrian#include "timer.h"
586059Samurai#include "fsm.h"
5946686Sbrian#include "proto.h"
6036285Sbrian#include "lqr.h"
616059Samurai#include "hdlc.h"
6263484Sbrian#include "lcp.h"
636735Samurai#include "auth.h"
6436285Sbrian#include "async.h"
6536285Sbrian#include "throughput.h"
6636285Sbrian#include "descriptor.h"
6743888Sbrian#include "chap.h"
6836285Sbrian#include "iplist.h"
6936285Sbrian#include "slcompress.h"
7081634Sbrian#include "ncpaddr.h"
7136285Sbrian#include "ipcp.h"
7236285Sbrian#include "filter.h"
7336285Sbrian#include "ccp.h"
7436285Sbrian#include "link.h"
7536285Sbrian#include "physical.h"
7636285Sbrian#include "mp.h"
7743313Sbrian#ifndef NORADIUS
7843313Sbrian#include "radius.h"
7943313Sbrian#endif
8081634Sbrian#include "ipv6cp.h"
8181634Sbrian#include "ncp.h"
8236285Sbrian#include "bundle.h"
8336285Sbrian#include "chat.h"
8438174Sbrian#include "cbcp.h"
8543888Sbrian#include "command.h"
8636285Sbrian#include "datalink.h"
8793418Sbrian#ifndef NODES
8836287Sbrian#include "chap_ms.h"
8967910Sbrian#include "mppe.h"
9037192Sbrian#endif
9155253Sbrian#include "id.h"
926059Samurai
9355146Sbrianstatic const char * const chapcodes[] = {
9419866Sphk  "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE"
956059Samurai};
9643693Sbrian#define MAXCHAPCODE (sizeof chapcodes / sizeof chapcodes[0] - 1)
976059Samurai
9830715Sbrianstatic void
9936285SbrianChapOutput(struct physical *physical, u_int code, u_int id,
10043693Sbrian	   const u_char *ptr, int count, const char *text)
1016059Samurai{
1026059Samurai  int plen;
1036059Samurai  struct fsmheader lh;
1046059Samurai  struct mbuf *bp;
1056059Samurai
10628679Sbrian  plen = sizeof(struct fsmheader) + count;
1076059Samurai  lh.code = code;
1086059Samurai  lh.id = id;
1096059Samurai  lh.length = htons(plen);
11054912Sbrian  bp = m_get(plen, MB_CHAPOUT);
11130715Sbrian  memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
1126059Samurai  if (count)
11330715Sbrian    memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count);
11436285Sbrian  log_DumpBp(LogDEBUG, "ChapOutput", bp);
11537926Sbrian  if (text == NULL)
11637926Sbrian    log_Printf(LogPHASE, "Chap Output: %s\n", chapcodes[code]);
11737926Sbrian  else
11837926Sbrian    log_Printf(LogPHASE, "Chap Output: %s (%s)\n", chapcodes[code], text);
11946686Sbrian  link_PushPacket(&physical->link, bp, physical->dl->bundle,
12050867Sbrian                  LINK_QUEUES(&physical->link) - 1, PROTO_CHAP);
1216059Samurai}
1226059Samurai
12343693Sbrianstatic char *
12444123Sbrianchap_BuildAnswer(char *name, char *key, u_char id, char *challenge, u_char type
12593418Sbrian#ifndef NODES
12667910Sbrian                 , char *peerchallenge, char *authresponse, int lanman
12744123Sbrian#endif
12844123Sbrian                )
1296059Samurai{
13043693Sbrian  char *result, *digest;
13143693Sbrian  size_t nlen, klen;
13243693Sbrian
13343693Sbrian  nlen = strlen(name);
13443693Sbrian  klen = strlen(key);
13543693Sbrian
13693418Sbrian#ifndef NODES
13744106Sbrian  if (type == 0x80) {
13843693Sbrian    char expkey[AUTHLEN << 2];
13943693Sbrian    MD4_CTX MD4context;
14043693Sbrian    int f;
14143693Sbrian
14243693Sbrian    if ((result = malloc(1 + nlen + MS_CHAP_RESPONSE_LEN)) == NULL)
14343693Sbrian      return result;
14443693Sbrian
14544106Sbrian    digest = result;					/* the response */
14644106Sbrian    *digest++ = MS_CHAP_RESPONSE_LEN;			/* 49 */
14744106Sbrian    memcpy(digest + MS_CHAP_RESPONSE_LEN, name, nlen);
14844106Sbrian    if (lanman) {
14944106Sbrian      memset(digest + 24, '\0', 25);
15044106Sbrian      mschap_LANMan(digest, challenge + 1, key);	/* LANMan response */
15144106Sbrian    } else {
15244106Sbrian      memset(digest, '\0', 25);
15344106Sbrian      digest += 24;
15443693Sbrian
15544106Sbrian      for (f = 0; f < klen; f++) {
15644106Sbrian        expkey[2*f] = key[f];
15744106Sbrian        expkey[2*f+1] = '\0';
15844106Sbrian      }
15944106Sbrian      /*
16044106Sbrian       *           -----------
16144106Sbrian       * expkey = | k\0e\0y\0 |
16244106Sbrian       *           -----------
16344106Sbrian       */
16444106Sbrian      MD4Init(&MD4context);
16544106Sbrian      MD4Update(&MD4context, expkey, klen << 1);
16644106Sbrian      MD4Final(digest, &MD4context);
16744106Sbrian
16844106Sbrian      /*
16944106Sbrian       *           ---- -------- ---------------- ------- ------
17044106Sbrian       * result = | 49 | LANMan | 16 byte digest | 9 * ? | name |
17144106Sbrian       *           ---- -------- ---------------- ------- ------
17244106Sbrian       */
17344106Sbrian      mschap_NT(digest, challenge + 1);
17443693Sbrian    }
17543693Sbrian    /*
17644106Sbrian     *           ---- -------- ------------- ----- ------
17744106Sbrian     *          |    |  struct MS_ChapResponse24  |      |
17844106Sbrian     * result = | 49 | LANMan  |  NT digest | 0/1 | name |
17944106Sbrian     *           ---- -------- ------------- ----- ------
18044106Sbrian     * where only one of LANMan & NT digest are set.
18143693Sbrian     */
18267910Sbrian  } else if (type == 0x81) {
18367910Sbrian    char expkey[AUTHLEN << 2];
18467910Sbrian    char pwdhash[CHAP81_HASH_LEN];
18567910Sbrian    char pwdhashhash[CHAP81_HASH_LEN];
18667910Sbrian    char *ntresponse;
18767910Sbrian    int f;
18867910Sbrian
18967910Sbrian    if ((result = malloc(1 + nlen + CHAP81_RESPONSE_LEN)) == NULL)
19067910Sbrian      return result;
19167910Sbrian
19267910Sbrian    memset(result, 0, 1 + nlen + CHAP81_RESPONSE_LEN);
19367910Sbrian
19467910Sbrian    digest = result;
19567910Sbrian    *digest++ = CHAP81_RESPONSE_LEN;		/* value size */
19667910Sbrian
19767910Sbrian    /* Copy our challenge */
19867910Sbrian    memcpy(digest, peerchallenge + 1, CHAP81_CHALLENGE_LEN);
19967910Sbrian
20067910Sbrian    /* Expand password to Unicode XXX */
20167910Sbrian    for (f = 0; f < klen; f++) {
20267910Sbrian      expkey[2*f] = key[f];
20367910Sbrian      expkey[2*f+1] = '\0';
20467910Sbrian    }
20567910Sbrian
20667910Sbrian    ntresponse = digest + CHAP81_NTRESPONSE_OFF;
20767910Sbrian
20867910Sbrian    /* Get some needed hashes */
20967910Sbrian    NtPasswordHash(expkey, klen * 2, pwdhash);
21067910Sbrian    HashNtPasswordHash(pwdhash, pwdhashhash);
21167910Sbrian
21267910Sbrian    /* Generate NTRESPONSE to respond on challenge call */
21367910Sbrian    GenerateNTResponse(challenge + 1, peerchallenge + 1, name, nlen,
21467910Sbrian                       expkey, klen * 2, ntresponse);
21567910Sbrian
21667910Sbrian    /* Generate MPPE MASTERKEY */
21768461Sbrian    GetMasterKey(pwdhashhash, ntresponse, MPPE_MasterKey);    /* XXX Global ! */
21867910Sbrian
21967910Sbrian    /* Generate AUTHRESPONSE to verify on auth success */
22098243Sbrian    GenerateAuthenticatorResponse(expkey, klen * 2, ntresponse,
22167910Sbrian                                  peerchallenge + 1, challenge + 1, name, nlen,
22267910Sbrian                                  authresponse);
22367910Sbrian
22467910Sbrian    authresponse[CHAP81_AUTHRESPONSE_LEN] = 0;
22567910Sbrian
22667910Sbrian    memcpy(digest + CHAP81_RESPONSE_LEN, name, nlen);
22743693Sbrian  } else
22843693Sbrian#endif
22943693Sbrian  if ((result = malloc(nlen + 17)) != NULL) {
23043693Sbrian    /* Normal MD5 stuff */
23143693Sbrian    MD5_CTX MD5context;
23243693Sbrian
23343693Sbrian    digest = result;
23443693Sbrian    *digest++ = 16;				/* value size */
23543693Sbrian
23643693Sbrian    MD5Init(&MD5context);
23743693Sbrian    MD5Update(&MD5context, &id, 1);
23843693Sbrian    MD5Update(&MD5context, key, klen);
23943693Sbrian    MD5Update(&MD5context, challenge + 1, *challenge);
24043693Sbrian    MD5Final(digest, &MD5context);
24143693Sbrian
24243693Sbrian    memcpy(digest + 16, name, nlen);
24343693Sbrian    /*
24443693Sbrian     *           ---- -------- ------
24543693Sbrian     * result = | 16 | digest | name |
24643693Sbrian     *           ---- -------- ------
24743693Sbrian     */
24843693Sbrian  }
24943693Sbrian
25043693Sbrian  return result;
25143693Sbrian}
25243693Sbrian
25343693Sbrianstatic void
25443888Sbrianchap_StartChild(struct chap *chap, char *prog, const char *name)
25543888Sbrian{
25643888Sbrian  char *argv[MAXARGS], *nargv[MAXARGS];
25743888Sbrian  int argc, fd;
25843888Sbrian  int in[2], out[2];
25947849Sbrian  pid_t pid;
26043888Sbrian
26143888Sbrian  if (chap->child.fd != -1) {
26243888Sbrian    log_Printf(LogWARN, "Chap: %s: Program already running\n", prog);
26343888Sbrian    return;
26443888Sbrian  }
26543888Sbrian
26643888Sbrian  if (pipe(in) == -1) {
26743888Sbrian    log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno));
26843888Sbrian    return;
26943888Sbrian  }
27043888Sbrian
27143888Sbrian  if (pipe(out) == -1) {
27243888Sbrian    log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno));
27343888Sbrian    close(in[0]);
27443888Sbrian    close(in[1]);
27543888Sbrian    return;
27643888Sbrian  }
27743888Sbrian
27847849Sbrian  pid = getpid();
27943888Sbrian  switch ((chap->child.pid = fork())) {
28043888Sbrian    case -1:
28143888Sbrian      log_Printf(LogERROR, "Chap: fork: %s\n", strerror(errno));
28243888Sbrian      close(in[0]);
28343888Sbrian      close(in[1]);
28443888Sbrian      close(out[0]);
28543888Sbrian      close(out[1]);
28643888Sbrian      chap->child.pid = 0;
28743888Sbrian      return;
28843888Sbrian
28943888Sbrian    case 0:
29043888Sbrian      timer_TermService();
29154914Sbrian
29254914Sbrian      if ((argc = command_Interpret(prog, strlen(prog), argv)) <= 0) {
29354914Sbrian        if (argc < 0) {
29454914Sbrian          log_Printf(LogWARN, "CHAP: Invalid command syntax\n");
29554914Sbrian          _exit(255);
29654914Sbrian        }
29754914Sbrian        _exit(0);
29854914Sbrian      }
29954914Sbrian
30043888Sbrian      close(in[1]);
30143888Sbrian      close(out[0]);
30249976Sbrian      if (out[1] == STDIN_FILENO)
30349976Sbrian        out[1] = dup(out[1]);
30443888Sbrian      dup2(in[0], STDIN_FILENO);
30543888Sbrian      dup2(out[1], STDOUT_FILENO);
30649976Sbrian      close(STDERR_FILENO);
30749976Sbrian      if (open(_PATH_DEVNULL, O_RDWR) != STDERR_FILENO) {
30843888Sbrian        log_Printf(LogALERT, "Chap: Failed to open %s: %s\n",
30943888Sbrian                  _PATH_DEVNULL, strerror(errno));
31043888Sbrian        exit(1);
31143888Sbrian      }
31249976Sbrian      for (fd = getdtablesize(); fd > STDERR_FILENO; fd--)
31349976Sbrian        fcntl(fd, F_SETFD, 1);
31464802Sbrian#ifndef NOSUID
31555252Sbrian      setuid(ID0realuid());
31664802Sbrian#endif
31743888Sbrian      command_Expand(nargv, argc, (char const *const *)argv,
31847849Sbrian                     chap->auth.physical->dl->bundle, 0, pid);
31943888Sbrian      execvp(nargv[0], nargv);
32049976Sbrian      printf("exec() of %s failed: %s\n", nargv[0], strerror(errno));
32149976Sbrian      _exit(255);
32243888Sbrian
32343888Sbrian    default:
32443888Sbrian      close(in[0]);
32543888Sbrian      close(out[1]);
32643888Sbrian      chap->child.fd = out[0];
32743888Sbrian      chap->child.buf.len = 0;
32843888Sbrian      write(in[1], chap->auth.in.name, strlen(chap->auth.in.name));
32943888Sbrian      write(in[1], "\n", 1);
33045907Sbrian      write(in[1], chap->challenge.peer + 1, *chap->challenge.peer);
33143888Sbrian      write(in[1], "\n", 1);
33243888Sbrian      write(in[1], name, strlen(name));
33343888Sbrian      write(in[1], "\n", 1);
33443888Sbrian      close(in[1]);
33543888Sbrian      break;
33643888Sbrian  }
33743888Sbrian}
33843888Sbrian
33943888Sbrianstatic void
34043888Sbrianchap_Cleanup(struct chap *chap, int sig)
34143888Sbrian{
34243888Sbrian  if (chap->child.pid) {
34343888Sbrian    int status;
34443888Sbrian
34543888Sbrian    close(chap->child.fd);
34643888Sbrian    chap->child.fd = -1;
34743888Sbrian    if (sig)
34843888Sbrian      kill(chap->child.pid, SIGTERM);
34943888Sbrian    chap->child.pid = 0;
35043888Sbrian    chap->child.buf.len = 0;
35143888Sbrian
35243888Sbrian    if (wait(&status) == -1)
35343888Sbrian      log_Printf(LogERROR, "Chap: wait: %s\n", strerror(errno));
35443888Sbrian    else if (WIFSIGNALED(status))
35543888Sbrian      log_Printf(LogWARN, "Chap: Child received signal %d\n", WTERMSIG(status));
35643888Sbrian    else if (WIFEXITED(status) && WEXITSTATUS(status))
35743888Sbrian      log_Printf(LogERROR, "Chap: Child exited %d\n", WEXITSTATUS(status));
35843888Sbrian  }
35945907Sbrian  *chap->challenge.local = *chap->challenge.peer = '\0';
36093418Sbrian#ifndef NODES
36144106Sbrian  chap->peertries = 0;
36244123Sbrian#endif
36343888Sbrian}
36443888Sbrian
36543888Sbrianstatic void
36644123Sbrianchap_Respond(struct chap *chap, char *name, char *key, u_char type
36793418Sbrian#ifndef NODES
36844123Sbrian             , int lm
36944123Sbrian#endif
37044123Sbrian            )
37143888Sbrian{
37244106Sbrian  u_char *ans;
37343888Sbrian
37445907Sbrian  ans = chap_BuildAnswer(name, key, chap->auth.id, chap->challenge.peer, type
37593418Sbrian#ifndef NODES
37667910Sbrian                         , chap->challenge.local, chap->authresponse, lm
37744123Sbrian#endif
37844123Sbrian                        );
37943888Sbrian
38043888Sbrian  if (ans) {
38143888Sbrian    ChapOutput(chap->auth.physical, CHAP_RESPONSE, chap->auth.id,
38243888Sbrian               ans, *ans + 1 + strlen(name), name);
38393418Sbrian#ifndef NODES
38444106Sbrian    chap->NTRespSent = !lm;
38568461Sbrian    MPPE_IsServer = 0;		/* XXX Global ! */
38644123Sbrian#endif
38743888Sbrian    free(ans);
38843888Sbrian  } else
38943888Sbrian    ChapOutput(chap->auth.physical, CHAP_FAILURE, chap->auth.id,
39043888Sbrian               "Out of memory!", 14, NULL);
39143888Sbrian}
39243888Sbrian
39343888Sbrianstatic int
39458028Sbrianchap_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
39543888Sbrian{
39643888Sbrian  struct chap *chap = descriptor2chap(d);
39743888Sbrian
39843888Sbrian  if (r && chap && chap->child.fd != -1) {
39943888Sbrian    FD_SET(chap->child.fd, r);
40043888Sbrian    if (*n < chap->child.fd + 1)
40143888Sbrian      *n = chap->child.fd + 1;
40243888Sbrian    log_Printf(LogTIMER, "Chap: fdset(r) %d\n", chap->child.fd);
40343888Sbrian    return 1;
40443888Sbrian  }
40543888Sbrian
40643888Sbrian  return 0;
40743888Sbrian}
40843888Sbrian
40943888Sbrianstatic int
41058028Sbrianchap_IsSet(struct fdescriptor *d, const fd_set *fdset)
41143888Sbrian{
41243888Sbrian  struct chap *chap = descriptor2chap(d);
41343888Sbrian
41443888Sbrian  return chap && chap->child.fd != -1 && FD_ISSET(chap->child.fd, fdset);
41543888Sbrian}
41643888Sbrian
41743888Sbrianstatic void
41858028Sbrianchap_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
41943888Sbrian{
42043888Sbrian  struct chap *chap = descriptor2chap(d);
42143888Sbrian  int got;
42243888Sbrian
42343888Sbrian  got = read(chap->child.fd, chap->child.buf.ptr + chap->child.buf.len,
42443888Sbrian             sizeof chap->child.buf.ptr - chap->child.buf.len - 1);
42543888Sbrian  if (got == -1) {
42643888Sbrian    log_Printf(LogERROR, "Chap: Read: %s\n", strerror(errno));
42743888Sbrian    chap_Cleanup(chap, SIGTERM);
42843888Sbrian  } else if (got == 0) {
42943888Sbrian    log_Printf(LogWARN, "Chap: Read: Child terminated connection\n");
43043888Sbrian    chap_Cleanup(chap, SIGTERM);
43143888Sbrian  } else {
43243888Sbrian    char *name, *key, *end;
43343888Sbrian
43443888Sbrian    chap->child.buf.len += got;
43543888Sbrian    chap->child.buf.ptr[chap->child.buf.len] = '\0';
43643888Sbrian    name = chap->child.buf.ptr;
43743888Sbrian    name += strspn(name, " \t");
43843888Sbrian    if ((key = strchr(name, '\n')) == NULL)
43943888Sbrian      end = NULL;
44043888Sbrian    else
44143888Sbrian      end = strchr(++key, '\n');
44243888Sbrian
44343888Sbrian    if (end == NULL) {
44443888Sbrian      if (chap->child.buf.len == sizeof chap->child.buf.ptr - 1) {
44543888Sbrian        log_Printf(LogWARN, "Chap: Read: Input buffer overflow\n");
44643888Sbrian        chap_Cleanup(chap, SIGTERM);
44743888Sbrian      }
44843888Sbrian    } else {
44993418Sbrian#ifndef NODES
45044106Sbrian      int lanman = chap->auth.physical->link.lcp.his_authtype == 0x80 &&
45144106Sbrian                   ((chap->NTRespSent &&
45244106Sbrian                     IsAccepted(chap->auth.physical->link.lcp.cfg.chap80lm)) ||
45344106Sbrian                    !IsAccepted(chap->auth.physical->link.lcp.cfg.chap80nt));
45444123Sbrian#endif
45544106Sbrian
45643888Sbrian      while (end >= name && strchr(" \t\r\n", *end))
45743888Sbrian        *end-- = '\0';
45843888Sbrian      end = key - 1;
45943888Sbrian      while (end >= name && strchr(" \t\r\n", *end))
46043888Sbrian        *end-- = '\0';
46143888Sbrian      key += strspn(key, " \t");
46243888Sbrian
46344123Sbrian      chap_Respond(chap, name, key, chap->auth.physical->link.lcp.his_authtype
46493418Sbrian#ifndef NODES
46544123Sbrian                   , lanman
46644123Sbrian#endif
46744123Sbrian                  );
46843888Sbrian      chap_Cleanup(chap, 0);
46943888Sbrian    }
47043888Sbrian  }
47143888Sbrian}
47243888Sbrian
47343888Sbrianstatic int
47458028Sbrianchap_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
47543888Sbrian{
47643888Sbrian  /* We never want to write here ! */
47743888Sbrian  log_Printf(LogALERT, "chap_Write: Internal error: Bad call !\n");
47843888Sbrian  return 0;
47943888Sbrian}
48043888Sbrian
48143888Sbrianstatic void
48267910Sbrianchap_ChallengeInit(struct authinfo *authp)
48343693Sbrian{
48443693Sbrian  struct chap *chap = auth2chap(authp);
48513379Sphk  int len, i;
4866059Samurai  char *cp;
4876059Samurai
48843888Sbrian  len = strlen(authp->physical->dl->bundle->cfg.auth.name);
48943401Sbrian
49045907Sbrian  if (!*chap->challenge.local) {
49143888Sbrian    randinit();
49245907Sbrian    cp = chap->challenge.local;
49343888Sbrian
49443313Sbrian#ifndef NORADIUS
49543888Sbrian    if (*authp->physical->dl->bundle->radius.cfg.file) {
49643888Sbrian      /* For radius, our challenge is 16 readable NUL terminated bytes :*/
49743888Sbrian      *cp++ = 16;
49843888Sbrian      for (i = 0; i < 16; i++)
49943888Sbrian        *cp++ = (random() % 10) + '0';
50043888Sbrian    } else
50143313Sbrian#endif
50243888Sbrian    {
50393418Sbrian#ifndef NODES
50444106Sbrian      if (authp->physical->link.lcp.want_authtype == 0x80)
50544106Sbrian        *cp++ = 8;	/* MS does 8 byte callenges :-/ */
50667910Sbrian      else if (authp->physical->link.lcp.want_authtype == 0x81)
50767910Sbrian        *cp++ = 16;	/* MS-CHAP-V2 does 16 bytes challenges */
50844106Sbrian      else
50944106Sbrian#endif
51044106Sbrian        *cp++ = random() % (CHAPCHALLENGELEN-16) + 16;
51145907Sbrian      for (i = 0; i < *chap->challenge.local; i++)
51243888Sbrian        *cp++ = random() & 0xff;
51343888Sbrian    }
51443888Sbrian    memcpy(cp, authp->physical->dl->bundle->cfg.auth.name, len);
51543313Sbrian  }
5166059Samurai}
5176059Samurai
51830715Sbrianstatic void
51967910Sbrianchap_Challenge(struct authinfo *authp)
52067910Sbrian{
52167910Sbrian  struct chap *chap = auth2chap(authp);
52267910Sbrian  int len;
52367910Sbrian
52467912Sbrian  log_Printf(LogDEBUG, "CHAP%02X: Challenge\n",
52567912Sbrian             authp->physical->link.lcp.want_authtype);
52667910Sbrian
52767910Sbrian  len = strlen(authp->physical->dl->bundle->cfg.auth.name);
52867910Sbrian
52967910Sbrian  /* Generate new local challenge value */
53067910Sbrian  if (!*chap->challenge.local)
53167910Sbrian    chap_ChallengeInit(authp);
53267910Sbrian
53393418Sbrian#ifndef NODES
53467910Sbrian  if (authp->physical->link.lcp.want_authtype == 0x81)
53567910Sbrian    ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id,
53667910Sbrian             chap->challenge.local, 1 + *chap->challenge.local, NULL);
53767910Sbrian  else
53867910Sbrian#endif
53967910Sbrian    ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id,
54067910Sbrian             chap->challenge.local, 1 + *chap->challenge.local + len, NULL);
54167910Sbrian}
54267910Sbrian
54367910Sbrianstatic void
54443693Sbrianchap_Success(struct authinfo *authp)
5456059Samurai{
54696324Sbrian  struct bundle *bundle = authp->physical->dl->bundle;
54767912Sbrian  const char *msg;
54896324Sbrian
54943693Sbrian  datalink_GotAuthname(authp->physical->dl, authp->in.name);
55093418Sbrian#ifndef NODES
55167910Sbrian  if (authp->physical->link.lcp.want_authtype == 0x81) {
55296730Sbrian#ifndef NORADIUS
55396730Sbrian    if (*bundle->radius.cfg.file && bundle->radius.msrepstr)
55496730Sbrian      msg = bundle->radius.msrepstr;
55596730Sbrian    else
55696731Sbrian#endif
55796730Sbrian      msg = auth2chap(authp)->authresponse;
55868461Sbrian    MPPE_MasterKeyValid = 1;		/* XXX Global ! */
55967910Sbrian  } else
56067910Sbrian#endif
56196324Sbrian#ifndef NORADIUS
56296324Sbrian  if (*bundle->radius.cfg.file && bundle->radius.repstr)
56396324Sbrian    msg = bundle->radius.repstr;
56496324Sbrian  else
56596324Sbrian#endif
56667910Sbrian    msg = "Welcome!!";
56767910Sbrian
56880763Sbrian  ChapOutput(authp->physical, CHAP_SUCCESS, authp->id, msg, strlen(msg),
56967910Sbrian             NULL);
57067910Sbrian
57143693Sbrian  authp->physical->link.lcp.auth_ineed = 0;
57296324Sbrian  if (Enabled(bundle, OPT_UTMP))
57343693Sbrian    physical_Login(authp->physical, authp->in.name);
5746059Samurai
57543693Sbrian  if (authp->physical->link.lcp.auth_iwait == 0)
57643693Sbrian    /*
57743693Sbrian     * Either I didn't need to authenticate, or I've already been
57843693Sbrian     * told that I got the answer right.
57943693Sbrian     */
58043693Sbrian    datalink_AuthOk(authp->physical->dl);
58143693Sbrian}
5826059Samurai
58343693Sbrianstatic void
58443693Sbrianchap_Failure(struct authinfo *authp)
58543693Sbrian{
58693418Sbrian#ifndef NODES
58796324Sbrian  char buf[1024], *ptr;
58867910Sbrian#endif
58967912Sbrian  const char *msg;
59067910Sbrian
59196324Sbrian#ifndef NORADIUS
59296324Sbrian  struct bundle *bundle = authp->physical->link.lcp.fsm.bundle;
59396324Sbrian  if (*bundle->radius.cfg.file && bundle->radius.errstr)
59496324Sbrian    msg = bundle->radius.errstr;
59596324Sbrian  else
59696324Sbrian#endif
59793418Sbrian#ifndef NODES
59896324Sbrian  if (authp->physical->link.lcp.want_authtype == 0x80) {
59996324Sbrian    sprintf(buf, "E=691 R=1 M=Invalid!");
60096324Sbrian    msg = buf;
60196324Sbrian  } else if (authp->physical->link.lcp.want_authtype == 0x81) {
60267910Sbrian    int i;
60367910Sbrian
60467912Sbrian    ptr = buf;
60567912Sbrian    ptr += sprintf(buf, "E=691 R=0 C=");
60667910Sbrian    for (i=0; i<16; i++)
60767912Sbrian      ptr += sprintf(ptr, "%02X", *(auth2chap(authp)->challenge.local+1+i));
60898243Sbrian
60967912Sbrian    sprintf(ptr, " V=3 M=Invalid!");
61067910Sbrian    msg = buf;
61167910Sbrian  } else
61267910Sbrian#endif
61367910Sbrian    msg = "Invalid!!";
61467910Sbrian
61567910Sbrian  ChapOutput(authp->physical, CHAP_FAILURE, authp->id, msg, strlen(msg) + 1,
61667910Sbrian             NULL);
61743693Sbrian  datalink_AuthNotOk(authp->physical->dl);
61843693Sbrian}
61937926Sbrian
62044106Sbrianstatic int
62144123Sbrianchap_Cmp(u_char type, char *myans, int mylen, char *hisans, int hislen
62293418Sbrian#ifndef NODES
62344123Sbrian         , int lm
62444123Sbrian#endif
62544123Sbrian        )
62644106Sbrian{
62744106Sbrian  if (mylen != hislen)
62844106Sbrian    return 0;
62993418Sbrian#ifndef NODES
63044106Sbrian  else if (type == 0x80) {
63144106Sbrian    int off = lm ? 0 : 24;
63244106Sbrian
63344106Sbrian    if (memcmp(myans + off, hisans + off, 24))
63444106Sbrian      return 0;
63544123Sbrian  }
63644123Sbrian#endif
63744123Sbrian  else if (memcmp(myans, hisans, mylen))
63844106Sbrian    return 0;
63944106Sbrian
64044106Sbrian  return 1;
64144106Sbrian}
64244106Sbrian
64393418Sbrian#ifndef NODES
64444106Sbrianstatic int
64544106Sbrianchap_HaveAnotherGo(struct chap *chap)
64644106Sbrian{
64744106Sbrian  if (++chap->peertries < 3) {
64844106Sbrian    /* Give the peer another shot */
64945907Sbrian    *chap->challenge.local = '\0';
65044106Sbrian    chap_Challenge(&chap->auth);
65144106Sbrian    return 1;
65244106Sbrian  }
65344106Sbrian
65444106Sbrian  return 0;
65544106Sbrian}
65644123Sbrian#endif
65744106Sbrian
65843693Sbrianvoid
65943693Sbrianchap_Init(struct chap *chap, struct physical *p)
66043693Sbrian{
66143888Sbrian  chap->desc.type = CHAP_DESCRIPTOR;
66243888Sbrian  chap->desc.UpdateSet = chap_UpdateSet;
66343888Sbrian  chap->desc.IsSet = chap_IsSet;
66443888Sbrian  chap->desc.Read = chap_Read;
66543888Sbrian  chap->desc.Write = chap_Write;
66643888Sbrian  chap->child.pid = 0;
66743888Sbrian  chap->child.fd = -1;
66843693Sbrian  auth_Init(&chap->auth, p, chap_Challenge, chap_Success, chap_Failure);
66945907Sbrian  *chap->challenge.local = *chap->challenge.peer = '\0';
67093418Sbrian#ifndef NODES
67144106Sbrian  chap->NTRespSent = 0;
67244106Sbrian  chap->peertries = 0;
67344123Sbrian#endif
67443693Sbrian}
67529840Sbrian
67643693Sbrianvoid
67743888Sbrianchap_ReInit(struct chap *chap)
67843888Sbrian{
67943888Sbrian  chap_Cleanup(chap, SIGTERM);
68043888Sbrian}
68143888Sbrian
68246686Sbrianstruct mbuf *
68346686Sbrianchap_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
68443693Sbrian{
68546686Sbrian  struct physical *p = link2physical(l);
68643693Sbrian  struct chap *chap = &p->dl->chap;
68744106Sbrian  char *name, *key, *ans;
68844123Sbrian  int len, nlen;
68948817Sbrian  u_char alen;
69093418Sbrian#ifndef NODES
69144123Sbrian  int lanman;
69244123Sbrian#endif
69329840Sbrian
69446686Sbrian  if (p == NULL) {
69546686Sbrian    log_Printf(LogERROR, "chap_Input: Not a physical link - dropped\n");
69654912Sbrian    m_freem(bp);
69746686Sbrian    return NULL;
69846686Sbrian  }
69946686Sbrian
70046686Sbrian  if (bundle_Phase(bundle) != PHASE_NETWORK &&
70146686Sbrian      bundle_Phase(bundle) != PHASE_AUTHENTICATE) {
70245220Sbrian    log_Printf(LogPHASE, "Unexpected chap input - dropped !\n");
70354912Sbrian    m_freem(bp);
70446686Sbrian    return NULL;
70545220Sbrian  }
70645220Sbrian
70754912Sbrian  m_settype(bp, MB_CHAPIN);
70844159Sbrian  if ((bp = auth_ReadHeader(&chap->auth, bp)) == NULL &&
70944159Sbrian      ntohs(chap->auth.in.hdr.length) == 0)
71044159Sbrian    log_Printf(LogWARN, "Chap Input: Truncated header !\n");
71143693Sbrian  else if (chap->auth.in.hdr.code == 0 || chap->auth.in.hdr.code > MAXCHAPCODE)
71243693Sbrian    log_Printf(LogPHASE, "Chap Input: %d: Bad CHAP code !\n",
71343693Sbrian               chap->auth.in.hdr.code);
71443693Sbrian  else {
71554912Sbrian    len = m_length(bp);
71643693Sbrian    ans = NULL;
71743693Sbrian
71843693Sbrian    if (chap->auth.in.hdr.code != CHAP_CHALLENGE &&
71943693Sbrian        chap->auth.id != chap->auth.in.hdr.id &&
72046686Sbrian        Enabled(bundle, OPT_IDCHECK)) {
72143693Sbrian      /* Wrong conversation dude ! */
72243693Sbrian      log_Printf(LogPHASE, "Chap Input: %s dropped (got id %d, not %d)\n",
72343693Sbrian                 chapcodes[chap->auth.in.hdr.code], chap->auth.in.hdr.id,
72443693Sbrian                 chap->auth.id);
72554912Sbrian      m_freem(bp);
72646686Sbrian      return NULL;
72725630Sbrian    }
72843693Sbrian    chap->auth.id = chap->auth.in.hdr.id;	/* We respond with this id */
72929840Sbrian
73093418Sbrian#ifndef NODES
73144106Sbrian    lanman = 0;
73244123Sbrian#endif
73343693Sbrian    switch (chap->auth.in.hdr.code) {
73443693Sbrian      case CHAP_CHALLENGE:
73544106Sbrian        bp = mbuf_Read(bp, &alen, 1);
73644106Sbrian        len -= alen + 1;
73743693Sbrian        if (len < 0) {
73843693Sbrian          log_Printf(LogERROR, "Chap Input: Truncated challenge !\n");
73954912Sbrian          m_freem(bp);
74046686Sbrian          return NULL;
74143693Sbrian        }
74245907Sbrian        *chap->challenge.peer = alen;
74345907Sbrian        bp = mbuf_Read(bp, chap->challenge.peer + 1, alen);
74443693Sbrian        bp = auth_ReadName(&chap->auth, bp, len);
74593418Sbrian#ifndef NODES
74644106Sbrian        lanman = p->link.lcp.his_authtype == 0x80 &&
74744106Sbrian                 ((chap->NTRespSent && IsAccepted(p->link.lcp.cfg.chap80lm)) ||
74844106Sbrian                  !IsAccepted(p->link.lcp.cfg.chap80nt));
74967910Sbrian
75067910Sbrian        /* Generate local challenge value */
75167910Sbrian        chap_ChallengeInit(&chap->auth);
75244123Sbrian#endif
75343693Sbrian        break;
75443313Sbrian
75543693Sbrian      case CHAP_RESPONSE:
75643693Sbrian        auth_StopTimer(&chap->auth);
75743693Sbrian        bp = mbuf_Read(bp, &alen, 1);
75843693Sbrian        len -= alen + 1;
75943693Sbrian        if (len < 0) {
76043693Sbrian          log_Printf(LogERROR, "Chap Input: Truncated response !\n");
76154912Sbrian          m_freem(bp);
76246686Sbrian          return NULL;
76343693Sbrian        }
76498311Sbrian        if ((ans = malloc(alen + 1)) == NULL) {
76543693Sbrian          log_Printf(LogERROR, "Chap Input: Out of memory !\n");
76654912Sbrian          m_freem(bp);
76746686Sbrian          return NULL;
76843693Sbrian        }
76943693Sbrian        *ans = chap->auth.id;
77043693Sbrian        bp = mbuf_Read(bp, ans + 1, alen);
77143693Sbrian        bp = auth_ReadName(&chap->auth, bp, len);
77293418Sbrian#ifndef NODES
77398243Sbrian        lanman = p->link.lcp.want_authtype == 0x80 &&
77467910Sbrian                 alen == 49 && ans[alen] == 0;
77544123Sbrian#endif
77643693Sbrian        break;
77743313Sbrian
77843693Sbrian      case CHAP_SUCCESS:
77943693Sbrian      case CHAP_FAILURE:
78043693Sbrian        /* chap->auth.in.name is already set up at CHALLENGE time */
78143693Sbrian        if ((ans = malloc(len + 1)) == NULL) {
78243693Sbrian          log_Printf(LogERROR, "Chap Input: Out of memory !\n");
78354912Sbrian          m_freem(bp);
78446686Sbrian          return NULL;
78543693Sbrian        }
78643693Sbrian        bp = mbuf_Read(bp, ans, len);
78743693Sbrian        ans[len] = '\0';
78843693Sbrian        break;
78943401Sbrian    }
79036285Sbrian
79143693Sbrian    switch (chap->auth.in.hdr.code) {
79243693Sbrian      case CHAP_CHALLENGE:
79343693Sbrian      case CHAP_RESPONSE:
79443693Sbrian        if (*chap->auth.in.name)
79544106Sbrian          log_Printf(LogPHASE, "Chap Input: %s (%d bytes from %s%s)\n",
79644106Sbrian                     chapcodes[chap->auth.in.hdr.code], alen,
79744106Sbrian                     chap->auth.in.name,
79893418Sbrian#ifndef NODES
79944106Sbrian                     lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
80044123Sbrian                     " - lanman" :
80144123Sbrian#endif
80244123Sbrian                     "");
80343693Sbrian        else
80444106Sbrian          log_Printf(LogPHASE, "Chap Input: %s (%d bytes%s)\n",
80544106Sbrian                     chapcodes[chap->auth.in.hdr.code], alen,
80693418Sbrian#ifndef NODES
80744106Sbrian                     lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
80844123Sbrian                     " - lanman" :
80944123Sbrian#endif
81044123Sbrian                     "");
81143693Sbrian        break;
81236285Sbrian
81343693Sbrian      case CHAP_SUCCESS:
81443693Sbrian      case CHAP_FAILURE:
81543693Sbrian        if (*ans)
81643693Sbrian          log_Printf(LogPHASE, "Chap Input: %s (%s)\n",
81743693Sbrian                     chapcodes[chap->auth.in.hdr.code], ans);
81843693Sbrian        else
81943693Sbrian          log_Printf(LogPHASE, "Chap Input: %s\n",
82043693Sbrian                     chapcodes[chap->auth.in.hdr.code]);
82143693Sbrian        break;
8226059Samurai    }
8236059Samurai
82443693Sbrian    switch (chap->auth.in.hdr.code) {
82543693Sbrian      case CHAP_CHALLENGE:
82664465Sbrian        if (*bundle->cfg.auth.key == '!' && bundle->cfg.auth.key[1] != '!')
82746686Sbrian          chap_StartChild(chap, bundle->cfg.auth.key + 1,
82846686Sbrian                          bundle->cfg.auth.name);
82943888Sbrian        else
83064465Sbrian          chap_Respond(chap, bundle->cfg.auth.name, bundle->cfg.auth.key +
83164465Sbrian                       (*bundle->cfg.auth.key == '!' ? 1 : 0),
83264465Sbrian                       p->link.lcp.his_authtype
83393418Sbrian#ifndef NODES
83444123Sbrian                       , lanman
83544123Sbrian#endif
83644123Sbrian                      );
83743693Sbrian        break;
8386059Samurai
83943693Sbrian      case CHAP_RESPONSE:
84043693Sbrian        name = chap->auth.in.name;
84143693Sbrian        nlen = strlen(name);
84296730Sbrian#ifndef NODES
84396730Sbrian        if (p->link.lcp.want_authtype == 0x81) {
84498311Sbrian          struct MSCHAPv2_resp *resp = (struct MSCHAPv2_resp *)(ans + 1);
84598311Sbrian
84698311Sbrian          chap->challenge.peer[0] = sizeof resp->PeerChallenge;
84798311Sbrian          memcpy(chap->challenge.peer + 1, resp->PeerChallenge,
84898311Sbrian                 sizeof resp->PeerChallenge);
84996730Sbrian        }
85096730Sbrian#endif
85196730Sbrian
85243693Sbrian#ifndef NORADIUS
85396730Sbrian        if (*bundle->radius.cfg.file) {
85496730Sbrian          if (!radius_Authenticate(&bundle->radius, &chap->auth,
85596730Sbrian                                   chap->auth.in.name, ans, alen + 1,
85696730Sbrian                                   chap->challenge.local + 1,
85798311Sbrian                                   *chap->challenge.local))
85896730Sbrian            chap_Failure(&chap->auth);
85996730Sbrian        } else
86043693Sbrian#endif
86143693Sbrian        {
86298311Sbrian          if (p->link.lcp.want_authtype == 0x81 && ans[alen] != '\0' &&
86398311Sbrian              alen == sizeof(struct MSCHAPv2_resp)) {
86498311Sbrian            struct MSCHAPv2_resp *resp = (struct MSCHAPv2_resp *)(ans + 1);
86598311Sbrian
86698311Sbrian            log_Printf(LogWARN, "%s: Compensating for corrupt (Win98/WinME?) "
86798311Sbrian                       "CHAP81 RESPONSE\n", l->name);
86898311Sbrian            resp->Flags = '\0';	/* rfc2759 says it *MUST* be zero */
86998311Sbrian          }
87046686Sbrian          key = auth_GetSecret(bundle, name, nlen, p);
87143693Sbrian          if (key) {
87293418Sbrian#ifndef NODES
87367910Sbrian            if (p->link.lcp.want_authtype == 0x80 &&
87467910Sbrian                lanman && !IsEnabled(p->link.lcp.cfg.chap80lm)) {
87544106Sbrian              log_Printf(LogPHASE, "Auth failure: LANMan not enabled\n");
87644106Sbrian              if (chap_HaveAnotherGo(chap))
87744106Sbrian                break;
87843693Sbrian              key = NULL;
87967910Sbrian            } else if (p->link.lcp.want_authtype == 0x80 &&
88067910Sbrian                !lanman && !IsEnabled(p->link.lcp.cfg.chap80nt)) {
88144106Sbrian              log_Printf(LogPHASE, "Auth failure: mschap not enabled\n");
88244106Sbrian              if (chap_HaveAnotherGo(chap))
88344106Sbrian                break;
88444106Sbrian              key = NULL;
88567910Sbrian            } else if (p->link.lcp.want_authtype == 0x81 &&
88667910Sbrian                !IsEnabled(p->link.lcp.cfg.chap81)) {
88767910Sbrian              log_Printf(LogPHASE, "Auth failure: CHAP81 not enabled\n");
88867910Sbrian              key = NULL;
88944123Sbrian            } else
89044123Sbrian#endif
89144123Sbrian            {
89298311Sbrian              char *myans = chap_BuildAnswer(name, key, chap->auth.id,
89398311Sbrian                                             chap->challenge.local,
89444123Sbrian                                       p->link.lcp.want_authtype
89593418Sbrian#ifndef NODES
89667910Sbrian                                       , chap->challenge.peer,
89768461Sbrian                                       chap->authresponse, lanman);
89868461Sbrian              MPPE_IsServer = 1;		/* XXX Global ! */
89968461Sbrian#else
90068461Sbrian                                      );
90144123Sbrian#endif
90244106Sbrian              if (myans == NULL)
90343693Sbrian                key = NULL;
90444106Sbrian              else {
90544123Sbrian                if (!chap_Cmp(p->link.lcp.want_authtype, myans + 1, *myans,
90644123Sbrian                              ans + 1, alen
90793418Sbrian#ifndef NODES
90844123Sbrian                              , lanman
90944123Sbrian#endif
91044123Sbrian                             ))
91144106Sbrian                  key = NULL;
91244106Sbrian                free(myans);
91344106Sbrian              }
91443693Sbrian            }
91543693Sbrian          }
9166059Samurai
91743693Sbrian          if (key)
91843693Sbrian            chap_Success(&chap->auth);
91943693Sbrian          else
92043693Sbrian            chap_Failure(&chap->auth);
92143693Sbrian        }
9226059Samurai
92343693Sbrian        break;
9246059Samurai
9256059Samurai      case CHAP_SUCCESS:
92643693Sbrian        if (p->link.lcp.auth_iwait == PROTO_CHAP) {
92743693Sbrian          p->link.lcp.auth_iwait = 0;
92867910Sbrian          if (p->link.lcp.auth_ineed == 0) {
92993418Sbrian#ifndef NODES
93067910Sbrian            if (p->link.lcp.his_authtype == 0x81) {
93198149Sbrian              if (strncmp(ans, chap->authresponse, 42)) {
93267910Sbrian                datalink_AuthNotOk(p->dl);
93381094Sbrian	        log_Printf(LogWARN, "CHAP81: AuthenticatorResponse: (%.42s)"
93481094Sbrian                           " != ans: (%.42s)\n", chap->authresponse, ans);
93598243Sbrian
93667910Sbrian              } else {
93767910Sbrian                /* Successful login */
93868461Sbrian                MPPE_MasterKeyValid = 1;		/* XXX Global ! */
93967910Sbrian                datalink_AuthOk(p->dl);
94067910Sbrian              }
94167910Sbrian            } else
94267910Sbrian#endif
94343693Sbrian            /*
94443693Sbrian             * We've succeeded in our ``login''
94543693Sbrian             * If we're not expecting  the peer to authenticate (or he already
94643693Sbrian             * has), proceed to network phase.
94743693Sbrian             */
94843693Sbrian            datalink_AuthOk(p->dl);
94967910Sbrian          }
95043693Sbrian        }
95143693Sbrian        break;
95243693Sbrian
9536059Samurai      case CHAP_FAILURE:
95443693Sbrian        datalink_AuthNotOk(p->dl);
95543693Sbrian        break;
9566059Samurai    }
95743693Sbrian    free(ans);
9586059Samurai  }
95943693Sbrian
96054912Sbrian  m_freem(bp);
96146686Sbrian  return NULL;
9626059Samurai}
963