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