blob: 4f42945cd4503facd4c62576a2badafd2e6b4b00 [file] [log] [blame]
/*****************************************************************************\
* tls.c - definitions for TLS work in connection manager
*****************************************************************************
* Copyright (C) SchedMD LLC.
*
* This file is part of Slurm, a resource management program.
* For details, see <https://slurm.schedmd.com/>.
* Please also read the included file: DISCLAIMER.
*
* Slurm 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 2 of the License, or (at your option)
* any later version.
*
* In addition, as a special exception, the copyright holders give permission
* to link the code of portions of this program with the OpenSSL library under
* certain conditions as described in each individual source file, and
* distribute linked combinations including the two. You must obey the GNU
* General Public License in all respects for all of the code used other than
* OpenSSL. If you modify file(s) with this exception, you may extend this
* exception to your version of the file(s), but you are not obligated to do
* so. If you do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source files in
* the program, then also delete it here.
*
* Slurm 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 Slurm; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\*****************************************************************************/
#include "src/common/fd.h"
#include "src/common/log.h"
#include "src/common/macros.h"
#include "src/common/pack.h"
#include "src/common/read_config.h"
#include "src/common/xmalloc.h"
#include "src/conmgr/tls.h"
#include "src/conmgr/tls_fingerprint.h"
#include "src/conmgr/conmgr.h"
#include "src/conmgr/mgr.h"
#include "src/interfaces/tls.h"
#define HANDLE_ENC_ARGS_MAGIC 0x2a4afb43
typedef struct {
int magic; /* HANDLE_ENC_ARGS_MAGIC */
int index;
conmgr_fd_t *con;
ssize_t wrote;
} handle_enc_args_t;
static void _shift_buf_bytes(buf_t *buf, const size_t bytes)
{
void *start = NULL;
size_t remain = 0;
xassert(get_buf_offset(buf) >= bytes);
if (get_buf_offset(buf) == bytes) {
set_buf_offset(buf, 0);
return;
}
start = (((void *) get_buf_data(buf)) + bytes);
remain = (get_buf_offset(buf) - bytes);
xassert(remain > 0);
xassert(remain < size_buf(buf));
(void) memcpy(get_buf_data(buf), start, remain);
set_buf_offset(buf, remain);
}
static void _post_wait_close_fds(bool locked, conmgr_fd_t *con)
{
if (!locked)
slurm_mutex_lock(&mgr.mutex);
xassert(con_flag(con, FLAG_TLS_WAIT_ON_CLOSE));
close_con(true, con);
con_unset_flag(con, FLAG_TLS_WAIT_ON_CLOSE);
if (!locked)
slurm_mutex_unlock(&mgr.mutex);
}
static void _delayed_close(conmgr_callback_args_t conmgr_args, void *arg)
{
conmgr_fd_t *con = conmgr_args.con;
log_flag(CONMGR, "%s: [%s] close wait complete", __func__, con->name);
_post_wait_close_fds(false, con);
}
/*
* Check and enforce if TLS has requested wait on operations and then close
* connection
*/
static void _wait_close(bool locked, conmgr_fd_t *con)
{
timespec_t delay = { 0 };
if (!locked)
slurm_mutex_lock(&mgr.mutex);
xassert(!con_flag(con, FLAG_TLS_WAIT_ON_CLOSE));
/* Soft close the connection to stop any more activity */
con_set_polling(con, PCTL_TYPE_NONE, __func__);
con_set_flag(con, FLAG_READ_EOF);
con_set_flag(con, FLAG_TLS_WAIT_ON_CLOSE);
con_unset_flag(con, FLAG_CAN_WRITE);
con_unset_flag(con, FLAG_CAN_READ);
xassert(con->tls);
delay = tls_g_get_delay(con->tls);
if (delay.tv_sec) {
log_flag(CONMGR, "%s: [%s] deferring close",
__func__, con->name);
add_work_con_delayed_abs_fifo(true, con, _delayed_close, NULL,
delay);
} else {
log_flag(CONMGR, "%s: [%s] closing now",
__func__, con->name);
_post_wait_close_fds(true, con);
}
if (!locked)
slurm_mutex_unlock(&mgr.mutex);
}
extern void tls_close(conmgr_callback_args_t conmgr_args, void *arg)
{
conmgr_fd_t *con = conmgr_args.con;
void *tls = NULL;
int rc = EINVAL;
buf_t *tls_in = NULL;
list_t *tls_out = NULL;
slurm_mutex_lock(&mgr.mutex);
xassert(con->tls);
xassert(con_flag(con, FLAG_TLS_CLIENT) ^
con_flag(con, FLAG_TLS_SERVER));
xassert(con->input_fd == -1);
xassert(con_flag(con, FLAG_READ_EOF));
xassert(!con_flag(con, FLAG_TLS_WAIT_ON_CLOSE));
tls = con->tls;
slurm_mutex_unlock(&mgr.mutex);
if (!tls) {
log_flag(CONMGR, "%s: [%s] closing TLS state skipped",
__func__, con->name);
return;
}
log_flag(CONMGR, "%s: [%s] closing via tls_g_destroy()",
__func__, con->name);
errno = SLURM_SUCCESS;
tls_g_destroy_conn(tls, false);
if ((rc = errno))
log_flag(CONMGR, "%s: [%s] tls_g_destroy() failed: %s",
__func__, con->name, slurm_strerror(rc));
slurm_mutex_lock(&mgr.mutex);
xassert(tls == con->tls);
con->tls = NULL;
SWAP(tls_in, con->tls_in);
SWAP(tls_out, con->tls_out);
slurm_mutex_unlock(&mgr.mutex);
FREE_NULL_BUFFER(tls_in);
FREE_NULL_LIST(tls_out);
}
static int _recv(void *io_context, uint8_t *buf, uint32_t len)
{
conmgr_fd_t *con = io_context;
size_t bytes = 0;
xassert(con->magic == MAGIC_CON_MGR_FD);
xassert(con->tls);
xassert(con->tls_in);
xassert(con_flag(con, FLAG_WORK_ACTIVE));
if (!(bytes = get_buf_offset(con->tls_in))) {
if (con_flag(con, FLAG_READ_EOF)) {
log_flag(CONMGR, "%s: [%s] recv() returning EOF",
__func__, con->name);
return 0;
}
log_flag(CONMGR, "%s: [%s] recv() returning EWOULDBLOCK",
__func__, con->name);
errno = EWOULDBLOCK;
return -1;
}
if (bytes > len)
bytes = len;
log_flag_hex_range(NET_RAW, get_buf_data(con->tls_in),
get_buf_offset(con->tls_in), 0, bytes,
"[%s] TLS recv() %u/%u bytes encrypted",
con->name, bytes, len);
(void) memcpy(buf, get_buf_data(con->tls_in), bytes);
_shift_buf_bytes(con->tls_in, bytes);
return bytes;
}
extern void tls_handle_decrypt(conmgr_callback_args_t conmgr_args, void *arg)
{
conmgr_fd_t *con = conmgr_args.con;
buf_t *buf = con->in;
void *start = NULL;
size_t need = -1, readable = -1;
ssize_t read_c = -1;
int rc = EINVAL;
int try = 0;
again:
slurm_mutex_lock(&mgr.mutex);
if (con_flag(con, FLAG_ON_DATA_TRIED) ||
con_flag(con, FLAG_TLS_WAIT_ON_CLOSE)) {
if (slurm_conf.debug_flags & DEBUG_FLAG_CONMGR) {
char *flags = con_flags_string(con->flags);
log_flag(NET, "%s: [%s] skipping with flags=%s",
__func__, con->name, flags);
xfree(flags);
}
slurm_mutex_unlock(&mgr.mutex);
return;
}
slurm_mutex_unlock(&mgr.mutex);
if (try > 1) {
log_flag(NET, "%s: [%s] need >%d bytes of incoming data to decrypted TLS",
__func__, con->name,
get_buf_offset(con->tls_in));
slurm_mutex_lock(&mgr.mutex);
/* lock to tell mgr that we are done for now */
con_set_flag(con, FLAG_ON_DATA_TRIED);
slurm_mutex_unlock(&mgr.mutex);
return;
}
if ((need = get_buf_offset(con->tls_in)) <= 0) {
log_flag(NET, "%s: [%s] already decrypted all incoming TLS data",
__func__, con->name);
return;
}
if ((rc = try_grow_buf_remaining(buf, need))) {
error("%s: [%s] unable to allocate larger input buffer for TLS data: %s",
__func__, con->name, slurm_strerror(rc));
_wait_close(false, con);
return;
}
readable = remaining_buf(buf);
start = ((void *) get_buf_data(buf)) + get_buf_offset(buf);
xassert(readable >= need);
xassert(con->tls);
xassert(con->magic == MAGIC_CON_MGR_FD);
/* TLS will callback to _recv() to read from con->tls_in*/
read_c = tls_g_recv(con->tls, start, readable);
if (read_c < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
log_flag(NET, "%s: [%s] TLS would block on tls_g_recv()",
__func__, con->name);
return;
}
log_flag(NET, "%s: [%s] error while decrypting TLS: %m",
__func__, con->name);
_wait_close(false, con);
return;
} else if (read_c == 0) {
log_flag(NET, "%s: [%s] read EOF with %u bytes previously decrypted",
__func__, con->name, get_buf_offset(buf));
slurm_mutex_lock(&mgr.mutex);
/* lock to tell mgr that we are done */
con_set_flag(con, FLAG_READ_EOF);
slurm_mutex_unlock(&mgr.mutex);
return;
} else {
log_flag(NET, "%s: [%s] decrypted TLS %zd/%zd bytes with %u bytes previously decrypted",
__func__, con->name, read_c, readable,
get_buf_offset(buf));
log_flag_hex_range(NET_RAW, get_buf_data(buf),
(get_buf_offset(buf) + read_c),
get_buf_offset(buf),
(get_buf_offset(buf) + read_c),
"%s: [%s] decrypted", __func__, con->name);
set_buf_offset(buf, (get_buf_offset(buf) + read_c));
if (get_buf_offset(con->tls_in) > 0) {
try++;
goto again;
}
}
}
static int _send(void *io_context, const uint8_t *src, uint32_t len)
{
conmgr_fd_t *con = io_context;
buf_t *buf = NULL;
void *dst = NULL;
xassert(con->magic == MAGIC_CON_MGR_FD);
xassert(con->tls);
xassert(con_flag(con, FLAG_WORK_ACTIVE));
if (!(dst = try_xmalloc(len)) || !(buf = create_buf(dst, len))) {
xfree(dst);
errno = ENOMEM;
return -1;
}
log_flag_hex(NET_RAW, src, len, "[%s] TLS send encrypted", con->name);
(void) memcpy(dst, src, len);
slurm_mutex_lock(&mgr.mutex);
list_append(con->tls_out, buf);
if (con_flag(con, FLAG_WATCH_WRITE_TIMEOUT))
con->last_write = timespec_now();
slurm_mutex_unlock(&mgr.mutex);
return len;
}
/* WARNING: caller must not hold mgr->mutex lock */
static void _negotiate(conmgr_fd_t *con, void *tls)
{
int rc = tls_g_negotiate_conn(tls);
if (rc == EWOULDBLOCK) {
log_flag(CONMGR, "%s: [%s] tls_g_negotiate_conn() requires more incoming data",
__func__, con->name);
slurm_mutex_lock(&mgr.mutex);
xassert(!con_flag(con, FLAG_IS_TLS_CONNECTED));
xassert(con_flag(con, FLAG_TLS_SERVER) ||
con_flag(con, FLAG_TLS_CLIENT));
xassert(!con_flag(con, FLAG_WAIT_ON_FINGERPRINT));
xassert(con_flag(con, FLAG_WORK_ACTIVE));
xassert(!con_flag(con, FLAG_TLS_WAIT_ON_CLOSE));
/* Wait for more incoming data before trying again */
con_set_flag(con, FLAG_ON_DATA_TRIED);
slurm_mutex_unlock(&mgr.mutex);
return;
} else if (rc) {
log_flag(CONMGR, "%s: [%s] tls_g_negotiate_tls() failed: %s",
__func__, con->name, slurm_strerror(rc));
_wait_close(false, con);
return;
} else {
slurm_mutex_lock(&mgr.mutex);
xassert(!con_flag(con, FLAG_IS_TLS_CONNECTED));
xassert(con_flag(con, FLAG_TLS_SERVER) ||
con_flag(con, FLAG_TLS_CLIENT));
xassert(!con_flag(con, FLAG_WAIT_ON_FINGERPRINT));
xassert(con_flag(con, FLAG_WORK_ACTIVE));
xassert(!con_flag(con, FLAG_TLS_WAIT_ON_CLOSE));
xassert(con->tls == tls);
con_set_flag(con, FLAG_IS_TLS_CONNECTED);
if (con->events->on_connection)
queue_on_connection(con);
slurm_mutex_unlock(&mgr.mutex);
log_flag(CONMGR, "%s: [%s] TLS connected", __func__, con->name);
}
}
extern void tls_create(conmgr_callback_args_t conmgr_args, void *arg)
{
conmgr_fd_t *con = conmgr_args.con;
conn_args_t tls_args = {
.input_fd = -1,
.output_fd = -1,
.defer_blinding = true,
.callbacks = {
.recv = _recv,
.send = _send,
.io_context = con,
},
.defer_negotiation = true,
};
int rc = SLURM_ERROR;
void *tls = NULL;
buf_t *tls_in = NULL;
list_t *tls_out = NULL;
if (tls_g_init() || !tls_available()) {
log_flag(CONMGR, "%s: [%s] TLS disabled: Unable to secure connection. Closing connection.",
__func__, con->name);
close_con(true, con);
close_con_output(true, con);
return;
}
slurm_mutex_lock(&mgr.mutex);
xassert(con_flag(con, FLAG_TLS_CLIENT) ^
con_flag(con, FLAG_TLS_SERVER));
xassert(!con_flag(con, FLAG_IS_TLS_CONNECTED));
xassert(con_flag(con, FLAG_IS_CONNECTED));
xassert(!con_flag(con, FLAG_WAIT_ON_FINGERPRINT));
if ((con->input_fd < 0) || (con->output_fd < 0)) {
xassert(con_flag(con, FLAG_READ_EOF));
slurm_mutex_unlock(&mgr.mutex);
log_flag(CONMGR, "%s: [%s] skip TLS create due to partial connection",
__func__, con->name);
return;
}
if ((tls = con->tls)) {
slurm_mutex_unlock(&mgr.mutex);
log_flag(CONMGR, "%s: [%s] attempting TLS negotiation again",
__func__, con->name);
_negotiate(con, tls);
return;
}
xassert(con->input_fd >= 0);
xassert(con->output_fd >= 0);
xassert(!con->tls_in);
xassert(!con->tls_out);
/* Should not be any outgoing data yet */
xassert(list_is_empty(con->out));
slurm_mutex_unlock(&mgr.mutex);
tls_in = create_buf(xmalloc(BUFFER_START_SIZE), BUFFER_START_SIZE);
tls_out = list_create((ListDelF) free_buf);
if (get_buf_offset(con->in)) {
/*
* Need to move the TLS handshake to con->tls_in to allow tls
* plugin to read the handshake
*/
const size_t bytes = get_buf_offset(con->in);
if ((rc = try_grow_buf_remaining(tls_in, bytes))) {
FREE_NULL_BUFFER(tls_in);
FREE_NULL_LIST(tls_out);
log_flag(CONMGR, "%s: [%s] out of memory for TLS handshake: %s",
__func__, con->name, slurm_strerror(rc));
close_con(false, con);
return;
}
log_flag_hex(NET_RAW, get_buf_data(con->in), bytes,
"[%s] transferring for decryption", con->name);
(void) memcpy(get_buf_data(tls_in), get_buf_data(con->in),
bytes);
set_buf_offset(con->in, 0);
set_buf_offset(tls_in, bytes);
xassert(!con_flag(con, FLAG_ON_DATA_TRIED));
}
slurm_mutex_lock(&mgr.mutex);
xassert(!con->tls);
xassert(!con->tls_in);
xassert(!con->tls_out);
xassert(con_flag(con, FLAG_TLS_CLIENT) ^
con_flag(con, FLAG_TLS_SERVER));
if (con_flag(con, FLAG_TLS_CLIENT))
tls_args.mode = TLS_CONN_CLIENT;
else if (con_flag(con, FLAG_TLS_SERVER))
tls_args.mode = TLS_CONN_SERVER;
xassert(tls_args.mode != TLS_CONN_NULL);
xassert(con->input_fd >= 0);
xassert(con->output_fd >= 0);
con->tls_in = tls_in;
con->tls_out = tls_out;
slurm_mutex_unlock(&mgr.mutex);
if (!(tls = tls_g_create_conn(&tls_args))) {
rc = errno;
log_flag(CONMGR, "%s: [%s] tls_g_create() failed: %s",
__func__, con->name, slurm_strerror(rc));
slurm_mutex_lock(&mgr.mutex);
xassert(!con_flag(con, FLAG_IS_TLS_CONNECTED));
xassert(!con->tls);
close_con(true, con);
con->tls_in = NULL;
con->tls_out = NULL;
slurm_mutex_unlock(&mgr.mutex);
FREE_NULL_BUFFER(tls_in);
FREE_NULL_LIST(tls_out);
} else {
log_flag(CONMGR, "%s: [%s] tls_g_create() success",
__func__, con->name);
slurm_mutex_lock(&mgr.mutex);
xassert(!con_flag(con, FLAG_IS_TLS_CONNECTED));
xassert(!con->tls);
con->tls = tls;
xassert(con->tls_in == tls_in);
xassert(con->tls_out == tls_out);
slurm_mutex_unlock(&mgr.mutex);
_negotiate(con, tls);
}
}
extern void tls_adopt(conmgr_fd_t *con, void *tls_conn)
{
conn_callbacks_t callbacks = {
.recv = _recv,
.send = _send,
.io_context = con,
};
int rc;
xassert(tls_conn);
xassert(con->magic == MAGIC_CON_MGR_FD);
xassert(con_flag(con, FLAG_TLS_CLIENT) ||
con_flag(con, FLAG_TLS_SERVER));
con->tls = tls_conn;
con->tls_in = create_buf(xmalloc(BUFFER_START_SIZE), BUFFER_START_SIZE);
con->tls_out = list_create((ListDelF) free_buf);
/* Can't finger print existing TLS connections */
con_unset_flag(con, FLAG_WAIT_ON_FINGERPRINT);
if ((rc = tls_g_set_conn_callbacks(tls_conn, &callbacks))) {
log_flag(CONMGR, "%s: [%s] adopting TLS state failed: %s",
__func__, con->name, slurm_strerror(rc));
con_set_flag(con, FLAG_READ_EOF);
} else {
log_flag(CONMGR, "%s: [%s] adopted TLS state",
__func__, con->name);
/* TLS state must already be connected */
con_set_flag(con, FLAG_IS_TLS_CONNECTED);
}
}
extern void tls_handle_read(conmgr_callback_args_t conmgr_args, void *arg)
{
conmgr_fd_t *con = conmgr_args.con;
xassert(!con_flag(con, FLAG_WAIT_ON_FINGERPRINT));
xassert(con->tls);
xassert(con_flag(con, FLAG_TLS_CLIENT) ||
con_flag(con, FLAG_TLS_SERVER));
read_input(con, con->tls_in, "input TLS buffer");
}
extern void tls_handle_write(conmgr_callback_args_t conmgr_args, void *arg)
{
conmgr_fd_t *con = conmgr_args.con;
const size_t count = list_count(con->tls_out);
xassert(con->magic == MAGIC_CON_MGR_FD);
xassert(con_flag(con, FLAG_TLS_CLIENT) ||
con_flag(con, FLAG_TLS_SERVER));
xassert(!con_flag(con, FLAG_WAIT_ON_FINGERPRINT));
if (count)
write_output(con, count, con->tls_out);
}
static int _foreach_write_tls(void *x, void *key)
{
buf_t *out = x;
handle_enc_args_t *args = key;
conmgr_fd_t *con = args->con;
void *start = ((void *) get_buf_data(out)) + get_buf_offset(out);
xassert(out->magic == BUF_MAGIC);
xassert(args->magic == HANDLE_ENC_ARGS_MAGIC);
xassert(con->magic == MAGIC_CON_MGR_FD);
args->wrote = tls_g_send(con->tls, start, remaining_buf(out));
if (args->wrote < 0) {
error("%s: [%s] tls_g_send() failed: %m", __func__, con->name);
return SLURM_ERROR;
} else if (!args->wrote) {
log_flag(NET, "%s: [%s] encrypt[%d] of 0/%u bytes to outgoing fd %u",
__func__, args->con->name, args->index,
remaining_buf(out), args->con->output_fd);
return 0;
}
if (args->wrote >= remaining_buf(out)) {
log_flag(NET, "%s: [%s] completed encrypt[%d] of %u/%u bytes to outgoing fd %u",
__func__, args->con->name, args->index,
remaining_buf(out), size_buf(out),
args->con->output_fd);
log_flag_hex_range(NET_RAW, get_buf_data(out), size_buf(out),
get_buf_offset(out),
(get_buf_offset(out) + args->wrote),
"%s: [%s] completed encrypt[%d] of %u/%u bytes",
__func__, args->con->name, args->index,
remaining_buf(out), size_buf(out));
args->wrote -= remaining_buf(out);
args->index++;
return 1;
} else {
log_flag(CONMGR, "%s: [%s] partial encrypt[%d] of %zd/%u bytes to outgoing fd %u",
__func__, args->con->name, args->index,
args->wrote, size_buf(out), args->con->output_fd);
log_flag_hex_range(NET_RAW, get_buf_data(out), size_buf(out),
get_buf_offset(out),
(get_buf_offset(out) + args->wrote),
"%s: [%s] partial encrypt[%d] of %zd/%u bytes",
__func__, args->con->name, args->index,
args->wrote, size_buf(out));
set_buf_offset(out, get_buf_offset(out) + args->wrote);
args->wrote = 0;
args->index++;
return 0;
}
}
extern void tls_handle_encrypt(conmgr_callback_args_t conmgr_args, void *arg)
{
conmgr_fd_t *con = conmgr_args.con;
handle_enc_args_t args = {
.magic = HANDLE_ENC_ARGS_MAGIC,
.con = con,
};
xassert(con->magic == MAGIC_CON_MGR_FD);
xassert(con->tls);
xassert(con_flag(con, FLAG_TLS_CLIENT) ||
con_flag(con, FLAG_TLS_SERVER));
if (list_delete_all(con->out, _foreach_write_tls, &args) < 0) {
error("%s: [%s] _foreach_write_tls() failed",
__func__, con->name);
/* drop outbound data on the floor */
list_flush(con->out);
_wait_close(false, con);
}
}
extern int on_fingerprint_tls(conmgr_fd_t *con, const void *buffer,
const size_t bytes, void *arg)
{
int match = EINVAL;
xassert(con->magic == MAGIC_CON_MGR_FD);
slurm_mutex_lock(&mgr.mutex);
if (con_flag(con, FLAG_TLS_CLIENT) || con_flag(con, FLAG_TLS_SERVER)) {
slurm_mutex_unlock(&mgr.mutex);
log_flag(CONMGR, "%s: [%s] skipping TLS fingerprinting as TLS already activated",
__func__, con->name);
return SLURM_SUCCESS;
}
xassert(!con->tls);
xassert(!con->tls_in);
xassert(!con->tls_out);
xassert(!con_flag(con, FLAG_TLS_CLIENT));
xassert(!con_flag(con, FLAG_TLS_SERVER));
xassert(!con_flag(con, FLAG_IS_TLS_CONNECTED));
xassert(!con_flag(con, FLAG_READ_EOF));
xassert(!con_flag(con, FLAG_IS_LISTEN));
xassert(con_flag(con, FLAG_IS_CONNECTED));
xassert(con_flag(con, FLAG_WAIT_ON_FINGERPRINT));
slurm_mutex_unlock(&mgr.mutex);
if (!(match = tls_is_handshake(get_buf_data(con->in),
get_buf_offset(con->in), con->name))) {
log_flag(CONMGR, "%s: [%s] TLS matched",
__func__, con->name);
slurm_mutex_lock(&mgr.mutex);
/* Only servers can accept an incoming TLS handshake requests */
con_set_flag(con, FLAG_TLS_SERVER);
slurm_mutex_unlock(&mgr.mutex);
return SLURM_SUCCESS;
} else if (match == EWOULDBLOCK) {
log_flag(CONMGR, "%s: [%s] waiting for more bytes for TLS match",
__func__, con->name);
slurm_mutex_lock(&mgr.mutex);
con_set_flag(con, FLAG_ON_DATA_TRIED);
slurm_mutex_unlock(&mgr.mutex);
return EWOULDBLOCK;
} else if (match == ENOENT) {
log_flag(CONMGR, "%s: [%s] TLS not detected",
__func__, con->name);
return SLURM_SUCCESS;
}
fatal_abort("should never happen");
}
extern int tls_extract(conmgr_fd_t *con, extract_fd_t *extract)
{
int rc;
if (con->input_fd < 0) {
log_flag(CONMGR, "%s: [%s] invalid input_fd",
__func__, con->name);
close_con(true, con);
return EBADF;
}
if (con->output_fd < 0) {
log_flag(CONMGR, "%s: [%s] invalid output_fd",
__func__, con->name);
close_con(true, con);
return EBADF;
}
if ((rc = tls_g_set_conn_fds(con->tls, con->input_fd,
con->output_fd))) {
log_flag(CONMGR, "%s: [%s] tls_g_set_fds() failed: %s",
__func__, con->name, slurm_strerror(rc));
close_con(true, con);
return rc;
}
/* Take the TLS state for extraction */
SWAP(extract->tls_conn, con->tls);
return rc;
}