mirror of
https://github.com/samba-team/samba.git
synced 2025-01-03 01:18:10 +03:00
r15400: Move the TLS code behind the socket interface.
This reduces caller complexity, because the TLS code is now called
just like any other socket. (A new socket context is returned by the
tls_init_server and tls_init_client routines).
When TLS is not available, the original socket is returned.
Andrew Bartlett
(This used to be commit 09b2f30dfa
)
This commit is contained in:
parent
49994442bb
commit
742c110cd6
@ -46,10 +46,6 @@
|
|||||||
static void ldapsrv_terminate_connection(struct ldapsrv_connection *conn,
|
static void ldapsrv_terminate_connection(struct ldapsrv_connection *conn,
|
||||||
const char *reason)
|
const char *reason)
|
||||||
{
|
{
|
||||||
if (conn->tls) {
|
|
||||||
talloc_free(conn->tls);
|
|
||||||
conn->tls = NULL;
|
|
||||||
}
|
|
||||||
stream_terminate_connection(conn->connection, reason);
|
stream_terminate_connection(conn->connection, reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -430,13 +426,14 @@ static void ldapsrv_accept(struct stream_connection *c)
|
|||||||
port = socket_address->port;
|
port = socket_address->port;
|
||||||
talloc_free(socket_address);
|
talloc_free(socket_address);
|
||||||
|
|
||||||
conn->tls = tls_init_server(ldapsrv_service->tls_params, c->socket,
|
if (port == 636) {
|
||||||
c->event.fde, NULL, port != 389);
|
c->socket = tls_init_server(ldapsrv_service->tls_params, c->socket,
|
||||||
if (!conn->tls) {
|
c->event.fde, NULL);
|
||||||
ldapsrv_terminate_connection(conn, "ldapsrv_accept: tls_init_server() failed");
|
if (!c->socket) {
|
||||||
return;
|
ldapsrv_terminate_connection(conn, "ldapsrv_accept: tls_init_server() failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
conn->packet = packet_init(conn);
|
conn->packet = packet_init(conn);
|
||||||
if (conn->packet == NULL) {
|
if (conn->packet == NULL) {
|
||||||
ldapsrv_terminate_connection(conn, "out of memory");
|
ldapsrv_terminate_connection(conn, "out of memory");
|
||||||
@ -444,7 +441,7 @@ static void ldapsrv_accept(struct stream_connection *c)
|
|||||||
}
|
}
|
||||||
|
|
||||||
packet_set_private(conn->packet, conn);
|
packet_set_private(conn->packet, conn);
|
||||||
packet_set_tls(conn->packet, conn->tls);
|
packet_set_socket(conn->packet, c->socket);
|
||||||
packet_set_callback(conn->packet, ldapsrv_decode);
|
packet_set_callback(conn->packet, ldapsrv_decode);
|
||||||
packet_set_full_request(conn->packet, ldapsrv_complete_packet);
|
packet_set_full_request(conn->packet, ldapsrv_complete_packet);
|
||||||
packet_set_error_handler(conn->packet, ldapsrv_error_handler);
|
packet_set_error_handler(conn->packet, ldapsrv_error_handler);
|
||||||
|
@ -26,7 +26,6 @@ struct ldapsrv_connection {
|
|||||||
struct gensec_security *gensec;
|
struct gensec_security *gensec;
|
||||||
struct auth_session_info *session_info;
|
struct auth_session_info *session_info;
|
||||||
struct ldapsrv_service *service;
|
struct ldapsrv_service *service;
|
||||||
struct tls_context *tls;
|
|
||||||
struct cli_credentials *server_credentials;
|
struct cli_credentials *server_credentials;
|
||||||
struct ldb_context *ldb;
|
struct ldb_context *ldb;
|
||||||
|
|
||||||
|
@ -37,9 +37,9 @@ static int socket_destructor(void *ptr)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static NTSTATUS socket_create_with_ops(TALLOC_CTX *mem_ctx, const struct socket_ops *ops,
|
_PUBLIC_ NTSTATUS socket_create_with_ops(TALLOC_CTX *mem_ctx, const struct socket_ops *ops,
|
||||||
struct socket_context **new_sock,
|
struct socket_context **new_sock,
|
||||||
enum socket_type type, uint32_t flags)
|
enum socket_type type, uint32_t flags)
|
||||||
{
|
{
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
|
||||||
|
@ -117,6 +117,9 @@ struct socket_context {
|
|||||||
|
|
||||||
|
|
||||||
/* prototypes */
|
/* prototypes */
|
||||||
|
NTSTATUS socket_create_with_ops(TALLOC_CTX *mem_ctx, const struct socket_ops *ops,
|
||||||
|
struct socket_context **new_sock,
|
||||||
|
enum socket_type type, uint32_t flags);
|
||||||
NTSTATUS socket_create(const char *name, enum socket_type type,
|
NTSTATUS socket_create(const char *name, enum socket_type type,
|
||||||
struct socket_context **new_sock, uint32_t flags);
|
struct socket_context **new_sock, uint32_t flags);
|
||||||
NTSTATUS socket_connect(struct socket_context *sock,
|
NTSTATUS socket_connect(struct socket_context *sock,
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
#include "dlinklist.h"
|
#include "dlinklist.h"
|
||||||
#include "lib/events/events.h"
|
#include "lib/events/events.h"
|
||||||
#include "lib/socket/socket.h"
|
#include "lib/socket/socket.h"
|
||||||
#include "lib/tls/tls.h"
|
|
||||||
#include "lib/stream/packet.h"
|
#include "lib/stream/packet.h"
|
||||||
|
|
||||||
|
|
||||||
@ -37,7 +36,6 @@ struct packet_context {
|
|||||||
DATA_BLOB partial;
|
DATA_BLOB partial;
|
||||||
uint32_t num_read;
|
uint32_t num_read;
|
||||||
uint32_t initial_read;
|
uint32_t initial_read;
|
||||||
struct tls_context *tls;
|
|
||||||
struct socket_context *sock;
|
struct socket_context *sock;
|
||||||
struct event_context *ev;
|
struct event_context *ev;
|
||||||
size_t packet_size;
|
size_t packet_size;
|
||||||
@ -126,15 +124,7 @@ _PUBLIC_ void packet_set_full_request(struct packet_context *pc, packet_full_req
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
set a tls context to use. You must either set a tls_context or a socket_context
|
set a socket context to use. You must set a socket_context
|
||||||
*/
|
|
||||||
_PUBLIC_ void packet_set_tls(struct packet_context *pc, struct tls_context *tls)
|
|
||||||
{
|
|
||||||
pc->tls = tls;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
set a socket context to use. You must either set a tls_context or a socket_context
|
|
||||||
*/
|
*/
|
||||||
_PUBLIC_ void packet_set_socket(struct packet_context *pc, struct socket_context *sock)
|
_PUBLIC_ void packet_set_socket(struct packet_context *pc, struct socket_context *sock)
|
||||||
{
|
{
|
||||||
@ -194,7 +184,6 @@ _PUBLIC_ void packet_set_nofree(struct packet_context *pc)
|
|||||||
*/
|
*/
|
||||||
static void packet_error(struct packet_context *pc, NTSTATUS status)
|
static void packet_error(struct packet_context *pc, NTSTATUS status)
|
||||||
{
|
{
|
||||||
pc->tls = NULL;
|
|
||||||
pc->sock = NULL;
|
pc->sock = NULL;
|
||||||
if (pc->error_handler) {
|
if (pc->error_handler) {
|
||||||
pc->error_handler(pc->private, status);
|
pc->error_handler(pc->private, status);
|
||||||
@ -266,9 +255,7 @@ _PUBLIC_ void packet_recv(struct packet_context *pc)
|
|||||||
} else if (pc->initial_read != 0) {
|
} else if (pc->initial_read != 0) {
|
||||||
npending = pc->initial_read - pc->num_read;
|
npending = pc->initial_read - pc->num_read;
|
||||||
} else {
|
} else {
|
||||||
if (pc->tls) {
|
if (pc->sock) {
|
||||||
status = tls_socket_pending(pc->tls, &npending);
|
|
||||||
} else if (pc->sock) {
|
|
||||||
status = socket_pending(pc->sock, &npending);
|
status = socket_pending(pc->sock, &npending);
|
||||||
} else {
|
} else {
|
||||||
status = NT_STATUS_CONNECTION_DISCONNECTED;
|
status = NT_STATUS_CONNECTION_DISCONNECTED;
|
||||||
@ -293,13 +280,9 @@ _PUBLIC_ void packet_recv(struct packet_context *pc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pc->tls) {
|
status = socket_recv(pc->sock, pc->partial.data + pc->num_read,
|
||||||
status = tls_socket_recv(pc->tls, pc->partial.data + pc->num_read,
|
npending, &nread);
|
||||||
npending, &nread);
|
|
||||||
} else {
|
|
||||||
status = socket_recv(pc->sock, pc->partial.data + pc->num_read,
|
|
||||||
npending, &nread);
|
|
||||||
}
|
|
||||||
if (NT_STATUS_IS_ERR(status)) {
|
if (NT_STATUS_IS_ERR(status)) {
|
||||||
packet_error(pc, status);
|
packet_error(pc, status);
|
||||||
return;
|
return;
|
||||||
@ -452,11 +435,8 @@ _PUBLIC_ void packet_queue_run(struct packet_context *pc)
|
|||||||
DATA_BLOB blob = data_blob_const(el->blob.data + el->nsent,
|
DATA_BLOB blob = data_blob_const(el->blob.data + el->nsent,
|
||||||
el->blob.length - el->nsent);
|
el->blob.length - el->nsent);
|
||||||
|
|
||||||
if (pc->tls) {
|
status = socket_send(pc->sock, &blob, &nwritten);
|
||||||
status = tls_socket_send(pc->tls, &blob, &nwritten);
|
|
||||||
} else {
|
|
||||||
status = socket_send(pc->sock, &blob, &nwritten);
|
|
||||||
}
|
|
||||||
if (NT_STATUS_IS_ERR(status)) {
|
if (NT_STATUS_IS_ERR(status)) {
|
||||||
packet_error(pc, NT_STATUS_NET_WRITE_FAULT);
|
packet_error(pc, NT_STATUS_NET_WRITE_FAULT);
|
||||||
return;
|
return;
|
||||||
|
@ -21,8 +21,6 @@
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "lib/tls/tls.h"
|
|
||||||
|
|
||||||
typedef NTSTATUS (*packet_full_request_fn_t)(void *private,
|
typedef NTSTATUS (*packet_full_request_fn_t)(void *private,
|
||||||
DATA_BLOB blob, size_t *packet_size);
|
DATA_BLOB blob, size_t *packet_size);
|
||||||
typedef NTSTATUS (*packet_callback_fn_t)(void *private, DATA_BLOB blob);
|
typedef NTSTATUS (*packet_callback_fn_t)(void *private, DATA_BLOB blob);
|
||||||
@ -35,7 +33,6 @@ void packet_set_callback(struct packet_context *pc, packet_callback_fn_t callbac
|
|||||||
void packet_set_error_handler(struct packet_context *pc, packet_error_handler_fn_t handler);
|
void packet_set_error_handler(struct packet_context *pc, packet_error_handler_fn_t handler);
|
||||||
void packet_set_private(struct packet_context *pc, void *private);
|
void packet_set_private(struct packet_context *pc, void *private);
|
||||||
void packet_set_full_request(struct packet_context *pc, packet_full_request_fn_t callback);
|
void packet_set_full_request(struct packet_context *pc, packet_full_request_fn_t callback);
|
||||||
void packet_set_tls(struct packet_context *pc, struct tls_context *tls);
|
|
||||||
void packet_set_socket(struct packet_context *pc, struct socket_context *sock);
|
void packet_set_socket(struct packet_context *pc, struct socket_context *sock);
|
||||||
void packet_set_event_context(struct packet_context *pc, struct event_context *ev);
|
void packet_set_event_context(struct packet_context *pc, struct event_context *ev);
|
||||||
void packet_set_fde(struct packet_context *pc, struct fd_event *fde);
|
void packet_set_fde(struct packet_context *pc, struct fd_event *fde);
|
||||||
|
@ -3,8 +3,10 @@
|
|||||||
|
|
||||||
transport layer security handling code
|
transport layer security handling code
|
||||||
|
|
||||||
Copyright (C) Andrew Tridgell 2005
|
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
|
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
|
it under the terms of the GNU General Public License as published by
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
the Free Software Foundation; either version 2 of the License, or
|
||||||
@ -35,23 +37,61 @@ struct tls_params {
|
|||||||
gnutls_dh_params dh_params;
|
gnutls_dh_params dh_params;
|
||||||
BOOL tls_enabled;
|
BOOL tls_enabled;
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
/* hold per connection tls data */
|
/* hold per connection tls data */
|
||||||
struct tls_context {
|
struct tls_context {
|
||||||
struct socket_context *socket;
|
struct socket_context *socket;
|
||||||
struct fd_event *fde;
|
struct fd_event *fde;
|
||||||
|
BOOL tls_enabled;
|
||||||
|
#if HAVE_LIBGNUTLS
|
||||||
gnutls_session session;
|
gnutls_session session;
|
||||||
BOOL done_handshake;
|
BOOL done_handshake;
|
||||||
BOOL have_first_byte;
|
BOOL have_first_byte;
|
||||||
uint8_t first_byte;
|
uint8_t first_byte;
|
||||||
BOOL tls_enabled;
|
|
||||||
BOOL tls_detect;
|
BOOL tls_detect;
|
||||||
const char *plain_chars;
|
const char *plain_chars;
|
||||||
BOOL output_pending;
|
BOOL output_pending;
|
||||||
gnutls_certificate_credentials xcred;
|
gnutls_certificate_credentials xcred;
|
||||||
BOOL interrupted;
|
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 HAVE_LIBGNUTLS
|
||||||
|
|
||||||
|
static 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 { \
|
#define TLSCHECK(call) do { \
|
||||||
ret = call; \
|
ret = call; \
|
||||||
if (ret < 0) { \
|
if (ret < 0) { \
|
||||||
@ -61,7 +101,6 @@ struct tls_context {
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
callback for reading from a socket
|
callback for reading from a socket
|
||||||
*/
|
*/
|
||||||
@ -199,8 +238,9 @@ static NTSTATUS tls_interrupted(struct tls_context *tls)
|
|||||||
/*
|
/*
|
||||||
see how many bytes are pending on the connection
|
see how many bytes are pending on the connection
|
||||||
*/
|
*/
|
||||||
NTSTATUS tls_socket_pending(struct tls_context *tls, size_t *npending)
|
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) {
|
if (!tls->tls_enabled || tls->tls_detect) {
|
||||||
return socket_pending(tls->socket, npending);
|
return socket_pending(tls->socket, npending);
|
||||||
}
|
}
|
||||||
@ -219,11 +259,13 @@ NTSTATUS tls_socket_pending(struct tls_context *tls, size_t *npending)
|
|||||||
/*
|
/*
|
||||||
receive data either by tls or normal socket_recv
|
receive data either by tls or normal socket_recv
|
||||||
*/
|
*/
|
||||||
NTSTATUS tls_socket_recv(struct tls_context *tls, void *buf, size_t wantlen,
|
static NTSTATUS tls_socket_recv(struct socket_context *sock, void *buf,
|
||||||
size_t *nread)
|
size_t wantlen, size_t *nread)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
struct tls_context *tls = talloc_get_type(sock->private_data, struct tls_context);
|
||||||
|
|
||||||
if (tls->tls_enabled && tls->tls_detect) {
|
if (tls->tls_enabled && tls->tls_detect) {
|
||||||
status = socket_recv(tls->socket, &tls->first_byte, 1, nread);
|
status = socket_recv(tls->socket, &tls->first_byte, 1, nread);
|
||||||
NT_STATUS_NOT_OK_RETURN(status);
|
NT_STATUS_NOT_OK_RETURN(status);
|
||||||
@ -268,10 +310,12 @@ NTSTATUS tls_socket_recv(struct tls_context *tls, void *buf, size_t wantlen,
|
|||||||
/*
|
/*
|
||||||
send data either by tls or normal socket_recv
|
send data either by tls or normal socket_recv
|
||||||
*/
|
*/
|
||||||
NTSTATUS tls_socket_send(struct tls_context *tls, const DATA_BLOB *blob, size_t *sendlen)
|
static NTSTATUS tls_socket_send(struct socket_context *sock,
|
||||||
|
const DATA_BLOB *blob, size_t *sendlen)
|
||||||
{
|
{
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
int ret;
|
int ret;
|
||||||
|
struct tls_context *tls = talloc_get_type(sock->private_data, struct tls_context);
|
||||||
|
|
||||||
if (!tls->tls_enabled) {
|
if (!tls->tls_enabled) {
|
||||||
return socket_send(tls->socket, blob, sendlen);
|
return socket_send(tls->socket, blob, sendlen);
|
||||||
@ -389,24 +433,41 @@ init_failed:
|
|||||||
/*
|
/*
|
||||||
setup for a new connection
|
setup for a new connection
|
||||||
*/
|
*/
|
||||||
struct tls_context *tls_init_server(struct tls_params *params,
|
struct socket_context *tls_init_server(struct tls_params *params,
|
||||||
struct socket_context *socket,
|
struct socket_context *socket,
|
||||||
struct fd_event *fde,
|
struct fd_event *fde,
|
||||||
const char *plain_chars,
|
const char *plain_chars)
|
||||||
BOOL tls_enable)
|
|
||||||
{
|
{
|
||||||
struct tls_context *tls;
|
struct tls_context *tls;
|
||||||
int ret;
|
int ret;
|
||||||
|
struct socket_context *new_sock;
|
||||||
|
NTSTATUS nt_status;
|
||||||
|
|
||||||
|
nt_status = socket_create_with_ops(socket, &tls_socket_ops, &new_sock,
|
||||||
|
SOCKET_TYPE_STREAM, 0);
|
||||||
|
if (!NT_STATUS_IS_OK(nt_status)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
tls = talloc(socket, struct tls_context);
|
tls = talloc(new_sock, struct tls_context);
|
||||||
if (tls == NULL) return NULL;
|
if (tls == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
tls->socket = socket;
|
tls->socket = socket;
|
||||||
tls->fde = fde;
|
tls->fde = fde;
|
||||||
|
if (talloc_reference(tls, fde) == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (talloc_reference(tls, socket) == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (!params->tls_enabled || !tls_enable) {
|
new_sock->private_data = tls;
|
||||||
|
|
||||||
|
if (!params->tls_enabled) {
|
||||||
tls->tls_enabled = False;
|
tls->tls_enabled = False;
|
||||||
return tls;
|
return new_sock;
|
||||||
}
|
}
|
||||||
|
|
||||||
TLSCHECK(gnutls_init(&tls->session, GNUTLS_SERVER));
|
TLSCHECK(gnutls_init(&tls->session, GNUTLS_SERVER));
|
||||||
@ -436,38 +497,49 @@ struct tls_context *tls_init_server(struct tls_params *params,
|
|||||||
tls->tls_enabled = True;
|
tls->tls_enabled = True;
|
||||||
tls->interrupted = False;
|
tls->interrupted = False;
|
||||||
|
|
||||||
return tls;
|
new_sock->state = SOCKET_STATE_SERVER_CONNECTED;
|
||||||
|
|
||||||
|
return new_sock;
|
||||||
|
|
||||||
failed:
|
failed:
|
||||||
DEBUG(0,("TLS init connection failed - %s\n", gnutls_strerror(ret)));
|
DEBUG(0,("TLS init connection failed - %s\n", gnutls_strerror(ret)));
|
||||||
tls->tls_enabled = False;
|
tls->tls_enabled = False;
|
||||||
params->tls_enabled = False;
|
params->tls_enabled = False;
|
||||||
return tls;
|
return new_sock;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
setup for a new client connection
|
setup for a new client connection
|
||||||
*/
|
*/
|
||||||
struct tls_context *tls_init_client(struct socket_context *socket,
|
struct socket_context *tls_init_client(struct socket_context *socket,
|
||||||
struct fd_event *fde,
|
struct fd_event *fde)
|
||||||
BOOL tls_enable)
|
|
||||||
{
|
{
|
||||||
struct tls_context *tls;
|
struct tls_context *tls;
|
||||||
int ret=0;
|
int ret = 0;
|
||||||
const int cert_type_priority[] = { GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0 };
|
const int cert_type_priority[] = { GNUTLS_CRT_X509, GNUTLS_CRT_OPENPGP, 0 };
|
||||||
char *cafile;
|
char *cafile;
|
||||||
|
struct socket_context *new_sock;
|
||||||
|
NTSTATUS nt_status;
|
||||||
|
|
||||||
|
nt_status = socket_create_with_ops(socket, &tls_socket_ops, &new_sock,
|
||||||
|
SOCKET_TYPE_STREAM, 0);
|
||||||
|
if (!NT_STATUS_IS_OK(nt_status)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
tls = talloc(socket, struct tls_context);
|
tls = talloc(new_sock, struct tls_context);
|
||||||
if (tls == NULL) return NULL;
|
if (tls == NULL) return NULL;
|
||||||
|
|
||||||
tls->socket = socket;
|
tls->socket = socket;
|
||||||
tls->fde = fde;
|
tls->fde = fde;
|
||||||
tls->tls_enabled = tls_enable;
|
if (talloc_reference(tls, fde) == NULL) {
|
||||||
|
return NULL;
|
||||||
if (!tls->tls_enabled) {
|
|
||||||
return tls;
|
|
||||||
}
|
}
|
||||||
|
if (talloc_reference(tls, socket) == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
new_sock->private_data = tls;
|
||||||
|
|
||||||
cafile = private_path(tls, lp_tls_cafile());
|
cafile = private_path(tls, lp_tls_cafile());
|
||||||
if (!cafile || !*cafile) {
|
if (!cafile || !*cafile) {
|
||||||
@ -498,19 +570,61 @@ struct tls_context *tls_init_client(struct socket_context *socket,
|
|||||||
tls->tls_enabled = True;
|
tls->tls_enabled = True;
|
||||||
tls->interrupted = False;
|
tls->interrupted = False;
|
||||||
|
|
||||||
return tls;
|
new_sock->state = SOCKET_STATE_CLIENT_CONNECTED;
|
||||||
|
|
||||||
|
return new_sock;
|
||||||
|
|
||||||
failed:
|
failed:
|
||||||
DEBUG(0,("TLS init connection failed - %s\n", gnutls_strerror(ret)));
|
DEBUG(0,("TLS init connection failed - %s\n", gnutls_strerror(ret)));
|
||||||
tls->tls_enabled = False;
|
tls->tls_enabled = False;
|
||||||
return tls;
|
return new_sock;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL tls_enabled(struct tls_context *tls)
|
static NTSTATUS tls_socket_set_option(struct socket_context *sock, const char *option, const char *val)
|
||||||
{
|
{
|
||||||
return tls->tls_enabled;
|
set_socket_options(socket_get_fd(sock), option);
|
||||||
|
return NT_STATUS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *tls_socket_get_peer_name(struct socket_context *sock, TALLOC_CTX *mem_ctx)
|
||||||
|
{
|
||||||
|
struct tls_context *tls = talloc_get_type(sock->private_data, struct tls_context);
|
||||||
|
return socket_get_peer_name(tls->socket, mem_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct socket_address *tls_socket_get_peer_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
|
||||||
|
{
|
||||||
|
struct tls_context *tls = talloc_get_type(sock->private_data, struct tls_context);
|
||||||
|
return socket_get_peer_addr(tls->socket, mem_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct socket_address *tls_socket_get_my_addr(struct socket_context *sock, TALLOC_CTX *mem_ctx)
|
||||||
|
{
|
||||||
|
struct tls_context *tls = talloc_get_type(sock->private_data, struct tls_context);
|
||||||
|
return socket_get_my_addr(tls->socket, mem_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tls_socket_get_fd(struct socket_context *sock)
|
||||||
|
{
|
||||||
|
struct tls_context *tls = talloc_get_type(sock->private_data, struct tls_context);
|
||||||
|
return socket_get_fd(tls->socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct socket_ops tls_socket_ops = {
|
||||||
|
.name = "tls",
|
||||||
|
.fn_init = tls_socket_init,
|
||||||
|
.fn_recv = tls_socket_recv,
|
||||||
|
.fn_send = tls_socket_send,
|
||||||
|
.fn_pending = tls_socket_pending,
|
||||||
|
|
||||||
|
.fn_set_option = tls_socket_set_option,
|
||||||
|
|
||||||
|
.fn_get_peer_name = tls_socket_get_peer_name,
|
||||||
|
.fn_get_peer_addr = tls_socket_get_peer_addr,
|
||||||
|
.fn_get_my_addr = tls_socket_get_my_addr,
|
||||||
|
.fn_get_fd = tls_socket_get_fd
|
||||||
|
};
|
||||||
|
|
||||||
BOOL tls_support(struct tls_params *params)
|
BOOL tls_support(struct tls_params *params)
|
||||||
{
|
{
|
||||||
return params->tls_enabled;
|
return params->tls_enabled;
|
||||||
@ -526,38 +640,25 @@ struct tls_params *tls_initialise(TALLOC_CTX *mem_ctx)
|
|||||||
return talloc_new(mem_ctx);
|
return talloc_new(mem_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tls_context *tls_init_server(struct tls_params *params,
|
/*
|
||||||
struct socket_context *sock,
|
setup for a new connection
|
||||||
struct fd_event *fde,
|
*/
|
||||||
const char *plain_chars,
|
struct socket_context *tls_init_server(struct tls_params *params,
|
||||||
BOOL tls_enable)
|
struct socket_context *socket,
|
||||||
|
struct fd_event *fde,
|
||||||
|
const char *plain_chars)
|
||||||
{
|
{
|
||||||
if (tls_enable && plain_chars == NULL) return NULL;
|
return socket;
|
||||||
return (struct tls_context *)sock;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct tls_context *tls_init_client(struct socket_context *sock,
|
|
||||||
struct fd_event *fde,
|
|
||||||
BOOL tls_enable)
|
|
||||||
{
|
|
||||||
return (struct tls_context *)sock;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
NTSTATUS tls_socket_recv(struct tls_context *tls, void *buf, size_t wantlen,
|
/*
|
||||||
size_t *nread)
|
setup for a new client connection
|
||||||
|
*/
|
||||||
|
struct socket_context *tls_init_client(struct socket_context *socket,
|
||||||
|
struct fd_event *fde)
|
||||||
{
|
{
|
||||||
return socket_recv((struct socket_context *)tls, buf, wantlen, nread);
|
return socket;
|
||||||
}
|
|
||||||
|
|
||||||
NTSTATUS tls_socket_send(struct tls_context *tls, const DATA_BLOB *blob, size_t *sendlen)
|
|
||||||
{
|
|
||||||
return socket_send((struct socket_context *)tls, blob, sendlen);
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL tls_enabled(struct tls_context *tls)
|
|
||||||
{
|
|
||||||
return False;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL tls_support(struct tls_params *params)
|
BOOL tls_support(struct tls_params *params)
|
||||||
@ -565,9 +666,5 @@ BOOL tls_support(struct tls_params *params)
|
|||||||
return False;
|
return False;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS tls_socket_pending(struct tls_context *tls, size_t *npending)
|
|
||||||
{
|
|
||||||
return socket_pending((struct socket_context *)tls, npending);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -37,31 +37,21 @@ struct tls_params *tls_initialise(TALLOC_CTX *mem_ctx);
|
|||||||
tls and non-tls servers on the same port. If this is NULL then only
|
tls and non-tls servers on the same port. If this is NULL then only
|
||||||
tls connections will be allowed
|
tls connections will be allowed
|
||||||
*/
|
*/
|
||||||
struct tls_context *tls_init_server(struct tls_params *parms,
|
struct socket_context *tls_init_server(struct tls_params *parms,
|
||||||
struct socket_context *sock,
|
struct socket_context *sock,
|
||||||
struct fd_event *fde,
|
struct fd_event *fde,
|
||||||
const char *plain_chars,
|
const char *plain_chars);
|
||||||
BOOL tls_enable);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
call tls_init_client() on each new client connection
|
call tls_init_client() on each new client connection
|
||||||
*/
|
*/
|
||||||
struct tls_context *tls_init_client(struct socket_context *sock,
|
struct socket_context *tls_init_client(struct socket_context *sock,
|
||||||
struct fd_event *fde,
|
struct fd_event *fde);
|
||||||
BOOL tls_enable);
|
|
||||||
|
|
||||||
/*
|
|
||||||
call these to send and receive data. They behave like socket_send() and socket_recv()
|
|
||||||
*/
|
|
||||||
NTSTATUS tls_socket_recv(struct tls_context *tls, void *buf, size_t wantlen,
|
|
||||||
size_t *nread);
|
|
||||||
NTSTATUS tls_socket_send(struct tls_context *tls, const DATA_BLOB *blob,
|
|
||||||
size_t *sendlen);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
return True if a connection used tls
|
return True if a connection used tls
|
||||||
*/
|
*/
|
||||||
BOOL tls_enabled(struct tls_context *tls);
|
BOOL tls_enabled(struct socket_context *tls);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -69,10 +59,6 @@ BOOL tls_enabled(struct tls_context *tls);
|
|||||||
*/
|
*/
|
||||||
BOOL tls_support(struct tls_params *parms);
|
BOOL tls_support(struct tls_params *parms);
|
||||||
|
|
||||||
|
const struct socket_ops *socket_tls_ops(enum socket_type type);
|
||||||
/*
|
|
||||||
ask for the number of bytes in a pending incoming packet
|
|
||||||
*/
|
|
||||||
NTSTATUS tls_socket_pending(struct tls_context *tls, size_t *npending);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -223,7 +223,7 @@ NTSTATUS ldap_bind_sasl(struct ldap_connection *conn, struct cli_credentials *cr
|
|||||||
|
|
||||||
/* require Kerberos SIGN/SEAL only if we don't use SSL
|
/* require Kerberos SIGN/SEAL only if we don't use SSL
|
||||||
* Windows seem not to like double encryption */
|
* Windows seem not to like double encryption */
|
||||||
if (conn->tls == NULL || (! tls_enabled(conn->tls))) {
|
if (!tls_enabled(conn->sock)) {
|
||||||
gensec_want_feature(conn->gensec, 0 | GENSEC_FEATURE_SIGN | GENSEC_FEATURE_SEAL);
|
gensec_want_feature(conn->gensec, 0 | GENSEC_FEATURE_SIGN | GENSEC_FEATURE_SEAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,6 +32,7 @@
|
|||||||
#include "libcli/ldap/ldap_client.h"
|
#include "libcli/ldap/ldap_client.h"
|
||||||
#include "libcli/composite/composite.h"
|
#include "libcli/composite/composite.h"
|
||||||
#include "lib/stream/packet.h"
|
#include "lib/stream/packet.h"
|
||||||
|
#include "lib/tls/tls.h"
|
||||||
#include "auth/gensec/gensec.h"
|
#include "auth/gensec/gensec.h"
|
||||||
#include "system/time.h"
|
#include "system/time.h"
|
||||||
|
|
||||||
@ -85,12 +86,10 @@ static void ldap_connection_dead(struct ldap_connection *conn)
|
|||||||
if (req->async.fn) {
|
if (req->async.fn) {
|
||||||
req->async.fn(req);
|
req->async.fn(req);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
talloc_free(conn->tls);
|
talloc_free(conn->sock); /* this will also free event.fde */
|
||||||
/* talloc_free(conn->sock); this will also free event.fde */
|
|
||||||
talloc_free(conn->packet);
|
talloc_free(conn->packet);
|
||||||
conn->tls = NULL;
|
|
||||||
conn->sock = NULL;
|
conn->sock = NULL;
|
||||||
conn->event.fde = NULL;
|
conn->event.fde = NULL;
|
||||||
conn->packet = NULL;
|
conn->packet = NULL;
|
||||||
@ -270,7 +269,7 @@ static void ldap_io_handler(struct event_context *ev, struct fd_event *fde,
|
|||||||
struct ldap_connection);
|
struct ldap_connection);
|
||||||
if (flags & EVENT_FD_WRITE) {
|
if (flags & EVENT_FD_WRITE) {
|
||||||
packet_queue_run(conn->packet);
|
packet_queue_run(conn->packet);
|
||||||
if (conn->tls == NULL) return;
|
if (!tls_enabled(conn->sock)) return;
|
||||||
}
|
}
|
||||||
if (flags & EVENT_FD_READ) {
|
if (flags & EVENT_FD_READ) {
|
||||||
packet_recv(conn->packet);
|
packet_recv(conn->packet);
|
||||||
@ -339,11 +338,6 @@ struct composite_context *ldap_connect_send(struct ldap_connection *conn,
|
|||||||
struct composite_context *result, *ctx;
|
struct composite_context *result, *ctx;
|
||||||
struct ldap_connect_state *state;
|
struct ldap_connect_state *state;
|
||||||
|
|
||||||
if (conn->reconnect.url == NULL) {
|
|
||||||
conn->reconnect.url = talloc_strdup(conn, url);
|
|
||||||
if (conn->reconnect.url == NULL) goto failed;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = talloc_zero(NULL, struct composite_context);
|
result = talloc_zero(NULL, struct composite_context);
|
||||||
if (result == NULL) goto failed;
|
if (result == NULL) goto failed;
|
||||||
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
result->state = COMPOSITE_STATE_IN_PROGRESS;
|
||||||
@ -357,6 +351,11 @@ struct composite_context *ldap_connect_send(struct ldap_connection *conn,
|
|||||||
|
|
||||||
state->conn = conn;
|
state->conn = conn;
|
||||||
|
|
||||||
|
if (conn->reconnect.url == NULL) {
|
||||||
|
conn->reconnect.url = talloc_strdup(conn, url);
|
||||||
|
if (conn->reconnect.url == NULL) goto failed;
|
||||||
|
}
|
||||||
|
|
||||||
state->ctx->status = ldap_parse_basic_url(conn, url, &conn->host,
|
state->ctx->status = ldap_parse_basic_url(conn, url, &conn->host,
|
||||||
&conn->port, &conn->ldaps);
|
&conn->port, &conn->ldaps);
|
||||||
if (!NT_STATUS_IS_OK(state->ctx->status)) {
|
if (!NT_STATUS_IS_OK(state->ctx->status)) {
|
||||||
@ -379,6 +378,7 @@ struct composite_context *ldap_connect_send(struct ldap_connection *conn,
|
|||||||
|
|
||||||
static void ldap_connect_recv_conn(struct composite_context *ctx)
|
static void ldap_connect_recv_conn(struct composite_context *ctx)
|
||||||
{
|
{
|
||||||
|
struct socket_context *initial_socket;
|
||||||
struct ldap_connect_state *state =
|
struct ldap_connect_state *state =
|
||||||
talloc_get_type(ctx->async.private_data,
|
talloc_get_type(ctx->async.private_data,
|
||||||
struct ldap_connect_state);
|
struct ldap_connect_state);
|
||||||
@ -398,21 +398,24 @@ static void ldap_connect_recv_conn(struct composite_context *ctx)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
conn->tls = tls_init_client(conn->sock, conn->event.fde, conn->ldaps);
|
talloc_steal(conn, conn->sock);
|
||||||
if (conn->tls == NULL) {
|
initial_socket = conn->sock;
|
||||||
talloc_free(conn->sock);
|
if (conn->ldaps) {
|
||||||
return;
|
conn->sock = tls_init_client(conn->sock, conn->event.fde);
|
||||||
|
if (conn->sock == NULL) {
|
||||||
|
talloc_free(initial_socket);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
talloc_steal(conn, conn->tls);
|
|
||||||
talloc_steal(conn->tls, conn->sock);
|
|
||||||
|
|
||||||
conn->packet = packet_init(conn);
|
conn->packet = packet_init(conn);
|
||||||
if (conn->packet == NULL) {
|
if (conn->packet == NULL) {
|
||||||
talloc_free(conn->sock);
|
talloc_free(conn->sock);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
packet_set_private(conn->packet, conn);
|
packet_set_private(conn->packet, conn);
|
||||||
packet_set_tls(conn->packet, conn->tls);
|
packet_set_socket(conn->packet, conn->sock);
|
||||||
packet_set_callback(conn->packet, ldap_recv_handler);
|
packet_set_callback(conn->packet, ldap_recv_handler);
|
||||||
packet_set_full_request(conn->packet, ldap_complete_packet);
|
packet_set_full_request(conn->packet, ldap_complete_packet);
|
||||||
packet_set_error_handler(conn->packet, ldap_error_handler);
|
packet_set_error_handler(conn->packet, ldap_error_handler);
|
||||||
@ -535,7 +538,7 @@ struct ldap_request *ldap_request_send(struct ldap_connection *conn,
|
|||||||
req = talloc_zero(conn, struct ldap_request);
|
req = talloc_zero(conn, struct ldap_request);
|
||||||
if (req == NULL) return NULL;
|
if (req == NULL) return NULL;
|
||||||
|
|
||||||
if (conn->tls == NULL) {
|
if (conn->sock == NULL) {
|
||||||
status = NT_STATUS_INVALID_CONNECTION;
|
status = NT_STATUS_INVALID_CONNECTION;
|
||||||
goto failed;
|
goto failed;
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,6 @@ struct ldap_request {
|
|||||||
|
|
||||||
/* main context for a ldap client connection */
|
/* main context for a ldap client connection */
|
||||||
struct ldap_connection {
|
struct ldap_connection {
|
||||||
struct tls_context *tls;
|
|
||||||
struct socket_context *sock;
|
struct socket_context *sock;
|
||||||
char *host;
|
char *host;
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
|
@ -237,12 +237,12 @@ static void http_redirect(EspHandle handle, int code, char *url)
|
|||||||
char *p = strrchr(web->input.url, '/');
|
char *p = strrchr(web->input.url, '/');
|
||||||
if (p == web->input.url) {
|
if (p == web->input.url) {
|
||||||
url = talloc_asprintf(web, "http%s://%s/%s",
|
url = talloc_asprintf(web, "http%s://%s/%s",
|
||||||
tls_enabled(web->tls)?"s":"",
|
tls_enabled(web->conn->socket)?"s":"",
|
||||||
host, url);
|
host, url);
|
||||||
} else {
|
} else {
|
||||||
int dirlen = p - web->input.url;
|
int dirlen = p - web->input.url;
|
||||||
url = talloc_asprintf(web, "http%s://%s%*.*s/%s",
|
url = talloc_asprintf(web, "http%s://%s%*.*s/%s",
|
||||||
tls_enabled(web->tls)?"s":"",
|
tls_enabled(web->conn->socket)?"s":"",
|
||||||
host,
|
host,
|
||||||
dirlen, dirlen, web->input.url,
|
dirlen, dirlen, web->input.url,
|
||||||
url);
|
url);
|
||||||
@ -452,7 +452,7 @@ static void http_setup_arrays(struct esp_state *esp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SETVAR(ESP_SERVER_OBJ, "DOCUMENT_ROOT", lp_swat_directory());
|
SETVAR(ESP_SERVER_OBJ, "DOCUMENT_ROOT", lp_swat_directory());
|
||||||
SETVAR(ESP_SERVER_OBJ, "SERVER_PROTOCOL", tls_enabled(web->tls)?"https":"http");
|
SETVAR(ESP_SERVER_OBJ, "SERVER_PROTOCOL", tls_enabled(web->conn->socket)?"https":"http");
|
||||||
SETVAR(ESP_SERVER_OBJ, "SERVER_SOFTWARE", "SWAT");
|
SETVAR(ESP_SERVER_OBJ, "SERVER_SOFTWARE", "SWAT");
|
||||||
SETVAR(ESP_SERVER_OBJ, "GATEWAY_INTERFACE", "CGI/1.1");
|
SETVAR(ESP_SERVER_OBJ, "GATEWAY_INTERFACE", "CGI/1.1");
|
||||||
SETVAR(ESP_SERVER_OBJ, "TLS_SUPPORT", tls_support(edata->tls_params)?"True":"False");
|
SETVAR(ESP_SERVER_OBJ, "TLS_SUPPORT", tls_support(edata->tls_params)?"True":"False");
|
||||||
|
@ -76,7 +76,7 @@ static void websrv_recv(struct stream_connection *conn, uint16_t flags)
|
|||||||
DATA_BLOB b;
|
DATA_BLOB b;
|
||||||
|
|
||||||
/* not the most efficient http parser ever, but good enough for us */
|
/* not the most efficient http parser ever, but good enough for us */
|
||||||
status = tls_socket_recv(web->tls, buf, sizeof(buf), &nread);
|
status = socket_recv(conn->socket, buf, sizeof(buf), &nread);
|
||||||
if (NT_STATUS_IS_ERR(status)) goto failed;
|
if (NT_STATUS_IS_ERR(status)) goto failed;
|
||||||
if (!NT_STATUS_IS_OK(status)) return;
|
if (!NT_STATUS_IS_OK(status)) return;
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ static void websrv_send(struct stream_connection *conn, uint16_t flags)
|
|||||||
b.data += web->output.nsent;
|
b.data += web->output.nsent;
|
||||||
b.length -= web->output.nsent;
|
b.length -= web->output.nsent;
|
||||||
|
|
||||||
status = tls_socket_send(web->tls, &b, &nsent);
|
status = socket_send(conn->socket, &b, &nsent);
|
||||||
if (NT_STATUS_IS_ERR(status)) {
|
if (NT_STATUS_IS_ERR(status)) {
|
||||||
stream_terminate_connection(web->conn, "socket_send: failed");
|
stream_terminate_connection(web->conn, "socket_send: failed");
|
||||||
return;
|
return;
|
||||||
@ -183,8 +183,6 @@ static void websrv_send(struct stream_connection *conn, uint16_t flags)
|
|||||||
|
|
||||||
if (web->output.content.length == web->output.nsent &&
|
if (web->output.content.length == web->output.nsent &&
|
||||||
web->output.fd == -1) {
|
web->output.fd == -1) {
|
||||||
talloc_free(web->tls);
|
|
||||||
web->tls = NULL;
|
|
||||||
stream_terminate_connection(web->conn, "websrv_send: finished sending");
|
stream_terminate_connection(web->conn, "websrv_send: finished sending");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -211,9 +209,10 @@ static void websrv_accept(struct stream_connection *conn)
|
|||||||
timeval_current_ofs(HTTP_TIMEOUT, 0),
|
timeval_current_ofs(HTTP_TIMEOUT, 0),
|
||||||
websrv_timeout, web);
|
websrv_timeout, web);
|
||||||
|
|
||||||
web->tls = tls_init_server(edata->tls_params, conn->socket,
|
/* Overwrite the socket with a (possibly) TLS socket */
|
||||||
conn->event.fde, "GPHO", True);
|
conn->socket = tls_init_server(edata->tls_params, conn->socket,
|
||||||
if (web->tls == NULL) goto failed;
|
conn->event.fde, "GPHO");
|
||||||
|
if (conn->socket == NULL) goto failed;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -54,7 +54,6 @@ struct websrv_context {
|
|||||||
int response_code;
|
int response_code;
|
||||||
const char **headers;
|
const char **headers;
|
||||||
} output;
|
} output;
|
||||||
struct tls_context *tls;
|
|
||||||
struct session_data *session;
|
struct session_data *session;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user