diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c index cbf2662b4..b5cb75da4 100644 --- a/examples/echoserver/echoserver.c +++ b/examples/echoserver/echoserver.c @@ -383,6 +383,7 @@ static int wolfSSH_AGENT_DefaultActions(WS_AgentCbAction action, void* vCtx) if (action == WOLFSSH_AGENT_LOCAL_SETUP) { struct sockaddr_un* name = &ctx->name; size_t size; + int envSet = 0, nameBound = 0; WMEMSET(name, 0, sizeof(struct sockaddr_un)); ctx->pid = getpid(); @@ -390,15 +391,16 @@ static int wolfSSH_AGENT_DefaultActions(WS_AgentCbAction action, void* vCtx) ret = snprintf(name->sun_path, sizeof(name->sun_path), "/tmp/wolfserver.%d", ctx->pid); + if (ret >= 0) { + name->sun_path[sizeof(name->sun_path) - 1] = '\0'; + size = WSTRLEN(name->sun_path); + ret = (size < WSTRLEN("/tmp/wolfserver.")); + } if (ret == 0) { - name->sun_path[sizeof(name->sun_path) - 1] = '\0'; - size = WSTRLEN(name->sun_path) + - offsetof(struct sockaddr_un, sun_path); + size += offsetof(struct sockaddr_un, sun_path); ctx->listenFd = socket(AF_UNIX, SOCK_STREAM, 0); - if (ctx->listenFd == -1) { - ret = -1; - } + ret = (ctx->listenFd == -1) ? -1 : 0; } if (ret == 0) { @@ -407,10 +409,12 @@ static int wolfSSH_AGENT_DefaultActions(WS_AgentCbAction action, void* vCtx) } if (ret == 0) { + nameBound = 1; ret = setenv(EnvNameAuthPort, name->sun_path, 1); } if (ret == 0) { + envSet = 1; ret = listen(ctx->listenFd, 5); } @@ -418,6 +422,16 @@ static int wolfSSH_AGENT_DefaultActions(WS_AgentCbAction action, void* vCtx) ctx->state = AGENT_STATE_LISTEN; } else { + if (nameBound) { + unlink(ctx->name.sun_path); + } + if (envSet) { + unsetenv(EnvNameAuthPort); + } + if (ctx->listenFd >= 0) { + close(ctx->listenFd); + ctx->listenFd = -1; + } ret = WS_AGENT_SETUP_E; } } @@ -1510,7 +1524,7 @@ static THREAD_RETURN WOLFSSH_THREAD server_worker(void* vArgs) if (!threadCtx->nonBlock) { ret = wolfSSH_accept(threadCtx->ssh); if (wolfSSH_get_error(threadCtx->ssh) == WS_AUTH_PENDING) { - printf("Auth pending error, use -N for non blocking\n"); + printf("Auth pending error, use -N for non-blocking\n"); printf("Trying to close down the connection\n"); } } @@ -2749,7 +2763,7 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) #ifdef WOLFSSH_TEST_BLOCK if (!nonBlock) { - ES_ERROR("Use -N when testing forced non blocking"); + ES_ERROR("Use -N when testing forced non-blocking\n"); } #endif diff --git a/examples/portfwd/portfwd.c b/examples/portfwd/portfwd.c index 723d1ba2c..8b8a94d93 100644 --- a/examples/portfwd/portfwd.c +++ b/examples/portfwd/portfwd.c @@ -235,6 +235,7 @@ THREAD_RETURN WOLFSSH_THREAD portfwd_worker(void* args) const char* fwdToHost = NULL; const char* username = NULL; const char* password = NULL; + const char* readyFile = NULL; SOCKADDR_IN_T hostAddr; socklen_t hostAddrSz = sizeof(hostAddr); SOCKET_T sshFd; @@ -266,7 +267,7 @@ THREAD_RETURN WOLFSSH_THREAD portfwd_worker(void* args) ((func_args*)args)->return_code = 0; - while ((ch = mygetopt(argc, argv, "?f:h:p:t:u:F:P:T:")) != -1) { + while ((ch = mygetopt(argc, argv, "?f:h:p:t:u:F:P:R:T:")) != -1) { switch (ch) { case 'h': host = myoptarg; @@ -306,6 +307,10 @@ THREAD_RETURN WOLFSSH_THREAD portfwd_worker(void* args) password = myoptarg; break; + case 'R': + readyFile = myoptarg; + break; + case 'T': fwdToHost = myoptarg; break; @@ -404,6 +409,25 @@ THREAD_RETURN WOLFSSH_THREAD portfwd_worker(void* args) if (ret != WS_SUCCESS) err_sys("Couldn't connect SFTP"); + if (readyFile != NULL) { + #ifndef NO_FILESYSTEM + WFILE* f = NULL; + ret = WFOPEN(NULL, &f, readyFile, "w"); + if (f != NULL && ret == 0) { + char portStr[10]; + int l; + + l = WSNPRINTF(portStr, sizeof(portStr), "%d\n", (int)fwdFromPort); + if (l > 0) { + WFWRITE(NULL, portStr, MIN((size_t)l, sizeof(portStr)), 1, f); + WFCLOSE(NULL, f); + } + } + #else + err_sys("cannot create readyFile with no file system.\r\n"); + #endif + } + FD_ZERO(&templateFds); FD_SET(sshFd, &templateFds); FD_SET(listenFd, &templateFds); diff --git a/scripts/fwd.test b/scripts/fwd.test new file mode 100755 index 000000000..26034eb6e --- /dev/null +++ b/scripts/fwd.test @@ -0,0 +1,49 @@ +#!/usr/bin/env sh + +# Prerequisite checking + +if [ ! -x "$(which expect)" ] +then + echo "skipping: missing expect" + exit 77 +fi + +if [ ! -x ./scripts/fwd.test.expect ] +then + echo "fail: missing expect script" + exit 1 +fi + +if [ ! -x "$(which nc)" ] +then + echo "skipping: missing netcat" + exit 77 +fi + +## libtool can leave behind a script that runs the actual executable. +if [ ! -x ./examples/echoserver/echoserver ] || \ + ./examples/echoserver/echoserver "-?" 2>&1 | grep -q "does not exist" +then + echo "fail: missing echoserver" + exit 1 +fi + +## libtool can leave behind a script that runs the actual executable. +if [ ! -x ./examples/portfwd/portfwd ] || \ + ./examples/portfwd/portfwd "-?" 2>&1 | grep -q "does not exist" +then + echo "skipping: missing forwarding" + exit 77 +fi + +## test for nonblocking only +if ./examples/client/client "-?" 2>&1 | grep WOLFSSH_TEST_BLOCK >/dev/null 2>&1 +then + echo "skipping: non-blocking test" + exit 77 +fi + + +# Run the expect script + +./scripts/fwd.test.expect diff --git a/scripts/fwd.test.expect b/scripts/fwd.test.expect new file mode 100755 index 000000000..fdb5383e1 --- /dev/null +++ b/scripts/fwd.test.expect @@ -0,0 +1,154 @@ +#!/usr/bin/env expect -f +# +# SSH Tunnel Test Script +# +# Tests an SSH tunnel using wolfSSH and netcat (nc). +# +# Architecture: +# +# [nc client] --plain--> :12345 [wolfssh client] +# | +# SSH +# | +# [wolfssh server] :ephem --plain--> :11111 [nc server] +# +# The nc client sends each line of a Lorem Ipsum paragraph through the tunnel +# to the nc server one at a time. The server echoes each line back. Both sides +# verify receipt of every line. +# +# Ports used: +# 11111 - nc server (plain text backend) +# 12345 - wolfssh client listener (plain text, nc connects here) +# 22222 - wolfSSH rendezvous (SSH, internal use only) +# +# Requirements: nc (netcat), expect + +set timeout 30 + +set lorem_lines { + {Lorem ipsum dolor sit amet, consectetur adipiscing elit,} + {sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.} + {Ut enim ad minim veniam, quis nostrud exercitation ullamco} + {laboris nisi ut aliquip ex ea commodo consequat.} + {Duis aute irure dolor in reprehenderit in voluptate velit esse} + {cillum dolore eu fugiat nulla pariatur.} + {Excepteur sint occaecat cupidatat non proident, sunt in culpa qui} + {officia deserunt mollit anim id est laborum.} +} + +# PIDs for cleanup +set nc_server_pid "" +set wolfssh_srv_pid "" +set wolfssh_clt_pid "" +set nc_client_pid "" + +# --- Cleanup ----------------------------------------------------------------- +proc cleanup {} { + global nc_client_pid wolfssh_clt_pid wolfssh_srv_pid nc_server_pid + + puts "\n--- Cleaning up ---" + foreach pid [list $nc_client_pid $wolfssh_clt_pid $wolfssh_srv_pid $nc_server_pid] { + if {$pid ne ""} { + catch {exec kill $pid} + } + } + puts "Done." +} + +# --- Fail helper ------------------------------------------------------------- +proc fail {msg} { + puts "\n\[FAIL\] $msg" + cleanup + exit 1 +} + +# --- Check prerequisites ----------------------------------------------------- +foreach tool {nc} { + if {[catch {exec which $tool}]} { + puts "ERROR: '$tool' not found in PATH" + exit 1 + } +} + +# --- [1] Start nc server ----------------------------------------------------- +puts "\n\[1\] Starting nc server: nc -l 11111" +spawn nc -l 11111 +set nc_server_id $spawn_id +set nc_server_pid [exp_pid] +puts " PID $nc_server_pid — waiting for a connection..." + +# --- [2] Start wolfssh server ------------------------------------------------ +puts "\n\[2\] Starting wolfssh server..." +spawn ./examples/echoserver/echoserver -1 -f +set wolfssh_srv_id $spawn_id +set wolfssh_srv_pid [exp_pid] +puts " PID $wolfssh_srv_pid — waiting for a connection..." + +# --- [3] Start wolfssh client ------------------------------------------------ +puts "\n\[3\] Starting wolfssh client (plain:12345 -> 11111)..." +spawn ./examples/portfwd/portfwd -u jill -P upthehill -f 12345 -t 11111 +set wolfssh_clt_id $spawn_id +set wolfssh_clt_pid [exp_pid] + +expect { + -i $wolfssh_clt_id + -re {sampled} { + puts " wolfssh client ready (PID $wolfssh_clt_pid)." + } + -re {(?i)(error|fatal)} { + fail "wolfssh client failed to start" + } + timeout { + fail "Timed out waiting for wolfssh client to start" + } +} + +# Brief pause to let the wolfssh tunnels fully bind their listening ports +sleep 1 + +# --- [4] Start nc client ----------------------------------------------------- +puts "\n\[4\] Starting nc client: nc localhost 12345" +spawn nc localhost 12345 +set nc_client_id $spawn_id +set nc_client_pid [exp_pid] +puts " PID $nc_client_pid" + +# Allow the TCP handshake and SSH negotiation to complete +sleep 1 + +# --- [5] Send each line, verify receipt, echo back, verify echo -------------- +set n [llength $lorem_lines] +set i 0 +foreach line $lorem_lines { + incr i + puts "\n\[5.$i/$n\] Client sending: \"$line\"" + send -i $nc_client_id "$line\n" + + expect { + -i $nc_server_id + -ex $line { + puts " \[PASS\] Server received line $i." + } + timeout { + fail "Server did not receive line $i within ${timeout}s" + } + } + + send -i $nc_server_id "$line\n" + + expect { + -i $nc_client_id + -ex $line { + puts " \[PASS\] Client received echo of line $i." + } + timeout { + fail "Client did not receive echo of line $i within ${timeout}s" + } + } +} + +# --- Done -------------------------------------------------------------------- +puts "\n=== TEST PASSED ===\n" + +cleanup +exit 0 diff --git a/scripts/include.am b/scripts/include.am index 02f4d943f..2f7693625 100644 --- a/scripts/include.am +++ b/scripts/include.am @@ -11,4 +11,5 @@ if BUILD_SCP dist_noinst_SCRIPTS+= scripts/scp.test endif -dist_noinst_SCRIPTS+= scripts/external.test +dist_noinst_SCRIPTS+= scripts/external.test scripts/fwd.test +EXTRA_DIST += scripts/fwd.test.expect diff --git a/src/agent.c b/src/agent.c index 5cc160d64..dd5bb8782 100644 --- a/src/agent.c +++ b/src/agent.c @@ -374,6 +374,7 @@ static int PostLock(WOLFSSH_AGENT_CTX* agent, word32 ppSz; WLOG(WS_LOG_AGENT, "Posting lock to agent %p", agent); + WOLFSSH_UNUSED(agent); ppSz = sizeof(pp) - 1; if (passphraseSz < ppSz) @@ -395,6 +396,7 @@ static int PostUnlock(WOLFSSH_AGENT_CTX* agent, word32 ppSz; WLOG(WS_LOG_AGENT, "Posting unlock to agent %p", agent); + WOLFSSH_UNUSED(agent); ppSz = sizeof(pp) - 1; if (passphraseSz < ppSz) diff --git a/src/ssh.c b/src/ssh.c index 1506987e0..afebd0ae0 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -2607,7 +2607,7 @@ int wolfSSH_worker(WOLFSSH* ssh, word32* channelId) } #endif /* WOLFSSH_TEST_BLOCK */ - if (ret == WS_SUCCESS) { + if (ret == WS_SUCCESS || ret == WS_CHAN_RXD) { if (channelId != NULL) { *channelId = ssh->lastRxId; }