Home | History | Annotate | Download | only in ppp
      1 /*****************************************************************************
      2 * pap.c - Network Password Authentication Protocol program file.
      3 *
      4 * Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.
      5 * portions Copyright (c) 1997 by Global Election Systems Inc.
      6 *
      7 * The authors hereby grant permission to use, copy, modify, distribute,
      8 * and license this software and its documentation for any purpose, provided
      9 * that existing copyright notices are retained in all copies and that this
     10 * notice and the following disclaimer are included verbatim in any
     11 * distributions. No written agreement, license, or royalty fee is required
     12 * for any of the authorized uses.
     13 *
     14 * THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR
     15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     17 * IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
     18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24 *
     25 ******************************************************************************
     26 * REVISION HISTORY
     27 *
     28 * 03-01-01 Marc Boucher <marc (at) mbsi.ca>
     29 *   Ported to lwIP.
     30 * 97-12-12 Guy Lancaster <lancasterg (at) acm.org>, Global Election Systems Inc.
     31 *   Original.
     32 *****************************************************************************/
     33 /*
     34  * upap.c - User/Password Authentication Protocol.
     35  *
     36  * Copyright (c) 1989 Carnegie Mellon University.
     37  * All rights reserved.
     38  *
     39  * Redistribution and use in source and binary forms are permitted
     40  * provided that the above copyright notice and this paragraph are
     41  * duplicated in all such forms and that any documentation,
     42  * advertising materials, and other materials related to such
     43  * distribution and use acknowledge that the software was developed
     44  * by Carnegie Mellon University.  The name of the
     45  * University may not be used to endorse or promote products derived
     46  * from this software without specific prior written permission.
     47  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
     48  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
     49  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
     50  */
     51 
     52 #include "lwip/opt.h"
     53 
     54 #if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */
     55 
     56 #if PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */
     57 
     58 #include "ppp.h"
     59 #include "pppdebug.h"
     60 
     61 #include "auth.h"
     62 #include "pap.h"
     63 
     64 #include <string.h>
     65 
     66 #if 0 /* UNUSED */
     67 static bool hide_password = 1;
     68 
     69 /*
     70  * Command-line options.
     71  */
     72 static option_t pap_option_list[] = {
     73     { "hide-password", o_bool, &hide_password,
     74       "Don't output passwords to log", 1 },
     75     { "show-password", o_bool, &hide_password,
     76       "Show password string in debug log messages", 0 },
     77     { "pap-restart", o_int, &upap[0].us_timeouttime,
     78       "Set retransmit timeout for PAP" },
     79     { "pap-max-authreq", o_int, &upap[0].us_maxtransmits,
     80       "Set max number of transmissions for auth-reqs" },
     81     { "pap-timeout", o_int, &upap[0].us_reqtimeout,
     82       "Set time limit for peer PAP authentication" },
     83     { NULL }
     84 };
     85 #endif
     86 
     87 /*
     88  * Protocol entry points.
     89  */
     90 static void upap_init      (int);
     91 static void upap_lowerup   (int);
     92 static void upap_lowerdown (int);
     93 static void upap_input     (int, u_char *, int);
     94 static void upap_protrej   (int);
     95 #if PPP_ADDITIONAL_CALLBACKS
     96 static int  upap_printpkt (u_char *, int, void (*)(void *, char *, ...), void *);
     97 #endif /* PPP_ADDITIONAL_CALLBACKS */
     98 
     99 struct protent pap_protent = {
    100   PPP_PAP,
    101   upap_init,
    102   upap_input,
    103   upap_protrej,
    104   upap_lowerup,
    105   upap_lowerdown,
    106   NULL,
    107   NULL,
    108 #if PPP_ADDITIONAL_CALLBACKS
    109   upap_printpkt,
    110   NULL,
    111 #endif /* PPP_ADDITIONAL_CALLBACKS */
    112   1,
    113   "PAP",
    114 #if PPP_ADDITIONAL_CALLBACKS
    115   NULL,
    116   NULL,
    117   NULL
    118 #endif /* PPP_ADDITIONAL_CALLBACKS */
    119 };
    120 
    121 upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */
    122 
    123 static void upap_timeout   (void *);
    124 static void upap_reqtimeout(void *);
    125 static void upap_rauthreq  (upap_state *, u_char *, u_char, int);
    126 static void upap_rauthack  (upap_state *, u_char *, int, int);
    127 static void upap_rauthnak  (upap_state *, u_char *, int, int);
    128 static void upap_sauthreq  (upap_state *);
    129 static void upap_sresp     (upap_state *, u_char, u_char, char *, int);
    130 
    131 
    132 /*
    133  * upap_init - Initialize a UPAP unit.
    134  */
    135 static void
    136 upap_init(int unit)
    137 {
    138   upap_state *u = &upap[unit];
    139 
    140   UPAPDEBUG(LOG_INFO, ("upap_init: %d\n", unit));
    141   u->us_unit         = unit;
    142   u->us_user         = NULL;
    143   u->us_userlen      = 0;
    144   u->us_passwd       = NULL;
    145   u->us_passwdlen    = 0;
    146   u->us_clientstate  = UPAPCS_INITIAL;
    147   u->us_serverstate  = UPAPSS_INITIAL;
    148   u->us_id           = 0;
    149   u->us_timeouttime  = UPAP_DEFTIMEOUT;
    150   u->us_maxtransmits = 10;
    151   u->us_reqtimeout   = UPAP_DEFREQTIME;
    152 }
    153 
    154 /*
    155  * upap_authwithpeer - Authenticate us with our peer (start client).
    156  *
    157  * Set new state and send authenticate's.
    158  */
    159 void
    160 upap_authwithpeer(int unit, char *user, char *password)
    161 {
    162   upap_state *u = &upap[unit];
    163 
    164   UPAPDEBUG(LOG_INFO, ("upap_authwithpeer: %d user=%s password=%s s=%d\n",
    165              unit, user, password, u->us_clientstate));
    166 
    167   /* Save the username and password we're given */
    168   u->us_user = user;
    169   u->us_userlen = (int)strlen(user);
    170   u->us_passwd = password;
    171   u->us_passwdlen = (int)strlen(password);
    172 
    173   u->us_transmits = 0;
    174 
    175   /* Lower layer up yet? */
    176   if (u->us_clientstate == UPAPCS_INITIAL ||
    177       u->us_clientstate == UPAPCS_PENDING) {
    178     u->us_clientstate = UPAPCS_PENDING;
    179     return;
    180   }
    181 
    182   upap_sauthreq(u);      /* Start protocol */
    183 }
    184 
    185 
    186 /*
    187  * upap_authpeer - Authenticate our peer (start server).
    188  *
    189  * Set new state.
    190  */
    191 void
    192 upap_authpeer(int unit)
    193 {
    194   upap_state *u = &upap[unit];
    195 
    196   /* Lower layer up yet? */
    197   if (u->us_serverstate == UPAPSS_INITIAL ||
    198       u->us_serverstate == UPAPSS_PENDING) {
    199     u->us_serverstate = UPAPSS_PENDING;
    200     return;
    201   }
    202 
    203   u->us_serverstate = UPAPSS_LISTEN;
    204   if (u->us_reqtimeout > 0) {
    205     TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
    206   }
    207 }
    208 
    209 /*
    210  * upap_timeout - Retransmission timer for sending auth-reqs expired.
    211  */
    212 static void
    213 upap_timeout(void *arg)
    214 {
    215   upap_state *u = (upap_state *) arg;
    216 
    217   UPAPDEBUG(LOG_INFO, ("upap_timeout: %d timeout %d expired s=%d\n",
    218         u->us_unit, u->us_timeouttime, u->us_clientstate));
    219 
    220   if (u->us_clientstate != UPAPCS_AUTHREQ) {
    221 	UPAPDEBUG(LOG_INFO, ("upap_timeout: not in AUTHREQ state!\n"));
    222     return;
    223   }
    224 
    225   if (u->us_transmits >= u->us_maxtransmits) {
    226     /* give up in disgust */
    227     UPAPDEBUG(LOG_ERR, ("No response to PAP authenticate-requests\n"));
    228     u->us_clientstate = UPAPCS_BADAUTH;
    229     auth_withpeer_fail(u->us_unit, PPP_PAP);
    230     return;
    231   }
    232 
    233   upap_sauthreq(u);    /* Send Authenticate-Request and set upap timeout*/
    234 }
    235 
    236 
    237 /*
    238  * upap_reqtimeout - Give up waiting for the peer to send an auth-req.
    239  */
    240 static void
    241 upap_reqtimeout(void *arg)
    242 {
    243   upap_state *u = (upap_state *) arg;
    244 
    245   if (u->us_serverstate != UPAPSS_LISTEN) {
    246     return; /* huh?? */
    247   }
    248 
    249   auth_peer_fail(u->us_unit, PPP_PAP);
    250   u->us_serverstate = UPAPSS_BADAUTH;
    251 }
    252 
    253 
    254 /*
    255  * upap_lowerup - The lower layer is up.
    256  *
    257  * Start authenticating if pending.
    258  */
    259 static void
    260 upap_lowerup(int unit)
    261 {
    262   upap_state *u = &upap[unit];
    263 
    264   UPAPDEBUG(LOG_INFO, ("upap_lowerup: init %d clientstate s=%d\n", unit, u->us_clientstate));
    265 
    266   if (u->us_clientstate == UPAPCS_INITIAL) {
    267     u->us_clientstate = UPAPCS_CLOSED;
    268   } else if (u->us_clientstate == UPAPCS_PENDING) {
    269     upap_sauthreq(u);  /* send an auth-request */
    270     /* now client state is UPAPCS__AUTHREQ */
    271   }
    272 
    273   if (u->us_serverstate == UPAPSS_INITIAL) {
    274     u->us_serverstate = UPAPSS_CLOSED;
    275   } else if (u->us_serverstate == UPAPSS_PENDING) {
    276     u->us_serverstate = UPAPSS_LISTEN;
    277     if (u->us_reqtimeout > 0) {
    278       TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
    279     }
    280   }
    281 }
    282 
    283 
    284 /*
    285  * upap_lowerdown - The lower layer is down.
    286  *
    287  * Cancel all timeouts.
    288  */
    289 static void
    290 upap_lowerdown(int unit)
    291 {
    292   upap_state *u = &upap[unit];
    293 
    294   UPAPDEBUG(LOG_INFO, ("upap_lowerdown: %d s=%d\n", unit, u->us_clientstate));
    295 
    296   if (u->us_clientstate == UPAPCS_AUTHREQ) { /* Timeout pending? */
    297     UNTIMEOUT(upap_timeout, u);    /* Cancel timeout */
    298   }
    299   if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0) {
    300     UNTIMEOUT(upap_reqtimeout, u);
    301   }
    302 
    303   u->us_clientstate = UPAPCS_INITIAL;
    304   u->us_serverstate = UPAPSS_INITIAL;
    305 }
    306 
    307 
    308 /*
    309  * upap_protrej - Peer doesn't speak this protocol.
    310  *
    311  * This shouldn't happen.  In any case, pretend lower layer went down.
    312  */
    313 static void
    314 upap_protrej(int unit)
    315 {
    316   upap_state *u = &upap[unit];
    317 
    318   if (u->us_clientstate == UPAPCS_AUTHREQ) {
    319     UPAPDEBUG(LOG_ERR, ("PAP authentication failed due to protocol-reject\n"));
    320     auth_withpeer_fail(unit, PPP_PAP);
    321   }
    322   if (u->us_serverstate == UPAPSS_LISTEN) {
    323     UPAPDEBUG(LOG_ERR, ("PAP authentication of peer failed (protocol-reject)\n"));
    324     auth_peer_fail(unit, PPP_PAP);
    325   }
    326   upap_lowerdown(unit);
    327 }
    328 
    329 
    330 /*
    331  * upap_input - Input UPAP packet.
    332  */
    333 static void
    334 upap_input(int unit, u_char *inpacket, int l)
    335 {
    336   upap_state *u = &upap[unit];
    337   u_char *inp;
    338   u_char code, id;
    339   int len;
    340 
    341   /*
    342    * Parse header (code, id and length).
    343    * If packet too short, drop it.
    344    */
    345   inp = inpacket;
    346   if (l < (int)UPAP_HEADERLEN) {
    347     UPAPDEBUG(LOG_INFO, ("pap_input: rcvd short header.\n"));
    348     return;
    349   }
    350   GETCHAR(code, inp);
    351   GETCHAR(id, inp);
    352   GETSHORT(len, inp);
    353   if (len < (int)UPAP_HEADERLEN) {
    354     UPAPDEBUG(LOG_INFO, ("pap_input: rcvd illegal length.\n"));
    355     return;
    356   }
    357   if (len > l) {
    358     UPAPDEBUG(LOG_INFO, ("pap_input: rcvd short packet.\n"));
    359     return;
    360   }
    361   len -= UPAP_HEADERLEN;
    362 
    363   /*
    364    * Action depends on code.
    365    */
    366   switch (code) {
    367     case UPAP_AUTHREQ:
    368       upap_rauthreq(u, inp, id, len);
    369       break;
    370 
    371     case UPAP_AUTHACK:
    372       upap_rauthack(u, inp, id, len);
    373       break;
    374 
    375     case UPAP_AUTHNAK:
    376       upap_rauthnak(u, inp, id, len);
    377       break;
    378 
    379     default:        /* XXX Need code reject */
    380       UPAPDEBUG(LOG_INFO, ("pap_input: UNHANDLED default: code: %d, id: %d, len: %d.\n", code, id, len));
    381       break;
    382   }
    383 }
    384 
    385 
    386 /*
    387  * upap_rauth - Receive Authenticate.
    388  */
    389 static void
    390 upap_rauthreq(upap_state *u, u_char *inp, u_char id, int len)
    391 {
    392   u_char ruserlen, rpasswdlen;
    393   char *ruser, *rpasswd;
    394   u_char retcode;
    395   char *msg;
    396   int msglen;
    397 
    398   UPAPDEBUG(LOG_INFO, ("pap_rauth: Rcvd id %d.\n", id));
    399 
    400   if (u->us_serverstate < UPAPSS_LISTEN) {
    401     return;
    402   }
    403 
    404   /*
    405    * If we receive a duplicate authenticate-request, we are
    406    * supposed to return the same status as for the first request.
    407    */
    408   if (u->us_serverstate == UPAPSS_OPEN) {
    409     upap_sresp(u, UPAP_AUTHACK, id, "", 0);  /* return auth-ack */
    410     return;
    411   }
    412   if (u->us_serverstate == UPAPSS_BADAUTH) {
    413     upap_sresp(u, UPAP_AUTHNAK, id, "", 0);  /* return auth-nak */
    414     return;
    415   }
    416 
    417   /*
    418    * Parse user/passwd.
    419    */
    420   if (len < (int)sizeof (u_char)) {
    421     UPAPDEBUG(LOG_INFO, ("pap_rauth: rcvd short packet.\n"));
    422     return;
    423   }
    424   GETCHAR(ruserlen, inp);
    425   len -= sizeof (u_char) + ruserlen + sizeof (u_char);
    426   if (len < 0) {
    427     UPAPDEBUG(LOG_INFO, ("pap_rauth: rcvd short packet.\n"));
    428     return;
    429   }
    430   ruser = (char *) inp;
    431   INCPTR(ruserlen, inp);
    432   GETCHAR(rpasswdlen, inp);
    433   if (len < rpasswdlen) {
    434     UPAPDEBUG(LOG_INFO, ("pap_rauth: rcvd short packet.\n"));
    435     return;
    436   }
    437   rpasswd = (char *) inp;
    438 
    439   /*
    440    * Check the username and password given.
    441    */
    442   retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd, rpasswdlen, &msg, &msglen);
    443   /* lwip: currently retcode is always UPAP_AUTHACK */
    444   BZERO(rpasswd, rpasswdlen);
    445 
    446   upap_sresp(u, retcode, id, msg, msglen);
    447 
    448   if (retcode == UPAP_AUTHACK) {
    449     u->us_serverstate = UPAPSS_OPEN;
    450     auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen);
    451   } else {
    452     u->us_serverstate = UPAPSS_BADAUTH;
    453     auth_peer_fail(u->us_unit, PPP_PAP);
    454   }
    455 
    456   if (u->us_reqtimeout > 0) {
    457     UNTIMEOUT(upap_reqtimeout, u);
    458   }
    459 }
    460 
    461 
    462 /*
    463  * upap_rauthack - Receive Authenticate-Ack.
    464  */
    465 static void
    466 upap_rauthack(upap_state *u, u_char *inp, int id, int len)
    467 {
    468   u_char msglen;
    469   char *msg;
    470 
    471   LWIP_UNUSED_ARG(id);
    472 
    473   UPAPDEBUG(LOG_INFO, ("pap_rauthack: Rcvd id %d s=%d\n", id, u->us_clientstate));
    474 
    475   if (u->us_clientstate != UPAPCS_AUTHREQ) { /* XXX */
    476     UPAPDEBUG(LOG_INFO, ("pap_rauthack: us_clientstate != UPAPCS_AUTHREQ\n"));
    477     return;
    478   }
    479 
    480   /*
    481    * Parse message.
    482    */
    483   if (len < (int)sizeof (u_char)) {
    484     UPAPDEBUG(LOG_INFO, ("pap_rauthack: ignoring missing msg-length.\n"));
    485   } else {
    486     GETCHAR(msglen, inp);
    487     if (msglen > 0) {
    488       len -= sizeof (u_char);
    489       if (len < msglen) {
    490         UPAPDEBUG(LOG_INFO, ("pap_rauthack: rcvd short packet.\n"));
    491         return;
    492       }
    493       msg = (char *) inp;
    494       PRINTMSG(msg, msglen);
    495     }
    496   }
    497   UNTIMEOUT(upap_timeout, u);    /* Cancel timeout */
    498   u->us_clientstate = UPAPCS_OPEN;
    499 
    500   auth_withpeer_success(u->us_unit, PPP_PAP);
    501 }
    502 
    503 
    504 /*
    505  * upap_rauthnak - Receive Authenticate-Nak.
    506  */
    507 static void
    508 upap_rauthnak(upap_state *u, u_char *inp, int id, int len)
    509 {
    510   u_char msglen;
    511   char *msg;
    512 
    513   LWIP_UNUSED_ARG(id);
    514 
    515   UPAPDEBUG(LOG_INFO, ("pap_rauthnak: Rcvd id %d s=%d\n", id, u->us_clientstate));
    516 
    517   if (u->us_clientstate != UPAPCS_AUTHREQ) { /* XXX */
    518     return;
    519   }
    520 
    521   /*
    522    * Parse message.
    523    */
    524   if (len < sizeof (u_char)) {
    525     UPAPDEBUG(LOG_INFO, ("pap_rauthnak: ignoring missing msg-length.\n"));
    526   } else {
    527     GETCHAR(msglen, inp);
    528     if(msglen > 0) {
    529       len -= sizeof (u_char);
    530       if (len < msglen) {
    531         UPAPDEBUG(LOG_INFO, ("pap_rauthnak: rcvd short packet.\n"));
    532         return;
    533       }
    534       msg = (char *) inp;
    535       PRINTMSG(msg, msglen);
    536     }
    537   }
    538 
    539   u->us_clientstate = UPAPCS_BADAUTH;
    540 
    541   UPAPDEBUG(LOG_ERR, ("PAP authentication failed\n"));
    542   auth_withpeer_fail(u->us_unit, PPP_PAP);
    543 }
    544 
    545 
    546 /*
    547  * upap_sauthreq - Send an Authenticate-Request.
    548  */
    549 static void
    550 upap_sauthreq(upap_state *u)
    551 {
    552   u_char *outp;
    553   int outlen;
    554 
    555   outlen = UPAP_HEADERLEN + 2 * sizeof (u_char)
    556          + u->us_userlen + u->us_passwdlen;
    557   outp = outpacket_buf[u->us_unit];
    558 
    559   MAKEHEADER(outp, PPP_PAP);
    560 
    561   PUTCHAR(UPAP_AUTHREQ, outp);
    562   PUTCHAR(++u->us_id, outp);
    563   PUTSHORT(outlen, outp);
    564   PUTCHAR(u->us_userlen, outp);
    565   BCOPY(u->us_user, outp, u->us_userlen);
    566   INCPTR(u->us_userlen, outp);
    567   PUTCHAR(u->us_passwdlen, outp);
    568   BCOPY(u->us_passwd, outp, u->us_passwdlen);
    569 
    570   pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN);
    571 
    572   UPAPDEBUG(LOG_INFO, ("pap_sauth: Sent id %d\n", u->us_id));
    573 
    574   TIMEOUT(upap_timeout, u, u->us_timeouttime);
    575   ++u->us_transmits;
    576   u->us_clientstate = UPAPCS_AUTHREQ;
    577 }
    578 
    579 
    580 /*
    581  * upap_sresp - Send a response (ack or nak).
    582  */
    583 static void
    584 upap_sresp(upap_state *u, u_char code, u_char id, char *msg, int msglen)
    585 {
    586   u_char *outp;
    587   int outlen;
    588 
    589   outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
    590   outp = outpacket_buf[u->us_unit];
    591   MAKEHEADER(outp, PPP_PAP);
    592 
    593   PUTCHAR(code, outp);
    594   PUTCHAR(id, outp);
    595   PUTSHORT(outlen, outp);
    596   PUTCHAR(msglen, outp);
    597   BCOPY(msg, outp, msglen);
    598   pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN);
    599 
    600   UPAPDEBUG(LOG_INFO, ("pap_sresp: Sent code %d, id %d s=%d\n", code, id, u->us_clientstate));
    601 }
    602 
    603 #if PPP_ADDITIONAL_CALLBACKS
    604 static char *upap_codenames[] = {
    605     "AuthReq", "AuthAck", "AuthNak"
    606 };
    607 
    608 /*
    609  * upap_printpkt - print the contents of a PAP packet.
    610  */
    611 static int upap_printpkt(
    612   u_char *p,
    613   int plen,
    614   void (*printer) (void *, char *, ...),
    615   void *arg
    616 )
    617 {
    618   LWIP_UNUSED_ARG(p);
    619   LWIP_UNUSED_ARG(plen);
    620   LWIP_UNUSED_ARG(printer);
    621   LWIP_UNUSED_ARG(arg);
    622   return 0;
    623 }
    624 #endif /* PPP_ADDITIONAL_CALLBACKS */
    625 
    626 #endif /* PAP_SUPPORT */
    627 
    628 #endif /* PPP_SUPPORT */
    629