From 55bcb332268a325169bc4e6866c08f8f0e440ca0 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Thu, 24 Sep 2026 10:24:54 -0700 Subject: [PATCH 1/4] Leave the server SCP code out of client builds A client-only library still built and exported wolfSSH_SCP_accept(). The server SCP entry points now sit under NO_WOLFSSH_SERVER, the way the client ones already sit under NO_WOLFSSH_CLIENT. - guard wolfSSH_SCP_accept(), DoScpRequest() and ParseScpCommand() - guard the DoScpRequest() and ParseScpCommand() prototypes in internal.h --- src/wolfscp.c | 6 +++++- wolfssh/internal.h | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/wolfscp.c b/src/wolfscp.c index f658d51c0..c2be9423b 100644 --- a/src/wolfscp.c +++ b/src/wolfscp.c @@ -887,6 +887,7 @@ int DoScpSource(WOLFSSH* ssh) return ret; } +#ifndef NO_WOLFSSH_SERVER /* Contract is in wolfssh/wolfscp.h. */ int wolfSSH_SCP_accept(WOLFSSH* ssh) { @@ -992,6 +993,7 @@ int DoScpRequest(WOLFSSH* ssh) return ret; } +#endif /* !NO_WOLFSSH_SERVER */ /* Sets the error message that is sent back to the peer when an error or fatal * confirmation message is sent. Expected to be used inside the scp @@ -1616,6 +1618,7 @@ static int ParseBasePathHelper(WOLFSSH* ssh) return ret; }*/ +#ifndef NO_WOLFSSH_SERVER /* Parse scp command received, currently only looks for and stores the * SCP base path being written to. * @@ -1735,6 +1738,7 @@ int ParseScpCommand(WOLFSSH* ssh) return ret; } +#endif /* !NO_WOLFSSH_SERVER */ /* Reads and parses SCP protocol control messages * @@ -2221,7 +2225,7 @@ int wolfSSH_SCP_from(WOLFSSH* ssh, const char* src, const char* dst) return ret; } -#endif /* ! NO_WOLFSSH_CLIENT */ +#endif /* !NO_WOLFSSH_CLIENT */ #if !defined(WOLFSSH_SCP_USER_CALLBACKS) diff --git a/wolfssh/internal.h b/wolfssh/internal.h index d65da0d80..d706855b6 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -2322,10 +2322,12 @@ enum WS_ScpDirection { WOLFSSH_SCP_FROM }; +#ifndef NO_WOLFSSH_SERVER WOLFSSH_LOCAL int DoScpRequest(WOLFSSH* ssh); +WOLFSSH_LOCAL int ParseScpCommand(WOLFSSH* ssh); +#endif /* !NO_WOLFSSH_SERVER */ WOLFSSH_LOCAL int DoScpSink(WOLFSSH* ssh); WOLFSSH_LOCAL int DoScpSource(WOLFSSH* ssh); -WOLFSSH_LOCAL int ParseScpCommand(WOLFSSH* ssh); WOLFSSH_LOCAL int ReceiveScpMessage(WOLFSSH* ssh); WOLFSSH_LOCAL int ReceiveScpFile(WOLFSSH* ssh); WOLFSSH_LOCAL int SendScpConfirmation(WOLFSSH* ssh); From 68f0e26c162f1fccf769f5a062dc49968b5f7952 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Mon, 12 Oct 2026 11:31:26 -0700 Subject: [PATCH 2/4] Drop the sshd and client apps with their side --enable-all turns on wolfsshd and the ssh client app, so adding --disable-server or --disable-client built an app against a library missing its side and the link failed. configure now leaves out the app whose side is disabled, and stops with an error when that app was asked for outright. - give the client-less main() stubs in portfwd and scpclient a prototype, which -Wstrict-prototypes requires before C23 --- configure.ac | 12 ++++++++++++ examples/portfwd/portfwd.c | 2 +- examples/scpclient/scpclient.c | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/configure.ac b/configure.ac index fcc8d9553..2e29e2c08 100644 --- a/configure.ac +++ b/configure.ac @@ -262,6 +262,18 @@ AS_IF([test "x$ENABLED_DISTRO" = "xyes"], [ENABLED_ALL=yes; enable_shared=yes; enable_static=yes]) AS_IF([test "x$ENABLED_ALL" = "xyes"], [ENABLED_KEYGEN=yes; ENABLED_SCP=yes; ENABLED_SFTP=yes; ENABLED_FWD=yes; ENABLED_SHELL=yes; ENABLED_AGENT=yes; ENABLED_SSHD=yes; ENABLED_SSHCLIENT=yes; ENABLED_CERTS=yes; ENABLED_KEYBOARD_INTERACTIVE=yes]) + +# The apps need the side of the library they run on. Asking for one outright +# without its side is an error; getting it from --enable-all only drops it. +AS_IF([test "x$ENABLED_SERVER" = "xno" && test "x$ENABLED_SSHD" = "xyes"], + [AS_IF([test "x$enable_sshd" = "xyes"], + [AC_MSG_ERROR([--enable-sshd requires the server, leave out --disable-server.])], + [ENABLED_SSHD=no])]) +AS_IF([test "x$ENABLED_CLIENT" = "xno" && test "x$ENABLED_SSHCLIENT" = "xyes"], + [AS_IF([test "x$enable_sshclient" = "xyes"], + [AC_MSG_ERROR([--enable-sshclient requires the client, leave out --disable-client.])], + [ENABLED_SSHCLIENT=no])]) + AS_IF([test "x$ENABLED_SSHD" = "xyes"], [ENABLED_SHELL=yes]) diff --git a/examples/portfwd/portfwd.c b/examples/portfwd/portfwd.c index 953bcf074..325309137 100644 --- a/examples/portfwd/portfwd.c +++ b/examples/portfwd/portfwd.c @@ -1000,7 +1000,7 @@ char* myoptarg = NULL; #endif /* NO_MAIN_DRIVER */ #else -int main() +int main(void) { printf("NO_WOLFSSH_CLIENT macro used, wolfSSH client not compiled in.\n"); return -1; diff --git a/examples/scpclient/scpclient.c b/examples/scpclient/scpclient.c index 0872f30de..1f56393e5 100644 --- a/examples/scpclient/scpclient.c +++ b/examples/scpclient/scpclient.c @@ -387,7 +387,7 @@ char* myoptarg = NULL; #endif /* NO_MAIN_DRIVER */ #else -int main() +int main(void) { printf("wolfSSH built with NO_WOLFSSH_CLIENT\n"); printf("SCP client unavailable\n"); From a90ffbe10c0314381d42d79c95aedcabf4de1277 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Mon, 12 Oct 2026 11:31:26 -0700 Subject: [PATCH 3/4] tests: move AppendBlob() to the shared helpers The agent relay tests call AppendBlob() from the client-only block, but it was defined inside the block that needs both client and server, so --disable-server with the agent enabled failed to compile regress.c. It now sits with the other shared Append helpers. --- tests/regress.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tests/regress.c b/tests/regress.c index d7af9c49a..e4c3b5433 100644 --- a/tests/regress.c +++ b/tests/regress.c @@ -208,6 +208,14 @@ static word32 AppendData(byte* buf, word32 bufSz, word32 idx, return idx; } +/* Callers sit in separate conditional blocks; some builds have none. */ +static WS_MAYBE_UNUSED word32 AppendBlob(byte* buf, word32 bufSz, word32 idx, + const byte* data, word32 dataSz) +{ + idx = AppendUint32(buf, bufSz, idx, dataSz); + return AppendData(buf, bufSz, idx, data, dataSz); +} + /* A string of any bytes, for the names a C string cannot hold. */ static word32 AppendStringSz(byte* buf, word32 bufSz, word32 idx, const char* value, word32 valueSz) @@ -842,13 +850,6 @@ static int ReadStringRef(word32* strSz, const byte** str, return WS_SUCCESS; } -static word32 AppendBlob(byte* buf, word32 bufSz, word32 idx, - const byte* data, word32 dataSz) -{ - idx = AppendUint32(buf, bufSz, idx, dataSz); - return AppendData(buf, bufSz, idx, data, dataSz); -} - static int RegressionClientUserAuth(byte authType, WS_UserAuthData* authData, void* ctx) { From f3e9e10b0eda840beb6658f99ff8cb3676978995 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Mon, 12 Oct 2026 13:59:17 -0700 Subject: [PATCH 4/4] CI: build each side of the library alone os-check now builds and runs make check on --enable-all with --disable-server and with --disable-client, so a server-only call left in a client build, or the reverse, fails in CI. --- .github/workflows/os-check.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/os-check.yml b/.github/workflows/os-check.yml index 9d39e60d5..41e4c918c 100644 --- a/.github/workflows/os-check.yml +++ b/.github/workflows/os-check.yml @@ -73,6 +73,8 @@ jobs: '--enable-all', '--enable-all CFLAGS=-DWOLFSSH_LOCAL_PREAD_PWRITE', '--enable-all --enable-ossh-certs', + '--enable-all --disable-server', + '--enable-all --disable-client', '--enable-sftp', '--enable-sftp --disable-sftp-zeroize', '--enable-scp',