1 /* $OpenBSD: upap.c,v 1.12 2024/08/09 05:16:13 deraadt 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 /* 46 * TODO: 47 */ 48 49 #include <stdio.h> 50 #include <string.h> 51 #include <sys/types.h> 52 #include <sys/time.h> 53 #include <syslog.h> 54 55 #include "pppd.h" 56 #include "upap.h" 57 58 /* 59 * Protocol entry points. 60 */ 61 static void upap_init(int); 62 static void upap_lowerup(int); 63 static void upap_lowerdown(int); 64 static void upap_input(int, u_char *, int); 65 static void upap_protrej(int); 66 static int upap_printpkt(u_char *, int, void (*)(void *, char *, ...), void *); 67 68 struct protent pap_protent = { 69 PPP_PAP, 70 upap_init, 71 upap_input, 72 upap_protrej, 73 upap_lowerup, 74 upap_lowerdown, 75 NULL, 76 NULL, 77 upap_printpkt, 78 NULL, 79 1, 80 "PAP", 81 NULL, 82 NULL, 83 NULL 84 }; 85 86 upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */ 87 88 static void upap_timeout(void *); 89 static void upap_reqtimeout(void *); 90 static void upap_rauthreq(upap_state *, u_char *, int, int); 91 static void upap_rauthack(upap_state *, u_char *, int, int); 92 static void upap_rauthnak(upap_state *, u_char *, int, int); 93 static void upap_sauthreq(upap_state *); 94 static void upap_sresp(upap_state *, int, int, char *, int); 95 96 97 /* 98 * upap_init - Initialize a UPAP unit. 99 */ 100 static void 101 upap_init(int unit) 102 { 103 upap_state *u = &upap[unit]; 104 105 u->us_unit = unit; 106 u->us_user = NULL; 107 u->us_userlen = 0; 108 u->us_passwd = NULL; 109 u->us_passwdlen = 0; 110 u->us_clientstate = UPAPCS_INITIAL; 111 u->us_serverstate = UPAPSS_INITIAL; 112 u->us_id = 0; 113 u->us_timeouttime = UPAP_DEFTIMEOUT; 114 u->us_maxtransmits = 10; 115 u->us_reqtimeout = UPAP_DEFREQTIME; 116 } 117 118 119 /* 120 * upap_authwithpeer - Authenticate us with our peer (start client). 121 * 122 * Set new state and send authenticate's. 123 */ 124 void 125 upap_authwithpeer(int unit, char *user, char *password) 126 { 127 upap_state *u = &upap[unit]; 128 129 /* Save the username and password we're given */ 130 u->us_user = user; 131 u->us_userlen = strlen(user); 132 u->us_passwd = password; 133 u->us_passwdlen = strlen(password); 134 u->us_transmits = 0; 135 136 /* Lower layer up yet? */ 137 if (u->us_clientstate == UPAPCS_INITIAL || 138 u->us_clientstate == UPAPCS_PENDING) { 139 u->us_clientstate = UPAPCS_PENDING; 140 return; 141 } 142 143 upap_sauthreq(u); /* Start protocol */ 144 } 145 146 147 /* 148 * upap_authpeer - Authenticate our peer (start server). 149 * 150 * Set new state. 151 */ 152 void 153 upap_authpeer(int unit) 154 { 155 upap_state *u = &upap[unit]; 156 157 /* Lower layer up yet? */ 158 if (u->us_serverstate == UPAPSS_INITIAL || 159 u->us_serverstate == UPAPSS_PENDING) { 160 u->us_serverstate = UPAPSS_PENDING; 161 return; 162 } 163 164 u->us_serverstate = UPAPSS_LISTEN; 165 if (u->us_reqtimeout > 0) 166 TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout); 167 } 168 169 170 /* 171 * upap_timeout - Retransmission timer for sending auth-reqs expired. 172 */ 173 static void 174 upap_timeout(void *arg) 175 { 176 upap_state *u = (upap_state *) arg; 177 178 if (u->us_clientstate != UPAPCS_AUTHREQ) 179 return; 180 181 if (u->us_transmits >= u->us_maxtransmits) { 182 /* give up in disgust */ 183 syslog(LOG_ERR, "No response to PAP authenticate-requests"); 184 u->us_clientstate = UPAPCS_BADAUTH; 185 auth_withpeer_fail(u->us_unit, PPP_PAP); 186 return; 187 } 188 189 upap_sauthreq(u); /* Send Authenticate-Request */ 190 } 191 192 193 /* 194 * upap_reqtimeout - Give up waiting for the peer to send an auth-req. 195 */ 196 static void 197 upap_reqtimeout(void *arg) 198 { 199 upap_state *u = (upap_state *) arg; 200 201 if (u->us_serverstate != UPAPSS_LISTEN) 202 return; /* huh?? */ 203 204 auth_peer_fail(u->us_unit, PPP_PAP); 205 u->us_serverstate = UPAPSS_BADAUTH; 206 } 207 208 209 /* 210 * upap_lowerup - The lower layer is up. 211 * 212 * Start authenticating if pending. 213 */ 214 static void 215 upap_lowerup(int unit) 216 { 217 upap_state *u = &upap[unit]; 218 219 if (u->us_clientstate == UPAPCS_INITIAL) 220 u->us_clientstate = UPAPCS_CLOSED; 221 else if (u->us_clientstate == UPAPCS_PENDING) { 222 upap_sauthreq(u); /* send an auth-request */ 223 } 224 225 if (u->us_serverstate == UPAPSS_INITIAL) 226 u->us_serverstate = UPAPSS_CLOSED; 227 else if (u->us_serverstate == UPAPSS_PENDING) { 228 u->us_serverstate = UPAPSS_LISTEN; 229 if (u->us_reqtimeout > 0) 230 TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout); 231 } 232 } 233 234 235 /* 236 * upap_lowerdown - The lower layer is down. 237 * 238 * Cancel all timeouts. 239 */ 240 static void 241 upap_lowerdown(int unit) 242 { 243 upap_state *u = &upap[unit]; 244 245 if (u->us_clientstate == UPAPCS_AUTHREQ) /* Timeout pending? */ 246 UNTIMEOUT(upap_timeout, u); /* Cancel timeout */ 247 if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0) 248 UNTIMEOUT(upap_reqtimeout, u); 249 250 u->us_clientstate = UPAPCS_INITIAL; 251 u->us_serverstate = UPAPSS_INITIAL; 252 } 253 254 255 /* 256 * upap_protrej - Peer doesn't speak this protocol. 257 * 258 * This shouldn't happen. In any case, pretend lower layer went down. 259 */ 260 static void 261 upap_protrej(int unit) 262 { 263 upap_state *u = &upap[unit]; 264 265 if (u->us_clientstate == UPAPCS_AUTHREQ) { 266 syslog(LOG_ERR, "PAP authentication failed due to protocol-reject"); 267 auth_withpeer_fail(unit, PPP_PAP); 268 } 269 if (u->us_serverstate == UPAPSS_LISTEN) { 270 syslog(LOG_ERR, "PAP authentication of peer failed (protocol-reject)"); 271 auth_peer_fail(unit, PPP_PAP); 272 } 273 upap_lowerdown(unit); 274 } 275 276 277 /* 278 * upap_input - Input UPAP packet. 279 */ 280 static void 281 upap_input(int unit, u_char *inpacket, int l) 282 { 283 upap_state *u = &upap[unit]; 284 u_char *inp; 285 u_char code, id; 286 int len; 287 288 /* 289 * Parse header (code, id and length). 290 * If packet too short, drop it. 291 */ 292 inp = inpacket; 293 if (l < UPAP_HEADERLEN) { 294 UPAPDEBUG((LOG_INFO, "pap_input: rcvd short header.")); 295 return; 296 } 297 GETCHAR(code, inp); 298 GETCHAR(id, inp); 299 GETSHORT(len, inp); 300 if (len < UPAP_HEADERLEN) { 301 UPAPDEBUG((LOG_INFO, "pap_input: rcvd illegal length.")); 302 return; 303 } 304 if (len > l) { 305 UPAPDEBUG((LOG_INFO, "pap_input: rcvd short packet.")); 306 return; 307 } 308 len -= UPAP_HEADERLEN; 309 310 /* 311 * Action depends on code. 312 */ 313 switch (code) { 314 case UPAP_AUTHREQ: 315 upap_rauthreq(u, inp, id, len); 316 break; 317 318 case UPAP_AUTHACK: 319 upap_rauthack(u, inp, id, len); 320 break; 321 322 case UPAP_AUTHNAK: 323 upap_rauthnak(u, inp, id, len); 324 break; 325 326 default: /* XXX Need code reject */ 327 break; 328 } 329 } 330 331 332 /* 333 * upap_rauth - Receive Authenticate. 334 */ 335 static void 336 upap_rauthreq(upap_state *u, u_char *inp, int id, int len) 337 { 338 u_char ruserlen, rpasswdlen; 339 char *ruser, *rpasswd; 340 int retcode; 341 char *msg; 342 int msglen; 343 344 UPAPDEBUG((LOG_INFO, "pap_rauth: Rcvd id %d.", id)); 345 346 if (u->us_serverstate < UPAPSS_LISTEN) 347 return; 348 349 /* 350 * If we receive a duplicate authenticate-request, we are 351 * supposed to return the same status as for the first request. 352 */ 353 if (u->us_serverstate == UPAPSS_OPEN) { 354 upap_sresp(u, UPAP_AUTHACK, id, "", 0); /* return auth-ack */ 355 return; 356 } 357 if (u->us_serverstate == UPAPSS_BADAUTH) { 358 upap_sresp(u, UPAP_AUTHNAK, id, "", 0); /* return auth-nak */ 359 return; 360 } 361 362 /* 363 * Parse user/passwd. 364 */ 365 if (len < sizeof (u_char)) { 366 UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.")); 367 return; 368 } 369 GETCHAR(ruserlen, inp); 370 len -= sizeof (u_char) + ruserlen + sizeof (u_char); 371 if (len < 0) { 372 UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.")); 373 return; 374 } 375 ruser = (char *) inp; 376 INCPTR(ruserlen, inp); 377 GETCHAR(rpasswdlen, inp); 378 if (len < rpasswdlen) { 379 UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.")); 380 return; 381 } 382 rpasswd = (char *) inp; 383 384 /* 385 * Check the username and password given. 386 */ 387 retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd, 388 rpasswdlen, &msg, &msglen); 389 EXPLICIT_BZERO(rpasswd, rpasswdlen); 390 391 upap_sresp(u, retcode, id, msg, msglen); 392 393 if (retcode == UPAP_AUTHACK) { 394 u->us_serverstate = UPAPSS_OPEN; 395 auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen); 396 } else { 397 u->us_serverstate = UPAPSS_BADAUTH; 398 auth_peer_fail(u->us_unit, PPP_PAP); 399 } 400 401 if (u->us_reqtimeout > 0) 402 UNTIMEOUT(upap_reqtimeout, u); 403 } 404 405 406 /* 407 * upap_rauthack - Receive Authenticate-Ack. 408 */ 409 static void 410 upap_rauthack(upap_state *u, u_char *inp, int id, int len) 411 { 412 u_char msglen; 413 char *msg; 414 415 UPAPDEBUG((LOG_INFO, "pap_rauthack: Rcvd id %d.", id)); 416 if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */ 417 return; 418 419 /* 420 * Parse message. 421 */ 422 if (len < sizeof (u_char)) { 423 UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet.")); 424 return; 425 } 426 GETCHAR(msglen, inp); 427 len -= sizeof (u_char); 428 if (len < msglen) { 429 UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet.")); 430 return; 431 } 432 msg = (char *) inp; 433 PRINTMSG(msg, msglen); 434 435 u->us_clientstate = UPAPCS_OPEN; 436 437 auth_withpeer_success(u->us_unit, PPP_PAP); 438 } 439 440 441 /* 442 * upap_rauthnak - Receive Authenticate-Nakk. 443 */ 444 static void 445 upap_rauthnak(upap_state *u, u_char *inp, int id, int len) 446 { 447 u_char msglen; 448 char *msg; 449 450 UPAPDEBUG((LOG_INFO, "pap_rauthnak: Rcvd id %d.", id)); 451 if (u->us_clientstate != UPAPCS_AUTHREQ) /* XXX */ 452 return; 453 454 /* 455 * Parse message. 456 */ 457 if (len < sizeof (u_char)) { 458 UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.")); 459 return; 460 } 461 GETCHAR(msglen, inp); 462 len -= sizeof (u_char); 463 if (len < msglen) { 464 UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.")); 465 return; 466 } 467 msg = (char *) inp; 468 PRINTMSG(msg, msglen); 469 470 u->us_clientstate = UPAPCS_BADAUTH; 471 472 syslog(LOG_ERR, "PAP authentication failed"); 473 auth_withpeer_fail(u->us_unit, PPP_PAP); 474 } 475 476 477 /* 478 * upap_sauthreq - Send an Authenticate-Request. 479 */ 480 static void 481 upap_sauthreq(upap_state *u) 482 { 483 u_char *outp; 484 int outlen; 485 486 outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) + 487 u->us_userlen + u->us_passwdlen; 488 outp = outpacket_buf; 489 490 MAKEHEADER(outp, PPP_PAP); 491 492 PUTCHAR(UPAP_AUTHREQ, outp); 493 PUTCHAR(++u->us_id, outp); 494 PUTSHORT(outlen, outp); 495 PUTCHAR(u->us_userlen, outp); 496 BCOPY(u->us_user, outp, u->us_userlen); 497 INCPTR(u->us_userlen, outp); 498 PUTCHAR(u->us_passwdlen, outp); 499 BCOPY(u->us_passwd, outp, u->us_passwdlen); 500 501 output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN); 502 503 UPAPDEBUG((LOG_INFO, "pap_sauth: Sent id %d.", u->us_id)); 504 505 TIMEOUT(upap_timeout, u, u->us_timeouttime); 506 ++u->us_transmits; 507 u->us_clientstate = UPAPCS_AUTHREQ; 508 } 509 510 511 /* 512 * upap_sresp - Send a response (ack or nak). 513 */ 514 static void 515 upap_sresp(upap_state *u, int code, int id, char *msg, int msglen) 516 { 517 u_char *outp; 518 int outlen; 519 520 outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen; 521 outp = outpacket_buf; 522 MAKEHEADER(outp, PPP_PAP); 523 524 PUTCHAR(code, outp); 525 PUTCHAR(id, outp); 526 PUTSHORT(outlen, outp); 527 PUTCHAR(msglen, outp); 528 BCOPY(msg, outp, msglen); 529 output(u->us_unit, outpacket_buf, outlen + PPP_HDRLEN); 530 531 UPAPDEBUG((LOG_INFO, "pap_sresp: Sent code %d, id %d.", code, id)); 532 } 533 534 /* 535 * upap_printpkt - print the contents of a PAP packet. 536 */ 537 static char *upap_codenames[] = { 538 "AuthReq", "AuthAck", "AuthNak" 539 }; 540 541 static int 542 upap_printpkt(u_char *p, int plen, void (*printer)(void *, char *, ...), void *arg) 543 { 544 int code, id, len; 545 int mlen, ulen, wlen; 546 char *user, *pwd, *msg; 547 u_char *pstart; 548 549 if (plen < UPAP_HEADERLEN) 550 return 0; 551 pstart = p; 552 GETCHAR(code, p); 553 GETCHAR(id, p); 554 GETSHORT(len, p); 555 if (len < UPAP_HEADERLEN || len > plen) 556 return 0; 557 558 if (code >= 1 && code <= sizeof(upap_codenames) / sizeof(char *)) 559 printer(arg, " %s", upap_codenames[code-1]); 560 else 561 printer(arg, " code=0x%x", code); 562 printer(arg, " id=0x%x", id); 563 len -= UPAP_HEADERLEN; 564 switch (code) { 565 case UPAP_AUTHREQ: 566 if (len < 1) 567 break; 568 ulen = p[0]; 569 if (len < ulen + 2) 570 break; 571 wlen = p[ulen + 1]; 572 if (len < ulen + wlen + 2) 573 break; 574 user = (char *) (p + 1); 575 pwd = (char *) (p + ulen + 2); 576 p += ulen + wlen + 2; 577 len -= ulen + wlen + 2; 578 printer(arg, " user="); 579 print_string(user, ulen, printer, arg); 580 printer(arg, " password="); 581 print_string(pwd, wlen, printer, arg); 582 break; 583 case UPAP_AUTHACK: 584 case UPAP_AUTHNAK: 585 if (len < 1) 586 break; 587 mlen = p[0]; 588 if (len < mlen + 1) 589 break; 590 msg = (char *) (p + 1); 591 p += mlen + 1; 592 len -= mlen + 1; 593 printer(arg, " "); 594 print_string(msg, mlen, printer, arg); 595 break; 596 } 597 598 /* print the rest of the bytes in the packet */ 599 for (; len > 0; --len) { 600 GETCHAR(code, p); 601 printer(arg, " %.2x", code); 602 } 603 604 return p - pstart; 605 } 606