diff --git a/client.c b/client.c index f037163a..fc3c12fd 100644 --- a/client.c +++ b/client.c @@ -32,6 +32,7 @@ #include #include "tmux.h" +#include "tmate.h" struct imsgbuf client_ibuf; struct event client_event; @@ -206,8 +207,8 @@ client_main(int argc, char **argv, int flags) } #ifdef TMATE_SLAVE - cmdflags &= ~CMD_STARTSERVER; -#endif + fd = tmux_socket_fd; +#else /* * Check if this could be a nested session, if the command can't nest: @@ -227,6 +228,7 @@ client_main(int argc, char **argv, int flags) fprintf(stderr, "failed to connect to server\n"); return (1); } +#endif /* Set process title, log and signals now this is the client. */ #ifdef HAVE_SETPROCTITLE @@ -293,8 +295,9 @@ client_main(int argc, char **argv, int flags) /* Print the exit message, if any, and exit. */ if (client_attached) { - if (client_exitreason != CLIENT_EXIT_NONE && !login_shell) - printf("[%s]\n", client_exit_message()); + if (client_exitreason != CLIENT_EXIT_NONE && !login_shell) { + printf("[%s]\r\n", client_exit_message()); + } ppid = getppid(); if (client_exittype == MSG_DETACHKILL && ppid > 1) diff --git a/server.c b/server.c index 6781249d..ce98f979 100644 --- a/server.c +++ b/server.c @@ -97,9 +97,7 @@ server_create_socket(void) fatal("listen failed"); setblocking(fd, 0); - server_update_socket(); - - return (fd); + server_update_socket(); return (fd); } /* Fork new server. */ @@ -162,9 +160,10 @@ server_start(int lockfd, char *lockfile) setproctitle("server (%s)", socket_path); #endif +#ifdef TMATE_SLAVE + server_fd = tmux_socket_fd; +#else server_fd = server_create_socket(); - -#ifndef TMATE_SLAVE server_client_create(pair[1]); unlink(lockfile); @@ -397,10 +396,12 @@ server_signal_callback(int sig, unused short events, unused void *data) server_child_signal(); break; case SIGUSR1: +#ifndef TMATE_SLAVE event_del(&server_ev_accept); close(server_fd); server_fd = server_create_socket(); server_add_accept(0); +#endif break; } } diff --git a/tmate-slave.c b/tmate-slave.c index 143d02d4..025a83db 100644 --- a/tmate-slave.c +++ b/tmate-slave.c @@ -1,8 +1,16 @@ #include #include #include +#include #include "tmate.h" +struct tmate_encoder *tmate_encoder; +int tmux_socket_fd; +const char *tmate_session_token; + +extern int server_create_socket(void); +extern int client_connect(char *path, int start_server); + static void usage(void) { fprintf(stderr, "usage: tmate-slave [-p PORT]\n"); @@ -14,8 +22,6 @@ int main(int argc, char **argv) int port = 22; char *log_path = NULL; /* stderr */ - strcpy(socket_path, "/tmp/tmate-slave"); - while ((opt = getopt(argc, argv, "p:l:v")) != -1) { switch (opt) { case 'p': @@ -38,16 +44,62 @@ int main(int argc, char **argv) return 0; } -struct tmate_encoder *tmate_encoder; - -void tmate_spawn_slave_server(struct tmate_ssh_client *client) +static void set_session_token(const char *token) { + tmate_session_token = xstrdup(token); + strcpy(socket_path, "/tmp/tmate-slave-"); + strcat(socket_path, token); +} + +static char tmate_token_digits[] = "abcdefghijklmnopqrstuvwxyz" + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789"; +#define NUM_DIGITS (sizeof(tmate_token_digits) - 1) + +static char *get_random_token(void) +{ + int i; + char *token = xmalloc(TMATE_TOKEN_LEN + 1); + + ssh_get_random(token, TMATE_TOKEN_LEN, 0); + for (i = 0; i < TMATE_TOKEN_LEN; i++) + token[i] = tmate_token_digits[token[i] % NUM_DIGITS]; + token[i] = 0; + + return token; +} + +static int validate_token(const char *token) +{ + int len = strlen(token); + int i; + + if (len != TMATE_TOKEN_LEN) + return -1; + + for (i = 0; i < len; i++) { + if (!strchr(tmate_token_digits, token[i])) + return -1; + } + + return 0; +} + +static void tmate_spawn_slave_server(struct tmate_ssh_client *client) +{ + char *token; struct tmate_encoder encoder; struct tmate_decoder decoder; - tmate_debug("Spawn tmux slave server"); + token = get_random_token(); + set_session_token(token); + free(token); - ev_base = osdep_event_init(); + tmate_debug("Spawning tmux slave server %s", tmate_session_token); + + tmux_socket_fd = server_create_socket(); + if (tmux_socket_fd < 0) + tmate_fatal("Cannot create to the tmux socket"); tmate_encoder_init(&encoder); tmate_decoder_init(&decoder); @@ -59,22 +111,68 @@ void tmate_spawn_slave_server(struct tmate_ssh_client *client) /* never reached */ } -void tmate_spawn_slave_client(struct tmate_ssh_client *ssh_client) +static void ssh_echo(struct tmate_ssh_client *ssh_client, + const char *str) +{ + ssh_channel_write(ssh_client->channel, str, strlen(str)); +} + +#define BAD_TOKEN_ERROR_STR \ +" " "\r\n" \ +" Dear guest," "\r\n" \ +" " "\r\n" \ +" There isn't much I can do without a valid session token." "\r\n" \ +" Feel free to reach out if you are having issues." "\r\n" \ +" " "\r\n" \ +" Thanks," "\r\n" \ +" Nico" "\r\n" \ +" " "\r\n" + +#define EXPIRED_TOKEN_ERROR_STR \ +" " "\r\n" \ +" Dear guest," "\r\n" \ +" " "\r\n" \ +" The provided session token is invalid, or has expired." "\r\n" \ +" Feel free to reach out if you are having issues." "\r\n" \ +" " "\r\n" \ +" Thanks," "\r\n" \ +" Nico" "\r\n" \ +" " "\r\n" + +static void random_sleep(void) +{ + usleep(50000 + (rand() % 50000)); +} + +static void tmate_spawn_slave_client(struct tmate_ssh_client *ssh_client) { struct tmate_ssh_client_pty _client; struct tmate_ssh_client_pty *client = &_client; + char *argv[] = {(char *)"attach", NULL}; + char *token = ssh_client->username; int slave_pty; int ret; - char *argv[] = {(char *)"attach", NULL}; + + if (validate_token(token) < 0) { + ssh_echo(ssh_client, BAD_TOKEN_ERROR_STR); + tmate_fatal("Bad token"); + } + + set_session_token(token); + + tmate_debug("Spawn tmux slave client %s", tmate_session_token); + + tmux_socket_fd = client_connect(socket_path, 0); + if (tmux_socket_fd < 0) { + random_sleep(); /* for timing attacks */ + ssh_echo(ssh_client, EXPIRED_TOKEN_ERROR_STR); + tmate_fatal("Expired token"); + } client->session = ssh_client->session; client->channel = ssh_client->channel; client->winsize_pty = ssh_client->winsize_pty; - tmate_debug("Spawn tmux slave client"); - - ev_base = osdep_event_init(); - if (openpty(&client->pty, &slave_pty, NULL, NULL, NULL) < 0) tmate_fatal("Cannot allocate pty"); @@ -89,3 +187,13 @@ void tmate_spawn_slave_client(struct tmate_ssh_client *ssh_client) tmate_flush_pty(client); exit(ret); } + +void tmate_spawn_slave(struct tmate_ssh_client *client) +{ + ev_base = osdep_event_init(); + + if (client->role == TMATE_ROLE_SERVER) + tmate_spawn_slave_server(client); + else + tmate_spawn_slave_client(client); +} diff --git a/tmate-ssh-server.c b/tmate-ssh-server.c index 10ac0309..3ac6866d 100644 --- a/tmate-ssh-server.c +++ b/tmate-ssh-server.c @@ -105,18 +105,19 @@ static int init_client_step(struct tmate_ssh_client *client, if (ssh_message_type(msg) == SSH_REQUEST_CHANNEL && ssh_message_subtype(msg) == SSH_CHANNEL_REQUEST_SUBSYSTEM && !strcmp(ssh_message_channel_request_subsystem(msg), "tmate")) { - alarm(0); - ssh_message_channel_request_reply_success(msg); - tmate_spawn_slave_server(client); - /* never reached */ + client->role = TMATE_ROLE_SERVER; } /* shell request (slave client) */ if (ssh_message_type(msg) == SSH_REQUEST_CHANNEL && ssh_message_subtype(msg) == SSH_CHANNEL_REQUEST_SHELL) { + client->role = TMATE_ROLE_CLIENT; + } + + if (client->role) { alarm(0); ssh_message_channel_request_reply_success(msg); - tmate_spawn_slave_client(client); + tmate_spawn_slave(client); /* never reached */ } diff --git a/tmate.h b/tmate.h index eb4f34f9..7f49740c 100644 --- a/tmate.h +++ b/tmate.h @@ -60,10 +60,15 @@ extern void tmate_decoder_commit(struct tmate_decoder *decoder, size_t len); typedef struct ssh_session_struct* ssh_session; typedef struct ssh_channel_struct* ssh_channel; +#define TMATE_ROLE_SERVER 1 +#define TMATE_ROLE_CLIENT 2 + struct tmate_ssh_client { ssh_session session; ssh_channel channel; + int role; + struct tmate_encoder *encoder; struct tmate_decoder *decoder; @@ -102,10 +107,12 @@ extern void tmate_ssh_server_main(int port); /* tmate-slave.c */ -extern struct tmate_encoder *tmate_encoder; +#define TMATE_TOKEN_LEN 25 -extern void tmate_spawn_slave_server(struct tmate_ssh_client *client); -extern void tmate_spawn_slave_client(struct tmate_ssh_client *client); +extern struct tmate_encoder *tmate_encoder; +extern int tmux_socket_fd; + +extern void tmate_spawn_slave(struct tmate_ssh_client *client); /* tmate-debug.c */ extern void tmate_print_trace(void);