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

📄 tls.c

📁 samba最新软件
💻 C
📖 第 1 页 / 共 2 页
字号:
/*    Unix SMB/CIFS implementation.   transport layer security handling code   Copyright (C) Andrew Tridgell 2004-2005   Copyright (C) Stefan Metzmacher 2004   Copyright (C) Andrew Bartlett 2006    This program is free software; you can redistribute it and/or modify   it under the terms of the GNU General Public License as published by   the Free Software Foundation; either version 3 of the License, or   (at your option) any later version.      This program is distributed in the hope that it will be useful,   but WITHOUT ANY WARRANTY; without even the implied warranty of   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   GNU General Public License for more details.      You should have received a copy of the GNU General Public License   along with this program.  If not, see <http://www.gnu.org/licenses/>.*/#include "includes.h"#include "lib/events/events.h"#include "lib/socket/socket.h"#include "lib/tls/tls.h"#include "param/param.h"#if ENABLE_GNUTLS#include "gnutls/gnutls.h"#define DH_BITS 1024#if defined(HAVE_GNUTLS_DATUM) && !defined(HAVE_GNUTLS_DATUM_T)typedef gnutls_datum gnutls_datum_t;#endif/* hold persistent tls data */struct tls_params {	gnutls_certificate_credentials x509_cred;	gnutls_dh_params dh_params;	bool tls_enabled;};#endif/* hold per connection tls data */struct tls_context {	struct socket_context *socket;	struct fd_event *fde;	bool tls_enabled;#if ENABLE_GNUTLS	gnutls_session session;	bool done_handshake;	bool have_first_byte;	uint8_t first_byte;	bool tls_detect;	const char *plain_chars;	bool output_pending;	gnutls_certificate_credentials xcred;	bool interrupted;#endif};bool tls_enabled(struct socket_context *sock){	struct tls_context *tls;	if (!sock) {		return false;	}	if (strcmp(sock->backend_name, "tls") != 0) {		return false;	}	tls = talloc_get_type(sock->private_data, struct tls_context);	if (!tls) {		return false;	}	return tls->tls_enabled;}#if ENABLE_GNUTLSstatic const struct socket_ops tls_socket_ops;static NTSTATUS tls_socket_init(struct socket_context *sock){	switch (sock->type) {	case SOCKET_TYPE_STREAM:		break;	default:		return NT_STATUS_INVALID_PARAMETER;	}	sock->backend_name = "tls";	return NT_STATUS_OK;}#define TLSCHECK(call) do { \	ret = call; \	if (ret < 0) { \		DEBUG(0,("TLS %s - %s\n", #call, gnutls_strerror(ret))); \		goto failed; \	} \} while (0)/*  callback for reading from a socket*/static ssize_t tls_pull(gnutls_transport_ptr ptr, void *buf, size_t size){	struct tls_context *tls = talloc_get_type(ptr, struct tls_context);	NTSTATUS status;	size_t nread;		if (tls->have_first_byte) {		*(uint8_t *)buf = tls->first_byte;		tls->have_first_byte = false;		return 1;	}	status = socket_recv(tls->socket, buf, size, &nread);	if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) {		return 0;	}	if (NT_STATUS_IS_ERR(status)) {		EVENT_FD_NOT_READABLE(tls->fde);		EVENT_FD_NOT_WRITEABLE(tls->fde);		errno = EBADF;		return -1;	}	if (!NT_STATUS_IS_OK(status)) {		EVENT_FD_READABLE(tls->fde);		errno = EAGAIN;		return -1;	}	if (tls->output_pending) {		EVENT_FD_WRITEABLE(tls->fde);	}	if (size != nread) {		EVENT_FD_READABLE(tls->fde);	}	return nread;}/*  callback for writing to a socket*/static ssize_t tls_push(gnutls_transport_ptr ptr, const void *buf, size_t size){	struct tls_context *tls = talloc_get_type(ptr, struct tls_context);	NTSTATUS status;	size_t nwritten;	DATA_BLOB b;	if (!tls->tls_enabled) {		return size;	}	b.data = discard_const(buf);	b.length = size;	status = socket_send(tls->socket, &b, &nwritten);	if (NT_STATUS_EQUAL(status, STATUS_MORE_ENTRIES)) {		errno = EAGAIN;		return -1;	}	if (!NT_STATUS_IS_OK(status)) {		EVENT_FD_WRITEABLE(tls->fde);		return -1;	}	if (size != nwritten) {		EVENT_FD_WRITEABLE(tls->fde);	}	return nwritten;}/*  destroy a tls session */static int tls_destructor(struct tls_context *tls){	int ret;	ret = gnutls_bye(tls->session, GNUTLS_SHUT_WR);	if (ret < 0) {		DEBUG(0,("TLS gnutls_bye failed - %s\n", gnutls_strerror(ret)));	}	return 0;}/*  possibly continue the handshake process*/static NTSTATUS tls_handshake(struct tls_context *tls){	int ret;	if (tls->done_handshake) {		return NT_STATUS_OK;	}		ret = gnutls_handshake(tls->session);	if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {		if (gnutls_record_get_direction(tls->session) == 1) {			EVENT_FD_WRITEABLE(tls->fde);		}		return STATUS_MORE_ENTRIES;	}	if (ret < 0) {		DEBUG(0,("TLS gnutls_handshake failed - %s\n", gnutls_strerror(ret)));		return NT_STATUS_UNEXPECTED_NETWORK_ERROR;	}	tls->done_handshake = true;	return NT_STATUS_OK;}/*  possibly continue an interrupted operation*/static NTSTATUS tls_interrupted(struct tls_context *tls){	int ret;	if (!tls->interrupted) {		return NT_STATUS_OK;	}	if (gnutls_record_get_direction(tls->session) == 1) {		ret = gnutls_record_send(tls->session, NULL, 0);	} else {		ret = gnutls_record_recv(tls->session, NULL, 0);	}	if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {		return STATUS_MORE_ENTRIES;	}	tls->interrupted = false;	return NT_STATUS_OK;}/*  see how many bytes are pending on the connection*/static NTSTATUS tls_socket_pending(struct socket_context *sock, size_t *npending){	struct tls_context *tls = talloc_get_type(sock->private_data, struct tls_context);	if (!tls->tls_enabled || tls->tls_detect) {		return socket_pending(tls->socket, npending);	}	*npending = gnutls_record_check_pending(tls->session);	if (*npending == 0) {		NTSTATUS status = socket_pending(tls->socket, npending);		if (*npending == 0) {			/* seems to be a gnutls bug */			(*npending) = 100;		}		return status;	}	return NT_STATUS_OK;}/*  receive data either by tls or normal socket_recv*/static NTSTATUS tls_socket_recv(struct socket_context *sock, void *buf, 				size_t wantlen, size_t *nread){	int ret;	NTSTATUS status;	struct tls_context *tls = talloc_get_type(sock->private_data, struct tls_context);	if (tls->tls_enabled && tls->tls_detect) {		status = socket_recv(tls->socket, &tls->first_byte, 1, nread);		NT_STATUS_NOT_OK_RETURN(status);		if (*nread == 0) return NT_STATUS_OK;		tls->tls_detect = false;		/* look for the first byte of a valid HTTP operation */		if (strchr(tls->plain_chars, tls->first_byte)) {			/* not a tls link */			tls->tls_enabled = false;			*(uint8_t *)buf = tls->first_byte;			return NT_STATUS_OK;		}		tls->have_first_byte = true;	}	if (!tls->tls_enabled) {		return socket_recv(tls->socket, buf, wantlen, nread);	}	status = tls_handshake(tls);	NT_STATUS_NOT_OK_RETURN(status);	status = tls_interrupted(tls);	NT_STATUS_NOT_OK_RETURN(status);	ret = gnutls_record_recv(tls->session, buf, wantlen);	if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {		if (gnutls_record_get_direction(tls->session) == 1) {			EVENT_FD_WRITEABLE(tls->fde);		}		tls->interrupted = true;		return STATUS_MORE_ENTRIES;	}	if (ret < 0) {		return NT_STATUS_UNEXPECTED_NETWORK_ERROR;	}	*nread = ret;	return NT_STATUS_OK;}/*  send data either by tls or normal socket_recv*/static NTSTATUS tls_socket_send(struct socket_context *sock, 				const DATA_BLOB *blob, size_t *sendlen){	NTSTATUS status;	int ret;	struct tls_context *tls = talloc_get_type(sock->private_data, struct tls_context);	if (!tls->tls_enabled) {		return socket_send(tls->socket, blob, sendlen);	}	status = tls_handshake(tls);	NT_STATUS_NOT_OK_RETURN(status);	status = tls_interrupted(tls);	NT_STATUS_NOT_OK_RETURN(status);	ret = gnutls_record_send(tls->session, blob->data, blob->length);	if (ret == GNUTLS_E_INTERRUPTED || ret == GNUTLS_E_AGAIN) {		if (gnutls_record_get_direction(tls->session) == 1) {			EVENT_FD_WRITEABLE(tls->fde);		}		tls->interrupted = true;		return STATUS_MORE_ENTRIES;	}	if (ret < 0) {		DEBUG(0,("gnutls_record_send of %d failed - %s\n", (int)blob->length, gnutls_strerror(ret)));		return NT_STATUS_UNEXPECTED_NETWORK_ERROR;	}	*sendlen = ret;

⌨️ 快捷键说明

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