⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fe-secure.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * fe-secure.c *	  functions related to setting up a secure connection to the backend. *	  Secure connections are expected to provide confidentiality, *	  message integrity and endpoint authentication. * * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/interfaces/libpq/fe-secure.c,v 1.73.2.1 2006/01/24 16:38:50 tgl Exp $ * * NOTES *	  [ Most of these notes are wrong/obsolete, but perhaps not all ] * *	  The client *requires* a valid server certificate.  Since *	  SSH tunnels provide anonymous confidentiality, the presumption *	  is that sites that want endpoint authentication will use the *	  direct SSL support, while sites that are comfortable with *	  anonymous connections will use SSH tunnels. * *	  This code verifies the server certificate, to detect simple *	  "man-in-the-middle" and "impersonation" attacks.	The *	  server certificate, or better yet the CA certificate used *	  to sign the server certificate, should be present in the *	  "~/.postgresql/root.crt" file.  If this file isn't *	  readable, or the server certificate can't be validated, *	  pqsecure_open_client() will return an error code. * *	  Additionally, the server certificate's "common name" must *	  resolve to the other end of the socket.  This makes it *	  substantially harder to pull off a "man-in-the-middle" or *	  "impersonation" attack even if the server's private key *	  has been stolen.	This check limits acceptable network *	  layers to Unix sockets (weird, but legal), TCPv4 and TCPv6. * *	  Unfortunately neither the current front- or back-end handle *	  failure gracefully, resulting in the backend hiccupping. *	  This points out problems in each (the frontend shouldn't even *	  try to do SSL if pqsecure_initialize() fails, and the backend *	  shouldn't crash/recover if an SSH negotiation fails.  The *	  backend definitely needs to be fixed, to prevent a "denial *	  of service" attack, but I don't know enough about how the *	  backend works (especially that pre-SSL negotiation) to identify *	  a fix. * *	  ... * *	  Unlike the server's static private key, the client's *	  static private key (~/.postgresql/postgresql.key) *	  should normally be stored encrypted.	However we still *	  support EPH since it's useful for other reasons. * *	  ... * *	  Client certificates are supported, if the server requests *	  or requires them.  Client certificates can be used for *	  authentication, to prevent sessions from being hijacked, *	  or to allow "road warriors" to access the database while *	  keeping it closed to everyone else. * *	  The user's certificate and private key are located in *		~/.postgresql/postgresql.crt *	  and *		~/.postgresql/postgresql.key *	  respectively. * *	  ... * *	  We don't provide informational callbacks here (like *	  info_cb() in be-secure.c), since there's mechanism to *	  display that information to the client. * *------------------------------------------------------------------------- */#include "postgres_fe.h"#include <signal.h>#include <fcntl.h>#include <ctype.h>#include "libpq-fe.h"#include "libpq-int.h"#include "fe-auth.h"#include "pqsignal.h"#ifdef WIN32#include "win32.h"#else#include <sys/socket.h>#include <unistd.h>#include <netdb.h>#include <netinet/in.h>#ifdef HAVE_NETINET_TCP_H#include <netinet/tcp.h>#endif#include <arpa/inet.h>#endif#include <sys/stat.h>#ifdef ENABLE_THREAD_SAFETY#ifdef WIN32#include "pthread-win32.h"#else#include <pthread.h>#endif#endif#ifndef HAVE_STRDUP#include "strdup.h"#endif#ifdef USE_SSL#include <openssl/ssl.h>#include <openssl/dh.h>#endif   /* USE_SSL */#ifdef USE_SSL#ifndef WIN32#define USERCERTFILE	".postgresql/postgresql.crt"#define USERKEYFILE		".postgresql/postgresql.key"#define ROOTCERTFILE	".postgresql/root.crt"#define DHFILEPATTERN	"%s/.postgresql/dh%d.pem"#else/* On Windows, the "home" directory is already PostgreSQL-specific */#define USERCERTFILE	"postgresql.crt"#define USERKEYFILE		"postgresql.key"#define ROOTCERTFILE	"root.crt"#define DHFILEPATTERN	"%s/dh%d.pem"#endif#ifdef NOT_USEDstatic int	verify_peer(PGconn *);#endifstatic int	verify_cb(int ok, X509_STORE_CTX *ctx);static DH  *load_dh_file(int keylength);static DH  *load_dh_buffer(const char *, size_t);static DH  *tmp_dh_cb(SSL *s, int is_export, int keylength);static int	client_cert_cb(SSL *, X509 **, EVP_PKEY **);static int	init_ssl_system(PGconn *conn);static int	initialize_SSL(PGconn *);static void destroy_SSL(void);static PostgresPollingStatusType open_client_SSL(PGconn *);static void close_SSL(PGconn *);static char *SSLerrmessage(void);static void SSLerrfree(char *buf);#endif#ifdef USE_SSLstatic bool pq_initssllib = true;static SSL_CTX *SSL_context = NULL;#endif/* ------------------------------------------------------------ *//*						 Hardcoded values						*//* ------------------------------------------------------------ *//* *	Hardcoded DH parameters, used in empheral DH keying. *	As discussed above, EDH protects the confidentiality of *	sessions even if the static private key is compromised, *	so we are *highly* motivated to ensure that we can use *	EDH even if the user... or an attacker... deletes the *	~/.postgresql/dh*.pem files. * *	It's not critical that users have EPH keys, but it doesn't *	hurt and if it's missing someone will demand it, so.... */#ifdef USE_SSLstatic const char file_dh512[] ="-----BEGIN DH PARAMETERS-----\n\MEYCQQD1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6ypUM2Zafq9AKUJsCRtMIPWak\n\XUGfnHy9iUsiGSa6q6Jew1XpKgVfAgEC\n\-----END DH PARAMETERS-----\n";static const char file_dh1024[] ="-----BEGIN DH PARAMETERS-----\n\MIGHAoGBAPSI/VhOSdvNILSd5JEHNmszbDgNRR0PfIizHHxbLY7288kjwEPwpVsY\n\jY67VYy4XTjTNP18F1dDox0YbN4zISy1Kv884bEpQBgRjXyEpwpy1obEAxnIByl6\n\ypUM2Zafq9AKUJsCRtMIPWakXUGfnHy9iUsiGSa6q6Jew1XpL3jHAgEC\n\-----END DH PARAMETERS-----\n";static const char file_dh2048[] ="-----BEGIN DH PARAMETERS-----\n\MIIBCAKCAQEA9kJXtwh/CBdyorrWqULzBej5UxE5T7bxbrlLOCDaAadWoxTpj0BV\n\89AHxstDqZSt90xkhkn4DIO9ZekX1KHTUPj1WV/cdlJPPT2N286Z4VeSWc39uK50\n\T8X8dryDxUcwYc58yWb/Ffm7/ZFexwGq01uejaClcjrUGvC/RgBYK+X0iP1YTknb\n\zSC0neSRBzZrM2w4DUUdD3yIsxx8Wy2O9vPJI8BD8KVbGI2Ou1WMuF040zT9fBdX\n\Q6MdGGzeMyEstSr/POGxKUAYEY18hKcKctaGxAMZyAcpesqVDNmWn6vQClCbAkbT\n\CD1mpF1Bn5x8vYlLIhkmuquiXsNV6TILOwIBAg==\n\-----END DH PARAMETERS-----\n";static const char file_dh4096[] ="-----BEGIN DH PARAMETERS-----\n\MIICCAKCAgEA+hRyUsFN4VpJ1O8JLcCo/VWr19k3BCgJ4uk+d+KhehjdRqNDNyOQ\n\l/MOyQNQfWXPeGKmOmIig6Ev/nm6Nf9Z2B1h3R4hExf+zTiHnvVPeRBhjdQi81rt\n\Xeoh6TNrSBIKIHfUJWBh3va0TxxjQIs6IZOLeVNRLMqzeylWqMf49HsIXqbcokUS\n\Vt1BkvLdW48j8PPv5DsKRN3tloTxqDJGo9tKvj1Fuk74A+Xda1kNhB7KFlqMyN98\n\VETEJ6c7KpfOo30mnK30wqw3S8OtaIR/maYX72tGOno2ehFDkq3pnPtEbD2CScxc\n\alJC+EL7RPk5c/tgeTvCngvc1KZn92Y//EI7G9tPZtylj2b56sHtMftIoYJ9+ODM\n\sccD5Piz/rejE3Ome8EOOceUSCYAhXn8b3qvxVI1ddd1pED6FHRhFvLrZxFvBEM9\n\ERRMp5QqOaHJkM+Dxv8Cj6MqrCbfC4u+ZErxodzuusgDgvZiLF22uxMZbobFWyte\n\OvOzKGtwcTqO/1wV5gKkzu1ZVswVUQd5Gg8lJicwqRWyyNRczDDoG9jVDxmogKTH\n\AaqLulO7R8Ifa1SwF2DteSGVtgWEN8gDpN3RBmmPTDngyF2DHb5qmpnznwtFKdTL\n\KWbuHn491xNO25CQWMtem80uKw+pTnisBRF/454n1Jnhub144YRBoN8CAQI=\n\-----END DH PARAMETERS-----\n";#endif/* ------------------------------------------------------------ *//*			 Procedures common to all secure sessions			*//* ------------------------------------------------------------ *//* *	Exported function to allow application to tell us it's already *	initialized OpenSSL. */voidPQinitSSL(int do_init){#ifdef USE_SSL	pq_initssllib = do_init;#endif}/* *	Initialize global context */intpqsecure_initialize(PGconn *conn){	int			r = 0;#ifdef USE_SSL	r = initialize_SSL(conn);#endif	return r;}/* *	Destroy global context */voidpqsecure_destroy(void){#ifdef USE_SSL	destroy_SSL();#endif}/* *	Attempt to negotiate secure session. */PostgresPollingStatusTypepqsecure_open_client(PGconn *conn){#ifdef USE_SSL	/* First time through? */	if (conn->ssl == NULL)	{		if (!(conn->ssl = SSL_new(SSL_context)) ||			!SSL_set_app_data(conn->ssl, conn) ||			!SSL_set_fd(conn->ssl, conn->sock))		{			char	   *err = SSLerrmessage();			printfPQExpBuffer(&conn->errorMessage,				   libpq_gettext("could not establish SSL connection: %s\n"),							  err);			SSLerrfree(err);			close_SSL(conn);			return PGRES_POLLING_FAILED;		}		/*		 * Initialize errorMessage to empty.  This allows open_client_SSL() to		 * detect whether client_cert_cb() has stored a message.		 */		resetPQExpBuffer(&conn->errorMessage);	}	/* Begin or continue the actual handshake */	return open_client_SSL(conn);#else	/* shouldn't get here */	return PGRES_POLLING_FAILED;#endif}/* *	Close secure session. */voidpqsecure_close(PGconn *conn){#ifdef USE_SSL	if (conn->ssl)		close_SSL(conn);#endif}/* *	Read data from a secure connection. */ssize_tpqsecure_read(PGconn *conn, void *ptr, size_t len){	ssize_t		n;#ifdef USE_SSL	if (conn->ssl)	{		int			err;rloop:		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)						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 = recv(conn->sock, ptr, len, 0);	return n;}/* *	Write data to a secure connection. */ssize_tpqsecure_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

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -