diff options
author | Nicolas Viennot <nicolas@viennot.biz> | 2013-07-22 19:45:34 -0400 |
---|---|---|
committer | Nicolas Viennot <nicolas@viennot.biz> | 2013-07-23 16:55:06 -0400 |
commit | 13d3439933410669c21916ac60977719ea469a11 (patch) | |
tree | 6397349648b56b5aae13d8762fad2a29faab6ec3 | |
parent | b97568cac283b6ff847521014524bd310714ebb4 (diff) |
SSH key passphrase support1.8.6
Closes #6
-rw-r--r-- | tmate-encoder.c | 1 | ||||
-rw-r--r-- | tmate-session.c | 8 | ||||
-rw-r--r-- | tmate-ssh-client.c | 122 | ||||
-rw-r--r-- | tmate.h | 4 | ||||
-rw-r--r-- | tmux.h | 17 | ||||
-rw-r--r-- | window-copy.c | 42 |
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); -} @@ -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; @@ -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); } |