chap.c revision 96324
1/*-
2 * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
3 *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
4 *                           Internet Initiative Japan, Inc (IIJ)
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD: head/usr.sbin/ppp/chap.c 96324 2002-05-10 03:11:35Z brian $
29 */
30
31#include <sys/param.h>
32#include <netinet/in.h>
33#include <netinet/in_systm.h>
34#include <netinet/ip.h>
35#include <sys/socket.h>
36#include <sys/un.h>
37
38#include <errno.h>
39#include <fcntl.h>
40#ifndef NODES
41#include <md4.h>
42#endif
43#include <md5.h>
44#include <paths.h>
45#include <signal.h>
46#include <stdio.h>
47#include <stdlib.h>
48#include <string.h>
49#include <sys/wait.h>
50#include <termios.h>
51#include <unistd.h>
52
53#include "layer.h"
54#include "mbuf.h"
55#include "log.h"
56#include "defs.h"
57#include "timer.h"
58#include "fsm.h"
59#include "proto.h"
60#include "lqr.h"
61#include "hdlc.h"
62#include "lcp.h"
63#include "auth.h"
64#include "async.h"
65#include "throughput.h"
66#include "descriptor.h"
67#include "chap.h"
68#include "iplist.h"
69#include "slcompress.h"
70#include "ncpaddr.h"
71#include "ip.h"
72#include "ipcp.h"
73#include "filter.h"
74#include "ccp.h"
75#include "link.h"
76#include "physical.h"
77#include "mp.h"
78#ifndef NORADIUS
79#include "radius.h"
80#endif
81#include "ipv6cp.h"
82#include "ncp.h"
83#include "bundle.h"
84#include "chat.h"
85#include "cbcp.h"
86#include "command.h"
87#include "datalink.h"
88#ifndef NODES
89#include "chap_ms.h"
90#include "mppe.h"
91#endif
92#include "id.h"
93
94static const char * const chapcodes[] = {
95  "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE"
96};
97#define MAXCHAPCODE (sizeof chapcodes / sizeof chapcodes[0] - 1)
98
99static void
100ChapOutput(struct physical *physical, u_int code, u_int id,
101	   const u_char *ptr, int count, const char *text)
102{
103  int plen;
104  struct fsmheader lh;
105  struct mbuf *bp;
106
107  plen = sizeof(struct fsmheader) + count;
108  lh.code = code;
109  lh.id = id;
110  lh.length = htons(plen);
111  bp = m_get(plen, MB_CHAPOUT);
112  memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
113  if (count)
114    memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count);
115  log_DumpBp(LogDEBUG, "ChapOutput", bp);
116  if (text == NULL)
117    log_Printf(LogPHASE, "Chap Output: %s\n", chapcodes[code]);
118  else
119    log_Printf(LogPHASE, "Chap Output: %s (%s)\n", chapcodes[code], text);
120  link_PushPacket(&physical->link, bp, physical->dl->bundle,
121                  LINK_QUEUES(&physical->link) - 1, PROTO_CHAP);
122}
123
124static char *
125chap_BuildAnswer(char *name, char *key, u_char id, char *challenge, u_char type
126#ifndef NODES
127                 , char *peerchallenge, char *authresponse, int lanman
128#endif
129                )
130{
131  char *result, *digest;
132  size_t nlen, klen;
133
134  nlen = strlen(name);
135  klen = strlen(key);
136
137#ifndef NODES
138  if (type == 0x80) {
139    char expkey[AUTHLEN << 2];
140    MD4_CTX MD4context;
141    int f;
142
143    if ((result = malloc(1 + nlen + MS_CHAP_RESPONSE_LEN)) == NULL)
144      return result;
145
146    digest = result;					/* the response */
147    *digest++ = MS_CHAP_RESPONSE_LEN;			/* 49 */
148    memcpy(digest + MS_CHAP_RESPONSE_LEN, name, nlen);
149    if (lanman) {
150      memset(digest + 24, '\0', 25);
151      mschap_LANMan(digest, challenge + 1, key);	/* LANMan response */
152    } else {
153      memset(digest, '\0', 25);
154      digest += 24;
155
156      for (f = 0; f < klen; f++) {
157        expkey[2*f] = key[f];
158        expkey[2*f+1] = '\0';
159      }
160      /*
161       *           -----------
162       * expkey = | k\0e\0y\0 |
163       *           -----------
164       */
165      MD4Init(&MD4context);
166      MD4Update(&MD4context, expkey, klen << 1);
167      MD4Final(digest, &MD4context);
168
169      /*
170       *           ---- -------- ---------------- ------- ------
171       * result = | 49 | LANMan | 16 byte digest | 9 * ? | name |
172       *           ---- -------- ---------------- ------- ------
173       */
174      mschap_NT(digest, challenge + 1);
175    }
176    /*
177     *           ---- -------- ------------- ----- ------
178     *          |    |  struct MS_ChapResponse24  |      |
179     * result = | 49 | LANMan  |  NT digest | 0/1 | name |
180     *           ---- -------- ------------- ----- ------
181     * where only one of LANMan & NT digest are set.
182     */
183  } else if (type == 0x81) {
184    char expkey[AUTHLEN << 2];
185    char pwdhash[CHAP81_HASH_LEN];
186    char pwdhashhash[CHAP81_HASH_LEN];
187    char *ntresponse;
188    int f;
189
190    if ((result = malloc(1 + nlen + CHAP81_RESPONSE_LEN)) == NULL)
191      return result;
192
193    memset(result, 0, 1 + nlen + CHAP81_RESPONSE_LEN);
194
195    digest = result;
196    *digest++ = CHAP81_RESPONSE_LEN;		/* value size */
197
198    /* Copy our challenge */
199    memcpy(digest, peerchallenge + 1, CHAP81_CHALLENGE_LEN);
200
201    /* Expand password to Unicode XXX */
202    for (f = 0; f < klen; f++) {
203      expkey[2*f] = key[f];
204      expkey[2*f+1] = '\0';
205    }
206
207    ntresponse = digest + CHAP81_NTRESPONSE_OFF;
208
209    /* Get some needed hashes */
210    NtPasswordHash(expkey, klen * 2, pwdhash);
211    HashNtPasswordHash(pwdhash, pwdhashhash);
212
213    /* Generate NTRESPONSE to respond on challenge call */
214    GenerateNTResponse(challenge + 1, peerchallenge + 1, name, nlen,
215                       expkey, klen * 2, ntresponse);
216
217    /* Generate MPPE MASTERKEY */
218    GetMasterKey(pwdhashhash, ntresponse, MPPE_MasterKey);    /* XXX Global ! */
219
220    /* Generate AUTHRESPONSE to verify on auth success */
221    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  struct bundle *bundle = authp->physical->dl->bundle;
548  const char *msg;
549
550  datalink_GotAuthname(authp->physical->dl, authp->in.name);
551#ifndef NODES
552  if (authp->physical->link.lcp.want_authtype == 0x81) {
553    msg = auth2chap(authp)->authresponse;
554    MPPE_MasterKeyValid = 1;		/* XXX Global ! */
555  } else
556#endif
557#ifndef NORADIUS
558  if (*bundle->radius.cfg.file && bundle->radius.repstr)
559    msg = bundle->radius.repstr;
560  else
561#endif
562    msg = "Welcome!!";
563
564  ChapOutput(authp->physical, CHAP_SUCCESS, authp->id, msg, strlen(msg),
565             NULL);
566
567  authp->physical->link.lcp.auth_ineed = 0;
568  if (Enabled(bundle, OPT_UTMP))
569    physical_Login(authp->physical, authp->in.name);
570
571  if (authp->physical->link.lcp.auth_iwait == 0)
572    /*
573     * Either I didn't need to authenticate, or I've already been
574     * told that I got the answer right.
575     */
576    datalink_AuthOk(authp->physical->dl);
577}
578
579static void
580chap_Failure(struct authinfo *authp)
581{
582#ifndef NODES
583  char buf[1024], *ptr;
584#endif
585  const char *msg;
586
587#ifndef NORADIUS
588  struct bundle *bundle = authp->physical->link.lcp.fsm.bundle;
589  if (*bundle->radius.cfg.file && bundle->radius.errstr)
590    msg = bundle->radius.errstr;
591  else
592#endif
593#ifndef NODES
594  if (authp->physical->link.lcp.want_authtype == 0x80) {
595    sprintf(buf, "E=691 R=1 M=Invalid!");
596    msg = buf;
597  } else if (authp->physical->link.lcp.want_authtype == 0x81) {
598    int i;
599
600    ptr = buf;
601    ptr += sprintf(buf, "E=691 R=0 C=");
602    for (i=0; i<16; i++)
603      ptr += sprintf(ptr, "%02X", *(auth2chap(authp)->challenge.local+1+i));
604
605    sprintf(ptr, " V=3 M=Invalid!");
606    msg = buf;
607  } else
608#endif
609    msg = "Invalid!!";
610
611  ChapOutput(authp->physical, CHAP_FAILURE, authp->id, msg, strlen(msg) + 1,
612             NULL);
613  datalink_AuthNotOk(authp->physical->dl);
614}
615
616static int
617chap_Cmp(u_char type, char *myans, int mylen, char *hisans, int hislen
618#ifndef NODES
619         , int lm
620#endif
621        )
622{
623  if (mylen != hislen)
624    return 0;
625#ifndef NODES
626  else if (type == 0x80) {
627    int off = lm ? 0 : 24;
628
629    if (memcmp(myans + off, hisans + off, 24))
630      return 0;
631  }
632#endif
633  else if (memcmp(myans, hisans, mylen))
634    return 0;
635
636  return 1;
637}
638
639#ifndef NODES
640static int
641chap_HaveAnotherGo(struct chap *chap)
642{
643  if (++chap->peertries < 3) {
644    /* Give the peer another shot */
645    *chap->challenge.local = '\0';
646    chap_Challenge(&chap->auth);
647    return 1;
648  }
649
650  return 0;
651}
652#endif
653
654void
655chap_Init(struct chap *chap, struct physical *p)
656{
657  chap->desc.type = CHAP_DESCRIPTOR;
658  chap->desc.UpdateSet = chap_UpdateSet;
659  chap->desc.IsSet = chap_IsSet;
660  chap->desc.Read = chap_Read;
661  chap->desc.Write = chap_Write;
662  chap->child.pid = 0;
663  chap->child.fd = -1;
664  auth_Init(&chap->auth, p, chap_Challenge, chap_Success, chap_Failure);
665  *chap->challenge.local = *chap->challenge.peer = '\0';
666#ifndef NODES
667  chap->NTRespSent = 0;
668  chap->peertries = 0;
669#endif
670}
671
672void
673chap_ReInit(struct chap *chap)
674{
675  chap_Cleanup(chap, SIGTERM);
676}
677
678struct mbuf *
679chap_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
680{
681  struct physical *p = link2physical(l);
682  struct chap *chap = &p->dl->chap;
683  char *name, *key, *ans;
684  int len, nlen;
685  u_char alen;
686#ifndef NODES
687  int lanman;
688#endif
689
690  if (p == NULL) {
691    log_Printf(LogERROR, "chap_Input: Not a physical link - dropped\n");
692    m_freem(bp);
693    return NULL;
694  }
695
696  if (bundle_Phase(bundle) != PHASE_NETWORK &&
697      bundle_Phase(bundle) != PHASE_AUTHENTICATE) {
698    log_Printf(LogPHASE, "Unexpected chap input - dropped !\n");
699    m_freem(bp);
700    return NULL;
701  }
702
703  m_settype(bp, MB_CHAPIN);
704  if ((bp = auth_ReadHeader(&chap->auth, bp)) == NULL &&
705      ntohs(chap->auth.in.hdr.length) == 0)
706    log_Printf(LogWARN, "Chap Input: Truncated header !\n");
707  else if (chap->auth.in.hdr.code == 0 || chap->auth.in.hdr.code > MAXCHAPCODE)
708    log_Printf(LogPHASE, "Chap Input: %d: Bad CHAP code !\n",
709               chap->auth.in.hdr.code);
710  else {
711    len = m_length(bp);
712    ans = NULL;
713
714    if (chap->auth.in.hdr.code != CHAP_CHALLENGE &&
715        chap->auth.id != chap->auth.in.hdr.id &&
716        Enabled(bundle, OPT_IDCHECK)) {
717      /* Wrong conversation dude ! */
718      log_Printf(LogPHASE, "Chap Input: %s dropped (got id %d, not %d)\n",
719                 chapcodes[chap->auth.in.hdr.code], chap->auth.in.hdr.id,
720                 chap->auth.id);
721      m_freem(bp);
722      return NULL;
723    }
724    chap->auth.id = chap->auth.in.hdr.id;	/* We respond with this id */
725
726#ifndef NODES
727    lanman = 0;
728#endif
729    switch (chap->auth.in.hdr.code) {
730      case CHAP_CHALLENGE:
731        bp = mbuf_Read(bp, &alen, 1);
732        len -= alen + 1;
733        if (len < 0) {
734          log_Printf(LogERROR, "Chap Input: Truncated challenge !\n");
735          m_freem(bp);
736          return NULL;
737        }
738        *chap->challenge.peer = alen;
739        bp = mbuf_Read(bp, chap->challenge.peer + 1, alen);
740        bp = auth_ReadName(&chap->auth, bp, len);
741#ifndef NODES
742        lanman = p->link.lcp.his_authtype == 0x80 &&
743                 ((chap->NTRespSent && IsAccepted(p->link.lcp.cfg.chap80lm)) ||
744                  !IsAccepted(p->link.lcp.cfg.chap80nt));
745
746        /* Generate local challenge value */
747        chap_ChallengeInit(&chap->auth);
748#endif
749        break;
750
751      case CHAP_RESPONSE:
752        auth_StopTimer(&chap->auth);
753        bp = mbuf_Read(bp, &alen, 1);
754        len -= alen + 1;
755        if (len < 0) {
756          log_Printf(LogERROR, "Chap Input: Truncated response !\n");
757          m_freem(bp);
758          return NULL;
759        }
760        if ((ans = malloc(alen + 2)) == NULL) {
761          log_Printf(LogERROR, "Chap Input: Out of memory !\n");
762          m_freem(bp);
763          return NULL;
764        }
765        *ans = chap->auth.id;
766        bp = mbuf_Read(bp, ans + 1, alen);
767        if (p->link.lcp.want_authtype == 0x81 && ans[alen] != '\0') {
768          log_Printf(LogWARN, "%s: Compensating for corrupt (Win98/WinME?) "
769                     "CHAP81 RESPONSE\n", l->name);
770          ans[alen] = '\0';
771        }
772        ans[alen+1] = '\0';
773        bp = auth_ReadName(&chap->auth, bp, len);
774#ifndef NODES
775        lanman = p->link.lcp.want_authtype == 0x80 &&
776                 alen == 49 && ans[alen] == 0;
777#endif
778        break;
779
780      case CHAP_SUCCESS:
781      case CHAP_FAILURE:
782        /* chap->auth.in.name is already set up at CHALLENGE time */
783        if ((ans = malloc(len + 1)) == NULL) {
784          log_Printf(LogERROR, "Chap Input: Out of memory !\n");
785          m_freem(bp);
786          return NULL;
787        }
788        bp = mbuf_Read(bp, ans, len);
789        ans[len] = '\0';
790        break;
791    }
792
793    switch (chap->auth.in.hdr.code) {
794      case CHAP_CHALLENGE:
795      case CHAP_RESPONSE:
796        if (*chap->auth.in.name)
797          log_Printf(LogPHASE, "Chap Input: %s (%d bytes from %s%s)\n",
798                     chapcodes[chap->auth.in.hdr.code], alen,
799                     chap->auth.in.name,
800#ifndef NODES
801                     lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
802                     " - lanman" :
803#endif
804                     "");
805        else
806          log_Printf(LogPHASE, "Chap Input: %s (%d bytes%s)\n",
807                     chapcodes[chap->auth.in.hdr.code], alen,
808#ifndef NODES
809                     lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
810                     " - lanman" :
811#endif
812                     "");
813        break;
814
815      case CHAP_SUCCESS:
816      case CHAP_FAILURE:
817        if (*ans)
818          log_Printf(LogPHASE, "Chap Input: %s (%s)\n",
819                     chapcodes[chap->auth.in.hdr.code], ans);
820        else
821          log_Printf(LogPHASE, "Chap Input: %s\n",
822                     chapcodes[chap->auth.in.hdr.code]);
823        break;
824    }
825
826    switch (chap->auth.in.hdr.code) {
827      case CHAP_CHALLENGE:
828        if (*bundle->cfg.auth.key == '!' && bundle->cfg.auth.key[1] != '!')
829          chap_StartChild(chap, bundle->cfg.auth.key + 1,
830                          bundle->cfg.auth.name);
831        else
832          chap_Respond(chap, bundle->cfg.auth.name, bundle->cfg.auth.key +
833                       (*bundle->cfg.auth.key == '!' ? 1 : 0),
834                       p->link.lcp.his_authtype
835#ifndef NODES
836                       , lanman
837#endif
838                      );
839        break;
840
841      case CHAP_RESPONSE:
842        name = chap->auth.in.name;
843        nlen = strlen(name);
844#ifndef NORADIUS
845        if (*bundle->radius.cfg.file)
846          radius_Authenticate(&bundle->radius, &chap->auth,
847                              chap->auth.in.name, ans, alen + 1,
848                              chap->challenge.local + 1,
849                              *chap->challenge.local);
850        else
851#endif
852        {
853          key = auth_GetSecret(bundle, name, nlen, p);
854          if (key) {
855            char *myans;
856#ifndef NODES
857            if (p->link.lcp.want_authtype == 0x80 &&
858                lanman && !IsEnabled(p->link.lcp.cfg.chap80lm)) {
859              log_Printf(LogPHASE, "Auth failure: LANMan not enabled\n");
860              if (chap_HaveAnotherGo(chap))
861                break;
862              key = NULL;
863            } else if (p->link.lcp.want_authtype == 0x80 &&
864                !lanman && !IsEnabled(p->link.lcp.cfg.chap80nt)) {
865              log_Printf(LogPHASE, "Auth failure: mschap not enabled\n");
866              if (chap_HaveAnotherGo(chap))
867                break;
868              key = NULL;
869            } else if (p->link.lcp.want_authtype == 0x81 &&
870                !IsEnabled(p->link.lcp.cfg.chap81)) {
871              log_Printf(LogPHASE, "Auth failure: CHAP81 not enabled\n");
872              key = NULL;
873            } else
874#endif
875            {
876#ifndef NODES
877              /* Get peer's challenge */
878              if (p->link.lcp.want_authtype == 0x81) {
879                chap->challenge.peer[0] = CHAP81_CHALLENGE_LEN;
880                memcpy(chap->challenge.peer + 1, ans + 1, CHAP81_CHALLENGE_LEN);
881              }
882#endif
883
884              myans = chap_BuildAnswer(name, key, chap->auth.id,
885                                       chap->challenge.local,
886                                       p->link.lcp.want_authtype
887#ifndef NODES
888                                       , chap->challenge.peer,
889                                       chap->authresponse, lanman);
890              MPPE_IsServer = 1;		/* XXX Global ! */
891#else
892                                      );
893#endif
894              if (myans == NULL)
895                key = NULL;
896              else {
897                if (!chap_Cmp(p->link.lcp.want_authtype, myans + 1, *myans,
898                              ans + 1, alen
899#ifndef NODES
900                              , lanman
901#endif
902                             ))
903                  key = NULL;
904                free(myans);
905              }
906            }
907          }
908
909          if (key)
910            chap_Success(&chap->auth);
911          else
912            chap_Failure(&chap->auth);
913        }
914
915        break;
916
917      case CHAP_SUCCESS:
918        if (p->link.lcp.auth_iwait == PROTO_CHAP) {
919          p->link.lcp.auth_iwait = 0;
920          if (p->link.lcp.auth_ineed == 0) {
921#ifndef NODES
922            if (p->link.lcp.his_authtype == 0x81) {
923              if (strncmp(ans, chap->authresponse, 42)) {
924                datalink_AuthNotOk(p->dl);
925	        log_Printf(LogWARN, "CHAP81: AuthenticatorResponse: (%.42s)"
926                           " != ans: (%.42s)\n", chap->authresponse, ans);
927
928              } else {
929                /* Successful login */
930                MPPE_MasterKeyValid = 1;		/* XXX Global ! */
931                datalink_AuthOk(p->dl);
932              }
933            } else
934#endif
935            /*
936             * We've succeeded in our ``login''
937             * If we're not expecting  the peer to authenticate (or he already
938             * has), proceed to network phase.
939             */
940            datalink_AuthOk(p->dl);
941          }
942        }
943        break;
944
945      case CHAP_FAILURE:
946        datalink_AuthNotOk(p->dl);
947        break;
948    }
949    free(ans);
950  }
951
952  m_freem(bp);
953  return NULL;
954}
955