/* * Checks a socket, using poll or select, for data to be read, written, * or both. Returns >0 if one or more conditions are met, 0 if it timed * out, -1 if an error occurred. */ static int pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time) { int result; if (!conn) return -1; if (conn->sock < 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("socket not open\n")); return -1; } /* We will retry as long as we get EINTR */ do result = pqSocketPoll(conn->sock, forRead, forWrite, end_time); while (result < 0 && SOCK_ERRNO == EINTR); if (result < 0) { char sebuf[256]; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("select() failed: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); } return result; }
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; }
/* * Checks a socket, using poll or select, for data to be read, written, * or both. Returns >0 if one or more conditions are met, 0 if it timed * out, -1 if an error occurred. * * If SSL is in use, the SSL buffer is checked prior to checking the socket * for read data directly. */ static int pqSocketCheck(PGconn *conn, int forRead, int forWrite, time_t end_time) { int result; if (!conn) return -1; if (conn->sock < 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("socket not open\n")); return -1; } #ifdef USE_SSL /* Check for SSL library buffering read bytes */ if (forRead && conn->ssl && SSL_pending(conn->ssl) > 0) { /* short-circuit the select */ return 1; } #endif /* We will retry as long as we get EINTR */ do result = pqSocketPoll(conn->sock, forRead, forWrite, end_time); while (result < 0 && SOCK_ERRNO == EINTR); if (result < 0) { char sebuf[256]; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("select() failed: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); } return result; }
/* * 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); }
/* * pqSendSome: send data waiting in the output buffer. * * len is how much to try to send (typically equal to outCount, but may * be less). * * Return 0 on success, -1 on failure and 1 when not all data could be sent * because the socket would block and the connection is non-blocking. */ static int pqSendSome(PGconn *conn, int len) { char *ptr = conn->outBuffer; int remaining = conn->outCount; int result = 0; if (conn->sock < 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("connection not open\n")); return -1; } /* while there's still data to send */ while (len > 0) { int sent; char sebuf[256]; #ifndef WIN32 sent = pqsecure_write(conn, ptr, len); #else /* * Windows can fail on large sends, per KB article Q201213. The * failure-point appears to be different in different versions of * Windows, but 64k should always be safe. */ sent = pqsecure_write(conn, ptr, Min(len, 65536)); #endif if (sent < 0) { /* * Anything except EAGAIN/EWOULDBLOCK/EINTR is trouble. If it's * EPIPE or ECONNRESET, assume we've lost the backend connection * permanently. */ switch (SOCK_ERRNO) { #ifdef EAGAIN case EAGAIN: break; #endif #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) case EWOULDBLOCK: break; #endif case EINTR: continue; case EPIPE: #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")); /* * We used to close the socket here, but that's a bad idea * since there might be unread data waiting (typically, a * NOTICE message from the backend telling us it's * committing hara-kiri...). Leave the socket open until * pqReadData finds no more data can be read. But abandon * attempt to send data. */ conn->outCount = 0; return -1; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not send data to server: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); /* We don't assume it's a fatal error... */ conn->outCount = 0; return -1; } } else { ptr += sent; len -= sent; remaining -= sent; } if (len > 0) { /* * We didn't send it all, wait till we can send more. * * If the connection is in non-blocking mode we don't wait, but * return 1 to indicate that data is still pending. */ if (pqIsnonblocking(conn)) { result = 1; break; } /* * There are scenarios in which we can't send data because the * communications channel is full, but we cannot expect the server * to clear the channel eventually because it's blocked trying to * send data to us. (This can happen when we are sending a large * amount of COPY data, and the server has generated lots of * NOTICE responses.) To avoid a deadlock situation, we must be * prepared to accept and buffer incoming data before we try * again. Furthermore, it is possible that such incoming data * might not arrive until after we've gone to sleep. Therefore, * we wait for either read ready or write ready. */ if (pqReadData(conn) < 0) { result = -1; /* error message already set up */ break; } if (pqWait(TRUE, TRUE, conn)) { result = -1; break; } } } /* shift the remaining contents of the buffer */ if (remaining > 0) memmove(conn->outBuffer, ptr, remaining); conn->outCount = remaining; return result; }
/* ---------- * pqReadData: read more data, if any is available * Possible return values: * 1: successfully loaded at least one more byte * 0: no data is presently available, but no error detected * -1: error detected (including EOF = connection closure); * conn->errorMessage set * NOTE: callers must not assume that pointers or indexes into conn->inBuffer * remain valid across this call! * ---------- */ int pqReadData(PGconn *conn) { int someread = 0; int nread; char sebuf[256]; if (conn->sock < 0) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("connection not open\n")); return -1; } /* Left-justify any data in the buffer to make room */ if (conn->inStart < conn->inEnd) { if (conn->inStart > 0) { memmove(conn->inBuffer, conn->inBuffer + conn->inStart, conn->inEnd - conn->inStart); conn->inEnd -= conn->inStart; conn->inCursor -= conn->inStart; conn->inStart = 0; } } else { /* buffer is logically empty, reset it */ conn->inStart = conn->inCursor = conn->inEnd = 0; } /* * If the buffer is fairly full, enlarge it. We need to be able to enlarge * the buffer in case a single message exceeds the initial buffer size. We * enlarge before filling the buffer entirely so as to avoid asking the * kernel for a partial packet. The magic constant here should be large * enough for a TCP packet or Unix pipe bufferload. 8K is the usual pipe * buffer size, so... */ if (conn->inBufSize - conn->inEnd < 8192) { if (pqCheckInBufferSpace(conn->inEnd + (size_t) 8192, conn)) { /* * We don't insist that the enlarge worked, but we need some room */ if (conn->inBufSize - conn->inEnd < 100) return -1; /* errorMessage already set */ } } /* OK, try to read some data */ retry3: nread = pqsecure_read(conn, conn->inBuffer + conn->inEnd, conn->inBufSize - conn->inEnd); if (nread < 0) { if (SOCK_ERRNO == EINTR) goto retry3; /* Some systems return EAGAIN/EWOULDBLOCK for no data */ #ifdef EAGAIN if (SOCK_ERRNO == EAGAIN) return someread; #endif #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) if (SOCK_ERRNO == EWOULDBLOCK) return someread; #endif /* We might get ECONNRESET here if using TCP and backend died */ #ifdef ECONNRESET if (SOCK_ERRNO == ECONNRESET) goto definitelyFailed; #endif printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not receive data from server: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return -1; } if (nread > 0) { conn->inEnd += nread; /* * Hack to deal with the fact that some kernels will only give us back * 1 packet per recv() call, even if we asked for more and there is * more available. If it looks like we are reading a long message, * loop back to recv() again immediately, until we run out of data or * buffer space. Without this, the block-and-restart behavior of * libpq's higher levels leads to O(N^2) performance on long messages. * * Since we left-justified the data above, conn->inEnd gives the * amount of data already read in the current message. We consider * the message "long" once we have acquired 32k ... */ if (conn->inEnd > 32768 && (conn->inBufSize - conn->inEnd) >= 8192) { someread = 1; goto retry3; } return 1; } if (someread) return 1; /* got a zero read after successful tries */ /* * A return value of 0 could mean just that no data is now available, or * it could mean EOF --- that is, the server has closed the connection. * Since we have the socket in nonblock mode, the only way to tell the * difference is to see if select() is saying that the file is ready. * Grumble. Fortunately, we don't expect this path to be taken much, * since in normal practice we should not be trying to read data unless * the file selected for reading already. * * In SSL mode it's even worse: SSL_read() could say WANT_READ and then * data could arrive before we make the pqReadReady() test. So we must * play dumb and assume there is more data, relying on the SSL layer to * detect true EOF. */ #ifdef USE_SSL if (conn->ssl) return 0; #endif switch (pqReadReady(conn)) { case 0: /* definitely no data available */ return 0; case 1: /* ready for read */ break; default: goto definitelyFailed; } /* * Still not sure that it's EOF, because some data could have just * arrived. */ retry4: nread = pqsecure_read(conn, conn->inBuffer + conn->inEnd, conn->inBufSize - conn->inEnd); if (nread < 0) { if (SOCK_ERRNO == EINTR) goto retry4; /* Some systems return EAGAIN/EWOULDBLOCK for no data */ #ifdef EAGAIN if (SOCK_ERRNO == EAGAIN) return 0; #endif #if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN)) if (SOCK_ERRNO == EWOULDBLOCK) return 0; #endif /* We might get ECONNRESET here if using TCP and backend died */ #ifdef ECONNRESET if (SOCK_ERRNO == ECONNRESET) goto definitelyFailed; #endif printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not receive data from server: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return -1; } if (nread > 0) { conn->inEnd += nread; return 1; } /* * OK, we are getting a zero read even though select() says ready. This * means the connection has been closed. Cope. */ definitelyFailed: 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")); conn->status = CONNECTION_BAD; /* No more connection to backend */ pqsecure_close(conn); closesocket(conn->sock); conn->sock = -1; return -1; }
/* * 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; }
/* This function has not been changed to deal with NO_SOCKET_TO_FD (i.e., systems on which sockets cannot be converted to file descriptors). The first person to try building a kerberos client on such a system (OS/2, Windows 95, and maybe others) will have to take care of this. */ void start_kerberos4_server (cvsroot_t *root, struct buffer **to_server_p, struct buffer **from_server_p) { int s; int port; struct hostent *hp; struct sockaddr_in sin; char *hname; s = socket (AF_INET, SOCK_STREAM, 0); if (s < 0) error (1, 0, "cannot create socket: %s", SOCK_STRERROR (SOCK_ERRNO)); port = get_cvs_port_number (root); hp = init_sockaddr (&sin, root->hostname, port); hname = xstrdup (hp->h_name); TRACE (TRACE_FUNCTION, "Connecting to %s(%s):%d", root->hostname, inet_ntoa (sin.sin_addr), port); if (connect (s, (struct sockaddr *) &sin, sizeof sin) < 0) error (1, 0, "connect to %s(%s):%d failed: %s", root->hostname, inet_ntoa (sin.sin_addr), port, SOCK_STRERROR (SOCK_ERRNO)); { const char *realm; struct sockaddr_in laddr; int laddrlen; KTEXT_ST ticket; MSG_DAT msg_data; CREDENTIALS cred; int status; realm = krb_realmofhost (hname); laddrlen = sizeof (laddr); if (getsockname (s, (struct sockaddr *) &laddr, &laddrlen) < 0) error (1, 0, "getsockname failed: %s", SOCK_STRERROR (SOCK_ERRNO)); /* We don't care about the checksum, and pass it as zero. */ status = krb_sendauth (KOPT_DO_MUTUAL, s, &ticket, "rcmd", hname, realm, (unsigned long) 0, &msg_data, &cred, sched, &laddr, &sin, "KCVSV1.0"); if (status != KSUCCESS) error (1, 0, "kerberos authentication failed: %s", krb_get_err_text (status)); memcpy (kblock, cred.session, sizeof (C_Block)); } close_on_exec (s); free (hname); /* Give caller the values it wants. */ make_bufs_from_fds (s, s, 0, root, to_server_p, from_server_p, 1); }
/* * Verify that common name resolves to peer. */ static int verify_peer(PGconn *conn) { struct hostent *h = NULL; struct sockaddr addr; struct sockaddr_in *sin; ACCEPT_TYPE_ARG3 len; char **s; unsigned long l; /* get the address on the other side of the socket */ len = sizeof(addr); if (getpeername(conn->sock, &addr, &len) == -1) { char sebuf[256]; printfPQExpBuffer(&conn->errorMessage, libpq_gettext("error querying socket: %s\n"), SOCK_STRERROR(SOCK_ERRNO, sebuf, sizeof(sebuf))); return -1; } /* weird, but legal case */ if (addr.sa_family == AF_UNIX) return 0; { struct hostent hpstr; char buf[BUFSIZ]; int herrno = 0; /* * Currently, pqGethostbyname() is used only on platforms that don't * have getaddrinfo(). If you enable this function, you should * convert the pqGethostbyname() function call to use getaddrinfo(). */ pqGethostbyname(conn->peer_cn, &hpstr, buf, sizeof(buf), &h, &herrno); } /* what do we know about the peer's common name? */ if (h == NULL) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("could not get information about host \"%s\": %s\n"), conn->peer_cn, hstrerror(h_errno)); return -1; } /* does the address match? */ switch (addr.sa_family) { case AF_INET: sin = (struct sockaddr_in *) & addr; for (s = h->h_addr_list; *s != NULL; s++) { if (!memcmp(&sin->sin_addr.s_addr, *s, h->h_length)) return 0; } break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("unsupported protocol\n")); return -1; } /* * the prior test should be definitive, but in practice it sometimes * fails. So we also check the aliases. */ for (s = h->h_aliases; *s != NULL; s++) { if (pg_strcasecmp(conn->peer_cn, *s) == 0) return 0; } /* generate protocol-aware error message */ switch (addr.sa_family) { case AF_INET: sin = (struct sockaddr_in *) & addr; l = ntohl(sin->sin_addr.s_addr); printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "server common name \"%s\" does not resolve to %ld.%ld.%ld.%ld\n"), conn->peer_cn, (l >> 24) % 0x100, (l >> 16) % 0x100, (l >> 8) % 0x100, l % 0x100); break; default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext( "server common name \"%s\" does not resolve to peer address\n"), conn->peer_cn); } return -1; }
/* * 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; }
/* * Attempt to negotiate SSL connection. */ static PostgresPollingStatusType open_client_SSL(PGconn *conn) { int r; r = SSL_connect(conn->ssl); if (r <= 0) { int err = SSL_get_error(conn->ssl, r); switch (err) { case SSL_ERROR_WANT_READ: return PGRES_POLLING_READING; case SSL_ERROR_WANT_WRITE: return PGRES_POLLING_WRITING; case SSL_ERROR_SYSCALL: { char sebuf[256]; if (r == -1) 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")); close_SSL(conn); return PGRES_POLLING_FAILED; } case SSL_ERROR_SSL: { /* * If there are problems with the local certificate files, * these will be detected by client_cert_cb() which is * called from SSL_connect(). We want to return that * error message and not the rather unhelpful error that * OpenSSL itself returns. So check to see if an error * message was already stored. */ if (conn->errorMessage.len == 0) { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("SSL error: %s\n"), err); SSLerrfree(err); } close_SSL(conn); return PGRES_POLLING_FAILED; } default: printfPQExpBuffer(&conn->errorMessage, libpq_gettext("unrecognized SSL error code: %d\n"), err); close_SSL(conn); return PGRES_POLLING_FAILED; } } /* check the certificate chain of the server */ #ifdef NOT_USED /* CLIENT CERTIFICATES NOT REQUIRED bjm 2002-09-26 */ /* * this eliminates simple man-in-the-middle attacks and simple * impersonations */ r = SSL_get_verify_result(conn->ssl); if (r != X509_V_OK) { printfPQExpBuffer(&conn->errorMessage, libpq_gettext("certificate could not be validated: %s\n"), X509_verify_cert_error_string(r)); close_SSL(conn); return PGRES_POLLING_FAILED; } #endif /* pull out server distinguished and common names */ conn->peer = SSL_get_peer_certificate(conn->ssl); if (conn->peer == NULL) { char *err = SSLerrmessage(); printfPQExpBuffer(&conn->errorMessage, libpq_gettext("certificate could not be obtained: %s\n"), err); SSLerrfree(err); close_SSL(conn); return PGRES_POLLING_FAILED; } X509_NAME_oneline(X509_get_subject_name(conn->peer), conn->peer_dn, sizeof(conn->peer_dn)); conn->peer_dn[sizeof(conn->peer_dn) - 1] = '\0'; X509_NAME_get_text_by_NID(X509_get_subject_name(conn->peer), NID_commonName, conn->peer_cn, SM_USER); conn->peer_cn[SM_USER] = '\0'; /* verify that the common name resolves to peer */ #ifdef NOT_USED /* CLIENT CERTIFICATES NOT REQUIRED bjm 2002-09-26 */ /* * this is necessary to eliminate man-in-the-middle attacks and * impersonations where the attacker somehow learned the server's private * key */ if (verify_peer(conn) == -1) { close_SSL(conn); return PGRES_POLLING_FAILED; } #endif /* SSL handshake is complete */ return PGRES_POLLING_OK; }
#ifdef HAVE_UNIX_SOCKETS if (IS_AF_UNIX(conn->raddr.addr.ss_family)) { char service[NI_MAXHOST]; pg_getnameinfo_all(&conn->raddr.addr, conn->raddr.salen, NULL, 0, service, sizeof(service), NI_NUMERICSERV); appendPQExpBuffer(&conn->errorMessage, libpq_gettext("could not connect to server: %s\n" "\tIs the server running locally and accepting\n" "\tconnections on Unix domain socket \"%s\"?\n"), SOCK_STRERROR(errorno, sebuf, sizeof(sebuf)), service); } else #endif /* HAVE_UNIX_SOCKETS */ { char host_addr[NI_MAXHOST]; const char *displayed_host; struct sockaddr_storage *addr = &conn->raddr.addr; /* * Optionally display the network address with the hostname. This is * useful to distinguish between IPv4 and IPv6 connections. */ if (conn->pghostaddr != NULL) strlcpy(host_addr, conn->pghostaddr, NI_MAXHOST); else if (addr->ss_family == AF_INET) {