1
0
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:
Nicolas Viennot 2015-09-19 03:35:40 -04:00
parent 31cc091823
commit 4ac1183848
13 changed files with 582 additions and 556 deletions

View File

@ -179,8 +179,9 @@ dist_tmate_slave_SOURCES = \
signal.c \
status.c \
tmate-debug.c \
tmate-decoder.c \
tmate-encoder.c \
tmate-client-decoder.c \
tmate-client-encoder.c \
tmate-msgpack.c \
tmate-slave.c \
tmate-ssh-client-pty.c \
tmate-ssh-client.c \

View File

@ -207,7 +207,7 @@ client_main(int argc, char **argv, int flags)
}
#ifdef TMATE_SLAVE
fd = tmux_socket_fd;
fd = tmate_session->tmux_socket_fd;
#else
/*
@ -325,7 +325,7 @@ client_send_identify(int flags)
int fd;
#ifdef TMATE_SLAVE
strcpy(data.ip_address, tmate_client.ip_address);
strcpy(data.ip_address, tmate_session->ssh_client.ip_address);
#endif
data.flags = flags;

6
log.c
View File

@ -73,11 +73,13 @@ log_vwrite(int level, const char *msg, va_list ap)
{
char *fmt = NULL;
const char *token = tmate_session->session_token;
if (log_settings.log_level < level)
return;
if (tmate_session_token) {
if (asprintf(&fmt, "[%s] %s", tmate_session_token, msg) < 0)
if (token) {
if (asprintf(&fmt, "[%s] %s", token, msg) < 0)
exit(1);
msg = fmt;
}

View File

@ -162,7 +162,7 @@ server_start(int lockfd, char *lockfile)
#endif
#ifdef TMATE_SLAVE
server_fd = tmux_socket_fd;
server_fd = tmate_session->tmux_socket_fd;
#else
server_fd = server_create_socket();
server_client_create(pair[1]);

View File

@ -6,111 +6,21 @@ char *tmate_left_status, *tmate_right_status;
static struct session *main_session;
struct tmate_unpacker {
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,
static void tmate_header(struct tmate_session *session,
struct tmate_unpacker *uk)
{
char port_arg[16] = {0};
char *client_version = xstrdup("< 1.8.6");
char tmp[512];
decoder->protocol = unpack_int(uk);
if (decoder->protocol >= 3) {
session->client_protocol_version = unpack_int(uk);
if (session->client_protocol_version >= 3) {
free(client_version);
client_version = unpack_string(uk);
}
tmate_debug("new master, client version: %s, protocol version: %d",
client_version, decoder->protocol);
client_version, session->client_protocol_version);
#if 0
if (strcmp(client_version, TMATE_LATEST_VERSION))
@ -119,14 +29,14 @@ static void tmate_header(struct tmate_decoder *decoder,
free(client_version);
if (tmate_settings.ssh_port != 22)
sprintf(port_arg, " -p%d", tmate_settings.ssh_port);
if (tmate_settings->ssh_port != 22)
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_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_send_env("tmate_ssh", tmp);
@ -231,7 +141,7 @@ static void tmate_sync_windows(struct session *s,
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 session *s;
@ -254,7 +164,7 @@ static void tmate_sync_layout(struct tmate_decoder *decoder,
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 window_pane *wp;
@ -263,7 +173,7 @@ static void tmate_pty_data(struct tmate_decoder *decoder,
int id;
id = unpack_int(uk);
unpack_raw(uk, &buf, &len);
unpack_buffer(uk, &buf, &len);
wp = window_pane_find_by_id(id);
if (!wp)
@ -275,7 +185,7 @@ static void tmate_pty_data(struct tmate_decoder *decoder,
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 cmd_q *cmd_q;
@ -297,7 +207,7 @@ out:
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 client *c;
@ -320,7 +230,7 @@ static void tmate_failed_cmd(struct tmate_decoder *decoder,
free(cause);
}
static void tmate_status(struct tmate_decoder *decoder,
static void tmate_status(struct tmate_session *session,
struct tmate_unpacker *uk)
{
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 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 cm_uk, sel_uk, input_uk;
@ -368,7 +278,7 @@ static void tmate_sync_copy_mode(struct tmate_decoder *decoder,
return;
}
if (decoder->protocol >= 2)
if (session->client_protocol_version >= 2)
base_backing = unpack_int(&cm_uk);
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) {
data->screen.sel.flag = 1;
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)
+ screen_size_y(data->backing)
- 1;
@ -424,7 +334,7 @@ static void tmate_sync_copy_mode(struct tmate_decoder *decoder,
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 window_pane *wp;
@ -445,70 +355,21 @@ static void tmate_write_copy_mode(struct tmate_decoder *decoder,
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;
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
#define dispatch(c, f) case c: f(session, uk); break
int cmd = unpack_int(uk);
switch (cmd) {
case TMATE_HEADER: tmate_header(decoder, uk); break;
case TMATE_SYNC_LAYOUT: tmate_sync_layout(decoder, uk); break;
case TMATE_PTY_DATA: tmate_pty_data(decoder, uk); break;
case TMATE_EXEC_CMD: tmate_exec_cmd(decoder, uk); break;
case TMATE_FAILED_CMD: tmate_failed_cmd(decoder, uk); break;
case TMATE_STATUS: tmate_status(decoder, uk); break;
case TMATE_SYNC_COPY_MODE: tmate_sync_copy_mode(decoder, uk); break;
case TMATE_WRITE_COPY_MODE: tmate_write_copy_mode(decoder, uk); break;
default: decoder_error();
dispatch(TMATE_HEADER, tmate_header);
dispatch(TMATE_SYNC_LAYOUT, tmate_sync_layout);
dispatch(TMATE_PTY_DATA, tmate_pty_data);
dispatch(TMATE_EXEC_CMD, tmate_exec_cmd);
dispatch(TMATE_FAILED_CMD, tmate_failed_cmd);
dispatch(TMATE_STATUS, tmate_status);
dispatch(TMATE_SYNC_COPY_MODE, tmate_sync_copy_mode);
dispatch(TMATE_WRITE_COPY_MODE, tmate_write_copy_mode);
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");
}

View File

@ -1,36 +1,6 @@
#include "tmate.h"
static int msgpack_write(void *data, const char *buf, unsigned int len)
{
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)
#define pack(what, ...) _pack(&tmate_session->client_encoder, what, __VA_ARGS__)
static void __tmate_notify(const char *msg)
{
@ -75,9 +45,9 @@ void printflike2 tmate_notify_later(int timeout, const char *fmt, ...)
* multiple times.
*/
evtimer_assign(&tmate_encoder->ev_notify_timer, ev_base,
evtimer_assign(&tmate_session->ev_notify_timer, ev_base,
__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)
@ -127,7 +97,7 @@ void tmate_notify_client_left(struct client *c)
void tmate_send_client_ready(void)
{
if (tmate_decoder && tmate_decoder->protocol < 4)
if (tmate_session->client_protocol_version < 4)
return;
pack(array, 1);
@ -136,7 +106,7 @@ void tmate_send_client_ready(void)
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;
pack(array, 3);

View File

@ -52,7 +52,7 @@ static int print_resolved_stack_frame(const char *frame)
}
#endif
void tmate_print_trace(void)
void tmate_print_stack_trace(void)
{
void *array[20];
size_t size;

164
tmate-msgpack.c Normal file
View 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);
}

View File

@ -16,13 +16,10 @@
#include <time.h>
#include <fcntl.h>
#include <sys/syslog.h>
#include <sched.h>
#include "tmate.h"
struct tmate_decoder *tmate_decoder;
struct tmate_encoder *tmate_encoder;
int tmux_socket_fd;
const char *tmate_session_token;
const char *tmate_session_token_ro;
struct tmate_session _tmate_session, *tmate_session = &_tmate_session;
extern FILE *log_file;
@ -33,7 +30,7 @@ static int dev_urandom_fd;
extern int server_create_socket(void);
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,
.ssh_port = TMATE_SSH_DEFAULT_PORT,
.master_hostname = TMATE_DEFAULT_MASTER_HOST,
@ -43,6 +40,8 @@ struct tmate_settings tmate_settings = {
.use_syslog = false,
};
struct tmate_settings *tmate_settings = &_tmate_settings;
static void usage(void)
{
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;
}
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 opt;
@ -68,25 +79,25 @@ int main(int argc, char **argv, char **envp)
while ((opt = getopt(argc, argv, "k:p:lvm:q:")) != -1) {
switch (opt) {
case 'p':
tmate_settings.ssh_port = atoi(optarg);
tmate_settings->ssh_port = atoi(optarg);
break;
case 'k':
tmate_settings.keys_dir = xstrdup(optarg);
tmate_settings->keys_dir = xstrdup(optarg);
break;
case 's':
tmate_settings.use_syslog = true;
tmate_settings->use_syslog = true;
break;
case 'v':
tmate_settings.log_level++;
tmate_settings->log_level++;
break;
case 'm':
tmate_settings.master_hostname = xstrdup(optarg);
tmate_settings->master_hostname = xstrdup(optarg);
break;
case 'q':
tmate_settings.master_port = atoi(optarg);
tmate_settings->master_port = atoi(optarg);
break;
case 'h':
tmate_settings.tmate_host = xstrdup(optarg);
tmate_settings->tmate_host = xstrdup(optarg);
break;
default:
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];
if (gethostname(hostname, sizeof(hostname)) < 0)
tmate_fatal("cannot get hostname");
tmate_settings.tmate_host = xstrdup(hostname);
tmate_settings->tmate_host = xstrdup(hostname);
}
cmdline = *argv;
cmdline_end = *envp;
init_logging("tmate-ssh",
tmate_settings.use_syslog, tmate_settings.log_level);
tmate_settings->use_syslog, tmate_settings->log_level);
tmate_preload_trace_lib();
@ -117,7 +128,8 @@ int main(int argc, char **argv, char **envp)
(mkdir(TMATE_WORKDIR "/jail", 0700) < 0 && errno != EEXIST))
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;
}
@ -139,33 +151,33 @@ static char *get_random_token(void)
return token;
}
static void set_session_token(struct tmate_ssh_client *client,
static void set_session_token(struct tmate_session *session,
const char *token)
{
tmate_session_token = xstrdup(token);
session->session_token = xstrdup(token);
strcpy(socket_path, TMATE_WORKDIR "/sessions/");
strcat(socket_path, token);
memset(cmdline, 0, cmdline_end - cmdline);
sprintf(cmdline, "tmate-slave [%s] %s %s",
tmate_session_token,
client->role == TMATE_ROLE_SERVER ? "(server)" : "(client)",
client->ip_address);
session->session_token,
session->ssh_client.role == TMATE_ROLE_SERVER ? "(server)" : "(client)",
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];
tmate_session_token_ro = get_random_token();
session->session_token_ro = get_random_token();
#ifdef DEVENV
strcpy((char *)tmate_session_token_ro, "READONLYTOKENFORDEVENV000");
strcpy((char *)session->session_token_ro, "READONLYTOKENFORDEVENV000");
#endif
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);
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");
}
@ -250,9 +262,8 @@ static void jail(void)
uid = pw->pw_uid;
gid = pw->pw_gid;
/*
* We are already in a new PID namespace (from the server fork).
*/
if (getuid() != 0)
tmate_fatal("Need root priviledges");
if (chroot(TMATE_WORKDIR "/jail") < 0)
tmate_fatal("Cannot chroot()");
@ -260,6 +271,9 @@ static void jail(void)
if (chdir("/") < 0)
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)
tmate_fatal("Cannot setgroups()");
@ -272,8 +286,8 @@ static void jail(void)
if (nice(1) < 0)
tmate_fatal("Cannot nice()");
tmate_debug("Dropped priviledges to %s (%d,%d)",
TMATE_JAIL_USER, uid, gid);
tmate_debug("Dropped priviledges to %s (%d,%d), jailed in %s",
TMATE_JAIL_USER, uid, gid, TMATE_WORKDIR "/jail");
}
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");
}
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;
struct tmate_encoder encoder;
struct tmate_decoder decoder;
@ -294,17 +310,17 @@ static void tmate_spawn_slave_server(struct tmate_ssh_client *client)
strcpy(token, "SUPERSECURETOKENFORDEVENV");
#endif
set_session_token(client, token);
set_session_token(session, token);
free(token);
tmate_debug("Spawning slave server for %s at %s (%s)",
client->username, client->ip_address, client->pubkey);
tmux_socket_fd = server_create_socket();
if (tmux_socket_fd < 0)
session->tmux_socket_fd = server_create_socket();
if (session->tmux_socket_fd < 0)
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.
@ -312,27 +328,23 @@ static void tmate_spawn_slave_server(struct tmate_ssh_client *client)
*/
setup_ncurse(STDOUT_FILENO, "screen-256color");
close_fds_except((int[]){tmux_socket_fd,
ssh_get_fd(client->session),
close_fds_except((int[]){session->tmux_socket_fd,
ssh_get_fd(session->ssh_client.session),
log_file ? fileno(log_file) : -1}, 3);
jail();
ev_base = osdep_event_init();
event_reinit(ev_base);
tmate_encoder_init(&encoder);
tmate_decoder_init(&decoder);
tmate_encoder = &encoder;
tmate_decoder = &decoder;
tmate_ssh_client_init(client, &encoder, &decoder);
tmate_daemon_init(session);
tmux_server_init(IDENTIFY_UTF8 | IDENTIFY_256COLOURS);
/* 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_ro[] = {(char *)"attach", (char *)"-r", NULL};
char **argv = argv_rw;
@ -351,13 +363,13 @@ static void tmate_spawn_slave_client(struct tmate_ssh_client *client)
tmate_fatal("Invalid token");
}
set_session_token(client, token);
set_session_token(session, token);
tmate_debug("Spawning slave client for %s (%s)",
client->ip_address, client->pubkey);
tmux_socket_fd = client_connect(socket_path, 0);
if (tmux_socket_fd < 0) {
session->tmux_socket_fd = client_connect(socket_path, 0);
if (session->tmux_socket_fd < 0) {
random_sleep(); /* for making timing attacks harder */
ssh_echo(client, EXPIRED_TOKEN_ERROR_STR);
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
* to the server.
*/
client->readonly = 0;
session->readonly = false;
if (lstat(socket_path, &fstat) < 0)
tmate_fatal("Cannot fstat()");
if (S_ISLNK(fstat.st_mode)) {
client->readonly = 1;
session->readonly = true;
argv = argv_ro;
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");
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");
close_fds_except((int[]){STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO,
tmux_socket_fd, ssh_get_fd(client->session),
client->pty, log_file ? fileno(log_file) : -1}, 7);
session->tmux_socket_fd,
ssh_get_fd(session->ssh_client.session),
session->pty, log_file ? fileno(log_file) : -1}, 7);
jail();
event_reinit(ev_base);
ev_base = osdep_event_init();
tmate_ssh_client_pty_init(client);
tmate_ssh_client_pty_init(session);
ret = client_main(argc, argv, IDENTIFY_UTF8 | IDENTIFY_256COLOURS);
tmate_flush_pty(client);
tmate_flush_pty(session);
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
tmate_spawn_slave_client(client);
tmate_spawn_slave_client(session);
}

View File

@ -1,62 +1,40 @@
#include <libssh/libssh.h>
#include <libssh/server.h>
#include <libssh/callbacks.h>
#include <errno.h>
#include "tmate.h"
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;
char buf[4096];
char *ptr;
struct tmate_session *session = userdata;
char *data = _data;
size_t written = 0;
ssize_t len;
for (;;) {
len = ssh_channel_read_nonblocking(client->channel,
buf, sizeof(buf), 0);
if (len < 0) {
if (!ssh_is_connected(client->session))
tmate_fatal("Disconnected");
if (session->readonly)
return total_len;
tmate_fatal("Error reading from channel: %s",
ssh_get_error(client->session));
}
if (len == 0)
return;
if (client->readonly)
continue;
ptr = buf;
setblocking(client->pty, 1);
while (len > 0) {
written = write(client->pty, ptr, len);
if (written < 0)
setblocking(session->pty, 1);
while (total_len) {
len = write(session->pty, data, total_len);
if (len < 0)
tmate_fatal("Error writing to pty");
ptr += written;
len -= written;
}
setblocking(client->pty, 0);
total_len -= len;
written += len;
data += len;
}
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);
consume_channel(client);
}
struct tmate_session *session = arg;
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 &&
ssh_message_subtype(msg) == SSH_CHANNEL_REQUEST_WINDOW_CHANGE) {
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_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);
return 1;
@ -72,27 +50,13 @@ static int message_callback(struct tmate_ssh_client *client,
return 0;
}
static int __message_callback(ssh_session session, ssh_message msg, void *arg)
{
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)
static void on_pty_event(struct tmate_session *session)
{
ssize_t len, written;
char buf[4096];
for (;;) {
len = read(client->pty, buf, sizeof(buf));
len = read(session->pty, buf, sizeof(buf));
if (len < 0) {
if (errno == EAGAIN)
return;
@ -102,10 +66,10 @@ static void on_pty_event(struct tmate_ssh_client *client)
if (len == 0)
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)
tmate_fatal("Error writing to channel: %s",
ssh_get_error(client->session));
ssh_get_error(session->ssh_client.session));
if (len != written)
tmate_fatal("Cannot write %d bytes, wrote %d",
(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);
}
void tmate_flush_pty(struct tmate_ssh_client *client)
void tmate_flush_pty(struct tmate_session *session)
{
on_pty_event(client);
close(client->pty);
on_pty_event(session);
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);
event_assign(&client->ev_pty, ev_base, client->pty,
EV_READ | EV_PERSIST, __on_pty_event, client);
event_add(&client->ev_pty, NULL);
}
struct tmate_ssh_client *client = &session->ssh_client;
void tmate_ssh_client_pty_init(struct tmate_ssh_client *client)
{
ioctl(client->pty, TIOCSWINSZ, &client->winsize_pty);
register_session_fd_event(client);
register_pty_event(client);
ioctl(session->pty, TIOCSWINSZ, &session->ssh_client.winsize_pty);
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);
}

View File

@ -1,116 +1,77 @@
#include "tmate.h"
#include <libssh/libssh.h>
#include <libssh/server.h>
#include <libssh/callbacks.h>
extern int server_shutdown;
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)
static void on_decoder_read(void *userdata, struct tmate_unpacker *uk)
{
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;
ssize_t len;
size_t len;
for (;;) {
tmate_decoder_get_buffer(client->decoder, &buf, &len);
if (len == 0) {
request_termination("Decoder buffer full");
break;
}
while (total_len) {
tmate_decoder_get_buffer(&session->client_decoder, &buf, &len);
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)
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;
}
static void on_session_event(struct tmate_ssh_client *client)
return written;
}
static void on_encoder_write(void *userdata, struct evbuffer *buffer)
{
ssh_execute_message_callbacks(client->session);
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;
struct tmate_session *session = userdata;
ssize_t len, written;
char *buf;
if (server_shutdown)
return;
for(;;) {
len = evbuffer_get_length(evb);
len = evbuffer_get_length(buffer);
if (!len)
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) {
request_termination("Error writing to channel: %s",
ssh_get_error(client->session));
tmate_warn("Error writing to channel: %s",
ssh_get_error(session->ssh_client.session));
request_server_termination();
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);
}
static void register_input_stream_event(struct tmate_ssh_client *client)
{
event_assign(&client->encoder->ev_readable, ev_base, -1,
EV_READ | EV_PERSIST, __flush_input_stream, client);
event_add(&client->encoder->ev_readable, NULL);
}
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);
struct tmate_ssh_client *client = &session->ssh_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);
tmate_encoder_init(&session->client_encoder, on_encoder_write, session);
tmate_decoder_init(&session->client_decoder, on_decoder_read, session);
}

View File

@ -4,28 +4,24 @@
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <sys/wait.h>
#include <sys/syscall.h>
#include <sched.h>
#include <stdio.h>
#include <event.h>
#include <arpa/inet.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)
{
struct tmate_ssh_client *client = arg;
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;
tv.tv_sec = TMATE_KEEPALIVE;
tv.tv_usec = 0;
struct timeval tv = { TMATE_SSH_KEEPALIVE, 0 };
evtimer_assign(&client->ev_keepalive_timer, ev_base,
on_keepalive_timer, client);
@ -65,12 +61,6 @@ static int subsystem_request(ssh_session session, ssh_channel channel,
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)
{
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)
tmate_fatal("Error getting channel");
ssh_channel_cb.userdata = client;
ssh_callbacks_init(&ssh_channel_cb);
ssh_set_channel_callbacks(client->channel, &ssh_channel_cb);
memset(&client->channel_cb, 0, sizeof(client->channel_cb));
ssh_callbacks_init(&client->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;
}
@ -121,16 +115,39 @@ static struct ssh_server_callbacks_struct ssh_server_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 grace_period = SSH_GRACE_PERIOD;
int grace_period = TMATE_SSH_GRACE_PERIOD;
ssh_event mainloop;
ssh_session session = client->session;
ssh_message msg;
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) */
setpgid(0, 0);
@ -163,7 +180,11 @@ static void client_bootstrap(struct tmate_ssh_client *client)
}
alarm(0);
tmate_spawn_slave(client);
start_keepalive_timer(client);
register_on_ssh_read(client);
tmate_spawn_slave(_session);
/* never reached */
}
@ -182,13 +203,13 @@ static void handle_sigchld(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)
{
tmate_info("CRASH, printing stack trace");
tmate_print_trace();
tmate_print_stack_trace();
tmate_fatal("CRASHED");
}
@ -208,14 +229,6 @@ static void setup_signals(void)
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)
{
struct sockaddr sa;
@ -243,8 +256,6 @@ static int get_ip(int fd, char *dst, size_t len)
return 0;
}
struct tmate_ssh_client tmate_client;
static void ssh_log_function(int priority, const char *function,
const char *buffer, void *userdata)
{
@ -281,9 +292,10 @@ static ssh_bind prepare_ssh(const char *keys_dir, int port)
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;
pid_t pid;
@ -293,6 +305,9 @@ void tmate_ssh_server_main(const char *keys_dir, int port)
for (;;) {
client->session = ssh_new();
client->channel = NULL;
client->winsize_pty.ws_col = 80;
client->winsize_pty.ws_row = 24;
if (!client->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)
tmate_fatal("Error getting IP address from connection");
if ((pid = namespace_fork()) < 0) {
if (getuid() == 0)
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 = fork()) < 0)
tmate_fatal("Can't fork");
if (pid) {
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);
} else {
ssh_bind_free(bind);
tmate_session_token = "init";
client_bootstrap(client);
session->session_token = "init";
client_bootstrap(session);
}
}
}

217
tmate.h
View File

@ -5,9 +5,13 @@
#include <sys/types.h>
#include <msgpack.h>
#include <libssh/libssh.h>
#include <libssh/callbacks.h>
#include <event.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 printflike2 tmate_log(int level, const char *msg, ...);
@ -22,7 +26,83 @@ extern void printflike2 tmate_log(int level, const char *msg, ...);
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"
@ -35,14 +115,7 @@ enum tmate_client_commands {
TMATE_CLIENT_READY,
};
struct tmate_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 tmate_client_encoder_init(struct tmate_encoder *encoder);
extern void printflike1 tmate_notify(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_client_ready(void);
/* tmate-decoder.c */
/* tmate-client-decoder.c */
#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;
@ -77,19 +151,23 @@ enum tmate_commands {
#define TMATE_PANE_ACTIVE 1
struct tmate_decoder {
int protocol;
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);
extern void tmate_dispatch_daemon_message(struct tmate_session *session,
struct tmate_unpacker *uk);
/* 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_CLIENT 2
@ -98,12 +176,14 @@ struct tmate_ssh_client {
ssh_session session;
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;
struct tmate_encoder *encoder;
struct tmate_decoder *decoder;
char *username;
char *pubkey;
@ -111,53 +191,21 @@ struct tmate_ssh_client {
struct event ev_ssh;
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_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);
extern void tmate_ssh_server_main(struct tmate_session *session,
const char *keys_dir, int port);
/* 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
#define TMATE_SSH_DEFAULT_PORT 2200
#else
#define TMATE_SSH_DEFAULT_PORT 22
#endif
#define TMATE_SSH_GRACE_PERIOD 60
#define TMATE_SSH_DEFAULT_KEYS_DIR "keys"
#define TMATE_DEFAULT_MASTER_HOST NULL
@ -167,24 +215,51 @@ extern struct tmate_settings tmate_settings;
#define TMATE_WORKDIR "/tmp/tmate"
#define TMATE_JAIL_USER "nobody"
extern int tmate_port;
extern struct tmate_encoder *tmate_encoder;
extern struct tmate_decoder *tmate_decoder;
extern int tmux_socket_fd;
extern char *tmate_host;
extern const char *tmate_session_token;
extern const char *tmate_session_token_ro;
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;
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 long tmate_get_random_long(void);
extern void tmate_reopen_logfile(void);
extern void tmate_spawn_slave(struct tmate_ssh_client *client);
extern void request_server_termination(void);
extern void tmate_spawn_slave(struct tmate_session *session);
/* tmate-debug.c */
extern void tmate_preload_trace_lib(void);
extern void tmate_print_trace(void);
extern void tmate_print_stack_trace(void);
/* tmux-bare.c */