diff --git a/.gitignore b/.gitignore index be6072c..af9f365 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ build/ +deps/ __pycache__/ smtp-test-data.conf diff --git a/Makefile b/Makefile index 59a0a4e..2049fde 100644 --- a/Makefile +++ b/Makefile @@ -8,11 +8,29 @@ DESTDIR ?= CC ?= cc CFLAGS ?= -O2 -g CFLAGS += -std=c99 -D_GNU_SOURCE -Wall -Wextra -Wno-unused-parameter +BUILD := build + +# libssh2 before 1.11 cannot talk to current OpenSSH (no ed25519 before 1.9, +# only SHA-1 RSA signatures and key exchanges OpenSSH 10 dropped), so an older +# system libssh2 is replaced by a static build of this release (needs OpenSSL +# headers and curl). BUNDLE_LIBSSH2=yes|no overrides the check. +LIBSSH2_VER := 1.11.1 +LIBSSH2_SHA256 := d9ec76cbe34db98eec3539fe2c899d26b0c837cb3eb466a56b0f109cabf658f7 +LIBSSH2_DIR := deps/libssh2-$(LIBSSH2_VER) +BUNDLE_LIBSSH2 ?= $(shell pkg-config --atleast-version=1.11 libssh2 2>/dev/null && echo no || echo yes) + +ifeq ($(BUNDLE_LIBSSH2),yes) +PKGS := sqlite3 libssl libcrypto +LIBSSH2_A := $(LIBSSH2_DIR)/lib/libssh2.a +PKG_CFLAGS := -I$(LIBSSH2_DIR)/include $(shell pkg-config --cflags $(PKGS)) +PKG_LIBS := $(LIBSSH2_A) $(shell pkg-config --libs $(PKGS)) +else PKGS := libssh2 sqlite3 +LIBSSH2_A := PKG_CFLAGS := $(shell pkg-config --cflags $(PKGS)) PKG_LIBS := $(shell pkg-config --libs $(PKGS)) +endif -BUILD := build SRC := backend/src COMMON := config log net proto json services db stats OBJS_ALL := $(addprefix $(BUILD)/,$(addsuffix .o,$(COMMON) hub client relay main)) @@ -20,7 +38,7 @@ OBJS_TEST := $(addprefix $(BUILD)/,$(addsuffix .o,config log net proto json ser PYTHON ?= python3 -.PHONY: all test test-c test-web install clean docker-test check-deps +.PHONY: all test test-c test-web install clean distclean docker-test check-deps all: $(BUILD)/patchbayd @@ -31,8 +49,8 @@ $(BUILD): check-deps: @pkg-config --exists $(PKGS) || { \ echo "missing build dependencies (pkg-config cannot find: $(PKGS))" >&2; \ - echo " APT: sudo apt-get install build-essential pkg-config libssh2-1-dev libsqlite3-dev" >&2; \ - echo " XBPS: sudo xbps-install base-devel pkg-config libssh2-devel sqlite-devel" >&2; \ + echo " APT: sudo apt-get install build-essential pkg-config libssh2-1-dev libsqlite3-dev libssl-dev curl" >&2; \ + echo " XBPS: sudo xbps-install base-devel pkg-config libssh2-devel sqlite-devel openssl-devel curl" >&2; \ echo " or: sudo ./install.sh --role client|target (keeps an existing config)" >&2; \ exit 1; } @@ -42,7 +60,20 @@ $(BUILD)/schema.h: schema.sql | $(BUILD) sed -e 's/\\/\\\\/g' -e 's/"/\\"/g' -e 's/^/"/' -e 's/$$/\\n"/' $<; \ printf ';\n'; } > $@ -$(BUILD)/%.o: $(SRC)/%.c $(wildcard $(SRC)/*.h) $(BUILD)/schema.h | $(BUILD) check-deps +# Kept outside $(BUILD) so "make clean" (run by install.sh) does not download it again. +$(LIBSSH2_DIR)/lib/libssh2.a: | check-deps + @echo "system libssh2 is older than 1.11; building libssh2 $(LIBSSH2_VER) (static)" + rm -rf deps/src && mkdir -p deps/src + curl -fsSL --max-filesize 20000000 -o deps/src/libssh2.tar.gz \ + https://libssh2.org/download/libssh2-$(LIBSSH2_VER).tar.gz + echo "$(LIBSSH2_SHA256) deps/src/libssh2.tar.gz" | sha256sum -c - + tar -xzf deps/src/libssh2.tar.gz -C deps/src + cd deps/src/libssh2-$(LIBSSH2_VER) && ./configure --quiet --prefix="$(abspath $(LIBSSH2_DIR))" \ + --disable-shared --enable-static --with-pic --with-crypto=openssl --without-libz \ + --disable-examples-build --disable-docker-tests --disable-sshd-tests && $(MAKE) && $(MAKE) install + rm -rf deps/src + +$(BUILD)/%.o: $(SRC)/%.c $(wildcard $(SRC)/*.h) $(BUILD)/schema.h $(LIBSSH2_A) | $(BUILD) check-deps $(CC) $(CFLAGS) $(PKG_CFLAGS) -I$(BUILD) -c -o $@ $< $(BUILD)/patchbayd: $(OBJS_ALL) @@ -76,3 +107,6 @@ docker-test: clean: rm -rf $(BUILD) + +distclean: clean + rm -rf deps diff --git a/README.md b/README.md index ba3ddcb..b0918a9 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Port forwarding and routing between Linux machines over SSH, managed from a node The script installs dependencies via APT or XBPS, builds, installs to `/usr/local` (override with `PREFIX=`), creates `/etc/patchbay/patchbay.conf` from `examples/` and installs systemd, runit or OpenRC services (`--init` to choose, `--no-deps` to skip packages). -Dependencies: a C99 compiler, make, pkg-config, libssh2 (1.11+ recommended for AES-GCM), SQLite 3; on the target also OpenSSH server, Python 3 with Flask and cryptography. +Dependencies: a C99 compiler, make, pkg-config, libssh2 1.11+ (an older system libssh2 is replaced by a static build of 1.11.1, which needs OpenSSL headers and curl), SQLite 3; on the target also OpenSSH server, Python 3 with Flask and cryptography. ## Usage diff --git a/backend/src/client.c b/backend/src/client.c index 332135b..2378cc4 100644 --- a/backend/src/client.c +++ b/backend/src/client.c @@ -897,6 +897,13 @@ int client_identity(const struct pb_config *c, char *out, size_t outsz) for (int i = 0; cands[i]; i++) { if (access(cands[i], R_OK) != 0) continue; + // Once created, our own key stays in use (e.g. after a libssh2 + // upgrade made root's RSA key usable again), so the key added in + // the web UI keeps matching. + if (key_is_rsa(cands[i]) && access(PB_CLIENT_KEY, R_OK) == 0) { + snprintf(out, outsz, "%s", PB_CLIENT_KEY); + return 0; + } if (key_is_rsa(cands[i]) && !rsa_usable()) { // A key the target rejects is worse than none: use our own instead. static int told; diff --git a/install.sh b/install.sh index ef79c20..75e27ac 100755 --- a/install.sh +++ b/install.sh @@ -30,14 +30,14 @@ say() { printf '==> %s\n' "$*"; } # Dependencies if [ $DEPS = 1 ]; then if command -v apt-get >/dev/null; then - PKGS="build-essential pkg-config libssh2-1-dev libsqlite3-dev openssh-client" + PKGS="build-essential pkg-config libssh2-1-dev libsqlite3-dev libssl-dev curl openssh-client" [ "$ROLE" = target ] && PKGS="$PKGS openssh-server python3 python3-flask python3-cryptography" say "installing packages via APT: $PKGS" apt-get update # shellcheck disable=SC2086 DEBIAN_FRONTEND=noninteractive apt-get install -y $PKGS elif command -v xbps-install >/dev/null; then - PKGS="base-devel pkg-config libssh2-devel sqlite-devel openssh" + PKGS="base-devel pkg-config libssh2-devel sqlite-devel openssl-devel curl openssh" [ "$ROLE" = target ] && PKGS="$PKGS shadow python3 python3-Flask python3-cryptography" say "installing packages via XBPS: $PKGS" xbps-install -Sy