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

📄 be-secure.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 2 页
字号:
	ret = 1;err:	return (ret);}/* *	Load precomputed DH parameters. * *	To prevent "downgrade" attacks, we perform a number of checks *	to verify that the DBA-generated DH parameters file contains *	what we expect it to contain. */static DH  *load_dh_file(int keylength){	FILE	   *fp;	char		fnbuf[MAXPGPATH];	DH		   *dh = NULL;	int			codes;	/* attempt to open file.  It's not an error if it doesn't exist. */	snprintf(fnbuf, sizeof(fnbuf), "dh%d.pem", keylength);	if ((fp = fopen(fnbuf, "r")) == NULL)		return NULL;/*	flock(fileno(fp), LOCK_SH); */	dh = PEM_read_DHparams(fp, NULL, NULL, NULL);/*	flock(fileno(fp), LOCK_UN); */	fclose(fp);	/* is the prime the correct size? */	if (dh != NULL && 8 * DH_size(dh) < keylength)	{		elog(LOG, "DH errors (%s): %d bits expected, %d bits found",			 fnbuf, keylength, 8 * DH_size(dh));		dh = NULL;	}	/* make sure the DH parameters are usable */	if (dh != NULL)	{		if (DH_check(dh, &codes) == 0)		{			elog(LOG, "DH_check error (%s): %s", fnbuf, SSLerrmessage());			return NULL;		}		if (codes & DH_CHECK_P_NOT_PRIME)		{			elog(LOG, "DH error (%s): p is not prime", fnbuf);			return NULL;		}		if ((codes & DH_NOT_SUITABLE_GENERATOR) &&			(codes & DH_CHECK_P_NOT_SAFE_PRIME))		{			elog(LOG,				 "DH error (%s): neither suitable generator or safe prime",				 fnbuf);			return NULL;		}	}	return dh;}/* *	Load hardcoded DH parameters. * *	To prevent problems if the DH parameters files don't even *	exist, we can load DH parameters hardcoded into this file. */static DH  *load_dh_buffer(const char *buffer, size_t len){	BIO		   *bio;	DH		   *dh = NULL;	bio = BIO_new_mem_buf((char *) buffer, len);	if (bio == NULL)		return NULL;	dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);	if (dh == NULL)		ereport(DEBUG2,				(errmsg_internal("DH load buffer: %s",								 SSLerrmessage())));	BIO_free(bio);	return dh;}/* *	Generate an empheral DH key.  Because this can take a long *	time to compute, we can use precomputed parameters of the *	common key sizes. * *	Since few sites will bother to precompute these parameter *	files, we also provide a fallback to the parameters provided *	by the OpenSSL project. * *	These values can be static (once loaded or computed) since *	the OpenSSL library can efficiently generate random keys from *	the information provided. */static DH  *tmp_dh_cb(SSL *s, int is_export, int keylength){	DH		   *r = NULL;	static DH  *dh = NULL;	static DH  *dh512 = NULL;	static DH  *dh1024 = NULL;	static DH  *dh2048 = NULL;	static DH  *dh4096 = NULL;	switch (keylength)	{		case 512:			if (dh512 == NULL)				dh512 = load_dh_file(keylength);			if (dh512 == NULL)				dh512 = load_dh_buffer(file_dh512, sizeof file_dh512);			r = dh512;			break;		case 1024:			if (dh1024 == NULL)				dh1024 = load_dh_file(keylength);			if (dh1024 == NULL)				dh1024 = load_dh_buffer(file_dh1024, sizeof file_dh1024);			r = dh1024;			break;		case 2048:			if (dh2048 == NULL)				dh2048 = load_dh_file(keylength);			if (dh2048 == NULL)				dh2048 = load_dh_buffer(file_dh2048, sizeof file_dh2048);			r = dh2048;			break;		case 4096:			if (dh4096 == NULL)				dh4096 = load_dh_file(keylength);			if (dh4096 == NULL)				dh4096 = load_dh_buffer(file_dh4096, sizeof file_dh4096);			r = dh4096;			break;		default:			if (dh == NULL)				dh = load_dh_file(keylength);			r = dh;	}	/* this may take a long time, but it may be necessary... */	if (r == NULL || 8 * DH_size(r) < keylength)	{		ereport(DEBUG2,				(errmsg_internal("DH: generating parameters (%d bits)....",								 keylength)));		r = DH_generate_parameters(keylength, DH_GENERATOR_2, NULL, NULL);	}	return r;}/* *	Certificate verification callback * *	This callback allows us to log intermediate problems during *	verification, but for now we'll see if the final error message *	contains enough information. * *	This callback also allows us to override the default acceptance *	criteria (e.g., accepting self-signed or expired certs), but *	for now we accept the default checks. */static intverify_cb(int ok, X509_STORE_CTX *ctx){	return ok;}/* *	This callback is used to copy SSL information messages *	into the PostgreSQL log. */static voidinfo_cb(const SSL *ssl, int type, int args){	switch (type)	{		case SSL_CB_HANDSHAKE_START:			ereport(DEBUG4,					(errmsg_internal("SSL: handshake start")));			break;		case SSL_CB_HANDSHAKE_DONE:			ereport(DEBUG4,					(errmsg_internal("SSL: handshake done")));			break;		case SSL_CB_ACCEPT_LOOP:			ereport(DEBUG4,					(errmsg_internal("SSL: accept loop")));			break;		case SSL_CB_ACCEPT_EXIT:			ereport(DEBUG4,					(errmsg_internal("SSL: accept exit (%d)", args)));			break;		case SSL_CB_CONNECT_LOOP:			ereport(DEBUG4,					(errmsg_internal("SSL: connect loop")));			break;		case SSL_CB_CONNECT_EXIT:			ereport(DEBUG4,					(errmsg_internal("SSL: connect exit (%d)", args)));			break;		case SSL_CB_READ_ALERT:			ereport(DEBUG4,					(errmsg_internal("SSL: read alert (0x%04x)", args)));			break;		case SSL_CB_WRITE_ALERT:			ereport(DEBUG4,					(errmsg_internal("SSL: write alert (0x%04x)", args)));			break;	}}/* *	Initialize global SSL context. */static intinitialize_SSL(void){	struct stat buf;	if (!SSL_context)	{		SSL_library_init();		SSL_load_error_strings();		SSL_context = SSL_CTX_new(SSLv23_method());		if (!SSL_context)			ereport(FATAL,					(errmsg("could not create SSL context: %s",							SSLerrmessage())));		/*		 * Load and verify certificate and private key		 */		if (!SSL_CTX_use_certificate_file(SSL_context,										  SERVER_CERT_FILE,										  SSL_FILETYPE_PEM))			ereport(FATAL,					(errcode(ERRCODE_CONFIG_FILE_ERROR),				  errmsg("could not load server certificate file \"%s\": %s",						 SERVER_CERT_FILE, SSLerrmessage())));		if (stat(SERVER_PRIVATE_KEY_FILE, &buf) == -1)			ereport(FATAL,					(errcode_for_file_access(),					 errmsg("could not access private key file \"%s\": %m",							SERVER_PRIVATE_KEY_FILE)));		/*		 * Require no public access to key file.		 *		 * XXX temporarily suppress check when on Windows, because there may		 * not be proper support for Unix-y file permissions.  Need to think		 * of a reasonable check to apply on Windows.  (See also the data		 * directory permission check in postmaster.c)		 */#if !defined(WIN32) && !defined(__CYGWIN__)		if (!S_ISREG(buf.st_mode) || (buf.st_mode & (S_IRWXG | S_IRWXO)) ||			buf.st_uid != geteuid())			ereport(FATAL,					(errcode(ERRCODE_CONFIG_FILE_ERROR),					 errmsg("unsafe permissions on private key file \"%s\"",							SERVER_PRIVATE_KEY_FILE),					 errdetail("File must be owned by the database user and must have no permissions for \"group\" or \"other\".")));#endif		if (!SSL_CTX_use_PrivateKey_file(SSL_context,										 SERVER_PRIVATE_KEY_FILE,										 SSL_FILETYPE_PEM))			ereport(FATAL,					(errmsg("could not load private key file \"%s\": %s",							SERVER_PRIVATE_KEY_FILE, SSLerrmessage())));		if (!SSL_CTX_check_private_key(SSL_context))			ereport(FATAL,					(errmsg("check of private key failed: %s",							SSLerrmessage())));	}	/* 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 | SSL_OP_NO_SSLv2);	/* setup the allowed cipher list */	if (SSL_CTX_set_cipher_list(SSL_context, "ALL:!ADH:!LOW:!EXP:!MD5:@STRENGTH") != 1)		elog(FATAL, "could not set the cipher list (no valid ciphers available)");	/*	 * Require and check client certificates only if we have a root.crt file.	 */	if (!SSL_CTX_load_verify_locations(SSL_context, ROOT_CERT_FILE, NULL))	{		/* Not fatal - we do not require client certificates */		ereport(LOG,				(errmsg("could not load root certificate file \"%s\": %s",						ROOT_CERT_FILE, SSLerrmessage()),				 errdetail("Will not verify client certificates.")));	}	else	{		SSL_CTX_set_verify(SSL_context,						   (SSL_VERIFY_PEER |							SSL_VERIFY_FAIL_IF_NO_PEER_CERT |							SSL_VERIFY_CLIENT_ONCE),						   verify_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 intopen_server_SSL(Port *port){	int			r;	int			err;	Assert(!port->ssl);	Assert(!port->peer);	if (!(port->ssl = SSL_new(SSL_context)))	{		ereport(COMMERROR,				(errcode(ERRCODE_PROTOCOL_VIOLATION),				 errmsg("could not initialize SSL connection: %s",						SSLerrmessage())));		close_SSL(port);		return -1;	}	if (!my_SSL_set_fd(port->ssl, port->sock))	{		ereport(COMMERROR,				(errcode(ERRCODE_PROTOCOL_VIOLATION),				 errmsg("could not set SSL socket: %s",						SSLerrmessage())));		close_SSL(port);		return -1;	}aloop:	r = SSL_accept(port->ssl);	if (r <= 0)	{		err = SSL_get_error(port->ssl, r);		switch (err)		{			case SSL_ERROR_WANT_READ:			case SSL_ERROR_WANT_WRITE:#ifdef WIN32				pgwin32_waitforsinglesocket(SSL_get_fd(port->ssl),											(err == SSL_ERROR_WANT_READ) ?					   FD_READ | FD_CLOSE | FD_ACCEPT : FD_WRITE | FD_CLOSE);#endif				goto aloop;			case SSL_ERROR_SYSCALL:				if (r < 0)					ereport(COMMERROR,							(errcode_for_socket_access(),							 errmsg("could not accept SSL connection: %m")));				else					ereport(COMMERROR,							(errcode(ERRCODE_PROTOCOL_VIOLATION),					errmsg("could not accept SSL connection: EOF detected")));				break;			case SSL_ERROR_SSL:				ereport(COMMERROR,						(errcode(ERRCODE_PROTOCOL_VIOLATION),						 errmsg("could not accept SSL connection: %s",								SSLerrmessage())));				break;			case SSL_ERROR_ZERO_RETURN:				ereport(COMMERROR,						(errcode(ERRCODE_PROTOCOL_VIOLATION),				   errmsg("could not accept SSL connection: EOF detected")));				break;			default:				ereport(COMMERROR,						(errcode(ERRCODE_PROTOCOL_VIOLATION),						 errmsg("unrecognized SSL error code: %d",								err)));				break;		}		close_SSL(port);		return -1;	}	port->count = 0;	/* get client certificate, if available. */	port->peer = SSL_get_peer_certificate(port->ssl);	if (port->peer == NULL)	{		strncpy(port->peer_dn, "(anonymous)", sizeof(port->peer_dn));		strncpy(port->peer_cn, "(anonymous)", sizeof(port->peer_cn));	}	else	{		X509_NAME_oneline(X509_get_subject_name(port->peer),						  port->peer_dn, sizeof(port->peer_dn));		port->peer_dn[sizeof(port->peer_dn) - 1] = '\0';		X509_NAME_get_text_by_NID(X509_get_subject_name(port->peer),					   NID_commonName, port->peer_cn, sizeof(port->peer_cn));		port->peer_cn[sizeof(port->peer_cn) - 1] = '\0';	}	ereport(DEBUG2,			(errmsg("SSL connection from \"%s\"", port->peer_cn)));	/* set up debugging/info callback */	SSL_CTX_set_info_callback(SSL_context, info_cb);	return 0;}/* *	Close SSL connection. */static voidclose_SSL(Port *port){	if (port->ssl)	{		SSL_shutdown(port->ssl);		SSL_free(port->ssl);		port->ssl = NULL;	}	if (port->peer)	{		X509_free(port->peer);		port->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 const char *SSLerrmessage(void){	unsigned long errcode;	const char *errreason;	static char errbuf[32];	errcode = ERR_get_error();	if (errcode == 0)		return "No SSL error reported";	errreason = ERR_reason_error_string(errcode);	if (errreason != NULL)		return errreason;	snprintf(errbuf, sizeof(errbuf), "SSL error code %lu", errcode);	return errbuf;}#endif   /* USE_SSL */

⌨️ 快捷键说明

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