Home | History | Annotate | Download | only in src
      1 /*-
      2  * Copyright (c) 1996 - 2001 Brian Somers <brian (at) Awfulhak.org>
      3  *          based on work by Toshiharu OHNO <tony-o (at) 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: src/usr.sbin/ppp/pap.c,v 1.51.26.1 2010/12/21 17:10:29 kensmith Exp $
     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 <stdlib.h>
     39 #include <string.h>		/* strlen/memcpy */
     40 #include <termios.h>
     41 
     42 #include "layer.h"
     43 #include "mbuf.h"
     44 #include "log.h"
     45 #include "defs.h"
     46 #include "timer.h"
     47 #include "fsm.h"
     48 #include "auth.h"
     49 #include "pap.h"
     50 #include "lqr.h"
     51 #include "hdlc.h"
     52 #include "lcp.h"
     53 #include "proto.h"
     54 #include "async.h"
     55 #include "throughput.h"
     56 #include "ccp.h"
     57 #include "link.h"
     58 #include "descriptor.h"
     59 #include "physical.h"
     60 #include "iplist.h"
     61 #include "slcompress.h"
     62 #include "ncpaddr.h"
     63 #include "ipcp.h"
     64 #include "filter.h"
     65 #include "mp.h"
     66 #ifndef NORADIUS
     67 #include "radius.h"
     68 #endif
     69 #include "ipv6cp.h"
     70 #include "ncp.h"
     71 #include "bundle.h"
     72 #include "chat.h"
     73 #include "chap.h"
     74 #include "cbcp.h"
     75 #include "datalink.h"
     76 
     77 static const char * const papcodes[] = {
     78   "???", "REQUEST", "SUCCESS", "FAILURE"
     79 };
     80 #define MAXPAPCODE (sizeof papcodes / sizeof papcodes[0] - 1)
     81 
     82 static void
     83 pap_Req(struct authinfo *authp)
     84 {
     85   struct bundle *bundle = authp->physical->dl->bundle;
     86   struct fsmheader lh;
     87   struct mbuf *bp;
     88   u_char *cp;
     89   int namelen, keylen, plen;
     90 
     91   namelen = strlen(bundle->cfg.auth.name);
     92   keylen = strlen(bundle->cfg.auth.key);
     93   plen = namelen + keylen + 2;
     94   log_Printf(LogDEBUG, "pap_Req: namelen = %d, keylen = %d\n", namelen, keylen);
     95   log_Printf(LogPHASE, "Pap Output: %s ********\n", bundle->cfg.auth.name);
     96   if (*bundle->cfg.auth.name == '\0')
     97     log_Printf(LogWARN, "Sending empty PAP authname!\n");
     98   lh.code = PAP_REQUEST;
     99   lh.id = authp->id;
    100   lh.length = htons(plen + sizeof(struct fsmheader));
    101   bp = m_get(plen + sizeof(struct fsmheader), MB_PAPOUT);
    102   memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
    103   cp = MBUF_CTOP(bp) + sizeof(struct fsmheader);
    104   *cp++ = namelen;
    105   memcpy(cp, bundle->cfg.auth.name, namelen);
    106   cp += namelen;
    107   *cp++ = keylen;
    108   memcpy(cp, bundle->cfg.auth.key, keylen);
    109   link_PushPacket(&authp->physical->link, bp, bundle,
    110                   LINK_QUEUES(&authp->physical->link) - 1, PROTO_PAP);
    111 }
    112 
    113 static void
    114 SendPapCode(struct authinfo *authp, int code, const char *message)
    115 {
    116   struct fsmheader lh;
    117   struct mbuf *bp;
    118   u_char *cp;
    119   int plen, mlen;
    120 
    121   lh.code = code;
    122   lh.id = authp->id;
    123   mlen = strlen(message);
    124   plen = mlen + 1;
    125   lh.length = htons(plen + sizeof(struct fsmheader));
    126   bp = m_get(plen + sizeof(struct fsmheader), MB_PAPOUT);
    127   memcpy(MBUF_CTOP(bp), &lh, sizeof(struct fsmheader));
    128   cp = MBUF_CTOP(bp) + sizeof(struct fsmheader);
    129   /*
    130    * If our message is longer than 255 bytes, truncate the length to
    131    * 255 and send the entire message anyway.  Maybe the other end will
    132    * display it... (see pap_Input() !)
    133    */
    134   *cp++ = mlen > 255 ? 255 : mlen;
    135   memcpy(cp, message, mlen);
    136   log_Printf(LogPHASE, "Pap Output: %s\n", papcodes[code]);
    137 
    138   link_PushPacket(&authp->physical->link, bp, authp->physical->dl->bundle,
    139                   LINK_QUEUES(&authp->physical->link) - 1, PROTO_PAP);
    140 }
    141 
    142 static void
    143 pap_Success(struct authinfo *authp)
    144 {
    145   struct bundle *bundle = authp->physical->dl->bundle;
    146 
    147   datalink_GotAuthname(authp->physical->dl, authp->in.name);
    148 #ifndef NORADIUS
    149   if (*bundle->radius.cfg.file && bundle->radius.repstr)
    150     SendPapCode(authp, PAP_ACK, bundle->radius.repstr);
    151   else
    152 #endif
    153     SendPapCode(authp, PAP_ACK, "Greetings!!");
    154   authp->physical->link.lcp.auth_ineed = 0;
    155   if (Enabled(bundle, OPT_UTMP))
    156     physical_Login(authp->physical, authp->in.name);
    157 
    158   if (authp->physical->link.lcp.auth_iwait == 0)
    159     /*
    160      * Either I didn't need to authenticate, or I've already been
    161      * told that I got the answer right.
    162      */
    163     datalink_AuthOk(authp->physical->dl);
    164 }
    165 
    166 static void
    167 pap_Failure(struct authinfo *authp)
    168 {
    169   SendPapCode(authp, PAP_NAK, "Login incorrect");
    170   datalink_AuthNotOk(authp->physical->dl);
    171 }
    172 
    173 void
    174 pap_Init(struct authinfo *pap, struct physical *p)
    175 {
    176   auth_Init(pap, p, pap_Req, pap_Success, pap_Failure);
    177 }
    178 
    179 struct mbuf *
    180 pap_Input(struct bundle *bundle, struct link *l, struct mbuf *bp)
    181 {
    182   struct physical *p = link2physical(l);
    183   struct authinfo *authp = &p->dl->pap;
    184   u_char nlen, klen, *key;
    185   const char *txt;
    186   int txtlen;
    187 
    188   if (p == NULL) {
    189     log_Printf(LogERROR, "pap_Input: Not a physical link - dropped\n");
    190     m_freem(bp);
    191     return NULL;
    192   }
    193 
    194   if (bundle_Phase(bundle) != PHASE_NETWORK &&
    195       bundle_Phase(bundle) != PHASE_AUTHENTICATE) {
    196     log_Printf(LogPHASE, "Unexpected pap input - dropped !\n");
    197     m_freem(bp);
    198     return NULL;
    199   }
    200 
    201   if ((bp = auth_ReadHeader(authp, bp)) == NULL &&
    202       ntohs(authp->in.hdr.length) == 0) {
    203     log_Printf(LogWARN, "Pap Input: Truncated header !\n");
    204     return NULL;
    205   }
    206 
    207   if (authp->in.hdr.code == 0 || authp->in.hdr.code > MAXPAPCODE) {
    208     log_Printf(LogPHASE, "Pap Input: %d: Bad PAP code !\n", authp->in.hdr.code);
    209     m_freem(bp);
    210     return NULL;
    211   }
    212 
    213   if (authp->in.hdr.code != PAP_REQUEST && authp->id != authp->in.hdr.id &&
    214       Enabled(bundle, OPT_IDCHECK)) {
    215     /* Wrong conversation dude ! */
    216     log_Printf(LogPHASE, "Pap Input: %s dropped (got id %d, not %d)\n",
    217                papcodes[authp->in.hdr.code], authp->in.hdr.id, authp->id);
    218     m_freem(bp);
    219     return NULL;
    220   }
    221   m_settype(bp, MB_PAPIN);
    222   authp->id = authp->in.hdr.id;		/* We respond with this id */
    223 
    224   if (bp) {
    225     bp = mbuf_Read(bp, &nlen, 1);
    226     if (authp->in.hdr.code == PAP_ACK) {
    227       /*
    228        * Don't restrict the length of our acknowledgement freetext to
    229        * nlen (a one-byte length).  Show the rest of the ack packet
    230        * instead.  This isn't really part of the protocol.....
    231        */
    232       bp = m_pullup(bp);
    233       txt = MBUF_CTOP(bp);
    234       txtlen = m_length(bp);
    235     } else {
    236       bp = auth_ReadName(authp, bp, nlen);
    237       txt = authp->in.name;
    238       txtlen = strlen(authp->in.name);
    239     }
    240   } else {
    241     txt = "";
    242     txtlen = 0;
    243   }
    244 
    245   log_Printf(LogPHASE, "Pap Input: %s (%.*s)\n",
    246              papcodes[authp->in.hdr.code], txtlen, txt);
    247 
    248   switch (authp->in.hdr.code) {
    249     case PAP_REQUEST:
    250       if (bp == NULL) {
    251         log_Printf(LogPHASE, "Pap Input: No key given !\n");
    252         break;
    253       }
    254       bp = mbuf_Read(bp, &klen, 1);
    255       if (m_length(bp) < klen) {
    256         log_Printf(LogERROR, "Pap Input: Truncated key !\n");
    257         break;
    258       }
    259       if ((key = malloc(klen+1)) == NULL) {
    260         log_Printf(LogERROR, "Pap Input: Out of memory !\n");
    261         break;
    262       }
    263       bp = mbuf_Read(bp, key, klen);
    264       key[klen] = '\0';
    265 
    266 #ifndef NORADIUS
    267       if (*bundle->radius.cfg.file) {
    268         if (!radius_Authenticate(&bundle->radius, authp, authp->in.name,
    269                                  key, strlen(key), NULL, 0))
    270           pap_Failure(authp);
    271       } else
    272 #endif
    273       if (auth_Validate(bundle, authp->in.name, key))
    274         pap_Success(authp);
    275       else
    276         pap_Failure(authp);
    277 
    278       free(key);
    279       break;
    280 
    281     case PAP_ACK:
    282       auth_StopTimer(authp);
    283       if (p->link.lcp.auth_iwait == PROTO_PAP) {
    284         p->link.lcp.auth_iwait = 0;
    285         if (p->link.lcp.auth_ineed == 0)
    286           /*
    287            * We've succeeded in our ``login''
    288            * If we're not expecting  the peer to authenticate (or he already
    289            * has), proceed to network phase.
    290            */
    291           datalink_AuthOk(p->dl);
    292       }
    293       break;
    294 
    295     case PAP_NAK:
    296       auth_StopTimer(authp);
    297       datalink_AuthNotOk(p->dl);
    298       break;
    299   }
    300 
    301   m_freem(bp);
    302   return NULL;
    303 }
    304