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