mirror of
https://github.com/tmate-io/tmate.git
synced 2025-03-15 08:38:53 +01:00
parent
b97568cac2
commit
13d3439933
@ -19,6 +19,7 @@ static int msgpack_write(void *data, const char *buf, unsigned int len)
|
||||
void tmate_encoder_init(struct tmate_encoder *encoder)
|
||||
{
|
||||
msgpack_packer_init(&encoder->pk, encoder, &msgpack_write);
|
||||
encoder->ev_readable.ev_flags = 0;
|
||||
encoder->buffer = evbuffer_new();
|
||||
}
|
||||
|
||||
|
@ -87,7 +87,7 @@ static void lookup_and_connect(void)
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
tmate_status_message("Looking up %s...", TMATE_HOST);
|
||||
tmate_info("Looking up %s...", TMATE_HOST);
|
||||
(void)evdns_getaddrinfo(ev_dnsbase, TMATE_HOST, NULL,
|
||||
&hints, dns_cb, NULL);
|
||||
}
|
||||
@ -96,10 +96,14 @@ void tmate_session_init(void)
|
||||
{
|
||||
tmate_catch_sigsegv();
|
||||
|
||||
TAILQ_INIT(&tmate_session.clients);
|
||||
tmate_encoder_init(&tmate_session.encoder);
|
||||
tmate_decoder_init(&tmate_session.decoder);
|
||||
|
||||
TAILQ_INIT(&tmate_session.clients);
|
||||
|
||||
tmate_session.need_passphrase = 0;
|
||||
tmate_session.passphrase = NULL;
|
||||
|
||||
/* The header will be written as soon as the first client connects */
|
||||
tmate_write_header();
|
||||
}
|
||||
|
@ -10,10 +10,11 @@ static void consume_channel(struct tmate_ssh_client *client);
|
||||
static void flush_input_stream(struct tmate_ssh_client *client);
|
||||
static void __flush_input_stream(evutil_socket_t fd, short what, void *arg);
|
||||
static void __on_session_event(evutil_socket_t fd, short what, void *arg);
|
||||
static void printflike2 disconnect_session(struct tmate_ssh_client *client,
|
||||
const char *fmt, ...);
|
||||
static void printflike2 kill_session(struct tmate_ssh_client *client,
|
||||
const char *fmt, ...);
|
||||
static void printflike2 reconnect_session(struct tmate_ssh_client *client,
|
||||
const char *fmt, ...);
|
||||
static void on_session_event(struct tmate_ssh_client *client);
|
||||
|
||||
static void log_function(ssh_session session, int priority,
|
||||
const char *message, void *userdata)
|
||||
@ -79,7 +80,7 @@ static void connection_complete(struct tmate_ssh_client *connected_client)
|
||||
continue;
|
||||
|
||||
assert(!client->has_encoder);
|
||||
tmate_ssh_client_free(client);
|
||||
kill_session(client, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@ -99,6 +100,66 @@ static char *get_identity(void)
|
||||
return identity;
|
||||
}
|
||||
|
||||
static int passphrase_callback(const char *prompt, char *buf, size_t len,
|
||||
int echo, int verify, void *userdata)
|
||||
{
|
||||
struct tmate_ssh_client *client = userdata;
|
||||
|
||||
client->tmate_session->need_passphrase = 1;
|
||||
|
||||
if (client->tmate_session->passphrase)
|
||||
strncpy(buf, client->tmate_session->passphrase, len);
|
||||
else
|
||||
strcpy(buf, "");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void on_passphrase_read(const char *passphrase, void *private)
|
||||
{
|
||||
struct tmate_ssh_client *client = private;
|
||||
|
||||
client->tmate_session->passphrase = xstrdup(passphrase);
|
||||
on_session_event(client);
|
||||
}
|
||||
|
||||
static void request_passphrase(struct tmate_ssh_client *client)
|
||||
{
|
||||
struct window_pane *wp;
|
||||
struct window_copy_mode_data *data;
|
||||
|
||||
/*
|
||||
* We'll display the prompt on the first pane.
|
||||
* It doesn't make much sense, but it's simpler to reuse the copy mode
|
||||
* and its key parsing logic compared to rolling something on our own.
|
||||
*/
|
||||
wp = RB_MIN(window_pane_tree, &all_window_panes);
|
||||
|
||||
if (wp->mode) {
|
||||
data = wp->modedata;
|
||||
if (data->inputtype == WINDOW_COPY_PASSWORD) {
|
||||
/* We are already requesting the passphrase */
|
||||
return;
|
||||
}
|
||||
window_pane_reset_mode(wp);
|
||||
}
|
||||
|
||||
window_pane_set_mode(wp, &window_copy_mode);
|
||||
window_copy_init_from_pane(wp);
|
||||
data = wp->modedata;
|
||||
|
||||
data->inputtype = WINDOW_COPY_PASSWORD;
|
||||
data->inputprompt = "SSH key passphrase";
|
||||
|
||||
mode_key_init(&data->mdata, &mode_key_tree_vi_edit);
|
||||
|
||||
window_copy_update_selection(wp);
|
||||
window_copy_redraw_screen(wp);
|
||||
|
||||
data->password_cb = on_passphrase_read;
|
||||
data->password_cb_private = client;
|
||||
}
|
||||
|
||||
static void on_session_event(struct tmate_ssh_client *client)
|
||||
{
|
||||
char *identity;
|
||||
@ -139,6 +200,11 @@ static void on_session_event(struct tmate_ssh_client *client)
|
||||
ssh_options_set(session, SSH_OPTIONS_COMPRESSION, "yes");
|
||||
|
||||
if ((identity = get_identity())) {
|
||||
/*
|
||||
* FIXME libssh will continue with the next set of
|
||||
* keys if the identity has a passphrase and the
|
||||
* regular one doesn't.
|
||||
*/
|
||||
ssh_options_set(session, SSH_OPTIONS_IDENTITY, identity);
|
||||
free(identity);
|
||||
}
|
||||
@ -164,7 +230,7 @@ static void on_session_event(struct tmate_ssh_client *client)
|
||||
|
||||
case SSH_AUTH_SERVER:
|
||||
if ((hash_len = ssh_get_pubkey_hash(session, &hash)) < 0) {
|
||||
disconnect_session(client, "Cannot authenticate server");
|
||||
kill_session(client, "Cannot authenticate server");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -199,7 +265,7 @@ static void on_session_event(struct tmate_ssh_client *client)
|
||||
free(hash_str);
|
||||
|
||||
if (!match) {
|
||||
disconnect_session(client, "Cannot authenticate server");
|
||||
kill_session(client, "Cannot authenticate server");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -216,14 +282,18 @@ static void on_session_event(struct tmate_ssh_client *client)
|
||||
/* fall through */
|
||||
|
||||
case SSH_AUTH_CLIENT:
|
||||
switch (ssh_userauth_autopubkey(session, NULL)) {
|
||||
client->tried_passphrase = client->tmate_session->passphrase;
|
||||
switch (ssh_userauth_autopubkey(session, client->tried_passphrase)) {
|
||||
case SSH_AUTH_AGAIN:
|
||||
return;
|
||||
case SSH_AUTH_PARTIAL:
|
||||
case SSH_AUTH_INFO:
|
||||
case SSH_AUTH_DENIED:
|
||||
disconnect_session(client, "Access denied. Check your SSH keys "
|
||||
"(passphrases are not supported yet).");
|
||||
if (client->tmate_session->need_passphrase &&
|
||||
!client->tried_passphrase)
|
||||
request_passphrase(client);
|
||||
else
|
||||
kill_session(client, "Access denied. Check your SSH keys.");
|
||||
return;
|
||||
case SSH_AUTH_ERROR:
|
||||
reconnect_session(client, "Auth error: %s",
|
||||
@ -316,12 +386,12 @@ static void __on_session_event(evutil_socket_t fd, short what, void *arg)
|
||||
on_session_event(arg);
|
||||
}
|
||||
|
||||
static void __disconnect_session(struct tmate_ssh_client *client,
|
||||
const char *fmt, va_list va)
|
||||
static void __kill_session(struct tmate_ssh_client *client,
|
||||
const char *fmt, va_list va)
|
||||
{
|
||||
struct tmate_encoder *encoder;
|
||||
|
||||
if (fmt)
|
||||
if (fmt && TAILQ_EMPTY(&client->tmate_session->clients))
|
||||
__tmate_status_message(fmt, va);
|
||||
else
|
||||
tmate_debug("Disconnecting %s", client->server_ip);
|
||||
@ -348,14 +418,19 @@ static void __disconnect_session(struct tmate_ssh_client *client,
|
||||
client->state = SSH_NONE;
|
||||
}
|
||||
|
||||
static void printflike2 disconnect_session(struct tmate_ssh_client *client,
|
||||
const char *fmt, ...)
|
||||
static void printflike2 kill_session(struct tmate_ssh_client *client,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
TAILQ_REMOVE(&client->tmate_session->clients, client, node);
|
||||
|
||||
va_start(ap, fmt);
|
||||
__disconnect_session(client, fmt, ap);
|
||||
__kill_session(client, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
free(client->server_ip);
|
||||
free(client);
|
||||
}
|
||||
|
||||
static void connect_session(struct tmate_ssh_client *client)
|
||||
@ -377,8 +452,12 @@ static void printflike2 reconnect_session(struct tmate_ssh_client *client,
|
||||
struct timeval tv;
|
||||
va_list ap;
|
||||
|
||||
#if 1
|
||||
TAILQ_REMOVE(&client->tmate_session->clients, client, node);
|
||||
#endif
|
||||
|
||||
va_start(ap, fmt);
|
||||
__disconnect_session(client, fmt, ap);
|
||||
__kill_session(client, fmt, ap);
|
||||
va_end(ap);
|
||||
|
||||
/* Not yet implemented... */
|
||||
@ -389,16 +468,17 @@ static void printflike2 reconnect_session(struct tmate_ssh_client *client,
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
struct tmate_ssh_client *tmate_ssh_client_alloc(struct tmate_session *session,
|
||||
const char *server_ip)
|
||||
{
|
||||
struct tmate_ssh_client *client;
|
||||
client = xmalloc(sizeof(*client));
|
||||
|
||||
memset(&client->ssh_callbacks, 0, sizeof(client->ssh_callbacks));
|
||||
ssh_callbacks_init(&client->ssh_callbacks);
|
||||
client->ssh_callbacks.log_function = log_function;
|
||||
client->ssh_callbacks.userdata = client;
|
||||
client->ssh_callbacks.auth_function = passphrase_callback;
|
||||
|
||||
client->tmate_session = session;
|
||||
TAILQ_INSERT_TAIL(&session->clients, client, node);
|
||||
@ -409,6 +489,8 @@ struct tmate_ssh_client *tmate_ssh_client_alloc(struct tmate_session *session,
|
||||
client->channel = NULL;
|
||||
client->has_encoder = 0;
|
||||
|
||||
client->ev_ssh.ev_flags = 0;
|
||||
|
||||
evtimer_assign(&client->ev_ssh_reconnect, ev_base,
|
||||
on_reconnect_timer, client);
|
||||
|
||||
@ -416,11 +498,3 @@ struct tmate_ssh_client *tmate_ssh_client_alloc(struct tmate_session *session,
|
||||
|
||||
return client;
|
||||
}
|
||||
|
||||
void tmate_ssh_client_free(struct tmate_ssh_client *client)
|
||||
{
|
||||
disconnect_session(client, NULL);
|
||||
TAILQ_REMOVE(&client->tmate_session->clients, client, node);
|
||||
free(client->server_ip);
|
||||
free(client);
|
||||
}
|
||||
|
4
tmate.h
4
tmate.h
@ -117,6 +117,7 @@ struct tmate_ssh_client {
|
||||
* has to be in the struct itself).
|
||||
*/
|
||||
struct ssh_callbacks_struct ssh_callbacks;
|
||||
char *tried_passphrase;
|
||||
ssh_session session;
|
||||
ssh_channel channel;
|
||||
|
||||
@ -127,7 +128,6 @@ TAILQ_HEAD(tmate_ssh_clients, tmate_ssh_client);
|
||||
|
||||
extern struct tmate_ssh_client *tmate_ssh_client_alloc(struct tmate_session *session,
|
||||
const char *server_ip);
|
||||
extern void tmate_ssh_client_free(struct tmate_ssh_client *client);
|
||||
|
||||
/* tmate-session.c */
|
||||
|
||||
@ -141,6 +141,8 @@ struct tmate_session {
|
||||
* losers are disconnected and killed.
|
||||
*/
|
||||
struct tmate_ssh_clients clients;
|
||||
int need_passphrase;
|
||||
char *passphrase;
|
||||
};
|
||||
|
||||
extern struct tmate_session tmate_session;
|
||||
|
17
tmux.h
17
tmux.h
@ -2245,6 +2245,10 @@ enum window_copy_input_type {
|
||||
WINDOW_COPY_JUMPTOFORWARD,
|
||||
WINDOW_COPY_JUMPTOBACK,
|
||||
WINDOW_COPY_GOTOLINE,
|
||||
|
||||
#ifdef TMATE
|
||||
WINDOW_COPY_PASSWORD,
|
||||
#endif
|
||||
};
|
||||
|
||||
/*
|
||||
@ -2263,6 +2267,11 @@ enum window_copy_input_type {
|
||||
* a newly-allocated screen structure (which is deallocated when the
|
||||
* mode ends).
|
||||
*/
|
||||
|
||||
#ifdef TMATE
|
||||
typedef void (*copy_password_callback)(const char *password, void *private);
|
||||
#endif
|
||||
|
||||
struct window_copy_mode_data {
|
||||
struct screen screen;
|
||||
|
||||
@ -2295,6 +2304,11 @@ struct window_copy_mode_data {
|
||||
|
||||
enum window_copy_input_type jumptype;
|
||||
char jumpchar;
|
||||
|
||||
#ifdef TMATE
|
||||
copy_password_callback password_cb;
|
||||
void *password_cb_private;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@ -2306,6 +2320,9 @@ void printflike2 window_copy_add(struct window_pane *, const char *, ...);
|
||||
void window_copy_vadd(struct window_pane *, const char *, va_list);
|
||||
void window_copy_pageup(struct window_pane *);
|
||||
|
||||
int window_copy_update_selection(struct window_pane *);
|
||||
void window_copy_redraw_screen(struct window_pane *);
|
||||
|
||||
/* window-choose.c */
|
||||
extern const struct window_mode window_choose_mode;
|
||||
void window_choose_add(struct window_pane *,
|
||||
|
@ -34,7 +34,6 @@ void window_copy_mouse(
|
||||
struct window_pane *, struct session *, struct mouse_event *);
|
||||
|
||||
void window_copy_redraw_lines(struct window_pane *, u_int, u_int);
|
||||
void window_copy_redraw_screen(struct window_pane *);
|
||||
void window_copy_write_line(
|
||||
struct window_pane *, struct screen_write_ctx *, u_int);
|
||||
void window_copy_write_lines(
|
||||
@ -52,7 +51,6 @@ void window_copy_search_down(struct window_pane *, const char *);
|
||||
void window_copy_goto_line(struct window_pane *, const char *);
|
||||
void window_copy_update_cursor(struct window_pane *, u_int, u_int);
|
||||
void window_copy_start_selection(struct window_pane *);
|
||||
int window_copy_update_selection(struct window_pane *);
|
||||
void *window_copy_get_selection(struct window_pane *, size_t *);
|
||||
void window_copy_copy_buffer(struct window_pane *, int, void *, size_t);
|
||||
void window_copy_copy_pipe(
|
||||
@ -136,6 +134,10 @@ window_copy_init(struct window_pane *wp)
|
||||
|
||||
data->backing = NULL;
|
||||
|
||||
#ifdef TMATE
|
||||
data->password_cb = NULL;
|
||||
#endif
|
||||
|
||||
return (s);
|
||||
}
|
||||
|
||||
@ -614,7 +616,10 @@ __window_copy_key(struct window_pane *wp, struct session *sess, int key)
|
||||
case WINDOW_COPY_JUMPTOFORWARD:
|
||||
case WINDOW_COPY_JUMPTOBACK:
|
||||
case WINDOW_COPY_NUMERICPREFIX:
|
||||
#ifdef TMATE
|
||||
case WINDOW_COPY_PASSWORD:
|
||||
break;
|
||||
#endif
|
||||
case WINDOW_COPY_SEARCHUP:
|
||||
if (cmd == MODEKEYCOPY_SEARCHAGAIN) {
|
||||
for (; np != 0; np--) {
|
||||
@ -746,7 +751,18 @@ window_copy_key_input(struct window_pane *wp, int key)
|
||||
window_copy_goto_line(wp, data->inputstr);
|
||||
*data->inputstr = '\0';
|
||||
break;
|
||||
#ifdef TMATE
|
||||
case WINDOW_COPY_PASSWORD:
|
||||
if (data->password_cb) {
|
||||
data->password_cb(data->inputstr,
|
||||
data->password_cb_private);
|
||||
}
|
||||
*data->inputstr = '\0';
|
||||
window_copy_copy_selection(wp, -1);
|
||||
window_pane_reset_mode(wp);
|
||||
#endif
|
||||
}
|
||||
|
||||
data->numprefix = -1;
|
||||
return (1);
|
||||
case MODEKEY_OTHER:
|
||||
@ -1081,24 +1097,46 @@ window_copy_write_line(
|
||||
struct screen *s = &data->screen;
|
||||
struct options *oo = &wp->window->options;
|
||||
struct grid_cell gc;
|
||||
#ifdef TMATE
|
||||
char hdr[256];
|
||||
#else
|
||||
char hdr[32];
|
||||
#endif
|
||||
size_t last, xoff = 0, size = 0;
|
||||
|
||||
window_mode_attrs(&gc, oo);
|
||||
|
||||
last = screen_size_y(s) - 1;
|
||||
if (py == 0) {
|
||||
#ifdef TMATE
|
||||
if (data->inputtype != WINDOW_COPY_PASSWORD) {
|
||||
#endif
|
||||
size = xsnprintf(hdr, sizeof hdr,
|
||||
"[%u/%u]", data->oy, screen_hsize(data->backing));
|
||||
if (size > screen_size_x(s))
|
||||
size = screen_size_x(s);
|
||||
screen_write_cursormove(ctx, screen_size_x(s) - size, 0);
|
||||
screen_write_puts(ctx, &gc, "%s", hdr);
|
||||
#ifdef TMATE
|
||||
}
|
||||
#endif
|
||||
} else if (py == last && data->inputtype != WINDOW_COPY_OFF) {
|
||||
if (data->inputtype == WINDOW_COPY_NUMERICPREFIX) {
|
||||
xoff = size = xsnprintf(hdr, sizeof hdr,
|
||||
"Repeat: %u", data->numprefix);
|
||||
} else {
|
||||
|
||||
#ifdef TMATE
|
||||
if (data->inputtype == WINDOW_COPY_PASSWORD) {
|
||||
int password_len = strlen(data->inputstr);
|
||||
xoff = size = xsnprintf(hdr, sizeof hdr, "%s: ", data->inputprompt);
|
||||
memset(hdr+xoff, '*', password_len);
|
||||
xoff += password_len;
|
||||
size += password_len;
|
||||
hdr[xoff] = '\0';
|
||||
}
|
||||
else
|
||||
#endif
|
||||
xoff = size = xsnprintf(hdr, sizeof hdr,
|
||||
"%s: %s", data->inputprompt, data->inputstr);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user