chap.c revision 44106
16059Samurai/*
26059Samurai *			PPP CHAP Module
36059Samurai *
46059Samurai *	    Written by Toshiharu OHNO (tony-o@iij.ad.jp)
56059Samurai *
66059Samurai *   Copyright (C) 1993, Internet Initiative Japan, Inc. All rights reserverd.
76059Samurai *
86059Samurai * Redistribution and use in source and binary forms are permitted
96059Samurai * provided that the above copyright notice and this paragraph are
106059Samurai * duplicated in all such forms and that any documentation,
116059Samurai * advertising materials, and other materials related to such
126059Samurai * distribution and use acknowledge that the software was developed
136059Samurai * by the Internet Initiative Japan, Inc.  The name of the
146059Samurai * IIJ may not be used to endorse or promote products derived
156059Samurai * from this software without specific prior written permission.
166059Samurai * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
176059Samurai * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
186059Samurai * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
198857Srgrimes *
2044106Sbrian * $Id: chap.c,v 1.43 1999/02/11 10:14:07 brian Exp $
218857Srgrimes *
226059Samurai *	TODO:
236059Samurai */
2443313Sbrian#include <sys/param.h>
2530715Sbrian#include <netinet/in.h>
2636285Sbrian#include <netinet/in_systm.h>
2736285Sbrian#include <netinet/ip.h>
2836285Sbrian#include <sys/un.h>
2930715Sbrian
3043888Sbrian#include <errno.h>
3143888Sbrian#include <fcntl.h>
3237192Sbrian#ifdef HAVE_DES
3336287Sbrian#include <md4.h>
3437192Sbrian#endif
3530715Sbrian#include <md5.h>
3643888Sbrian#include <paths.h>
3743888Sbrian#include <signal.h>
3830715Sbrian#include <stdlib.h>
3944106Sbrian#include <string.h>
4043888Sbrian#include <sys/wait.h>
4136285Sbrian#include <termios.h>
4243888Sbrian#include <unistd.h>
4329840Sbrian
4430715Sbrian#include "mbuf.h"
4530715Sbrian#include "log.h"
4630715Sbrian#include "defs.h"
4730715Sbrian#include "timer.h"
486059Samurai#include "fsm.h"
496059Samurai#include "lcpproto.h"
506059Samurai#include "lcp.h"
5136285Sbrian#include "lqr.h"
526059Samurai#include "hdlc.h"
536735Samurai#include "auth.h"
5436285Sbrian#include "async.h"
5536285Sbrian#include "throughput.h"
5636285Sbrian#include "descriptor.h"
5743888Sbrian#include "chap.h"
5836285Sbrian#include "iplist.h"
5936285Sbrian#include "slcompress.h"
6036285Sbrian#include "ipcp.h"
6136285Sbrian#include "filter.h"
6236285Sbrian#include "ccp.h"
6336285Sbrian#include "link.h"
6436285Sbrian#include "physical.h"
6536285Sbrian#include "mp.h"
6643313Sbrian#ifndef NORADIUS
6743313Sbrian#include "radius.h"
6843313Sbrian#endif
6936285Sbrian#include "bundle.h"
7036285Sbrian#include "chat.h"
7138174Sbrian#include "cbcp.h"
7243888Sbrian#include "command.h"
7336285Sbrian#include "datalink.h"
7437192Sbrian#ifdef HAVE_DES
7536287Sbrian#include "chap_ms.h"
7637192Sbrian#endif
776059Samurai
7831343Sbrianstatic const char *chapcodes[] = {
7919866Sphk  "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE"
806059Samurai};
8143693Sbrian#define MAXCHAPCODE (sizeof chapcodes / sizeof chapcodes[0] - 1)
826059Samurai
8330715Sbrianstatic void
8436285SbrianChapOutput(struct physical *physical, u_int code, u_int id,
8543693Sbrian	   const u_char *ptr, int count, const char *text)
866059Samurai{
876059Samurai  int plen;
886059Samurai  struct fsmheader lh;
896059Samurai  struct mbuf *bp;
906059Samurai
9128679Sbrian  plen = sizeof(struct fsmheader) + count;
926059Samurai  lh.code = code;
936059Samurai  lh.id = id;
946059Samurai  lh.length = htons(plen);
9536285Sbrian  bp = mbuf_Alloc(plen, MB_FSM);
9630715Sbrian  memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
976059Samurai  if (count)
9830715Sbrian    memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count);
9936285Sbrian  log_DumpBp(LogDEBUG, "ChapOutput", bp);
10037926Sbrian  if (text == NULL)
10137926Sbrian    log_Printf(LogPHASE, "Chap Output: %s\n", chapcodes[code]);
10237926Sbrian  else
10337926Sbrian    log_Printf(LogPHASE, "Chap Output: %s (%s)\n", chapcodes[code], text);
10436285Sbrian  hdlc_Output(&physical->link, PRI_LINK, PROTO_CHAP, bp);
1056059Samurai}
1066059Samurai
10743693Sbrianstatic char *
10844106Sbrianchap_BuildAnswer(char *name, char *key, u_char id, char *challenge,
10944106Sbrian                 u_char type, int lanman)
1106059Samurai{
11143693Sbrian  char *result, *digest;
11243693Sbrian  size_t nlen, klen;
11343693Sbrian
11443693Sbrian  nlen = strlen(name);
11543693Sbrian  klen = strlen(key);
11643693Sbrian
11743693Sbrian#ifdef HAVE_DES
11844106Sbrian  if (type == 0x80) {
11943693Sbrian    char expkey[AUTHLEN << 2];
12043693Sbrian    MD4_CTX MD4context;
12143693Sbrian    int f;
12243693Sbrian
12343693Sbrian    if ((result = malloc(1 + nlen + MS_CHAP_RESPONSE_LEN)) == NULL)
12443693Sbrian      return result;
12543693Sbrian
12644106Sbrian    digest = result;					/* the response */
12744106Sbrian    *digest++ = MS_CHAP_RESPONSE_LEN;			/* 49 */
12844106Sbrian    memcpy(digest + MS_CHAP_RESPONSE_LEN, name, nlen);
12944106Sbrian    if (lanman) {
13044106Sbrian      memset(digest + 24, '\0', 25);
13144106Sbrian      mschap_LANMan(digest, challenge + 1, key);	/* LANMan response */
13244106Sbrian    } else {
13344106Sbrian      memset(digest, '\0', 25);
13444106Sbrian      digest += 24;
13543693Sbrian
13644106Sbrian      for (f = 0; f < klen; f++) {
13744106Sbrian        expkey[2*f] = key[f];
13844106Sbrian        expkey[2*f+1] = '\0';
13944106Sbrian      }
14044106Sbrian      /*
14144106Sbrian       *           -----------
14244106Sbrian       * expkey = | k\0e\0y\0 |
14344106Sbrian       *           -----------
14444106Sbrian       */
14544106Sbrian      MD4Init(&MD4context);
14644106Sbrian      MD4Update(&MD4context, expkey, klen << 1);
14744106Sbrian      MD4Final(digest, &MD4context);
14844106Sbrian
14944106Sbrian      /*
15044106Sbrian       *           ---- -------- ---------------- ------- ------
15144106Sbrian       * result = | 49 | LANMan | 16 byte digest | 9 * ? | name |
15244106Sbrian       *           ---- -------- ---------------- ------- ------
15344106Sbrian       */
15444106Sbrian      mschap_NT(digest, challenge + 1);
15543693Sbrian    }
15643693Sbrian    /*
15744106Sbrian     *           ---- -------- ------------- ----- ------
15844106Sbrian     *          |    |  struct MS_ChapResponse24  |      |
15944106Sbrian     * result = | 49 | LANMan  |  NT digest | 0/1 | name |
16044106Sbrian     *           ---- -------- ------------- ----- ------
16144106Sbrian     * where only one of LANMan & NT digest are set.
16243693Sbrian     */
16343693Sbrian  } else
16443693Sbrian#endif
16543693Sbrian  if ((result = malloc(nlen + 17)) != NULL) {
16643693Sbrian    /* Normal MD5 stuff */
16743693Sbrian    MD5_CTX MD5context;
16843693Sbrian
16943693Sbrian    digest = result;
17043693Sbrian    *digest++ = 16;				/* value size */
17143693Sbrian
17243693Sbrian    MD5Init(&MD5context);
17343693Sbrian    MD5Update(&MD5context, &id, 1);
17443693Sbrian    MD5Update(&MD5context, key, klen);
17543693Sbrian    MD5Update(&MD5context, challenge + 1, *challenge);
17643693Sbrian    MD5Final(digest, &MD5context);
17743693Sbrian
17843693Sbrian    memcpy(digest + 16, name, nlen);
17943693Sbrian    /*
18043693Sbrian     *           ---- -------- ------
18143693Sbrian     * result = | 16 | digest | name |
18243693Sbrian     *           ---- -------- ------
18343693Sbrian     */
18443693Sbrian  }
18543693Sbrian
18643693Sbrian  return result;
18743693Sbrian}
18843693Sbrian
18943693Sbrianstatic void
19043888Sbrianchap_StartChild(struct chap *chap, char *prog, const char *name)
19143888Sbrian{
19243888Sbrian  char *argv[MAXARGS], *nargv[MAXARGS];
19343888Sbrian  int argc, fd;
19443888Sbrian  int in[2], out[2];
19543888Sbrian
19643888Sbrian  if (chap->child.fd != -1) {
19743888Sbrian    log_Printf(LogWARN, "Chap: %s: Program already running\n", prog);
19843888Sbrian    return;
19943888Sbrian  }
20043888Sbrian
20143888Sbrian  if (pipe(in) == -1) {
20243888Sbrian    log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno));
20343888Sbrian    return;
20443888Sbrian  }
20543888Sbrian
20643888Sbrian  if (pipe(out) == -1) {
20743888Sbrian    log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno));
20843888Sbrian    close(in[0]);
20943888Sbrian    close(in[1]);
21043888Sbrian    return;
21143888Sbrian  }
21243888Sbrian
21343888Sbrian  switch ((chap->child.pid = fork())) {
21443888Sbrian    case -1:
21543888Sbrian      log_Printf(LogERROR, "Chap: fork: %s\n", strerror(errno));
21643888Sbrian      close(in[0]);
21743888Sbrian      close(in[1]);
21843888Sbrian      close(out[0]);
21943888Sbrian      close(out[1]);
22043888Sbrian      chap->child.pid = 0;
22143888Sbrian      return;
22243888Sbrian
22343888Sbrian    case 0:
22443888Sbrian      timer_TermService();
22543888Sbrian      close(in[1]);
22643888Sbrian      close(out[0]);
22743888Sbrian      if (out[1] == STDIN_FILENO) {
22843888Sbrian        fd = dup(out[1]);
22943888Sbrian        close(out[1]);
23043888Sbrian        out[1] = fd;
23143888Sbrian      }
23243888Sbrian      dup2(in[0], STDIN_FILENO);
23343888Sbrian      dup2(out[1], STDOUT_FILENO);
23443888Sbrian      if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) {
23543888Sbrian        log_Printf(LogALERT, "Chap: Failed to open %s: %s\n",
23643888Sbrian                  _PATH_DEVNULL, strerror(errno));
23743888Sbrian        exit(1);
23843888Sbrian      }
23943888Sbrian      dup2(fd, STDERR_FILENO);
24043888Sbrian      fcntl(3, F_SETFD, 1);		/* Set close-on-exec flag */
24143888Sbrian
24243888Sbrian      setuid(geteuid());
24343888Sbrian      argc = command_Interpret(prog, strlen(prog), argv);
24443888Sbrian      command_Expand(nargv, argc, (char const *const *)argv,
24543888Sbrian                     chap->auth.physical->dl->bundle, 0);
24643888Sbrian      execvp(nargv[0], nargv);
24743888Sbrian
24843888Sbrian      log_Printf(LogWARN, "exec() of %s failed: %s\n",
24943888Sbrian                nargv[0], strerror(errno));
25043888Sbrian      exit(255);
25143888Sbrian
25243888Sbrian    default:
25343888Sbrian      close(in[0]);
25443888Sbrian      close(out[1]);
25543888Sbrian      chap->child.fd = out[0];
25643888Sbrian      chap->child.buf.len = 0;
25743888Sbrian      write(in[1], chap->auth.in.name, strlen(chap->auth.in.name));
25843888Sbrian      write(in[1], "\n", 1);
25943888Sbrian      write(in[1], chap->challenge + 1, *chap->challenge);
26043888Sbrian      write(in[1], "\n", 1);
26143888Sbrian      write(in[1], name, strlen(name));
26243888Sbrian      write(in[1], "\n", 1);
26343888Sbrian      close(in[1]);
26443888Sbrian      break;
26543888Sbrian  }
26643888Sbrian}
26743888Sbrian
26843888Sbrianstatic void
26943888Sbrianchap_Cleanup(struct chap *chap, int sig)
27043888Sbrian{
27143888Sbrian  if (chap->child.pid) {
27243888Sbrian    int status;
27343888Sbrian
27443888Sbrian    close(chap->child.fd);
27543888Sbrian    chap->child.fd = -1;
27643888Sbrian    if (sig)
27743888Sbrian      kill(chap->child.pid, SIGTERM);
27843888Sbrian    chap->child.pid = 0;
27943888Sbrian    chap->child.buf.len = 0;
28043888Sbrian
28143888Sbrian    if (wait(&status) == -1)
28243888Sbrian      log_Printf(LogERROR, "Chap: wait: %s\n", strerror(errno));
28343888Sbrian    else if (WIFSIGNALED(status))
28443888Sbrian      log_Printf(LogWARN, "Chap: Child received signal %d\n", WTERMSIG(status));
28543888Sbrian    else if (WIFEXITED(status) && WEXITSTATUS(status))
28643888Sbrian      log_Printf(LogERROR, "Chap: Child exited %d\n", WEXITSTATUS(status));
28743888Sbrian  }
28843888Sbrian  *chap->challenge = 0;
28944106Sbrian  chap->peertries = 0;
29043888Sbrian}
29143888Sbrian
29243888Sbrianstatic void
29344106Sbrianchap_Respond(struct chap *chap, char *name, char *key, u_char type, int lm)
29443888Sbrian{
29544106Sbrian  u_char *ans;
29643888Sbrian
29744106Sbrian  ans = chap_BuildAnswer(name, key, chap->auth.id, chap->challenge, type, lm);
29843888Sbrian
29943888Sbrian  if (ans) {
30043888Sbrian    ChapOutput(chap->auth.physical, CHAP_RESPONSE, chap->auth.id,
30143888Sbrian               ans, *ans + 1 + strlen(name), name);
30244106Sbrian    chap->NTRespSent = !lm;
30343888Sbrian    free(ans);
30443888Sbrian  } else
30543888Sbrian    ChapOutput(chap->auth.physical, CHAP_FAILURE, chap->auth.id,
30643888Sbrian               "Out of memory!", 14, NULL);
30743888Sbrian}
30843888Sbrian
30943888Sbrianstatic int
31043888Sbrianchap_UpdateSet(struct descriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
31143888Sbrian{
31243888Sbrian  struct chap *chap = descriptor2chap(d);
31343888Sbrian
31443888Sbrian  if (r && chap && chap->child.fd != -1) {
31543888Sbrian    FD_SET(chap->child.fd, r);
31643888Sbrian    if (*n < chap->child.fd + 1)
31743888Sbrian      *n = chap->child.fd + 1;
31843888Sbrian    log_Printf(LogTIMER, "Chap: fdset(r) %d\n", chap->child.fd);
31943888Sbrian    return 1;
32043888Sbrian  }
32143888Sbrian
32243888Sbrian  return 0;
32343888Sbrian}
32443888Sbrian
32543888Sbrianstatic int
32643888Sbrianchap_IsSet(struct descriptor *d, const fd_set *fdset)
32743888Sbrian{
32843888Sbrian  struct chap *chap = descriptor2chap(d);
32943888Sbrian
33043888Sbrian  return chap && chap->child.fd != -1 && FD_ISSET(chap->child.fd, fdset);
33143888Sbrian}
33243888Sbrian
33343888Sbrianstatic void
33443888Sbrianchap_Read(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
33543888Sbrian{
33643888Sbrian  struct chap *chap = descriptor2chap(d);
33743888Sbrian  int got;
33843888Sbrian
33943888Sbrian  got = read(chap->child.fd, chap->child.buf.ptr + chap->child.buf.len,
34043888Sbrian             sizeof chap->child.buf.ptr - chap->child.buf.len - 1);
34143888Sbrian  if (got == -1) {
34243888Sbrian    log_Printf(LogERROR, "Chap: Read: %s\n", strerror(errno));
34343888Sbrian    chap_Cleanup(chap, SIGTERM);
34443888Sbrian  } else if (got == 0) {
34543888Sbrian    log_Printf(LogWARN, "Chap: Read: Child terminated connection\n");
34643888Sbrian    chap_Cleanup(chap, SIGTERM);
34743888Sbrian  } else {
34843888Sbrian    char *name, *key, *end;
34943888Sbrian
35043888Sbrian    chap->child.buf.len += got;
35143888Sbrian    chap->child.buf.ptr[chap->child.buf.len] = '\0';
35243888Sbrian    name = chap->child.buf.ptr;
35343888Sbrian    name += strspn(name, " \t");
35443888Sbrian    if ((key = strchr(name, '\n')) == NULL)
35543888Sbrian      end = NULL;
35643888Sbrian    else
35743888Sbrian      end = strchr(++key, '\n');
35843888Sbrian
35943888Sbrian    if (end == NULL) {
36043888Sbrian      if (chap->child.buf.len == sizeof chap->child.buf.ptr - 1) {
36143888Sbrian        log_Printf(LogWARN, "Chap: Read: Input buffer overflow\n");
36243888Sbrian        chap_Cleanup(chap, SIGTERM);
36343888Sbrian      }
36443888Sbrian    } else {
36544106Sbrian      int lanman = chap->auth.physical->link.lcp.his_authtype == 0x80 &&
36644106Sbrian                   ((chap->NTRespSent &&
36744106Sbrian                     IsAccepted(chap->auth.physical->link.lcp.cfg.chap80lm)) ||
36844106Sbrian                    !IsAccepted(chap->auth.physical->link.lcp.cfg.chap80nt));
36944106Sbrian
37043888Sbrian      while (end >= name && strchr(" \t\r\n", *end))
37143888Sbrian        *end-- = '\0';
37243888Sbrian      end = key - 1;
37343888Sbrian      while (end >= name && strchr(" \t\r\n", *end))
37443888Sbrian        *end-- = '\0';
37543888Sbrian      key += strspn(key, " \t");
37643888Sbrian
37744106Sbrian      chap_Respond(chap, name, key,
37844106Sbrian                   chap->auth.physical->link.lcp.his_authtype, lanman);
37943888Sbrian      chap_Cleanup(chap, 0);
38043888Sbrian    }
38143888Sbrian  }
38243888Sbrian}
38343888Sbrian
38443888Sbrianstatic int
38543888Sbrianchap_Write(struct descriptor *d, struct bundle *bundle, const fd_set *fdset)
38643888Sbrian{
38743888Sbrian  /* We never want to write here ! */
38843888Sbrian  log_Printf(LogALERT, "chap_Write: Internal error: Bad call !\n");
38943888Sbrian  return 0;
39043888Sbrian}
39143888Sbrian
39243888Sbrianstatic void
39343693Sbrianchap_Challenge(struct authinfo *authp)
39443693Sbrian{
39543693Sbrian  struct chap *chap = auth2chap(authp);
39613379Sphk  int len, i;
3976059Samurai  char *cp;
3986059Samurai
39943888Sbrian  len = strlen(authp->physical->dl->bundle->cfg.auth.name);
40043401Sbrian
40143888Sbrian  if (!*chap->challenge) {
40243888Sbrian    randinit();
40343888Sbrian    cp = chap->challenge;
40443888Sbrian
40543313Sbrian#ifndef NORADIUS
40643888Sbrian    if (*authp->physical->dl->bundle->radius.cfg.file) {
40743888Sbrian      /* For radius, our challenge is 16 readable NUL terminated bytes :*/
40843888Sbrian      *cp++ = 16;
40943888Sbrian      for (i = 0; i < 16; i++)
41043888Sbrian        *cp++ = (random() % 10) + '0';
41143888Sbrian    } else
41243313Sbrian#endif
41343888Sbrian    {
41444106Sbrian#ifdef HAVE_DES
41544106Sbrian      if (authp->physical->link.lcp.want_authtype == 0x80)
41644106Sbrian        *cp++ = 8;	/* MS does 8 byte callenges :-/ */
41744106Sbrian      else
41844106Sbrian#endif
41944106Sbrian        *cp++ = random() % (CHAPCHALLENGELEN-16) + 16;
42043888Sbrian      for (i = 0; i < *chap->challenge; i++)
42143888Sbrian        *cp++ = random() & 0xff;
42243888Sbrian    }
42343888Sbrian    memcpy(cp, authp->physical->dl->bundle->cfg.auth.name, len);
42443313Sbrian  }
42543693Sbrian  ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id, chap->challenge,
42643888Sbrian	     1 + *chap->challenge + len, NULL);
4276059Samurai}
4286059Samurai
42930715Sbrianstatic void
43043693Sbrianchap_Success(struct authinfo *authp)
4316059Samurai{
43243693Sbrian  datalink_GotAuthname(authp->physical->dl, authp->in.name);
43343693Sbrian  ChapOutput(authp->physical, CHAP_SUCCESS, authp->id, "Welcome!!", 10, NULL);
43443693Sbrian  authp->physical->link.lcp.auth_ineed = 0;
43543693Sbrian  if (Enabled(authp->physical->dl->bundle, OPT_UTMP))
43643693Sbrian    physical_Login(authp->physical, authp->in.name);
4376059Samurai
43843693Sbrian  if (authp->physical->link.lcp.auth_iwait == 0)
43943693Sbrian    /*
44043693Sbrian     * Either I didn't need to authenticate, or I've already been
44143693Sbrian     * told that I got the answer right.
44243693Sbrian     */
44343693Sbrian    datalink_AuthOk(authp->physical->dl);
44443693Sbrian}
4456059Samurai
44643693Sbrianstatic void
44743693Sbrianchap_Failure(struct authinfo *authp)
44843693Sbrian{
44943693Sbrian  ChapOutput(authp->physical, CHAP_FAILURE, authp->id, "Invalid!!", 9, NULL);
45043693Sbrian  datalink_AuthNotOk(authp->physical->dl);
45143693Sbrian}
45237926Sbrian
45344106Sbrianstatic int
45444106Sbrianchap_Cmp(u_char type, int lm, char *myans, int mylen, char *hisans, int hislen)
45544106Sbrian{
45644106Sbrian  if (mylen != hislen)
45744106Sbrian    return 0;
45844106Sbrian  else if (type == 0x80) {
45944106Sbrian    int off = lm ? 0 : 24;
46044106Sbrian
46144106Sbrian    if (memcmp(myans + off, hisans + off, 24))
46244106Sbrian      return 0;
46344106Sbrian  } else if (memcmp(myans, hisans, mylen))
46444106Sbrian    return 0;
46544106Sbrian
46644106Sbrian  return 1;
46744106Sbrian}
46844106Sbrian
46944106Sbrianstatic int
47044106Sbrianchap_HaveAnotherGo(struct chap *chap)
47144106Sbrian{
47244106Sbrian  if (++chap->peertries < 3) {
47344106Sbrian    /* Give the peer another shot */
47444106Sbrian    *chap->challenge = '\0';
47544106Sbrian    chap_Challenge(&chap->auth);
47644106Sbrian    return 1;
47744106Sbrian  }
47844106Sbrian
47944106Sbrian  return 0;
48044106Sbrian}
48144106Sbrian
48243693Sbrianvoid
48343693Sbrianchap_Init(struct chap *chap, struct physical *p)
48443693Sbrian{
48543888Sbrian  chap->desc.type = CHAP_DESCRIPTOR;
48643888Sbrian  chap->desc.UpdateSet = chap_UpdateSet;
48743888Sbrian  chap->desc.IsSet = chap_IsSet;
48843888Sbrian  chap->desc.Read = chap_Read;
48943888Sbrian  chap->desc.Write = chap_Write;
49043888Sbrian  chap->child.pid = 0;
49143888Sbrian  chap->child.fd = -1;
49243693Sbrian  auth_Init(&chap->auth, p, chap_Challenge, chap_Success, chap_Failure);
49343693Sbrian  *chap->challenge = 0;
49444106Sbrian  chap->NTRespSent = 0;
49544106Sbrian  chap->peertries = 0;
49643693Sbrian}
49729840Sbrian
49843693Sbrianvoid
49943888Sbrianchap_ReInit(struct chap *chap)
50043888Sbrian{
50143888Sbrian  chap_Cleanup(chap, SIGTERM);
50243888Sbrian}
50343888Sbrian
50443888Sbrianvoid
50543693Sbrianchap_Input(struct physical *p, struct mbuf *bp)
50643693Sbrian{
50743693Sbrian  struct chap *chap = &p->dl->chap;
50844106Sbrian  char *name, *key, *ans;
50944106Sbrian  int len, nlen, lanman;
51043693Sbrian  u_char alen;
51129840Sbrian
51243693Sbrian  if ((bp = auth_ReadHeader(&chap->auth, bp)) == NULL)
51343693Sbrian    log_Printf(LogERROR, "Chap Input: Truncated header !\n");
51443693Sbrian  else if (chap->auth.in.hdr.code == 0 || chap->auth.in.hdr.code > MAXCHAPCODE)
51543693Sbrian    log_Printf(LogPHASE, "Chap Input: %d: Bad CHAP code !\n",
51643693Sbrian               chap->auth.in.hdr.code);
51743693Sbrian  else {
51843693Sbrian    len = mbuf_Length(bp);
51943693Sbrian    ans = NULL;
52043693Sbrian
52143693Sbrian    if (chap->auth.in.hdr.code != CHAP_CHALLENGE &&
52243693Sbrian        chap->auth.id != chap->auth.in.hdr.id &&
52343693Sbrian        Enabled(p->dl->bundle, OPT_IDCHECK)) {
52443693Sbrian      /* Wrong conversation dude ! */
52543693Sbrian      log_Printf(LogPHASE, "Chap Input: %s dropped (got id %d, not %d)\n",
52643693Sbrian                 chapcodes[chap->auth.in.hdr.code], chap->auth.in.hdr.id,
52743693Sbrian                 chap->auth.id);
52843693Sbrian      mbuf_Free(bp);
52925630Sbrian      return;
53025630Sbrian    }
53143693Sbrian    chap->auth.id = chap->auth.in.hdr.id;	/* We respond with this id */
53229840Sbrian
53344106Sbrian    lanman = 0;
53443693Sbrian    switch (chap->auth.in.hdr.code) {
53543693Sbrian      case CHAP_CHALLENGE:
53644106Sbrian        bp = mbuf_Read(bp, &alen, 1);
53744106Sbrian        len -= alen + 1;
53843693Sbrian        if (len < 0) {
53943693Sbrian          log_Printf(LogERROR, "Chap Input: Truncated challenge !\n");
54043693Sbrian          mbuf_Free(bp);
54143693Sbrian          return;
54243693Sbrian        }
54344106Sbrian        *chap->challenge = alen;
54444106Sbrian        bp = mbuf_Read(bp, chap->challenge + 1, alen);
54543693Sbrian        bp = auth_ReadName(&chap->auth, bp, len);
54644106Sbrian        lanman = p->link.lcp.his_authtype == 0x80 &&
54744106Sbrian                 ((chap->NTRespSent && IsAccepted(p->link.lcp.cfg.chap80lm)) ||
54844106Sbrian                  !IsAccepted(p->link.lcp.cfg.chap80nt));
54943693Sbrian        break;
55043313Sbrian
55143693Sbrian      case CHAP_RESPONSE:
55243693Sbrian        auth_StopTimer(&chap->auth);
55343693Sbrian        bp = mbuf_Read(bp, &alen, 1);
55443693Sbrian        len -= alen + 1;
55543693Sbrian        if (len < 0) {
55643693Sbrian          log_Printf(LogERROR, "Chap Input: Truncated response !\n");
55743693Sbrian          mbuf_Free(bp);
55843693Sbrian          return;
55943693Sbrian        }
56043693Sbrian        if ((ans = malloc(alen + 2)) == NULL) {
56143693Sbrian          log_Printf(LogERROR, "Chap Input: Out of memory !\n");
56243693Sbrian          mbuf_Free(bp);
56343693Sbrian          return;
56443693Sbrian        }
56543693Sbrian        *ans = chap->auth.id;
56643693Sbrian        bp = mbuf_Read(bp, ans + 1, alen);
56743693Sbrian        ans[alen+1] = '\0';
56843693Sbrian        bp = auth_ReadName(&chap->auth, bp, len);
56944106Sbrian        lanman = alen == 49 && ans[alen] == 0;
57043693Sbrian        break;
57143313Sbrian
57243693Sbrian      case CHAP_SUCCESS:
57343693Sbrian      case CHAP_FAILURE:
57443693Sbrian        /* chap->auth.in.name is already set up at CHALLENGE time */
57543693Sbrian        if ((ans = malloc(len + 1)) == NULL) {
57643693Sbrian          log_Printf(LogERROR, "Chap Input: Out of memory !\n");
57743693Sbrian          mbuf_Free(bp);
57843693Sbrian          return;
57943693Sbrian        }
58043693Sbrian        bp = mbuf_Read(bp, ans, len);
58143693Sbrian        ans[len] = '\0';
58243693Sbrian        break;
58343401Sbrian    }
58436285Sbrian
58543693Sbrian    switch (chap->auth.in.hdr.code) {
58643693Sbrian      case CHAP_CHALLENGE:
58743693Sbrian      case CHAP_RESPONSE:
58843693Sbrian        if (*chap->auth.in.name)
58944106Sbrian          log_Printf(LogPHASE, "Chap Input: %s (%d bytes from %s%s)\n",
59044106Sbrian                     chapcodes[chap->auth.in.hdr.code], alen,
59144106Sbrian                     chap->auth.in.name,
59244106Sbrian                     lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
59344106Sbrian                     " - lanman" : "");
59443693Sbrian        else
59544106Sbrian          log_Printf(LogPHASE, "Chap Input: %s (%d bytes%s)\n",
59644106Sbrian                     chapcodes[chap->auth.in.hdr.code], alen,
59744106Sbrian                     lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
59844106Sbrian                     " - lanman" : "");
59943693Sbrian        break;
60036285Sbrian
60143693Sbrian      case CHAP_SUCCESS:
60243693Sbrian      case CHAP_FAILURE:
60343693Sbrian        if (*ans)
60443693Sbrian          log_Printf(LogPHASE, "Chap Input: %s (%s)\n",
60543693Sbrian                     chapcodes[chap->auth.in.hdr.code], ans);
60643693Sbrian        else
60743693Sbrian          log_Printf(LogPHASE, "Chap Input: %s\n",
60843693Sbrian                     chapcodes[chap->auth.in.hdr.code]);
60943693Sbrian        break;
6106059Samurai    }
6116059Samurai
61243693Sbrian    switch (chap->auth.in.hdr.code) {
61343693Sbrian      case CHAP_CHALLENGE:
61443888Sbrian        if (*p->dl->bundle->cfg.auth.key == '!')
61543888Sbrian          chap_StartChild(chap, p->dl->bundle->cfg.auth.key + 1,
61643888Sbrian                          p->dl->bundle->cfg.auth.name);
61743888Sbrian        else
61844106Sbrian          chap_Respond(chap, p->dl->bundle->cfg.auth.name,
61944106Sbrian                       p->dl->bundle->cfg.auth.key,
62044106Sbrian                       p->link.lcp.his_authtype, lanman);
62143693Sbrian        break;
6226059Samurai
62343693Sbrian      case CHAP_RESPONSE:
62443693Sbrian        name = chap->auth.in.name;
62543693Sbrian        nlen = strlen(name);
62643693Sbrian#ifndef NORADIUS
62743693Sbrian        if (*p->dl->bundle->radius.cfg.file) {
62843693Sbrian          chap->challenge[*chap->challenge+1] = '\0';
62943693Sbrian          radius_Authenticate(&p->dl->bundle->radius, &chap->auth,
63043693Sbrian                              chap->auth.in.name, ans, chap->challenge + 1);
63143693Sbrian        } else
63243693Sbrian#endif
63343693Sbrian        {
63443693Sbrian          key = auth_GetSecret(p->dl->bundle, name, nlen, p);
63543693Sbrian          if (key) {
63644106Sbrian            char *myans;
63744106Sbrian            if (lanman && !IsEnabled(p->link.lcp.cfg.chap80lm)) {
63844106Sbrian              log_Printf(LogPHASE, "Auth failure: LANMan not enabled\n");
63944106Sbrian              if (chap_HaveAnotherGo(chap))
64044106Sbrian                break;
64143693Sbrian              key = NULL;
64244106Sbrian            } else if (!lanman && !IsEnabled(p->link.lcp.cfg.chap80nt)) {
64344106Sbrian              log_Printf(LogPHASE, "Auth failure: mschap not enabled\n");
64444106Sbrian              if (chap_HaveAnotherGo(chap))
64544106Sbrian                break;
64644106Sbrian              key = NULL;
64744106Sbrian            } else {
64844106Sbrian              myans = chap_BuildAnswer(name, key, chap->auth.id,
64944106Sbrian                                       chap->challenge,
65044106Sbrian                                       p->link.lcp.want_authtype, lanman);
65144106Sbrian              if (myans == NULL)
65243693Sbrian                key = NULL;
65344106Sbrian              else {
65444106Sbrian                if (!chap_Cmp(p->link.lcp.want_authtype, lanman,
65544106Sbrian                              myans + 1, *myans, ans + 1, alen))
65644106Sbrian                  key = NULL;
65744106Sbrian                free(myans);
65844106Sbrian              }
65943693Sbrian            }
66043693Sbrian          }
6616059Samurai
66243693Sbrian          if (key)
66343693Sbrian            chap_Success(&chap->auth);
66443693Sbrian          else
66543693Sbrian            chap_Failure(&chap->auth);
66643693Sbrian        }
6676059Samurai
66843693Sbrian        break;
6696059Samurai
6706059Samurai      case CHAP_SUCCESS:
67143693Sbrian        if (p->link.lcp.auth_iwait == PROTO_CHAP) {
67243693Sbrian          p->link.lcp.auth_iwait = 0;
67343693Sbrian          if (p->link.lcp.auth_ineed == 0)
67443693Sbrian            /*
67543693Sbrian             * We've succeeded in our ``login''
67643693Sbrian             * If we're not expecting  the peer to authenticate (or he already
67743693Sbrian             * has), proceed to network phase.
67843693Sbrian             */
67943693Sbrian            datalink_AuthOk(p->dl);
68043693Sbrian        }
68143693Sbrian        break;
68243693Sbrian
6836059Samurai      case CHAP_FAILURE:
68443693Sbrian        datalink_AuthNotOk(p->dl);
68543693Sbrian        break;
6866059Samurai    }
68743693Sbrian    free(ans);
6886059Samurai  }
68943693Sbrian
69036285Sbrian  mbuf_Free(bp);
6916059Samurai}
692