/* * Discard any pending SIGPIPE and reset the signal mask. * * Note: we are effectively assuming here that the C library doesn't queue * up multiple SIGPIPE events. If it did, then we'd accidentally leave * ours in the queue when an event was already pending and we got another. * As long as it doesn't queue multiple events, we're OK because the caller * can't tell the difference. * * The caller should say got_epipe = FALSE if it is certain that it * didn't get an EPIPE error; in that case we'll skip the clear operation * and things are definitely OK, queuing or no. If it got one or might have * gotten one, pass got_epipe = TRUE. * * We do not want this to change errno, since if it did that could lose * the error code from a preceding send(). We essentially assume that if * we were able to do pq_block_sigpipe(), this can't fail. */ void pq_reset_sigpipe(sigset_t *osigset, bool sigpipe_pending, bool got_epipe) { int save_errno = SOCK_ERRNO; int signo; sigset_t sigset; /* Clear SIGPIPE only if none was pending */ if (got_epipe && !sigpipe_pending) { if (sigpending(&sigset) == 0 && sigismember(&sigset, SIGPIPE)) { sigset_t sigpipe_sigset; sigemptyset(&sigpipe_sigset); sigaddset(&sigpipe_sigset, SIGPIPE); sigwait(&sigpipe_sigset, &signo); } } /* Restore saved block mask */ pthread_sigmask(SIG_SETMASK, osigset, NULL); SOCK_ERRNO_SET(save_errno); }
/* * Block SIGPIPE for this thread. This prevents send()/write() from exiting * the application. */ int pq_block_sigpipe(sigset_t *osigset, bool *sigpipe_pending) { sigset_t sigpipe_sigset; sigset_t sigset; sigemptyset(&sigpipe_sigset); sigaddset(&sigpipe_sigset, SIGPIPE); /* Block SIGPIPE and save previous mask for later reset */ SOCK_ERRNO_SET(pthread_sigmask(SIG_BLOCK, &sigpipe_sigset, osigset)); if (SOCK_ERRNO) return -1; /* We can have a pending SIGPIPE only if it was blocked before */ if (sigismember(osigset, SIGPIPE)) { /* Is there a pending SIGPIPE? */ if (sigpending(&sigset) != 0) return -1; if (sigismember(&sigset, SIGPIPE)) *sigpipe_pending = true; else *sigpipe_pending = false; } else *sigpipe_pending = false; return 0; }
/* * recv more than 1 bytes using SSL. */ static int SOCK_SSL_recv(SocketClass *sock, void *buffer, int len) { CSTR func = "SOCK_SSL_recv"; int n, err, gerrno, retry_count = 0; retry: n = SSL_read(sock->ssl, buffer, len); err = SSL_get_error(sock->ssl, len); gerrno = SOCK_ERRNO; inolog("%s: %d get_error=%d Lasterror=%d\n", func, n, err, gerrno); switch (err) { case SSL_ERROR_NONE: break; case SSL_ERROR_WANT_READ: retry_count++; if (SOCK_wait_for_ready(sock, FALSE, retry_count) >= 0) goto retry; n = -1; break; case SSL_ERROR_WANT_WRITE: goto retry; break; case SSL_ERROR_SYSCALL: if (-1 != n) { n = -1; SOCK_ERRNO_SET(ECONNRESET); } break; case SSL_ERROR_SSL: case SSL_ERROR_ZERO_RETURN: n = -1; SOCK_ERRNO_SET(ECONNRESET); break; default: n = -1; } return n; }
ssize_t pqsecure_raw_read(PGconn *conn, void *ptr, size_t len) { ssize_t n; int result_errno = 0; char sebuf[256]; n = recv(conn->sock, ptr, len, 0); if (n < 0) { result_errno = SOCK_ERRNO; /* Set error message if appropriate */ switch (result_errno) { #ifdef EAGAIN case EAGAIN: #endif #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) case EWOULDBLOCK: #endif case EINTR: /* no error message, caller is expected to retry */ break; #ifdef ECONNRESET case ECONNRESET: printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "server closed the connection unexpectedly\n" "\tThis probably means the server terminated abnormally\n" "\tbefore or while processing the request.\n")); break; #endif default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not receive data from server: %s\n"), SOCK_STRERROR(result_errno, sebuf, sizeof(sebuf))); break; } } /* ensure we return the intended errno to caller */ SOCK_ERRNO_SET(result_errno); return n; }
/* * Read data from a secure connection. */ ssize_t pqsecure_read(PGconn *conn, void *ptr, size_t len) { ssize_t n; #ifdef USE_SSL if (conn->ssl) { int err; DECLARE_SIGPIPE_INFO(spinfo); /* SSL_read can write to the socket, so we need to disable SIGPIPE */ DISABLE_SIGPIPE(conn, spinfo, return -1); rloop: SOCK_ERRNO_SET(0); n = SSL_read(conn->ssl, ptr, len); err = SSL_get_error(conn->ssl, n); switch (err) { case SSL_ERROR_NONE: break; case SSL_ERROR_WANT_READ: n = 0; break; case SSL_ERROR_WANT_WRITE: /* * Returning 0 here would cause caller to wait for read-ready, * which is not correct since what SSL wants is wait for * write-ready. The former could get us stuck in an infinite * wait, so don't risk it; busy-loop instead. */ goto rloop; case SSL_ERROR_SYSCALL: { char sebuf[256]; if (n == -1) { REMEMBER_EPIPE(spinfo, SOCK_ERRNO == EPIPE); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); } else { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: EOF detected\n")); SOCK_ERRNO_SET(ECONNRESET); n = -1; } break; } case SSL_ERROR_SSL: { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), err); SSLerrfree(err); } /* fall through */ case SSL_ERROR_ZERO_RETURN: SOCK_ERRNO_SET(ECONNRESET); n = -1; break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("unrecognized SSL error code: %d\n"), err); n = -1; break; } RESTORE_SIGPIPE(conn, spinfo); }
/* * Read data from a secure connection. * * On failure, this function is responsible for putting a suitable message * into conn->errorMessage. The caller must still inspect errno, but only * to determine whether to continue/retry after error. */ ssize_t pqsecure_read(PGconn * conn, void *ptr, size_t len) { ssize_t n; int result_errno = 0; char sebuf[256]; #ifdef USE_SSL if (conn->ssl) { int err; DECLARE_SIGPIPE_INFO(spinfo); /* SSL_read can write to the socket, so we need to disable SIGPIPE */ DISABLE_SIGPIPE(conn, spinfo, return -1); rloop: SOCK_ERRNO_SET(0); n = SSL_read(conn->ssl, ptr, len); err = SSL_get_error(conn->ssl, n); switch (err) { case SSL_ERROR_NONE: if (n < 0) { /* Not supposed to happen, so we don't translate the msg */ print_pqbuf(&conn->errorMessage, "SSL_read failed but did not provide error information\n"); /* assume the connection is broken */ result_errno = ECONNRESET; } break; case SSL_ERROR_WANT_READ: n = 0; break; case SSL_ERROR_WANT_WRITE: /* * Returning 0 here would cause caller to wait for read-ready, * which is not correct since what SSL wants is wait for * write-ready. The former could get us stuck in an infinite * wait, so don't risk it; busy-loop instead. */ goto rloop; case SSL_ERROR_SYSCALL: if (n < 0) { result_errno = SOCK_ERRNO; REMEMBER_EPIPE(spinfo, result_errno == EPIPE); if (result_errno == EPIPE || result_errno == ECONNRESET) print_pqbuf(&conn->errorMessage, libpq_gettext ("server closed the connection unexpectedly\n" "\tThis probably means the server terminated abnormally\n" "\tbefore or while processing the request.\n")); else print_pqbuf(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), SOCK_STRERROR(result_errno, sebuf, sizeof(sebuf))); } else { print_pqbuf(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: EOF detected\n")); /* assume the connection is broken */ result_errno = ECONNRESET; n = -1; } break; case SSL_ERROR_SSL: { char *errm = SSLerrmessage(); print_pqbuf(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), errm); SSLerrfree(errm); /* assume the connection is broken */ result_errno = ECONNRESET; n = -1; break; } case SSL_ERROR_ZERO_RETURN: /* * Per OpenSSL documentation, this error code is only returned * for a clean connection closure, so we should not report it * as a server crash. */ print_pqbuf(&conn->errorMessage, libpq_gettext("SSL connection has been closed unexpectedly\n")); result_errno = ECONNRESET; n = -1; break; default: print_pqbuf(&conn->errorMessage, libpq_gettext("unrecognized SSL error code: %d\n"), err); /* assume the connection is broken */ result_errno = ECONNRESET; n = -1; break; } RESTORE_SIGPIPE(conn, spinfo); } else
ssize_t pqsecure_raw_write(PGconn *conn, const void *ptr, size_t len) { ssize_t n; int flags = 0; int result_errno = 0; char sebuf[256]; DECLARE_SIGPIPE_INFO(spinfo); #ifdef MSG_NOSIGNAL if (conn->sigpipe_flag) flags |= MSG_NOSIGNAL; retry_masked: #endif /* MSG_NOSIGNAL */ DISABLE_SIGPIPE(conn, spinfo, return -1); n = send(conn->sock, ptr, len, flags); if (n < 0) { result_errno = SOCK_ERRNO; /* * If we see an EINVAL, it may be because MSG_NOSIGNAL isn't available * on this machine. So, clear sigpipe_flag so we don't try the flag * again, and retry the send(). */ #ifdef MSG_NOSIGNAL if (flags != 0 && result_errno == EINVAL) { conn->sigpipe_flag = false; flags = 0; goto retry_masked; } #endif /* MSG_NOSIGNAL */ /* Set error message if appropriate */ switch (result_errno) { #ifdef EAGAIN case EAGAIN: #endif #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) case EWOULDBLOCK: #endif case EINTR: /* no error message, caller is expected to retry */ break; case EPIPE: /* Set flag for EPIPE */ REMEMBER_EPIPE(spinfo, true); /* FALL THRU */ #ifdef ECONNRESET case ECONNRESET: #endif printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "server closed the connection unexpectedly\n" "\tThis probably means the server terminated abnormally\n" "\tbefore or while processing the request.\n")); break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not send data to server: %s\n"), SOCK_STRERROR(result_errno, sebuf, sizeof(sebuf))); break; } } RESTORE_SIGPIPE(conn, spinfo); /* ensure we return the intended errno to caller */ SOCK_ERRNO_SET(result_errno); return n; }
/* * Write data to a secure connection. */ ssize_t pqsecure_write(PGconn *conn, const void *ptr, size_t len) { ssize_t n; #ifndef WIN32 #ifdef ENABLE_THREAD_SAFETY sigset_t osigmask; bool sigpipe_pending; bool got_epipe = false; if (pq_block_sigpipe(&osigmask, &sigpipe_pending) < 0) return -1; #else pqsigfunc oldsighandler = pqsignal(SIGPIPE, SIG_IGN); #endif /* ENABLE_THREAD_SAFETY */ #endif /* WIN32 */ #ifdef USE_SSL if (conn->ssl) { int err; n = SSL_write(conn->ssl, ptr, len); err = SSL_get_error(conn->ssl, n); switch (err) { case SSL_ERROR_NONE: break; case SSL_ERROR_WANT_READ: /* * Returning 0 here causes caller to wait for write-ready, * which is not really the right thing, but it's the best we * can do. */ n = 0; break; case SSL_ERROR_WANT_WRITE: n = 0; break; case SSL_ERROR_SYSCALL: { char sebuf[256]; if (n == -1) { #if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32) if (SOCK_ERRNO == EPIPE) got_epipe = true; #endif printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); } else { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL SYSCALL error: EOF detected\n")); SOCK_ERRNO_SET(ECONNRESET); n = -1; } break; } case SSL_ERROR_SSL: { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), err); SSLerrfree(err); } /* fall through */ case SSL_ERROR_ZERO_RETURN: SOCK_ERRNO_SET(ECONNRESET); n = -1; break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("unrecognized SSL error code: %d\n"), err); n = -1; break; } } else #endif { n = send(conn->sock, ptr, len, 0); #if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32) if (n < 0 && SOCK_ERRNO == EPIPE) got_epipe = true; #endif } #ifndef WIN32 #ifdef ENABLE_THREAD_SAFETY pq_reset_sigpipe(&osigmask, sigpipe_pending, got_epipe); #else pqsignal(SIGPIPE, oldsighandler); #endif /* ENABLE_THREAD_SAFETY */ #endif /* WIN32 */ return n; }
int SSPI_send(SocketClass *self, const void *buffer, int len) { CSTR func = "SSPI_send"; if (0 != (self->sspisvcs & SchannelService)) { SecPkgContext_StreamSizes sizes; int ttllen, wrtlen, slen; LPVOID lpHead; LPVOID lpMsg; LPVOID lpTrail; SecBuffer sb[4]; SecBufferDesc sbd; SchannelSpec *ssd = (SchannelSpec *) self->ssd; QueryContextAttributes(&ssd->hCtxt, SECPKG_ATTR_STREAM_SIZES, &sizes); slen = len; ttllen = sizes.cbHeader + len + sizes.cbTrailer; if (ttllen > sizes.cbMaximumMessage) { ttllen = sizes.cbMaximumMessage; slen = ttllen - sizes.cbHeader - sizes.cbTrailer; } lpHead = malloc(ttllen); lpMsg = (char *) lpHead + sizes.cbHeader; memcpy(lpMsg, buffer, slen); lpTrail = (char *) lpMsg + slen; sb[0].cbBuffer = sizes.cbHeader; sb[0].pvBuffer = lpHead; sb[0].BufferType = SECBUFFER_STREAM_HEADER; sb[1].cbBuffer = slen; sb[1].pvBuffer = lpMsg; sb[1].BufferType = SECBUFFER_DATA; sb[2].cbBuffer = sizes.cbTrailer; sb[2].pvBuffer = lpTrail; sb[2].BufferType = SECBUFFER_STREAM_TRAILER; /* sb[3].cbBuffer = 16; sb[3].pvBuffer = lpPad; */ sb[3].BufferType = SECBUFFER_EMPTY; sbd.cBuffers = 4; sbd.pBuffers = sb; sbd.ulVersion = SECBUFFER_VERSION; EncryptMessage(&ssd->hCtxt, 0, &sbd, 0); mylog("EMPTY=%p %d %d\n", sb[3].pvBuffer, sb[3].cbBuffer, sb[3].BufferType); if (wrtlen = sendall(self->socket, lpHead, ttllen), wrtlen < 0) { int gerrno = SOCK_ERRNO; free(lpHead); SOCK_ERRNO_SET(gerrno); return -1; } free(lpHead); return slen; } else return send(self->socket, (char *) buffer, len, 0); }