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@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