From d654ff22194bde5fc6e02b2f93ae55cb69c4ddcc Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Wed, 18 Sep 2019 23:35:07 -0400 Subject: [PATCH 01/59] Send TMATE_READY message when the config files are done loading This fixes bug where webhooks are not registering correctly, leading to a disconnect and reconnect. --- server.c | 4 ---- tmate-session.c | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/server.c b/server.c index 81334f1e..a2378959 100644 --- a/server.c +++ b/server.c @@ -205,10 +205,6 @@ server_start(struct event_base *base, int lockfd, char *lockfile) status_prompt_load_history(); -#ifdef TMATE - tmate_write_ready(); -#endif - server_add_accept(0); proc_loop(server_proc, server_loop); diff --git a/tmate-session.c b/tmate-session.c index 8d647203..106687e1 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -138,6 +138,7 @@ void tmate_session_start(void) * - While we are parsing the config file, we need to be able to * serialize it, and so we need a worker encoder. */ + tmate_write_ready(); lookup_and_connect(); } From 44635e752d17993943885c1e77864f5395d740f6 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sat, 12 Oct 2019 13:50:27 -0400 Subject: [PATCH 02/59] Use docker to build static releases Static builds are possible with the musl C library. glibc is capricious when it comes to static linking and DNS support (and other things). --- Dockerfile | 27 +++++++++++++++++++ Makefile.static-build | 61 ------------------------------------------ compat/clock_gettime.c | 9 ------- compat/memcpy.c | 11 -------- configure.ac | 15 ++--------- 5 files changed, 29 insertions(+), 94 deletions(-) create mode 100644 Dockerfile delete mode 100644 Makefile.static-build delete mode 100644 compat/clock_gettime.c delete mode 100644 compat/memcpy.c diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 00000000..82d75ef4 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,27 @@ +FROM alpine:3.10 + +WORKDIR /build + +RUN apk add --no-cache wget cmake make gcc g++ linux-headers zlib-dev openssl-dev \ + automake autoconf libevent-dev ncurses-dev msgpack-c-dev libexecinfo-dev \ + ncurses-static libexecinfo-static libevent-static msgpack-c ncurses-libs \ + libevent libexecinfo openssl zlib + +RUN set -ex; \ + mkdir -p /src/libssh/build; \ + cd /src; \ + wget -O libssh.tar.xz https://www.libssh.org/files/0.9/libssh-0.9.0.tar.xz; \ + tar -xf libssh.tar.xz -C /src/libssh --strip-components=1; \ + cd /src/libssh/build; \ + cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr \ + -DWITH_SFTP=OFF -DWITH_SERVER=OFF -DWITH_PCAP=OFF \ + -DWITH_STATIC_LIB=ON -DWITH_GSSAPI=OFF ..; \ + make -j $(nproc); \ + make install + +COPY . . + +RUN ./autogen.sh +RUN ./configure --enable-static +RUN make -j $(nproc) +RUN strip tmate diff --git a/Makefile.static-build b/Makefile.static-build deleted file mode 100644 index 9bc83d92..00000000 --- a/Makefile.static-build +++ /dev/null @@ -1,61 +0,0 @@ -LIBSSH=libssh-0.7.2 -LIBSSH_URL=https://red.libssh.org/attachments/download/177/$(LIBSSH).tar.xz -LIBSSH_LIB=ext/lib/libssh.a - -MSGPACK=msgpack-1.3.0 -MSGPACK_URL=https://github.com/msgpack/msgpack-c/releases/download/cpp-1.3.0/$(MSGPACK).tar.gz -MSGPACK_LIB=ext/lib/libmsgpack.a - -TMATE_CONFIGURE=PKG_CONFIG_PATH=./ext/lib/pkgconfig - -LIBC=$(shell gcc -print-file-name=libc.a) -STATIC_LIBC_OBJECTS=fdelt_chk -STATIC_COMPAT_OBJECTS=memcpy clock_gettime - -all: tmate - -dependencies: - apt-get install build-essential cmake libssl-dev autoconf automake pkg-config libtool libevent-dev libncurses-dev zlib1g-dev - -downloads/$(notdir $(LIBSSH_URL)): - mkdir -p downloads - wget -O $@ $(LIBSSH_URL) - -$(LIBSSH)/.ready: downloads/$(notdir $(LIBSSH_URL)) - tar xf $< - touch $@ - -downloads/$(notdir $(MSGPACK_URL)): - mkdir -p downloads - wget -O $@ $(MSGPACK_URL) - -$(MSGPACK)/.ready: downloads/$(notdir $(MSGPACK_URL)) - tar xf $< - touch $@ - -$(LIBSSH_LIB): $(LIBSSH)/.ready - mkdir -p $(LIBSSH)/build - cd $(LIBSSH)/build; ([ -f Makefile ] || cmake -DCMAKE_INSTALL_PREFIX:PATH=$(shell pwd)/ext .. -DWITH_SFTP=OFF -DWITH_SERVER=OFF -DWITH_PCAP=OFF -DWITH_STATIC_LIB=ON -DWITH_GSSAPI=OFF) - +make -C $(LIBSSH)/build install - -$(MSGPACK_LIB): $(MSGPACK)/.ready - mkdir -p $(MSGPACK)/build - cd $(MSGPACK)/build; ([ -f Makefile ] || cmake -DCMAKE_INSTALL_PREFIX:PATH=$(shell pwd)/ext ..) - +make -C $(MSGPACK)/build install - -libc/%.o: - mkdir -p libc - cd libc; ar x $(LIBC) $(notdir $@) - -compat/%.o: compat/%.c - gcc -c -o $@ $< - -tmate: $(MSGPACK_LIB) $(LIBSSH_LIB) $(patsubst %,libc/%.o,$(STATIC_LIBC_OBJECTS)) $(patsubst %,compat/%.o,$(STATIC_COMPAT_OBJECTS)) - ./autogen.sh - $(TMATE_CONFIGURE) ./configure --enable-static - +make - strip tmate - -clean: - rm -rf ext libc $(LIBSSH) $(MSGPACK) - +make clean diff --git a/compat/clock_gettime.c b/compat/clock_gettime.c deleted file mode 100644 index 0b631b79..00000000 --- a/compat/clock_gettime.c +++ /dev/null @@ -1,9 +0,0 @@ -#define _GNU_SOURCE -#include -#include -#include - -int clock_gettime(clockid_t clk_id, struct timespec *tp) -{ - return syscall(SYS_clock_gettime, clk_id, tp); -} diff --git a/compat/memcpy.c b/compat/memcpy.c deleted file mode 100644 index 37092a33..00000000 --- a/compat/memcpy.c +++ /dev/null @@ -1,11 +0,0 @@ -// http://stackoverflow.com/questions/8823267/linking-against-older-symbol-version-in-a-so-file - -#include - -/* some systems do not have newest memcpy@@GLIBC_2.14 - stay with old good one */ -asm (".symver memcpy, memcpy@GLIBC_2.2.5"); - -void *__wrap_memcpy(void *dest, const void *src, size_t n) -{ - return memcpy(dest, src, n); -} diff --git a/configure.ac b/configure.ac index 647ae333..2681300a 100644 --- a/configure.ac +++ b/configure.ac @@ -47,10 +47,11 @@ AC_ARG_ENABLE( found_static=$enable_static ) if test "x$found_static" = xyes; then + # XXX Static build are only doable with the musl library PKG_CONFIG="pkg-config --static" CFLAGS="$CFLAGS -flto" - LDFLAGS="$LDFLAGS -flto" + LDFLAGS="$LDFLAGS -flto -static -no-pie" PKG_CHECK_MODULES([ZLIB], [zlib], [ CPPFLAGS="$ZLIB_CFLAGS $CPPFLAGS" @@ -61,7 +62,6 @@ if test "x$found_static" = xyes; then CPPFLAGS="$LIBCRYPTO_CFLAGS $CPPFLAGS" LIBS="$LIBCRYPTO_LIBS $LIBS" ]) - # See more static settings below... (search for found_static) fi # Is this gcc? @@ -462,17 +462,6 @@ if test "x$found_getopt" != xno; then fi AM_CONDITIONAL(NO_GETOPT, [test "x$found_getopt" = xno]) -if test "x$found_static" = xyes; then - # libc and libdl should be dynamically linked. - # but we want to lower our requirements for libc's version. - # so we extract some symobls and add them here - if test `uname -m` = x86_64; then - LIBS="compat/memcpy.o -Wl,--wrap=memcpy $LIBS" - fi - LIBS="compat/clock_gettime.o libc/fdelt_chk.o $LIBS" - LIBS="-Wl,-Bstatic ${LIBS/-ldl/} -Wl,-Bdynamic -ldl" -fi - # Check for BSD-style integer types. AC_MSG_CHECKING(for BSD-style unsigned types) AC_COMPILE_IFELSE([AC_LANG_SOURCE( From 74ff5229830afcca8cd57976a48632fef6f85c17 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sat, 12 Oct 2019 14:13:12 -0400 Subject: [PATCH 03/59] Build static build releases on travis-ci --- .travis.yml | 42 ++++++++++++++++++++++++++++++++++-------- Dockerfile | 27 ++++++++++++++------------- package_release.sh | 14 ++++++++++++++ 3 files changed, 62 insertions(+), 21 deletions(-) create mode 100755 package_release.sh diff --git a/.travis.yml b/.travis.yml index a1d7e427..a02e89a8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,36 @@ language: c +services: +- docker + matrix: - include: - - compiler: gcc - - compiler: clang - env: CFLAGS="-g -O2" -before_install: - - sudo apt-get update -qq - - sudo apt-get -y install debhelper autotools-dev dh-autoreconf file libncurses5-dev libevent-dev pkg-config libutempter-dev build-essential -script: (CFLAGS= ./autogen.sh) && ./configure --enable-debug && make + include: + - arch: amd64 + env: PLATFORM=amd64 + - arch: amd64 + env: PLATFORM=i386 + - arch: arm64 + env: PLATFORM=arm32v6 + - arch: arm64 + env: PLATFORM=arm32v7 + - arch: arm64 + env: PLATFORM=arm64v8 + +script: +- 'docker build . --tag local-$PLATFORM/tmate-build --build-arg PLATFORM=$PLATFORM' +# On arch=arm64, some directories are not setup correctly, and 'ruby -S gem +# install dpl' required by the release push scripts fails. +- 'if [ "$TRAVIS_TAG" ]; then sudo chown -R $USER: /var/lib/gems /usr/local/bin; fi' +- 'if [ "$TRAVIS_TAG" ]; then ./package_release.sh $TRAVIS_TAG $PLATFORM; fi' + +deploy: + provider: releases + api_key: + secure: T2109tjjOsrVLEpJZK/uxmO0AuDGXYFdN4AAsNTmVwu/W5dcX57Kk2TCgqDuLfD21iGGXP0U/OYHM06IfBDODBWCA9P8ASHYsenS7wIiFnvCEMbfzoAFyBMrXN2kNdM2+ho3aqc0xE2lQKOKDLxpGm5FZrzujscXXzxQjWBU5Hk= + skip_cleanup: true + overwrite: true + file_glob: true + file: /tmp/tmate-release/*.tar.* + on: + repo: tmate-io/tmate + branch: master + tags: true diff --git a/Dockerfile b/Dockerfile index 82d75ef4..c7aa2b9f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,5 @@ -FROM alpine:3.10 +ARG PLATFORM=amd64 +FROM ${PLATFORM}/alpine:3.10 WORKDIR /build @@ -8,20 +9,20 @@ RUN apk add --no-cache wget cmake make gcc g++ linux-headers zlib-dev openssl-de libevent libexecinfo openssl zlib RUN set -ex; \ - mkdir -p /src/libssh/build; \ - cd /src; \ - wget -O libssh.tar.xz https://www.libssh.org/files/0.9/libssh-0.9.0.tar.xz; \ - tar -xf libssh.tar.xz -C /src/libssh --strip-components=1; \ - cd /src/libssh/build; \ - cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr \ - -DWITH_SFTP=OFF -DWITH_SERVER=OFF -DWITH_PCAP=OFF \ - -DWITH_STATIC_LIB=ON -DWITH_GSSAPI=OFF ..; \ - make -j $(nproc); \ - make install + mkdir -p /src/libssh/build; \ + cd /src; \ + wget -O libssh.tar.xz https://www.libssh.org/files/0.9/libssh-0.9.0.tar.xz; \ + tar -xf libssh.tar.xz -C /src/libssh --strip-components=1; \ + cd /src/libssh/build; \ + cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr \ + -DWITH_SFTP=OFF -DWITH_SERVER=OFF -DWITH_PCAP=OFF \ + -DWITH_STATIC_LIB=ON -DWITH_GSSAPI=OFF ..; \ + make -j $(nproc); \ + make install COPY . . -RUN ./autogen.sh -RUN ./configure --enable-static +RUN ./autogen.sh && ./configure --enable-static RUN make -j $(nproc) RUN strip tmate +RUN ./tmate -V diff --git a/package_release.sh b/package_release.sh new file mode 100755 index 00000000..f4186e3c --- /dev/null +++ b/package_release.sh @@ -0,0 +1,14 @@ +#!/bin/bash +set -eux +VERSION=$1 +PLATFORM=$2 +RELEASE_NAME=tmate-$VERSION-static-linux-$PLATFORM + +# This assumes the follow command has already been run: +# docker build . --tag local-$PLATFORM/tmate-build --build-arg PLATFORM=$PLATFORM + +mkdir -p /tmp/tmate-release/$RELEASE_NAME +cd /tmp/tmate-release +docker run --rm local-$PLATFORM/tmate-build cat tmate > $RELEASE_NAME/tmate +chmod +x $RELEASE_NAME/tmate +tar -cf - $RELEASE_NAME | xz > tmate-$VERSION-static-linux-$PLATFORM.tar.xz From 7153958e9908658383438745592d9a8da64b2a3f Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sat, 12 Oct 2019 21:09:39 -0400 Subject: [PATCH 04/59] Allow the use of C.UTF-8 locale --- tmux.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tmux.c b/tmux.c index d55c2e1d..d7cf8d97 100644 --- a/tmux.c +++ b/tmux.c @@ -205,12 +205,12 @@ main(int argc, char **argv) const char *s; int opt, flags, keys; - if (setlocale(LC_CTYPE, "en_US.UTF-8") == NULL) { + if (setlocale(LC_CTYPE, "en_US.UTF-8") == NULL && + setlocale(LC_CTYPE, "C.UTF-8") == NULL) { if (setlocale(LC_CTYPE, "") == NULL) errx(1, "invalid LC_ALL, LC_CTYPE or LANG"); s = nl_langinfo(CODESET); - if (strcasecmp(s, "UTF-8") != 0 && - strcasecmp(s, "UTF8") != 0) + if (strcasecmp(s, "UTF-8") != 0 && strcasecmp(s, "UTF8") != 0) errx(1, "need UTF-8 locale (LC_CTYPE) but have %s", s); } From 7262aead737af678923ae7b9209ae220b0f915b9 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sat, 12 Oct 2019 19:29:48 -0400 Subject: [PATCH 05/59] Bump to version 2.3.1 --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 2681300a..f623cadc 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # configure.ac -AC_INIT(tmate, 2.3.0) +AC_INIT(tmate, 2.3.1) AC_CONFIG_AUX_DIR(etc) AM_INIT_AUTOMAKE([foreign subdir-objects]) From 4efe25d91d5c5de0fcb4df2cf9199a96b13afd66 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Tue, 15 Oct 2019 03:04:24 -0400 Subject: [PATCH 06/59] During SSH authentication, try the none auth method first --- tmate-ssh-client.c | 44 ++++++++++++++++++++++++++++++++------------ tmate.h | 4 +++- 2 files changed, 35 insertions(+), 13 deletions(-) diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index c5fb4243..e33f4b17 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -235,7 +235,7 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) case SSH_INIT: client->session = session = ssh_new(); if (!session) { - tmate_fatal("cannot initialize"); + tmate_fatal("cannot ssh_new()"); return; } @@ -344,13 +344,30 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) */ tmate_debug("Connected to %s", client->server_ip); on_ssh_auth_server_complete(client); - client->state = SSH_AUTH_CLIENT; + client->state = SSH_AUTH_CLIENT_NONE; /* fall through */ - case SSH_AUTH_CLIENT: + case SSH_AUTH_CLIENT_NONE: + switch (ssh_userauth_none(session, NULL)) { + case SSH_AUTH_AGAIN: + return; + case SSH_AUTH_ERROR: + kill_ssh_client(client, "Auth error: %s", ssh_get_error(session)); + return; + case SSH_AUTH_SUCCESS: + tmate_debug("Auth successful via none method"); + client->state = SSH_NEW_CHANNEL; + goto SSH_NEW_CHANNEL; + case SSH_AUTH_PARTIAL: + case SSH_AUTH_DENIED: + client->state = SSH_AUTH_CLIENT_PUBKEY; + /* fall through */ + } + + case SSH_AUTH_CLIENT_PUBKEY: client->tried_passphrase = client->tmate_session->passphrase; - switch (ssh_userauth_autopubkey(session, client->tried_passphrase)) { + switch (ssh_userauth_publickey_auto(session, NULL, client->tried_passphrase)) { case SSH_AUTH_AGAIN: return; case SSH_AUTH_PARTIAL: @@ -372,17 +389,20 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) kill_ssh_client(client, "Auth error: %s", ssh_get_error(session)); return; case SSH_AUTH_SUCCESS: - tmate_debug("Auth successful"); - client->state = SSH_OPEN_CHANNEL; - - client->channel = channel = ssh_channel_new(session); - if (!channel) { - tmate_fatal("cannot initialize"); - return; - } + tmate_debug("Auth successful with pubkey"); + client->state = SSH_NEW_CHANNEL; /* fall through */ } +SSH_NEW_CHANNEL: + case SSH_NEW_CHANNEL: + client->channel = channel = ssh_channel_new(session); + if (!channel) { + tmate_fatal("cannot ssh_channel_new()"); + return; + } + client->state = SSH_OPEN_CHANNEL; + case SSH_OPEN_CHANNEL: switch (ssh_channel_open_session(channel)) { case SSH_AGAIN: diff --git a/tmate.h b/tmate.h index f096a35c..7deb0ba6 100644 --- a/tmate.h +++ b/tmate.h @@ -106,7 +106,9 @@ enum tmate_ssh_client_state_types { SSH_INIT, SSH_CONNECT, SSH_AUTH_SERVER, - SSH_AUTH_CLIENT, + SSH_AUTH_CLIENT_NONE, + SSH_AUTH_CLIENT_PUBKEY, + SSH_NEW_CHANNEL, SSH_OPEN_CHANNEL, SSH_BOOTSTRAP, SSH_READY, From 7f693a97aede385aad30db1412c48f0093b72509 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 20 Oct 2019 21:23:48 -0400 Subject: [PATCH 07/59] Add options for customizing session names (WIP) --- options-table.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/options-table.c b/options-table.c index 4966431c..617ba05e 100644 --- a/options-table.c +++ b/options-table.c @@ -959,6 +959,24 @@ const struct options_table_entry options_table[] = { .scope = OPTIONS_TABLE_SERVER, .default_str = "" }, + + { .name = "tmate-account-key", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_SERVER, + .default_str = "" + }, + + { .name = "tmate-session-name", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_SERVER, + .default_str = "" + }, + + { .name = "tmate-session-name-ro", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_SERVER, + .default_str = "" + }, #endif { .name = NULL } From 6e84bab68ca80f90023d4336467a44098d17a06f Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 3 Nov 2019 05:11:37 -0500 Subject: [PATCH 08/59] Add foreground mode with -F --- cfg.c | 18 ++++++++++++++++ client.c | 51 ++++++++++++++++++++++++++++++++++++++++++++++ cmd-new-session.c | 3 +++ log.c | 49 +++++++++++++++++++++++++++++++------------- proc.c | 10 +++++++-- server.c | 14 ++++++++++--- session.c | 21 +++++++++++++++---- signal.c | 18 ++++++++++++++++ tmate-msg.c | 2 +- tmate-session.c | 2 +- tmate-ssh-client.c | 14 +++++++------ tmate.h | 7 +++---- tmux.c | 13 ++++++++++-- tmux.h | 12 ++++++++++- 14 files changed, 196 insertions(+), 38 deletions(-) diff --git a/cfg.c b/cfg.c index 572f8369..68894cb2 100644 --- a/cfg.c +++ b/cfg.c @@ -149,6 +149,20 @@ load_cfg(const char *path, struct cmd_q *cmdq, char **cause) return (found); } +static void print_cfg_errors(void) +{ + u_int i; + + for (i = 0; i < cfg_ncauses; i++) { + tmate_info("%s", cfg_causes[i]); + free(cfg_causes[i]); + } + + free(cfg_causes); + cfg_causes = NULL; + cfg_ncauses = 0; +} + void cfg_default_done(__unused struct cmd_q *cmdq) { @@ -158,6 +172,10 @@ cfg_default_done(__unused struct cmd_q *cmdq) #ifdef TMATE tmate_session_start(); + if (tmate_foreground && cfg_ncauses) { + print_cfg_errors(); + exit(1); + } #endif if (!RB_EMPTY(&sessions)) diff --git a/client.c b/client.c index 164abdd3..ad349972 100644 --- a/client.c +++ b/client.c @@ -32,6 +32,7 @@ #include #include "tmux.h" +#include "tmate.h" struct tmuxproc *client_proc; struct tmuxpeer *client_peer; @@ -213,8 +214,56 @@ client_exit_message(void) #ifdef TMATE extern const struct cmd_entry cmd_attach_session_entry; extern const struct cmd_entry cmd_new_session_entry; + +/* For foreground mode */ +static int __argc; +static char **__argv; #endif +static void _run_initial_client_cmd(int argc, char **argv) +{ + struct cmd_q *cmd_q; + struct cmd_list *cmdlist; + char *cause; + const char *default_argv[] = {"new-session"}; + + if (argc == 0) { + argc = 1; + argv = (char **)default_argv; + } + + cmd_q = cmdq_new(NULL); /* No client */ + + if ((cmdlist = cmd_list_parse(argc, (char **)argv, NULL, 0, &cause)) == NULL) { + tmate_fatal("%s", cause); + } + + cmdq_run(cmd_q, cmdlist, NULL); + cmd_list_free(cmdlist); + cmdq_free(cmd_q); + + /* error messages land in cfg_causes */ + extern char **cfg_causes; + extern u_int cfg_ncauses; + int has_error = !!cfg_ncauses; + for (u_int i = 0; i < cfg_ncauses; i++) { + tmate_info("%s", cfg_causes[i]); + free(cfg_causes[i]); + } + + free(cfg_causes); + cfg_causes = NULL; + cfg_ncauses = 0; + + if (has_error) + exit(1); +} + +void run_initial_client_cmd(void) +{ + _run_initial_client_cmd(__argc, __argv); +} + /* Client main loop. */ int client_main(struct event_base *base, int argc, char **argv, int flags, @@ -232,6 +281,8 @@ client_main(struct event_base *base, int argc, char **argv, int flags, size_t size; #ifdef TMATE int cant_nest = 0; + __argc = argc; + __argv = argv; #endif /* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */ diff --git a/cmd-new-session.c b/cmd-new-session.c index 357ffed1..fb2f7eab 100644 --- a/cmd-new-session.c +++ b/cmd-new-session.c @@ -131,6 +131,9 @@ cmd_new_session_exec(struct cmd *self, struct cmd_q *cmdq) if (c == NULL) detached = 1; + if (tmate_foreground) + detached = 1; + /* Is this client already attached? */ already_attached = 0; if (c != NULL && c->session != NULL) diff --git a/log.c b/log.c index 018348cf..bc798778 100644 --- a/log.c +++ b/log.c @@ -32,6 +32,11 @@ static int log_level; static void log_event_cb(int, const char *); static void log_vwrite(const char *, va_list); +static int is_log_stdout(void) +{ + return fileno(log_file) <= 2; +} + /* Log callback for libevent. */ static void log_event_cb(__unused int severity, const char *msg) @@ -53,6 +58,18 @@ log_get_level(void) return (log_level); } +void +log_open_fp(FILE *f) +{ + if (log_file != NULL && !is_log_stdout()) + fclose(log_file); + + log_file = f; + + setvbuf(log_file, NULL, _IOLBF, 0); + event_set_log_callback(log_event_cb); +} + /* Open logging to file. */ void log_open(const char *name) @@ -62,24 +79,18 @@ log_open(const char *name) if (log_level == 0) return; - if (log_file != NULL) - fclose(log_file); - xasprintf(&path, "tmate-%s-%ld.log", name, (long)getpid()); - log_file = fopen(path, "w"); + FILE *f = fopen(path, "w"); free(path); - if (log_file == NULL) - return; - - setvbuf(log_file, NULL, _IOLBF, 0); - event_set_log_callback(log_event_cb); + if (f) + log_open_fp(f); } /* Close logging. */ void log_close(void) { - if (log_file != NULL) + if (log_file != NULL && !is_log_stdout()) fclose(log_file); log_file = NULL; @@ -102,9 +113,16 @@ log_vwrite(const char *msg, va_list ap) exit(1); gettimeofday(&tv, NULL); - if (fprintf(log_file, "%lld.%06d %s\n", (long long)tv.tv_sec, - (int)tv.tv_usec, out) == -1) - exit(1); + + if (is_log_stdout()) { + if (fprintf(log_file, "%s\n", out) == -1) + exit(1); + } else { + if (fprintf(log_file, "%lld.%06d %s\n", (long long)tv.tv_sec, + (int)tv.tv_usec, out) == -1) + exit(1); + } + fflush(log_file); free(out); @@ -113,10 +131,13 @@ log_vwrite(const char *msg, va_list ap) /* Log a debug message. */ void -log_debug(const char *msg, ...) +log_emit(int level, const char *msg, ...) { va_list ap; + if (log_level < level) + return; + va_start(ap, msg); log_vwrite(msg, ap); va_end(ap); diff --git a/proc.c b/proc.c index 27880f57..edd4a6f8 100644 --- a/proc.c +++ b/proc.c @@ -172,7 +172,7 @@ proc_start(const char *name, struct event_base *base, int forkflag, struct tmuxproc *tp; struct utsname u; - if (forkflag) { + if (forkflag && !tmate_foreground) { switch (fork()) { case -1: fatal("fork failed"); @@ -189,7 +189,13 @@ proc_start(const char *name, struct event_base *base, int forkflag, fatalx("event_reinit failed"); } - log_open(name); + if (tmate_foreground) { + if (forkflag) + clear_signals(0); + log_open_fp(stdout); + } else { + log_open(name); + } #ifdef HAVE_SETPROCTITLE setproctitle("%s (%s)", name, socket_path); diff --git a/server.c b/server.c index a2378959..05706769 100644 --- a/server.c +++ b/server.c @@ -152,14 +152,16 @@ server_start(struct event_base *base, int lockfd, char *lockfile) { int pair[2]; - if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0) - fatal("socketpair failed"); + if (!tmate_foreground) + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pair) != 0) + fatal("socketpair failed"); server_proc = proc_start("server", base, 1, server_signal); if (server_proc == NULL) { close(pair[1]); return (pair[0]); } + close(pair[0]); if (log_get_level() > 3) @@ -190,7 +192,8 @@ server_start(struct event_base *base, int lockfd, char *lockfile) if (server_fd == -1) fatal("couldn't create socket"); server_update_socket(); - server_client_create(pair[1]); + if (!tmate_foreground) + server_client_create(pair[1]); if (lockfd >= 0) { unlink(lockfile); @@ -207,11 +210,15 @@ server_start(struct event_base *base, int lockfd, char *lockfile) server_add_accept(0); + if (tmate_foreground) + run_initial_client_cmd(); + proc_loop(server_proc, server_loop); status_prompt_save_history(); #ifdef TMATE unlink(socket_path); #endif + exit(0); } @@ -361,6 +368,7 @@ server_signal(int sig) int fd; switch (sig) { + case SIGINT: case SIGTERM: server_exit = 1; server_send_exit(); diff --git a/session.c b/session.c index 5a3b867a..91fb9c1d 100644 --- a/session.c +++ b/session.c @@ -215,10 +215,6 @@ session_destroy(struct session *s) log_debug("session %s destroyed", s->name); -#ifdef TMATE - tmate_write_fin(); -#endif - RB_REMOVE(sessions, &sessions, s); notify_session_closed(s); @@ -240,6 +236,23 @@ session_destroy(struct session *s) free((void *)s->cwd); session_unref(s); + +#ifdef TMATE + if (tmate_foreground && !server_exit) { + tmate_info("Shell exited, restarting"); + /* + * throttle restarts. This is a blocking sleep. + * It's simpler than using a timer, but fairly harmless + * from a blocking perspective. + */ + usleep(500*1000); + next_session_id = 0; + run_initial_client_cmd(); + } else { + tmate_info("Session terminated"); + tmate_write_fin(); + } +#endif } /* Check a session name is valid: not empty and no colons or periods. */ diff --git a/signal.c b/signal.c index 19938638..f20a0257 100644 --- a/signal.c +++ b/signal.c @@ -24,6 +24,7 @@ #include "tmux.h" +struct event ev_sigint; struct event ev_sighup; struct event ev_sigchld; struct event ev_sigcont; @@ -40,15 +41,23 @@ set_signals(void (*handler)(int, short, void *), void *arg) sigemptyset(&sigact.sa_mask); sigact.sa_flags = SA_RESTART; sigact.sa_handler = SIG_IGN; +#ifndef TMATE if (sigaction(SIGINT, &sigact, NULL) != 0) fatal("sigaction failed"); +#endif if (sigaction(SIGPIPE, &sigact, NULL) != 0) fatal("sigaction failed"); if (sigaction(SIGUSR2, &sigact, NULL) != 0) fatal("sigaction failed"); +#ifndef TMATE if (sigaction(SIGTSTP, &sigact, NULL) != 0) fatal("sigaction failed"); +#endif +#ifdef TMATE + signal_set(&ev_sigint, SIGINT, handler, arg); + signal_add(&ev_sigint, NULL); +#endif signal_set(&ev_sighup, SIGHUP, handler, arg); signal_add(&ev_sighup, NULL); signal_set(&ev_sigchld, SIGCHLD, handler, arg); @@ -72,16 +81,24 @@ clear_signals(int after_fork) sigemptyset(&sigact.sa_mask); sigact.sa_flags = SA_RESTART; sigact.sa_handler = SIG_DFL; +#ifndef TMATE if (sigaction(SIGINT, &sigact, NULL) != 0) fatal("sigaction failed"); +#endif if (sigaction(SIGPIPE, &sigact, NULL) != 0) fatal("sigaction failed"); if (sigaction(SIGUSR2, &sigact, NULL) != 0) fatal("sigaction failed"); +#ifndef TMATE if (sigaction(SIGTSTP, &sigact, NULL) != 0) fatal("sigaction failed"); +#endif if (after_fork) { +#ifdef TMATE + if (sigaction(SIGINT, &sigact, NULL) != 0) + fatal("sigaction failed"); +#endif if (sigaction(SIGHUP, &sigact, NULL) != 0) fatal("sigaction failed"); if (sigaction(SIGCHLD, &sigact, NULL) != 0) @@ -95,6 +112,7 @@ clear_signals(int after_fork) if (sigaction(SIGWINCH, &sigact, NULL) != 0) fatal("sigaction failed"); } else { + event_del(&ev_sigint); event_del(&ev_sighup); event_del(&ev_sigchld); event_del(&ev_sigcont); diff --git a/tmate-msg.c b/tmate-msg.c index 880e3905..a47f9e4d 100644 --- a/tmate-msg.c +++ b/tmate-msg.c @@ -56,7 +56,7 @@ void __tmate_status_message(const char *fmt, va_list ap) char *message; xvasprintf(&message, fmt, ap); - tmate_debug("%s", message); + tmate_info("%s", message); TAILQ_FOREACH(c, &clients, entry) { if (c && !(c->flags & CLIENT_READONLY)) diff --git a/tmate-session.c b/tmate-session.c index 106687e1..5ab13511 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -96,7 +96,7 @@ static void lookup_and_connect(void) tmate_server_host = options_get_string(global_options, "tmate-server-host"); - tmate_info("Looking up %s...", tmate_server_host); + tmate_debug("Looking up %s...", tmate_server_host); (void)evdns_getaddrinfo(tmate_session.ev_dnsbase, tmate_server_host, NULL, &hints, dns_cb, (void *)tmate_server_host); } diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index e33f4b17..66eb1716 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -171,12 +171,12 @@ static void request_passphrase(struct tmate_ssh_client *client) #define KEEPALIVE_IDLE 20 #define KEEPALIVE_INTVL 10 -static void setup_socket(int fd) +static void tune_socket_opts(int fd) { #define SSO(level, optname, val) ({ \ int _flag = val; \ if (setsockopt(fd, level, optname, &(_flag), sizeof(int)) < 0) { \ - tmate_warn("setsockopt(" #level ", " #optname ", %d) failed", val); \ + tmate_debug("setsockopt(" #level ", " #optname ", %d) failed", val); \ } \ }) @@ -197,7 +197,7 @@ static void setup_socket(int fd) #undef SSO } -static void init_conn_fd(struct tmate_ssh_client *client) +static void init_conn_fd(struct tmate_ssh_client *client, bool tune_socket) { int fd; @@ -207,7 +207,9 @@ static void init_conn_fd(struct tmate_ssh_client *client) if ((fd = ssh_get_fd(client->session)) < 0) return; - setup_socket(fd); + if (tune_socket) + tune_socket_opts(fd); + event_set(&client->ev_ssh, fd, EV_READ | EV_PERSIST, __on_ssh_client_event, client); event_add(&client->ev_ssh, NULL); @@ -267,14 +269,14 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) case SSH_CONNECT: switch (ssh_connect(session)) { case SSH_AGAIN: - init_conn_fd(client); + init_conn_fd(client, false); return; case SSH_ERROR: kill_ssh_client(client, "Error connecting: %s", ssh_get_error(session)); return; case SSH_OK: - init_conn_fd(client); + init_conn_fd(client, true); tmate_debug("Establishing connection to %s", client->server_ip); client->state = SSH_AUTH_SERVER; diff --git a/tmate.h b/tmate.h index 7deb0ba6..9bf8e975 100644 --- a/tmate.h +++ b/tmate.h @@ -9,10 +9,9 @@ #include "tmux.h" -#define tmate_debug(...) log_debug("[tmate] D " __VA_ARGS__) -#define tmate_warn(...) log_debug("[tmate] W " __VA_ARGS__) -#define tmate_info(...) log_debug("[tmate] I " __VA_ARGS__) -#define tmate_fatal(...) fatalx("[tmate] " __VA_ARGS__) +#define tmate_debug(...) log_emit(LOG_DEBUG, __VA_ARGS__) +#define tmate_info(...) log_emit(LOG_INFO, __VA_ARGS__) +#define tmate_fatal(...) fatalx( __VA_ARGS__) /* tmate-msgpack.c */ diff --git a/tmux.c b/tmux.c index d7cf8d97..60341f84 100644 --- a/tmux.c +++ b/tmux.c @@ -48,7 +48,11 @@ __dead void usage(void); static char *make_label(const char *); #ifndef HAVE___PROGNAME -char *__progname = (char *) "tmux"; +char *__progname = (char *) "tmate"; +#endif + +#ifdef TMATE +int tmate_foreground; #endif __dead void @@ -228,7 +232,7 @@ main(int argc, char **argv) #endif label = path = NULL; - while ((opt = getopt(argc, argv, "2c:Cdf:lL:qS:uUVv")) != -1) { + while ((opt = getopt(argc, argv, "2c:CdFf:lL:qS:uUVv")) != -1) { switch (opt) { case '2': flags |= CLIENT_256COLOURS; @@ -268,6 +272,11 @@ main(int argc, char **argv) case 'v': log_add_level(); break; + case 'F': + tmate_foreground = 1; + log_add_level(); + unsetenv("TMUX"); + break; default: usage(); } diff --git a/tmux.h b/tmux.h index 1ab784b7..3956e240 100644 --- a/tmux.h +++ b/tmux.h @@ -1549,6 +1549,9 @@ extern struct options *global_w_options; extern struct environ *global_environ; extern struct timeval start_time; extern const char *socket_path; +#ifdef TMATE +extern int tmate_foreground; +#endif const char *getshell(void); int checkshell(const char *); int areshell(const char *); @@ -1875,6 +1878,7 @@ void signal_waiting_clients(const char *name); void cmd_wait_for_flush(void); /* client.c */ +void run_initial_client_cmd(void); int client_main(struct event_base *, int, char **, int, const char *); /* key-bindings.c */ @@ -1902,6 +1906,7 @@ void alerts_queue(struct window *, int); void alerts_check_session(struct session *); /* server.c */ +extern int server_exit; extern struct tmuxproc *server_proc; extern struct clients clients; extern struct cmd_find_state marked_pane; @@ -2356,9 +2361,14 @@ struct event_base *osdep_event_init(void); /* log.c */ void log_add_level(void); int log_get_level(void); +void log_open_fp(FILE *f); void log_open(const char *); void log_close(void); -void printflike(1, 2) log_debug(const char *, ...); +#define LOG_ERROR 0 +#define LOG_INFO 1 +#define LOG_DEBUG 2 +#define log_debug(...) log_emit(LOG_DEBUG+1, __VA_ARGS__) +void printflike(2, 3) log_emit(int level, const char *, ...); __dead void printflike(1, 2) fatal(const char *, ...); __dead void printflike(1, 2) fatalx(const char *, ...); From c63c8fbf90ffdf7bc58a8f73428600ee29a6dcf5 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 3 Nov 2019 18:15:27 -0500 Subject: [PATCH 09/59] Only use tmate.conf, not .tmux.conf Fixes #108 --- cfg.c | 16 +--------------- session.c | 2 +- tmux.c | 3 +-- 3 files changed, 3 insertions(+), 18 deletions(-) diff --git a/cfg.c b/cfg.c index 68894cb2..1fcbd0d6 100644 --- a/cfg.c +++ b/cfg.c @@ -71,7 +71,7 @@ start_cfg(void) cfg_add_cause("%s: %s", TMUX_CONF, strerror(errno)); if (cfg_file == NULL && (home = find_home()) != NULL) { - xasprintf(&cfg_file, "%s/.tmux.conf", home); + xasprintf(&cfg_file, "%s/.tmate.conf", home); if (access(cfg_file, R_OK) != 0 && errno == ENOENT) { free(cfg_file); cfg_file = NULL; @@ -81,20 +81,6 @@ start_cfg(void) cfg_add_cause("%s: %s", cfg_file, cause); free(cause); -#ifdef TMATE - cause = NULL; - if ((home = find_home()) != NULL) { - xasprintf(&tmate_cfg_file, "%s/.tmate.conf", home); - if (access(tmate_cfg_file, R_OK) != 0 && errno == ENOENT) { - free(tmate_cfg_file); - tmate_cfg_file = NULL; - } - } - if (tmate_cfg_file != NULL && load_cfg(tmate_cfg_file, cfg_cmd_q, &cause) == -1) - cfg_add_cause("%s: %s", cfg_file, cause); - free(cause); -#endif - cmdq_continue(cfg_cmd_q); } diff --git a/session.c b/session.c index 91fb9c1d..ab58ed9f 100644 --- a/session.c +++ b/session.c @@ -249,7 +249,7 @@ session_destroy(struct session *s) next_session_id = 0; run_initial_client_cmd(); } else { - tmate_info("Session terminated"); + tmate_info("Session closed"); tmate_write_fin(); } #endif diff --git a/tmux.c b/tmux.c index 60341f84..91ee316a 100644 --- a/tmux.c +++ b/tmux.c @@ -59,8 +59,7 @@ __dead void usage(void) { fprintf(stderr, - "usage: %s [-2CluvV] [-c shell-command] [-f file] [-L socket-name]\n" - " [-S socket-path] [command [flags]]\n", + "usage: %s [-vVF] [-f config-file] [-S socket-path] [command [flags]]\n", __progname); exit(1); } From c78198dc59f49e4998f36e31d289b7dd5450178f Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 3 Nov 2019 22:40:41 -0500 Subject: [PATCH 10/59] Add command line arguments to set the account_key/session_names -k account_key -n session_name -r session_name_ro --- server.c | 1 + tmux.c | 35 ++++++++++++++++++++++++++++++++++- tmux.h | 1 + 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/server.c b/server.c index 05706769..f8f08d12 100644 --- a/server.c +++ b/server.c @@ -203,6 +203,7 @@ server_start(struct event_base *base, int lockfd, char *lockfile) #ifdef TMATE tmate_set_editor_mode(); + tmate_init_boot_options(); #endif start_cfg(); diff --git a/tmux.c b/tmux.c index 91ee316a..72c91d39 100644 --- a/tmux.c +++ b/tmux.c @@ -201,6 +201,30 @@ find_home(void) return (home); } +#ifdef TMATE +static char *account_key; +static char *session_name; +static char *session_name_ro; + +void tmate_init_boot_options(void) +{ + if (account_key) + tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "tmate-account-key", account_key}); + if (session_name) + tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "tmate-session-name", session_name}); + if (session_name_ro) + tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "tmate-session-name-ro", session_name_ro}); + + free(account_key); + free(session_name); + free(session_name_ro); + + account_key = NULL; + session_name = NULL; + session_name_ro = NULL; +} +#endif + int main(int argc, char **argv) { @@ -231,7 +255,7 @@ main(int argc, char **argv) #endif label = path = NULL; - while ((opt = getopt(argc, argv, "2c:CdFf:lL:qS:uUVv")) != -1) { + while ((opt = getopt(argc, argv, "2c:CdFf:lL:qS:uUVvk:n:r:")) != -1) { switch (opt) { case '2': flags |= CLIENT_256COLOURS; @@ -276,6 +300,15 @@ main(int argc, char **argv) log_add_level(); unsetenv("TMUX"); break; + case 'k': + account_key = xstrdup(optarg); + break; + case 'n': + session_name = xstrdup(optarg); + break; + case 'r': + session_name_ro = xstrdup(optarg); + break; default: usage(); } diff --git a/tmux.h b/tmux.h index 3956e240..83a573c1 100644 --- a/tmux.h +++ b/tmux.h @@ -1551,6 +1551,7 @@ extern struct timeval start_time; extern const char *socket_path; #ifdef TMATE extern int tmate_foreground; +void tmate_init_boot_options(void); #endif const char *getshell(void); int checkshell(const char *); From 19341bc5444e7954da23ac06ac799c0fd80a160e Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Mon, 4 Nov 2019 16:43:59 -0500 Subject: [PATCH 11/59] Add authorized_keys option -a --- options-table.c | 12 ++++++++++++ tmate-encoder.c | 8 ++++++++ tmate-session.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ tmate.h | 1 + tmux.c | 10 +++++++++- 5 files changed, 75 insertions(+), 1 deletion(-) diff --git a/options-table.c b/options-table.c index 617ba05e..dd9f696e 100644 --- a/options-table.c +++ b/options-table.c @@ -977,6 +977,18 @@ const struct options_table_entry options_table[] = { .scope = OPTIONS_TABLE_SERVER, .default_str = "" }, + + { .name = "tmate-authorized-keys", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_SERVER, + .default_str = "" + }, + + { .name = "tmate-set", + .type = OPTIONS_TABLE_STRING, + .scope = OPTIONS_TABLE_SERVER, + .default_str = "" + }, #endif { .name = NULL } diff --git a/tmate-encoder.c b/tmate-encoder.c index c15d8921..0040a3bf 100644 --- a/tmate-encoder.c +++ b/tmate-encoder.c @@ -238,6 +238,14 @@ void tmate_exec_cmd_args(int argc, const char **argv) append_saved_cmd(&tmate_session, argc, argv); } +void tmate_set_val(const char *name, const char *value) +{ + char *buf; + xasprintf(&buf, "%s=%s", name, value); + tmate_exec_cmd_args(3, (const char *[]){"set-option", "tmate-set", buf}); + free(buf); +} + void tmate_exec_cmd(struct cmd *cmd) { int argc; diff --git a/tmate-session.c b/tmate-session.c index 5ab13511..e3eb0c19 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -129,6 +129,50 @@ void tmate_session_init(struct event_base *base) tmate_write_header(); } +static void send_authorized_keys() +{ + char *path; + path = options_get_string(global_options, "tmate-authorized-keys"); + if (strlen(path) == 0) + return; + + path = xstrdup(path); + tmate_info("Using %s for access control", path); + + FILE *f; + char *line; + size_t len; + + if (path[0] == '~' && path[1] == '/') { + const char *home = find_home(); + if (home) { + char *new_path; + xasprintf(&new_path, "%s%s", home, &path[1]); + free(path); + path = new_path; + } + } + + if ((f = fopen(path, "r")) == NULL) { + cfg_add_cause("%s: %s", path, strerror(errno)); + free(path); + return; + } + + while ((line = fparseln(f, &len, NULL, NULL, 0)) != NULL) { + if (len == 0) + continue; + tmate_set_val("authorized_keys", line); + free(line); + } + + if (ferror(f)) + cfg_add_cause("%s: %s", path, strerror(errno)); + + fclose(f); + free(path); +} + void tmate_session_start(void) { /* @@ -138,6 +182,7 @@ void tmate_session_start(void) * - While we are parsing the config file, we need to be able to * serialize it, and so we need a worker encoder. */ + send_authorized_keys(); tmate_write_ready(); lookup_and_connect(); } diff --git a/tmate.h b/tmate.h index 9bf8e975..e1b9af47 100644 --- a/tmate.h +++ b/tmate.h @@ -83,6 +83,7 @@ extern void tmate_write_ready(void); extern void tmate_sync_layout(void); extern void tmate_pty_data(struct window_pane *wp, const char *buf, size_t len); extern int tmate_should_replicate_cmd(const struct cmd_entry *cmd); +extern void tmate_set_val(const char *name, const char *value); extern void tmate_exec_cmd_args(int argc, const char **argv); extern void tmate_exec_cmd(struct cmd *cmd); extern void tmate_failed_cmd(int client_id, const char *cause); diff --git a/tmux.c b/tmux.c index 72c91d39..90b46403 100644 --- a/tmux.c +++ b/tmux.c @@ -205,6 +205,7 @@ find_home(void) static char *account_key; static char *session_name; static char *session_name_ro; +static char *authorized_keys; void tmate_init_boot_options(void) { @@ -214,14 +215,18 @@ void tmate_init_boot_options(void) tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "tmate-session-name", session_name}); if (session_name_ro) tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "tmate-session-name-ro", session_name_ro}); + if (authorized_keys) + tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "tmate-authorized-keys", authorized_keys}); free(account_key); free(session_name); free(session_name_ro); + free(authorized_keys_file); account_key = NULL; session_name = NULL; session_name_ro = NULL; + authorized_keys = NULL; } #endif @@ -255,7 +260,7 @@ main(int argc, char **argv) #endif label = path = NULL; - while ((opt = getopt(argc, argv, "2c:CdFf:lL:qS:uUVvk:n:r:")) != -1) { + while ((opt = getopt(argc, argv, "2c:CdFf:lL:qS:uUVvk:n:r:a:")) != -1) { switch (opt) { case '2': flags |= CLIENT_256COLOURS; @@ -309,6 +314,9 @@ main(int argc, char **argv) case 'r': session_name_ro = xstrdup(optarg); break; + case 'a': + authorized_keys = xstrdup(optarg); + break; default: usage(); } From 206c0f38b4c6d865b5294cc9ba66eb6b4a611100 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Mon, 4 Nov 2019 17:27:00 -0500 Subject: [PATCH 12/59] Set boot options via tmux commands --- cfg.c | 3 +++ client.c | 46 ++++++++++++++++++++++++++++++---------------- server.c | 1 - tmux.c | 32 +++++++++++++------------------- tmux.h | 4 +++- 5 files changed, 49 insertions(+), 37 deletions(-) diff --git a/cfg.c b/cfg.c index 1fcbd0d6..2410fbf9 100644 --- a/cfg.c +++ b/cfg.c @@ -157,6 +157,9 @@ cfg_default_done(__unused struct cmd_q *cmdq) cfg_finished = 1; #ifdef TMATE + /* We do it this late, this way, CLI options take precedence over cfg file */ + tmate_load_cli_options(); + tmate_session_start(); if (tmate_foreground && cfg_ncauses) { print_cfg_errors(); diff --git a/client.c b/client.c index ad349972..456fe793 100644 --- a/client.c +++ b/client.c @@ -217,37 +217,37 @@ extern const struct cmd_entry cmd_new_session_entry; /* For foreground mode */ static int __argc; -static char **__argv; +static const char **__argv; #endif -static void _run_initial_client_cmd(int argc, char **argv) +int run_headless_command(int argc, const char **argv, int flags, void (*err_callback)(const char *)) { struct cmd_q *cmd_q; struct cmd_list *cmdlist; char *cause; - const char *default_argv[] = {"new-session"}; - - if (argc == 0) { - argc = 1; - argv = (char **)default_argv; - } - cmd_q = cmdq_new(NULL); /* No client */ if ((cmdlist = cmd_list_parse(argc, (char **)argv, NULL, 0, &cause)) == NULL) { - tmate_fatal("%s", cause); + if (err_callback) + err_callback(cause); + return -1; } cmdq_run(cmd_q, cmdlist, NULL); cmd_list_free(cmdlist); cmdq_free(cmd_q); + if (flags & DEFER_ERRORS_CFG) + return 0; + /* error messages land in cfg_causes */ extern char **cfg_causes; extern u_int cfg_ncauses; - int has_error = !!cfg_ncauses; + + int ret = cfg_ncauses ? -1 : 0; for (u_int i = 0; i < cfg_ncauses; i++) { - tmate_info("%s", cfg_causes[i]); + if (err_callback) + err_callback(cfg_causes[i]); free(cfg_causes[i]); } @@ -255,13 +255,27 @@ static void _run_initial_client_cmd(int argc, char **argv) cfg_causes = NULL; cfg_ncauses = 0; - if (has_error) - exit(1); + return ret; +} + +static void initial_client_cmd_err_callback(const char *cause) +{ + tmate_info("%s", cause); } void run_initial_client_cmd(void) { - _run_initial_client_cmd(__argc, __argv); + int argc = __argc; + const char **argv = __argv; + + const char *default_argv[] = {"new-session"}; + if (argc == 0) { + argc = 1; + argv = default_argv; + } + + if (run_headless_command(argc, argv, 0, initial_client_cmd_err_callback) < 0) + exit(1); } /* Client main loop. */ @@ -282,7 +296,7 @@ client_main(struct event_base *base, int argc, char **argv, int flags, #ifdef TMATE int cant_nest = 0; __argc = argc; - __argv = argv; + __argv = (const char **)argv; #endif /* Ignore SIGCHLD now or daemon() in the server will leave a zombie. */ diff --git a/server.c b/server.c index f8f08d12..05706769 100644 --- a/server.c +++ b/server.c @@ -203,7 +203,6 @@ server_start(struct event_base *base, int lockfd, char *lockfile) #ifdef TMATE tmate_set_editor_mode(); - tmate_init_boot_options(); #endif start_cfg(); diff --git a/tmux.c b/tmux.c index 90b46403..2c790eca 100644 --- a/tmux.c +++ b/tmux.c @@ -207,26 +207,20 @@ static char *session_name; static char *session_name_ro; static char *authorized_keys; -void tmate_init_boot_options(void) +void tmate_load_cli_options(void) { - if (account_key) - tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "tmate-account-key", account_key}); - if (session_name) - tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "tmate-session-name", session_name}); - if (session_name_ro) - tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "tmate-session-name-ro", session_name_ro}); - if (authorized_keys) - tmate_exec_cmd_args(4, (const char *[]){"set-option", "-g", "tmate-authorized-keys", authorized_keys}); - - free(account_key); - free(session_name); - free(session_name_ro); - free(authorized_keys_file); - - account_key = NULL; - session_name = NULL; - session_name_ro = NULL; - authorized_keys = NULL; +#define SET_OPT(name, val) ({\ + if (val) { \ + run_headless_command(3, (const char *[]){"set-option", name, val}, DEFER_ERRORS_CFG, NULL); \ + free(val); \ + val = NULL; \ + } \ +}) + SET_OPT("tmate-account-key", account_key); + SET_OPT("tmate-account-name", session_name); + SET_OPT("tmate-account-name-ro", session_name_ro); + SET_OPT("tmate-authorized-keys", authorized_keys); +#undef SET_OPT } #endif diff --git a/tmux.h b/tmux.h index 83a573c1..9f3ca7bd 100644 --- a/tmux.h +++ b/tmux.h @@ -1551,7 +1551,7 @@ extern struct timeval start_time; extern const char *socket_path; #ifdef TMATE extern int tmate_foreground; -void tmate_init_boot_options(void); +void tmate_load_cli_options(void); #endif const char *getshell(void); int checkshell(const char *); @@ -1879,6 +1879,8 @@ void signal_waiting_clients(const char *name); void cmd_wait_for_flush(void); /* client.c */ +#define DEFER_ERRORS_CFG 1 +int run_headless_command(int argc, const char **argv, int flags, void (*err_callback)(const char *)); void run_initial_client_cmd(void); int client_main(struct event_base *, int, char **, int, const char *); From fa49dc980d3aad68ffccb01579a1a29a023137f9 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Mon, 4 Nov 2019 19:00:06 -0500 Subject: [PATCH 13/59] Provide a better CLI help (-h) --- tmux.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/tmux.c b/tmux.c index 2c790eca..be50adfd 100644 --- a/tmux.c +++ b/tmux.c @@ -59,8 +59,18 @@ __dead void usage(void) { fprintf(stderr, - "usage: %s [-vVF] [-f config-file] [-S socket-path] [command [flags]]\n", - __progname); + "Usage: %s [options] [tmux-command [flags]]\n" + "\n" + "Basic options:\n" + " -n specify the session name instead of getting a random one\n" + " -r same, but for the read-only session name\n" + " -k specify the account-key, necessary for named sessions on tmate.io\n" + " -F set the foreground mode, useful for setting remote access\n" + " -f set the config file path\n" + " -S set the socket path, useful to issue commands to a running tmate instance\n" + " -v set verbosity (can be repeated)\n" + " -V print version\n" + ,__progname); exit(1); } @@ -254,7 +264,7 @@ main(int argc, char **argv) #endif label = path = NULL; - while ((opt = getopt(argc, argv, "2c:CdFf:lL:qS:uUVvk:n:r:a:")) != -1) { + while ((opt = getopt(argc, argv, "h2c:CdFf:lL:qS:uUVvk:n:r:a:")) != -1) { switch (opt) { case '2': flags |= CLIENT_256COLOURS; @@ -311,6 +321,7 @@ main(int argc, char **argv) case 'a': authorized_keys = xstrdup(optarg); break; + case 'h': default: usage(); } From c71307ed5c9c00c1fdd28add86b5d06a7fceb98e Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Tue, 5 Nov 2019 19:29:18 -0500 Subject: [PATCH 14/59] Fix reconnection hanging bugs --- tmate-msgpack.c | 13 +++++--- tmate-session.c | 81 ++++++++++++++++++++++++++++------------------ tmate-ssh-client.c | 24 ++++++++------ tmate.h | 9 +++--- 4 files changed, 76 insertions(+), 51 deletions(-) diff --git a/tmate-msgpack.c b/tmate-msgpack.c index 144cda70..c41b07ee 100644 --- a/tmate-msgpack.c +++ b/tmate-msgpack.c @@ -19,7 +19,7 @@ static int on_encoder_write(void *userdata, const char *buf, size_t len) tmate_fatal("Cannot buffer encoded data"); if (!encoder->ev_active) { - event_active(&encoder->ev_buffer, EV_READ, 0); + event_active(encoder->ev_buffer, EV_READ, 0); encoder->ev_active = true; } @@ -57,10 +57,12 @@ void tmate_encoder_init(struct tmate_encoder *encoder, if (!encoder->buffer) tmate_fatal("Can't allocate buffer"); - event_set(&encoder->ev_buffer, -1, - EV_READ | EV_PERSIST, on_encoder_buffer_ready, encoder); + encoder->ev_buffer = event_new(tmate_session.ev_base, -1, + EV_READ | EV_PERSIST, on_encoder_buffer_ready, encoder); + if (!encoder->ev_buffer) + tmate_fatal("Can't allocate event"); - event_add(&encoder->ev_buffer, NULL); + event_add(encoder->ev_buffer, NULL); encoder->ev_active = false; } @@ -69,7 +71,8 @@ void tmate_encoder_destroy(struct tmate_encoder *encoder) { /* encoder->pk doesn't need any cleanup */ evbuffer_free(encoder->buffer); - event_del(&encoder->ev_buffer); + event_del(encoder->ev_buffer); + event_free(encoder->ev_buffer); memset(encoder, 0, sizeof(*encoder)); } diff --git a/tmate-session.c b/tmate-session.c index e3eb0c19..b9f03a8e 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -20,35 +20,50 @@ struct tmate_session tmate_session; static void lookup_and_connect(void); static void on_dns_retry(__unused evutil_socket_t fd, __unused short what, - __unused void *arg) + void *arg) { + struct tmate_session *session = arg; + + assert(session->ev_dns_retry); + event_free(session->ev_dns_retry); + session->ev_dns_retry = NULL; + lookup_and_connect(); } static void dns_cb(int errcode, struct evutil_addrinfo *addr, void *ptr) { struct evutil_addrinfo *ai; - struct timeval tv; const char *host = ptr; if (errcode) { + struct tmate_session *session = &tmate_session; + + if (session->ev_dns_retry) + return; + + struct timeval tv = { .tv_sec = TMATE_DNS_RETRY_TIMEOUT, .tv_usec = 0 }; + + session->ev_dns_retry = evtimer_new(session->ev_base, on_dns_retry, session); + if (!session->ev_dns_retry) + tmate_fatal("out of memory"); + evtimer_add(session->ev_dns_retry, &tv); + tmate_status_message("%s lookup failure. Retrying in %d seconds (%s)", host, TMATE_DNS_RETRY_TIMEOUT, evutil_gai_strerror(errcode)); - - tv.tv_sec = TMATE_DNS_RETRY_TIMEOUT; - tv.tv_usec = 0; - - evtimer_assign(&tmate_session.ev_dns_retry, tmate_session.ev_base, - on_dns_retry, NULL); - evtimer_add(&tmate_session.ev_dns_retry, &tv); - return; } tmate_status_message("Connecting to %s...", host); - for (ai = addr; ai; ai = ai->ai_next) { + int i, num_clients = 0; + for (ai = addr; ai; ai = ai->ai_next) + num_clients++; + + struct tmate_ssh_client *ssh_clients[num_clients]; + + for (ai = addr, i = 0; ai; ai = ai->ai_next, i++) { char buf[128]; const char *ip = NULL; if (ai->ai_family == AF_INET) { @@ -59,23 +74,16 @@ static void dns_cb(int errcode, struct evutil_addrinfo *addr, void *ptr) ip = evutil_inet_ntop(AF_INET6, &sin6->sin6_addr, buf, 128); } - tmate_debug("Trying server %s", ip); - - /* - * Note: We don't deal with the client list. Clients manage it - * and free client structs when necessary. - */ - (void)tmate_ssh_client_alloc(&tmate_session, ip); + ssh_clients[i] = tmate_ssh_client_alloc(&tmate_session, ip); } + for (i = 0; i < num_clients; i++) + connect_ssh_client(ssh_clients[i]); + evutil_freeaddrinfo(addr); - /* - * XXX For some reason, freeing the DNS resolver makes MacOSX flip out... - * not sure what's going on... - * evdns_base_free(tmate_session.ev_dnsbase, 0); - * tmate_session.ev_dnsbase = NULL; - */ + evdns_base_free(tmate_session.ev_dnsbase, 0); + tmate_session.ev_dnsbase = NULL; } static void lookup_and_connect(void) @@ -83,8 +91,8 @@ static void lookup_and_connect(void) struct evutil_addrinfo hints; const char *tmate_server_host; - if (!tmate_session.ev_dnsbase) - tmate_session.ev_dnsbase = evdns_base_new(tmate_session.ev_base, 1); + assert(!tmate_session.ev_dnsbase); + tmate_session.ev_dnsbase = evdns_base_new(tmate_session.ev_base, 1); if (!tmate_session.ev_dnsbase) tmate_fatal("Cannot initialize the DNS lookup service"); @@ -191,12 +199,18 @@ static void on_reconnect_retry(__unused evutil_socket_t fd, __unused short what, { struct tmate_session *session = arg; + assert(session->ev_connection_retry); + event_free(session->ev_connection_retry); + session->ev_connection_retry = NULL; + if (session->last_server_ip) { /* * We have a previous server ip. Let's try that again first, * but then connect to any server if it fails again. */ - (void)tmate_ssh_client_alloc(&tmate_session, session->last_server_ip); + struct tmate_ssh_client *c = tmate_ssh_client_alloc(session, + session->last_server_ip); + connect_ssh_client(c); free(session->last_server_ip); session->last_server_ip = NULL; } else { @@ -214,18 +228,21 @@ void tmate_reconnect_session(struct tmate_session *session, const char *message) */ struct timeval tv = { .tv_sec = TMATE_RECONNECT_RETRY_TIMEOUT, .tv_usec = 0 }; - evtimer_assign(&session->ev_connection_retry, session->ev_base, - on_reconnect_retry, session); - evtimer_add(&session->ev_connection_retry, &tv); + if (session->ev_connection_retry) + return; - if (message) + session->ev_connection_retry = evtimer_new(session->ev_base, on_reconnect_retry, session); + if (!session->ev_connection_retry) + tmate_fatal("out of memory"); + evtimer_add(session->ev_connection_retry, &tv); + + if (message && !tmate_foreground) tmate_status_message("Reconnecting... (%s)", message); else tmate_status_message("Reconnecting..."); /* * This says that we'll need to send a snapshot of the current state. - * Until we have persisted logs... */ session->reconnected = true; } diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index 66eb1716..3f4690df 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -210,8 +210,12 @@ static void init_conn_fd(struct tmate_ssh_client *client, bool tune_socket) if (tune_socket) tune_socket_opts(fd); - event_set(&client->ev_ssh, fd, EV_READ | EV_PERSIST, __on_ssh_client_event, client); - event_add(&client->ev_ssh, NULL); + assert(!client->ev_ssh); + client->ev_ssh = event_new(client->tmate_session->ev_base, + fd, EV_READ | EV_PERSIST, __on_ssh_client_event, client); + if (!client->ev_ssh) + tmate_fatal("out of memory"); + event_add(client->ev_ssh, NULL); client->has_init_conn_fd = true; } @@ -479,7 +483,8 @@ static void kill_ssh_client(struct tmate_ssh_client *client, tmate_debug("SSH client killed (%s)", client->server_ip); if (client->has_init_conn_fd) { - event_del(&client->ev_ssh); + event_del(client->ev_ssh); + event_free(client->ev_ssh); client->has_init_conn_fd = false; } @@ -506,12 +511,11 @@ static void kill_ssh_client(struct tmate_ssh_client *client, free(client); } -static void connect_ssh_client(struct tmate_ssh_client *client) +void connect_ssh_client(struct tmate_ssh_client *client) { - if (!client->session) { - client->state = SSH_INIT; - on_ssh_client_event(client); - } + assert(!client->session); + client->state = SSH_INIT; + on_ssh_client_event(client); } static void ssh_log_function(int priority, const char *function, @@ -522,9 +526,11 @@ static void ssh_log_function(int priority, const char *function, 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, 0, sizeof(*client)); ssh_set_log_callback(ssh_log_function); @@ -544,7 +550,5 @@ struct tmate_ssh_client *tmate_ssh_client_alloc(struct tmate_session *session, client->has_init_conn_fd = false; - connect_ssh_client(client); - return client; } diff --git a/tmate.h b/tmate.h index e1b9af47..9b177120 100644 --- a/tmate.h +++ b/tmate.h @@ -22,7 +22,7 @@ struct tmate_encoder { tmate_encoder_write_cb *ready_callback; void *userdata; struct evbuffer *buffer; - struct event ev_buffer; + struct event *ev_buffer; bool ev_active; }; @@ -142,10 +142,11 @@ struct tmate_ssh_client { ssh_channel channel; bool has_init_conn_fd; - struct event ev_ssh; + struct event *ev_ssh; }; TAILQ_HEAD(tmate_ssh_clients, tmate_ssh_client); +extern void connect_ssh_client(struct tmate_ssh_client *client); extern struct tmate_ssh_client *tmate_ssh_client_alloc(struct tmate_session *session, const char *server_ip); @@ -154,7 +155,7 @@ extern struct tmate_ssh_client *tmate_ssh_client_alloc(struct tmate_session *ses struct tmate_session { struct event_base *ev_base; struct evdns_base *ev_dnsbase; - struct event ev_dns_retry; + struct event *ev_dns_retry; struct tmate_encoder encoder; struct tmate_decoder decoder; @@ -175,7 +176,7 @@ struct tmate_session { char *passphrase; bool reconnected; - struct event ev_connection_retry; + struct event *ev_connection_retry; char *last_server_ip; char *reconnection_data; /* From 442143cd90bc284b487aa2c723b81c8d33e5e38e Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Tue, 5 Nov 2019 21:18:13 -0500 Subject: [PATCH 15/59] Show message when restarting shell --- options-table.c | 8 ++++++++ session.c | 40 +++++++++++++++++++++++++++++++--------- 2 files changed, 39 insertions(+), 9 deletions(-) diff --git a/options-table.c b/options-table.c index dd9f696e..4a20c548 100644 --- a/options-table.c +++ b/options-table.c @@ -989,6 +989,14 @@ const struct options_table_entry options_table[] = { .scope = OPTIONS_TABLE_SERVER, .default_str = "" }, + + { .name = "tmate-foreground-restart", + .type = OPTIONS_TABLE_NUMBER, + .scope = OPTIONS_TABLE_SERVER, + .minimum = 0, + .maximum = 1, + .default_num = 1 + }, #endif { .name = NULL } diff --git a/session.c b/session.c index ab58ed9f..d1a644d5 100644 --- a/session.c +++ b/session.c @@ -207,6 +207,36 @@ session_free(__unused int fd, __unused short events, void *arg) } } +static void maybe_restart_session(void) +{ + int fg_restart = options_get_number(global_options, "tmate-foreground-restart"); + if (!fg_restart) + return; + + /* + * throttle restarts. This is a blocking sleep. It's + * simpler than using a timer, but fairly harmless + * from a blocking perspective. + */ + usleep(500*1000); + next_session_id = 0; + run_initial_client_cmd(); + + tmate_info("Shell exited. Shell restarted"); + + struct session *s; + s = RB_MIN(sessions, &sessions); + if (!s) + return; + + struct window_pane *wp; + wp = s->curw->window->active; + window_pane_set_mode(wp, &window_copy_mode); + window_copy_init_for_output(wp); + window_copy_add(wp, "%s", "Shell exited. Shell restarted."); + window_copy_add(wp, "%s", "Note: press the following sequence to disconnect from SSH: ~."); +} + /* Destroy a session. */ void session_destroy(struct session *s) @@ -239,15 +269,7 @@ session_destroy(struct session *s) #ifdef TMATE if (tmate_foreground && !server_exit) { - tmate_info("Shell exited, restarting"); - /* - * throttle restarts. This is a blocking sleep. - * It's simpler than using a timer, but fairly harmless - * from a blocking perspective. - */ - usleep(500*1000); - next_session_id = 0; - run_initial_client_cmd(); + maybe_restart_session(); } else { tmate_info("Session closed"); tmate_write_fin(); From 9781946a70d0bde07abdeca3221b5cb4a31b6f3c Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Tue, 5 Nov 2019 21:32:21 -0500 Subject: [PATCH 16/59] Show initial message in copy mode --- tmate-msg.c | 20 ++++++++++++++++++++ tmate-session.c | 5 +++++ 2 files changed, 25 insertions(+) diff --git a/tmate-msg.c b/tmate-msg.c index a47f9e4d..4ee0a5de 100644 --- a/tmate-msg.c +++ b/tmate-msg.c @@ -50,6 +50,24 @@ static void tmate_status_message_client(struct client *c, const char *message) recalculate_sizes(); } +static void tmate_status_message_session(const char *message) +{ + if (tmate_foreground) + return; + + struct session *s; + s = RB_MIN(sessions, &sessions); + if (!s) { + cfg_add_cause("%s", message); + return; + } + + struct window_pane *wp; + wp = s->curw->window->active; + if (wp->mode == &window_copy_mode) + window_copy_add(wp, "%s", message); +} + void __tmate_status_message(const char *fmt, va_list ap) { struct client *c; @@ -63,6 +81,8 @@ void __tmate_status_message(const char *fmt, va_list ap) tmate_status_message_client(c, message); } + tmate_status_message_session(message); + free(message); } diff --git a/tmate-session.c b/tmate-session.c index b9f03a8e..0c07a758 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -190,6 +190,11 @@ void tmate_session_start(void) * - While we are parsing the config file, we need to be able to * serialize it, and so we need a worker encoder. */ + if (!tmate_foreground) { + cfg_add_cause("%s", "To see these messages again, run: tmate show-messages"); + cfg_add_cause("%s", "-----------------------------------------------------"); + } + send_authorized_keys(); tmate_write_ready(); lookup_and_connect(); From 0272757aa531166acca449f081ea008c263b4485 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Wed, 6 Nov 2019 12:34:18 -0500 Subject: [PATCH 17/59] Clarify user message --- tmate-session.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tmate-session.c b/tmate-session.c index 0c07a758..0e6080e8 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -192,6 +192,7 @@ void tmate_session_start(void) */ if (!tmate_foreground) { cfg_add_cause("%s", "To see these messages again, run: tmate show-messages"); + cfg_add_cause("%s", "Press to dismiss"); cfg_add_cause("%s", "-----------------------------------------------------"); } From 1600a81e589e92f3e7bd68a34645797909a32b9a Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Wed, 6 Nov 2019 20:34:44 -0500 Subject: [PATCH 18/59] Also add crash info on SIGABRT --- tmate-debug.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tmate-debug.c b/tmate-debug.c index f58efe0e..59e8fe7d 100644 --- a/tmate-debug.c +++ b/tmate-debug.c @@ -85,7 +85,7 @@ void tmate_print_stack_trace(void) } -static void handle_sigsegv(__unused int sig) +static void handle_crash(__unused int sig) { /* TODO send stack trace to server */ tmate_info("CRASH, printing stack trace"); @@ -95,6 +95,7 @@ static void handle_sigsegv(__unused int sig) void tmate_catch_sigsegv(void) { - signal(SIGSEGV, handle_sigsegv); + signal(SIGSEGV, handle_crash); + signal(SIGABRT, handle_crash); } #endif From ba860b8f4580cee8878341a5cd1fb4fe4d440651 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Thu, 7 Nov 2019 09:08:17 -0500 Subject: [PATCH 19/59] Cleanup warnings --- Makefile.am | 7 +++++-- client.c | 3 --- compat/b64_ntop.c | 4 +++- configure.ac | 1 + log.c | 9 +++++++-- osdep-darwin.c | 2 ++ screen-redraw.c | 2 +- session.c | 1 + tmate-session.c | 2 +- tmate-ssh-client.c | 18 +++++++++--------- tmux.h | 2 ++ xmalloc.c | 2 ++ 12 files changed, 34 insertions(+), 19 deletions(-) diff --git a/Makefile.am b/Makefile.am index 2551bce3..3da954ae 100644 --- a/Makefile.am +++ b/Makefile.am @@ -33,8 +33,8 @@ CFLAGS += -g CFLAGS += -Wno-long-long -Wall -W -Wnested-externs -Wformat=2 CFLAGS += -Wmissing-prototypes -Wstrict-prototypes -Wmissing-declarations CFLAGS += -Wwrite-strings -Wshadow -Wpointer-arith -Wsign-compare -CFLAGS += -Wundef -Wbad-function-cast -Winline -Wcast-align -CFLAGS += -Wdeclaration-after-statement -Wno-pointer-sign -Wno-attributes +CFLAGS += -Wundef -Wbad-function-cast -Winline +CFLAGS += -Wno-pointer-sign -Wno-attributes CPPFLAGS += -DDEBUG endif if IS_COVERAGE @@ -44,6 +44,9 @@ endif CPPFLAGS += -iquote. endif +CFLAGS += -Wno-unused-parameter -Wno-unused-variable -Wno-null-pointer-arithmetic +CFLAGS += -Wno-deprecated-declarations -Wno-format-nonliteral + # Set flags for Solaris. if IS_SUNOS if IS_GCC diff --git a/client.c b/client.c index 456fe793..c587ec0d 100644 --- a/client.c +++ b/client.c @@ -241,9 +241,6 @@ int run_headless_command(int argc, const char **argv, int flags, void (*err_call return 0; /* error messages land in cfg_causes */ - extern char **cfg_causes; - extern u_int cfg_ncauses; - int ret = cfg_ncauses ? -1 : 0; for (u_int i = 0; i < cfg_ncauses; i++) { if (err_callback) diff --git a/compat/b64_ntop.c b/compat/b64_ntop.c index 2b4dc2d4..fd8930f5 100644 --- a/compat/b64_ntop.c +++ b/compat/b64_ntop.c @@ -52,6 +52,8 @@ #include #include +#include "compat.h" + #define Assert(Cond) if (!(Cond)) abort() static const char Base64[] = @@ -122,7 +124,7 @@ static const char Pad64 = '='; */ int -b64_ntop(uint8_t const *src, size_t srclength, char *target, size_t targsize) { +b64_ntop(const char *src, size_t srclength, char *target, size_t targsize) { size_t datalength = 0; uint8_t input[3]; uint8_t output[4]; diff --git a/configure.ac b/configure.ac index f623cadc..8bdb0686 100644 --- a/configure.ac +++ b/configure.ac @@ -2,6 +2,7 @@ AC_INIT(tmate, 2.3.1) +AM_SILENT_RULES([yes]) AC_CONFIG_AUX_DIR(etc) AM_INIT_AUTOMAKE([foreign subdir-objects]) diff --git a/log.c b/log.c index bc798778..12266aa4 100644 --- a/log.c +++ b/log.c @@ -98,6 +98,7 @@ log_close(void) } /* Write a log message. */ +__attribute__((__format__(__printf__, 1, 0))) static void log_vwrite(const char *msg, va_list ap) { @@ -144,6 +145,7 @@ log_emit(int level, const char *msg, ...) } /* Log a critical error with error string and die. */ +__attribute__((__format__(__printf__, 1, 0))) __dead void fatal(const char *msg, ...) { @@ -153,11 +155,13 @@ fatal(const char *msg, ...) va_start(ap, msg); if (asprintf(&fmt, "fatal: %s: %s", msg, strerror(errno)) == -1) exit(1); - log_vwrite(fmt, ap); + msg = fmt; + log_vwrite(msg, ap); exit(1); } /* Log a critical error and die. */ +__attribute__((__format__(__printf__, 1, 0))) __dead void fatalx(const char *msg, ...) { @@ -167,6 +171,7 @@ fatalx(const char *msg, ...) va_start(ap, msg); if (asprintf(&fmt, "fatal: %s", msg) == -1) exit(1); - log_vwrite(fmt, ap); + msg = fmt; + log_vwrite(msg, ap); exit(1); } diff --git a/osdep-darwin.c b/osdep-darwin.c index 40b18951..53b48138 100644 --- a/osdep-darwin.c +++ b/osdep-darwin.c @@ -28,7 +28,9 @@ char *osdep_get_name(int, char *); char *osdep_get_cwd(int); struct event_base *osdep_event_init(void); +#ifndef __unused #define __unused __attribute__ ((__unused__)) +#endif char * osdep_get_name(int fd, __unused char *tty) diff --git a/screen-redraw.c b/screen-redraw.c index 952a8515..4201b022 100644 --- a/screen-redraw.c +++ b/screen-redraw.c @@ -278,7 +278,7 @@ screen_redraw_draw_borders(struct client *c, int status, u_int top) struct window *w = s->curw->window; struct options *oo = w->options; struct tty *tty = &c->tty; - struct window_pane *wp; + struct window_pane *wp = NULL; struct grid_cell m_active_gc, active_gc, m_other_gc, other_gc; struct grid_cell msg_gc; u_int i, j, type, msgx = 0, msgy = 0; diff --git a/session.c b/session.c index d1a644d5..07ca9acc 100644 --- a/session.c +++ b/session.c @@ -621,6 +621,7 @@ session_group_index(struct session_group *sg) } fatalx("session group not found"); + for(;;); } /* diff --git a/tmate-session.c b/tmate-session.c index 0e6080e8..f3a904bd 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -137,7 +137,7 @@ void tmate_session_init(struct event_base *base) tmate_write_header(); } -static void send_authorized_keys() +static void send_authorized_keys(void) { char *path; path = options_get_string(global_options, "tmate-authorized-keys"); diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index 3f4690df..030b330a 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -115,7 +115,7 @@ static int passphrase_callback(__unused const char *prompt, char *buf, size_t le client->tmate_session->need_passphrase = 1; if (client->tmate_session->passphrase) - strncpy(buf, client->tmate_session->passphrase, len); + strlcpy(buf, client->tmate_session->passphrase, len); else strcpy(buf, ""); @@ -268,7 +268,7 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) } client->state = SSH_CONNECT; - /* fall through */ + // fall through case SSH_CONNECT: switch (ssh_connect(session)) { @@ -284,8 +284,8 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) tmate_debug("Establishing connection to %s", client->server_ip); client->state = SSH_AUTH_SERVER; - /* fall through */ } + // fall through case SSH_AUTH_SERVER: #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0) @@ -352,7 +352,7 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) on_ssh_auth_server_complete(client); client->state = SSH_AUTH_CLIENT_NONE; - /* fall through */ + // fall through case SSH_AUTH_CLIENT_NONE: switch (ssh_userauth_none(session, NULL)) { @@ -368,8 +368,8 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) case SSH_AUTH_PARTIAL: case SSH_AUTH_DENIED: client->state = SSH_AUTH_CLIENT_PUBKEY; - /* fall through */ } + // fall through case SSH_AUTH_CLIENT_PUBKEY: client->tried_passphrase = client->tmate_session->passphrase; @@ -397,8 +397,8 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) case SSH_AUTH_SUCCESS: tmate_debug("Auth successful with pubkey"); client->state = SSH_NEW_CHANNEL; - /* fall through */ } + // fall through SSH_NEW_CHANNEL: case SSH_NEW_CHANNEL: @@ -408,6 +408,7 @@ SSH_NEW_CHANNEL: return; } client->state = SSH_OPEN_CHANNEL; + // fall through case SSH_OPEN_CHANNEL: switch (ssh_channel_open_session(channel)) { @@ -420,8 +421,8 @@ SSH_NEW_CHANNEL: case SSH_OK: tmate_debug("Session opened, initalizing tmate"); client->state = SSH_BOOTSTRAP; - /* fall through */ } + // fall through case SSH_BOOTSTRAP: switch (ssh_channel_request_subsystem(channel, "tmate")) { @@ -449,9 +450,8 @@ SSH_NEW_CHANNEL: free(client->tmate_session->last_server_ip); client->tmate_session->last_server_ip = xstrdup(client->server_ip); - - /* fall through */ } + // fall through case SSH_READY: read_channel(client); diff --git a/tmux.h b/tmux.h index 9f3ca7bd..c60a044e 100644 --- a/tmux.h +++ b/tmux.h @@ -1576,6 +1576,8 @@ void proc_kill_peer(struct tmuxpeer *); extern int cfg_finished; extern int cfg_references; extern struct client *cfg_client; +extern char **cfg_causes; +extern u_int cfg_ncauses; void start_cfg(void); int load_cfg(const char *, struct cmd_q *, char **); void set_cfg_file(const char *); diff --git a/xmalloc.c b/xmalloc.c index afa8e585..90af1e2f 100644 --- a/xmalloc.c +++ b/xmalloc.c @@ -94,6 +94,7 @@ xasprintf(char **ret, const char *fmt, ...) return i; } +__attribute__((__format__(__printf__, 2, 0))) int xvasprintf(char **ret, const char *fmt, va_list ap) { @@ -120,6 +121,7 @@ xsnprintf(char *str, size_t len, const char *fmt, ...) return i; } +__attribute__((__format__(__printf__, 3, 0))) int xvsnprintf(char *str, size_t len, const char *fmt, va_list ap) { From 8b62c547486ce031bdefc91a7930e590e6dd5c2b Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Thu, 7 Nov 2019 11:29:28 -0500 Subject: [PATCH 20/59] Fix typo --- tmux.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tmux.c b/tmux.c index be50adfd..b6b03346 100644 --- a/tmux.c +++ b/tmux.c @@ -62,8 +62,8 @@ usage(void) "Usage: %s [options] [tmux-command [flags]]\n" "\n" "Basic options:\n" - " -n specify the session name instead of getting a random one\n" - " -r same, but for the read-only session name\n" + " -n specify the session token instead of getting a random one\n" + " -r same, but for the read-only token\n" " -k specify the account-key, necessary for named sessions on tmate.io\n" " -F set the foreground mode, useful for setting remote access\n" " -f set the config file path\n" @@ -227,8 +227,8 @@ void tmate_load_cli_options(void) } \ }) SET_OPT("tmate-account-key", account_key); - SET_OPT("tmate-account-name", session_name); - SET_OPT("tmate-account-name-ro", session_name_ro); + SET_OPT("tmate-session-name", session_name); + SET_OPT("tmate-session-name-ro", session_name_ro); SET_OPT("tmate-authorized-keys", authorized_keys); #undef SET_OPT } From d3c8808b0fddee80cf599257e0e68ab44a96d584 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Thu, 7 Nov 2019 11:38:54 -0500 Subject: [PATCH 21/59] Version bump --- configure.ac | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 8bdb0686..028d5559 100644 --- a/configure.ac +++ b/configure.ac @@ -1,6 +1,6 @@ # configure.ac -AC_INIT(tmate, 2.3.1) +AC_INIT(tmate, 2.4.0) AM_SILENT_RULES([yes]) AC_CONFIG_AUX_DIR(etc) From 2b146115446ca0477d2c3d7155f07f22fdb9c265 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Thu, 7 Nov 2019 13:31:28 -0500 Subject: [PATCH 22/59] Polish session messages --- session.c | 4 ++-- tmate-session.c | 5 ++++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/session.c b/session.c index 07ca9acc..879eb657 100644 --- a/session.c +++ b/session.c @@ -222,7 +222,7 @@ static void maybe_restart_session(void) next_session_id = 0; run_initial_client_cmd(); - tmate_info("Shell exited. Shell restarted"); + tmate_info("Session shell restarted"); struct session *s; s = RB_MIN(sessions, &sessions); @@ -233,7 +233,7 @@ static void maybe_restart_session(void) wp = s->curw->window->active; window_pane_set_mode(wp, &window_copy_mode); window_copy_init_for_output(wp); - window_copy_add(wp, "%s", "Shell exited. Shell restarted."); + window_copy_add(wp, "%s", "Session shell restarted"); window_copy_add(wp, "%s", "Note: press the following sequence to disconnect from SSH: ~."); } diff --git a/tmate-session.c b/tmate-session.c index f3a904bd..1863f78c 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -190,7 +190,10 @@ void tmate_session_start(void) * - While we are parsing the config file, we need to be able to * serialize it, and so we need a worker encoder. */ - if (!tmate_foreground) { + if (tmate_foreground) { + tmate_set_val("foreground", "true"); + tmate_info("To connect to the session locally, run: tmate -S %s attach", socket_path); + } else { cfg_add_cause("%s", "To see these messages again, run: tmate show-messages"); cfg_add_cause("%s", "Press to dismiss"); cfg_add_cause("%s", "-----------------------------------------------------"); From 2b860313088465044a596b7604dc184336c93e54 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 10 Nov 2019 03:44:37 -0500 Subject: [PATCH 23/59] Fix keepalive bug --- tmate-session.c | 6 ++-- tmate-ssh-client.c | 69 +++++++++++++++++++++++++++++++--------------- tmate.h | 1 - 3 files changed, 50 insertions(+), 26 deletions(-) diff --git a/tmate-session.c b/tmate-session.c index 1863f78c..10c6123b 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -36,6 +36,9 @@ static void dns_cb(int errcode, struct evutil_addrinfo *addr, void *ptr) struct evutil_addrinfo *ai; const char *host = ptr; + evdns_base_free(tmate_session.ev_dnsbase, 0); + tmate_session.ev_dnsbase = NULL; + if (errcode) { struct tmate_session *session = &tmate_session; @@ -81,9 +84,6 @@ static void dns_cb(int errcode, struct evutil_addrinfo *addr, void *ptr) connect_ssh_client(ssh_clients[i]); evutil_freeaddrinfo(addr); - - evdns_base_free(tmate_session.ev_dnsbase, 0); - tmate_session.ev_dnsbase = NULL; } static void lookup_and_connect(void) diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index 030b330a..221d7c9f 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -167,57 +167,84 @@ static void request_passphrase(struct tmate_ssh_client *client) data->password_cb_private = client; } -#define KEEPALIVE_CNT 3 -#define KEEPALIVE_IDLE 20 -#define KEEPALIVE_INTVL 10 +#define KEEPALIVE_IDLE 30 +#define KEEPALIVE_CNT 4 +#define KEEPALIVE_INTVL 11 +#define WRITE_TIMEOUT 80 static void tune_socket_opts(int fd) { #define SSO(level, optname, val) ({ \ int _flag = val; \ if (setsockopt(fd, level, optname, &(_flag), sizeof(int)) < 0) { \ - tmate_debug("setsockopt(" #level ", " #optname ", %d) failed", val); \ + tmate_info("setsockopt(" #level ", " #optname ", %d) failed", val); \ } \ }) SSO(IPPROTO_TCP, TCP_NODELAY, 1); SSO(SOL_SOCKET, SO_KEEPALIVE, 1); #ifdef TCP_KEEPALIVE + /* + * The TCP_KEEPALIVE options enable to specify the amount of time, in + * seconds, that the connection must be idle before keepalive probes + * (if enabled) are sent. + */ SSO(IPPROTO_TCP, TCP_KEEPALIVE, KEEPALIVE_IDLE); #endif -#ifdef TCP_KEEPCNT - SSO(IPPROTO_TCP, TCP_KEEPCNT, KEEPALIVE_CNT); -#endif #ifdef TCP_KEEPIDLE + /* + * Same as TCP_KEEPALIVE, but on different systems + */ SSO(IPPROTO_TCP, TCP_KEEPIDLE, KEEPALIVE_IDLE); #endif +#ifdef TCP_KEEPCNT + /* + * When keepalive probes are enabled, this option will set the number + * of times a keepalive probe should be repeated if the peer is not + * responding. After this many probes, the connection will be closed. + */ + SSO(IPPROTO_TCP, TCP_KEEPCNT, KEEPALIVE_CNT); +#endif #ifdef TCP_KEEPINTVL + /* + * When keepalive probes are enabled, this option will set the amount + * of time in seconds between successive keepalives sent to probe an + * unresponsive peer. + */ SSO(IPPROTO_TCP, TCP_KEEPINTVL, KEEPALIVE_INTVL); #endif +#ifdef TCP_USER_TIMEOUT + /* + * This option takes an unsigned int as an argument. When the + * value is greater than 0, it specifies the maximum amount of + * time in milliseconds that transmitted data may remain + * unacknowledged before TCP will forcibly close the + * corresponding connection and return ETIMEDOUT to the + * application. + */ + SSO(IPPROTO_TCP, TCP_USER_TIMEOUT, 1000*WRITE_TIMEOUT); +#endif #undef SSO } -static void init_conn_fd(struct tmate_ssh_client *client, bool tune_socket) +static void init_conn_fd(struct tmate_ssh_client *client) { int fd; - if (client->has_init_conn_fd) + if (client->ev_ssh) return; if ((fd = ssh_get_fd(client->session)) < 0) return; - if (tune_socket) - tune_socket_opts(fd); + tune_socket_opts(fd); - assert(!client->ev_ssh); - client->ev_ssh = event_new(client->tmate_session->ev_base, - fd, EV_READ | EV_PERSIST, __on_ssh_client_event, client); + client->ev_ssh = event_new(client->tmate_session->ev_base, fd, + EV_READ | EV_PERSIST, + __on_ssh_client_event, client); if (!client->ev_ssh) tmate_fatal("out of memory"); event_add(client->ev_ssh, NULL); - - client->has_init_conn_fd = true; } static void on_ssh_client_event(struct tmate_ssh_client *client) @@ -273,14 +300,14 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) case SSH_CONNECT: switch (ssh_connect(session)) { case SSH_AGAIN: - init_conn_fd(client, false); + init_conn_fd(client); return; case SSH_ERROR: kill_ssh_client(client, "Error connecting: %s", ssh_get_error(session)); return; case SSH_OK: - init_conn_fd(client, true); + init_conn_fd(client); tmate_debug("Establishing connection to %s", client->server_ip); client->state = SSH_AUTH_SERVER; @@ -482,10 +509,10 @@ static void kill_ssh_client(struct tmate_ssh_client *client, tmate_debug("SSH client killed (%s)", client->server_ip); - if (client->has_init_conn_fd) { + if (client->ev_ssh) { event_del(client->ev_ssh); event_free(client->ev_ssh); - client->has_init_conn_fd = false; + client->ev_ssh = NULL; } if (client->state == SSH_READY) { @@ -548,7 +575,5 @@ struct tmate_ssh_client *tmate_ssh_client_alloc(struct tmate_session *session, client->channel = NULL; client->has_encoder = 0; - client->has_init_conn_fd = false; - return client; } diff --git a/tmate.h b/tmate.h index 9b177120..5c3af6a0 100644 --- a/tmate.h +++ b/tmate.h @@ -141,7 +141,6 @@ struct tmate_ssh_client { ssh_session session; ssh_channel channel; - bool has_init_conn_fd; struct event *ev_ssh; }; TAILQ_HEAD(tmate_ssh_clients, tmate_ssh_client); From 86ec8d1ad6f00b28ae9c20c6e3d0d2256d5336d2 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 10 Nov 2019 03:59:12 -0500 Subject: [PATCH 24/59] Better crash messages --- tmate-debug.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tmate-debug.c b/tmate-debug.c index 59e8fe7d..8b4ddd5b 100644 --- a/tmate-debug.c +++ b/tmate-debug.c @@ -88,9 +88,13 @@ void tmate_print_stack_trace(void) static void handle_crash(__unused int sig) { /* TODO send stack trace to server */ - tmate_info("CRASH, printing stack trace"); + const char *what = sig == SIGSEGV ? "SIGSEGV" : "SIGABRT"; + tmate_info("%s printing stack trace", what); tmate_print_stack_trace(); - tmate_fatal("CRASHED"); + + /* Reraise */ + signal(sig, NULL); + kill(getpid(), sig); } void tmate_catch_sigsegv(void) From 9fc6e96444bf913c5dc8d1db1c6ff0eed55b9781 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 10 Nov 2019 15:31:54 -0500 Subject: [PATCH 25/59] Send uname --- tmate-encoder.c | 19 +++++++++++++++++++ tmate-protocol.h | 3 +++ tmate-session.c | 1 + tmate.h | 1 + 4 files changed, 24 insertions(+) diff --git a/tmate-encoder.c b/tmate-encoder.c index 0040a3bf..e1373451 100644 --- a/tmate-encoder.c +++ b/tmate-encoder.c @@ -1,3 +1,4 @@ +#include #include "tmate.h" #include "tmate-protocol.h" #include "window-copy.h" @@ -12,6 +13,23 @@ void tmate_write_header(void) pack(string, VERSION); } +void tmate_write_uname(void) +{ + struct utsname name; + if (uname(&name) < 0) { + tmate_debug("uname() failed"); + return; + } + + pack(array, 6); + pack(int, TMATE_OUT_UNAME); + pack(string, name.sysname); + pack(string, name.nodename); + pack(string, name.release); + pack(string, name.version); + pack(string, name.machine); +} + void tmate_write_ready(void) { pack(array, 1); @@ -464,6 +482,7 @@ void tmate_send_reconnection_state(struct tmate_session *session) tmate_send_reconnection_data(session); replay_saved_cmd(session); /* TODO send all option variables */ + tmate_write_uname(); tmate_write_ready(); tmate_sync_layout(); diff --git a/tmate-protocol.h b/tmate-protocol.h index 595b6271..81716bb2 100644 --- a/tmate-protocol.h +++ b/tmate-protocol.h @@ -56,6 +56,7 @@ enum tmate_daemon_out_msg_types { TMATE_OUT_RECONNECT, TMATE_OUT_SNAPSHOT, TMATE_OUT_EXEC_CMD, + TMATE_OUT_UNAME, }; /* @@ -77,6 +78,8 @@ enum tmate_daemon_out_msg_types { [TMATE_OUT_RECONNECT, string: reconnection_data] [TMATE_OUT_SNAPSHOT, ...] [TMATE_OUT_EXEC_CMD, string: cmd_name, ...string: args] +[TMATE_OUT_UNAME, string: name.sysname, string: name.nodename, + string: name.release, string: name.version, string: name.machine] */ enum tmate_daemon_in_msg_types { diff --git a/tmate-session.c b/tmate-session.c index 10c6123b..d88ec5a5 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -200,6 +200,7 @@ void tmate_session_start(void) } send_authorized_keys(); + tmate_write_uname(); tmate_write_ready(); lookup_and_connect(); } diff --git a/tmate.h b/tmate.h index 5c3af6a0..1fdda4e0 100644 --- a/tmate.h +++ b/tmate.h @@ -79,6 +79,7 @@ extern void unpack_array(struct tmate_unpacker *uk, struct tmate_unpacker *neste struct tmate_session; extern void tmate_write_header(void); +extern void tmate_write_uname(void); extern void tmate_write_ready(void); extern void tmate_sync_layout(void); extern void tmate_pty_data(struct window_pane *wp, const char *buf, size_t len); From e5f6e68fadc2ca7a27c84a1a3b2ac9e4dce5079c Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 10 Nov 2019 14:05:14 -0500 Subject: [PATCH 26/59] Unify tmate-debug.c with tmate-ssh-server --- tmate-debug.c | 11 +++++++++-- tmate.h | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/tmate-debug.c b/tmate-debug.c index 8b4ddd5b..81850284 100644 --- a/tmate-debug.c +++ b/tmate-debug.c @@ -11,6 +11,7 @@ void tmate_print_stack_trace(void) {} void tmate_catch_sigsegv(void) {} +void tmate_preload_trace_lib(void) {} #else @@ -84,8 +85,7 @@ void tmate_print_stack_trace(void) free (strings); } - -static void handle_crash(__unused int sig) +static void handle_crash(int sig) { /* TODO send stack trace to server */ const char *what = sig == SIGSEGV ? "SIGSEGV" : "SIGABRT"; @@ -102,4 +102,11 @@ void tmate_catch_sigsegv(void) signal(SIGSEGV, handle_crash); signal(SIGABRT, handle_crash); } + +void tmate_preload_trace_lib(void) +{ + void *array[1]; + backtrace(array, 1); +} + #endif diff --git a/tmate.h b/tmate.h index 1fdda4e0..ec6d0f29 100644 --- a/tmate.h +++ b/tmate.h @@ -203,6 +203,7 @@ extern void tmate_reconnect_session(struct tmate_session *session, const char *m /* tmate-debug.c */ extern void tmate_print_stack_trace(void); extern void tmate_catch_sigsegv(void); +extern void tmate_preload_trace_lib(void); /* tmate-msg.c */ From bfa3c104d7aed6300313694585fa676f33ba5e4a Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 10 Nov 2019 15:19:32 -0500 Subject: [PATCH 27/59] Refactor static builds --- .gitignore | 1 + .travis.yml | 4 ++-- Dockerfile | 5 +++-- build_static_release.sh | 33 +++++++++++++++++++++++++++++++++ package_release.sh | 14 -------------- 5 files changed, 39 insertions(+), 18 deletions(-) create mode 100755 build_static_release.sh delete mode 100755 package_release.sh diff --git a/.gitignore b/.gitignore index 93153ede..bcbdfe13 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,4 @@ downloads/ ext/ libssh-*/ msgpack-*/ +releases/ diff --git a/.travis.yml b/.travis.yml index a02e89a8..fc43a83f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,7 +20,7 @@ script: # On arch=arm64, some directories are not setup correctly, and 'ruby -S gem # install dpl' required by the release push scripts fails. - 'if [ "$TRAVIS_TAG" ]; then sudo chown -R $USER: /var/lib/gems /usr/local/bin; fi' -- 'if [ "$TRAVIS_TAG" ]; then ./package_release.sh $TRAVIS_TAG $PLATFORM; fi' +- 'if [ "$TRAVIS_TAG" ]; then ./build_static_release.sh $TRAVIS_TAG $PLATFORM; fi' deploy: provider: releases @@ -29,7 +29,7 @@ deploy: skip_cleanup: true overwrite: true file_glob: true - file: /tmp/tmate-release/*.tar.* + file: releases/*.tar.* on: repo: tmate-io/tmate branch: master diff --git a/Dockerfile b/Dockerfile index c7aa2b9f..8b736f63 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,9 +20,10 @@ RUN set -ex; \ make -j $(nproc); \ make install -COPY . . +COPY compat ./compat +COPY *.c *.h autogen.sh Makefile.am configure.ac ./ RUN ./autogen.sh && ./configure --enable-static RUN make -j $(nproc) -RUN strip tmate +RUN objcopy --only-keep-debug tmate tmate.symbols && strip tmate RUN ./tmate -V diff --git a/build_static_release.sh b/build_static_release.sh new file mode 100755 index 00000000..77b5d003 --- /dev/null +++ b/build_static_release.sh @@ -0,0 +1,33 @@ +#!/bin/bash +set -eux + +# This is invoked by .travis.yml + +VERSION=$1 +PLATFORM=$2 + +SRC_VERSION=`cat configure.ac | grep AC_INIT | sed -E 's/^AC_INIT\(tmate, (.+)\)$/\1/'` + +if [ $SRC_VERSION != $VERSION ]; then + echo "Version mismatch: $SRC_VERSION != $VERSION" + exit 1 +fi + +RELEASE_NAME=tmate-$VERSION-static-linux-$PLATFORM +echo "Building $RELEASE_NAME" + +docker build . --tag local-$PLATFORM/tmate-build --build-arg PLATFORM=$PLATFORM + +mkdir -p releases +cd releases + +rm -rf $RELEASE_NAME +mkdir -p $RELEASE_NAME +docker run --rm local-$PLATFORM/tmate-build cat tmate > $RELEASE_NAME/tmate +chmod +x $RELEASE_NAME/tmate +tar -cf - $RELEASE_NAME | xz > tmate-$VERSION-static-linux-$PLATFORM.tar.xz + +rm -rf $RELEASE_NAME-symbols +mkdir -p $RELEASE_NAME-symbols +docker run --rm local-$PLATFORM/tmate-build cat tmate.symbols > $RELEASE_NAME-symbols/tmate.symbols +tar -cf - $RELEASE_NAME-symbols | xz > dbg-symbols-tmate-$VERSION-static-linux-$PLATFORM.tar.xz diff --git a/package_release.sh b/package_release.sh deleted file mode 100755 index f4186e3c..00000000 --- a/package_release.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash -set -eux -VERSION=$1 -PLATFORM=$2 -RELEASE_NAME=tmate-$VERSION-static-linux-$PLATFORM - -# This assumes the follow command has already been run: -# docker build . --tag local-$PLATFORM/tmate-build --build-arg PLATFORM=$PLATFORM - -mkdir -p /tmp/tmate-release/$RELEASE_NAME -cd /tmp/tmate-release -docker run --rm local-$PLATFORM/tmate-build cat tmate > $RELEASE_NAME/tmate -chmod +x $RELEASE_NAME/tmate -tar -cf - $RELEASE_NAME | xz > tmate-$VERSION-static-linux-$PLATFORM.tar.xz From 7e02dba7efb73aabbf1a4f0cd3c43739d62b82bf Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 10 Nov 2019 16:23:00 -0500 Subject: [PATCH 28/59] Minor refactor --- tmate-ssh-client.c | 38 ++++++++++++++++++++------------------ tmate.h | 1 - 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index 221d7c9f..c52c166c 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -86,7 +86,6 @@ static void on_ssh_auth_server_complete(struct tmate_ssh_client *connected_clien if (client == connected_client) continue; - assert(!client->has_encoder); kill_ssh_client(client, NULL); } } @@ -177,7 +176,9 @@ static void tune_socket_opts(int fd) #define SSO(level, optname, val) ({ \ int _flag = val; \ if (setsockopt(fd, level, optname, &(_flag), sizeof(int)) < 0) { \ - tmate_info("setsockopt(" #level ", " #optname ", %d) failed", val); \ + /* If the connection has been closed, we'll get EINVAL */ \ + if (errno != EINVAL) \ + tmate_info("setsockopt(" #level ", " #optname ", %d) failed %s", val, strerror(errno)); \ } \ }) @@ -249,23 +250,11 @@ static void init_conn_fd(struct tmate_ssh_client *client) static void on_ssh_client_event(struct tmate_ssh_client *client) { - char *identity; - ssh_key pubkey; - enum ssh_keytypes_e key_type; - unsigned char *hash; - ssize_t hash_len; - char *hash_str; - const char *server_hash_str; - int match; - - int verbosity = SSH_LOG_NOLOG + log_get_level(); - int port = options_get_number(global_options, "tmate-server-port"); - ssh_session session = client->session; ssh_channel channel = client->channel; switch (client->state) { - case SSH_INIT: + case SSH_INIT: { client->session = session = ssh_new(); if (!session) { tmate_fatal("cannot ssh_new()"); @@ -274,6 +263,9 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) ssh_set_callbacks(session, &client->ssh_callbacks); + int verbosity = SSH_LOG_NOLOG + log_get_level(); + int port = options_get_number(global_options, "tmate-server-port"); + ssh_set_blocking(session, 0); ssh_options_set(session, SSH_OPTIONS_HOST, client->server_ip); ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &verbosity); @@ -281,6 +273,7 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) ssh_options_set(session, SSH_OPTIONS_USER, "tmate"); ssh_options_set(session, SSH_OPTIONS_COMPRESSION, "yes"); + char *identity; if ((identity = get_identity())) { /* * FIXME libssh will continue with the next set of @@ -295,7 +288,8 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) } client->state = SSH_CONNECT; - // fall through + } + // fall through case SSH_CONNECT: switch (ssh_connect(session)) { @@ -314,7 +308,15 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) } // fall through - case SSH_AUTH_SERVER: + case SSH_AUTH_SERVER: { + ssh_key pubkey; + enum ssh_keytypes_e key_type; + unsigned char *hash; + ssize_t hash_len; + char *hash_str; + const char *server_hash_str; + int match; + #if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 9, 0) if (ssh_get_server_publickey(session, &pubkey) < 0) tmate_fatal("ssh_get_server_publickey"); @@ -379,6 +381,7 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) on_ssh_auth_server_complete(client); client->state = SSH_AUTH_CLIENT_NONE; + } // fall through case SSH_AUTH_CLIENT_NONE: @@ -573,7 +576,6 @@ struct tmate_ssh_client *tmate_ssh_client_alloc(struct tmate_session *session, client->state = SSH_NONE; client->session = NULL; client->channel = NULL; - client->has_encoder = 0; return client; } diff --git a/tmate.h b/tmate.h index ec6d0f29..f4783dc8 100644 --- a/tmate.h +++ b/tmate.h @@ -130,7 +130,6 @@ struct tmate_ssh_client { char *server_ip; - int has_encoder; int state; /* From 9fe8b32293982bb85eb12b9c55991b6fa0dac400 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 10 Nov 2019 16:29:05 -0500 Subject: [PATCH 29/59] Add foreground tip --- tmate-session.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tmate-session.c b/tmate-session.c index d88ec5a5..02f25c14 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -194,7 +194,8 @@ void tmate_session_start(void) tmate_set_val("foreground", "true"); tmate_info("To connect to the session locally, run: tmate -S %s attach", socket_path); } else { - cfg_add_cause("%s", "To see these messages again, run: tmate show-messages"); + cfg_add_cause("%s", "Tip: if you wish to use tmate for remote access, run tmate -F"); + cfg_add_cause("%s", "To see the following messages again, run: tmate show-messages"); cfg_add_cause("%s", "Press to dismiss"); cfg_add_cause("%s", "-----------------------------------------------------"); } From f895fe01b1ddd0f0dbd0d019c5f290c7650b7d3b Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sun, 10 Nov 2019 22:27:23 -0500 Subject: [PATCH 30/59] Rename account-key -> api-key --- options-table.c | 2 +- tmux.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/options-table.c b/options-table.c index 4a20c548..e3362ba8 100644 --- a/options-table.c +++ b/options-table.c @@ -960,7 +960,7 @@ const struct options_table_entry options_table[] = { .default_str = "" }, - { .name = "tmate-account-key", + { .name = "tmate-api-key", .type = OPTIONS_TABLE_STRING, .scope = OPTIONS_TABLE_SERVER, .default_str = "" diff --git a/tmux.c b/tmux.c index b6b03346..53b984d7 100644 --- a/tmux.c +++ b/tmux.c @@ -64,7 +64,7 @@ usage(void) "Basic options:\n" " -n specify the session token instead of getting a random one\n" " -r same, but for the read-only token\n" - " -k specify the account-key, necessary for named sessions on tmate.io\n" + " -k specify an api-key, necessary for using named sessions on tmate.io\n" " -F set the foreground mode, useful for setting remote access\n" " -f set the config file path\n" " -S set the socket path, useful to issue commands to a running tmate instance\n" @@ -212,7 +212,7 @@ find_home(void) } #ifdef TMATE -static char *account_key; +static char *api_key; static char *session_name; static char *session_name_ro; static char *authorized_keys; @@ -226,7 +226,7 @@ void tmate_load_cli_options(void) val = NULL; \ } \ }) - SET_OPT("tmate-account-key", account_key); + SET_OPT("tmate-api-key", api_key); SET_OPT("tmate-session-name", session_name); SET_OPT("tmate-session-name-ro", session_name_ro); SET_OPT("tmate-authorized-keys", authorized_keys); @@ -310,7 +310,7 @@ main(int argc, char **argv) unsetenv("TMUX"); break; case 'k': - account_key = xstrdup(optarg); + api_key = xstrdup(optarg); break; case 'n': session_name = xstrdup(optarg); From 5e00bfa5e137e76c81888727712ced2b3fd99f5b Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Sat, 16 Nov 2019 17:08:46 -0500 Subject: [PATCH 31/59] Rephrase --- tmate-session.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tmate-session.c b/tmate-session.c index 02f25c14..62493278 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -194,10 +194,10 @@ void tmate_session_start(void) tmate_set_val("foreground", "true"); tmate_info("To connect to the session locally, run: tmate -S %s attach", socket_path); } else { - cfg_add_cause("%s", "Tip: if you wish to use tmate for remote access, run tmate -F"); - cfg_add_cause("%s", "To see the following messages again, run: tmate show-messages"); - cfg_add_cause("%s", "Press to dismiss"); - cfg_add_cause("%s", "-----------------------------------------------------"); + cfg_add_cause("%s", "Tip: if you wish to use tmate only for remote access, run: tmate -F"); + cfg_add_cause("%s", "To see the following messages again, run in a tmate session: tmate show-messages"); + cfg_add_cause("%s", "Press or to continue"); + cfg_add_cause("%s", "---------------------------------------------------------------------"); } send_authorized_keys(); From f0a4707ef35b04afb87092f11782f63776b3cdec Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Thu, 28 Nov 2019 16:30:32 -0500 Subject: [PATCH 32/59] Update dockerfile for size --- Dockerfile | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8b736f63..2f6387c5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ ARG PLATFORM=amd64 -FROM ${PLATFORM}/alpine:3.10 +FROM ${PLATFORM}/alpine:3.10 AS build WORKDIR /build @@ -25,5 +25,13 @@ COPY *.c *.h autogen.sh Makefile.am configure.ac ./ RUN ./autogen.sh && ./configure --enable-static RUN make -j $(nproc) -RUN objcopy --only-keep-debug tmate tmate.symbols && strip tmate +RUN objcopy --only-keep-debug tmate tmate.symbols && chmod -x tmate.symbols && strip tmate RUN ./tmate -V + +FROM alpine:3.9 + +RUN apk --no-cache add bash +RUN mkdir /build +ENV PATH=/build:$PATH +COPY --from=build /build/tmate.symbols /build +COPY --from=build /build/tmate /build From cc01f3f13a73cba3021c072780a22d1fcbd0dceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20Szyma=C5=84ski?= Date: Fri, 29 Nov 2019 14:08:06 +0100 Subject: [PATCH 33/59] Add build on s390x and ppc64le --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index fc43a83f..5a83e0ed 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,10 @@ matrix: env: PLATFORM=arm32v7 - arch: arm64 env: PLATFORM=arm64v8 + - arch: s390x + env: PLATFORM=s390x + - arch: ppc64le + env: PLATFORM=ppc64le script: - 'docker build . --tag local-$PLATFORM/tmate-build --build-arg PLATFORM=$PLATFORM' From ba6ac3a363ae7bdd4af946cc81a19f703d06907f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Damian=20Szyma=C5=84ski?= Date: Fri, 6 Dec 2019 12:43:04 +0100 Subject: [PATCH 34/59] Update paths in build_static_release script (#178) --- build_static_release.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build_static_release.sh b/build_static_release.sh index 77b5d003..9cb35435 100755 --- a/build_static_release.sh +++ b/build_static_release.sh @@ -23,11 +23,11 @@ cd releases rm -rf $RELEASE_NAME mkdir -p $RELEASE_NAME -docker run --rm local-$PLATFORM/tmate-build cat tmate > $RELEASE_NAME/tmate +docker run --rm local-$PLATFORM/tmate-build cat /build/tmate > $RELEASE_NAME/tmate chmod +x $RELEASE_NAME/tmate tar -cf - $RELEASE_NAME | xz > tmate-$VERSION-static-linux-$PLATFORM.tar.xz rm -rf $RELEASE_NAME-symbols mkdir -p $RELEASE_NAME-symbols -docker run --rm local-$PLATFORM/tmate-build cat tmate.symbols > $RELEASE_NAME-symbols/tmate.symbols +docker run --rm local-$PLATFORM/tmate-build cat /build/tmate.symbols > $RELEASE_NAME-symbols/tmate.symbols tar -cf - $RELEASE_NAME-symbols | xz > dbg-symbols-tmate-$VERSION-static-linux-$PLATFORM.tar.xz From 9e3e39d66ddb4a610720fa37a5683c846d2a1ba6 Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Wed, 11 Mar 2020 11:30:33 -0400 Subject: [PATCH 35/59] Avoid initializing stdout twice Closes #190 --- log.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/log.c b/log.c index 12266aa4..45aaea46 100644 --- a/log.c +++ b/log.c @@ -61,6 +61,9 @@ log_get_level(void) void log_open_fp(FILE *f) { + if (log_file == f) + return; + if (log_file != NULL && !is_log_stdout()) fclose(log_file); From 339e6c43575244f72831654e5dda41c037febde7 Mon Sep 17 00:00:00 2001 From: Klemens Nanni Date: Thu, 2 Apr 2020 18:19:57 +0200 Subject: [PATCH 36/59] Include for global errno At least on OpenBSD the symbol `errno` is otherwise not defined; it is used in the `SSO()` macro and `send_authorized_keys()` function. --- tmate-session.c | 1 + tmate-ssh-client.c | 1 + 2 files changed, 2 insertions(+) diff --git a/tmate-session.c b/tmate-session.c index 62493278..5ba0896c 100644 --- a/tmate-session.c +++ b/tmate-session.c @@ -5,6 +5,7 @@ #include #include +#include #include #include #include diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index c52c166c..42c4e6a6 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include From cbec43f56dfb48c2fb6e00faa2cb85443d4b7d8f Mon Sep 17 00:00:00 2001 From: Nicolas Viennot Date: Tue, 14 Apr 2020 18:22:04 -0400 Subject: [PATCH 37/59] Better debugging when keys are not matching --- tmate-ssh-client.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index 42c4e6a6..995c92a7 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -328,7 +328,7 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) if (ssh_get_publickey_hash(pubkey, SSH_PUBLICKEY_HASH_SHA256, &hash, &hash_len) < 0) { - kill_ssh_client(client, "Cannot authenticate server"); + kill_ssh_client(client, "Failed to get server fingerprint"); return; } @@ -362,15 +362,17 @@ static void on_ssh_client_event(struct tmate_ssh_client *client) } match = !strcmp(hash_str, server_hash_str); + if (!match) { + kill_ssh_client(client, "Server fingerprint not recognized: " + "`%s', expected `%s'", server_hash_str, hash_str); + } ssh_key_free(pubkey); ssh_clean_pubkey_hash(&hash); free(hash_str); - if (!match) { - kill_ssh_client(client, "Cannot authenticate server"); + if (!match) return; - } /* * At this point, we abort other connection attempts to the From f6a4ae6042f4bb2b6db8eda23df31d8b788a7978 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Jacke?= Date: Thu, 18 Feb 2021 11:58:52 +0100 Subject: [PATCH 38/59] client: set IPTOS_LOWDELAY on TCP connection this helps edge routers to prioritize our interactive network traffic. --- tmate-ssh-client.c | 1 + 1 file changed, 1 insertion(+) diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index 995c92a7..ce8d5a5a 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -183,6 +183,7 @@ static void tune_socket_opts(int fd) } \ }) + SSO(IPPROTO_IP, IP_TOS, 0x10); /* IPTOS_LOWDELAY */ SSO(IPPROTO_TCP, TCP_NODELAY, 1); SSO(SOL_SOCKET, SO_KEEPALIVE, 1); #ifdef TCP_KEEPALIVE From 8123fa34f847c658f7cedf154dd4cf966047e6bf Mon Sep 17 00:00:00 2001 From: hpcbjdic Date: Tue, 24 Mar 2020 14:56:06 +0100 Subject: [PATCH 39/59] enable redefinition of TMUX_CONF Without the added #ifndef / #endif it's not possible to _actually_ redefine TMUX_CONF by means of the compiler flag -DTMUX_CONF=... as done by the build system. The same patch has also been applied to tmux, cf. master at https://github.com/tmux/tmux/blob/master/tmux.h. --- tmux.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tmux.h b/tmux.h index c60a044e..b38615b6 100644 --- a/tmux.h +++ b/tmux.h @@ -53,7 +53,9 @@ struct tmuxpeer; struct tmuxproc; /* Default global configuration file. */ +#ifndef TMUX_CONF #define TMUX_CONF "/etc/tmux.conf" +#endif /* * Minimum layout cell size, NOT including separator line. The scroll region From e5ce3f04d2851b4c825430f87620cc42d1d946d6 Mon Sep 17 00:00:00 2001 From: Sergio de Almeida Cipriano Junior Date: Wed, 18 Nov 2020 10:59:07 -0300 Subject: [PATCH 40/59] Fix typo in ssh client --- tmate-ssh-client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tmate-ssh-client.c b/tmate-ssh-client.c index ce8d5a5a..bed79e95 100644 --- a/tmate-ssh-client.c +++ b/tmate-ssh-client.c @@ -453,7 +453,7 @@ SSH_NEW_CHANNEL: ssh_get_error(session)); return; case SSH_OK: - tmate_debug("Session opened, initalizing tmate"); + tmate_debug("Session opened, initializing tmate"); client->state = SSH_BOOTSTRAP; } // fall through From 808b5645641c82cc09e5488ea0466908a514bba5 Mon Sep 17 00:00:00 2001 From: Sergio de Almeida Cipriano Junior Date: Wed, 18 Nov 2020 11:30:37 -0300 Subject: [PATCH 41/59] Update manpage --- tmux.1 | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/tmux.1 b/tmux.1 index b55b3682..c90b5560 100644 --- a/tmux.1 +++ b/tmux.1 @@ -19,10 +19,11 @@ .Os .Sh NAME .Nm tmate -.Nd terminal multiplexer +.Nd terminal multiplexer with instant terminal sharing .Sh SYNOPSIS .Nm tmate .Bk -words +.Op show-messages .Op Fl 2CluvV .Op Fl c Ar shell-command .Op Fl f Ar file @@ -32,13 +33,24 @@ .Ek .Sh DESCRIPTION .Nm -is a terminal multiplexer: +is a terminal multiplexer with instant terminal sharing: it enables a number of terminals to be created, accessed, and -controlled from a single screen. +controlled from a single screen and be shared with another mates. .Nm may be detached from a screen and continue running in the background, -then later reattached. +then later reattached, like as a daemon. +.Pp +.Nm +provides an instant pairing solution, allowing you to share a terminal +with one or several teammates. Together with a voice call, it's almost like +pairing in person. The terminal sharing works by using SSH connections to +backend servers maintained by tmate upstream developers; teammates need to be +given a randomly-generated token to be able to join a session. +.Pp +.Nm +is a modified version of tmux, and uses the same configurations such as +keybindings, color schemes, etc. .Pp When .Nm @@ -47,9 +59,9 @@ is started it creates a new with a single .Em window and displays it on screen. -A status line at the bottom of the screen -shows information on the current session -and is used to enter interactive commands. +A status line at the bottom of the screen shows information +on the current session, such as ssh command to share with +your mate, and is used to enter interactive commands. .Pp A session is a single collection of .Em pseudo terminals From c9ec7af63238b0a47bf659729d32dde2066ce60f Mon Sep 17 00:00:00 2001 From: n0vember Date: Wed, 27 Jan 2021 15:53:45 +0100 Subject: [PATCH 42/59] add basic information for -a option in man page and help text --- tmux.1 | 4 ++++ tmux.c | 1 + 2 files changed, 5 insertions(+) diff --git a/tmux.1 b/tmux.1 index c90b5560..55f88c98 100644 --- a/tmux.1 +++ b/tmux.1 @@ -110,6 +110,10 @@ The options are as follows: Force .Nm to assume the terminal supports 256 colours. +.It Fl a Ar file +Limit access to the public keys listed in the +.Ar file +given as argument. .It Fl C Start in control mode (see the .Sx CONTROL MODE diff --git a/tmux.c b/tmux.c index 53b984d7..730c2dfc 100644 --- a/tmux.c +++ b/tmux.c @@ -68,6 +68,7 @@ usage(void) " -F set the foreground mode, useful for setting remote access\n" " -f set the config file path\n" " -S set the socket path, useful to issue commands to a running tmate instance\n" + " -a limit access to ssh public keys listed in provided file\n" " -v set verbosity (can be repeated)\n" " -V print version\n" ,__progname); From be4a88507e082e0e8e591e18b08374ff591b3980 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Sat, 5 Mar 2022 01:33:21 +0100 Subject: [PATCH 43/59] chore: add FUNDING.yml --- .github/FUNDING.yml | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..ea4e6439 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +github: nviennot From 169eb64b99719eadccba1f9a00856b68b589ef35 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 3 Aug 2022 18:19:32 +0800 Subject: [PATCH 44/59] Add FreeBSD build by https://github.com/vmactions/freebsd-vm --- .github/workflows/FreeBSD.yml | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 .github/workflows/FreeBSD.yml diff --git a/.github/workflows/FreeBSD.yml b/.github/workflows/FreeBSD.yml new file mode 100644 index 00000000..3a16af9f --- /dev/null +++ b/.github/workflows/FreeBSD.yml @@ -0,0 +1,40 @@ +name: FreeBSD +on: + push: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/FreeBSD.yml' + pull_request: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/FreeBSD.yml' + + + +jobs: + FreeBSD: + runs-on: macos-12 + steps: + - uses: actions/checkout@v2 + - uses: vmactions/freebsd-vm@v0 + with: + prepare: | + pkg install -y gmake automake autoconf libtool pkgconf libevent msgpack libssh + usesh: true + run: | + autoupdate + ./autogen.sh + ./configure + make + make install + + + From a258907cf8a8888cbb895aa478b697200081c006 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 3 Aug 2022 18:20:33 +0800 Subject: [PATCH 45/59] add NetBSD test by https://github.com/vmactions/netbsd-vm --- .github/workflows/NetBSD.yml | 40 ++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 .github/workflows/NetBSD.yml diff --git a/.github/workflows/NetBSD.yml b/.github/workflows/NetBSD.yml new file mode 100644 index 00000000..0566d3b9 --- /dev/null +++ b/.github/workflows/NetBSD.yml @@ -0,0 +1,40 @@ +name: NetBSD +on: + push: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/NetBSD.yml' + pull_request: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/NetBSD.yml' + + + +jobs: + NetBSD: + runs-on: macos-12 + steps: + - uses: actions/checkout@v2 + - uses: vmactions/netbsd-vm@v0 + with: + prepare: | + pkg_add gmake automake autoconf libtool pkgconf libevent msgpack libssh + usesh: true + run: | + autoupdate + ./autogen.sh + ./configure + make + make install + + + From b1079b43930b42f53f6f1579fd1d6afcf9134aeb Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 3 Aug 2022 18:21:37 +0800 Subject: [PATCH 46/59] add OpenBSD build by https://github.com/vmactions/openbsd-vm --- .github/workflows/OpenBSD.yml | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/workflows/OpenBSD.yml diff --git a/.github/workflows/OpenBSD.yml b/.github/workflows/OpenBSD.yml new file mode 100644 index 00000000..fbeda51d --- /dev/null +++ b/.github/workflows/OpenBSD.yml @@ -0,0 +1,44 @@ +name: OpenBSD +on: + push: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/OpenBSD.yml' + pull_request: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/OpenBSD.yml' + + + +jobs: + OpenBSD: + runs-on: macos-12 + steps: + - uses: actions/checkout@v2 + - uses: vmactions/openbsd-vm@v0 + with: + prepare: | + pkg_add gmake automake-1.16.3 autoconf-2.71 libtool pkgconf libevent msgpack libssh gcc-11.2.0p2 + usesh: true + run: | + ln -s /usr/local/bin/egcc /usr/local/bin/gcc + autoupdate + aclocal --print-ac-dir + export AUTOMAKE_VERSION=1.16 + export AUTOCONF_VERSION=2.71 + ./autogen.sh + ./configure + make + make install + + + From 577e04df6c746acbca0b98e12f6ca143bf031be1 Mon Sep 17 00:00:00 2001 From: neil Date: Wed, 3 Aug 2022 23:33:18 +0800 Subject: [PATCH 47/59] fix --- .github/workflows/OpenBSD.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/OpenBSD.yml b/.github/workflows/OpenBSD.yml index fbeda51d..3c884006 100644 --- a/.github/workflows/OpenBSD.yml +++ b/.github/workflows/OpenBSD.yml @@ -31,10 +31,9 @@ jobs: usesh: true run: | ln -s /usr/local/bin/egcc /usr/local/bin/gcc - autoupdate - aclocal --print-ac-dir export AUTOMAKE_VERSION=1.16 export AUTOCONF_VERSION=2.71 + autoupdate ./autogen.sh ./configure make From ef11a7b30ed743051e703b5745fa41916ae0be9f Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 13:39:23 +0800 Subject: [PATCH 48/59] fix OpenBSD.yml --- .github/workflows/OpenBSD.yml | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/.github/workflows/OpenBSD.yml b/.github/workflows/OpenBSD.yml index 3c884006..53f06485 100644 --- a/.github/workflows/OpenBSD.yml +++ b/.github/workflows/OpenBSD.yml @@ -27,10 +27,17 @@ jobs: - uses: vmactions/openbsd-vm@v0 with: prepare: | - pkg_add gmake automake-1.16.3 autoconf-2.71 libtool pkgconf libevent msgpack libssh gcc-11.2.0p2 + pkg_add automake-1.16.3 autoconf-2.71 libtool pkgconf libevent msgpack libssh usesh: true run: | - ln -s /usr/local/bin/egcc /usr/local/bin/gcc + sed -i 's,,,' *.[ch] + curl https://raw.githubusercontent.com/openbsd/ports/master/sysutils/tmate/patches/patch-Makefile_am | patch + curl https://raw.githubusercontent.com/openbsd/ports/master/sysutils/tmate/patches/patch-server_c | patch + curl https://raw.githubusercontent.com/openbsd/ports/master/sysutils/tmate/patches/patch-tmate-debug_c | patch + curl https://raw.githubusercontent.com/openbsd/ports/master/sysutils/tmate/patches/patch-tmate_h | patch + curl https://raw.githubusercontent.com/openbsd/ports/master/sysutils/tmate/patches/patch-tmux_c | patch + curl https://raw.githubusercontent.com/openbsd/ports/master/sysutils/tmate/patches/patch-tmux_h | patch + curl https://raw.githubusercontent.com/openbsd/ports/master/sysutils/tmate/patches/patch-osdep-openbsd_c | patch export AUTOMAKE_VERSION=1.16 export AUTOCONF_VERSION=2.71 autoupdate From 17d4a8a7dfa25bcf3ddb336916010f905f2f4183 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 13:45:53 +0800 Subject: [PATCH 49/59] fix OpenBSD.yml --- .github/workflows/OpenBSD.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/OpenBSD.yml b/.github/workflows/OpenBSD.yml index 53f06485..8fb7901b 100644 --- a/.github/workflows/OpenBSD.yml +++ b/.github/workflows/OpenBSD.yml @@ -27,7 +27,7 @@ jobs: - uses: vmactions/openbsd-vm@v0 with: prepare: | - pkg_add automake-1.16.3 autoconf-2.71 libtool pkgconf libevent msgpack libssh + pkg_add automake-1.16.3 autoconf-2.71 libtool pkgconf libevent msgpack libssh curl usesh: true run: | sed -i 's,,,' *.[ch] From fde4b58228cd8226e7128bf101e2fe569eed5882 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 13:46:36 +0800 Subject: [PATCH 50/59] add MacOS.yml --- .github/workflows/MacOS.yml | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/MacOS.yml diff --git a/.github/workflows/MacOS.yml b/.github/workflows/MacOS.yml new file mode 100644 index 00000000..5e118ee7 --- /dev/null +++ b/.github/workflows/MacOS.yml @@ -0,0 +1,37 @@ +name: MacOS +on: + push: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/MacOS.yml' + pull_request: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/MacOS.yml' + + + +jobs: + NetBSD: + runs-on: macos-latest + steps: + - uses: actions/checkout@v2 + - run: | + brew install automake + autoupdate + ./autogen.sh + ./configure + make + make install + + + + From 05a849ba2b29351419ad2034994111388c0817b7 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 13:47:18 +0800 Subject: [PATCH 51/59] fix MacOS.yml --- .github/workflows/MacOS.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/MacOS.yml b/.github/workflows/MacOS.yml index 5e118ee7..db1c9ca0 100644 --- a/.github/workflows/MacOS.yml +++ b/.github/workflows/MacOS.yml @@ -20,7 +20,7 @@ on: jobs: - NetBSD: + MacOS: runs-on: macos-latest steps: - uses: actions/checkout@v2 From 7c0bbf3e164d869073012b7fffd896869337b143 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 13:56:06 +0800 Subject: [PATCH 52/59] fix MacOS.yml --- .github/workflows/MacOS.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/MacOS.yml b/.github/workflows/MacOS.yml index db1c9ca0..37293260 100644 --- a/.github/workflows/MacOS.yml +++ b/.github/workflows/MacOS.yml @@ -25,7 +25,7 @@ jobs: steps: - uses: actions/checkout@v2 - run: | - brew install automake + brew install automake msgpack autoupdate ./autogen.sh ./configure From 17fcc8b76d28ae5e59b59a08a642e462eea34221 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 13:57:59 +0800 Subject: [PATCH 53/59] fix MacOS.yml --- .github/workflows/MacOS.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/MacOS.yml b/.github/workflows/MacOS.yml index 37293260..3dc5247e 100644 --- a/.github/workflows/MacOS.yml +++ b/.github/workflows/MacOS.yml @@ -25,7 +25,7 @@ jobs: steps: - uses: actions/checkout@v2 - run: | - brew install automake msgpack + brew install automake msgpack libssh autoupdate ./autogen.sh ./configure From 9a1aa9ae9d9c40b6d583355246089a9468dd03bc Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 14:29:15 +0800 Subject: [PATCH 54/59] add Ubuntu.yml --- .github/workflows/Ubuntu.yml | 37 ++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/Ubuntu.yml diff --git a/.github/workflows/Ubuntu.yml b/.github/workflows/Ubuntu.yml new file mode 100644 index 00000000..581e616d --- /dev/null +++ b/.github/workflows/Ubuntu.yml @@ -0,0 +1,37 @@ +name: Ubuntu +on: + push: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/Ubuntu.yml' + pull_request: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/Ubuntu.yml' + + + +jobs: + Ubuntu: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - run: | + apt-get install -y build-essential automake libtool libevent-dev libncurses5-dev libmsgpack-dev libssh-dev pkg-config + autoupdate + ACLOCAL_PATH=/usr/share/aclocal ./autogen.sh + ./configure + make + make install + + + + From 2ff8bc134d381c88eba8f382625642e5aec8d5da Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 14:33:12 +0800 Subject: [PATCH 55/59] fix Ubuntu.yml --- .github/workflows/Ubuntu.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Ubuntu.yml b/.github/workflows/Ubuntu.yml index 581e616d..7c8dea57 100644 --- a/.github/workflows/Ubuntu.yml +++ b/.github/workflows/Ubuntu.yml @@ -25,7 +25,7 @@ jobs: steps: - uses: actions/checkout@v2 - run: | - apt-get install -y build-essential automake libtool libevent-dev libncurses5-dev libmsgpack-dev libssh-dev pkg-config + sudo apt-get install -y build-essential automake libtool libevent-dev libncurses5-dev libmsgpack-dev libssh-dev pkg-config autoupdate ACLOCAL_PATH=/usr/share/aclocal ./autogen.sh ./configure From 3efc8496cc90d55dd9bc44d4b5f529ac9760bf66 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 14:34:47 +0800 Subject: [PATCH 56/59] fix Ubuntu.yml --- .github/workflows/Ubuntu.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Ubuntu.yml b/.github/workflows/Ubuntu.yml index 7c8dea57..cecf39b9 100644 --- a/.github/workflows/Ubuntu.yml +++ b/.github/workflows/Ubuntu.yml @@ -30,7 +30,7 @@ jobs: ACLOCAL_PATH=/usr/share/aclocal ./autogen.sh ./configure make - make install + sudo make install From 15001bfa7739b144969c1181e66c65f0cb14e614 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 14:57:15 +0800 Subject: [PATCH 57/59] fix --- .github/workflows/FreeBSD.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/FreeBSD.yml b/.github/workflows/FreeBSD.yml index 3a16af9f..e879618e 100644 --- a/.github/workflows/FreeBSD.yml +++ b/.github/workflows/FreeBSD.yml @@ -27,7 +27,7 @@ jobs: - uses: vmactions/freebsd-vm@v0 with: prepare: | - pkg install -y gmake automake autoconf libtool pkgconf libevent msgpack libssh + pkg install -y automake autoconf libtool pkgconf libevent msgpack libssh usesh: true run: | autoupdate From 6cb27ead4e77ba8cc15982d909fe57c074239434 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 15:04:07 +0800 Subject: [PATCH 58/59] fix NetBSD.yml --- .github/workflows/NetBSD.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/NetBSD.yml b/.github/workflows/NetBSD.yml index 0566d3b9..0bb0924a 100644 --- a/.github/workflows/NetBSD.yml +++ b/.github/workflows/NetBSD.yml @@ -27,7 +27,7 @@ jobs: - uses: vmactions/netbsd-vm@v0 with: prepare: | - pkg_add gmake automake autoconf libtool pkgconf libevent msgpack libssh + pkg_add automake autoconf libtool pkgconf libevent msgpack libssh usesh: true run: | autoupdate From ac919516f4f1b10ec928e20b3a5034d18f609d68 Mon Sep 17 00:00:00 2001 From: neil Date: Sat, 6 Aug 2022 15:05:07 +0800 Subject: [PATCH 59/59] add DragonflyBSD by https://github.com/vmactions/dragonflybsd-vm --- .github/workflows/DragonflyBSD.yml | 41 ++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 .github/workflows/DragonflyBSD.yml diff --git a/.github/workflows/DragonflyBSD.yml b/.github/workflows/DragonflyBSD.yml new file mode 100644 index 00000000..f014da9b --- /dev/null +++ b/.github/workflows/DragonflyBSD.yml @@ -0,0 +1,41 @@ +name: DragonflyBSD +on: + push: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/DragonflyBSD.yml' + pull_request: + branches: + - '*' + paths: + - '**.c' + - '**.h' + - 'compat/*' + - '.github/workflows/DragonflyBSD.yml' + + + +jobs: + DragonflyBSD: + runs-on: macos-12 + steps: + - uses: actions/checkout@v2 + - uses: vmactions/dragonflybsd-vm@v0 + with: + prepare: | + pkg install -y automake autoconf libtool pkgconf libevent msgpack libssh gsed + usesh: true + run: | + gsed -i "s/OK/0/g" tty-term.c + autoupdate + ./autogen.sh + ./configure + make + make install + + +