178189Sbrian/*-
278189Sbrian * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
378189Sbrian *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
478189Sbrian *                           Internet Initiative Japan, Inc (IIJ)
578189Sbrian * All rights reserved.
66059Samurai *
778189Sbrian * Redistribution and use in source and binary forms, with or without
878189Sbrian * modification, are permitted provided that the following conditions
978189Sbrian * are met:
1078189Sbrian * 1. Redistributions of source code must retain the above copyright
1178189Sbrian *    notice, this list of conditions and the following disclaimer.
1278189Sbrian * 2. Redistributions in binary form must reproduce the above copyright
1378189Sbrian *    notice, this list of conditions and the following disclaimer in the
1478189Sbrian *    documentation and/or other materials provided with the distribution.
156059Samurai *
1678189Sbrian * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1778189Sbrian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1878189Sbrian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1978189Sbrian * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2078189Sbrian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2178189Sbrian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2278189Sbrian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2378189Sbrian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2478189Sbrian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2578189Sbrian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2678189Sbrian * SUCH DAMAGE.
276059Samurai *
2850479Speter * $FreeBSD$
296059Samurai */
3078189Sbrian
3143313Sbrian#include <sys/param.h>
3230715Sbrian#include <netinet/in.h>
3336285Sbrian#include <netinet/in_systm.h>
3436285Sbrian#include <netinet/ip.h>
3581634Sbrian#include <sys/socket.h>
3636285Sbrian#include <sys/un.h>
3730715Sbrian
3843693Sbrian#include <stdlib.h>
3949472Sbrian#include <string.h>		/* strlen/memcpy */
4036285Sbrian#include <termios.h>
4130715Sbrian
4246686Sbrian#include "layer.h"
4330715Sbrian#include "mbuf.h"
4430715Sbrian#include "log.h"
4530715Sbrian#include "defs.h"
4630715Sbrian#include "timer.h"
476059Samurai#include "fsm.h"
4836285Sbrian#include "auth.h"
496059Samurai#include "pap.h"
5036285Sbrian#include "lqr.h"
516059Samurai#include "hdlc.h"
5263484Sbrian#include "lcp.h"
5346686Sbrian#include "proto.h"
5436285Sbrian#include "async.h"
5536285Sbrian#include "throughput.h"
5636285Sbrian#include "ccp.h"
5736285Sbrian#include "link.h"
5836285Sbrian#include "descriptor.h"
5936285Sbrian#include "physical.h"
6036285Sbrian#include "iplist.h"
6136285Sbrian#include "slcompress.h"
6281634Sbrian#include "ncpaddr.h"
6336285Sbrian#include "ipcp.h"
6436285Sbrian#include "filter.h"
6536285Sbrian#include "mp.h"
6643313Sbrian#ifndef NORADIUS
6743313Sbrian#include "radius.h"
6843313Sbrian#endif
6981634Sbrian#include "ipv6cp.h"
7081634Sbrian#include "ncp.h"
7136285Sbrian#include "bundle.h"
7236285Sbrian#include "chat.h"
7336285Sbrian#include "chap.h"
7438174Sbrian#include "cbcp.h"
7536285Sbrian#include "datalink.h"
766059Samurai
7755146Sbrianstatic const char * const papcodes[] = {
7855146Sbrian  "???", "REQUEST", "SUCCESS", "FAILURE"
7955146Sbrian};
8043693Sbrian#define MAXPAPCODE (sizeof papcodes / sizeof papcodes[0] - 1)
816059Samurai
8243693Sbrianstatic void
8343693Sbrianpap_Req(struct authinfo *authp)
846059Samurai{
8543693Sbrian  struct bundle *bundle = authp->physical->dl->bundle;
866059Samurai  struct fsmheader lh;
876059Samurai  struct mbuf *bp;
886059Samurai  u_char *cp;
896059Samurai  int namelen, keylen, plen;
906059Samurai
9143693Sbrian  namelen = strlen(bundle->cfg.auth.name);
9243693Sbrian  keylen = strlen(bundle->cfg.auth.key);
936059Samurai  plen = namelen + keylen + 2;
9443693Sbrian  log_Printf(LogDEBUG, "pap_Req: namelen = %d, keylen = %d\n", namelen, keylen);
9543693Sbrian  log_Printf(LogPHASE, "Pap Output: %s ********\n", bundle->cfg.auth.name);
9643693Sbrian  if (*bundle->cfg.auth.name == '\0')
9737926Sbrian    log_Printf(LogWARN, "Sending empty PAP authname!\n");
986059Samurai  lh.code = PAP_REQUEST;
9943693Sbrian  lh.id = authp->id;
1006059Samurai  lh.length = htons(plen + sizeof(struct fsmheader));
10154912Sbrian  bp = m_get(plen + sizeof(struct fsmheader), MB_PAPOUT);
10230715Sbrian  memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
1036059Samurai  cp = MBUF_CTOP(bp) + sizeof(struct fsmheader);
1046059Samurai  *cp++ = namelen;
10543693Sbrian  memcpy(cp, bundle->cfg.auth.name, namelen);
1066059Samurai  cp += namelen;
1076059Samurai  *cp++ = keylen;
10843693Sbrian  memcpy(cp, bundle->cfg.auth.key, keylen);
10950867Sbrian  link_PushPacket(&authp->physical->link, bp, bundle,
11050867Sbrian                  LINK_QUEUES(&authp->physical->link) - 1, PROTO_PAP);
1116059Samurai}
1126059Samurai
1136059Samuraistatic void
11443693SbrianSendPapCode(struct authinfo *authp, int code, const char *message)
1156059Samurai{
1166059Samurai  struct fsmheader lh;
1176059Samurai  struct mbuf *bp;
1186059Samurai  u_char *cp;
1196059Samurai  int plen, mlen;
1206059Samurai
1216059Samurai  lh.code = code;
12243693Sbrian  lh.id = authp->id;
1236059Samurai  mlen = strlen(message);
1246059Samurai  plen = mlen + 1;
1256059Samurai  lh.length = htons(plen + sizeof(struct fsmheader));
12654912Sbrian  bp = m_get(plen + sizeof(struct fsmheader), MB_PAPOUT);
12730715Sbrian  memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
1286059Samurai  cp = MBUF_CTOP(bp) + sizeof(struct fsmheader);
12953734Sbrian  /*
13053734Sbrian   * If our message is longer than 255 bytes, truncate the length to
13153734Sbrian   * 255 and send the entire message anyway.  Maybe the other end will
13253734Sbrian   * display it... (see pap_Input() !)
13353734Sbrian   */
13453734Sbrian  *cp++ = mlen > 255 ? 255 : mlen;
13530715Sbrian  memcpy(cp, message, mlen);
13637926Sbrian  log_Printf(LogPHASE, "Pap Output: %s\n", papcodes[code]);
13743693Sbrian
13846686Sbrian  link_PushPacket(&authp->physical->link, bp, authp->physical->dl->bundle,
13950867Sbrian                  LINK_QUEUES(&authp->physical->link) - 1, PROTO_PAP);
1406059Samurai}
1416059Samurai
14243693Sbrianstatic void
14343693Sbrianpap_Success(struct authinfo *authp)
1446059Samurai{
14596324Sbrian  struct bundle *bundle = authp->physical->dl->bundle;
14696324Sbrian
14743693Sbrian  datalink_GotAuthname(authp->physical->dl, authp->in.name);
14896324Sbrian#ifndef NORADIUS
14996324Sbrian  if (*bundle->radius.cfg.file && bundle->radius.repstr)
15096324Sbrian    SendPapCode(authp, PAP_ACK, bundle->radius.repstr);
15196324Sbrian  else
15296324Sbrian#endif
15396324Sbrian    SendPapCode(authp, PAP_ACK, "Greetings!!");
15443693Sbrian  authp->physical->link.lcp.auth_ineed = 0;
15596324Sbrian  if (Enabled(bundle, OPT_UTMP))
15643693Sbrian    physical_Login(authp->physical, authp->in.name);
1576059Samurai
15843693Sbrian  if (authp->physical->link.lcp.auth_iwait == 0)
15943693Sbrian    /*
16043693Sbrian     * Either I didn't need to authenticate, or I've already been
16143693Sbrian     * told that I got the answer right.
16243693Sbrian     */
16343693Sbrian    datalink_AuthOk(authp->physical->dl);
16443693Sbrian}
16518752Sjkh
16643693Sbrianstatic void
16743693Sbrianpap_Failure(struct authinfo *authp)
16843693Sbrian{
16943693Sbrian  SendPapCode(authp, PAP_NAK, "Login incorrect");
17043693Sbrian  datalink_AuthNotOk(authp->physical->dl);
1716059Samurai}
1726059Samurai
1736059Samuraivoid
17443693Sbrianpap_Init(struct authinfo *pap, struct physical *p)
1756059Samurai{
17643693Sbrian  auth_Init(pap, p, pap_Req, pap_Success, pap_Failure);
17743693Sbrian}
1786059Samurai
17946686Sbrianstruct mbuf *
18046686Sbrianpap_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
18143693Sbrian{
18246686Sbrian  struct physical *p = link2physical(l);
18343693Sbrian  struct authinfo *authp = &p->dl->pap;
18443693Sbrian  u_char nlen, klen, *key;
18553734Sbrian  const char *txt;
18653734Sbrian  int txtlen;
18736285Sbrian
18846686Sbrian  if (p == NULL) {
18946686Sbrian    log_Printf(LogERROR, "pap_Input: Not a physical link - dropped\n");
19054912Sbrian    m_freem(bp);
19146686Sbrian    return NULL;
19246686Sbrian  }
19346686Sbrian
19446686Sbrian  if (bundle_Phase(bundle) != PHASE_NETWORK &&
19546686Sbrian      bundle_Phase(bundle) != PHASE_AUTHENTICATE) {
19645220Sbrian    log_Printf(LogPHASE, "Unexpected pap input - dropped !\n");
19754912Sbrian    m_freem(bp);
19846686Sbrian    return NULL;
19945220Sbrian  }
20045220Sbrian
20144159Sbrian  if ((bp = auth_ReadHeader(authp, bp)) == NULL &&
20244159Sbrian      ntohs(authp->in.hdr.length) == 0) {
20344159Sbrian    log_Printf(LogWARN, "Pap Input: Truncated header !\n");
20446686Sbrian    return NULL;
20544159Sbrian  }
20643693Sbrian
20743693Sbrian  if (authp->in.hdr.code == 0 || authp->in.hdr.code > MAXPAPCODE) {
20843693Sbrian    log_Printf(LogPHASE, "Pap Input: %d: Bad PAP code !\n", authp->in.hdr.code);
20954912Sbrian    m_freem(bp);
21046686Sbrian    return NULL;
21143693Sbrian  }
21243693Sbrian
21343693Sbrian  if (authp->in.hdr.code != PAP_REQUEST && authp->id != authp->in.hdr.id &&
21446686Sbrian      Enabled(bundle, OPT_IDCHECK)) {
21543693Sbrian    /* Wrong conversation dude ! */
21643693Sbrian    log_Printf(LogPHASE, "Pap Input: %s dropped (got id %d, not %d)\n",
21743693Sbrian               papcodes[authp->in.hdr.code], authp->in.hdr.id, authp->id);
21854912Sbrian    m_freem(bp);
21946686Sbrian    return NULL;
22043693Sbrian  }
22154912Sbrian  m_settype(bp, MB_PAPIN);
22243693Sbrian  authp->id = authp->in.hdr.id;		/* We respond with this id */
22343693Sbrian
22443693Sbrian  if (bp) {
22543693Sbrian    bp = mbuf_Read(bp, &nlen, 1);
22653734Sbrian    if (authp->in.hdr.code == PAP_ACK) {
22753734Sbrian      /*
22853734Sbrian       * Don't restrict the length of our acknowledgement freetext to
22953734Sbrian       * nlen (a one-byte length).  Show the rest of the ack packet
23053734Sbrian       * instead.  This isn't really part of the protocol.....
23153734Sbrian       */
23254912Sbrian      bp = m_pullup(bp);
23353734Sbrian      txt = MBUF_CTOP(bp);
23454912Sbrian      txtlen = m_length(bp);
23553734Sbrian    } else {
23653734Sbrian      bp = auth_ReadName(authp, bp, nlen);
23753734Sbrian      txt = authp->in.name;
23853734Sbrian      txtlen = strlen(authp->in.name);
23953734Sbrian    }
24053734Sbrian  } else {
24153734Sbrian    txt = "";
24253734Sbrian    txtlen = 0;
24343693Sbrian  }
24443693Sbrian
24553734Sbrian  log_Printf(LogPHASE, "Pap Input: %s (%.*s)\n",
24653734Sbrian             papcodes[authp->in.hdr.code], txtlen, txt);
24743693Sbrian
24843693Sbrian  switch (authp->in.hdr.code) {
24943693Sbrian    case PAP_REQUEST:
25043693Sbrian      if (bp == NULL) {
25143693Sbrian        log_Printf(LogPHASE, "Pap Input: No key given !\n");
25243693Sbrian        break;
2536059Samurai      }
25443693Sbrian      bp = mbuf_Read(bp, &klen, 1);
25554912Sbrian      if (m_length(bp) < klen) {
25643693Sbrian        log_Printf(LogERROR, "Pap Input: Truncated key !\n");
25743693Sbrian        break;
25843693Sbrian      }
25943693Sbrian      if ((key = malloc(klen+1)) == NULL) {
26043693Sbrian        log_Printf(LogERROR, "Pap Input: Out of memory !\n");
26143693Sbrian        break;
26243693Sbrian      }
26343693Sbrian      bp = mbuf_Read(bp, key, klen);
26443693Sbrian      key[klen] = '\0';
26543693Sbrian
26643693Sbrian#ifndef NORADIUS
26796730Sbrian      if (*bundle->radius.cfg.file) {
26896730Sbrian        if (!radius_Authenticate(&bundle->radius, authp, authp->in.name,
26998311Sbrian                                 key, strlen(key), NULL, 0))
27096730Sbrian          pap_Failure(authp);
27196730Sbrian      } else
27243693Sbrian#endif
273134789Sbrian      if (auth_Validate(bundle, authp->in.name, key))
27443693Sbrian        pap_Success(authp);
27543693Sbrian      else
27643693Sbrian        pap_Failure(authp);
27743693Sbrian
27843693Sbrian      free(key);
27943693Sbrian      break;
28043693Sbrian
28143693Sbrian    case PAP_ACK:
28243693Sbrian      auth_StopTimer(authp);
28343693Sbrian      if (p->link.lcp.auth_iwait == PROTO_PAP) {
28443693Sbrian        p->link.lcp.auth_iwait = 0;
28543693Sbrian        if (p->link.lcp.auth_ineed == 0)
28643693Sbrian          /*
28743693Sbrian           * We've succeeded in our ``login''
28843693Sbrian           * If we're not expecting  the peer to authenticate (or he already
28943693Sbrian           * has), proceed to network phase.
29043693Sbrian           */
29143693Sbrian          datalink_AuthOk(p->dl);
29243693Sbrian      }
29343693Sbrian      break;
29443693Sbrian
29543693Sbrian    case PAP_NAK:
29643693Sbrian      auth_StopTimer(authp);
29743693Sbrian      datalink_AuthNotOk(p->dl);
29843693Sbrian      break;
2996059Samurai  }
30043693Sbrian
30154912Sbrian  m_freem(bp);
30246686Sbrian  return NULL;
3036059Samurai}
304