chap.c revision 93418
155825Speter/*-
2218822Sdim * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
3114370Speter *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
439818Speter *                           Internet Initiative Japan, Inc (IIJ)
5114370Speter * All rights reserved.
639818Speter *
739818Speter * Redistribution and use in source and binary forms, with or without
839818Speter * modification, are permitted provided that the following conditions
9220090Salc * are met:
10220090Salc * 1. Redistributions of source code must retain the above copyright
11114370Speter *    notice, this list of conditions and the following disclaimer.
12114370Speter * 2. Redistributions in binary form must reproduce the above copyright
13218822Sdim *    notice, this list of conditions and the following disclaimer in the
14114370Speter *    documentation and/or other materials provided with the distribution.
15114370Speter *
16114370Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17114370Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18114370Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19114370Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20114370Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21114370Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22114370Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23114370Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24114370Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25114370Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26114370Speter * SUCH DAMAGE.
27218822Sdim *
28218822Sdim * $FreeBSD: head/usr.sbin/ppp/chap.c 93418 2002-03-30 12:30:09Z brian $
29114370Speter */
30114370Speter
31114370Speter#include <sys/param.h>
32114370Speter#include <netinet/in.h>
33114370Speter#include <netinet/in_systm.h>
34114370Speter#include <netinet/ip.h>
35114370Speter#include <sys/socket.h>
36114370Speter#include <sys/un.h>
37114370Speter
38114370Speter#include <errno.h>
39114370Speter#include <fcntl.h>
40114370Speter#ifndef NODES
41114370Speter#include <md4.h>
42114370Speter#endif
43218822Sdim#include <md5.h>
44218822Sdim#include <paths.h>
45218822Sdim#include <signal.h>
46218822Sdim#include <stdio.h>
47218822Sdim#include <stdlib.h>
48218822Sdim#include <string.h>
49114370Speter#include <sys/wait.h>
50114370Speter#include <termios.h>
51114370Speter#include <unistd.h>
5239818Speter
53114370Speter#include "layer.h"
54114370Speter#include "mbuf.h"
55114370Speter#include "log.h"
56114370Speter#include "defs.h"
57114370Speter#include "timer.h"
58114370Speter#include "fsm.h"
59218822Sdim#include "proto.h"
6039818Speter#include "lqr.h"
6139818Speter#include "hdlc.h"
62114370Speter#include "lcp.h"
63114370Speter#include "auth.h"
64114370Speter#include "async.h"
65114370Speter#include "throughput.h"
66114370Speter#include "descriptor.h"
67114370Speter#include "chap.h"
68114370Speter#include "iplist.h"
6939818Speter#include "slcompress.h"
70114370Speter#include "ncpaddr.h"
71114370Speter#include "ip.h"
72114370Speter#include "ipcp.h"
73218822Sdim#include "filter.h"
74218822Sdim#include "ccp.h"
7539818Speter#include "link.h"
7639818Speter#include "physical.h"
77218822Sdim#include "mp.h"
78218822Sdim#ifndef NORADIUS
79218822Sdim#include "radius.h"
80218822Sdim#endif
81218822Sdim#include "ipv6cp.h"
82218822Sdim#include "ncp.h"
83218822Sdim#include "bundle.h"
84218822Sdim#include "chat.h"
8539818Speter#include "cbcp.h"
86218822Sdim#include "command.h"
87218822Sdim#include "datalink.h"
88218822Sdim#ifndef NODES
8939818Speter#include "chap_ms.h"
90218822Sdim#include "mppe.h"
91218822Sdim#endif
92218822Sdim#include "id.h"
93218822Sdim
94218822Sdimstatic const char * const chapcodes[] = {
95218822Sdim  "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE"
96218822Sdim};
97218822Sdim#define MAXCHAPCODE (sizeof chapcodes / sizeof chapcodes[0] - 1)
98218822Sdim
99218822Sdimstatic void
100218822SdimChapOutput(struct physical *physical, u_int code, u_int id,
101218822Sdim	   const u_char *ptr, int count, const char *text)
102218822Sdim{
103218822Sdim  int plen;
104129824Stjr  struct fsmheader lh;
105129824Stjr  struct mbuf *bp;
106114370Speter
10739818Speter  plen = sizeof(struct fsmheader) + count;
108114370Speter  lh.code = code;
109114370Speter  lh.id = id;
110114370Speter  lh.length = htons(plen);
111114370Speter  bp = m_get(plen, MB_CHAPOUT);
112114370Speter  memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
113114370Speter  if (count)
114114370Speter    memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count);
115114370Speter  log_DumpBp(LogDEBUG, "ChapOutput", bp);
116114370Speter  if (text == NULL)
117114370Speter    log_Printf(LogPHASE, "Chap Output: %s\n", chapcodes[code]);
118218822Sdim  else
119114370Speter    log_Printf(LogPHASE, "Chap Output: %s (%s)\n", chapcodes[code], text);
120218822Sdim  link_PushPacket(&physical->link, bp, physical->dl->bundle,
121114370Speter                  LINK_QUEUES(&physical->link) - 1, PROTO_CHAP);
122114370Speter}
123218822Sdim
124114370Speterstatic char *
125114370Speterchap_BuildAnswer(char *name, char *key, u_char id, char *challenge, u_char type
12639818Speter#ifndef NODES
127129824Stjr                 , char *peerchallenge, char *authresponse, int lanman
128129824Stjr#endif
129114370Speter                )
13039818Speter{
131114370Speter  char *result, *digest;
132218822Sdim  size_t nlen, klen;
133218822Sdim
134114370Speter  nlen = strlen(name);
135114370Speter  klen = strlen(key);
13639818Speter
137114370Speter#ifndef NODES
138218822Sdim  if (type == 0x80) {
139218822Sdim    char expkey[AUTHLEN << 2];
140218822Sdim    MD4_CTX MD4context;
141218822Sdim    int f;
142218822Sdim
143218822Sdim    if ((result = malloc(1 + nlen + MS_CHAP_RESPONSE_LEN)) == NULL)
144218822Sdim      return result;
145218822Sdim
146218822Sdim    digest = result;					/* the response */
147218822Sdim    *digest++ = MS_CHAP_RESPONSE_LEN;			/* 49 */
148218822Sdim    memcpy(digest + MS_CHAP_RESPONSE_LEN, name, nlen);
149218822Sdim    if (lanman) {
150218822Sdim      memset(digest + 24, '\0', 25);
15139818Speter      mschap_LANMan(digest, challenge + 1, key);	/* LANMan response */
152114370Speter    } else {
15339818Speter      memset(digest, '\0', 25);
15439818Speter      digest += 24;
155114370Speter
15639818Speter      for (f = 0; f < klen; f++) {
157114370Speter        expkey[2*f] = key[f];
158114370Speter        expkey[2*f+1] = '\0';
159218822Sdim      }
160218822Sdim      /*
161218822Sdim       *           -----------
162218822Sdim       * expkey = | k\0e\0y\0 |
16339818Speter       *           -----------
164218822Sdim       */
165218822Sdim      MD4Init(&MD4context);
166218822Sdim      MD4Update(&MD4context, expkey, klen << 1);
167218822Sdim      MD4Final(digest, &MD4context);
168218822Sdim
169218822Sdim      /*
170114370Speter       *           ---- -------- ---------------- ------- ------
171218822Sdim       * result = | 49 | LANMan | 16 byte digest | 9 * ? | name |
172218822Sdim       *           ---- -------- ---------------- ------- ------
173218822Sdim       */
174218822Sdim      mschap_NT(digest, challenge + 1);
175218822Sdim    }
176218822Sdim    /*
177218822Sdim     *           ---- -------- ------------- ----- ------
178218822Sdim     *          |    |  struct MS_ChapResponse24  |      |
179218822Sdim     * result = | 49 | LANMan  |  NT digest | 0/1 | name |
180218822Sdim     *           ---- -------- ------------- ----- ------
181218822Sdim     * where only one of LANMan & NT digest are set.
182114370Speter     */
18339818Speter  } else if (type == 0x81) {
184114370Speter    char expkey[AUTHLEN << 2];
185114370Speter    char pwdhash[CHAP81_HASH_LEN];
186114370Speter    char pwdhashhash[CHAP81_HASH_LEN];
187114370Speter    char *ntresponse;
188114370Speter    int f;
18939818Speter
190114370Speter    if ((result = malloc(1 + nlen + CHAP81_RESPONSE_LEN)) == NULL)
19139818Speter      return result;
19239818Speter
19339818Speter    memset(result, 0, 1 + nlen + CHAP81_RESPONSE_LEN);
19439818Speter
19539818Speter    digest = result;
19639818Speter    *digest++ = CHAP81_RESPONSE_LEN;		/* value size */
19739818Speter
19839818Speter    /* Copy our challenge */
19939818Speter    memcpy(digest, peerchallenge + 1, CHAP81_CHALLENGE_LEN);
20039818Speter
20139818Speter    /* Expand password to Unicode XXX */
20239818Speter    for (f = 0; f < klen; f++) {
20339818Speter      expkey[2*f] = key[f];
204114370Speter      expkey[2*f+1] = '\0';
20539818Speter    }
20639818Speter
20739818Speter    ntresponse = digest + CHAP81_NTRESPONSE_OFF;
20839818Speter
20939818Speter    /* Get some needed hashes */
21039818Speter    NtPasswordHash(expkey, klen * 2, pwdhash);
21139818Speter    HashNtPasswordHash(pwdhash, pwdhashhash);
21239818Speter
21339818Speter    /* Generate NTRESPONSE to respond on challenge call */
21439818Speter    GenerateNTResponse(challenge + 1, peerchallenge + 1, name, nlen,
21539818Speter                       expkey, klen * 2, ntresponse);
216218822Sdim
217218822Sdim    /* Generate MPPE MASTERKEY */
218218822Sdim    GetMasterKey(pwdhashhash, ntresponse, MPPE_MasterKey);    /* XXX Global ! */
219218822Sdim
220218822Sdim    /* Generate AUTHRESPONSE to verify on auth success */
22139818Speter    GenerateAuthenticatorResponse(expkey, klen * 2, ntresponse,
222                                  peerchallenge + 1, challenge + 1, name, nlen,
223                                  authresponse);
224
225    authresponse[CHAP81_AUTHRESPONSE_LEN] = 0;
226
227    memcpy(digest + CHAP81_RESPONSE_LEN, name, nlen);
228  } else
229#endif
230  if ((result = malloc(nlen + 17)) != NULL) {
231    /* Normal MD5 stuff */
232    MD5_CTX MD5context;
233
234    digest = result;
235    *digest++ = 16;				/* value size */
236
237    MD5Init(&MD5context);
238    MD5Update(&MD5context, &id, 1);
239    MD5Update(&MD5context, key, klen);
240    MD5Update(&MD5context, challenge + 1, *challenge);
241    MD5Final(digest, &MD5context);
242
243    memcpy(digest + 16, name, nlen);
244    /*
245     *           ---- -------- ------
246     * result = | 16 | digest | name |
247     *           ---- -------- ------
248     */
249  }
250
251  return result;
252}
253
254static void
255chap_StartChild(struct chap *chap, char *prog, const char *name)
256{
257  char *argv[MAXARGS], *nargv[MAXARGS];
258  int argc, fd;
259  int in[2], out[2];
260  pid_t pid;
261
262  if (chap->child.fd != -1) {
263    log_Printf(LogWARN, "Chap: %s: Program already running\n", prog);
264    return;
265  }
266
267  if (pipe(in) == -1) {
268    log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno));
269    return;
270  }
271
272  if (pipe(out) == -1) {
273    log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno));
274    close(in[0]);
275    close(in[1]);
276    return;
277  }
278
279  pid = getpid();
280  switch ((chap->child.pid = fork())) {
281    case -1:
282      log_Printf(LogERROR, "Chap: fork: %s\n", strerror(errno));
283      close(in[0]);
284      close(in[1]);
285      close(out[0]);
286      close(out[1]);
287      chap->child.pid = 0;
288      return;
289
290    case 0:
291      timer_TermService();
292
293      if ((argc = command_Interpret(prog, strlen(prog), argv)) <= 0) {
294        if (argc < 0) {
295          log_Printf(LogWARN, "CHAP: Invalid command syntax\n");
296          _exit(255);
297        }
298        _exit(0);
299      }
300
301      close(in[1]);
302      close(out[0]);
303      if (out[1] == STDIN_FILENO)
304        out[1] = dup(out[1]);
305      dup2(in[0], STDIN_FILENO);
306      dup2(out[1], STDOUT_FILENO);
307      close(STDERR_FILENO);
308      if (open(_PATH_DEVNULL, O_RDWR) != STDERR_FILENO) {
309        log_Printf(LogALERT, "Chap: Failed to open %s: %s\n",
310                  _PATH_DEVNULL, strerror(errno));
311        exit(1);
312      }
313      for (fd = getdtablesize(); fd > STDERR_FILENO; fd--)
314        fcntl(fd, F_SETFD, 1);
315#ifndef NOSUID
316      setuid(ID0realuid());
317#endif
318      command_Expand(nargv, argc, (char const *const *)argv,
319                     chap->auth.physical->dl->bundle, 0, pid);
320      execvp(nargv[0], nargv);
321      printf("exec() of %s failed: %s\n", nargv[0], strerror(errno));
322      _exit(255);
323
324    default:
325      close(in[0]);
326      close(out[1]);
327      chap->child.fd = out[0];
328      chap->child.buf.len = 0;
329      write(in[1], chap->auth.in.name, strlen(chap->auth.in.name));
330      write(in[1], "\n", 1);
331      write(in[1], chap->challenge.peer + 1, *chap->challenge.peer);
332      write(in[1], "\n", 1);
333      write(in[1], name, strlen(name));
334      write(in[1], "\n", 1);
335      close(in[1]);
336      break;
337  }
338}
339
340static void
341chap_Cleanup(struct chap *chap, int sig)
342{
343  if (chap->child.pid) {
344    int status;
345
346    close(chap->child.fd);
347    chap->child.fd = -1;
348    if (sig)
349      kill(chap->child.pid, SIGTERM);
350    chap->child.pid = 0;
351    chap->child.buf.len = 0;
352
353    if (wait(&status) == -1)
354      log_Printf(LogERROR, "Chap: wait: %s\n", strerror(errno));
355    else if (WIFSIGNALED(status))
356      log_Printf(LogWARN, "Chap: Child received signal %d\n", WTERMSIG(status));
357    else if (WIFEXITED(status) && WEXITSTATUS(status))
358      log_Printf(LogERROR, "Chap: Child exited %d\n", WEXITSTATUS(status));
359  }
360  *chap->challenge.local = *chap->challenge.peer = '\0';
361#ifndef NODES
362  chap->peertries = 0;
363#endif
364}
365
366static void
367chap_Respond(struct chap *chap, char *name, char *key, u_char type
368#ifndef NODES
369             , int lm
370#endif
371            )
372{
373  u_char *ans;
374
375  ans = chap_BuildAnswer(name, key, chap->auth.id, chap->challenge.peer, type
376#ifndef NODES
377                         , chap->challenge.local, chap->authresponse, lm
378#endif
379                        );
380
381  if (ans) {
382    ChapOutput(chap->auth.physical, CHAP_RESPONSE, chap->auth.id,
383               ans, *ans + 1 + strlen(name), name);
384#ifndef NODES
385    chap->NTRespSent = !lm;
386    MPPE_IsServer = 0;		/* XXX Global ! */
387#endif
388    free(ans);
389  } else
390    ChapOutput(chap->auth.physical, CHAP_FAILURE, chap->auth.id,
391               "Out of memory!", 14, NULL);
392}
393
394static int
395chap_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
396{
397  struct chap *chap = descriptor2chap(d);
398
399  if (r && chap && chap->child.fd != -1) {
400    FD_SET(chap->child.fd, r);
401    if (*n < chap->child.fd + 1)
402      *n = chap->child.fd + 1;
403    log_Printf(LogTIMER, "Chap: fdset(r) %d\n", chap->child.fd);
404    return 1;
405  }
406
407  return 0;
408}
409
410static int
411chap_IsSet(struct fdescriptor *d, const fd_set *fdset)
412{
413  struct chap *chap = descriptor2chap(d);
414
415  return chap && chap->child.fd != -1 && FD_ISSET(chap->child.fd, fdset);
416}
417
418static void
419chap_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
420{
421  struct chap *chap = descriptor2chap(d);
422  int got;
423
424  got = read(chap->child.fd, chap->child.buf.ptr + chap->child.buf.len,
425             sizeof chap->child.buf.ptr - chap->child.buf.len - 1);
426  if (got == -1) {
427    log_Printf(LogERROR, "Chap: Read: %s\n", strerror(errno));
428    chap_Cleanup(chap, SIGTERM);
429  } else if (got == 0) {
430    log_Printf(LogWARN, "Chap: Read: Child terminated connection\n");
431    chap_Cleanup(chap, SIGTERM);
432  } else {
433    char *name, *key, *end;
434
435    chap->child.buf.len += got;
436    chap->child.buf.ptr[chap->child.buf.len] = '\0';
437    name = chap->child.buf.ptr;
438    name += strspn(name, " \t");
439    if ((key = strchr(name, '\n')) == NULL)
440      end = NULL;
441    else
442      end = strchr(++key, '\n');
443
444    if (end == NULL) {
445      if (chap->child.buf.len == sizeof chap->child.buf.ptr - 1) {
446        log_Printf(LogWARN, "Chap: Read: Input buffer overflow\n");
447        chap_Cleanup(chap, SIGTERM);
448      }
449    } else {
450#ifndef NODES
451      int lanman = chap->auth.physical->link.lcp.his_authtype == 0x80 &&
452                   ((chap->NTRespSent &&
453                     IsAccepted(chap->auth.physical->link.lcp.cfg.chap80lm)) ||
454                    !IsAccepted(chap->auth.physical->link.lcp.cfg.chap80nt));
455#endif
456
457      while (end >= name && strchr(" \t\r\n", *end))
458        *end-- = '\0';
459      end = key - 1;
460      while (end >= name && strchr(" \t\r\n", *end))
461        *end-- = '\0';
462      key += strspn(key, " \t");
463
464      chap_Respond(chap, name, key, chap->auth.physical->link.lcp.his_authtype
465#ifndef NODES
466                   , lanman
467#endif
468                  );
469      chap_Cleanup(chap, 0);
470    }
471  }
472}
473
474static int
475chap_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
476{
477  /* We never want to write here ! */
478  log_Printf(LogALERT, "chap_Write: Internal error: Bad call !\n");
479  return 0;
480}
481
482static void
483chap_ChallengeInit(struct authinfo *authp)
484{
485  struct chap *chap = auth2chap(authp);
486  int len, i;
487  char *cp;
488
489  len = strlen(authp->physical->dl->bundle->cfg.auth.name);
490
491  if (!*chap->challenge.local) {
492    randinit();
493    cp = chap->challenge.local;
494
495#ifndef NORADIUS
496    if (*authp->physical->dl->bundle->radius.cfg.file) {
497      /* For radius, our challenge is 16 readable NUL terminated bytes :*/
498      *cp++ = 16;
499      for (i = 0; i < 16; i++)
500        *cp++ = (random() % 10) + '0';
501    } else
502#endif
503    {
504#ifndef NODES
505      if (authp->physical->link.lcp.want_authtype == 0x80)
506        *cp++ = 8;	/* MS does 8 byte callenges :-/ */
507      else if (authp->physical->link.lcp.want_authtype == 0x81)
508        *cp++ = 16;	/* MS-CHAP-V2 does 16 bytes challenges */
509      else
510#endif
511        *cp++ = random() % (CHAPCHALLENGELEN-16) + 16;
512      for (i = 0; i < *chap->challenge.local; i++)
513        *cp++ = random() & 0xff;
514    }
515    memcpy(cp, authp->physical->dl->bundle->cfg.auth.name, len);
516  }
517}
518
519static void
520chap_Challenge(struct authinfo *authp)
521{
522  struct chap *chap = auth2chap(authp);
523  int len;
524
525  log_Printf(LogDEBUG, "CHAP%02X: Challenge\n",
526             authp->physical->link.lcp.want_authtype);
527
528  len = strlen(authp->physical->dl->bundle->cfg.auth.name);
529
530  /* Generate new local challenge value */
531  if (!*chap->challenge.local)
532    chap_ChallengeInit(authp);
533
534#ifndef NODES
535  if (authp->physical->link.lcp.want_authtype == 0x81)
536    ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id,
537             chap->challenge.local, 1 + *chap->challenge.local, NULL);
538  else
539#endif
540    ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id,
541             chap->challenge.local, 1 + *chap->challenge.local + len, NULL);
542}
543
544static void
545chap_Success(struct authinfo *authp)
546{
547  const char *msg;
548  datalink_GotAuthname(authp->physical->dl, authp->in.name);
549#ifndef NODES
550  if (authp->physical->link.lcp.want_authtype == 0x81) {
551    msg = auth2chap(authp)->authresponse;
552    MPPE_MasterKeyValid = 1;		/* XXX Global ! */
553  } else
554#endif
555    msg = "Welcome!!";
556
557  ChapOutput(authp->physical, CHAP_SUCCESS, authp->id, msg, strlen(msg),
558             NULL);
559
560  authp->physical->link.lcp.auth_ineed = 0;
561  if (Enabled(authp->physical->dl->bundle, OPT_UTMP))
562    physical_Login(authp->physical, authp->in.name);
563
564  if (authp->physical->link.lcp.auth_iwait == 0)
565    /*
566     * Either I didn't need to authenticate, or I've already been
567     * told that I got the answer right.
568     */
569    datalink_AuthOk(authp->physical->dl);
570}
571
572static void
573chap_Failure(struct authinfo *authp)
574{
575#ifndef NODES
576  char buf[1024];
577#endif
578  const char *msg;
579
580#ifndef NODES
581  if (authp->physical->link.lcp.want_authtype == 0x81) {
582    char *ptr;
583    int i;
584
585    ptr = buf;
586    ptr += sprintf(buf, "E=691 R=0 C=");
587    for (i=0; i<16; i++)
588      ptr += sprintf(ptr, "%02X", *(auth2chap(authp)->challenge.local+1+i));
589
590    sprintf(ptr, " V=3 M=Invalid!");
591    msg = buf;
592  } else
593#endif
594    msg = "Invalid!!";
595
596  ChapOutput(authp->physical, CHAP_FAILURE, authp->id, msg, strlen(msg) + 1,
597             NULL);
598  datalink_AuthNotOk(authp->physical->dl);
599}
600
601static int
602chap_Cmp(u_char type, char *myans, int mylen, char *hisans, int hislen
603#ifndef NODES
604         , int lm
605#endif
606        )
607{
608  if (mylen != hislen)
609    return 0;
610#ifndef NODES
611  else if (type == 0x80) {
612    int off = lm ? 0 : 24;
613
614    if (memcmp(myans + off, hisans + off, 24))
615      return 0;
616  }
617#endif
618  else if (memcmp(myans, hisans, mylen))
619    return 0;
620
621  return 1;
622}
623
624#ifndef NODES
625static int
626chap_HaveAnotherGo(struct chap *chap)
627{
628  if (++chap->peertries < 3) {
629    /* Give the peer another shot */
630    *chap->challenge.local = '\0';
631    chap_Challenge(&chap->auth);
632    return 1;
633  }
634
635  return 0;
636}
637#endif
638
639void
640chap_Init(struct chap *chap, struct physical *p)
641{
642  chap->desc.type = CHAP_DESCRIPTOR;
643  chap->desc.UpdateSet = chap_UpdateSet;
644  chap->desc.IsSet = chap_IsSet;
645  chap->desc.Read = chap_Read;
646  chap->desc.Write = chap_Write;
647  chap->child.pid = 0;
648  chap->child.fd = -1;
649  auth_Init(&chap->auth, p, chap_Challenge, chap_Success, chap_Failure);
650  *chap->challenge.local = *chap->challenge.peer = '\0';
651#ifndef NODES
652  chap->NTRespSent = 0;
653  chap->peertries = 0;
654#endif
655}
656
657void
658chap_ReInit(struct chap *chap)
659{
660  chap_Cleanup(chap, SIGTERM);
661}
662
663struct mbuf *
664chap_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
665{
666  struct physical *p = link2physical(l);
667  struct chap *chap = &p->dl->chap;
668  char *name, *key, *ans;
669  int len, nlen;
670  u_char alen;
671#ifndef NODES
672  int lanman;
673#endif
674
675  if (p == NULL) {
676    log_Printf(LogERROR, "chap_Input: Not a physical link - dropped\n");
677    m_freem(bp);
678    return NULL;
679  }
680
681  if (bundle_Phase(bundle) != PHASE_NETWORK &&
682      bundle_Phase(bundle) != PHASE_AUTHENTICATE) {
683    log_Printf(LogPHASE, "Unexpected chap input - dropped !\n");
684    m_freem(bp);
685    return NULL;
686  }
687
688  m_settype(bp, MB_CHAPIN);
689  if ((bp = auth_ReadHeader(&chap->auth, bp)) == NULL &&
690      ntohs(chap->auth.in.hdr.length) == 0)
691    log_Printf(LogWARN, "Chap Input: Truncated header !\n");
692  else if (chap->auth.in.hdr.code == 0 || chap->auth.in.hdr.code > MAXCHAPCODE)
693    log_Printf(LogPHASE, "Chap Input: %d: Bad CHAP code !\n",
694               chap->auth.in.hdr.code);
695  else {
696    len = m_length(bp);
697    ans = NULL;
698
699    if (chap->auth.in.hdr.code != CHAP_CHALLENGE &&
700        chap->auth.id != chap->auth.in.hdr.id &&
701        Enabled(bundle, OPT_IDCHECK)) {
702      /* Wrong conversation dude ! */
703      log_Printf(LogPHASE, "Chap Input: %s dropped (got id %d, not %d)\n",
704                 chapcodes[chap->auth.in.hdr.code], chap->auth.in.hdr.id,
705                 chap->auth.id);
706      m_freem(bp);
707      return NULL;
708    }
709    chap->auth.id = chap->auth.in.hdr.id;	/* We respond with this id */
710
711#ifndef NODES
712    lanman = 0;
713#endif
714    switch (chap->auth.in.hdr.code) {
715      case CHAP_CHALLENGE:
716        bp = mbuf_Read(bp, &alen, 1);
717        len -= alen + 1;
718        if (len < 0) {
719          log_Printf(LogERROR, "Chap Input: Truncated challenge !\n");
720          m_freem(bp);
721          return NULL;
722        }
723        *chap->challenge.peer = alen;
724        bp = mbuf_Read(bp, chap->challenge.peer + 1, alen);
725        bp = auth_ReadName(&chap->auth, bp, len);
726#ifndef NODES
727        lanman = p->link.lcp.his_authtype == 0x80 &&
728                 ((chap->NTRespSent && IsAccepted(p->link.lcp.cfg.chap80lm)) ||
729                  !IsAccepted(p->link.lcp.cfg.chap80nt));
730
731        /* Generate local challenge value */
732        chap_ChallengeInit(&chap->auth);
733#endif
734        break;
735
736      case CHAP_RESPONSE:
737        auth_StopTimer(&chap->auth);
738        bp = mbuf_Read(bp, &alen, 1);
739        len -= alen + 1;
740        if (len < 0) {
741          log_Printf(LogERROR, "Chap Input: Truncated response !\n");
742          m_freem(bp);
743          return NULL;
744        }
745        if ((ans = malloc(alen + 2)) == NULL) {
746          log_Printf(LogERROR, "Chap Input: Out of memory !\n");
747          m_freem(bp);
748          return NULL;
749        }
750        *ans = chap->auth.id;
751        bp = mbuf_Read(bp, ans + 1, alen);
752        if (p->link.lcp.want_authtype == 0x81 && ans[alen] != '\0') {
753          log_Printf(LogWARN, "%s: Compensating for corrupt (Win98/WinME?) "
754                     "CHAP81 RESPONSE\n", l->name);
755          ans[alen] = '\0';
756        }
757        ans[alen+1] = '\0';
758        bp = auth_ReadName(&chap->auth, bp, len);
759#ifndef NODES
760        lanman = p->link.lcp.want_authtype == 0x80 &&
761                 alen == 49 && ans[alen] == 0;
762#endif
763        break;
764
765      case CHAP_SUCCESS:
766      case CHAP_FAILURE:
767        /* chap->auth.in.name is already set up at CHALLENGE time */
768        if ((ans = malloc(len + 1)) == NULL) {
769          log_Printf(LogERROR, "Chap Input: Out of memory !\n");
770          m_freem(bp);
771          return NULL;
772        }
773        bp = mbuf_Read(bp, ans, len);
774        ans[len] = '\0';
775        break;
776    }
777
778    switch (chap->auth.in.hdr.code) {
779      case CHAP_CHALLENGE:
780      case CHAP_RESPONSE:
781        if (*chap->auth.in.name)
782          log_Printf(LogPHASE, "Chap Input: %s (%d bytes from %s%s)\n",
783                     chapcodes[chap->auth.in.hdr.code], alen,
784                     chap->auth.in.name,
785#ifndef NODES
786                     lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
787                     " - lanman" :
788#endif
789                     "");
790        else
791          log_Printf(LogPHASE, "Chap Input: %s (%d bytes%s)\n",
792                     chapcodes[chap->auth.in.hdr.code], alen,
793#ifndef NODES
794                     lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
795                     " - lanman" :
796#endif
797                     "");
798        break;
799
800      case CHAP_SUCCESS:
801      case CHAP_FAILURE:
802        if (*ans)
803          log_Printf(LogPHASE, "Chap Input: %s (%s)\n",
804                     chapcodes[chap->auth.in.hdr.code], ans);
805        else
806          log_Printf(LogPHASE, "Chap Input: %s\n",
807                     chapcodes[chap->auth.in.hdr.code]);
808        break;
809    }
810
811    switch (chap->auth.in.hdr.code) {
812      case CHAP_CHALLENGE:
813        if (*bundle->cfg.auth.key == '!' && bundle->cfg.auth.key[1] != '!')
814          chap_StartChild(chap, bundle->cfg.auth.key + 1,
815                          bundle->cfg.auth.name);
816        else
817          chap_Respond(chap, bundle->cfg.auth.name, bundle->cfg.auth.key +
818                       (*bundle->cfg.auth.key == '!' ? 1 : 0),
819                       p->link.lcp.his_authtype
820#ifndef NODES
821                       , lanman
822#endif
823                      );
824        break;
825
826      case CHAP_RESPONSE:
827        name = chap->auth.in.name;
828        nlen = strlen(name);
829#ifndef NORADIUS
830        if (*bundle->radius.cfg.file)
831          radius_Authenticate(&bundle->radius, &chap->auth,
832                              chap->auth.in.name, ans, alen + 1,
833                              chap->challenge.local + 1,
834                              *chap->challenge.local);
835        else
836#endif
837        {
838          key = auth_GetSecret(bundle, name, nlen, p);
839          if (key) {
840            char *myans;
841#ifndef NODES
842            if (p->link.lcp.want_authtype == 0x80 &&
843                lanman && !IsEnabled(p->link.lcp.cfg.chap80lm)) {
844              log_Printf(LogPHASE, "Auth failure: LANMan not enabled\n");
845              if (chap_HaveAnotherGo(chap))
846                break;
847              key = NULL;
848            } else if (p->link.lcp.want_authtype == 0x80 &&
849                !lanman && !IsEnabled(p->link.lcp.cfg.chap80nt)) {
850              log_Printf(LogPHASE, "Auth failure: mschap not enabled\n");
851              if (chap_HaveAnotherGo(chap))
852                break;
853              key = NULL;
854            } else if (p->link.lcp.want_authtype == 0x81 &&
855                !IsEnabled(p->link.lcp.cfg.chap81)) {
856              log_Printf(LogPHASE, "Auth failure: CHAP81 not enabled\n");
857              key = NULL;
858            } else
859#endif
860            {
861#ifndef NODES
862              /* Get peer's challenge */
863              if (p->link.lcp.want_authtype == 0x81) {
864                chap->challenge.peer[0] = CHAP81_CHALLENGE_LEN;
865                memcpy(chap->challenge.peer + 1, ans + 1, CHAP81_CHALLENGE_LEN);
866              }
867#endif
868
869              myans = chap_BuildAnswer(name, key, chap->auth.id,
870                                       chap->challenge.local,
871                                       p->link.lcp.want_authtype
872#ifndef NODES
873                                       , chap->challenge.peer,
874                                       chap->authresponse, lanman);
875              MPPE_IsServer = 1;		/* XXX Global ! */
876#else
877                                      );
878#endif
879              if (myans == NULL)
880                key = NULL;
881              else {
882                if (!chap_Cmp(p->link.lcp.want_authtype, myans + 1, *myans,
883                              ans + 1, alen
884#ifndef NODES
885                              , lanman
886#endif
887                             ))
888                  key = NULL;
889                free(myans);
890              }
891            }
892          }
893
894          if (key)
895            chap_Success(&chap->auth);
896          else
897            chap_Failure(&chap->auth);
898        }
899
900        break;
901
902      case CHAP_SUCCESS:
903        if (p->link.lcp.auth_iwait == PROTO_CHAP) {
904          p->link.lcp.auth_iwait = 0;
905          if (p->link.lcp.auth_ineed == 0) {
906#ifndef NODES
907            if (p->link.lcp.his_authtype == 0x81) {
908              if (strncmp(ans, chap->authresponse, 42)) {
909                datalink_AuthNotOk(p->dl);
910	        log_Printf(LogWARN, "CHAP81: AuthenticatorResponse: (%.42s)"
911                           " != ans: (%.42s)\n", chap->authresponse, ans);
912
913              } else {
914                /* Successful login */
915                MPPE_MasterKeyValid = 1;		/* XXX Global ! */
916                datalink_AuthOk(p->dl);
917              }
918            } else
919#endif
920            /*
921             * We've succeeded in our ``login''
922             * If we're not expecting  the peer to authenticate (or he already
923             * has), proceed to network phase.
924             */
925            datalink_AuthOk(p->dl);
926          }
927        }
928        break;
929
930      case CHAP_FAILURE:
931        datalink_AuthNotOk(p->dl);
932        break;
933    }
934    free(ans);
935  }
936
937  m_freem(bp);
938  return NULL;
939}
940