mirror of
https://github.com/tmate-io/tmate-ssh-server.git
synced 2020-11-18 19:53:51 -08:00
Refactored tmate
This commit is contained in:
parent
31cc091823
commit
4ac1183848
@ -179,8 +179,9 @@ dist_tmate_slave_SOURCES = \
|
|||||||
signal.c \
|
signal.c \
|
||||||
status.c \
|
status.c \
|
||||||
tmate-debug.c \
|
tmate-debug.c \
|
||||||
tmate-decoder.c \
|
tmate-client-decoder.c \
|
||||||
tmate-encoder.c \
|
tmate-client-encoder.c \
|
||||||
|
tmate-msgpack.c \
|
||||||
tmate-slave.c \
|
tmate-slave.c \
|
||||||
tmate-ssh-client-pty.c \
|
tmate-ssh-client-pty.c \
|
||||||
tmate-ssh-client.c \
|
tmate-ssh-client.c \
|
||||||
|
4
client.c
4
client.c
@ -207,7 +207,7 @@ client_main(int argc, char **argv, int flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TMATE_SLAVE
|
#ifdef TMATE_SLAVE
|
||||||
fd = tmux_socket_fd;
|
fd = tmate_session->tmux_socket_fd;
|
||||||
#else
|
#else
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -325,7 +325,7 @@ client_send_identify(int flags)
|
|||||||
int fd;
|
int fd;
|
||||||
|
|
||||||
#ifdef TMATE_SLAVE
|
#ifdef TMATE_SLAVE
|
||||||
strcpy(data.ip_address, tmate_client.ip_address);
|
strcpy(data.ip_address, tmate_session->ssh_client.ip_address);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
data.flags = flags;
|
data.flags = flags;
|
||||||
|
6
log.c
6
log.c
@ -73,11 +73,13 @@ log_vwrite(int level, const char *msg, va_list ap)
|
|||||||
{
|
{
|
||||||
char *fmt = NULL;
|
char *fmt = NULL;
|
||||||
|
|
||||||
|
const char *token = tmate_session->session_token;
|
||||||
|
|
||||||
if (log_settings.log_level < level)
|
if (log_settings.log_level < level)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (tmate_session_token) {
|
if (token) {
|
||||||
if (asprintf(&fmt, "[%s] %s", tmate_session_token, msg) < 0)
|
if (asprintf(&fmt, "[%s] %s", token, msg) < 0)
|
||||||
exit(1);
|
exit(1);
|
||||||
msg = fmt;
|
msg = fmt;
|
||||||
}
|
}
|
||||||
|
2
server.c
2
server.c
@ -162,7 +162,7 @@ server_start(int lockfd, char *lockfile)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef TMATE_SLAVE
|
#ifdef TMATE_SLAVE
|
||||||
server_fd = tmux_socket_fd;
|
server_fd = tmate_session->tmux_socket_fd;
|
||||||
#else
|
#else
|
||||||
server_fd = server_create_socket();
|
server_fd = server_create_socket();
|
||||||
server_client_create(pair[1]);
|
server_client_create(pair[1]);
|
||||||
|
@ -6,111 +6,21 @@ char *tmate_left_status, *tmate_right_status;
|
|||||||
|
|
||||||
static struct session *main_session;
|
static struct session *main_session;
|
||||||
|
|
||||||
struct tmate_unpacker {
|
static void tmate_header(struct tmate_session *session,
|
||||||
msgpack_object *argv;
|
|
||||||
int argc;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void decoder_error(void)
|
|
||||||
{
|
|
||||||
#ifdef DEBUG
|
|
||||||
tmate_print_trace();
|
|
||||||
#endif
|
|
||||||
tmate_fatal("Received a bad message");
|
|
||||||
}
|
|
||||||
|
|
||||||
static void init_unpacker(struct tmate_unpacker *uk,
|
|
||||||
msgpack_object obj)
|
|
||||||
{
|
|
||||||
if (obj.type != MSGPACK_OBJECT_ARRAY)
|
|
||||||
decoder_error();
|
|
||||||
|
|
||||||
uk->argv = obj.via.array.ptr;
|
|
||||||
uk->argc = obj.via.array.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int64_t unpack_int(struct tmate_unpacker *uk)
|
|
||||||
{
|
|
||||||
int64_t val;
|
|
||||||
|
|
||||||
if (uk->argc == 0)
|
|
||||||
decoder_error();
|
|
||||||
|
|
||||||
if (uk->argv[0].type != MSGPACK_OBJECT_POSITIVE_INTEGER &&
|
|
||||||
uk->argv[0].type != MSGPACK_OBJECT_NEGATIVE_INTEGER)
|
|
||||||
decoder_error();
|
|
||||||
|
|
||||||
val = uk->argv[0].via.i64;
|
|
||||||
|
|
||||||
uk->argv++;
|
|
||||||
uk->argc--;
|
|
||||||
|
|
||||||
return val;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void unpack_raw(struct tmate_unpacker *uk,
|
|
||||||
const char **buf, size_t *len)
|
|
||||||
{
|
|
||||||
if (uk->argc == 0)
|
|
||||||
decoder_error();
|
|
||||||
|
|
||||||
if (uk->argv[0].type != MSGPACK_OBJECT_RAW)
|
|
||||||
decoder_error();
|
|
||||||
|
|
||||||
*len = uk->argv[0].via.raw.size;
|
|
||||||
*buf = uk->argv[0].via.raw.ptr;
|
|
||||||
|
|
||||||
uk->argv++;
|
|
||||||
uk->argc--;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char *unpack_string(struct tmate_unpacker *uk)
|
|
||||||
{
|
|
||||||
const char *buf;
|
|
||||||
char *alloc_buf;
|
|
||||||
size_t len;
|
|
||||||
|
|
||||||
unpack_raw(uk, &buf, &len);
|
|
||||||
|
|
||||||
alloc_buf = xmalloc(len + 1);
|
|
||||||
memcpy(alloc_buf, buf, len);
|
|
||||||
alloc_buf[len] = '\0';
|
|
||||||
|
|
||||||
return alloc_buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void unpack_array(struct tmate_unpacker *uk,
|
|
||||||
struct tmate_unpacker *nested)
|
|
||||||
{
|
|
||||||
if (uk->argc == 0)
|
|
||||||
decoder_error();
|
|
||||||
|
|
||||||
init_unpacker(nested, uk->argv[0]);
|
|
||||||
|
|
||||||
uk->argv++;
|
|
||||||
uk->argc--;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define unpack_each(nested_uk, tmp_uk, uk) \
|
|
||||||
for (unpack_array(uk, tmp_uk); \
|
|
||||||
(tmp_uk)->argc > 0 && (init_unpacker(nested_uk, (tmp_uk)->argv[0]), 1); \
|
|
||||||
(tmp_uk)->argv++, (tmp_uk)->argc--)
|
|
||||||
|
|
||||||
static void tmate_header(struct tmate_decoder *decoder,
|
|
||||||
struct tmate_unpacker *uk)
|
struct tmate_unpacker *uk)
|
||||||
{
|
{
|
||||||
char port_arg[16] = {0};
|
char port_arg[16] = {0};
|
||||||
char *client_version = xstrdup("< 1.8.6");
|
char *client_version = xstrdup("< 1.8.6");
|
||||||
char tmp[512];
|
char tmp[512];
|
||||||
|
|
||||||
decoder->protocol = unpack_int(uk);
|
session->client_protocol_version = unpack_int(uk);
|
||||||
if (decoder->protocol >= 3) {
|
if (session->client_protocol_version >= 3) {
|
||||||
free(client_version);
|
free(client_version);
|
||||||
client_version = unpack_string(uk);
|
client_version = unpack_string(uk);
|
||||||
}
|
}
|
||||||
|
|
||||||
tmate_debug("new master, client version: %s, protocol version: %d",
|
tmate_debug("new master, client version: %s, protocol version: %d",
|
||||||
client_version, decoder->protocol);
|
client_version, session->client_protocol_version);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
if (strcmp(client_version, TMATE_LATEST_VERSION))
|
if (strcmp(client_version, TMATE_LATEST_VERSION))
|
||||||
@ -119,14 +29,14 @@ static void tmate_header(struct tmate_decoder *decoder,
|
|||||||
|
|
||||||
free(client_version);
|
free(client_version);
|
||||||
|
|
||||||
if (tmate_settings.ssh_port != 22)
|
if (tmate_settings->ssh_port != 22)
|
||||||
sprintf(port_arg, " -p%d", tmate_settings.ssh_port);
|
sprintf(port_arg, " -p%d", tmate_settings->ssh_port);
|
||||||
|
|
||||||
sprintf(tmp, "ssh%s ro-%s@%s", port_arg, tmate_session_token_ro, tmate_settings.tmate_host);
|
sprintf(tmp, "ssh%s ro-%s@%s", port_arg, session->session_token_ro, tmate_settings->tmate_host);
|
||||||
tmate_notify("Remote session read only: %s (clear your screen if you share this)", tmp);
|
tmate_notify("Remote session read only: %s (clear your screen if you share this)", tmp);
|
||||||
tmate_send_env("tmate_ssh_ro", tmp);
|
tmate_send_env("tmate_ssh_ro", tmp);
|
||||||
|
|
||||||
sprintf(tmp, "ssh%s %s@%s", port_arg, tmate_session_token, tmate_settings.tmate_host);
|
sprintf(tmp, "ssh%s %s@%s", port_arg, session->session_token, tmate_settings->tmate_host);
|
||||||
tmate_notify("Remote session: %s", tmp);
|
tmate_notify("Remote session: %s", tmp);
|
||||||
tmate_send_env("tmate_ssh", tmp);
|
tmate_send_env("tmate_ssh", tmp);
|
||||||
|
|
||||||
@ -231,7 +141,7 @@ static void tmate_sync_windows(struct session *s,
|
|||||||
server_redraw_window(wl->window);
|
server_redraw_window(wl->window);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tmate_sync_layout(struct tmate_decoder *decoder,
|
static void tmate_sync_layout(struct tmate_session *session,
|
||||||
struct tmate_unpacker *uk)
|
struct tmate_unpacker *uk)
|
||||||
{
|
{
|
||||||
struct session *s;
|
struct session *s;
|
||||||
@ -254,7 +164,7 @@ static void tmate_sync_layout(struct tmate_decoder *decoder,
|
|||||||
tmate_sync_windows(s, uk);
|
tmate_sync_windows(s, uk);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tmate_pty_data(struct tmate_decoder *decoder,
|
static void tmate_pty_data(struct tmate_session *session,
|
||||||
struct tmate_unpacker *uk)
|
struct tmate_unpacker *uk)
|
||||||
{
|
{
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
@ -263,7 +173,7 @@ static void tmate_pty_data(struct tmate_decoder *decoder,
|
|||||||
int id;
|
int id;
|
||||||
|
|
||||||
id = unpack_int(uk);
|
id = unpack_int(uk);
|
||||||
unpack_raw(uk, &buf, &len);
|
unpack_buffer(uk, &buf, &len);
|
||||||
|
|
||||||
wp = window_pane_find_by_id(id);
|
wp = window_pane_find_by_id(id);
|
||||||
if (!wp)
|
if (!wp)
|
||||||
@ -275,7 +185,7 @@ static void tmate_pty_data(struct tmate_decoder *decoder,
|
|||||||
wp->window->flags |= WINDOW_SILENCE;
|
wp->window->flags |= WINDOW_SILENCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tmate_exec_cmd(struct tmate_decoder *decoder,
|
static void tmate_exec_cmd(struct tmate_session *session,
|
||||||
struct tmate_unpacker *uk)
|
struct tmate_unpacker *uk)
|
||||||
{
|
{
|
||||||
struct cmd_q *cmd_q;
|
struct cmd_q *cmd_q;
|
||||||
@ -297,7 +207,7 @@ out:
|
|||||||
free(cmd_str);
|
free(cmd_str);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tmate_failed_cmd(struct tmate_decoder *decoder,
|
static void tmate_failed_cmd(struct tmate_session *session,
|
||||||
struct tmate_unpacker *uk)
|
struct tmate_unpacker *uk)
|
||||||
{
|
{
|
||||||
struct client *c;
|
struct client *c;
|
||||||
@ -320,7 +230,7 @@ static void tmate_failed_cmd(struct tmate_decoder *decoder,
|
|||||||
free(cause);
|
free(cause);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tmate_status(struct tmate_decoder *decoder,
|
static void tmate_status(struct tmate_session *session,
|
||||||
struct tmate_unpacker *uk)
|
struct tmate_unpacker *uk)
|
||||||
{
|
{
|
||||||
struct client *c;
|
struct client *c;
|
||||||
@ -342,7 +252,7 @@ extern void window_copy_redraw_screen(struct window_pane *);
|
|||||||
extern int window_copy_update_selection(struct window_pane *);
|
extern int window_copy_update_selection(struct window_pane *);
|
||||||
extern void window_copy_init_for_output(struct window_pane *);
|
extern void window_copy_init_for_output(struct window_pane *);
|
||||||
|
|
||||||
static void tmate_sync_copy_mode(struct tmate_decoder *decoder,
|
static void tmate_sync_copy_mode(struct tmate_session *session,
|
||||||
struct tmate_unpacker *uk)
|
struct tmate_unpacker *uk)
|
||||||
{
|
{
|
||||||
struct tmate_unpacker cm_uk, sel_uk, input_uk;
|
struct tmate_unpacker cm_uk, sel_uk, input_uk;
|
||||||
@ -368,7 +278,7 @@ static void tmate_sync_copy_mode(struct tmate_decoder *decoder,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (decoder->protocol >= 2)
|
if (session->client_protocol_version >= 2)
|
||||||
base_backing = unpack_int(&cm_uk);
|
base_backing = unpack_int(&cm_uk);
|
||||||
|
|
||||||
if (window_pane_set_mode(wp, &window_copy_mode) == 0) {
|
if (window_pane_set_mode(wp, &window_copy_mode) == 0) {
|
||||||
@ -388,7 +298,7 @@ static void tmate_sync_copy_mode(struct tmate_decoder *decoder,
|
|||||||
if (sel_uk.argc) {
|
if (sel_uk.argc) {
|
||||||
data->screen.sel.flag = 1;
|
data->screen.sel.flag = 1;
|
||||||
data->selx = unpack_int(&sel_uk);
|
data->selx = unpack_int(&sel_uk);
|
||||||
if (decoder->protocol >= 2) {
|
if (session->client_protocol_version >= 2) {
|
||||||
data->sely = -unpack_int(&sel_uk) + screen_hsize(data->backing)
|
data->sely = -unpack_int(&sel_uk) + screen_hsize(data->backing)
|
||||||
+ screen_size_y(data->backing)
|
+ screen_size_y(data->backing)
|
||||||
- 1;
|
- 1;
|
||||||
@ -424,7 +334,7 @@ static void tmate_sync_copy_mode(struct tmate_decoder *decoder,
|
|||||||
window_copy_redraw_screen(wp);
|
window_copy_redraw_screen(wp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tmate_write_copy_mode(struct tmate_decoder *decoder,
|
static void tmate_write_copy_mode(struct tmate_session *session,
|
||||||
struct tmate_unpacker *uk)
|
struct tmate_unpacker *uk)
|
||||||
{
|
{
|
||||||
struct window_pane *wp;
|
struct window_pane *wp;
|
||||||
@ -445,70 +355,21 @@ static void tmate_write_copy_mode(struct tmate_decoder *decoder,
|
|||||||
free(str);
|
free(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_message(struct tmate_decoder *decoder, msgpack_object obj)
|
void tmate_dispatch_daemon_message(struct tmate_session *session,
|
||||||
|
struct tmate_unpacker *uk)
|
||||||
{
|
{
|
||||||
struct tmate_unpacker _uk;
|
#define dispatch(c, f) case c: f(session, uk); break
|
||||||
struct tmate_unpacker *uk = &_uk;
|
|
||||||
int cmd;
|
|
||||||
|
|
||||||
init_unpacker(uk, obj);
|
|
||||||
|
|
||||||
cmd = unpack_int(uk);
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
/* Really verbose tracers */
|
|
||||||
if (cmd != TMATE_PTY_DATA) {
|
|
||||||
msgpack_object_print(stderr, obj);
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
int cmd = unpack_int(uk);
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
case TMATE_HEADER: tmate_header(decoder, uk); break;
|
dispatch(TMATE_HEADER, tmate_header);
|
||||||
case TMATE_SYNC_LAYOUT: tmate_sync_layout(decoder, uk); break;
|
dispatch(TMATE_SYNC_LAYOUT, tmate_sync_layout);
|
||||||
case TMATE_PTY_DATA: tmate_pty_data(decoder, uk); break;
|
dispatch(TMATE_PTY_DATA, tmate_pty_data);
|
||||||
case TMATE_EXEC_CMD: tmate_exec_cmd(decoder, uk); break;
|
dispatch(TMATE_EXEC_CMD, tmate_exec_cmd);
|
||||||
case TMATE_FAILED_CMD: tmate_failed_cmd(decoder, uk); break;
|
dispatch(TMATE_FAILED_CMD, tmate_failed_cmd);
|
||||||
case TMATE_STATUS: tmate_status(decoder, uk); break;
|
dispatch(TMATE_STATUS, tmate_status);
|
||||||
case TMATE_SYNC_COPY_MODE: tmate_sync_copy_mode(decoder, uk); break;
|
dispatch(TMATE_SYNC_COPY_MODE, tmate_sync_copy_mode);
|
||||||
case TMATE_WRITE_COPY_MODE: tmate_write_copy_mode(decoder, uk); break;
|
dispatch(TMATE_WRITE_COPY_MODE, tmate_write_copy_mode);
|
||||||
default: decoder_error();
|
default: tmate_fatal("Bad message type: %d", cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tmate_decoder_commit(struct tmate_decoder *decoder, size_t len)
|
|
||||||
{
|
|
||||||
msgpack_unpacked result;
|
|
||||||
|
|
||||||
msgpack_unpacker_buffer_consumed(&decoder->unpacker, len);
|
|
||||||
|
|
||||||
msgpack_unpacked_init(&result);
|
|
||||||
while (msgpack_unpacker_next(&decoder->unpacker, &result)) {
|
|
||||||
handle_message(decoder, result.data);
|
|
||||||
}
|
|
||||||
msgpack_unpacked_destroy(&result);
|
|
||||||
|
|
||||||
if (msgpack_unpacker_message_size(&decoder->unpacker) >
|
|
||||||
TMATE_MAX_MESSAGE_SIZE) {
|
|
||||||
tmate_fatal("Message too big");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void tmate_decoder_get_buffer(struct tmate_decoder *decoder,
|
|
||||||
char **buf, size_t *len)
|
|
||||||
{
|
|
||||||
/* rewind the buffer if possible */
|
|
||||||
if (msgpack_unpacker_buffer_capacity(&decoder->unpacker) <
|
|
||||||
TMATE_MAX_MESSAGE_SIZE) {
|
|
||||||
msgpack_unpacker_expand_buffer(&decoder->unpacker, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
*buf = msgpack_unpacker_buffer(&decoder->unpacker);
|
|
||||||
*len = msgpack_unpacker_buffer_capacity(&decoder->unpacker);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tmate_decoder_init(struct tmate_decoder *decoder)
|
|
||||||
{
|
|
||||||
if (!msgpack_unpacker_init(&decoder->unpacker, 2*TMATE_MAX_MESSAGE_SIZE))
|
|
||||||
tmate_fatal("cannot initialize the unpacker");
|
|
||||||
}
|
|
@ -1,36 +1,6 @@
|
|||||||
#include "tmate.h"
|
#include "tmate.h"
|
||||||
|
|
||||||
static int msgpack_write(void *data, const char *buf, unsigned int len)
|
#define pack(what, ...) _pack(&tmate_session->client_encoder, what, __VA_ARGS__)
|
||||||
{
|
|
||||||
struct tmate_encoder *encoder = data;
|
|
||||||
|
|
||||||
evbuffer_add(encoder->buffer, buf, len);
|
|
||||||
|
|
||||||
if ((encoder->ev_readable.ev_flags & EVLIST_INSERTED) &&
|
|
||||||
!(encoder->ev_readable.ev_flags & EVLIST_ACTIVE)) {
|
|
||||||
event_active(&encoder->ev_readable, EV_READ, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void tmate_encoder_init(struct tmate_encoder *encoder)
|
|
||||||
{
|
|
||||||
encoder->buffer = evbuffer_new();
|
|
||||||
msgpack_packer_init(&encoder->pk, encoder, &msgpack_write);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define msgpack_pack_string(pk, str) do { \
|
|
||||||
int __strlen = strlen(str); \
|
|
||||||
msgpack_pack_raw(pk, __strlen); \
|
|
||||||
msgpack_pack_raw_body(pk, str, __strlen); \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
/* tmate_encoder may be NULL when replaying a session */
|
|
||||||
#define pack(what, ...) do { \
|
|
||||||
if (tmate_encoder) \
|
|
||||||
msgpack_pack_##what(&tmate_encoder->pk, __VA_ARGS__); \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
static void __tmate_notify(const char *msg)
|
static void __tmate_notify(const char *msg)
|
||||||
{
|
{
|
||||||
@ -75,9 +45,9 @@ void printflike2 tmate_notify_later(int timeout, const char *fmt, ...)
|
|||||||
* multiple times.
|
* multiple times.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
evtimer_assign(&tmate_encoder->ev_notify_timer, ev_base,
|
evtimer_assign(&tmate_session->ev_notify_timer, ev_base,
|
||||||
__tmate_notify_later, msg);
|
__tmate_notify_later, msg);
|
||||||
evtimer_add(&tmate_encoder->ev_notify_timer, &tv);
|
evtimer_add(&tmate_session->ev_notify_timer, &tv);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int num_clients(void)
|
static int num_clients(void)
|
||||||
@ -127,7 +97,7 @@ void tmate_notify_client_left(struct client *c)
|
|||||||
|
|
||||||
void tmate_send_client_ready(void)
|
void tmate_send_client_ready(void)
|
||||||
{
|
{
|
||||||
if (tmate_decoder && tmate_decoder->protocol < 4)
|
if (tmate_session->client_protocol_version < 4)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pack(array, 1);
|
pack(array, 1);
|
||||||
@ -136,7 +106,7 @@ void tmate_send_client_ready(void)
|
|||||||
|
|
||||||
void tmate_send_env(const char *name, const char *value)
|
void tmate_send_env(const char *name, const char *value)
|
||||||
{
|
{
|
||||||
if (tmate_decoder && tmate_decoder->protocol < 4)
|
if (tmate_session->client_protocol_version < 4)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pack(array, 3);
|
pack(array, 3);
|
@ -52,7 +52,7 @@ static int print_resolved_stack_frame(const char *frame)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void tmate_print_trace(void)
|
void tmate_print_stack_trace(void)
|
||||||
{
|
{
|
||||||
void *array[20];
|
void *array[20];
|
||||||
size_t size;
|
size_t size;
|
||||||
|
164
tmate-msgpack.c
Normal file
164
tmate-msgpack.c
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
#include "tmate.h"
|
||||||
|
|
||||||
|
static void on_encoder_buffer_ready(evutil_socket_t fd, short what, void *arg)
|
||||||
|
{
|
||||||
|
struct tmate_encoder *encoder = arg;
|
||||||
|
|
||||||
|
encoder->ev_active = false;
|
||||||
|
encoder->ready_callback(encoder->userdata, encoder->buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int on_encoder_write(void *userdata, const char *buf, unsigned int len)
|
||||||
|
{
|
||||||
|
struct tmate_encoder *encoder = userdata;
|
||||||
|
|
||||||
|
if (evbuffer_add(encoder->buffer, buf, len) < 0)
|
||||||
|
tmate_fatal("Cannot buffer encoded data");
|
||||||
|
|
||||||
|
if (!encoder->ev_active) {
|
||||||
|
event_active(&encoder->ev_buffer, EV_READ, 0);
|
||||||
|
encoder->ev_active = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tmate_encoder_init(struct tmate_encoder *encoder,
|
||||||
|
tmate_encoder_write_cb *callback,
|
||||||
|
void *userdata)
|
||||||
|
{
|
||||||
|
msgpack_packer_init(&encoder->pk, encoder, &on_encoder_write);
|
||||||
|
encoder->buffer = evbuffer_new();
|
||||||
|
encoder->ready_callback = callback;
|
||||||
|
encoder->userdata = userdata;
|
||||||
|
|
||||||
|
if (!encoder->buffer)
|
||||||
|
tmate_fatal("Can't allocate buffer");
|
||||||
|
|
||||||
|
event_assign(&encoder->ev_buffer, ev_base, -1,
|
||||||
|
EV_READ | EV_PERSIST, on_encoder_buffer_ready, encoder);
|
||||||
|
|
||||||
|
event_add(&encoder->ev_buffer, NULL);
|
||||||
|
|
||||||
|
encoder->ev_active = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void decoder_error(void)
|
||||||
|
{
|
||||||
|
tmate_print_stack_trace();
|
||||||
|
tmate_fatal("Received a bad message");
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_unpacker(struct tmate_unpacker *uk, msgpack_object obj)
|
||||||
|
{
|
||||||
|
if (obj.type != MSGPACK_OBJECT_ARRAY)
|
||||||
|
decoder_error();
|
||||||
|
|
||||||
|
uk->argv = obj.via.array.ptr;
|
||||||
|
uk->argc = obj.via.array.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t unpack_int(struct tmate_unpacker *uk)
|
||||||
|
{
|
||||||
|
int64_t val;
|
||||||
|
|
||||||
|
if (uk->argc == 0)
|
||||||
|
decoder_error();
|
||||||
|
|
||||||
|
if (uk->argv[0].type != MSGPACK_OBJECT_POSITIVE_INTEGER &&
|
||||||
|
uk->argv[0].type != MSGPACK_OBJECT_NEGATIVE_INTEGER)
|
||||||
|
decoder_error();
|
||||||
|
|
||||||
|
val = uk->argv[0].via.i64;
|
||||||
|
|
||||||
|
uk->argv++;
|
||||||
|
uk->argc--;
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unpack_buffer(struct tmate_unpacker *uk, const char **buf, size_t *len)
|
||||||
|
{
|
||||||
|
if (uk->argc == 0)
|
||||||
|
decoder_error();
|
||||||
|
|
||||||
|
#if NEW_MSGPACK_API
|
||||||
|
if (uk->argv[0].type != MSGPACK_OBJECT_STR &&
|
||||||
|
uk->argv[0].type != MSGPACK_OBJECT_BIN)
|
||||||
|
decoder_error();
|
||||||
|
|
||||||
|
*len = uk->argv[0].via.str.size;
|
||||||
|
*buf = uk->argv[0].via.str.ptr;
|
||||||
|
#else
|
||||||
|
if (uk->argv[0].type != MSGPACK_OBJECT_RAW)
|
||||||
|
decoder_error();
|
||||||
|
|
||||||
|
*len = uk->argv[0].via.raw.size;
|
||||||
|
*buf = uk->argv[0].via.raw.ptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
uk->argv++;
|
||||||
|
uk->argc--;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *unpack_string(struct tmate_unpacker *uk)
|
||||||
|
{
|
||||||
|
const char *buf;
|
||||||
|
char *alloc_buf;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
unpack_buffer(uk, &buf, &len);
|
||||||
|
|
||||||
|
alloc_buf = xmalloc(len + 1);
|
||||||
|
memcpy(alloc_buf, buf, len);
|
||||||
|
alloc_buf[len] = '\0';
|
||||||
|
|
||||||
|
return alloc_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
void unpack_array(struct tmate_unpacker *uk, struct tmate_unpacker *nested)
|
||||||
|
{
|
||||||
|
if (uk->argc == 0)
|
||||||
|
decoder_error();
|
||||||
|
|
||||||
|
init_unpacker(nested, uk->argv[0]);
|
||||||
|
|
||||||
|
uk->argv++;
|
||||||
|
uk->argc--;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tmate_decoder_init(struct tmate_decoder *decoder, tmate_decoder_reader *reader,
|
||||||
|
void *userdata)
|
||||||
|
{
|
||||||
|
if (!msgpack_unpacker_init(&decoder->unpacker, TMATE_MAX_MESSAGE_SIZE))
|
||||||
|
tmate_fatal("Cannot initialize the unpacker");
|
||||||
|
decoder->reader = reader;
|
||||||
|
decoder->userdata = userdata;
|
||||||
|
}
|
||||||
|
|
||||||
|
void tmate_decoder_get_buffer(struct tmate_decoder *decoder,
|
||||||
|
char **buf, size_t *len)
|
||||||
|
{
|
||||||
|
ssize_t current_size = msgpack_unpacker_message_size(&decoder->unpacker);
|
||||||
|
if (!msgpack_unpacker_reserve_buffer(&decoder->unpacker,
|
||||||
|
TMATE_MAX_MESSAGE_SIZE - current_size))
|
||||||
|
tmate_fatal("cannot expand decoder buffer");
|
||||||
|
|
||||||
|
*buf = msgpack_unpacker_buffer(&decoder->unpacker);
|
||||||
|
*len = msgpack_unpacker_buffer_capacity(&decoder->unpacker);
|
||||||
|
}
|
||||||
|
|
||||||
|
void tmate_decoder_commit(struct tmate_decoder *decoder, size_t len)
|
||||||
|
{
|
||||||
|
struct tmate_unpacker _uk, *uk = &_uk;
|
||||||
|
msgpack_unpacked result;
|
||||||
|
|
||||||
|
msgpack_unpacker_buffer_consumed(&decoder->unpacker, len);
|
||||||
|
|
||||||
|
msgpack_unpacked_init(&result);
|
||||||
|
while (msgpack_unpacker_next(&decoder->unpacker, &result)) {
|
||||||
|
init_unpacker(uk, result.data);
|
||||||
|
decoder->reader(decoder->userdata, uk);
|
||||||
|
}
|
||||||
|
msgpack_unpacked_destroy(&result);
|
||||||
|
}
|
139
tmate-slave.c
139
tmate-slave.c
@ -16,13 +16,10 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/syslog.h>
|
#include <sys/syslog.h>
|
||||||
|
#include <sched.h>
|
||||||
#include "tmate.h"
|
#include "tmate.h"
|
||||||
|
|
||||||
struct tmate_decoder *tmate_decoder;
|
struct tmate_session _tmate_session, *tmate_session = &_tmate_session;
|
||||||
struct tmate_encoder *tmate_encoder;
|
|
||||||
int tmux_socket_fd;
|
|
||||||
const char *tmate_session_token;
|
|
||||||
const char *tmate_session_token_ro;
|
|
||||||
|
|
||||||
extern FILE *log_file;
|
extern FILE *log_file;
|
||||||
|
|
||||||
@ -33,7 +30,7 @@ static int dev_urandom_fd;
|
|||||||
extern int server_create_socket(void);
|
extern int server_create_socket(void);
|
||||||
extern int client_connect(char *path, int start_server);
|
extern int client_connect(char *path, int start_server);
|
||||||
|
|
||||||
struct tmate_settings tmate_settings = {
|
struct tmate_settings _tmate_settings = {
|
||||||
.keys_dir = TMATE_SSH_DEFAULT_KEYS_DIR,
|
.keys_dir = TMATE_SSH_DEFAULT_KEYS_DIR,
|
||||||
.ssh_port = TMATE_SSH_DEFAULT_PORT,
|
.ssh_port = TMATE_SSH_DEFAULT_PORT,
|
||||||
.master_hostname = TMATE_DEFAULT_MASTER_HOST,
|
.master_hostname = TMATE_DEFAULT_MASTER_HOST,
|
||||||
@ -43,6 +40,8 @@ struct tmate_settings tmate_settings = {
|
|||||||
.use_syslog = false,
|
.use_syslog = false,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct tmate_settings *tmate_settings = &_tmate_settings;
|
||||||
|
|
||||||
static void usage(void)
|
static void usage(void)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "usage: tmate-slave [-k keys_dir] [-p port] [-m master_hostname] [-q master_port] [-s] [-v]\n");
|
fprintf(stderr, "usage: tmate-slave [-k keys_dir] [-p port] [-m master_hostname] [-q master_port] [-s] [-v]\n");
|
||||||
@ -61,6 +60,18 @@ long tmate_get_random_long(void)
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern int server_shutdown;
|
||||||
|
extern int server_fd;
|
||||||
|
extern void server_send_shutdown(void);
|
||||||
|
void request_server_termination(void)
|
||||||
|
{
|
||||||
|
if (server_fd) {
|
||||||
|
server_shutdown = 1;
|
||||||
|
server_send_shutdown();
|
||||||
|
} else
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv, char **envp)
|
int main(int argc, char **argv, char **envp)
|
||||||
{
|
{
|
||||||
int opt;
|
int opt;
|
||||||
@ -68,25 +79,25 @@ int main(int argc, char **argv, char **envp)
|
|||||||
while ((opt = getopt(argc, argv, "k:p:lvm:q:")) != -1) {
|
while ((opt = getopt(argc, argv, "k:p:lvm:q:")) != -1) {
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case 'p':
|
case 'p':
|
||||||
tmate_settings.ssh_port = atoi(optarg);
|
tmate_settings->ssh_port = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 'k':
|
case 'k':
|
||||||
tmate_settings.keys_dir = xstrdup(optarg);
|
tmate_settings->keys_dir = xstrdup(optarg);
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
tmate_settings.use_syslog = true;
|
tmate_settings->use_syslog = true;
|
||||||
break;
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
tmate_settings.log_level++;
|
tmate_settings->log_level++;
|
||||||
break;
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
tmate_settings.master_hostname = xstrdup(optarg);
|
tmate_settings->master_hostname = xstrdup(optarg);
|
||||||
break;
|
break;
|
||||||
case 'q':
|
case 'q':
|
||||||
tmate_settings.master_port = atoi(optarg);
|
tmate_settings->master_port = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
tmate_settings.tmate_host = xstrdup(optarg);
|
tmate_settings->tmate_host = xstrdup(optarg);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
@ -94,18 +105,18 @@ int main(int argc, char **argv, char **envp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tmate_settings.tmate_host) {
|
if (!tmate_settings->tmate_host) {
|
||||||
char hostname[255];
|
char hostname[255];
|
||||||
if (gethostname(hostname, sizeof(hostname)) < 0)
|
if (gethostname(hostname, sizeof(hostname)) < 0)
|
||||||
tmate_fatal("cannot get hostname");
|
tmate_fatal("cannot get hostname");
|
||||||
tmate_settings.tmate_host = xstrdup(hostname);
|
tmate_settings->tmate_host = xstrdup(hostname);
|
||||||
}
|
}
|
||||||
|
|
||||||
cmdline = *argv;
|
cmdline = *argv;
|
||||||
cmdline_end = *envp;
|
cmdline_end = *envp;
|
||||||
|
|
||||||
init_logging("tmate-ssh",
|
init_logging("tmate-ssh",
|
||||||
tmate_settings.use_syslog, tmate_settings.log_level);
|
tmate_settings->use_syslog, tmate_settings->log_level);
|
||||||
|
|
||||||
tmate_preload_trace_lib();
|
tmate_preload_trace_lib();
|
||||||
|
|
||||||
@ -117,7 +128,8 @@ int main(int argc, char **argv, char **envp)
|
|||||||
(mkdir(TMATE_WORKDIR "/jail", 0700) < 0 && errno != EEXIST))
|
(mkdir(TMATE_WORKDIR "/jail", 0700) < 0 && errno != EEXIST))
|
||||||
tmate_fatal("Cannot prepare session in " TMATE_WORKDIR);
|
tmate_fatal("Cannot prepare session in " TMATE_WORKDIR);
|
||||||
|
|
||||||
tmate_ssh_server_main(tmate_settings.keys_dir, tmate_settings.ssh_port);
|
tmate_ssh_server_main(tmate_session,
|
||||||
|
tmate_settings->keys_dir, tmate_settings->ssh_port);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,33 +151,33 @@ static char *get_random_token(void)
|
|||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_session_token(struct tmate_ssh_client *client,
|
static void set_session_token(struct tmate_session *session,
|
||||||
const char *token)
|
const char *token)
|
||||||
{
|
{
|
||||||
tmate_session_token = xstrdup(token);
|
session->session_token = xstrdup(token);
|
||||||
strcpy(socket_path, TMATE_WORKDIR "/sessions/");
|
strcpy(socket_path, TMATE_WORKDIR "/sessions/");
|
||||||
strcat(socket_path, token);
|
strcat(socket_path, token);
|
||||||
|
|
||||||
memset(cmdline, 0, cmdline_end - cmdline);
|
memset(cmdline, 0, cmdline_end - cmdline);
|
||||||
sprintf(cmdline, "tmate-slave [%s] %s %s",
|
sprintf(cmdline, "tmate-slave [%s] %s %s",
|
||||||
tmate_session_token,
|
session->session_token,
|
||||||
client->role == TMATE_ROLE_SERVER ? "(server)" : "(client)",
|
session->ssh_client.role == TMATE_ROLE_SERVER ? "(server)" : "(client)",
|
||||||
client->ip_address);
|
session->ssh_client.ip_address);
|
||||||
}
|
}
|
||||||
static void create_session_ro_symlink(void)
|
static void create_session_ro_symlink(struct tmate_session *session)
|
||||||
{
|
{
|
||||||
char session_ro_path[MAXPATHLEN];
|
char session_ro_path[MAXPATHLEN];
|
||||||
|
|
||||||
tmate_session_token_ro = get_random_token();
|
session->session_token_ro = get_random_token();
|
||||||
#ifdef DEVENV
|
#ifdef DEVENV
|
||||||
strcpy((char *)tmate_session_token_ro, "READONLYTOKENFORDEVENV000");
|
strcpy((char *)session->session_token_ro, "READONLYTOKENFORDEVENV000");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
strcpy(session_ro_path, TMATE_WORKDIR "/sessions/");
|
strcpy(session_ro_path, TMATE_WORKDIR "/sessions/");
|
||||||
strcat(session_ro_path, tmate_session_token_ro);
|
strcat(session_ro_path, session->session_token_ro);
|
||||||
|
|
||||||
unlink(session_ro_path);
|
unlink(session_ro_path);
|
||||||
if (symlink(tmate_session_token, session_ro_path) < 0)
|
if (symlink(session->session_token, session_ro_path) < 0)
|
||||||
tmate_fatal("Cannot create read-only symlink");
|
tmate_fatal("Cannot create read-only symlink");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -250,9 +262,8 @@ static void jail(void)
|
|||||||
uid = pw->pw_uid;
|
uid = pw->pw_uid;
|
||||||
gid = pw->pw_gid;
|
gid = pw->pw_gid;
|
||||||
|
|
||||||
/*
|
if (getuid() != 0)
|
||||||
* We are already in a new PID namespace (from the server fork).
|
tmate_fatal("Need root priviledges");
|
||||||
*/
|
|
||||||
|
|
||||||
if (chroot(TMATE_WORKDIR "/jail") < 0)
|
if (chroot(TMATE_WORKDIR "/jail") < 0)
|
||||||
tmate_fatal("Cannot chroot()");
|
tmate_fatal("Cannot chroot()");
|
||||||
@ -260,6 +271,9 @@ static void jail(void)
|
|||||||
if (chdir("/") < 0)
|
if (chdir("/") < 0)
|
||||||
tmate_fatal("Cannot chdir()");
|
tmate_fatal("Cannot chdir()");
|
||||||
|
|
||||||
|
if (unshare(CLONE_NEWPID | CLONE_NEWIPC | CLONE_NEWNS | CLONE_NEWNET) < 0)
|
||||||
|
tmate_fatal("Cannot create new namespace");
|
||||||
|
|
||||||
if (setgroups(1, (gid_t[]){gid}) < 0)
|
if (setgroups(1, (gid_t[]){gid}) < 0)
|
||||||
tmate_fatal("Cannot setgroups()");
|
tmate_fatal("Cannot setgroups()");
|
||||||
|
|
||||||
@ -272,8 +286,8 @@ static void jail(void)
|
|||||||
if (nice(1) < 0)
|
if (nice(1) < 0)
|
||||||
tmate_fatal("Cannot nice()");
|
tmate_fatal("Cannot nice()");
|
||||||
|
|
||||||
tmate_debug("Dropped priviledges to %s (%d,%d)",
|
tmate_debug("Dropped priviledges to %s (%d,%d), jailed in %s",
|
||||||
TMATE_JAIL_USER, uid, gid);
|
TMATE_JAIL_USER, uid, gid, TMATE_WORKDIR "/jail");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setup_ncurse(int fd, const char *name)
|
static void setup_ncurse(int fd, const char *name)
|
||||||
@ -283,8 +297,10 @@ static void setup_ncurse(int fd, const char *name)
|
|||||||
tmate_fatal("Cannot setup terminal");
|
tmate_fatal("Cannot setup terminal");
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tmate_spawn_slave_server(struct tmate_ssh_client *client)
|
static void tmate_spawn_slave_server(struct tmate_session *session)
|
||||||
{
|
{
|
||||||
|
struct tmate_ssh_client *client = &session->ssh_client;
|
||||||
|
|
||||||
char *token;
|
char *token;
|
||||||
struct tmate_encoder encoder;
|
struct tmate_encoder encoder;
|
||||||
struct tmate_decoder decoder;
|
struct tmate_decoder decoder;
|
||||||
@ -294,17 +310,17 @@ static void tmate_spawn_slave_server(struct tmate_ssh_client *client)
|
|||||||
strcpy(token, "SUPERSECURETOKENFORDEVENV");
|
strcpy(token, "SUPERSECURETOKENFORDEVENV");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
set_session_token(client, token);
|
set_session_token(session, token);
|
||||||
free(token);
|
free(token);
|
||||||
|
|
||||||
tmate_debug("Spawning slave server for %s at %s (%s)",
|
tmate_debug("Spawning slave server for %s at %s (%s)",
|
||||||
client->username, client->ip_address, client->pubkey);
|
client->username, client->ip_address, client->pubkey);
|
||||||
|
|
||||||
tmux_socket_fd = server_create_socket();
|
session->tmux_socket_fd = server_create_socket();
|
||||||
if (tmux_socket_fd < 0)
|
if (session->tmux_socket_fd < 0)
|
||||||
tmate_fatal("Cannot create to the tmux socket");
|
tmate_fatal("Cannot create to the tmux socket");
|
||||||
|
|
||||||
create_session_ro_symlink();
|
create_session_ro_symlink(session);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Needed to initialize the database used in tty-term.c.
|
* Needed to initialize the database used in tty-term.c.
|
||||||
@ -312,27 +328,23 @@ static void tmate_spawn_slave_server(struct tmate_ssh_client *client)
|
|||||||
*/
|
*/
|
||||||
setup_ncurse(STDOUT_FILENO, "screen-256color");
|
setup_ncurse(STDOUT_FILENO, "screen-256color");
|
||||||
|
|
||||||
close_fds_except((int[]){tmux_socket_fd,
|
close_fds_except((int[]){session->tmux_socket_fd,
|
||||||
ssh_get_fd(client->session),
|
ssh_get_fd(session->ssh_client.session),
|
||||||
log_file ? fileno(log_file) : -1}, 3);
|
log_file ? fileno(log_file) : -1}, 3);
|
||||||
|
|
||||||
jail();
|
jail();
|
||||||
|
|
||||||
ev_base = osdep_event_init();
|
event_reinit(ev_base);
|
||||||
|
|
||||||
tmate_encoder_init(&encoder);
|
tmate_daemon_init(session);
|
||||||
tmate_decoder_init(&decoder);
|
|
||||||
tmate_encoder = &encoder;
|
|
||||||
tmate_decoder = &decoder;
|
|
||||||
|
|
||||||
tmate_ssh_client_init(client, &encoder, &decoder);
|
|
||||||
|
|
||||||
tmux_server_init(IDENTIFY_UTF8 | IDENTIFY_256COLOURS);
|
tmux_server_init(IDENTIFY_UTF8 | IDENTIFY_256COLOURS);
|
||||||
/* never reached */
|
/* never reached */
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tmate_spawn_slave_client(struct tmate_ssh_client *client)
|
static void tmate_spawn_slave_client(struct tmate_session *session)
|
||||||
{
|
{
|
||||||
|
struct tmate_ssh_client *client = &session->ssh_client;
|
||||||
char *argv_rw[] = {(char *)"attach", NULL};
|
char *argv_rw[] = {(char *)"attach", NULL};
|
||||||
char *argv_ro[] = {(char *)"attach", (char *)"-r", NULL};
|
char *argv_ro[] = {(char *)"attach", (char *)"-r", NULL};
|
||||||
char **argv = argv_rw;
|
char **argv = argv_rw;
|
||||||
@ -351,13 +363,13 @@ static void tmate_spawn_slave_client(struct tmate_ssh_client *client)
|
|||||||
tmate_fatal("Invalid token");
|
tmate_fatal("Invalid token");
|
||||||
}
|
}
|
||||||
|
|
||||||
set_session_token(client, token);
|
set_session_token(session, token);
|
||||||
|
|
||||||
tmate_debug("Spawning slave client for %s (%s)",
|
tmate_debug("Spawning slave client for %s (%s)",
|
||||||
client->ip_address, client->pubkey);
|
client->ip_address, client->pubkey);
|
||||||
|
|
||||||
tmux_socket_fd = client_connect(socket_path, 0);
|
session->tmux_socket_fd = client_connect(socket_path, 0);
|
||||||
if (tmux_socket_fd < 0) {
|
if (session->tmux_socket_fd < 0) {
|
||||||
random_sleep(); /* for making timing attacks harder */
|
random_sleep(); /* for making timing attacks harder */
|
||||||
ssh_echo(client, EXPIRED_TOKEN_ERROR_STR);
|
ssh_echo(client, EXPIRED_TOKEN_ERROR_STR);
|
||||||
tmate_fatal("Expired token");
|
tmate_fatal("Expired token");
|
||||||
@ -370,16 +382,16 @@ static void tmate_spawn_slave_client(struct tmate_ssh_client *client)
|
|||||||
* 2) We prevent any input (aside from the window size) to go through
|
* 2) We prevent any input (aside from the window size) to go through
|
||||||
* to the server.
|
* to the server.
|
||||||
*/
|
*/
|
||||||
client->readonly = 0;
|
session->readonly = false;
|
||||||
if (lstat(socket_path, &fstat) < 0)
|
if (lstat(socket_path, &fstat) < 0)
|
||||||
tmate_fatal("Cannot fstat()");
|
tmate_fatal("Cannot fstat()");
|
||||||
if (S_ISLNK(fstat.st_mode)) {
|
if (S_ISLNK(fstat.st_mode)) {
|
||||||
client->readonly = 1;
|
session->readonly = true;
|
||||||
argv = argv_ro;
|
argv = argv_ro;
|
||||||
argc = 2;
|
argc = 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (openpty(&client->pty, &slave_pty, NULL, NULL, NULL) < 0)
|
if (openpty(&session->pty, &slave_pty, NULL, NULL, NULL) < 0)
|
||||||
tmate_fatal("Cannot allocate pty");
|
tmate_fatal("Cannot allocate pty");
|
||||||
|
|
||||||
dup2(slave_pty, STDIN_FILENO);
|
dup2(slave_pty, STDIN_FILENO);
|
||||||
@ -388,23 +400,24 @@ static void tmate_spawn_slave_client(struct tmate_ssh_client *client)
|
|||||||
|
|
||||||
setup_ncurse(slave_pty, "screen-256color");
|
setup_ncurse(slave_pty, "screen-256color");
|
||||||
close_fds_except((int[]){STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO,
|
close_fds_except((int[]){STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO,
|
||||||
tmux_socket_fd, ssh_get_fd(client->session),
|
session->tmux_socket_fd,
|
||||||
client->pty, log_file ? fileno(log_file) : -1}, 7);
|
ssh_get_fd(session->ssh_client.session),
|
||||||
|
session->pty, log_file ? fileno(log_file) : -1}, 7);
|
||||||
jail();
|
jail();
|
||||||
|
event_reinit(ev_base);
|
||||||
|
|
||||||
ev_base = osdep_event_init();
|
tmate_ssh_client_pty_init(session);
|
||||||
|
|
||||||
tmate_ssh_client_pty_init(client);
|
|
||||||
|
|
||||||
ret = client_main(argc, argv, IDENTIFY_UTF8 | IDENTIFY_256COLOURS);
|
ret = client_main(argc, argv, IDENTIFY_UTF8 | IDENTIFY_256COLOURS);
|
||||||
tmate_flush_pty(client);
|
tmate_flush_pty(session);
|
||||||
exit(ret);
|
exit(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tmate_spawn_slave(struct tmate_ssh_client *client)
|
void tmate_spawn_slave(struct tmate_session *session)
|
||||||
{
|
{
|
||||||
if (client->role == TMATE_ROLE_SERVER)
|
|
||||||
tmate_spawn_slave_server(client);
|
if (session->ssh_client.role == TMATE_ROLE_SERVER)
|
||||||
|
tmate_spawn_slave_server(session);
|
||||||
else
|
else
|
||||||
tmate_spawn_slave_client(client);
|
tmate_spawn_slave_client(session);
|
||||||
}
|
}
|
||||||
|
@ -1,62 +1,40 @@
|
|||||||
#include <libssh/libssh.h>
|
|
||||||
#include <libssh/server.h>
|
#include <libssh/server.h>
|
||||||
#include <libssh/callbacks.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include "tmate.h"
|
#include "tmate.h"
|
||||||
|
|
||||||
extern void client_write_server(enum msgtype type, void *buf, size_t len);
|
extern void client_write_server(enum msgtype type, void *buf, size_t len);
|
||||||
|
|
||||||
static void consume_channel(struct tmate_ssh_client *client)
|
static int on_ssh_channel_read(ssh_session _session, ssh_channel channel,
|
||||||
|
void *_data, uint32_t total_len,
|
||||||
|
int is_stderr, void *userdata)
|
||||||
{
|
{
|
||||||
ssize_t len, written;
|
struct tmate_session *session = userdata;
|
||||||
char buf[4096];
|
char *data = _data;
|
||||||
char *ptr;
|
size_t written = 0;
|
||||||
|
ssize_t len;
|
||||||
|
|
||||||
for (;;) {
|
if (session->readonly)
|
||||||
len = ssh_channel_read_nonblocking(client->channel,
|
return total_len;
|
||||||
buf, sizeof(buf), 0);
|
|
||||||
if (len < 0) {
|
|
||||||
if (!ssh_is_connected(client->session))
|
|
||||||
tmate_fatal("Disconnected");
|
|
||||||
|
|
||||||
tmate_fatal("Error reading from channel: %s",
|
setblocking(session->pty, 1);
|
||||||
ssh_get_error(client->session));
|
while (total_len) {
|
||||||
}
|
len = write(session->pty, data, total_len);
|
||||||
|
if (len < 0)
|
||||||
|
tmate_fatal("Error writing to pty");
|
||||||
|
|
||||||
if (len == 0)
|
total_len -= len;
|
||||||
return;
|
written += len;
|
||||||
|
data += len;
|
||||||
if (client->readonly)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
ptr = buf;
|
|
||||||
setblocking(client->pty, 1);
|
|
||||||
while (len > 0) {
|
|
||||||
written = write(client->pty, ptr, len);
|
|
||||||
if (written < 0)
|
|
||||||
tmate_fatal("Error writing to pty");
|
|
||||||
|
|
||||||
ptr += written;
|
|
||||||
len -= written;
|
|
||||||
}
|
|
||||||
setblocking(client->pty, 0);
|
|
||||||
}
|
}
|
||||||
|
setblocking(session->pty, 0);
|
||||||
|
|
||||||
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_session_event(struct tmate_ssh_client *client)
|
static int on_ssh_message_callback(ssh_session _session, ssh_message msg, void *arg)
|
||||||
{
|
{
|
||||||
ssh_execute_message_callbacks(client->session);
|
struct tmate_session *session = arg;
|
||||||
consume_channel(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __on_session_event(evutil_socket_t fd, short what, void *arg)
|
|
||||||
{
|
|
||||||
on_session_event(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int message_callback(struct tmate_ssh_client *client,
|
|
||||||
ssh_message msg)
|
|
||||||
{
|
|
||||||
if (ssh_message_type(msg) == SSH_REQUEST_CHANNEL &&
|
if (ssh_message_type(msg) == SSH_REQUEST_CHANNEL &&
|
||||||
ssh_message_subtype(msg) == SSH_CHANNEL_REQUEST_WINDOW_CHANGE) {
|
ssh_message_subtype(msg) == SSH_CHANNEL_REQUEST_WINDOW_CHANGE) {
|
||||||
struct winsize ws;
|
struct winsize ws;
|
||||||
@ -64,7 +42,7 @@ static int message_callback(struct tmate_ssh_client *client,
|
|||||||
ws.ws_col = ssh_message_channel_request_pty_width(msg);
|
ws.ws_col = ssh_message_channel_request_pty_width(msg);
|
||||||
ws.ws_row = ssh_message_channel_request_pty_height(msg);
|
ws.ws_row = ssh_message_channel_request_pty_height(msg);
|
||||||
|
|
||||||
ioctl(client->pty, TIOCSWINSZ, &ws);
|
ioctl(session->pty, TIOCSWINSZ, &ws);
|
||||||
client_write_server(MSG_RESIZE, NULL, 0);
|
client_write_server(MSG_RESIZE, NULL, 0);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -72,27 +50,13 @@ static int message_callback(struct tmate_ssh_client *client,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __message_callback(ssh_session session, ssh_message msg, void *arg)
|
static void on_pty_event(struct tmate_session *session)
|
||||||
{
|
|
||||||
return message_callback(arg, msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void register_session_fd_event(struct tmate_ssh_client *client)
|
|
||||||
{
|
|
||||||
ssh_set_message_callback(client->session, __message_callback, client);
|
|
||||||
|
|
||||||
event_assign(&client->ev_ssh, ev_base, ssh_get_fd(client->session),
|
|
||||||
EV_READ | EV_PERSIST, __on_session_event, client);
|
|
||||||
event_add(&client->ev_ssh, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void on_pty_event(struct tmate_ssh_client *client)
|
|
||||||
{
|
{
|
||||||
ssize_t len, written;
|
ssize_t len, written;
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
len = read(client->pty, buf, sizeof(buf));
|
len = read(session->pty, buf, sizeof(buf));
|
||||||
if (len < 0) {
|
if (len < 0) {
|
||||||
if (errno == EAGAIN)
|
if (errno == EAGAIN)
|
||||||
return;
|
return;
|
||||||
@ -102,10 +66,10 @@ static void on_pty_event(struct tmate_ssh_client *client)
|
|||||||
if (len == 0)
|
if (len == 0)
|
||||||
tmate_fatal("pty reached EOF");
|
tmate_fatal("pty reached EOF");
|
||||||
|
|
||||||
written = ssh_channel_write(client->channel, buf, len);
|
written = ssh_channel_write(session->ssh_client.channel, buf, len);
|
||||||
if (written < 0)
|
if (written < 0)
|
||||||
tmate_fatal("Error writing to channel: %s",
|
tmate_fatal("Error writing to channel: %s",
|
||||||
ssh_get_error(client->session));
|
ssh_get_error(session->ssh_client.session));
|
||||||
if (len != written)
|
if (len != written)
|
||||||
tmate_fatal("Cannot write %d bytes, wrote %d",
|
tmate_fatal("Cannot write %d bytes, wrote %d",
|
||||||
(int)len, (int)written);
|
(int)len, (int)written);
|
||||||
@ -117,25 +81,29 @@ static void __on_pty_event(evutil_socket_t fd, short what, void *arg)
|
|||||||
on_pty_event(arg);
|
on_pty_event(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tmate_flush_pty(struct tmate_ssh_client *client)
|
void tmate_flush_pty(struct tmate_session *session)
|
||||||
{
|
{
|
||||||
on_pty_event(client);
|
on_pty_event(session);
|
||||||
close(client->pty);
|
close(session->pty);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void register_pty_event(struct tmate_ssh_client *client)
|
void tmate_ssh_client_pty_init(struct tmate_session *session)
|
||||||
{
|
{
|
||||||
setblocking(client->pty, 0);
|
struct tmate_ssh_client *client = &session->ssh_client;
|
||||||
event_assign(&client->ev_pty, ev_base, client->pty,
|
|
||||||
EV_READ | EV_PERSIST, __on_pty_event, client);
|
|
||||||
event_add(&client->ev_pty, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void tmate_ssh_client_pty_init(struct tmate_ssh_client *client)
|
ioctl(session->pty, TIOCSWINSZ, &session->ssh_client.winsize_pty);
|
||||||
{
|
|
||||||
ioctl(client->pty, TIOCSWINSZ, &client->winsize_pty);
|
|
||||||
register_session_fd_event(client);
|
|
||||||
register_pty_event(client);
|
|
||||||
|
|
||||||
tmate_start_keepalive_timer(client);
|
memset(&client->channel_cb, 0, sizeof(client->channel_cb));
|
||||||
|
ssh_callbacks_init(&client->channel_cb);
|
||||||
|
client->channel_cb.userdata = session;
|
||||||
|
client->channel_cb.channel_data_function = on_ssh_channel_read,
|
||||||
|
ssh_set_channel_callbacks(client->channel, &client->channel_cb);
|
||||||
|
|
||||||
|
ssh_set_message_callback(session->ssh_client.session,
|
||||||
|
on_ssh_message_callback, session);
|
||||||
|
|
||||||
|
setblocking(session->pty, 0);
|
||||||
|
event_assign(&session->ev_pty, ev_base, session->pty,
|
||||||
|
EV_READ | EV_PERSIST, __on_pty_event, session);
|
||||||
|
event_add(&session->ev_pty, NULL);
|
||||||
}
|
}
|
||||||
|
@ -1,116 +1,77 @@
|
|||||||
#include "tmate.h"
|
#include "tmate.h"
|
||||||
#include <libssh/libssh.h>
|
|
||||||
#include <libssh/server.h>
|
|
||||||
#include <libssh/callbacks.h>
|
|
||||||
|
|
||||||
extern int server_shutdown;
|
static void on_decoder_read(void *userdata, struct tmate_unpacker *uk)
|
||||||
extern void server_send_shutdown(void);
|
|
||||||
|
|
||||||
#define request_termination(str, ...) do { \
|
|
||||||
tmate_info(str, ## __VA_ARGS__); \
|
|
||||||
server_shutdown = 1; \
|
|
||||||
server_send_shutdown(); \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
static void consume_channel(struct tmate_ssh_client *client)
|
|
||||||
{
|
{
|
||||||
|
struct tmate_session *session = userdata;
|
||||||
|
tmate_dispatch_daemon_message(session, uk);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int on_ssh_channel_read(ssh_session _session, ssh_channel channel,
|
||||||
|
void *_data, uint32_t total_len,
|
||||||
|
int is_stderr, void *userdata)
|
||||||
|
{
|
||||||
|
struct tmate_session *session = userdata;
|
||||||
|
char *data = _data;
|
||||||
|
size_t written = 0;
|
||||||
char *buf;
|
char *buf;
|
||||||
ssize_t len;
|
size_t len;
|
||||||
|
|
||||||
for (;;) {
|
while (total_len) {
|
||||||
tmate_decoder_get_buffer(client->decoder, &buf, &len);
|
tmate_decoder_get_buffer(&session->client_decoder, &buf, &len);
|
||||||
if (len == 0) {
|
|
||||||
request_termination("Decoder buffer full");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = ssh_channel_read_nonblocking(client->channel,
|
|
||||||
buf, len, 0);
|
|
||||||
if (len < 0) {
|
|
||||||
if (!ssh_is_connected(client->session))
|
|
||||||
request_termination("Disconnected");
|
|
||||||
else
|
|
||||||
request_termination("Error reading from channel: %s",
|
|
||||||
ssh_get_error(client->session));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
break;
|
tmate_fatal("No more room in client decoder. Message too big?");
|
||||||
|
|
||||||
tmate_decoder_commit(client->decoder, len);
|
if (len > total_len)
|
||||||
|
len = total_len;
|
||||||
|
|
||||||
|
memcpy(buf, data, len);
|
||||||
|
|
||||||
|
tmate_decoder_commit(&session->client_decoder, len);
|
||||||
|
|
||||||
|
total_len -= len;
|
||||||
|
written += len;
|
||||||
|
data += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void on_session_event(struct tmate_ssh_client *client)
|
static void on_encoder_write(void *userdata, struct evbuffer *buffer)
|
||||||
{
|
{
|
||||||
ssh_execute_message_callbacks(client->session);
|
struct tmate_session *session = userdata;
|
||||||
consume_channel(client);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __on_session_event(evutil_socket_t fd, short what, void *arg)
|
|
||||||
{
|
|
||||||
on_session_event(arg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void register_session_fd_event(struct tmate_ssh_client *client)
|
|
||||||
{
|
|
||||||
event_assign(&client->ev_ssh, ev_base, ssh_get_fd(client->session),
|
|
||||||
EV_READ | EV_PERSIST, __on_session_event, client);
|
|
||||||
event_add(&client->ev_ssh, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void flush_input_stream(struct tmate_ssh_client *client)
|
|
||||||
{
|
|
||||||
struct evbuffer *evb = client->encoder->buffer;
|
|
||||||
ssize_t len, written;
|
ssize_t len, written;
|
||||||
char *buf;
|
char *buf;
|
||||||
|
|
||||||
if (server_shutdown)
|
for(;;) {
|
||||||
return;
|
len = evbuffer_get_length(buffer);
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
len = evbuffer_get_length(evb);
|
|
||||||
if (!len)
|
if (!len)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
buf = evbuffer_pullup(evb, -1);
|
buf = evbuffer_pullup(buffer, -1);
|
||||||
|
|
||||||
written = ssh_channel_write(client->channel, buf, len);
|
written = ssh_channel_write(session->ssh_client.channel, buf, len);
|
||||||
if (written < 0) {
|
if (written < 0) {
|
||||||
request_termination("Error writing to channel: %s",
|
tmate_warn("Error writing to channel: %s",
|
||||||
ssh_get_error(client->session));
|
ssh_get_error(session->ssh_client.session));
|
||||||
|
request_server_termination();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
evbuffer_drain(evb, written);
|
evbuffer_drain(buffer, written);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __flush_input_stream(evutil_socket_t fd, short what, void *arg)
|
void tmate_daemon_init(struct tmate_session *session)
|
||||||
{
|
{
|
||||||
flush_input_stream(arg);
|
struct tmate_ssh_client *client = &session->ssh_client;
|
||||||
}
|
|
||||||
|
memset(&client->channel_cb, 0, sizeof(client->channel_cb));
|
||||||
static void register_input_stream_event(struct tmate_ssh_client *client)
|
ssh_callbacks_init(&client->channel_cb);
|
||||||
{
|
client->channel_cb.userdata = session;
|
||||||
event_assign(&client->encoder->ev_readable, ev_base, -1,
|
client->channel_cb.channel_data_function = on_ssh_channel_read,
|
||||||
EV_READ | EV_PERSIST, __flush_input_stream, client);
|
ssh_set_channel_callbacks(client->channel, &client->channel_cb);
|
||||||
event_add(&client->encoder->ev_readable, NULL);
|
|
||||||
}
|
tmate_encoder_init(&session->client_encoder, on_encoder_write, session);
|
||||||
|
tmate_decoder_init(&session->client_decoder, on_decoder_read, session);
|
||||||
|
|
||||||
void tmate_ssh_client_init(struct tmate_ssh_client *client,
|
|
||||||
struct tmate_encoder *encoder,
|
|
||||||
struct tmate_decoder *decoder)
|
|
||||||
{
|
|
||||||
client->winsize_pty.ws_col = 80;
|
|
||||||
client->winsize_pty.ws_row = 24;
|
|
||||||
|
|
||||||
client->encoder = encoder;
|
|
||||||
client->decoder = decoder;
|
|
||||||
|
|
||||||
register_session_fd_event(client);
|
|
||||||
register_input_stream_event(client);
|
|
||||||
|
|
||||||
tmate_start_keepalive_timer(client);
|
|
||||||
}
|
}
|
||||||
|
@ -4,28 +4,24 @@
|
|||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <sys/syscall.h>
|
|
||||||
#include <sched.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <event.h>
|
#include <event.h>
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
|
|
||||||
#include "tmate.h"
|
#include "tmate.h"
|
||||||
|
|
||||||
#define SSH_GRACE_PERIOD 60
|
static void start_keepalive_timer(struct tmate_ssh_client *client);
|
||||||
|
|
||||||
static void on_keepalive_timer(evutil_socket_t fd, short what, void *arg)
|
static void on_keepalive_timer(evutil_socket_t fd, short what, void *arg)
|
||||||
{
|
{
|
||||||
struct tmate_ssh_client *client = arg;
|
struct tmate_ssh_client *client = arg;
|
||||||
|
|
||||||
ssh_send_keepalive(client->session);
|
ssh_send_keepalive(client->session);
|
||||||
tmate_start_keepalive_timer(client);
|
start_keepalive_timer(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
void tmate_start_keepalive_timer(struct tmate_ssh_client *client)
|
static void start_keepalive_timer(struct tmate_ssh_client *client)
|
||||||
{
|
{
|
||||||
struct timeval tv;
|
struct timeval tv = { TMATE_SSH_KEEPALIVE, 0 };
|
||||||
tv.tv_sec = TMATE_KEEPALIVE;
|
|
||||||
tv.tv_usec = 0;
|
|
||||||
|
|
||||||
evtimer_assign(&client->ev_keepalive_timer, ev_base,
|
evtimer_assign(&client->ev_keepalive_timer, ev_base,
|
||||||
on_keepalive_timer, client);
|
on_keepalive_timer, client);
|
||||||
@ -65,12 +61,6 @@ static int subsystem_request(ssh_session session, ssh_channel channel,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct ssh_channel_callbacks_struct ssh_channel_cb = {
|
|
||||||
.channel_pty_request_function = pty_request,
|
|
||||||
.channel_shell_request_function = shell_request,
|
|
||||||
.channel_subsystem_request_function = subsystem_request,
|
|
||||||
};
|
|
||||||
|
|
||||||
static ssh_channel channel_open_request_cb(ssh_session session, void *userdata)
|
static ssh_channel channel_open_request_cb(ssh_session session, void *userdata)
|
||||||
{
|
{
|
||||||
struct tmate_ssh_client *client = userdata;
|
struct tmate_ssh_client *client = userdata;
|
||||||
@ -89,9 +79,13 @@ static ssh_channel channel_open_request_cb(ssh_session session, void *userdata)
|
|||||||
if (!client->channel)
|
if (!client->channel)
|
||||||
tmate_fatal("Error getting channel");
|
tmate_fatal("Error getting channel");
|
||||||
|
|
||||||
ssh_channel_cb.userdata = client;
|
memset(&client->channel_cb, 0, sizeof(client->channel_cb));
|
||||||
ssh_callbacks_init(&ssh_channel_cb);
|
ssh_callbacks_init(&client->channel_cb);
|
||||||
ssh_set_channel_callbacks(client->channel, &ssh_channel_cb);
|
client->channel_cb.userdata = client;
|
||||||
|
client->channel_cb.channel_pty_request_function = pty_request,
|
||||||
|
client->channel_cb.channel_shell_request_function = shell_request,
|
||||||
|
client->channel_cb.channel_subsystem_request_function = subsystem_request,
|
||||||
|
ssh_set_channel_callbacks(client->channel, &client->channel_cb);
|
||||||
|
|
||||||
return client->channel;
|
return client->channel;
|
||||||
}
|
}
|
||||||
@ -121,16 +115,39 @@ static struct ssh_server_callbacks_struct ssh_server_cb = {
|
|||||||
.channel_open_request_session_function = channel_open_request_cb,
|
.channel_open_request_session_function = channel_open_request_cb,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void client_bootstrap(struct tmate_ssh_client *client)
|
static void on_ssh_read(evutil_socket_t fd, short what, void *arg)
|
||||||
{
|
{
|
||||||
|
struct tmate_ssh_client *client = arg;
|
||||||
|
ssh_execute_message_callbacks(client->session);
|
||||||
|
|
||||||
|
if (!ssh_is_connected(client->session)) {
|
||||||
|
tmate_warn("SSH Disconnected");
|
||||||
|
|
||||||
|
/* For graceful tmux client termination */
|
||||||
|
request_server_termination();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void register_on_ssh_read(struct tmate_ssh_client *client)
|
||||||
|
{
|
||||||
|
event_assign(&client->ev_ssh, ev_base, ssh_get_fd(client->session),
|
||||||
|
EV_READ | EV_PERSIST, on_ssh_read, client);
|
||||||
|
event_add(&client->ev_ssh, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void client_bootstrap(struct tmate_session *_session)
|
||||||
|
{
|
||||||
|
struct tmate_ssh_client *client = &_session->ssh_client;
|
||||||
int auth = 0;
|
int auth = 0;
|
||||||
int grace_period = SSH_GRACE_PERIOD;
|
int grace_period = TMATE_SSH_GRACE_PERIOD;
|
||||||
ssh_event mainloop;
|
ssh_event mainloop;
|
||||||
ssh_session session = client->session;
|
ssh_session session = client->session;
|
||||||
ssh_message msg;
|
ssh_message msg;
|
||||||
|
|
||||||
tmate_notice("Bootstrapping ssh client ip=%s", client->ip_address);
|
tmate_notice("Bootstrapping ssh client ip=%s", client->ip_address);
|
||||||
|
|
||||||
|
ev_base = osdep_event_init();
|
||||||
|
|
||||||
/* new process group, we don't want to die with our parent (upstart) */
|
/* new process group, we don't want to die with our parent (upstart) */
|
||||||
setpgid(0, 0);
|
setpgid(0, 0);
|
||||||
|
|
||||||
@ -163,7 +180,11 @@ static void client_bootstrap(struct tmate_ssh_client *client)
|
|||||||
}
|
}
|
||||||
|
|
||||||
alarm(0);
|
alarm(0);
|
||||||
tmate_spawn_slave(client);
|
|
||||||
|
start_keepalive_timer(client);
|
||||||
|
register_on_ssh_read(client);
|
||||||
|
|
||||||
|
tmate_spawn_slave(_session);
|
||||||
/* never reached */
|
/* never reached */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,13 +203,13 @@ static void handle_sigchld(void)
|
|||||||
|
|
||||||
static void handle_sigalrm(void)
|
static void handle_sigalrm(void)
|
||||||
{
|
{
|
||||||
tmate_fatal("Connection grace period (%d) passed", SSH_GRACE_PERIOD);
|
tmate_fatal("Connection grace period (%d) passed", TMATE_SSH_GRACE_PERIOD);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_sigsegv(void)
|
static void handle_sigsegv(void)
|
||||||
{
|
{
|
||||||
tmate_info("CRASH, printing stack trace");
|
tmate_info("CRASH, printing stack trace");
|
||||||
tmate_print_trace();
|
tmate_print_stack_trace();
|
||||||
tmate_fatal("CRASHED");
|
tmate_fatal("CRASHED");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -208,14 +229,6 @@ static void setup_signals(void)
|
|||||||
signal(SIGSEGV, signal_handler);
|
signal(SIGSEGV, signal_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
static pid_t namespace_fork(void)
|
|
||||||
{
|
|
||||||
/* XXX we are breaking getpid() libc cache. Bad libc. */
|
|
||||||
unsigned long flags;
|
|
||||||
flags = CLONE_NEWPID | CLONE_NEWIPC | CLONE_NEWNS | CLONE_NEWNET;
|
|
||||||
return syscall(SYS_clone, flags | SIGCHLD, NULL, NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int get_ip(int fd, char *dst, size_t len)
|
static int get_ip(int fd, char *dst, size_t len)
|
||||||
{
|
{
|
||||||
struct sockaddr sa;
|
struct sockaddr sa;
|
||||||
@ -243,8 +256,6 @@ static int get_ip(int fd, char *dst, size_t len)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct tmate_ssh_client tmate_client;
|
|
||||||
|
|
||||||
static void ssh_log_function(int priority, const char *function,
|
static void ssh_log_function(int priority, const char *function,
|
||||||
const char *buffer, void *userdata)
|
const char *buffer, void *userdata)
|
||||||
{
|
{
|
||||||
@ -281,9 +292,10 @@ static ssh_bind prepare_ssh(const char *keys_dir, int port)
|
|||||||
return bind;
|
return bind;
|
||||||
}
|
}
|
||||||
|
|
||||||
void tmate_ssh_server_main(const char *keys_dir, int port)
|
void tmate_ssh_server_main(struct tmate_session *session,
|
||||||
|
const char *keys_dir, int port)
|
||||||
{
|
{
|
||||||
struct tmate_ssh_client *client = &tmate_client;
|
struct tmate_ssh_client *client = &session->ssh_client;
|
||||||
ssh_bind bind;
|
ssh_bind bind;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
@ -293,6 +305,9 @@ void tmate_ssh_server_main(const char *keys_dir, int port)
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
client->session = ssh_new();
|
client->session = ssh_new();
|
||||||
client->channel = NULL;
|
client->channel = NULL;
|
||||||
|
client->winsize_pty.ws_col = 80;
|
||||||
|
client->winsize_pty.ws_row = 24;
|
||||||
|
|
||||||
if (!client->session)
|
if (!client->session)
|
||||||
tmate_fatal("Cannot initialize session");
|
tmate_fatal("Cannot initialize session");
|
||||||
|
|
||||||
@ -303,12 +318,8 @@ void tmate_ssh_server_main(const char *keys_dir, int port)
|
|||||||
client->ip_address, sizeof(client->ip_address)) < 0)
|
client->ip_address, sizeof(client->ip_address)) < 0)
|
||||||
tmate_fatal("Error getting IP address from connection");
|
tmate_fatal("Error getting IP address from connection");
|
||||||
|
|
||||||
if ((pid = namespace_fork()) < 0) {
|
if ((pid = fork()) < 0)
|
||||||
if (getuid() == 0)
|
tmate_fatal("Can't fork");
|
||||||
tmate_fatal("Can't fork in new namespace, are you running a recent kernel?");
|
|
||||||
else
|
|
||||||
tmate_fatal("Can't fork in new namespace, run me with root priviledges");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pid) {
|
if (pid) {
|
||||||
tmate_info("Child spawned pid=%d, ip=%s",
|
tmate_info("Child spawned pid=%d, ip=%s",
|
||||||
@ -316,8 +327,8 @@ void tmate_ssh_server_main(const char *keys_dir, int port)
|
|||||||
ssh_free(client->session);
|
ssh_free(client->session);
|
||||||
} else {
|
} else {
|
||||||
ssh_bind_free(bind);
|
ssh_bind_free(bind);
|
||||||
tmate_session_token = "init";
|
session->session_token = "init";
|
||||||
client_bootstrap(client);
|
client_bootstrap(session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
217
tmate.h
217
tmate.h
@ -5,9 +5,13 @@
|
|||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <msgpack.h>
|
#include <msgpack.h>
|
||||||
#include <libssh/libssh.h>
|
#include <libssh/libssh.h>
|
||||||
|
#include <libssh/callbacks.h>
|
||||||
#include <event.h>
|
#include <event.h>
|
||||||
|
|
||||||
#include "tmux.h"
|
#include "tmux.h"
|
||||||
|
struct tmate_session;
|
||||||
|
|
||||||
|
/* log.c */
|
||||||
|
|
||||||
extern void init_logging(const char *program_name, bool use_syslog, int log_level);
|
extern void init_logging(const char *program_name, bool use_syslog, int log_level);
|
||||||
extern void printflike2 tmate_log(int level, const char *msg, ...);
|
extern void printflike2 tmate_log(int level, const char *msg, ...);
|
||||||
@ -22,7 +26,83 @@ extern void printflike2 tmate_log(int level, const char *msg, ...);
|
|||||||
exit(1); \
|
exit(1); \
|
||||||
})
|
})
|
||||||
|
|
||||||
/* tmate-encoder.c */
|
/* tmate-msgpack.c */
|
||||||
|
|
||||||
|
typedef void tmate_encoder_write_cb(void *userdata, struct evbuffer *buffer);
|
||||||
|
|
||||||
|
struct tmate_encoder {
|
||||||
|
msgpack_packer pk;
|
||||||
|
tmate_encoder_write_cb *ready_callback;
|
||||||
|
void *userdata;
|
||||||
|
struct evbuffer *buffer;
|
||||||
|
struct event ev_buffer;
|
||||||
|
bool ev_active;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void tmate_encoder_init(struct tmate_encoder *encoder,
|
||||||
|
tmate_encoder_write_cb *callback,
|
||||||
|
void *userdata);
|
||||||
|
|
||||||
|
#define NEW_MSGPACK_API 0
|
||||||
|
|
||||||
|
#if NEW_MSG_PACK
|
||||||
|
#define msgpack_pack_buffer(pk, buf, len) ({ \
|
||||||
|
msgpack_pack_bin(pk, len); \
|
||||||
|
msgpack_pack_bin_body(pk, buf, len); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define msgpack_pack_string(pk, str) ({ \
|
||||||
|
int __strlen = strlen(str); \
|
||||||
|
msgpack_pack_str(pk, __strlen); \
|
||||||
|
msgpack_pack_str_body(pk, str, __strlen); \
|
||||||
|
})
|
||||||
|
#else
|
||||||
|
/* old msgpack version */
|
||||||
|
#define msgpack_pack_buffer(pk, buf, len) ({ \
|
||||||
|
msgpack_pack_raw(pk, len); \
|
||||||
|
msgpack_pack_raw_body(pk, buf, len); \
|
||||||
|
})
|
||||||
|
|
||||||
|
#define msgpack_pack_string(pk, str) ({ \
|
||||||
|
int __strlen = strlen(str); \
|
||||||
|
msgpack_pack_raw(pk, __strlen); \
|
||||||
|
msgpack_pack_raw_body(pk, str, __strlen); \
|
||||||
|
})
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define _pack(enc, what, ...) msgpack_pack_##what(&(enc)->pk, __VA_ARGS__)
|
||||||
|
|
||||||
|
struct tmate_unpacker;
|
||||||
|
struct tmate_decoder;
|
||||||
|
typedef void tmate_decoder_reader(void *userdata, struct tmate_unpacker *uk);
|
||||||
|
|
||||||
|
struct tmate_decoder {
|
||||||
|
struct msgpack_unpacker unpacker;
|
||||||
|
tmate_decoder_reader *reader;
|
||||||
|
void *userdata;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void tmate_decoder_init(struct tmate_decoder *decoder, tmate_decoder_reader *reader, void *userdata);
|
||||||
|
extern void tmate_decoder_get_buffer(struct tmate_decoder *decoder, char **buf, size_t *len);
|
||||||
|
extern void tmate_decoder_commit(struct tmate_decoder *decoder, size_t len);
|
||||||
|
|
||||||
|
struct tmate_unpacker {
|
||||||
|
msgpack_object *argv;
|
||||||
|
int argc;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void init_unpacker(struct tmate_unpacker *uk, msgpack_object obj);
|
||||||
|
extern int64_t unpack_int(struct tmate_unpacker *uk);
|
||||||
|
extern void unpack_buffer(struct tmate_unpacker *uk, const char **buf, size_t *len);
|
||||||
|
extern char *unpack_string(struct tmate_unpacker *uk);
|
||||||
|
extern void unpack_array(struct tmate_unpacker *uk, struct tmate_unpacker *nested);
|
||||||
|
|
||||||
|
#define unpack_each(nested_uk, tmp_uk, uk) \
|
||||||
|
for (unpack_array(uk, tmp_uk); \
|
||||||
|
(tmp_uk)->argc > 0 && (init_unpacker(nested_uk, (tmp_uk)->argv[0]), 1); \
|
||||||
|
(tmp_uk)->argv++, (tmp_uk)->argc--)
|
||||||
|
|
||||||
|
/* tmate-client-encoder.c */
|
||||||
|
|
||||||
#define TMATE_LATEST_VERSION "1.8.10"
|
#define TMATE_LATEST_VERSION "1.8.10"
|
||||||
|
|
||||||
@ -35,14 +115,7 @@ enum tmate_client_commands {
|
|||||||
TMATE_CLIENT_READY,
|
TMATE_CLIENT_READY,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tmate_encoder {
|
extern void tmate_client_encoder_init(struct tmate_encoder *encoder);
|
||||||
struct evbuffer *buffer;
|
|
||||||
struct event ev_readable;
|
|
||||||
struct event ev_notify_timer;
|
|
||||||
msgpack_packer pk;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern void tmate_encoder_init(struct tmate_encoder *encoder);
|
|
||||||
|
|
||||||
extern void printflike1 tmate_notify(const char *fmt, ...);
|
extern void printflike1 tmate_notify(const char *fmt, ...);
|
||||||
extern void printflike2 tmate_notify_later(int timeout, const char *fmt, ...);
|
extern void printflike2 tmate_notify_later(int timeout, const char *fmt, ...);
|
||||||
@ -57,10 +130,11 @@ extern int tmate_should_exec_cmd_locally(const struct cmd_entry *cmd);
|
|||||||
extern void tmate_send_env(const char *name, const char *value);
|
extern void tmate_send_env(const char *name, const char *value);
|
||||||
extern void tmate_send_client_ready(void);
|
extern void tmate_send_client_ready(void);
|
||||||
|
|
||||||
/* tmate-decoder.c */
|
/* tmate-client-decoder.c */
|
||||||
|
|
||||||
#define TMATE_HLIMIT 2000
|
#define TMATE_HLIMIT 2000
|
||||||
#define TMATE_MAX_MESSAGE_SIZE (16*1024)
|
/* 17 and not 16 because the sender does not takes into account envelope size */
|
||||||
|
#define TMATE_MAX_MESSAGE_SIZE (17*1024)
|
||||||
|
|
||||||
extern char *tmate_left_status, *tmate_right_status;
|
extern char *tmate_left_status, *tmate_right_status;
|
||||||
|
|
||||||
@ -77,19 +151,23 @@ enum tmate_commands {
|
|||||||
|
|
||||||
#define TMATE_PANE_ACTIVE 1
|
#define TMATE_PANE_ACTIVE 1
|
||||||
|
|
||||||
struct tmate_decoder {
|
extern void tmate_dispatch_daemon_message(struct tmate_session *session,
|
||||||
int protocol;
|
struct tmate_unpacker *uk);
|
||||||
|
|
||||||
struct msgpack_unpacker unpacker;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern void tmate_decoder_init(struct tmate_decoder *decoder);
|
|
||||||
extern void tmate_decoder_get_buffer(struct tmate_decoder *decoder,
|
|
||||||
char **buf, size_t *len);
|
|
||||||
extern void tmate_decoder_commit(struct tmate_decoder *decoder, size_t len);
|
|
||||||
|
|
||||||
/* tmate-ssh-client.c */
|
/* tmate-ssh-client.c */
|
||||||
|
|
||||||
|
extern void tmate_daemon_init(struct tmate_session *session);
|
||||||
|
|
||||||
|
/* tmate-ssh-client-pty.c */
|
||||||
|
|
||||||
|
extern void tmate_ssh_client_pty_init(struct tmate_session *session);
|
||||||
|
extern void tmate_flush_pty(struct tmate_session *session);
|
||||||
|
|
||||||
|
/* tmate-ssh-server.c */
|
||||||
|
|
||||||
|
#define TMATE_SSH_BANNER "tmate"
|
||||||
|
#define TMATE_SSH_KEEPALIVE 60
|
||||||
|
|
||||||
#define TMATE_ROLE_SERVER 1
|
#define TMATE_ROLE_SERVER 1
|
||||||
#define TMATE_ROLE_CLIENT 2
|
#define TMATE_ROLE_CLIENT 2
|
||||||
|
|
||||||
@ -98,12 +176,14 @@ struct tmate_ssh_client {
|
|||||||
|
|
||||||
ssh_session session;
|
ssh_session session;
|
||||||
ssh_channel channel;
|
ssh_channel channel;
|
||||||
|
/*
|
||||||
|
* We need to store the entire callback struct because
|
||||||
|
* libssh stores the userdata within the cb struct...
|
||||||
|
*/
|
||||||
|
struct ssh_channel_callbacks_struct channel_cb;
|
||||||
|
|
||||||
int role;
|
int role;
|
||||||
|
|
||||||
struct tmate_encoder *encoder;
|
|
||||||
struct tmate_decoder *decoder;
|
|
||||||
|
|
||||||
char *username;
|
char *username;
|
||||||
char *pubkey;
|
char *pubkey;
|
||||||
|
|
||||||
@ -111,53 +191,21 @@ struct tmate_ssh_client {
|
|||||||
|
|
||||||
struct event ev_ssh;
|
struct event ev_ssh;
|
||||||
struct event ev_keepalive_timer;
|
struct event ev_keepalive_timer;
|
||||||
|
|
||||||
/* only for client-pty */
|
|
||||||
int pty;
|
|
||||||
struct event ev_pty;
|
|
||||||
int readonly;
|
|
||||||
};
|
};
|
||||||
extern void tmate_ssh_client_init(struct tmate_ssh_client *client,
|
|
||||||
struct tmate_encoder *encoder,
|
|
||||||
struct tmate_decoder *decoder);
|
|
||||||
|
|
||||||
/* tmate-ssh-client-pty.c */
|
extern void tmate_ssh_server_main(struct tmate_session *session,
|
||||||
|
const char *keys_dir, int port);
|
||||||
extern void tmate_ssh_client_pty_init(struct tmate_ssh_client *client);
|
|
||||||
extern void tmate_flush_pty(struct tmate_ssh_client *client);
|
|
||||||
|
|
||||||
/* tmate-ssh-server.c */
|
|
||||||
|
|
||||||
#define TMATE_SSH_BANNER "tmate"
|
|
||||||
#define TMATE_KEEPALIVE 60
|
|
||||||
|
|
||||||
#ifdef TMATE_RECORD_REPLAY
|
|
||||||
extern int tmate_session_log_fd;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern struct tmate_ssh_client tmate_client;
|
|
||||||
extern void tmate_start_keepalive_timer(struct tmate_ssh_client *client);
|
|
||||||
extern void tmate_ssh_server_main(const char *keys_dir, int port);
|
|
||||||
|
|
||||||
/* tmate-slave.c */
|
/* tmate-slave.c */
|
||||||
|
|
||||||
struct tmate_settings {
|
|
||||||
const char *keys_dir;
|
|
||||||
int ssh_port;
|
|
||||||
const char *master_hostname;
|
|
||||||
int master_port;
|
|
||||||
const char *tmate_host;
|
|
||||||
int log_level;
|
|
||||||
bool use_syslog;
|
|
||||||
};
|
|
||||||
extern struct tmate_settings tmate_settings;
|
|
||||||
|
|
||||||
#ifdef DEVENV
|
#ifdef DEVENV
|
||||||
#define TMATE_SSH_DEFAULT_PORT 2200
|
#define TMATE_SSH_DEFAULT_PORT 2200
|
||||||
#else
|
#else
|
||||||
#define TMATE_SSH_DEFAULT_PORT 22
|
#define TMATE_SSH_DEFAULT_PORT 22
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define TMATE_SSH_GRACE_PERIOD 60
|
||||||
|
|
||||||
#define TMATE_SSH_DEFAULT_KEYS_DIR "keys"
|
#define TMATE_SSH_DEFAULT_KEYS_DIR "keys"
|
||||||
|
|
||||||
#define TMATE_DEFAULT_MASTER_HOST NULL
|
#define TMATE_DEFAULT_MASTER_HOST NULL
|
||||||
@ -167,24 +215,51 @@ extern struct tmate_settings tmate_settings;
|
|||||||
#define TMATE_WORKDIR "/tmp/tmate"
|
#define TMATE_WORKDIR "/tmp/tmate"
|
||||||
#define TMATE_JAIL_USER "nobody"
|
#define TMATE_JAIL_USER "nobody"
|
||||||
|
|
||||||
extern int tmate_port;
|
struct tmate_settings {
|
||||||
extern struct tmate_encoder *tmate_encoder;
|
const char *keys_dir;
|
||||||
extern struct tmate_decoder *tmate_decoder;
|
int ssh_port;
|
||||||
extern int tmux_socket_fd;
|
const char *master_hostname;
|
||||||
extern char *tmate_host;
|
int master_port;
|
||||||
extern const char *tmate_session_token;
|
const char *tmate_host;
|
||||||
extern const char *tmate_session_token_ro;
|
int log_level;
|
||||||
|
bool use_syslog;
|
||||||
|
};
|
||||||
|
extern struct tmate_settings *tmate_settings;
|
||||||
|
|
||||||
|
struct tmate_session {
|
||||||
|
struct tmate_ssh_client ssh_client;
|
||||||
|
int tmux_socket_fd;
|
||||||
|
|
||||||
|
/* only for deamon */
|
||||||
|
|
||||||
|
struct tmate_encoder client_encoder;
|
||||||
|
struct tmate_decoder client_decoder;
|
||||||
|
int client_protocol_version;
|
||||||
|
|
||||||
|
struct tmate_encoder master_encoder;
|
||||||
|
struct tmate_decoder master_decoder;
|
||||||
|
|
||||||
|
const char *session_token;
|
||||||
|
const char *session_token_ro;
|
||||||
|
|
||||||
|
struct event ev_notify_timer;
|
||||||
|
|
||||||
|
/* only for client-pty */
|
||||||
|
int pty;
|
||||||
|
struct event ev_pty;
|
||||||
|
bool readonly;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern struct tmate_session *tmate_session;
|
||||||
extern void tmate_get_random_bytes(void *buffer, ssize_t len);
|
extern void tmate_get_random_bytes(void *buffer, ssize_t len);
|
||||||
extern long tmate_get_random_long(void);
|
extern long tmate_get_random_long(void);
|
||||||
|
extern void request_server_termination(void);
|
||||||
extern void tmate_reopen_logfile(void);
|
extern void tmate_spawn_slave(struct tmate_session *session);
|
||||||
extern void tmate_spawn_slave(struct tmate_ssh_client *client);
|
|
||||||
|
|
||||||
/* tmate-debug.c */
|
/* tmate-debug.c */
|
||||||
|
|
||||||
extern void tmate_preload_trace_lib(void);
|
extern void tmate_preload_trace_lib(void);
|
||||||
extern void tmate_print_trace(void);
|
extern void tmate_print_stack_trace(void);
|
||||||
|
|
||||||
/* tmux-bare.c */
|
/* tmux-bare.c */
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user