Home | History | Annotate | Line # | Download | only in pppd
      1 /*	$NetBSD: upap.c,v 1.6 2025/01/08 19:59:39 christos Exp $	*/
      2 
      3 /*
      4  * upap.c - User/Password Authentication Protocol.
      5  *
      6  * Copyright (c) 1984-2000 Carnegie Mellon University. All rights reserved.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  *
     12  * 1. Redistributions of source code must retain the above copyright
     13  *    notice, this list of conditions and the following disclaimer.
     14  *
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in
     17  *    the documentation and/or other materials provided with the
     18  *    distribution.
     19  *
     20  * 3. The name "Carnegie Mellon University" must not be used to
     21  *    endorse or promote products derived from this software without
     22  *    prior written permission. For permission or any legal
     23  *    details, please contact
     24  *      Office of Technology Transfer
     25  *      Carnegie Mellon University
     26  *      5000 Forbes Avenue
     27  *      Pittsburgh, PA  15213-3890
     28  *      (412) 268-4387, fax: (412) 268-7395
     29  *      tech-transfer (at) andrew.cmu.edu
     30  *
     31  * 4. Redistributions of any form whatsoever must retain the following
     32  *    acknowledgment:
     33  *    "This product includes software developed by Computing Services
     34  *     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
     35  *
     36  * CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
     37  * THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
     38  * AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
     39  * FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     40  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
     41  * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
     42  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     43  */
     44 
     45 #include <sys/cdefs.h>
     46 __RCSID("$NetBSD: upap.c,v 1.6 2025/01/08 19:59:39 christos Exp $");
     47 
     48 #ifdef HAVE_CONFIG_H
     49 #include "config.h"
     50 #endif
     51 
     52 /*
     53  * TODO:
     54  */
     55 
     56 #include <stdio.h>
     57 #include <string.h>
     58 
     59 #include "pppd-private.h"
     60 #include "options.h"
     61 #include "upap.h"
     62 
     63 
     64 static bool hide_password = 1;
     65 
     66 /*
     67  * Command-line options.
     68  */
     69 static struct option pap_option_list[] = {
     70     { "hide-password", o_bool, &hide_password,
     71       "Don't output passwords to log", OPT_PRIO | 1 },
     72     { "show-password", o_bool, &hide_password,
     73       "Show password string in debug log messages", OPT_PRIOSUB | 0 },
     74 
     75     { "pap-restart", o_int, &upap[0].us_timeouttime,
     76       "Set retransmit timeout for PAP", OPT_PRIO },
     77     { "pap-max-authreq", o_int, &upap[0].us_maxtransmits,
     78       "Set max number of transmissions for auth-reqs", OPT_PRIO },
     79     { "pap-timeout", o_int, &upap[0].us_reqtimeout,
     80       "Set time limit for peer PAP authentication", OPT_PRIO },
     81 
     82     { NULL }
     83 };
     84 
     85 /*
     86  * Protocol entry points.
     87  */
     88 static void upap_init(int);
     89 static void upap_lowerup(int);
     90 static void upap_lowerdown(int);
     91 static void upap_input(int, u_char *, int);
     92 static void upap_protrej(int);
     93 static int  upap_printpkt(u_char *, int,
     94 			  void (*)(void *, char *, ...), void *);
     95 
     96 struct protent pap_protent = {
     97     PPP_PAP,
     98     upap_init,
     99     upap_input,
    100     upap_protrej,
    101     upap_lowerup,
    102     upap_lowerdown,
    103     NULL,
    104     NULL,
    105     upap_printpkt,
    106     NULL,
    107     1,
    108     "PAP",
    109     NULL,
    110     pap_option_list,
    111     NULL,
    112     NULL,
    113     NULL
    114 };
    115 
    116 upap_state upap[NUM_PPP];		/* UPAP state; one for each unit */
    117 
    118 static void upap_timeout(void *);
    119 static void upap_reqtimeout(void *);
    120 static void upap_rauthreq(upap_state *, u_char *, int, int);
    121 static void upap_rauthack(upap_state *, u_char *, int, int);
    122 static void upap_rauthnak(upap_state *, u_char *, int, int);
    123 static void upap_sauthreq(upap_state *);
    124 static void upap_sresp(upap_state *, int, int, char *, int);
    125 
    126 
    127 /*
    128  * upap_init - Initialize a UPAP unit.
    129  */
    130 static void
    131 upap_init(int unit)
    132 {
    133     upap_state *u = &upap[unit];
    134 
    135     u->us_unit = unit;
    136     u->us_user = NULL;
    137     u->us_userlen = 0;
    138     u->us_passwd = NULL;
    139     u->us_passwdlen = 0;
    140     u->us_clientstate = UPAPCS_INITIAL;
    141     u->us_serverstate = UPAPSS_INITIAL;
    142     u->us_id = 0;
    143     u->us_timeouttime = UPAP_DEFTIMEOUT;
    144     u->us_maxtransmits = 10;
    145     u->us_reqtimeout = UPAP_DEFREQTIME;
    146 }
    147 
    148 
    149 /*
    150  * upap_authwithpeer - Authenticate us with our peer (start client).
    151  *
    152  * Set new state and send authenticate's.
    153  */
    154 void
    155 upap_authwithpeer(int unit, char *user, char *password)
    156 {
    157     upap_state *u = &upap[unit];
    158 
    159     /* Save the username and password we're given */
    160     u->us_user = user;
    161     u->us_userlen = strlen(user);
    162     u->us_passwd = password;
    163     u->us_passwdlen = strlen(password);
    164     u->us_transmits = 0;
    165 
    166     /* Lower layer up yet? */
    167     if (u->us_clientstate == UPAPCS_INITIAL ||
    168 	u->us_clientstate == UPAPCS_PENDING) {
    169 	u->us_clientstate = UPAPCS_PENDING;
    170 	return;
    171     }
    172 
    173     upap_sauthreq(u);			/* Start protocol */
    174 }
    175 
    176 
    177 /*
    178  * upap_authpeer - Authenticate our peer (start server).
    179  *
    180  * Set new state.
    181  */
    182 void
    183 upap_authpeer(int unit)
    184 {
    185     upap_state *u = &upap[unit];
    186 
    187     /* Lower layer up yet? */
    188     if (u->us_serverstate == UPAPSS_INITIAL ||
    189 	u->us_serverstate == UPAPSS_PENDING) {
    190 	u->us_serverstate = UPAPSS_PENDING;
    191 	return;
    192     }
    193 
    194     u->us_serverstate = UPAPSS_LISTEN;
    195     if (u->us_reqtimeout > 0)
    196 	TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
    197 }
    198 
    199 
    200 /*
    201  * upap_timeout - Retransmission timer for sending auth-reqs expired.
    202  */
    203 static void
    204 upap_timeout(void *arg)
    205 {
    206     upap_state *u = (upap_state *) arg;
    207 
    208     if (u->us_clientstate != UPAPCS_AUTHREQ)
    209 	return;
    210 
    211     if (u->us_transmits >= u->us_maxtransmits) {
    212 	/* give up in disgust */
    213 	error("No response to PAP authenticate-requests");
    214 	u->us_clientstate = UPAPCS_BADAUTH;
    215 	auth_withpeer_fail(u->us_unit, PPP_PAP);
    216 	return;
    217     }
    218 
    219     upap_sauthreq(u);		/* Send Authenticate-Request */
    220 }
    221 
    222 
    223 /*
    224  * upap_reqtimeout - Give up waiting for the peer to send an auth-req.
    225  */
    226 static void
    227 upap_reqtimeout(void *arg)
    228 {
    229     upap_state *u = (upap_state *) arg;
    230 
    231     if (u->us_serverstate != UPAPSS_LISTEN)
    232 	return;			/* huh?? */
    233 
    234     auth_peer_fail(u->us_unit, PPP_PAP);
    235     u->us_serverstate = UPAPSS_BADAUTH;
    236 }
    237 
    238 
    239 /*
    240  * upap_lowerup - The lower layer is up.
    241  *
    242  * Start authenticating if pending.
    243  */
    244 static void
    245 upap_lowerup(int unit)
    246 {
    247     upap_state *u = &upap[unit];
    248 
    249     if (u->us_clientstate == UPAPCS_INITIAL)
    250 	u->us_clientstate = UPAPCS_CLOSED;
    251     else if (u->us_clientstate == UPAPCS_PENDING) {
    252 	upap_sauthreq(u);	/* send an auth-request */
    253     }
    254 
    255     if (u->us_serverstate == UPAPSS_INITIAL)
    256 	u->us_serverstate = UPAPSS_CLOSED;
    257     else if (u->us_serverstate == UPAPSS_PENDING) {
    258 	u->us_serverstate = UPAPSS_LISTEN;
    259 	if (u->us_reqtimeout > 0)
    260 	    TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);
    261     }
    262 }
    263 
    264 
    265 /*
    266  * upap_lowerdown - The lower layer is down.
    267  *
    268  * Cancel all timeouts.
    269  */
    270 static void
    271 upap_lowerdown(int unit)
    272 {
    273     upap_state *u = &upap[unit];
    274 
    275     if (u->us_clientstate == UPAPCS_AUTHREQ)	/* Timeout pending? */
    276 	UNTIMEOUT(upap_timeout, u);		/* Cancel timeout */
    277     if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0)
    278 	UNTIMEOUT(upap_reqtimeout, u);
    279 
    280     u->us_clientstate = UPAPCS_INITIAL;
    281     u->us_serverstate = UPAPSS_INITIAL;
    282 }
    283 
    284 
    285 /*
    286  * upap_protrej - Peer doesn't speak this protocol.
    287  *
    288  * This shouldn't happen.  In any case, pretend lower layer went down.
    289  */
    290 static void
    291 upap_protrej(int unit)
    292 {
    293     upap_state *u = &upap[unit];
    294 
    295     if (u->us_clientstate == UPAPCS_AUTHREQ) {
    296 	error("PAP authentication failed due to protocol-reject");
    297 	auth_withpeer_fail(unit, PPP_PAP);
    298     }
    299     if (u->us_serverstate == UPAPSS_LISTEN) {
    300 	error("PAP authentication of peer failed (protocol-reject)");
    301 	auth_peer_fail(unit, PPP_PAP);
    302     }
    303     upap_lowerdown(unit);
    304 }
    305 
    306 
    307 /*
    308  * upap_input - Input UPAP packet.
    309  */
    310 static void
    311 upap_input(int unit, u_char *inpacket, int l)
    312 {
    313     upap_state *u = &upap[unit];
    314     u_char *inp;
    315     u_char code, id;
    316     int len;
    317 
    318     /*
    319      * Parse header (code, id and length).
    320      * If packet too short, drop it.
    321      */
    322     inp = inpacket;
    323     if (l < UPAP_HEADERLEN) {
    324 	UPAPDEBUG(("pap_input: rcvd short header."));
    325 	return;
    326     }
    327     GETCHAR(code, inp);
    328     GETCHAR(id, inp);
    329     GETSHORT(len, inp);
    330     if (len < UPAP_HEADERLEN) {
    331 	UPAPDEBUG(("pap_input: rcvd illegal length."));
    332 	return;
    333     }
    334     if (len > l) {
    335 	UPAPDEBUG(("pap_input: rcvd short packet."));
    336 	return;
    337     }
    338     len -= UPAP_HEADERLEN;
    339 
    340     /*
    341      * Action depends on code.
    342      */
    343     switch (code) {
    344     case UPAP_AUTHREQ:
    345 	upap_rauthreq(u, inp, id, len);
    346 	break;
    347 
    348     case UPAP_AUTHACK:
    349 	upap_rauthack(u, inp, id, len);
    350 	break;
    351 
    352     case UPAP_AUTHNAK:
    353 	upap_rauthnak(u, inp, id, len);
    354 	break;
    355 
    356     default:				/* XXX Need code reject */
    357 	break;
    358     }
    359 }
    360 
    361 
    362 /*
    363  * upap_rauth - Receive Authenticate.
    364  */
    365 static void
    366 upap_rauthreq(upap_state *u, u_char *inp, int id, int len)
    367 {
    368     u_char ruserlen, rpasswdlen;
    369     char *ruser, *rpasswd;
    370     char rhostname[256];
    371     int retcode;
    372     char *msg;
    373     int msglen;
    374 
    375     if (u->us_serverstate < UPAPSS_LISTEN)
    376 	return;
    377 
    378     /*
    379      * If we receive a duplicate authenticate-request, we are
    380      * supposed to return the same status as for the first request.
    381      */
    382     if (u->us_serverstate == UPAPSS_OPEN) {
    383 	upap_sresp(u, UPAP_AUTHACK, id, "", 0);	/* return auth-ack */
    384 	return;
    385     }
    386     if (u->us_serverstate == UPAPSS_BADAUTH) {
    387 	upap_sresp(u, UPAP_AUTHNAK, id, "", 0);	/* return auth-nak */
    388 	return;
    389     }
    390 
    391     /*
    392      * Parse user/passwd.
    393      */
    394     if (len < 1) {
    395 	UPAPDEBUG(("pap_rauth: rcvd short packet."));
    396 	return;
    397     }
    398     GETCHAR(ruserlen, inp);
    399     len -= sizeof (u_char) + ruserlen + sizeof (u_char);
    400     if (len < 0) {
    401 	UPAPDEBUG(("pap_rauth: rcvd short packet."));
    402 	return;
    403     }
    404     ruser = (char *) inp;
    405     INCPTR(ruserlen, inp);
    406     GETCHAR(rpasswdlen, inp);
    407     if (len < rpasswdlen) {
    408 	UPAPDEBUG(("pap_rauth: rcvd short packet."));
    409 	return;
    410     }
    411     rpasswd = (char *) inp;
    412 
    413     /*
    414      * Check the username and password given.
    415      */
    416     retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd,
    417 			   rpasswdlen, &msg);
    418     BZERO(rpasswd, rpasswdlen);
    419 
    420     /*
    421      * Check remote number authorization.  A plugin may have filled in
    422      * the remote number or added an allowed number, and rather than
    423      * return an authenticate failure, is leaving it for us to verify.
    424      */
    425     if (retcode == UPAP_AUTHACK) {
    426 	if (!auth_number()) {
    427 	    /* We do not want to leak info about the pap result. */
    428 	    retcode = UPAP_AUTHNAK; /* XXX exit value will be "wrong" */
    429 	    warn("calling number %q is not authorized", remote_number);
    430 	}
    431     }
    432 
    433     msglen = strlen(msg);
    434     if (msglen > 255)
    435 	msglen = 255;
    436     upap_sresp(u, retcode, id, msg, msglen);
    437 
    438     /* Null terminate and clean remote name. */
    439     slprintf(rhostname, sizeof(rhostname), "%.*v", ruserlen, ruser);
    440 
    441     if (retcode == UPAP_AUTHACK) {
    442 	u->us_serverstate = UPAPSS_OPEN;
    443 	notice("PAP peer authentication succeeded for %q", rhostname);
    444 	auth_peer_success(u->us_unit, PPP_PAP, 0, ruser, ruserlen);
    445     } else {
    446 	u->us_serverstate = UPAPSS_BADAUTH;
    447 	warn("PAP peer authentication failed for %q", rhostname);
    448 	auth_peer_fail(u->us_unit, PPP_PAP);
    449     }
    450 
    451     if (u->us_reqtimeout > 0)
    452 	UNTIMEOUT(upap_reqtimeout, u);
    453 }
    454 
    455 
    456 /*
    457  * upap_rauthack - Receive Authenticate-Ack.
    458  */
    459 static void
    460 upap_rauthack(upap_state *u, u_char *inp, int id, int len)
    461 {
    462     u_char msglen;
    463     char *msg;
    464 
    465     if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
    466 	return;
    467 
    468     /*
    469      * Parse message.
    470      */
    471     if (len < 1) {
    472 	UPAPDEBUG(("pap_rauthack: ignoring missing msg-length."));
    473     } else {
    474 	GETCHAR(msglen, inp);
    475 	if (msglen > 0) {
    476 	    len -= sizeof (u_char);
    477 	    if (len < msglen) {
    478 		UPAPDEBUG(("pap_rauthack: rcvd short packet."));
    479 		return;
    480 	    }
    481 	    msg = (char *) inp;
    482 	    PRINTMSG(msg, msglen);
    483 	}
    484     }
    485 
    486     u->us_clientstate = UPAPCS_OPEN;
    487 
    488     auth_withpeer_success(u->us_unit, PPP_PAP, 0);
    489 }
    490 
    491 
    492 /*
    493  * upap_rauthnak - Receive Authenticate-Nak.
    494  */
    495 static void
    496 upap_rauthnak(upap_state *u, u_char *inp, int id, int len)
    497 {
    498     u_char msglen;
    499     char *msg;
    500 
    501     if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */
    502 	return;
    503 
    504     /*
    505      * Parse message.
    506      */
    507     if (len < 1) {
    508 	UPAPDEBUG(("pap_rauthnak: ignoring missing msg-length."));
    509     } else {
    510 	GETCHAR(msglen, inp);
    511 	if (msglen > 0) {
    512 	    len -= sizeof (u_char);
    513 	    if (len < msglen) {
    514 		UPAPDEBUG(("pap_rauthnak: rcvd short packet."));
    515 		return;
    516 	    }
    517 	    msg = (char *) inp;
    518 	    PRINTMSG(msg, msglen);
    519 	}
    520     }
    521 
    522     u->us_clientstate = UPAPCS_BADAUTH;
    523 
    524     error("PAP authentication failed");
    525     auth_withpeer_fail(u->us_unit, PPP_PAP);
    526 }
    527 
    528 
    529 /*
    530  * upap_sauthreq - Send an Authenticate-Request.
    531  */
    532 static void
    533 upap_sauthreq(upap_state *u)
    534 {
    535     u_char *outp;
    536     int outlen;
    537 
    538     outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) +
    539 	u->us_userlen + u->us_passwdlen;
    540     outp = outpacket_buf;
    541 
    542     MAKEHEADER(outp, PPP_PAP);
    543 
    544     PUTCHAR(UPAP_AUTHREQ, outp);
    545     PUTCHAR(++u->us_id, outp);
    546     PUTSHORT(outlen, outp);
    547     PUTCHAR(u->us_userlen, outp);
    548     BCOPY(u->us_user, outp, u->us_userlen);
    549     INCPTR(u->us_userlen, outp);
    550     PUTCHAR(u->us_passwdlen, outp);
    551     BCOPY(u->us_passwd, outp, u->us_passwdlen);
    552 
    553     output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
    554 
    555     TIMEOUT(upap_timeout, u, u->us_timeouttime);
    556     ++u->us_transmits;
    557     u->us_clientstate = UPAPCS_AUTHREQ;
    558 }
    559 
    560 
    561 /*
    562  * upap_sresp - Send a response (ack or nak).
    563  */
    564 static void
    565 upap_sresp(upap_state *u, int code, int id, char *msg, int msglen)
    566 {
    567     u_char *outp;
    568     int outlen;
    569 
    570     outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;
    571     outp = outpacket_buf;
    572     MAKEHEADER(outp, PPP_PAP);
    573 
    574     PUTCHAR(code, outp);
    575     PUTCHAR(id, outp);
    576     PUTSHORT(outlen, outp);
    577     PUTCHAR(msglen, outp);
    578     BCOPY(msg, outp, msglen);
    579     output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN);
    580 }
    581 
    582 /*
    583  * upap_printpkt - print the contents of a PAP packet.
    584  */
    585 static char *upap_codenames[] = {
    586     "AuthReq", "AuthAck", "AuthNak"
    587 };
    588 
    589 static int
    590 upap_printpkt(u_char *p, int plen, void (*printer)(void *, char *, ...), void *arg)
    591 {
    592     int code, id, len;
    593     int mlen, ulen, wlen;
    594     char *user, *pwd, *msg;
    595     u_char *pstart;
    596 
    597     if (plen < UPAP_HEADERLEN)
    598 	return 0;
    599     pstart = p;
    600     GETCHAR(code, p);
    601     GETCHAR(id, p);
    602     GETSHORT(len, p);
    603     if (len < UPAP_HEADERLEN || len > plen)
    604 	return 0;
    605 
    606     if (code >= 1 && code <= sizeof(upap_codenames) / sizeof(char *))
    607 	printer(arg, " %s", upap_codenames[code-1]);
    608     else
    609 	printer(arg, " code=0x%x", code);
    610     printer(arg, " id=0x%x", id);
    611     len -= UPAP_HEADERLEN;
    612     switch (code) {
    613     case UPAP_AUTHREQ:
    614 	if (len < 1)
    615 	    break;
    616 	ulen = p[0];
    617 	if (len < ulen + 2)
    618 	    break;
    619 	wlen = p[ulen + 1];
    620 	if (len < ulen + wlen + 2)
    621 	    break;
    622 	user = (char *) (p + 1);
    623 	pwd = (char *) (p + ulen + 2);
    624 	p += ulen + wlen + 2;
    625 	len -= ulen + wlen + 2;
    626 	printer(arg, " user=");
    627 	print_string(user, ulen, printer, arg);
    628 	printer(arg, " password=");
    629 	if (!hide_password)
    630 	    print_string(pwd, wlen, printer, arg);
    631 	else
    632 	    printer(arg, "<hidden>");
    633 	break;
    634     case UPAP_AUTHACK:
    635     case UPAP_AUTHNAK:
    636 	if (len < 1)
    637 	    break;
    638 	mlen = p[0];
    639 	if (len < mlen + 1)
    640 	    break;
    641 	msg = (char *) (p + 1);
    642 	p += mlen + 1;
    643 	len -= mlen + 1;
    644 	printer(arg, " ");
    645 	print_string(msg, mlen, printer, arg);
    646 	break;
    647     }
    648 
    649     /* print the rest of the bytes in the packet */
    650     for (; len > 0; --len) {
    651 	GETCHAR(code, p);
    652 	printer(arg, " %.2x", code);
    653     }
    654 
    655     return p - pstart;
    656 }
    657