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

📄 fe-secure.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
	 * shouldn't be cast to unsigned long, but CRYPTO_set_id_callback requires	 * it, so we have to do it.	 */	return (unsigned long) pthread_self();}static pthread_mutex_t *pq_lockarray;static voidpq_lockingcallback(int mode, int n, const char *file, int line){	if (mode & CRYPTO_LOCK)		pthread_mutex_lock(&pq_lockarray[n]);	else		pthread_mutex_unlock(&pq_lockarray[n]);}#endif   /* ENABLE_THREAD_SAFETY */static intinit_ssl_system(PGconn *conn){#ifdef ENABLE_THREAD_SAFETY#ifndef WIN32	static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;#else	static pthread_mutex_t init_mutex = NULL;	static long mutex_initlock = 0;	if (init_mutex == NULL)	{		while (InterlockedExchange(&mutex_initlock, 1) == 1)			 /* loop, another thread own the lock */ ;		if (init_mutex == NULL)			pthread_mutex_init(&init_mutex, NULL);		InterlockedExchange(&mutex_initlock, 0);	}#endif	pthread_mutex_lock(&init_mutex);	if (pq_initssllib && pq_lockarray == NULL)	{		int			i;		CRYPTO_set_id_callback(pq_threadidcallback);		pq_lockarray = malloc(sizeof(pthread_mutex_t) * CRYPTO_num_locks());		if (!pq_lockarray)		{			pthread_mutex_unlock(&init_mutex);			return -1;		}		for (i = 0; i < CRYPTO_num_locks(); i++)			pthread_mutex_init(&pq_lockarray[i], NULL);		CRYPTO_set_locking_callback(pq_lockingcallback);	}#endif	if (!SSL_context)	{		if (pq_initssllib)		{			SSL_library_init();			SSL_load_error_strings();		}		SSL_context = SSL_CTX_new(TLSv1_method());		if (!SSL_context)		{			char	   *err = SSLerrmessage();			printfPQExpBuffer(&conn->errorMessage,						 libpq_gettext("could not create SSL context: %s\n"),							  err);			SSLerrfree(err);#ifdef ENABLE_THREAD_SAFETY			pthread_mutex_unlock(&init_mutex);#endif			return -1;		}	}#ifdef ENABLE_THREAD_SAFETY	pthread_mutex_unlock(&init_mutex);#endif	return 0;}/* *	Initialize global SSL context. */static intinitialize_SSL(PGconn *conn){	struct stat buf;	char		homedir[MAXPGPATH];	char		fnbuf[MAXPGPATH];	if (init_ssl_system(conn))		return -1;	/* Set up to verify server cert, if root.crt is present */	if (pqGetHomeDirectory(homedir, sizeof(homedir)))	{		snprintf(fnbuf, sizeof(fnbuf), "%s/%s", homedir, ROOTCERTFILE);		if (stat(fnbuf, &buf) == 0)		{			if (!SSL_CTX_load_verify_locations(SSL_context, fnbuf, NULL))			{				char	   *err = SSLerrmessage();				printfPQExpBuffer(&conn->errorMessage,								  libpq_gettext("could not read root certificate file \"%s\": %s\n"),								  fnbuf, err);				SSLerrfree(err);				return -1;			}			SSL_CTX_set_verify(SSL_context, SSL_VERIFY_PEER, verify_cb);		}	}	/* set up empheral DH keys */	SSL_CTX_set_tmp_dh_callback(SSL_context, tmp_dh_cb);	SSL_CTX_set_options(SSL_context, SSL_OP_SINGLE_DH_USE);	/* set up mechanism to provide client certificate, if available */	SSL_CTX_set_client_cert_cb(SSL_context, client_cert_cb);	return 0;}/* *	Destroy global SSL context. */static voiddestroy_SSL(void){	if (SSL_context)	{		SSL_CTX_free(SSL_context);		SSL_context = NULL;	}}/* *	Attempt to negotiate SSL connection. */static PostgresPollingStatusTypeopen_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;}/* *	Close SSL connection. */static voidclose_SSL(PGconn *conn){	if (conn->ssl)	{		SSL_shutdown(conn->ssl);		SSL_free(conn->ssl);		conn->ssl = NULL;	}	if (conn->peer)	{		X509_free(conn->peer);		conn->peer = NULL;	}}/* * Obtain reason string for last SSL error * * Some caution is needed here since ERR_reason_error_string will * return NULL if it doesn't recognize the error code.  We don't * want to return NULL ever. */static char ssl_nomem[] = "Out of memory allocating error description";#define SSL_ERR_LEN 128static char *SSLerrmessage(void){	unsigned long errcode;	const char *errreason;	char	   *errbuf;	errbuf = malloc(SSL_ERR_LEN);	if (!errbuf)		return ssl_nomem;	errcode = ERR_get_error();	if (errcode == 0)	{		strcpy(errbuf, "No SSL error reported");		return errbuf;	}	errreason = ERR_reason_error_string(errcode);	if (errreason != NULL)	{		strncpy(errbuf, errreason, SSL_ERR_LEN - 1);		errbuf[SSL_ERR_LEN - 1] = '\0';		return errbuf;	}	snprintf(errbuf, SSL_ERR_LEN, "SSL error code %lu", errcode);	return errbuf;}static voidSSLerrfree(char *buf){	if (buf != ssl_nomem)		free(buf);}/* *	Return pointer to SSL object. */SSL *PQgetssl(PGconn *conn){	if (!conn)		return NULL;	return conn->ssl;}#else							/* !USE_SSL */void *PQgetssl(PGconn *conn){	return NULL;}#endif   /* USE_SSL */#if defined(ENABLE_THREAD_SAFETY) && !defined(WIN32)/* *	Block SIGPIPE for this thread.	This prevents send()/write() from exiting *	the application. */intpq_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;}/* *	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. */voidpq_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);}#endif   /* ENABLE_THREAD_SAFETY */

⌨️ 快捷键说明

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