pap.c revision 134789
136270Swpaul/*-
236270Swpaul * Copyright (c) 1996 - 2001 Brian Somers <brian@Awfulhak.org>
336270Swpaul *          based on work by Toshiharu OHNO <tony-o@iij.ad.jp>
436270Swpaul *                           Internet Initiative Japan, Inc (IIJ)
536270Swpaul * All rights reserved.
636270Swpaul *
736270Swpaul * Redistribution and use in source and binary forms, with or without
836270Swpaul * modification, are permitted provided that the following conditions
936270Swpaul * are met:
1036270Swpaul * 1. Redistributions of source code must retain the above copyright
1136270Swpaul *    notice, this list of conditions and the following disclaimer.
1236270Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1336270Swpaul *    notice, this list of conditions and the following disclaimer in the
1436270Swpaul *    documentation and/or other materials provided with the distribution.
1536270Swpaul *
1636270Swpaul * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1736270Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1836270Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1936270Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2036270Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2136270Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2236270Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2336270Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2436270Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2536270Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2636270Swpaul * SUCH DAMAGE.
2736270Swpaul *
2836270Swpaul * $FreeBSD: head/usr.sbin/ppp/pap.c 134789 2004-09-05 01:46:52Z brian $
2936270Swpaul */
3036270Swpaul
3136270Swpaul#include <sys/param.h>
3243235Swpaul#include <netinet/in.h>
3336270Swpaul#include <netinet/in_systm.h>
3436270Swpaul#include <netinet/ip.h>
3536270Swpaul#include <sys/socket.h>
3636270Swpaul#include <sys/un.h>
3736270Swpaul
3836270Swpaul#include <stdlib.h>
3936270Swpaul#include <string.h>		/* strlen/memcpy */
4036270Swpaul#include <termios.h>
4139583Swpaul
4236270Swpaul#include "layer.h"
4336270Swpaul#include "mbuf.h"
4436270Swpaul#include "log.h"
4536270Swpaul#include "defs.h"
4639583Swpaul#include "timer.h"
4736270Swpaul#include "fsm.h"
4836270Swpaul#include "auth.h"
4936270Swpaul#include "pap.h"
5036270Swpaul#include "lqr.h"
5136270Swpaul#include "hdlc.h"
5236270Swpaul#include "lcp.h"
5336270Swpaul#include "proto.h"
5436270Swpaul#include "async.h"
5536270Swpaul#include "throughput.h"
5636270Swpaul#include "ccp.h"
5736270Swpaul#include "link.h"
5839583Swpaul#include "descriptor.h"
5936270Swpaul#include "physical.h"
6036270Swpaul#include "iplist.h"
6136270Swpaul#include "slcompress.h"
6236270Swpaul#include "ncpaddr.h"
6336270Swpaul#include "ipcp.h"
6436270Swpaul#include "filter.h"
6536270Swpaul#include "mp.h"
6639583Swpaul#ifndef NORADIUS
6739583Swpaul#include "radius.h"
6839583Swpaul#endif
6939583Swpaul#include "ipv6cp.h"
7039583Swpaul#include "ncp.h"
7139583Swpaul#include "bundle.h"
7239583Swpaul#include "chat.h"
7339583Swpaul#include "chap.h"
7439583Swpaul#include "cbcp.h"
7536270Swpaul#include "datalink.h"
7636270Swpaul
7739583Swpaulstatic const char * const papcodes[] = {
7836270Swpaul  "???", "REQUEST", "SUCCESS", "FAILURE"
7936270Swpaul};
8036270Swpaul#define MAXPAPCODE (sizeof papcodes / sizeof papcodes[0] - 1)
8136270Swpaul
8236270Swpaulstatic void
8336270Swpaulpap_Req(struct authinfo *authp)
8436270Swpaul{
8536270Swpaul  struct bundle *bundle = authp->physical->dl->bundle;
8636270Swpaul  struct fsmheader lh;
8736270Swpaul  struct mbuf *bp;
8836270Swpaul  u_char *cp;
8936270Swpaul  int namelen, keylen, plen;
9036270Swpaul
9136270Swpaul  namelen = strlen(bundle->cfg.auth.name);
9236270Swpaul  keylen = strlen(bundle->cfg.auth.key);
9336270Swpaul  plen = namelen + keylen + 2;
9436270Swpaul  log_Printf(LogDEBUG, "pap_Req: namelen = %d, keylen = %d\n", namelen, keylen);
9536270Swpaul  log_Printf(LogPHASE, "Pap Output: %s ********\n", bundle->cfg.auth.name);
9636270Swpaul  if (*bundle->cfg.auth.name == '\0')
9736270Swpaul    log_Printf(LogWARN, "Sending empty PAP authname!\n");
9836270Swpaul  lh.code = PAP_REQUEST;
9936270Swpaul  lh.id = authp->id;
10036270Swpaul  lh.length = htons(plen + sizeof(struct fsmheader));
10136270Swpaul  bp = m_get(plen + sizeof(struct fsmheader), MB_PAPOUT);
10236270Swpaul  memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
10336270Swpaul  cp = MBUF_CTOP(bp) + sizeof(struct fsmheader);
10436270Swpaul  *cp++ = namelen;
10536270Swpaul  memcpy(cp, bundle->cfg.auth.name, namelen);
10636270Swpaul  cp += namelen;
10736270Swpaul  *cp++ = keylen;
10836270Swpaul  memcpy(cp, bundle->cfg.auth.key, keylen);
10936270Swpaul  link_PushPacket(&authp->physical->link, bp, bundle,
11036270Swpaul                  LINK_QUEUES(&authp->physical->link) - 1, PROTO_PAP);
11136270Swpaul}
11236270Swpaul
11336270Swpaulstatic void
11436270SwpaulSendPapCode(struct authinfo *authp, int code, const char *message)
11536270Swpaul{
11636270Swpaul  struct fsmheader lh;
11736270Swpaul  struct mbuf *bp;
11836270Swpaul  u_char *cp;
11936270Swpaul  int plen, mlen;
12036270Swpaul
12136270Swpaul  lh.code = code;
12236270Swpaul  lh.id = authp->id;
12336270Swpaul  mlen = strlen(message);
12436270Swpaul  plen = mlen + 1;
12536270Swpaul  lh.length = htons(plen + sizeof(struct fsmheader));
12636270Swpaul  bp = m_get(plen + sizeof(struct fsmheader), MB_PAPOUT);
12736270Swpaul  memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
12836270Swpaul  cp = MBUF_CTOP(bp) + sizeof(struct fsmheader);
12936270Swpaul  /*
13036270Swpaul   * If our message is longer than 255 bytes, truncate the length to
13136270Swpaul   * 255 and send the entire message anyway.  Maybe the other end will
13236270Swpaul   * display it... (see pap_Input() !)
13336270Swpaul   */
13436270Swpaul  *cp++ = mlen > 255 ? 255 : mlen;
13536270Swpaul  memcpy(cp, message, mlen);
13636270Swpaul  log_Printf(LogPHASE, "Pap Output: %s\n", papcodes[code]);
13736270Swpaul
13836270Swpaul  link_PushPacket(&authp->physical->link, bp, authp->physical->dl->bundle,
13936270Swpaul                  LINK_QUEUES(&authp->physical->link) - 1, PROTO_PAP);
14036270Swpaul}
14136270Swpaul
14236270Swpaulstatic void
14336270Swpaulpap_Success(struct authinfo *authp)
14436270Swpaul{
14536270Swpaul  struct bundle *bundle = authp->physical->dl->bundle;
14636270Swpaul
14736270Swpaul  datalink_GotAuthname(authp->physical->dl, authp->in.name);
14836270Swpaul#ifndef NORADIUS
14936270Swpaul  if (*bundle->radius.cfg.file && bundle->radius.repstr)
15036270Swpaul    SendPapCode(authp, PAP_ACK, bundle->radius.repstr);
15136270Swpaul  else
15236270Swpaul#endif
15336270Swpaul    SendPapCode(authp, PAP_ACK, "Greetings!!");
15436270Swpaul  authp->physical->link.lcp.auth_ineed = 0;
15536270Swpaul  if (Enabled(bundle, OPT_UTMP))
15636270Swpaul    physical_Login(authp->physical, authp->in.name);
15736270Swpaul
15836270Swpaul  if (authp->physical->link.lcp.auth_iwait == 0)
15936270Swpaul    /*
16036270Swpaul     * Either I didn't need to authenticate, or I've already been
16136270Swpaul     * told that I got the answer right.
16236270Swpaul     */
16336270Swpaul    datalink_AuthOk(authp->physical->dl);
16436270Swpaul}
16536270Swpaul
16636270Swpaulstatic void
16736270Swpaulpap_Failure(struct authinfo *authp)
16836270Swpaul{
16936270Swpaul  SendPapCode(authp, PAP_NAK, "Login incorrect");
17036270Swpaul  datalink_AuthNotOk(authp->physical->dl);
17136270Swpaul}
17236270Swpaul
17336270Swpaulvoid
17436270Swpaulpap_Init(struct authinfo *pap, struct physical *p)
17536270Swpaul{
17636270Swpaul  auth_Init(pap, p, pap_Req, pap_Success, pap_Failure);
17736270Swpaul}
17836270Swpaul
17936270Swpaulstruct mbuf *
18036270Swpaulpap_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
18136270Swpaul{
18236270Swpaul  struct physical *p = link2physical(l);
18336270Swpaul  struct authinfo *authp = &p->dl->pap;
18436270Swpaul  u_char nlen, klen, *key;
18536270Swpaul  const char *txt;
18636270Swpaul  int txtlen;
18736270Swpaul
18836270Swpaul  if (p == NULL) {
18936270Swpaul    log_Printf(LogERROR, "pap_Input: Not a physical link - dropped\n");
19036270Swpaul    m_freem(bp);
19136270Swpaul    return NULL;
19236270Swpaul  }
19336270Swpaul
19436270Swpaul  if (bundle_Phase(bundle) != PHASE_NETWORK &&
19536270Swpaul      bundle_Phase(bundle) != PHASE_AUTHENTICATE) {
19636270Swpaul    log_Printf(LogPHASE, "Unexpected pap input - dropped !\n");
19736270Swpaul    m_freem(bp);
19836270Swpaul    return NULL;
19936270Swpaul  }
20036270Swpaul
20136270Swpaul  if ((bp = auth_ReadHeader(authp, bp)) == NULL &&
20236270Swpaul      ntohs(authp->in.hdr.length) == 0) {
20336270Swpaul    log_Printf(LogWARN, "Pap Input: Truncated header !\n");
20436270Swpaul    return NULL;
20536270Swpaul  }
20636270Swpaul
20736270Swpaul  if (authp->in.hdr.code == 0 || authp->in.hdr.code > MAXPAPCODE) {
20839957Swpaul    log_Printf(LogPHASE, "Pap Input: %d: Bad PAP code !\n", authp->in.hdr.code);
20939957Swpaul    m_freem(bp);
21039957Swpaul    return NULL;
21139957Swpaul  }
21239957Swpaul
21339957Swpaul  if (authp->in.hdr.code != PAP_REQUEST && authp->id != authp->in.hdr.id &&
21439957Swpaul      Enabled(bundle, OPT_IDCHECK)) {
21539583Swpaul    /* Wrong conversation dude ! */
21639583Swpaul    log_Printf(LogPHASE, "Pap Input: %s dropped (got id %d, not %d)\n",
21736270Swpaul               papcodes[authp->in.hdr.code], authp->in.hdr.id, authp->id);
21836270Swpaul    m_freem(bp);
21941591Sarchie    return NULL;
22041591Sarchie  }
22143235Swpaul  m_settype(bp, MB_PAPIN);
22236270Swpaul  authp->id = authp->in.hdr.id;		/* We respond with this id */
22336270Swpaul
22439583Swpaul  if (bp) {
22539583Swpaul    bp = mbuf_Read(bp, &nlen, 1);
22639583Swpaul    if (authp->in.hdr.code == PAP_ACK) {
22739583Swpaul      /*
22839583Swpaul       * Don't restrict the length of our acknowledgement freetext to
22939583Swpaul       * nlen (a one-byte length).  Show the rest of the ack packet
23039583Swpaul       * instead.  This isn't really part of the protocol.....
23139583Swpaul       */
23239583Swpaul      bp = m_pullup(bp);
23339583Swpaul      txt = MBUF_CTOP(bp);
23439583Swpaul      txtlen = m_length(bp);
23539583Swpaul    } else {
23639583Swpaul      bp = auth_ReadName(authp, bp, nlen);
23739583Swpaul      txt = authp->in.name;
23839583Swpaul      txtlen = strlen(authp->in.name);
23939583Swpaul    }
24039583Swpaul  } else {
24139583Swpaul    txt = "";
24239583Swpaul    txtlen = 0;
24339583Swpaul  }
24439583Swpaul
24539583Swpaul  log_Printf(LogPHASE, "Pap Input: %s (%.*s)\n",
24639583Swpaul             papcodes[authp->in.hdr.code], txtlen, txt);
24739583Swpaul
24839583Swpaul  switch (authp->in.hdr.code) {
24939583Swpaul    case PAP_REQUEST:
25039583Swpaul      if (bp == NULL) {
25139583Swpaul        log_Printf(LogPHASE, "Pap Input: No key given !\n");
25239583Swpaul        break;
25339583Swpaul      }
25439583Swpaul      bp = mbuf_Read(bp, &klen, 1);
25539583Swpaul      if (m_length(bp) < klen) {
25639583Swpaul        log_Printf(LogERROR, "Pap Input: Truncated key !\n");
25739583Swpaul        break;
25839583Swpaul      }
25939583Swpaul      if ((key = malloc(klen+1)) == NULL) {
26039583Swpaul        log_Printf(LogERROR, "Pap Input: Out of memory !\n");
26139583Swpaul        break;
26239583Swpaul      }
26339583Swpaul      bp = mbuf_Read(bp, key, klen);
26439583Swpaul      key[klen] = '\0';
26536270Swpaul
26636270Swpaul#ifndef NORADIUS
26736270Swpaul      if (*bundle->radius.cfg.file) {
26836270Swpaul        if (!radius_Authenticate(&bundle->radius, authp, authp->in.name,
26936270Swpaul                                 key, strlen(key), NULL, 0))
27036270Swpaul          pap_Failure(authp);
27136270Swpaul      } else
27236270Swpaul#endif
27336270Swpaul      if (auth_Validate(bundle, authp->in.name, key))
27436270Swpaul        pap_Success(authp);
27536270Swpaul      else
27636270Swpaul        pap_Failure(authp);
27736270Swpaul
27836270Swpaul      free(key);
27936270Swpaul      break;
28036270Swpaul
28136270Swpaul    case PAP_ACK:
28236270Swpaul      auth_StopTimer(authp);
28336270Swpaul      if (p->link.lcp.auth_iwait == PROTO_PAP) {
28436270Swpaul        p->link.lcp.auth_iwait = 0;
28536270Swpaul        if (p->link.lcp.auth_ineed == 0)
28637626Swpaul          /*
28737626Swpaul           * We've succeeded in our ``login''
28837626Swpaul           * If we're not expecting  the peer to authenticate (or he already
28937626Swpaul           * has), proceed to network phase.
29037626Swpaul           */
29137626Swpaul          datalink_AuthOk(p->dl);
29237626Swpaul      }
29337626Swpaul      break;
29437626Swpaul
29537626Swpaul    case PAP_NAK:
29637626Swpaul      auth_StopTimer(authp);
29737626Swpaul      datalink_AuthNotOk(p->dl);
29836270Swpaul      break;
29936270Swpaul  }
30036270Swpaul
30136270Swpaul  m_freem(bp);
30236270Swpaul  return NULL;
30336270Swpaul}
30436270Swpaul