summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNicolas Viennot <nicolas@viennot.biz>2013-07-22 19:45:34 -0400
committerNicolas Viennot <nicolas@viennot.biz>2013-07-23 16:55:06 -0400
commit13d3439933410669c21916ac60977719ea469a11 (patch)
tree6397349648b56b5aae13d8762fad2a29faab6ec3
parentb97568cac283b6ff847521014524bd310714ebb4 (diff)
SSH key passphrase support1.8.6
Closes #6
-rw-r--r--tmate-encoder.c1
-rw-r--r--tmate-session.c8
-rw-r--r--tmate-ssh-client.c122
-rw-r--r--tmate.h4
-rw-r--r--tmux.h17
-rw-r--r--window-copy.c42
6 files changed, 165 insertions, 29 deletions
diff --git a/tmate-encoder.c b/tmate-encoder.c
index e4a95a66..4ec59447 100644
--- a/tmate-encoder.c
+++ b/tmate-encoder.c
@@ -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();
}
diff --git a/tmate-session.c b/tmate-session.c
index bbca4c12..02469c59 100644
--- a/tmate-session.c
+++ b/tmate-session.c
@@ -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();
}
diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c
index 50842d97..a930e28c 100644
--- a/tmate-ssh-client.c
+++ b/tmate-ssh-client.c
@@ -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);
-}
diff --git a/tmate.h b/tmate.h
index 687fd7e6..673f3a6d 100644
--- a/tmate.h
+++ b/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;
diff --git a/tmux.h b/tmux.h
index c28cb9d9..94858f6d 100644
--- a/tmux.h
+++ b/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 *,
diff --git a/window-copy.c b/window-copy.c
index d3af1efb..3cb7eb38 100644
--- a/window-copy.c
+++ b/window-copy.c
@@ -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);
}