* Exchange a message for SASL communication protocol with the backend. * This should be used after calling pg_SASL_init to set up the status of * the protocol. */
| 629 | * the protocol. |
| 630 | */ |
| 631 | static int |
| 632 | pg_SASL_continue(PGconn *conn, int payloadlen, bool final) |
| 633 | { |
| 634 | char *output; |
| 635 | int outputlen; |
| 636 | bool done; |
| 637 | bool success; |
| 638 | int res; |
| 639 | char *challenge; |
| 640 | |
| 641 | /* Read the SASL challenge from the AuthenticationSASLContinue message. */ |
| 642 | challenge = malloc(payloadlen + 1); |
| 643 | if (!challenge) |
| 644 | { |
| 645 | appendPQExpBuffer(&conn->errorMessage, |
| 646 | libpq_gettext("out of memory allocating SASL buffer (%d)\n"), |
| 647 | payloadlen); |
| 648 | return STATUS_ERROR; |
| 649 | } |
| 650 | |
| 651 | if (pqGetnchar(challenge, payloadlen, conn)) |
| 652 | { |
| 653 | free(challenge); |
| 654 | return STATUS_ERROR; |
| 655 | } |
| 656 | /* For safety and convenience, ensure the buffer is NULL-terminated. */ |
| 657 | challenge[payloadlen] = '\0'; |
| 658 | |
| 659 | pg_fe_scram_exchange(conn->sasl_state, |
| 660 | challenge, payloadlen, |
| 661 | &output, &outputlen, |
| 662 | &done, &success); |
| 663 | free(challenge); /* don't need the input anymore */ |
| 664 | |
| 665 | if (final && !done) |
| 666 | { |
| 667 | if (outputlen != 0) |
| 668 | free(output); |
| 669 | |
| 670 | appendPQExpBufferStr(&conn->errorMessage, |
| 671 | libpq_gettext("AuthenticationSASLFinal received from server, but SASL authentication was not completed\n")); |
| 672 | return STATUS_ERROR; |
| 673 | } |
| 674 | if (outputlen != 0) |
| 675 | { |
| 676 | /* |
| 677 | * Send the SASL response to the server. |
| 678 | */ |
| 679 | res = pqPacketSend(conn, 'p', output, outputlen); |
| 680 | free(output); |
| 681 | |
| 682 | if (res != STATUS_OK) |
| 683 | return STATUS_ERROR; |
| 684 | } |
| 685 | |
| 686 | if (done && !success) |
| 687 | return STATUS_ERROR; |
| 688 |
no test coverage detected