* Attempt to write len bytes of data from ptr to a GSSAPI-encrypted connection. * * The connection must be already set up for GSSAPI encryption (i.e., GSSAPI * transport negotiation is complete). * * On success, returns the number of data bytes consumed (possibly less than * len). On failure, returns -1 with errno set appropriately. If the errno * indicates a non-retryable error, a messag
| 90 | * once the socket is ready. |
| 91 | */ |
| 92 | ssize_t |
| 93 | pg_GSS_write(PGconn *conn, const void *ptr, size_t len) |
| 94 | { |
| 95 | OM_uint32 major, |
| 96 | minor; |
| 97 | gss_buffer_desc input, |
| 98 | output = GSS_C_EMPTY_BUFFER; |
| 99 | ssize_t ret = -1; |
| 100 | size_t bytes_sent = 0; |
| 101 | size_t bytes_to_encrypt; |
| 102 | size_t bytes_encrypted; |
| 103 | gss_ctx_id_t gctx = conn->gctx; |
| 104 | |
| 105 | /* |
| 106 | * When we get a failure, we must not tell the caller we have successfully |
| 107 | * transmitted everything, else it won't retry. Hence a "success" |
| 108 | * (positive) return value must only count source bytes corresponding to |
| 109 | * fully-transmitted encrypted packets. The amount of source data |
| 110 | * corresponding to the current partly-transmitted packet is remembered in |
| 111 | * PqGSSSendConsumed. On a retry, the caller *must* be sending that data |
| 112 | * again, so if it offers a len less than that, something is wrong. |
| 113 | */ |
| 114 | if (len < PqGSSSendConsumed) |
| 115 | { |
| 116 | appendPQExpBufferStr(&conn->errorMessage, |
| 117 | "GSSAPI caller failed to retransmit all data needing to be retried\n"); |
| 118 | errno = EINVAL; |
| 119 | return -1; |
| 120 | } |
| 121 | |
| 122 | /* Discount whatever source data we already encrypted. */ |
| 123 | bytes_to_encrypt = len - PqGSSSendConsumed; |
| 124 | bytes_encrypted = PqGSSSendConsumed; |
| 125 | |
| 126 | /* |
| 127 | * Loop through encrypting data and sending it out until it's all done or |
| 128 | * pqsecure_raw_write() complains (which would likely mean that the socket |
| 129 | * is non-blocking and the requested send() would block, or there was some |
| 130 | * kind of actual error). |
| 131 | */ |
| 132 | while (bytes_to_encrypt || PqGSSSendLength) |
| 133 | { |
| 134 | int conf_state = 0; |
| 135 | uint32 netlen; |
| 136 | |
| 137 | /* |
| 138 | * Check if we have data in the encrypted output buffer that needs to |
| 139 | * be sent (possibly left over from a previous call), and if so, try |
| 140 | * to send it. If we aren't able to, return that fact back up to the |
| 141 | * caller. |
| 142 | */ |
| 143 | if (PqGSSSendLength) |
| 144 | { |
| 145 | ssize_t ret; |
| 146 | ssize_t amount = PqGSSSendLength - PqGSSSendNext; |
| 147 | |
| 148 | ret = pqsecure_raw_write(conn, PqGSSSendBuffer + PqGSSSendNext, amount); |
| 149 | if (ret <= 0) |
no test coverage detected