chap.c revision 96731
1122394Sharti/*-
2122394Sharti * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
3122394Sharti *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
4122394Sharti *                           Internet Initiative Japan, Inc (IIJ)
5122394Sharti * All rights reserved.
6122394Sharti *
7133211Sharti * Redistribution and use in source and binary forms, with or without
8133211Sharti * modification, are permitted provided that the following conditions
9133211Sharti * are met:
10133211Sharti * 1. Redistributions of source code must retain the above copyright
11133211Sharti *    notice, this list of conditions and the following disclaimer.
12133211Sharti * 2. Redistributions in binary form must reproduce the above copyright
13122394Sharti *    notice, this list of conditions and the following disclaimer in the
14122394Sharti *    documentation and/or other materials provided with the distribution.
15122394Sharti *
16133211Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17133211Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18133211Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19133211Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20133211Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21133211Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22133211Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23133211Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24133211Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25133211Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26133211Sharti * SUCH DAMAGE.
27133211Sharti *
28122394Sharti * $FreeBSD: head/usr.sbin/ppp/chap.c 96731 2002-05-16 14:28:32Z brian $
29156066Sharti */
30122394Sharti
31122394Sharti#include <sys/param.h>
32122394Sharti#include <netinet/in.h>
33122394Sharti#include <netinet/in_systm.h>
34122394Sharti#include <netinet/ip.h>
35122394Sharti#include <sys/socket.h>
36122394Sharti#include <sys/un.h>
37122394Sharti
38150920Sharti#include <errno.h>
39133211Sharti#include <fcntl.h>
40150920Sharti#ifndef NODES
41150920Sharti#include <md4.h>
42150920Sharti#endif
43122394Sharti#include <md5.h>
44156066Sharti#include <paths.h>
45156066Sharti#include <signal.h>
46122394Sharti#include <stdio.h>
47122394Sharti#include <stdlib.h>
48122394Sharti#include <string.h>
49122394Sharti#include <sys/wait.h>
50122394Sharti#include <termios.h>
51122394Sharti#include <unistd.h>
52122394Sharti
53122394Sharti#include "layer.h"
54122394Sharti#include "mbuf.h"
55122394Sharti#include "log.h"
56122394Sharti#include "defs.h"
57122394Sharti#include "timer.h"
58122394Sharti#include "fsm.h"
59122394Sharti#include "proto.h"
60122394Sharti#include "lqr.h"
61122394Sharti#include "hdlc.h"
62122394Sharti#include "lcp.h"
63122394Sharti#include "auth.h"
64122394Sharti#include "async.h"
65122394Sharti#include "throughput.h"
66122394Sharti#include "descriptor.h"
67122394Sharti#include "chap.h"
68122394Sharti#include "iplist.h"
69122394Sharti#include "slcompress.h"
70122394Sharti#include "ncpaddr.h"
71122394Sharti#include "ipcp.h"
72122394Sharti#include "filter.h"
73122394Sharti#include "ccp.h"
74122394Sharti#include "link.h"
75122394Sharti#include "physical.h"
76122394Sharti#include "mp.h"
77122394Sharti#ifndef NORADIUS
78122394Sharti#include "radius.h"
79122394Sharti#endif
80122394Sharti#include "ipv6cp.h"
81122394Sharti#include "ncp.h"
82122394Sharti#include "bundle.h"
83122394Sharti#include "chat.h"
84122394Sharti#include "cbcp.h"
85122394Sharti#include "command.h"
86122394Sharti#include "datalink.h"
87122394Sharti#ifndef NODES
88122394Sharti#include "chap_ms.h"
89122394Sharti#include "mppe.h"
90122394Sharti#endif
91122394Sharti#include "id.h"
92122394Sharti
93122394Shartistatic const char * const chapcodes[] = {
94122394Sharti  "???", "CHALLENGE", "RESPONSE", "SUCCESS", "FAILURE"
95122394Sharti};
96122394Sharti#define MAXCHAPCODE (sizeof chapcodes / sizeof chapcodes[0] - 1)
97122394Sharti
98122394Shartistatic void
99122394ShartiChapOutput(struct physical *physical, u_int code, u_int id,
100122394Sharti	   const u_char *ptr, int count, const char *text)
101122394Sharti{
102122394Sharti  int plen;
103122394Sharti  struct fsmheader lh;
104122394Sharti  struct mbuf *bp;
105122394Sharti
106122394Sharti  plen = sizeof(struct fsmheader) + count;
107122394Sharti  lh.code = code;
108122394Sharti  lh.id = id;
109122394Sharti  lh.length = htons(plen);
110122394Sharti  bp = m_get(plen, MB_CHAPOUT);
111122394Sharti  memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
112122394Sharti  if (count)
113122394Sharti    memcpy(MBUF_CTOP(bp) + sizeof(struct fsmheader), ptr, count);
114122394Sharti  log_DumpBp(LogDEBUG, "ChapOutput", bp);
115122394Sharti  if (text == NULL)
116122394Sharti    log_Printf(LogPHASE, "Chap Output: %s\n", chapcodes[code]);
117122394Sharti  else
118122394Sharti    log_Printf(LogPHASE, "Chap Output: %s (%s)\n", chapcodes[code], text);
119122394Sharti  link_PushPacket(&physical->link, bp, physical->dl->bundle,
120122394Sharti                  LINK_QUEUES(&physical->link) - 1, PROTO_CHAP);
121122394Sharti}
122122394Sharti
123122394Shartistatic char *
124122394Shartichap_BuildAnswer(char *name, char *key, u_char id, char *challenge, u_char type
125122394Sharti#ifndef NODES
126122394Sharti                 , char *peerchallenge, char *authresponse, int lanman
127122394Sharti#endif
128122394Sharti                )
129122394Sharti{
130122394Sharti  char *result, *digest;
131122394Sharti  size_t nlen, klen;
132122394Sharti
133122394Sharti  nlen = strlen(name);
134122394Sharti  klen = strlen(key);
135122394Sharti
136122394Sharti#ifndef NODES
137122394Sharti  if (type == 0x80) {
138122394Sharti    char expkey[AUTHLEN << 2];
139122394Sharti    MD4_CTX MD4context;
140122394Sharti    int f;
141122394Sharti
142122394Sharti    if ((result = malloc(1 + nlen + MS_CHAP_RESPONSE_LEN)) == NULL)
143122394Sharti      return result;
144122394Sharti
145122394Sharti    digest = result;					/* the response */
146122394Sharti    *digest++ = MS_CHAP_RESPONSE_LEN;			/* 49 */
147122394Sharti    memcpy(digest + MS_CHAP_RESPONSE_LEN, name, nlen);
148122394Sharti    if (lanman) {
149122394Sharti      memset(digest + 24, '\0', 25);
150122394Sharti      mschap_LANMan(digest, challenge + 1, key);	/* LANMan response */
151122394Sharti    } else {
152122394Sharti      memset(digest, '\0', 25);
153122394Sharti      digest += 24;
154122394Sharti
155122394Sharti      for (f = 0; f < klen; f++) {
156122394Sharti        expkey[2*f] = key[f];
157122394Sharti        expkey[2*f+1] = '\0';
158122394Sharti      }
159122394Sharti      /*
160122394Sharti       *           -----------
161122394Sharti       * expkey = | k\0e\0y\0 |
162122394Sharti       *           -----------
163122394Sharti       */
164122394Sharti      MD4Init(&MD4context);
165122394Sharti      MD4Update(&MD4context, expkey, klen << 1);
166122394Sharti      MD4Final(digest, &MD4context);
167122394Sharti
168122394Sharti      /*
169122394Sharti       *           ---- -------- ---------------- ------- ------
170122394Sharti       * result = | 49 | LANMan | 16 byte digest | 9 * ? | name |
171122394Sharti       *           ---- -------- ---------------- ------- ------
172122394Sharti       */
173122394Sharti      mschap_NT(digest, challenge + 1);
174122394Sharti    }
175122394Sharti    /*
176122394Sharti     *           ---- -------- ------------- ----- ------
177122394Sharti     *          |    |  struct MS_ChapResponse24  |      |
178122394Sharti     * result = | 49 | LANMan  |  NT digest | 0/1 | name |
179122394Sharti     *           ---- -------- ------------- ----- ------
180122394Sharti     * where only one of LANMan & NT digest are set.
181122394Sharti     */
182122394Sharti  } else if (type == 0x81) {
183122394Sharti    char expkey[AUTHLEN << 2];
184122394Sharti    char pwdhash[CHAP81_HASH_LEN];
185122394Sharti    char pwdhashhash[CHAP81_HASH_LEN];
186122394Sharti    char *ntresponse;
187122394Sharti    int f;
188122394Sharti
189122394Sharti    if ((result = malloc(1 + nlen + CHAP81_RESPONSE_LEN)) == NULL)
190122394Sharti      return result;
191122394Sharti
192122394Sharti    memset(result, 0, 1 + nlen + CHAP81_RESPONSE_LEN);
193122394Sharti
194122394Sharti    digest = result;
195122394Sharti    *digest++ = CHAP81_RESPONSE_LEN;		/* value size */
196122394Sharti
197122394Sharti    /* Copy our challenge */
198122394Sharti    memcpy(digest, peerchallenge + 1, CHAP81_CHALLENGE_LEN);
199216294Ssyrinx
200122394Sharti    /* Expand password to Unicode XXX */
201122394Sharti    for (f = 0; f < klen; f++) {
202122394Sharti      expkey[2*f] = key[f];
203122394Sharti      expkey[2*f+1] = '\0';
204122394Sharti    }
205122394Sharti
206122394Sharti    ntresponse = digest + CHAP81_NTRESPONSE_OFF;
207122394Sharti
208122394Sharti    /* Get some needed hashes */
209122394Sharti    NtPasswordHash(expkey, klen * 2, pwdhash);
210122394Sharti    HashNtPasswordHash(pwdhash, pwdhashhash);
211122394Sharti
212122394Sharti    /* Generate NTRESPONSE to respond on challenge call */
213122394Sharti    GenerateNTResponse(challenge + 1, peerchallenge + 1, name, nlen,
214122394Sharti                       expkey, klen * 2, ntresponse);
215122394Sharti
216122394Sharti    /* Generate MPPE MASTERKEY */
217122394Sharti    GetMasterKey(pwdhashhash, ntresponse, MPPE_MasterKey);    /* XXX Global ! */
218216294Ssyrinx
219216294Ssyrinx    /* Generate AUTHRESPONSE to verify on auth success */
220122394Sharti    GenerateAuthenticatorResponse(expkey, klen * 2, ntresponse,
221122394Sharti                                  peerchallenge + 1, challenge + 1, name, nlen,
222122394Sharti                                  authresponse);
223122394Sharti
224122394Sharti    authresponse[CHAP81_AUTHRESPONSE_LEN] = 0;
225122394Sharti
226122394Sharti    memcpy(digest + CHAP81_RESPONSE_LEN, name, nlen);
227122394Sharti  } else
228122394Sharti#endif
229122394Sharti  if ((result = malloc(nlen + 17)) != NULL) {
230122394Sharti    /* Normal MD5 stuff */
231122394Sharti    MD5_CTX MD5context;
232122394Sharti
233122394Sharti    digest = result;
234122394Sharti    *digest++ = 16;				/* value size */
235133211Sharti
236122394Sharti    MD5Init(&MD5context);
237122394Sharti    MD5Update(&MD5context, &id, 1);
238122394Sharti    MD5Update(&MD5context, key, klen);
239122394Sharti    MD5Update(&MD5context, challenge + 1, *challenge);
240122394Sharti    MD5Final(digest, &MD5context);
241122394Sharti
242122394Sharti    memcpy(digest + 16, name, nlen);
243122394Sharti    /*
244122394Sharti     *           ---- -------- ------
245122394Sharti     * result = | 16 | digest | name |
246122394Sharti     *           ---- -------- ------
247122394Sharti     */
248122394Sharti  }
249122394Sharti
250122394Sharti  return result;
251124861Sharti}
252124861Sharti
253124861Shartistatic void
254124861Shartichap_StartChild(struct chap *chap, char *prog, const char *name)
255124861Sharti{
256124861Sharti  char *argv[MAXARGS], *nargv[MAXARGS];
257124861Sharti  int argc, fd;
258122394Sharti  int in[2], out[2];
259122394Sharti  pid_t pid;
260122394Sharti
261122394Sharti  if (chap->child.fd != -1) {
262122394Sharti    log_Printf(LogWARN, "Chap: %s: Program already running\n", prog);
263122394Sharti    return;
264122394Sharti  }
265122394Sharti
266122394Sharti  if (pipe(in) == -1) {
267122394Sharti    log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno));
268122394Sharti    return;
269122394Sharti  }
270122394Sharti
271122394Sharti  if (pipe(out) == -1) {
272122394Sharti    log_Printf(LogERROR, "Chap: pipe: %s\n", strerror(errno));
273122394Sharti    close(in[0]);
274122394Sharti    close(in[1]);
275122394Sharti    return;
276122394Sharti  }
277122394Sharti
278122394Sharti  pid = getpid();
279122394Sharti  switch ((chap->child.pid = fork())) {
280122394Sharti    case -1:
281122394Sharti      log_Printf(LogERROR, "Chap: fork: %s\n", strerror(errno));
282122394Sharti      close(in[0]);
283122394Sharti      close(in[1]);
284133211Sharti      close(out[0]);
285122394Sharti      close(out[1]);
286122394Sharti      chap->child.pid = 0;
287122394Sharti      return;
288122394Sharti
289122394Sharti    case 0:
290133211Sharti      timer_TermService();
291122394Sharti
292122394Sharti      if ((argc = command_Interpret(prog, strlen(prog), argv)) <= 0) {
293133211Sharti        if (argc < 0) {
294122394Sharti          log_Printf(LogWARN, "CHAP: Invalid command syntax\n");
295122394Sharti          _exit(255);
296122394Sharti        }
297122394Sharti        _exit(0);
298122394Sharti      }
299122394Sharti
300122394Sharti      close(in[1]);
301122394Sharti      close(out[0]);
302122394Sharti      if (out[1] == STDIN_FILENO)
303122394Sharti        out[1] = dup(out[1]);
304122394Sharti      dup2(in[0], STDIN_FILENO);
305122394Sharti      dup2(out[1], STDOUT_FILENO);
306122394Sharti      close(STDERR_FILENO);
307122394Sharti      if (open(_PATH_DEVNULL, O_RDWR) != STDERR_FILENO) {
308122394Sharti        log_Printf(LogALERT, "Chap: Failed to open %s: %s\n",
309122394Sharti                  _PATH_DEVNULL, strerror(errno));
310122394Sharti        exit(1);
311122394Sharti      }
312122394Sharti      for (fd = getdtablesize(); fd > STDERR_FILENO; fd--)
313122394Sharti        fcntl(fd, F_SETFD, 1);
314122394Sharti#ifndef NOSUID
315122394Sharti      setuid(ID0realuid());
316122394Sharti#endif
317122394Sharti      command_Expand(nargv, argc, (char const *const *)argv,
318122394Sharti                     chap->auth.physical->dl->bundle, 0, pid);
319122394Sharti      execvp(nargv[0], nargv);
320122394Sharti      printf("exec() of %s failed: %s\n", nargv[0], strerror(errno));
321122394Sharti      _exit(255);
322122394Sharti
323122394Sharti    default:
324122394Sharti      close(in[0]);
325122394Sharti      close(out[1]);
326122394Sharti      chap->child.fd = out[0];
327133211Sharti      chap->child.buf.len = 0;
328122394Sharti      write(in[1], chap->auth.in.name, strlen(chap->auth.in.name));
329122394Sharti      write(in[1], "\n", 1);
330122394Sharti      write(in[1], chap->challenge.peer + 1, *chap->challenge.peer);
331122394Sharti      write(in[1], "\n", 1);
332122394Sharti      write(in[1], name, strlen(name));
333122394Sharti      write(in[1], "\n", 1);
334122394Sharti      close(in[1]);
335122394Sharti      break;
336122394Sharti  }
337122394Sharti}
338122394Sharti
339122394Shartistatic void
340122394Shartichap_Cleanup(struct chap *chap, int sig)
341122394Sharti{
342122394Sharti  if (chap->child.pid) {
343122394Sharti    int status;
344122394Sharti
345122394Sharti    close(chap->child.fd);
346124861Sharti    chap->child.fd = -1;
347124861Sharti    if (sig)
348124861Sharti      kill(chap->child.pid, SIGTERM);
349124861Sharti    chap->child.pid = 0;
350122394Sharti    chap->child.buf.len = 0;
351122394Sharti
352122394Sharti    if (wait(&status) == -1)
353122394Sharti      log_Printf(LogERROR, "Chap: wait: %s\n", strerror(errno));
354122394Sharti    else if (WIFSIGNALED(status))
355122394Sharti      log_Printf(LogWARN, "Chap: Child received signal %d\n", WTERMSIG(status));
356122394Sharti    else if (WIFEXITED(status) && WEXITSTATUS(status))
357122394Sharti      log_Printf(LogERROR, "Chap: Child exited %d\n", WEXITSTATUS(status));
358122394Sharti  }
359122394Sharti  *chap->challenge.local = *chap->challenge.peer = '\0';
360122394Sharti#ifndef NODES
361122394Sharti  chap->peertries = 0;
362122394Sharti#endif
363122394Sharti}
364133211Sharti
365122394Shartistatic void
366122394Shartichap_Respond(struct chap *chap, char *name, char *key, u_char type
367122394Sharti#ifndef NODES
368122394Sharti             , int lm
369122394Sharti#endif
370122394Sharti            )
371122394Sharti{
372122394Sharti  u_char *ans;
373122394Sharti
374122394Sharti  ans = chap_BuildAnswer(name, key, chap->auth.id, chap->challenge.peer, type
375122394Sharti#ifndef NODES
376122394Sharti                         , chap->challenge.local, chap->authresponse, lm
377122394Sharti#endif
378122394Sharti                        );
379122394Sharti
380122394Sharti  if (ans) {
381122394Sharti    ChapOutput(chap->auth.physical, CHAP_RESPONSE, chap->auth.id,
382122394Sharti               ans, *ans + 1 + strlen(name), name);
383122394Sharti#ifndef NODES
384122394Sharti    chap->NTRespSent = !lm;
385122394Sharti    MPPE_IsServer = 0;		/* XXX Global ! */
386122394Sharti#endif
387122394Sharti    free(ans);
388122394Sharti  } else
389122394Sharti    ChapOutput(chap->auth.physical, CHAP_FAILURE, chap->auth.id,
390122394Sharti               "Out of memory!", 14, NULL);
391122394Sharti}
392122394Sharti
393122394Shartistatic int
394122394Shartichap_UpdateSet(struct fdescriptor *d, fd_set *r, fd_set *w, fd_set *e, int *n)
395122394Sharti{
396122394Sharti  struct chap *chap = descriptor2chap(d);
397122394Sharti
398122394Sharti  if (r && chap && chap->child.fd != -1) {
399122394Sharti    FD_SET(chap->child.fd, r);
400122394Sharti    if (*n < chap->child.fd + 1)
401122394Sharti      *n = chap->child.fd + 1;
402122394Sharti    log_Printf(LogTIMER, "Chap: fdset(r) %d\n", chap->child.fd);
403122394Sharti    return 1;
404122394Sharti  }
405122394Sharti
406122394Sharti  return 0;
407122394Sharti}
408122394Sharti
409122394Shartistatic int
410122394Shartichap_IsSet(struct fdescriptor *d, const fd_set *fdset)
411122394Sharti{
412122394Sharti  struct chap *chap = descriptor2chap(d);
413122394Sharti
414122394Sharti  return chap && chap->child.fd != -1 && FD_ISSET(chap->child.fd, fdset);
415122394Sharti}
416122394Sharti
417122394Shartistatic void
418122394Shartichap_Read(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
419122394Sharti{
420122394Sharti  struct chap *chap = descriptor2chap(d);
421122394Sharti  int got;
422122394Sharti
423122394Sharti  got = read(chap->child.fd, chap->child.buf.ptr + chap->child.buf.len,
424122394Sharti             sizeof chap->child.buf.ptr - chap->child.buf.len - 1);
425122394Sharti  if (got == -1) {
426122394Sharti    log_Printf(LogERROR, "Chap: Read: %s\n", strerror(errno));
427122394Sharti    chap_Cleanup(chap, SIGTERM);
428122394Sharti  } else if (got == 0) {
429122394Sharti    log_Printf(LogWARN, "Chap: Read: Child terminated connection\n");
430122394Sharti    chap_Cleanup(chap, SIGTERM);
431122394Sharti  } else {
432122394Sharti    char *name, *key, *end;
433122394Sharti
434122394Sharti    chap->child.buf.len += got;
435122394Sharti    chap->child.buf.ptr[chap->child.buf.len] = '\0';
436122394Sharti    name = chap->child.buf.ptr;
437122394Sharti    name += strspn(name, " \t");
438122394Sharti    if ((key = strchr(name, '\n')) == NULL)
439122394Sharti      end = NULL;
440122394Sharti    else
441122394Sharti      end = strchr(++key, '\n');
442122394Sharti
443122394Sharti    if (end == NULL) {
444122394Sharti      if (chap->child.buf.len == sizeof chap->child.buf.ptr - 1) {
445122394Sharti        log_Printf(LogWARN, "Chap: Read: Input buffer overflow\n");
446122394Sharti        chap_Cleanup(chap, SIGTERM);
447122394Sharti      }
448122394Sharti    } else {
449122394Sharti#ifndef NODES
450122394Sharti      int lanman = chap->auth.physical->link.lcp.his_authtype == 0x80 &&
451122394Sharti                   ((chap->NTRespSent &&
452122394Sharti                     IsAccepted(chap->auth.physical->link.lcp.cfg.chap80lm)) ||
453122394Sharti                    !IsAccepted(chap->auth.physical->link.lcp.cfg.chap80nt));
454122394Sharti#endif
455122394Sharti
456122394Sharti      while (end >= name && strchr(" \t\r\n", *end))
457122394Sharti        *end-- = '\0';
458122394Sharti      end = key - 1;
459122394Sharti      while (end >= name && strchr(" \t\r\n", *end))
460122394Sharti        *end-- = '\0';
461122394Sharti      key += strspn(key, " \t");
462122394Sharti
463122394Sharti      chap_Respond(chap, name, key, chap->auth.physical->link.lcp.his_authtype
464122394Sharti#ifndef NODES
465122394Sharti                   , lanman
466122394Sharti#endif
467122394Sharti                  );
468122394Sharti      chap_Cleanup(chap, 0);
469122394Sharti    }
470122394Sharti  }
471122394Sharti}
472122394Sharti
473122394Shartistatic int
474122394Shartichap_Write(struct fdescriptor *d, struct bundle *bundle, const fd_set *fdset)
475122394Sharti{
476122394Sharti  /* We never want to write here ! */
477122394Sharti  log_Printf(LogALERT, "chap_Write: Internal error: Bad call !\n");
478122394Sharti  return 0;
479122394Sharti}
480122394Sharti
481122394Shartistatic void
482122394Shartichap_ChallengeInit(struct authinfo *authp)
483122394Sharti{
484122394Sharti  struct chap *chap = auth2chap(authp);
485122394Sharti  int len, i;
486122394Sharti  char *cp;
487122394Sharti
488122394Sharti  len = strlen(authp->physical->dl->bundle->cfg.auth.name);
489122394Sharti
490122394Sharti  if (!*chap->challenge.local) {
491122394Sharti    randinit();
492122394Sharti    cp = chap->challenge.local;
493122394Sharti
494122394Sharti#ifndef NORADIUS
495122394Sharti    if (*authp->physical->dl->bundle->radius.cfg.file) {
496122394Sharti      /* For radius, our challenge is 16 readable NUL terminated bytes :*/
497122394Sharti      *cp++ = 16;
498122394Sharti      for (i = 0; i < 16; i++)
499122394Sharti        *cp++ = (random() % 10) + '0';
500122394Sharti    } else
501122394Sharti#endif
502122394Sharti    {
503122394Sharti#ifndef NODES
504122394Sharti      if (authp->physical->link.lcp.want_authtype == 0x80)
505122394Sharti        *cp++ = 8;	/* MS does 8 byte callenges :-/ */
506122394Sharti      else if (authp->physical->link.lcp.want_authtype == 0x81)
507122394Sharti        *cp++ = 16;	/* MS-CHAP-V2 does 16 bytes challenges */
508122394Sharti      else
509122394Sharti#endif
510122394Sharti        *cp++ = random() % (CHAPCHALLENGELEN-16) + 16;
511122394Sharti      for (i = 0; i < *chap->challenge.local; i++)
512122394Sharti        *cp++ = random() & 0xff;
513122394Sharti    }
514122394Sharti    memcpy(cp, authp->physical->dl->bundle->cfg.auth.name, len);
515122394Sharti  }
516122394Sharti}
517122394Sharti
518122394Shartistatic void
519122394Shartichap_Challenge(struct authinfo *authp)
520122394Sharti{
521122394Sharti  struct chap *chap = auth2chap(authp);
522122394Sharti  int len;
523122394Sharti
524122394Sharti  log_Printf(LogDEBUG, "CHAP%02X: Challenge\n",
525122394Sharti             authp->physical->link.lcp.want_authtype);
526122394Sharti
527122394Sharti  len = strlen(authp->physical->dl->bundle->cfg.auth.name);
528122394Sharti
529122394Sharti  /* Generate new local challenge value */
530122394Sharti  if (!*chap->challenge.local)
531122394Sharti    chap_ChallengeInit(authp);
532122394Sharti
533122394Sharti#ifndef NODES
534122394Sharti  if (authp->physical->link.lcp.want_authtype == 0x81)
535122394Sharti    ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id,
536122394Sharti             chap->challenge.local, 1 + *chap->challenge.local, NULL);
537122394Sharti  else
538122394Sharti#endif
539122394Sharti    ChapOutput(authp->physical, CHAP_CHALLENGE, authp->id,
540122394Sharti             chap->challenge.local, 1 + *chap->challenge.local + len, NULL);
541122394Sharti}
542122394Sharti
543122394Shartistatic void
544122394Shartichap_Success(struct authinfo *authp)
545122394Sharti{
546122394Sharti  struct bundle *bundle = authp->physical->dl->bundle;
547122394Sharti  const char *msg;
548122394Sharti
549122394Sharti  datalink_GotAuthname(authp->physical->dl, authp->in.name);
550122394Sharti#ifndef NODES
551122394Sharti  if (authp->physical->link.lcp.want_authtype == 0x81) {
552122394Sharti#ifndef NORADIUS
553122394Sharti    if (*bundle->radius.cfg.file && bundle->radius.msrepstr)
554122394Sharti      msg = bundle->radius.msrepstr;
555122394Sharti    else
556122394Sharti#endif
557122394Sharti      msg = auth2chap(authp)->authresponse;
558122394Sharti    MPPE_MasterKeyValid = 1;		/* XXX Global ! */
559122394Sharti  } else
560122394Sharti#endif
561122394Sharti#ifndef NORADIUS
562122394Sharti  if (*bundle->radius.cfg.file && bundle->radius.repstr)
563122394Sharti    msg = bundle->radius.repstr;
564122394Sharti  else
565122394Sharti#endif
566122394Sharti    msg = "Welcome!!";
567122394Sharti
568122394Sharti  ChapOutput(authp->physical, CHAP_SUCCESS, authp->id, msg, strlen(msg),
569122394Sharti             NULL);
570122394Sharti
571122394Sharti  authp->physical->link.lcp.auth_ineed = 0;
572122394Sharti  if (Enabled(bundle, OPT_UTMP))
573122394Sharti    physical_Login(authp->physical, authp->in.name);
574122394Sharti
575122394Sharti  if (authp->physical->link.lcp.auth_iwait == 0)
576122394Sharti    /*
577122394Sharti     * Either I didn't need to authenticate, or I've already been
578122394Sharti     * told that I got the answer right.
579122394Sharti     */
580122394Sharti    datalink_AuthOk(authp->physical->dl);
581122394Sharti}
582122394Sharti
583122394Shartistatic void
584122394Shartichap_Failure(struct authinfo *authp)
585122394Sharti{
586122394Sharti#ifndef NODES
587122394Sharti  char buf[1024], *ptr;
588122394Sharti#endif
589122394Sharti  const char *msg;
590122394Sharti
591122394Sharti#ifndef NORADIUS
592122394Sharti  struct bundle *bundle = authp->physical->link.lcp.fsm.bundle;
593122394Sharti  if (*bundle->radius.cfg.file && bundle->radius.errstr)
594122394Sharti    msg = bundle->radius.errstr;
595122394Sharti  else
596122394Sharti#endif
597122394Sharti#ifndef NODES
598122394Sharti  if (authp->physical->link.lcp.want_authtype == 0x80) {
599122394Sharti    sprintf(buf, "E=691 R=1 M=Invalid!");
600122394Sharti    msg = buf;
601122394Sharti  } else if (authp->physical->link.lcp.want_authtype == 0x81) {
602122394Sharti    int i;
603122394Sharti
604122394Sharti    ptr = buf;
605122394Sharti    ptr += sprintf(buf, "E=691 R=0 C=");
606122394Sharti    for (i=0; i<16; i++)
607122394Sharti      ptr += sprintf(ptr, "%02X", *(auth2chap(authp)->challenge.local+1+i));
608122394Sharti
609122394Sharti    sprintf(ptr, " V=3 M=Invalid!");
610122394Sharti    msg = buf;
611122394Sharti  } else
612122394Sharti#endif
613122394Sharti    msg = "Invalid!!";
614122394Sharti
615122394Sharti  ChapOutput(authp->physical, CHAP_FAILURE, authp->id, msg, strlen(msg) + 1,
616122394Sharti             NULL);
617122394Sharti  datalink_AuthNotOk(authp->physical->dl);
618122394Sharti}
619122394Sharti
620122394Shartistatic int
621122394Shartichap_Cmp(u_char type, char *myans, int mylen, char *hisans, int hislen
622122394Sharti#ifndef NODES
623122394Sharti         , int lm
624122394Sharti#endif
625122394Sharti        )
626122394Sharti{
627122394Sharti  if (mylen != hislen)
628122394Sharti    return 0;
629122394Sharti#ifndef NODES
630122394Sharti  else if (type == 0x80) {
631122394Sharti    int off = lm ? 0 : 24;
632122394Sharti
633122394Sharti    if (memcmp(myans + off, hisans + off, 24))
634122394Sharti      return 0;
635122394Sharti  }
636122394Sharti#endif
637122394Sharti  else if (memcmp(myans, hisans, mylen))
638122394Sharti    return 0;
639122394Sharti
640122394Sharti  return 1;
641122394Sharti}
642122394Sharti
643122394Sharti#ifndef NODES
644122394Shartistatic int
645122394Shartichap_HaveAnotherGo(struct chap *chap)
646122394Sharti{
647122394Sharti  if (++chap->peertries < 3) {
648122394Sharti    /* Give the peer another shot */
649122394Sharti    *chap->challenge.local = '\0';
650122394Sharti    chap_Challenge(&chap->auth);
651122394Sharti    return 1;
652122394Sharti  }
653122394Sharti
654122394Sharti  return 0;
655122394Sharti}
656122394Sharti#endif
657122394Sharti
658122394Shartivoid
659122394Shartichap_Init(struct chap *chap, struct physical *p)
660122394Sharti{
661122394Sharti  chap->desc.type = CHAP_DESCRIPTOR;
662122394Sharti  chap->desc.UpdateSet = chap_UpdateSet;
663122394Sharti  chap->desc.IsSet = chap_IsSet;
664122394Sharti  chap->desc.Read = chap_Read;
665122394Sharti  chap->desc.Write = chap_Write;
666122394Sharti  chap->child.pid = 0;
667122394Sharti  chap->child.fd = -1;
668122394Sharti  auth_Init(&chap->auth, p, chap_Challenge, chap_Success, chap_Failure);
669122394Sharti  *chap->challenge.local = *chap->challenge.peer = '\0';
670122394Sharti#ifndef NODES
671122394Sharti  chap->NTRespSent = 0;
672122394Sharti  chap->peertries = 0;
673122394Sharti#endif
674122394Sharti}
675122394Sharti
676122394Shartivoid
677122394Shartichap_ReInit(struct chap *chap)
678122394Sharti{
679122394Sharti  chap_Cleanup(chap, SIGTERM);
680122394Sharti}
681122394Sharti
682122394Shartistruct mbuf *
683122394Shartichap_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
684122394Sharti{
685122394Sharti  struct physical *p = link2physical(l);
686122394Sharti  struct chap *chap = &p->dl->chap;
687122394Sharti  char *name, *key, *ans;
688122394Sharti  int len, nlen;
689122394Sharti  u_char alen;
690122394Sharti#ifndef NODES
691122394Sharti  int lanman;
692122394Sharti#endif
693122394Sharti
694122394Sharti  if (p == NULL) {
695122394Sharti    log_Printf(LogERROR, "chap_Input: Not a physical link - dropped\n");
696122394Sharti    m_freem(bp);
697122394Sharti    return NULL;
698122394Sharti  }
699122394Sharti
700122394Sharti  if (bundle_Phase(bundle) != PHASE_NETWORK &&
701122394Sharti      bundle_Phase(bundle) != PHASE_AUTHENTICATE) {
702122394Sharti    log_Printf(LogPHASE, "Unexpected chap input - dropped !\n");
703122394Sharti    m_freem(bp);
704122394Sharti    return NULL;
705122394Sharti  }
706122394Sharti
707122394Sharti  m_settype(bp, MB_CHAPIN);
708122394Sharti  if ((bp = auth_ReadHeader(&chap->auth, bp)) == NULL &&
709122394Sharti      ntohs(chap->auth.in.hdr.length) == 0)
710122394Sharti    log_Printf(LogWARN, "Chap Input: Truncated header !\n");
711122394Sharti  else if (chap->auth.in.hdr.code == 0 || chap->auth.in.hdr.code > MAXCHAPCODE)
712122394Sharti    log_Printf(LogPHASE, "Chap Input: %d: Bad CHAP code !\n",
713122394Sharti               chap->auth.in.hdr.code);
714122394Sharti  else {
715122394Sharti    len = m_length(bp);
716122394Sharti    ans = NULL;
717122394Sharti
718122394Sharti    if (chap->auth.in.hdr.code != CHAP_CHALLENGE &&
719122394Sharti        chap->auth.id != chap->auth.in.hdr.id &&
720122394Sharti        Enabled(bundle, OPT_IDCHECK)) {
721122394Sharti      /* Wrong conversation dude ! */
722122394Sharti      log_Printf(LogPHASE, "Chap Input: %s dropped (got id %d, not %d)\n",
723122394Sharti                 chapcodes[chap->auth.in.hdr.code], chap->auth.in.hdr.id,
724122394Sharti                 chap->auth.id);
725122394Sharti      m_freem(bp);
726122394Sharti      return NULL;
727122394Sharti    }
728122394Sharti    chap->auth.id = chap->auth.in.hdr.id;	/* We respond with this id */
729122394Sharti
730122394Sharti#ifndef NODES
731122394Sharti    lanman = 0;
732122394Sharti#endif
733122394Sharti    switch (chap->auth.in.hdr.code) {
734122394Sharti      case CHAP_CHALLENGE:
735122394Sharti        bp = mbuf_Read(bp, &alen, 1);
736122394Sharti        len -= alen + 1;
737122394Sharti        if (len < 0) {
738122394Sharti          log_Printf(LogERROR, "Chap Input: Truncated challenge !\n");
739122394Sharti          m_freem(bp);
740122394Sharti          return NULL;
741122394Sharti        }
742122394Sharti        *chap->challenge.peer = alen;
743122394Sharti        bp = mbuf_Read(bp, chap->challenge.peer + 1, alen);
744122394Sharti        bp = auth_ReadName(&chap->auth, bp, len);
745122394Sharti#ifndef NODES
746122394Sharti        lanman = p->link.lcp.his_authtype == 0x80 &&
747122394Sharti                 ((chap->NTRespSent && IsAccepted(p->link.lcp.cfg.chap80lm)) ||
748122394Sharti                  !IsAccepted(p->link.lcp.cfg.chap80nt));
749122394Sharti
750122394Sharti        /* Generate local challenge value */
751122394Sharti        chap_ChallengeInit(&chap->auth);
752122394Sharti#endif
753122394Sharti        break;
754122394Sharti
755122394Sharti      case CHAP_RESPONSE:
756122394Sharti        auth_StopTimer(&chap->auth);
757122394Sharti        bp = mbuf_Read(bp, &alen, 1);
758122394Sharti        len -= alen + 1;
759122394Sharti        if (len < 0) {
760122394Sharti          log_Printf(LogERROR, "Chap Input: Truncated response !\n");
761122394Sharti          m_freem(bp);
762122394Sharti          return NULL;
763122394Sharti        }
764122394Sharti        if ((ans = malloc(alen + 2)) == NULL) {
765122394Sharti          log_Printf(LogERROR, "Chap Input: Out of memory !\n");
766122394Sharti          m_freem(bp);
767122394Sharti          return NULL;
768122394Sharti        }
769122394Sharti        *ans = chap->auth.id;
770122394Sharti        bp = mbuf_Read(bp, ans + 1, alen);
771122394Sharti        if (p->link.lcp.want_authtype == 0x81 && ans[alen] != '\0') {
772122394Sharti          log_Printf(LogWARN, "%s: Compensating for corrupt (Win98/WinME?) "
773122394Sharti                     "CHAP81 RESPONSE\n", l->name);
774122394Sharti          ans[alen] = '\0';
775122394Sharti        }
776122394Sharti        ans[alen+1] = '\0';
777122394Sharti        bp = auth_ReadName(&chap->auth, bp, len);
778122394Sharti#ifndef NODES
779122394Sharti        lanman = p->link.lcp.want_authtype == 0x80 &&
780122394Sharti                 alen == 49 && ans[alen] == 0;
781122394Sharti#endif
782122394Sharti        break;
783122394Sharti
784122394Sharti      case CHAP_SUCCESS:
785122394Sharti      case CHAP_FAILURE:
786122394Sharti        /* chap->auth.in.name is already set up at CHALLENGE time */
787122394Sharti        if ((ans = malloc(len + 1)) == NULL) {
788122394Sharti          log_Printf(LogERROR, "Chap Input: Out of memory !\n");
789122394Sharti          m_freem(bp);
790122394Sharti          return NULL;
791122394Sharti        }
792122394Sharti        bp = mbuf_Read(bp, ans, len);
793122394Sharti        ans[len] = '\0';
794122394Sharti        break;
795122394Sharti    }
796122394Sharti
797122394Sharti    switch (chap->auth.in.hdr.code) {
798122394Sharti      case CHAP_CHALLENGE:
799122394Sharti      case CHAP_RESPONSE:
800122394Sharti        if (*chap->auth.in.name)
801122394Sharti          log_Printf(LogPHASE, "Chap Input: %s (%d bytes from %s%s)\n",
802122394Sharti                     chapcodes[chap->auth.in.hdr.code], alen,
803122394Sharti                     chap->auth.in.name,
804122394Sharti#ifndef NODES
805122394Sharti                     lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
806133211Sharti                     " - lanman" :
807122394Sharti#endif
808133211Sharti                     "");
809122394Sharti        else
810122394Sharti          log_Printf(LogPHASE, "Chap Input: %s (%d bytes%s)\n",
811122394Sharti                     chapcodes[chap->auth.in.hdr.code], alen,
812122394Sharti#ifndef NODES
813122394Sharti                     lanman && chap->auth.in.hdr.code == CHAP_RESPONSE ?
814122394Sharti                     " - lanman" :
815122394Sharti#endif
816122394Sharti                     "");
817122394Sharti        break;
818122394Sharti
819133211Sharti      case CHAP_SUCCESS:
820122394Sharti      case CHAP_FAILURE:
821122394Sharti        if (*ans)
822122394Sharti          log_Printf(LogPHASE, "Chap Input: %s (%s)\n",
823122394Sharti                     chapcodes[chap->auth.in.hdr.code], ans);
824122394Sharti        else
825133211Sharti          log_Printf(LogPHASE, "Chap Input: %s\n",
826122394Sharti                     chapcodes[chap->auth.in.hdr.code]);
827133211Sharti        break;
828122394Sharti    }
829122394Sharti
830122394Sharti    switch (chap->auth.in.hdr.code) {
831122394Sharti      case CHAP_CHALLENGE:
832122394Sharti        if (*bundle->cfg.auth.key == '!' && bundle->cfg.auth.key[1] != '!')
833122394Sharti          chap_StartChild(chap, bundle->cfg.auth.key + 1,
834122394Sharti                          bundle->cfg.auth.name);
835122394Sharti        else
836122394Sharti          chap_Respond(chap, bundle->cfg.auth.name, bundle->cfg.auth.key +
837133211Sharti                       (*bundle->cfg.auth.key == '!' ? 1 : 0),
838122394Sharti                       p->link.lcp.his_authtype
839122394Sharti#ifndef NODES
840122394Sharti                       , lanman
841122394Sharti#endif
842122394Sharti                      );
843133211Sharti        break;
844122394Sharti
845122394Sharti      case CHAP_RESPONSE:
846122394Sharti        name = chap->auth.in.name;
847122394Sharti        nlen = strlen(name);
848122394Sharti#ifndef NODES
849122394Sharti        if (p->link.lcp.want_authtype == 0x81) {
850122394Sharti          chap->challenge.peer[0] = CHAP81_CHALLENGE_LEN;
851122394Sharti          memcpy(chap->challenge.peer + 1, ans + 1, CHAP81_CHALLENGE_LEN);
852122394Sharti        }
853122394Sharti#endif
854133211Sharti
855122394Sharti#ifndef NORADIUS
856122394Sharti        if (*bundle->radius.cfg.file) {
857122394Sharti          if (!radius_Authenticate(&bundle->radius, &chap->auth,
858122394Sharti                                   chap->auth.in.name, ans, alen + 1,
859122394Sharti                                   chap->challenge.local + 1,
860122394Sharti                                   *chap->challenge.local,
861122394Sharti                                   chap->challenge.peer + 1,
862122394Sharti                                   *chap->challenge.peer))
863122394Sharti            chap_Failure(&chap->auth);
864122394Sharti        } else
865122394Sharti#endif
866122394Sharti        {
867122394Sharti          key = auth_GetSecret(bundle, name, nlen, p);
868122394Sharti          if (key) {
869122394Sharti            char *myans;
870133211Sharti#ifndef NODES
871122394Sharti            if (p->link.lcp.want_authtype == 0x80 &&
872133211Sharti                lanman && !IsEnabled(p->link.lcp.cfg.chap80lm)) {
873122394Sharti              log_Printf(LogPHASE, "Auth failure: LANMan not enabled\n");
874122394Sharti              if (chap_HaveAnotherGo(chap))
875122394Sharti                break;
876122394Sharti              key = NULL;
877122394Sharti            } else if (p->link.lcp.want_authtype == 0x80 &&
878122394Sharti                !lanman && !IsEnabled(p->link.lcp.cfg.chap80nt)) {
879122394Sharti              log_Printf(LogPHASE, "Auth failure: mschap not enabled\n");
880122394Sharti              if (chap_HaveAnotherGo(chap))
881122394Sharti                break;
882122394Sharti              key = NULL;
883122394Sharti            } else if (p->link.lcp.want_authtype == 0x81 &&
884122394Sharti                !IsEnabled(p->link.lcp.cfg.chap81)) {
885122394Sharti              log_Printf(LogPHASE, "Auth failure: CHAP81 not enabled\n");
886122394Sharti              key = NULL;
887122394Sharti            } else
888122394Sharti#endif
889122394Sharti            {
890122394Sharti              myans = chap_BuildAnswer(name, key, chap->auth.id,
891122394Sharti                                       chap->challenge.local,
892122394Sharti                                       p->link.lcp.want_authtype
893122394Sharti#ifndef NODES
894122394Sharti                                       , chap->challenge.peer,
895122394Sharti                                       chap->authresponse, lanman);
896122394Sharti              MPPE_IsServer = 1;		/* XXX Global ! */
897122394Sharti#else
898122394Sharti                                      );
899122394Sharti#endif
900122394Sharti              if (myans == NULL)
901122394Sharti                key = NULL;
902122394Sharti              else {
903122394Sharti                if (!chap_Cmp(p->link.lcp.want_authtype, myans + 1, *myans,
904122394Sharti                              ans + 1, alen
905122394Sharti#ifndef NODES
906122394Sharti                              , lanman
907122394Sharti#endif
908122394Sharti                             ))
909122394Sharti                  key = NULL;
910122394Sharti                free(myans);
911122394Sharti              }
912122394Sharti            }
913122394Sharti          }
914122394Sharti
915122394Sharti          if (key)
916122394Sharti            chap_Success(&chap->auth);
917122394Sharti          else
918216294Ssyrinx            chap_Failure(&chap->auth);
919216294Ssyrinx        }
920216294Ssyrinx
921216294Ssyrinx        break;
922216294Ssyrinx
923216294Ssyrinx      case CHAP_SUCCESS:
924216294Ssyrinx        if (p->link.lcp.auth_iwait == PROTO_CHAP) {
925216294Ssyrinx          p->link.lcp.auth_iwait = 0;
926216294Ssyrinx          if (p->link.lcp.auth_ineed == 0) {
927216294Ssyrinx#ifndef NODES
928216294Ssyrinx            if (p->link.lcp.his_authtype == 0x81) {
929216294Ssyrinx              if (strncmp(ans, chap->authresponse, 42) &&
930216294Ssyrinx                  (*ans != 1 || strncmp(ans + 1, chap->authresponse, 41))) {
931216294Ssyrinx                datalink_AuthNotOk(p->dl);
932122394Sharti	        log_Printf(LogWARN, "CHAP81: AuthenticatorResponse: (%.42s)"
933122394Sharti                           " != ans: (%.42s)\n", chap->authresponse, ans);
934122394Sharti
935122394Sharti              } else {
936122394Sharti                /* Successful login */
937122394Sharti                MPPE_MasterKeyValid = 1;		/* XXX Global ! */
938122394Sharti                datalink_AuthOk(p->dl);
939122394Sharti              }
940122394Sharti            } else
941122394Sharti#endif
942122394Sharti            /*
943122394Sharti             * We've succeeded in our ``login''
944122394Sharti             * If we're not expecting  the peer to authenticate (or he already
945122394Sharti             * has), proceed to network phase.
946122394Sharti             */
947122394Sharti            datalink_AuthOk(p->dl);
948122394Sharti          }
949122394Sharti        }
950122394Sharti        break;
951122394Sharti
952122394Sharti      case CHAP_FAILURE:
953122394Sharti        datalink_AuthNotOk(p->dl);
954122394Sharti        break;
955122394Sharti    }
956122394Sharti    free(ans);
957122394Sharti  }
958122394Sharti
959122394Sharti  m_freem(bp);
960122394Sharti  return NULL;
961122394Sharti}
962122394Sharti