From a42075d823dcfd66be418f331c5bf4da0bf48717 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Fri, 31 Aug 2018 11:16:28 -0700 Subject: [PATCH] TCP/IP Forwarding 1. Removed some unused macros in the configure.ac script. 2. Added option for enabling TCP/IP Forwarding. 3. Coalesced the option enable checks to one location in the configure script. 4. Removed redundant compile flags from the wolfSSH automake include. 5. Added a check of the BUILD_SCP option to leave out the wolfcsp file as needed. 6. Removed the redundant debug flags from the ax_harden macro since we add them at the configure level. 7. Modified the ax_harden macro to add the flags to AM_CFLAGS rather than CFLAGS. 8. Removed redundant AM_CFLAGS from the include.am that are adding them to their build's CFLAGS. 9. Replaced the have-wolfssl macro with AC_CHECK_LIB. 10. When adding per-target CPPFLAGS, add the AM_CPPFLAGS back in. 11. remove redundant call to wolfSSH_Init() from echoserver 12. Add runtime configuration of the session window size and max packet size. 13. Parse the TCP/IP direct connect flavor of the Channel Open message. 14. Save and release the host and origin addresses. 15. Added an example forwarding tool. 16. Move and rename the FIND_SELF and FIND_PEER constants. 17. Add planned functions ChannelSend, ChannelRead, ChannelExit, worker. 18. Add new function ChannelNext, which returns the next channel in the list. 19. Changed SendBuffered() from static to local so it could be used by the worker. 20. Separated creating a channel and sending an channel open request. 21. Added status code for pending open channel and for received data. --- .gitignore | 1 + configure.ac | 47 ++-- examples/echoserver/echoserver.c | 2 - examples/include.am | 1 + examples/wolffwd/include.am | 12 + examples/wolffwd/wolffwd.c | 439 +++++++++++++++++++++++++++++++ examples/wolffwd/wolffwd.h | 8 + m4/ax_harden_compiler_flags.m4 | 10 +- m4/have_wolfssl.m4 | 57 ---- src/include.am | 17 +- src/internal.c | 398 +++++++++++++++++++++++----- src/ssh.c | 355 ++++++++++++++++++++++++- tests/include.am | 12 +- wolfssh/error.h | 5 +- wolfssh/internal.h | 29 +- wolfssh/ssh.h | 28 ++ 16 files changed, 1240 insertions(+), 181 deletions(-) create mode 100644 examples/wolffwd/include.am create mode 100644 examples/wolffwd/wolffwd.c create mode 100644 examples/wolffwd/wolffwd.h delete mode 100644 m4/have_wolfssl.m4 diff --git a/.gitignore b/.gitignore index a3a0872..c8800fb 100644 --- a/.gitignore +++ b/.gitignore @@ -51,6 +51,7 @@ diff examples/client/client examples/echoserver/echoserver examples/server/server +examples/wolffwd/wolffwd wolfsftp/client/wolfsftp # test output diff --git a/configure.ac b/configure.ac index 5064b39..fb77ddc 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ AC_ARG_PROGRAM AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_HEADERS([src/config.h]) -WOLFSSH_LIBRARY_VERSION=4:0:3 +WOLFSSH_LIBRARY_VERSION=5:0:1 # | | | # +------+ | +---+ # | | | @@ -56,12 +56,7 @@ AC_CHECK_SIZEOF([long]) # Check headers/libs AC_CHECK_FUNCS([gethostbyname getaddrinfo gettimeofday inet_ntoa memset socket]) AC_CHECK_LIB([network],[socket]) - -# Requirements -TAO_REQUIRE_LIBWOLFSSL - -# since we have autoconf available, we can use cyassl options header -AM_CPPFLAGS="$AM_CPPFLAGS -DHAVE_CYASSL_OPTIONS" +AC_CHECK_LIB([wolfssl],[wolfCrypt_Init],,[AC_MSG_ERROR([libwolfssl is required for ${PACKAGE}, It can be obtained from https://www.wolfssl.com/download.html/])]) # DEBUG DEBUG_CFLAGS="-g -O0" @@ -81,10 +76,9 @@ AX_PTHREAD([ AS_CASE([$PTHREAD_CFLAGS],[-Qunused-arguments*],[PTHREAD_CFLAGS="-Xcompiler $PTHREAD_CFLAGS"]) AM_CFLAGS="$AM_CFLAGS $PTHREAD_CFLAGS"]) - # Inline Build AC_ARG_ENABLE([inline], - [AS_HELP_STRING([--enable-inline],[Enable inline functions (default: enabled)])], + [AS_HELP_STRING([--disable-inline],[Enable inline functions (default: enabled)])], [ENABLED_INLINE=$enableval],[ENABLED_INLINE=yes]) if test "$ENABLED_INLINE" = "no" @@ -99,31 +93,37 @@ AC_ARG_ENABLE([keygen], [AS_HELP_STRING([--enable-keygen],[Enable key generation (default: disabled)])], [ENABLED_KEYGEN=$enableval],[ENABLED_KEYGEN=no]) -AS_IF([test "x$ENABLED_KEYGEN" = "xyes"], - [AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSH_KEYGEN"]) - -AM_CONDITIONAL([BUILD_KEYGEN], [test "x$ENABLED_KEYGEN" = "xyes"]) - # SCP AC_ARG_ENABLE([scp], [AS_HELP_STRING([--enable-scp],[Enable scp support (default: disabled)])], [ENABLED_SCP=$enableval],[ENABLED_SCP=no]) -AS_IF([test "x$ENABLED_SCP" = "xyes"], - [AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSH_SCP"]) - -AM_CONDITIONAL([BUILD_SCP], [test "x$ENABLED_SCP" = "xyes"]) - # SFTP AC_ARG_ENABLE([sftp], [AS_HELP_STRING([--enable-sftp],[Enable SFTP support (default: disabled)])], [ENABLED_SFTP=$enableval],[ENABLED_SFTP=no]) +# TCP/IP Forwarding +AC_ARG_ENABLE([fwd], + [AS_HELP_STRING([--enable-fwd],[Enable TCP/IP Forwarding support (default: disabled)])], + [ENABLED_FWD=$enableval],[ENABLED_FWD=no]) + +AS_IF([test "x$ENABLED_INLINE" = "xno"], + [AM_CPPFLAGS="$AM_CPPFLAGS -DNO_INLINE"]) +AS_IF([test "x$ENABLED_KEYGEN" = "xyes"], + [AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSH_KEYGEN"]) +AS_IF([test "x$ENABLED_SCP" = "xyes"], + [AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSH_SCP"]) AS_IF([test "x$ENABLED_SFTP" = "xyes"], [AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSH_SFTP"]) +AS_IF([test "x$ENABLED_FWD" = "xyes"], + [AM_CPPFLAGS="$AM_CPPFLAGS -DWOLFSSH_FWD"]) -AM_CONDITIONAL([BUILD_SFTP], [test "x$ENABLED_SFTP" = "xyes"]) - +AM_CONDITIONAL([BUILD_INLINE],[test "x$ENABLED_INLINE" = "xyes"]) +AM_CONDITIONAL([BUILD_KEYGEN],[test "x$ENABLED_KEYGEN" = "xyes"]) +AM_CONDITIONAL([BUILD_SCP],[test "x$ENABLED_SCP" = "xyes"]) +AM_CONDITIONAL([BUILD_SFTP],[test "x$ENABLED_SFTP" = "xyes"]) +AM_CONDITIONAL([BUILD_FWD],[test "x$ENABLED_FWD" = "xyes"]) # Checks for typedefs, structures, and compiler characteristics. if test "$ac_cv_sizeof_long" = "8"; then @@ -154,7 +154,6 @@ AC_OUTPUT echo "---" echo "Running make clean..." make clean >/dev/null 2>&1 -echo # output config summary echo "---" @@ -167,10 +166,10 @@ echo " * C Compiler: $CC" echo " * C Flags: $CFLAGS" echo " * CPP Flags: $CPPFLAGS" echo " * Linker Flags: $LDFLAGS" -echo " * LIB Flags: $LIB" echo -echo " Features " +echo " Features" echo " * keygen: $ENABLED_KEYGEN" echo " * scp: $ENABLED_SCP" echo " * sftp: $ENABLED_SFTP" +echo " * TCP/IP Forwarding: $ENABLED_FWD" diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c index 9966054..1bd6108 100644 --- a/examples/echoserver/echoserver.c +++ b/examples/echoserver/echoserver.c @@ -827,8 +827,6 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) wolfSSH_Debugging_ON(); #endif - wolfSSH_Init(); - #ifndef WOLFSSL_NUCLEUS ChangeToWolfSshRoot(); #endif diff --git a/examples/include.am b/examples/include.am index e79244e..d50e919 100644 --- a/examples/include.am +++ b/examples/include.am @@ -5,3 +5,4 @@ include examples/client/include.am include examples/server/include.am include examples/echoserver/include.am +include examples/wolffwd/include.am diff --git a/examples/wolffwd/include.am b/examples/wolffwd/include.am new file mode 100644 index 0000000..504b5de --- /dev/null +++ b/examples/wolffwd/include.am @@ -0,0 +1,12 @@ +# vim:ft=automake +# All paths should be given relative to the root + +if BUILD_FWD +noinst_PROGRAMS += examples/wolffwd/wolffwd +noinst_HEADERS += examples/wolffwd/wolffwd.h +examples_wolffwd_wolffwd_SOURCES = examples/wolffwd/wolffwd.c +examples_wolffwd_wolffwd_LDADD = src/libwolfssh.la +examples_wolffwd_wolffwd_DEPENDENCIES = src/libwolfssh.la +endif + +DISTCLEANFILES+= examples/wolffwd/.libs/wolffwd diff --git a/examples/wolffwd/wolffwd.c b/examples/wolffwd/wolffwd.c new file mode 100644 index 0000000..488ca1e --- /dev/null +++ b/examples/wolffwd/wolffwd.c @@ -0,0 +1,439 @@ +#include +#include +#include +#include +#include +#include +#include +#include "examples/wolffwd/wolffwd.h" + + +/* The wolffwd tool will be a client or server in the port forwarding + * interaction. + * + * The wolffwd client will connect to an SSH server and request a tunnel. + * The client acts like a server for the local user application. It forwards + * the packets received to the SSH server who will then forward the packet + * to its local application server. + * + * The wolffwd server will listen for SSH connections, and when it receives + * one will only accept forward requests from the connection. All data for + * the forwarding channel are sent to the local application server and + * data from the server is forwarded to the client. + */ + + +static inline int max(int a, int b) +{ + return (a > b) ? a : b; +} + +static void ShowUsage(void) +{ + printf("wolffwd %s\n" + " -? display this help and exit\n" + " -h host to connect to, default %s\n" + " -p port to connect on, default %u\n" + " -u username to authenticate as (REQUIRED)\n" + " -P password for username, prompted if omitted\n" + " -F host to forward from, default 0.0.0.0\n" + " -f host port to forward from (REQUIRED)\n" + " -T host to forward to, default to host\n" + " -t port to forward to (REQUIRED)\n" + " -d server mode\n", + LIBWOLFSSH_VERSION_STRING, wolfSshIp, wolfSshPort); +} + + +static int SetEcho(int on) +{ +#ifndef USE_WINDOWS_API + static int echoInit = 0; + static struct termios originalTerm; + if (!echoInit) { + if (tcgetattr(STDIN_FILENO, &originalTerm) != 0) { + printf("Couldn't get the original terminal settings.\n"); + return -1; + } + echoInit = 1; + } + if (on) { + if (tcsetattr(STDIN_FILENO, TCSANOW, &originalTerm) != 0) { + printf("Couldn't restore the terminal settings.\n"); + return -1; + } + } + else { + struct termios newTerm; + memcpy(&newTerm, &originalTerm, sizeof(struct termios)); + + newTerm.c_lflag &= ~ECHO; + newTerm.c_lflag |= (ICANON | ECHONL); + + if (tcsetattr(STDIN_FILENO, TCSANOW, &newTerm) != 0) { + printf("Couldn't turn off echo.\n"); + return -1; + } + } +#else + static int echoInit = 0; + static DWORD originalTerm; + HANDLE stdinHandle = GetStdHandle(STD_INPUT_HANDLE); + if (!echoInit) { + if (GetConsoleMode(stdinHandle, &originalTerm) == 0) { + printf("Couldn't get the original terminal settings.\n"); + return -1; + } + echoInit = 1; + } + if (on) { + if (SetConsoleMode(stdinHandle, originalTerm) == 0) { + printf("Couldn't restore the terminal settings.\n"); + return -1; + } + } + else { + DWORD newTerm = originalTerm; + + newTerm &= ~ENABLE_ECHO_INPUT; + + if (SetConsoleMode(stdinHandle, newTerm) == 0) { + printf("Couldn't turn off echo.\n"); + return -1; + } + } +#endif + + return 0; +} + + +byte userPassword[256]; + + +static int wsUserAuth(byte authType, + WS_UserAuthData* authData, + void* ctx) +{ + const char* defaultPassword = (const char*)ctx; + word32 passwordSz; + int ret = WOLFSSH_USERAUTH_SUCCESS; + + (void)authType; + if (defaultPassword != NULL) { + passwordSz = (word32)strlen(defaultPassword); + memcpy(userPassword, defaultPassword, passwordSz); + } + else { + printf("Password: "); + SetEcho(0); + if (WFGETS((char*)userPassword, sizeof(userPassword), stdin) == NULL) { + printf("Getting password failed.\n"); + ret = WOLFSSH_USERAUTH_FAILURE; + } + else { + char* c = strpbrk((char*)userPassword, "\r\n");; + if (c != NULL) + *c = '\0'; + passwordSz = (word32)strlen((const char*)userPassword); + } + SetEcho(1); +#ifdef USE_WINDOWS_API + printf("\r\n"); +#endif + } + + if (ret == WOLFSSH_USERAUTH_SUCCESS) { + authData->sf.password.password = userPassword; + authData->sf.password.passwordSz = passwordSz; + } + + return ret; +} + + +#define INVALID_FWD_PORT 0 +static const char defaultFwdFromHost[] = "0.0.0.0"; + +/* + * fwdFromHost - address to bind the local listener socket to (default: any) + * fwdFromHostPort - port number to bind the local listener socket to + * fwdToHost - address to tell the remote peer to connect to on behalf of the + * client (actual server address) + * fwdToHostPort - port number to tell the remote peer to connect to on behalf + * of the client (actual server port) + * host - peer SSH server address to connect to + * hostPort - peer SSH server port number to connect to + */ + +THREAD_RETURN WOLFSSH_THREAD wolffwd_worker(void* args) +{ + WOLFSSH* ssh; + WOLFSSH_CTX* ctx; + char* host = (char*)wolfSshIp; + word16 port = wolfSshPort; + word16 fwdFromPort = INVALID_FWD_PORT; + word16 fwdToPort = INVALID_FWD_PORT; + const char* fwdFromHost = defaultFwdFromHost; + const char* fwdToHost = NULL; + const char* username = NULL; + const char* password = NULL; + SOCKADDR_IN_T hostAddr; + socklen_t hostAddrSz = sizeof(hostAddr); + SOCKET_T sshFd; + SOCKADDR_IN_T fwdFromHostAddr; + socklen_t fwdFromHostAddrSz = sizeof(fwdFromHostAddr); + SOCKET_T listenFd; + SOCKET_T appFd; + int argc = ((func_args*)args)->argc; + char** argv = ((func_args*)args)->argv; + int serverMode = 0; + fd_set templateFds; + fd_set rxFds; + fd_set errFds; + int nFds; + int ret; + char ch; + int done = 0; + int appFdSet = 0; + struct timeval to; + WOLFSSH_CHANNEL* fwdChannel = NULL; + byte buffer[4096]; + word32 bufferSz = sizeof(buffer); + word32 bufferUsed = 0; + + ((func_args*)args)->return_code = 0; + + while ((ch = mygetopt(argc, argv, "?df:h:p:t:u:F:P:T:")) != -1) { + switch (ch) { + case 'd': + serverMode = 1; + break; + + case 'h': + host = myoptarg; + break; + + case 'f': + fwdFromPort = (word16)atoi(myoptarg); + break; + + case 'p': + port = (word16)atoi(myoptarg); + #if !defined(NO_MAIN_DRIVER) || defined(USE_WINDOWS_API) + if (port == 0) + err_sys("port number cannot be 0"); + #endif + break; + + case 't': + fwdToPort = (word16)atoi(myoptarg); + break; + + case 'u': + username = myoptarg; + break; + + case 'F': + fwdFromHost = myoptarg; + break; + + case 'P': + password = myoptarg; + break; + + case 'T': + fwdToHost = myoptarg; + break; + + case '?': + ShowUsage(); + exit(EXIT_SUCCESS); + + default: + ShowUsage(); + exit(MY_EX_USAGE); + } + } + myoptind = 0; + + if (username == NULL) + err_sys("client requires a username parameter."); + if (fwdToPort == INVALID_FWD_PORT) + err_sys("requires a port to forward to"); + if (fwdFromPort == INVALID_FWD_PORT) + err_sys("requires a port to forward from"); + + if (fwdToHost == NULL) + fwdToHost = host; + + printf("wolffwd options\n" + " * ssh host: %s:%u\n" + " * username: %s\n" + " * password: %s\n" + " * forward from: %s:%u\n" + " * forward to: %s:%u\n" + " * server mode: %s\n", + host, port, username, password, + fwdFromHost, fwdFromPort, + fwdToHost, fwdToPort, + serverMode ? "yes" : "no"); + + ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_CLIENT, NULL); + if (ctx == NULL) + err_sys("couldn't create the ssh client"); + + if (((func_args*)args)->user_auth == NULL) + wolfSSH_SetUserAuth(ctx, wsUserAuth); + else + wolfSSH_SetUserAuth(ctx, ((func_args*)args)->user_auth); + + ssh = wolfSSH_new(ctx); + if (ssh == NULL) + err_sys("Couldn't create wolfSSH session."); + + if (password != NULL) + wolfSSH_SetUserAuthCtx(ssh, (void*)password); + + ret = wolfSSH_SetUsername(ssh, username); + if (ret != WS_SUCCESS) + err_sys("Couldn't set the username."); + + build_addr(&hostAddr, host, port); + build_addr(&fwdFromHostAddr, fwdFromHost, fwdFromPort); + + tcp_socket(&sshFd); /* Socket to SSH peer. */ + tcp_socket(&listenFd); /* Either receive from client application or connect + to server application. */ + tcp_listen(&listenFd, &fwdFromPort, 1); + + printf("Connecting to the SSH server...\n"); + ret = connect(sshFd, (const struct sockaddr *)&hostAddr, hostAddrSz); + if (ret != 0) + err_sys("Couldn't connect to server."); + + ret = wolfSSH_set_fd(ssh, (int)sshFd); + if (ret != WS_SUCCESS) + err_sys("Couldn't set the session's socket."); + + ret = wolfSSH_connect(ssh); + if (ret != WS_SUCCESS) + err_sys("Couldn't connect SFTP"); + + FD_ZERO(&templateFds); + FD_SET(sshFd, &templateFds); + FD_SET(listenFd, &templateFds); + nFds = max(sshFd, listenFd) + 1; + + printf("Entering the run loop...\n"); + while (!done) { + FD_COPY(&templateFds, &rxFds); + to.tv_sec = 1; + to.tv_usec = 0; + ret = select(nFds, &rxFds, NULL, &errFds, &to); + if (ret == 0) { + printf("select timed out\n"); + ret = wolfSSH_SendIgnore(ssh, NULL, 0); + if (ret != WS_SUCCESS) + printf("Couldn't send an ignore message.\n"); + continue; + } + else if (ret < 0) { + printf("select failed\n"); + break; + } + else + printf("select returned something: %d\n", ret); + + if (appFdSet && FD_ISSET(appFd, &rxFds)) { + int rxd; + printf("application packet received\n"); + rxd = (int)recv(appFd, buffer + bufferUsed, bufferSz - bufferUsed, 0); + if (rxd > 0) + bufferUsed += rxd; + else + break; + } + if (FD_ISSET(sshFd, &rxFds)) { + word32 channelId = 0; + + ret = wolfSSH_worker(ssh, &channelId); + if (ret == WS_CHAN_RXD) { + WOLFSSH_CHANNEL* readChannel; + + bufferSz = sizeof(buffer); + readChannel = wolfSSH_ChannelFind(ssh, + channelId, WS_CHANNEL_ID_SELF); + ret = (readChannel == NULL) ? WS_INVALID_CHANID : WS_SUCCESS; + + if (ret == WS_SUCCESS) + ret = wolfSSH_ChannelRead(readChannel, buffer, bufferSz); + if (ret > 0) { + bufferSz = (word32)ret; + ret = (int)send(appFd, buffer, bufferSz, 0); + } + ret = (ret != (int)bufferSz) ? -1 : WS_SUCCESS; + } + } + if (!appFdSet && FD_ISSET(listenFd, &rxFds)) { + appFd = accept(listenFd, + (struct sockaddr*)&fwdFromHostAddr, &fwdFromHostAddrSz); + FD_SET(appFd, &templateFds); + nFds = appFd + 1; + appFdSet = 1; + fwdChannel = wolfSSH_ChannelFwdNew(ssh, fwdToHost, fwdToPort, + fwdFromHost, fwdFromPort); + } + if (bufferUsed > 0) { + ret = wolfSSH_ChannelSend(fwdChannel, buffer, bufferUsed); + if (ret > 0) + bufferUsed -= ret; + } + } + + ret = wolfSSH_shutdown(ssh); + if (ret != WS_SUCCESS) + err_sys("Closing stream failed."); + + WCLOSESOCKET(sshFd); + WCLOSESOCKET(listenFd); + WCLOSESOCKET(appFd); + wolfSSH_free(ssh); + wolfSSH_CTX_free(ctx); + + return 0; +} + + +#ifndef NO_MAIN_DRIVER + +int main(int argc, char** argv) +{ + func_args args; + + args.argc = argc; + args.argv = argv; + args.return_code = 0; + args.user_auth = NULL; + + WSTARTTCP(); + + #ifdef DEBUG_WOLFSSH + wolfSSH_Debugging_ON(); + #endif + + wolfSSH_Init(); + + ChangeToWolfSshRoot(); + wolffwd_worker(&args); + + wolfSSH_Cleanup(); + + return args.return_code; +} + +int myoptind = 0; +char* myoptarg = NULL; + + +#endif /* NO_MAIN_DRIVER */ diff --git a/examples/wolffwd/wolffwd.h b/examples/wolffwd/wolffwd.h new file mode 100644 index 0000000..932dd39 --- /dev/null +++ b/examples/wolffwd/wolffwd.h @@ -0,0 +1,8 @@ +#pragma once + +#ifndef _WOLFSSH_CLIENT_H_ +#define _WOLFSSH_CLIENT_H_ + +THREAD_RETURN WOLFSSH_THREAD wolffwd_worker(void* args); + +#endif /* _WOLFSSH_CLIENT_H_ */ diff --git a/m4/ax_harden_compiler_flags.m4 b/m4/ax_harden_compiler_flags.m4 index 92d7d7e..a2067f0 100644 --- a/m4/ax_harden_compiler_flags.m4 +++ b/m4/ax_harden_compiler_flags.m4 @@ -105,10 +105,12 @@ [AX_APPEND_COMPILE_FLAGS([-Werror],[AM_CFLAGS]) ac_cv_warnings_as_errors="yes"]) - AS_IF([test "$ax_enable_debug" = "yes"], - [AX_APPEND_COMPILE_FLAGS([-g],[AM_CFLAGS]) - AX_APPEND_COMPILE_FLAGS([-ggdb],[AM_CFLAGS],[$ax_append_compile_cflags_extra]) - AX_APPEND_COMPILE_FLAGS([-O0],[AM_CFLAGS],[$ax_append_compile_cflags_extra])]) +dnl The main configure script handles setting the debugging flags. +dnl AS_IF([test "$ax_enable_debug" = "yes"], [ +dnl AX_APPEND_COMPILE_FLAGS([-g],[AM_CFLAGS]) +dnl AX_APPEND_COMPILE_FLAGS([-ggdb],[AM_CFLAGS],[$ax_append_compile_cflags_extra]) +dnl AX_APPEND_COMPILE_FLAGS([-O0],[AM_CFLAGS],[$ax_append_compile_cflags_extra]) +dnl ],[]) AX_APPEND_COMPILE_FLAGS([-Wno-pragmas],[AM_CFLAGS],[$ax_append_compile_cflags_extra]) diff --git a/m4/have_wolfssl.m4 b/m4/have_wolfssl.m4 deleted file mode 100644 index d9c5ae4..0000000 --- a/m4/have_wolfssl.m4 +++ /dev/null @@ -1,57 +0,0 @@ - -#-------------------------------------------------------------------- -# Check for libwolfssl -#-------------------------------------------------------------------- - - -AC_DEFUN([_TAO_SEARCH_LIBWOLFSSL],[ - AC_REQUIRE([AC_LIB_PREFIX]) - - LDFLAGS="$LDFLAGS -L/usr/local/lib" - LIBS="$LIBS -lwolfssl" - - AC_LIB_HAVE_LINKFLAGS(wolfssl,, - [ - #include - ],[ - wolfCrypt_Init(); - ]) - - AM_CONDITIONAL(HAVE_LIBWOLFSSL, [test "x${ac_cv_libwolfssl}" = "xyes"]) - - AS_IF([test "x${ac_cv_libwolfssl}" = "xyes"],[ - save_LIBS="${LIBS}" - LIBS="${LIBS} ${LTLIBWOLFSSL}" - AC_CHECK_FUNCS(wolfSSL_Cleanup) - LIBS="$save_LIBS" - ]) -]) - -AC_DEFUN([_TAO_HAVE_LIBWOLFSSL],[ - - AC_ARG_ENABLE([libwolfssl], - [AS_HELP_STRING([--disable-libwolfssl], - [Build with libwolfssl support @<:@default=on@:>@])], - [ac_enable_libwolfssl="$enableval"], - [ac_enable_libwolfssl="yes"]) - - _TAO_SEARCH_LIBWOLFSSL -]) - - -AC_DEFUN([TAO_HAVE_LIBWOLFSSL],[ - AC_REQUIRE([_TAO_HAVE_LIBWOLFSSL]) -]) - -AC_DEFUN([_TAO_REQUIRE_LIBWOLFSSL],[ - ac_enable_libwolfssl="yes" - _TAO_SEARCH_LIBWOLFSSL - - AS_IF([test x$ac_cv_libwolfssl = xno],[ - AC_MSG_ERROR([libwolfssl is required for ${PACKAGE}, It can be obtained from http://www.wolfssl.com/download.html/]) - ]) -]) - -AC_DEFUN([TAO_REQUIRE_LIBWOLFSSL],[ - AC_REQUIRE([_TAO_REQUIRE_LIBWOLFSSL]) -]) diff --git a/src/include.am b/src/include.am index 270527d..956ee6e 100644 --- a/src/include.am +++ b/src/include.am @@ -2,20 +2,15 @@ # included from Top Level Makefile.am # All paths should be given relative to the root - -lib_LTLIBRARIES+= src/libwolfssh.la +lib_LTLIBRARIES += src/libwolfssh.la src_libwolfssh_la_SOURCES = src/ssh.c \ src/internal.c \ src/memory.c \ src/log.c \ src/io.c \ - src/port.c \ - src/wolfscp.c -src_libwolfssh_la_CFLAGS = -DBUILDING_WOLFSSH $(AM_CFLAGS) -src_libwolfssh_la_CPPFLAGS = -DBUILDING_WOLFSSH $(AM_CPPFLAGS) -src_libwolfssh_la_LDFLAGS = ${AM_LDFLAGS} -no-undefined -version-info ${WOLFSSH_LIBRARY_VERSION} -src_libwolfssh_la_DEPENDENCIES = -EXTRA_DIST += + src/port.c +src_libwolfssh_la_CPPFLAGS = -DBUILDING_WOLFSSH ${AM_CPPFLAGS} +src_libwolfssh_la_LDFLAGS = -no-undefined -version-info ${WOLFSSH_LIBRARY_VERSION} if !BUILD_INLINE src_libwolfssh_la_SOURCES += src/misc.c @@ -25,6 +20,10 @@ if BUILD_KEYGEN src_libwolfssh_la_SOURCES += src/keygen.c endif +if BUILD_SCP +src_libwolfssh_la_SOURCES += src/wolfscp.c +endif + if BUILD_SFTP src_libwolfssh_la_SOURCES += src/wolfsftp.c endif diff --git a/src/internal.c b/src/internal.c index e4fb757..f2693e2 100644 --- a/src/internal.c +++ b/src/internal.c @@ -239,6 +239,15 @@ const char* GetErrorString(int err) case WS_NEXT_ERROR: return "Getting next value/state results in error"; + case WS_CHAN_RXD: + return "Channel data received"; + + case WS_INVALID_EXTDATA: + return "invalid extended data type"; + + case WS_CHAN_PENDING: + return "channel open pending"; + default: return "Unknown error code"; } @@ -363,6 +372,8 @@ WOLFSSH_CTX* CtxInit(WOLFSSH_CTX* ctx, byte side, void* heap) ctx->banner = cannedBanner; ctx->bannerSz = cannedBannerSz; #endif /* DEBUG_WOLFSSH */ + ctx->windowSz = DEFAULT_WINDOW_SZ; + ctx->maxPacketSz = DEFAULT_MAX_PACKET_SZ; return ctx; } @@ -849,7 +860,11 @@ static const NameIdPair NameIdMap[] = { { ID_USERAUTH_PUBLICKEY, "publickey" }, /* Channel Type IDs */ - { ID_CHANTYPE_SESSION, "session" } + { ID_CHANTYPE_SESSION, "session" }, +#ifdef WOLFSSH_FWD + { ID_CHANTYPE_TCPIP_FORWARD, "forwarded-tcpip" }, + { ID_CHANTYPE_TCPIP_DIRECT, "direct-tcpip" }, +#endif /* WOLFSSH_FWD */ }; @@ -908,6 +923,7 @@ WOLFSSH_CHANNEL* ChannelNew(WOLFSSH* ssh, byte channelType, buffer = (byte*)WMALLOC(initialWindowSz, heap, DYNTYPE_BUFFER); if (buffer != NULL) { WMEMSET(newChannel, 0, sizeof(WOLFSSH_CHANNEL)); + newChannel->ssh = ssh; newChannel->channelType = channelType; newChannel->channel = ssh->nextChannel++; newChannel->windowSz = initialWindowSz; @@ -945,6 +961,12 @@ void ChannelDelete(WOLFSSH_CHANNEL* channel, void* heap) (void)heap; if (channel) { + #ifdef WOLFSSH_FWD + if (channel->host) + WFREE(channel->host, heap, DYNTYPE_STRING); + if (channel->origin) + WFREE(channel->origin, heap, DYNTYPE_STRING); + #endif /* WOLFSSH_FWD */ WFREE(channel->inputBuffer.buffer, channel->inputBuffer.heap, DYNTYPE_BUFFER); if (channel->command) @@ -954,9 +976,6 @@ void ChannelDelete(WOLFSSH_CHANNEL* channel, void* heap) } -#define FIND_SELF 0 -#define FIND_PEER 1 - WOLFSSH_CHANNEL* ChannelFind(WOLFSSH* ssh, word32 channel, byte peer) { WOLFSSH_CHANNEL* findChannel = NULL; @@ -972,7 +991,7 @@ WOLFSSH_CHANNEL* ChannelFind(WOLFSSH* ssh, word32 channel, byte peer) word32 listSz = ssh->channelListSz; while (list && listSz) { - if (channel == ((peer == FIND_PEER) ? + if (channel == ((peer == WS_CHANNEL_ID_PEER) ? list->peerChannel : list->channel)) { findChannel = list; break; @@ -988,7 +1007,7 @@ WOLFSSH_CHANNEL* ChannelFind(WOLFSSH* ssh, word32 channel, byte peer) } -int ChannelUpdate(WOLFSSH_CHANNEL* channel, word32 peerChannelId, +int ChannelUpdatePeer(WOLFSSH_CHANNEL* channel, word32 peerChannelId, word32 peerInitialWindowSz, word32 peerMaxPacketSz) { int ret = WS_SUCCESS; @@ -999,13 +1018,49 @@ int ChannelUpdate(WOLFSSH_CHANNEL* channel, word32 peerChannelId, channel->peerChannel = peerChannelId; channel->peerWindowSz = peerInitialWindowSz; channel->peerMaxPacketSz = peerMaxPacketSz; + channel->openConfirmed = 1; } return ret; } -static int ChannelAppend(WOLFSSH* ssh, WOLFSSH_CHANNEL* channel) +#ifdef WOLFSSH_FWD +int ChannelUpdateForward(WOLFSSH_CHANNEL* channel, + const char* host, word32 hostPort, + const char* origin, word32 originPort) +{ + int ret = WS_SUCCESS; + char* hostCopy = NULL; + char* originCopy = NULL; + + if (channel == NULL || host == NULL || origin == NULL) + ret = WS_BAD_ARGUMENT; + else { + void* heap = channel->ssh->ctx->heap; + + hostCopy = (char*)WMALLOC(WSTRLEN(host) + 1, heap, DYNTYPE_STRING); + originCopy = (char*)WMALLOC(WSTRLEN(origin) + 1, heap, DYNTYPE_STRING); + if (hostCopy == NULL || originCopy == NULL) { + WFREE(hostCopy, heap, DYNTYPE_STRING); + WFREE(originCopy, heap, DYNTYPE_STRING); + ret = WS_MEMORY_E; + } + } + + if (ret == WS_SUCCESS) { + channel->host = hostCopy; + channel->hostPort = hostPort; + channel->origin = originCopy; + channel->originPort = originPort; + } + + return ret; +} +#endif /* WOLFSSH_FWD */ + + +int ChannelAppend(WOLFSSH* ssh, WOLFSSH_CHANNEL* channel) { int ret = WS_SUCCESS; @@ -1052,7 +1107,7 @@ int ChannelRemove(WOLFSSH* ssh, word32 channel, byte peer) word32 listSz = ssh->channelListSz; while (list && listSz) { - if (channel == ((peer == FIND_PEER) ? + if (channel == ((peer == WS_CHANNEL_ID_PEER) ? list->peerChannel : list->channel)) { if (prev == NULL) ssh->channelList = list->next; @@ -1287,7 +1342,7 @@ static int GetInputText(WOLFSSH* ssh, byte** pEol) } -static int SendBuffered(WOLFSSH* ssh) +int SendBuffered(WOLFSSH* ssh) { WLOG(WS_LOG_DEBUG, "Entering SendBuffered()"); @@ -2628,7 +2683,7 @@ static int DoKexDhGexGroup(WOLFSSH* ssh, byte* generator = NULL; word32 generatorSz; word32 begin; - int ret = WS_UNIMPLEMENTED_E; + int ret = WS_SUCCESS; if (ssh == NULL || buf == NULL || len == 0 || idx == NULL) ret = WS_BAD_ARGUMENT; @@ -3110,7 +3165,7 @@ static int DoUserAuthRequestEcc(WOLFSSH* ssh, WS_UserAuthData_PublicKey* pk, (void)hashId; - WLOG(WS_LOG_DEBUG, "Entering DoUserAuthRequestRsa()"); + WLOG(WS_LOG_DEBUG, "Entering DoUserAuthRequestEcc()"); if (ssh == NULL || pk == NULL || digest == NULL || digestSz == 0) ret = WS_BAD_ARGUMENT; @@ -3544,6 +3599,19 @@ static int DoGlobalRequest(WOLFSSH* ssh, ret = GetBoolean(&wantReply, buf, len, &begin); } +#ifdef WOLFSSH_FWD + if (ret == WS_SUCCESS) { + if (WSTRNCMP(name, "tcpip-forward", nameSz) == 0) { + fprintf(stderr, "tcpip-forward requested\n"); + fflush(stderr); + } + else if (WSTRNCMP(name, "cancel-tcpip-forward", nameSz) == 0) { + fprintf(stderr, "cancel-tcpip-forward requested\n"); + fflush(stderr); + } + } +#endif /* WOLFSSH_FWD */ + if (ret == WS_SUCCESS) { *idx += len; @@ -3556,23 +3624,81 @@ static int DoGlobalRequest(WOLFSSH* ssh, } +#ifdef WOLFSSH_FWD +static int DoChannelOpenForward(WOLFSSH* ssh, + char** host, word32* hostPort, + char** origin, word32* originPort, + byte* buf, word32 len, word32* idx) +{ + word32 begin; + int ret = WS_SUCCESS; + + WLOG(WS_LOG_DEBUG, "Entering DoChannelOpenForward()"); + + if (idx == NULL) + ret = WS_BAD_ARGUMENT; + + if (ret == WS_SUCCESS) { + begin = *idx; + ret = GetStringAlloc(ssh, host, buf, len, &begin); + } + + if (ret == WS_SUCCESS) + ret = GetUint32(hostPort, buf, len, &begin); + + if (ret == WS_SUCCESS) + ret = GetStringAlloc(ssh, origin, buf, len, &begin); + + if (ret == WS_SUCCESS) + ret = GetUint32(originPort, buf, len, &begin); + + if (ret == WS_SUCCESS) { + *idx = begin; + WLOG(WS_LOG_INFO, " host = %s:%u", *host, *hostPort); + WLOG(WS_LOG_INFO, " origin = %s:%u", *origin, *originPort); + } + else { + *idx += len; + WFREE(*host, ssh->ctx->heap, DYNTYPE_STRING); + WFREE(*origin, ssh->ctx->heap, DYNTYPE_STRING); + *host = NULL; + *origin = NULL; + } + + WLOG(WS_LOG_DEBUG, "Leaving DoChannelOpenForward(), ret = %d", ret); + return ret; +} +#endif /* WOLFSSH_FWD */ + + static int DoChannelOpen(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) { - word32 begin = *idx; + word32 begin; word32 typeSz; char type[32]; byte typeId = ID_UNKNOWN; word32 peerChannelId; word32 peerInitialWindowSz; word32 peerMaxPacketSz; - int ret; +#ifdef WOLFSSH_FWD + char* host = NULL; + char* origin = NULL; + word32 hostPort, originPort; +#endif /* WOLFSSH_FWD */ WOLFSSH_CHANNEL* newChannel; + int ret = WS_SUCCESS; WLOG(WS_LOG_DEBUG, "Entering DoChannelOpen()"); - typeSz = sizeof(type); - ret = GetString(type, &typeSz, buf, len, &begin); + if (idx == NULL) + ret = WS_BAD_ARGUMENT; + + if (ret == WS_SUCCESS) { + begin = *idx; + typeSz = sizeof(type); + ret = GetString(type, &typeSz, buf, len, &begin); + } if (ret == WS_SUCCESS) ret = GetUint32(&peerChannelId, buf, len, &begin); @@ -3584,34 +3710,63 @@ static int DoChannelOpen(WOLFSSH* ssh, ret = GetUint32(&peerMaxPacketSz, buf, len, &begin); if (ret == WS_SUCCESS) { - *idx = begin; - WLOG(WS_LOG_INFO, " type = %s", type); WLOG(WS_LOG_INFO, " peerChannelId = %u", peerChannelId); WLOG(WS_LOG_INFO, " peerInitialWindowSz = %u", peerInitialWindowSz); WLOG(WS_LOG_INFO, " peerMaxPacketSz = %u", peerMaxPacketSz); typeId = NameToId(type, typeSz); - if (typeId != ID_CHANTYPE_SESSION) - ret = WS_INVALID_CHANTYPE; + switch (typeId) { + case ID_CHANTYPE_SESSION: + break; + #ifdef WOLFSSH_FWD + /*case ID_CHANTYPE_TCPIP_FORWARD:*/ + case ID_CHANTYPE_TCPIP_DIRECT: + ret = DoChannelOpenForward(ssh, + &host, &hostPort, &origin, &originPort, + buf, len, &begin); + break; + #endif /* WOLFSSH_FWD */ + default: + ret = WS_INVALID_CHANTYPE; + } } if (ret == WS_SUCCESS) { + *idx = begin; + newChannel = ChannelNew(ssh, typeId, - DEFAULT_WINDOW_SZ, DEFAULT_MAX_PACKET_SZ); + ssh->ctx->windowSz, ssh->ctx->maxPacketSz); if (newChannel == NULL) ret = WS_RESOURCE_E; else { - ChannelUpdate(newChannel, peerChannelId, + ChannelUpdatePeer(newChannel, peerChannelId, peerInitialWindowSz, peerMaxPacketSz); if (ssh->channelListSz == 0) ssh->defaultPeerChannelId = peerChannelId; + #ifdef WOLFSSH_FWD + switch (typeId) { + /*case ID_CHANTYPE_TCPIP_FORWARD:*/ + case ID_CHANTYPE_TCPIP_DIRECT: + + ChannelUpdateForward(newChannel, + host, hostPort, origin, originPort); + break; + } + #endif /* WOLFSSH_FWD */ ChannelAppend(ssh, newChannel); ssh->clientState = CLIENT_CHANNEL_OPEN_DONE; } } +#ifdef WOLFSSH_FWD + if (ret != WS_SUCCESS) { + WFREE(host, ssh->ctx->heap, DYNTYPE_STRING); + WFREE(origin, ssh->ctx->heap, DYNTYPE_STRING); + } +#endif /* WOLFSSH_FWD */ + WLOG(WS_LOG_DEBUG, "Leaving DoChannelOpen(), ret = %d", ret); return ret; } @@ -3650,13 +3805,13 @@ static int DoChannelOpenConf(WOLFSSH* ssh, WLOG(WS_LOG_INFO, " peerInitialWindowSz = %u", peerInitialWindowSz); WLOG(WS_LOG_INFO, " peerMaxPacketSz = %u", peerMaxPacketSz); - channel = ChannelFind(ssh, channelId, FIND_SELF); + channel = ChannelFind(ssh, channelId, WS_CHANNEL_ID_SELF); if (channel == NULL) ret = WS_INVALID_CHANID; } if (ret == WS_SUCCESS) - ret = ChannelUpdate(channel, peerChannelId, + ret = ChannelUpdatePeer(channel, peerChannelId, peerInitialWindowSz, peerMaxPacketSz); if (ret == WS_SUCCESS) @@ -3703,7 +3858,7 @@ static int DoChannelOpenFail(WOLFSSH* ssh, WLOG(WS_LOG_INFO, "description: %s", desc); } - ret = ChannelRemove(ssh, channelId, FIND_SELF); + ret = ChannelRemove(ssh, channelId, WS_CHANNEL_ID_SELF); } if (ret == WS_SUCCESS) @@ -3729,7 +3884,7 @@ static int DoChannelEof(WOLFSSH* ssh, if (ret == WS_SUCCESS) { *idx = begin; - channel = ChannelFind(ssh, channelId, FIND_SELF); + channel = ChannelFind(ssh, channelId, WS_CHANNEL_ID_SELF); if (channel == NULL) ret = WS_INVALID_CHANID; } @@ -3757,7 +3912,7 @@ static int DoChannelClose(WOLFSSH* ssh, if (ret == WS_SUCCESS) { *idx = begin; - channel = ChannelFind(ssh, channelId, FIND_SELF); + channel = ChannelFind(ssh, channelId, WS_CHANNEL_ID_SELF); if (channel == NULL) ret = WS_INVALID_CHANID; } @@ -3767,7 +3922,7 @@ static int DoChannelClose(WOLFSSH* ssh, } if (ret == WS_SUCCESS) { - ret = ChannelRemove(ssh, channelId, FIND_SELF); + ret = ChannelRemove(ssh, channelId, WS_CHANNEL_ID_SELF); } if (ret == WS_SUCCESS) { @@ -3807,7 +3962,7 @@ static int DoChannelRequest(WOLFSSH* ssh, } if (ret == WS_SUCCESS) { - channel = ChannelFind(ssh, channelId, FIND_SELF); + channel = ChannelFind(ssh, channelId, WS_CHANNEL_ID_SELF); if (channel == NULL) ret = WS_INVALID_CHANID; } @@ -3944,7 +4099,7 @@ static int DoChannelWindowAdjust(WOLFSSH* ssh, if (ret == WS_SUCCESS) { *idx = begin; - channel = ChannelFind(ssh, channelId, FIND_SELF); + channel = ChannelFind(ssh, channelId, WS_CHANNEL_ID_SELF); if (channel == NULL) ret = WS_INVALID_CHANID; else { @@ -3984,18 +4139,66 @@ static int DoChannelData(WOLFSSH* ssh, if (ret == WS_SUCCESS) { *idx = begin + dataSz; - channel = ChannelFind(ssh, channelId, FIND_SELF); + channel = ChannelFind(ssh, channelId, WS_CHANNEL_ID_SELF); if (channel == NULL) ret = WS_INVALID_CHANID; else ret = ChannelPutData(channel, buf + begin, dataSz); } + if (ret == WS_SUCCESS) { + ssh->lastRxId = channelId; + ret = WS_CHAN_RXD; + } + WLOG(WS_LOG_DEBUG, "Leaving DoChannelData(), ret = %d", ret); return ret; } +static int DoChannelExtendedData(WOLFSSH* ssh, + byte* buf, word32 len, word32* idx) +{ + WOLFSSH_CHANNEL* channel = NULL; + word32 begin = *idx; + word32 dataSz = 0; + word32 channelId; + word32 dataTypeCode; + int ret; + + WLOG(WS_LOG_DEBUG, "Entering DoChannelExtendedData()"); + + ret = GetUint32(&channelId, buf, len, &begin); + if (ret == WS_SUCCESS) + ret = GetUint32(&dataTypeCode, buf, len, &begin); + if (ret == WS_SUCCESS) + ret = (dataTypeCode == CHANNEL_EXTENDED_DATA_STDERR) ? + WS_SUCCESS : WS_INVALID_EXTDATA; + if (ret == WS_SUCCESS) + ret = GetUint32(&dataSz, buf, len, &begin); + + if (ret == WS_SUCCESS) { + channel = ChannelFind(ssh, channelId, WS_CHANNEL_ID_SELF); + if (channel == NULL) + ret = WS_INVALID_CHANID; + else { +#ifdef DEBUG_WOLFSSH + DumpOctetString(buf + begin, dataSz); +#endif + ret = SendChannelWindowAdjust(ssh, channel->peerChannel, dataSz); + } + *idx = begin + dataSz; + } + + if (ret == WS_SUCCESS) { + ssh->lastRxId = channelId; + } + + WLOG(WS_LOG_DEBUG, "Leaving DoChannelExtendedData(), ret = %d", ret); + return ret; +} + + static int DoPacket(WOLFSSH* ssh) { byte* buf = (byte*)ssh->inputBuffer.buffer; @@ -4158,6 +4361,11 @@ static int DoPacket(WOLFSSH* ssh) ret = DoChannelData(ssh, buf + idx, payloadSz, &payloadIdx); break; + case MSGID_CHANNEL_EXTENDED_DATA: + WLOG(WS_LOG_DEBUG, "Decoding MSGID_CHANNEL_EXTENDED_DATA"); + ret = DoChannelExtendedData(ssh, buf + idx, payloadSz, &payloadIdx); + break; + case MSGID_CHANNEL_EOF: WLOG(WS_LOG_DEBUG, "Decoding MSGID_CHANNEL_EOF"); ret = DoChannelEof(ssh, buf + idx, payloadSz, &payloadIdx); @@ -4191,7 +4399,7 @@ static int DoPacket(WOLFSSH* ssh) ret = SendUnimplemented(ssh); } - if (ret == WS_SUCCESS) { + if (ret == WS_SUCCESS || ret == WS_CHAN_RXD) { idx += payloadIdx; if (idx + padSz > len) { @@ -4200,7 +4408,7 @@ static int DoPacket(WOLFSSH* ssh) } } - if (ret == WS_SUCCESS) { + if (ret == WS_SUCCESS || ret == WS_CHAN_RXD) { idx += padSz; ssh->inputBuffer.idx = idx; ssh->peerSeq++; @@ -4477,7 +4685,7 @@ static INLINE int DecryptAead(WOLFSSH* ssh, byte* plain, int DoReceive(WOLFSSH* ssh) { - int ret = WS_FATAL_ERROR; + int ret = WS_SUCCESS; int verifyResult; word32 readSz; byte peerBlockSz = ssh->peerBlockSz; @@ -4589,7 +4797,8 @@ int DoReceive(WOLFSSH* ssh) FALL_THROUGH /* no break */ case PROCESS_PACKET: - if ( (ret = DoPacket(ssh)) < 0) { + ret = DoPacket(ssh); + if (ret < 0 && ret != WS_CHAN_RXD) { return ret; } WLOG(WS_LOG_DEBUG, "PR3: peerMacSz = %u", peerMacSz); @@ -4607,9 +4816,9 @@ int DoReceive(WOLFSSH* ssh) WLOG(WS_LOG_DEBUG, "PR5: txCount = %u, rxCount = %u", ssh->txCount, ssh->rxCount); - return WS_SUCCESS; + return ret; } - return ret; + return WS_FATAL_ERROR; } @@ -6433,37 +6642,27 @@ int SendRequestSuccess(WOLFSSH* ssh, int success) } -int SendChannelOpenSession(WOLFSSH* ssh, - word32 initialWindowSz, word32 maxPacketSz) +static int SendChannelOpen(WOLFSSH* ssh, WOLFSSH_CHANNEL* channel, + byte* channelData, word32 channelDataSz) { - WOLFSSH_CHANNEL* newChannel; byte* output; const char* channelType; - word32 channelTypeSz, channelId, idx; + word32 channelTypeSz, idx; int ret = WS_SUCCESS; - WLOG(WS_LOG_DEBUG, "Entering SendChannelOpenSession()"); + WLOG(WS_LOG_DEBUG, "Entering SendChannelOpen()"); - if (ssh == NULL) + if (ssh == NULL || channel == NULL) + ret = WS_BAD_ARGUMENT; + if (channelDataSz > 0 && channelData == NULL) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { - channelId = ssh->nextChannel; - newChannel = ChannelNew(ssh, ID_CHANTYPE_SESSION, - initialWindowSz, maxPacketSz); - if (newChannel == NULL) - ret = WS_MEMORY_E; - - if (ret == WS_SUCCESS) - ret = ChannelAppend(ssh, newChannel); - } - - if (ret == WS_SUCCESS) { - channelType = IdToName(ID_CHANTYPE_SESSION); + channelType = IdToName(channel->channelType); channelTypeSz = (word32)WSTRLEN(channelType); ret = PreparePacket(ssh, MSG_ID_SZ + LENGTH_SZ + channelTypeSz + - (UINT32_SZ * 3)); + (UINT32_SZ * 3) + channelDataSz); } if (ret == WS_SUCCESS) { @@ -6475,12 +6674,15 @@ int SendChannelOpenSession(WOLFSSH* ssh, idx += LENGTH_SZ; WMEMCPY(output + idx, channelType, channelTypeSz); idx += channelTypeSz; - c32toa(channelId, output + idx); + c32toa(channel->channel, output + idx); idx += UINT32_SZ; - c32toa(initialWindowSz, output + idx); + c32toa(channel->windowSz, output + idx); idx += UINT32_SZ; - c32toa(maxPacketSz, output + idx); + c32toa(channel->maxPacketSz, output + idx); idx += UINT32_SZ; + if (channelDataSz > 0) + WMEMCPY(output + idx, channelData, channelDataSz); + idx += channelDataSz; ssh->outputBuffer.length = idx; @@ -6490,11 +6692,71 @@ int SendChannelOpenSession(WOLFSSH* ssh, if (ret == WS_SUCCESS) ret = SendBuffered(ssh); + WLOG(WS_LOG_DEBUG, "Leaving SendChannelOpen(), ret = %d", ret); + return ret; +} + + +int SendChannelOpenSession(WOLFSSH* ssh, WOLFSSH_CHANNEL* channel) +{ + int ret = WS_SUCCESS; + + WLOG(WS_LOG_DEBUG, "Entering SendChannelOpenSession()"); + + ret = SendChannelOpen(ssh, channel, NULL, 0); + WLOG(WS_LOG_DEBUG, "Leaving SendChannelOpenSession(), ret = %d", ret); return ret; } +#ifdef WOLFSSH_FWD +int SendChannelOpenForward(WOLFSSH* ssh, WOLFSSH_CHANNEL* channel) +{ + int ret = WS_SUCCESS; + byte* forwardData = NULL; + word32 hostSz, originSz, forwardDataSz, idx; + + WLOG(WS_LOG_DEBUG, "Entering SendChannelOpenForward()"); + + if (ssh == NULL || channel->host == NULL || channel->origin == NULL) + ret = WS_BAD_ARGUMENT; + + if (ret == WS_SUCCESS) { + hostSz = (word32)WSTRLEN(channel->host); + originSz = (word32)WSTRLEN(channel->origin); + forwardDataSz = UINT32_SZ * 2 + LENGTH_SZ * 2 + hostSz + originSz; + forwardData = (byte*)WMALLOC(forwardDataSz, + ssh->ctx->heap, DYNTYPE_TEMP); + if (forwardData == NULL) + ret = WS_MEMORY_E; + } + + if (ret == WS_SUCCESS) { + c32toa(hostSz, forwardData); + idx = LENGTH_SZ; + WMEMCPY(forwardData + idx, channel->host, hostSz); + idx += hostSz; + c32toa(channel->hostPort, forwardData + idx); + idx += UINT32_SZ; + c32toa(originSz, forwardData); + idx += LENGTH_SZ; + WMEMCPY(forwardData + idx, channel->origin, originSz); + idx += originSz; + c32toa(channel->originPort, forwardData + idx); + + ret = SendChannelOpen(ssh, channel, forwardData, forwardDataSz); + } + + if (forwardData) + WFREE(forwardData, ssh->ctx->heap, DYNTYPE_TEMP); + + WLOG(WS_LOG_DEBUG, "Leaving SendChannelOpenForward(), ret = %d", ret); + return ret; +} +#endif /* WOLFSSH_FWD */ + + int SendChannelOpenConf(WOLFSSH* ssh) { byte* output; @@ -6508,7 +6770,8 @@ int SendChannelOpenConf(WOLFSSH* ssh) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { - channel = ChannelFind(ssh, ssh->defaultPeerChannelId, FIND_PEER); + channel = ChannelFind(ssh, + ssh->defaultPeerChannelId, WS_CHANNEL_ID_PEER); if (channel == NULL) ret = WS_INVALID_CHANID; } @@ -6556,7 +6819,7 @@ int SendChannelEof(WOLFSSH* ssh, word32 peerChannelId) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { - channel = ChannelFind(ssh, peerChannelId, FIND_PEER); + channel = ChannelFind(ssh, peerChannelId, WS_CHANNEL_ID_PEER); if (channel == NULL) ret = WS_INVALID_CHANID; } @@ -6604,7 +6867,7 @@ int SendChannelEow(WOLFSSH* ssh, word32 peerChannelId) } if (ret == WS_SUCCESS) { - channel = ChannelFind(ssh, peerChannelId, FIND_PEER); + channel = ChannelFind(ssh, peerChannelId, WS_CHANNEL_ID_PEER); if (channel == NULL) ret = WS_INVALID_CHANID; } @@ -6653,7 +6916,7 @@ int SendChannelExit(WOLFSSH* ssh, word32 peerChannelId, int status) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { - channel = ChannelFind(ssh, peerChannelId, FIND_PEER); + channel = ChannelFind(ssh, peerChannelId, WS_CHANNEL_ID_PEER); if (channel == NULL) ret = WS_INVALID_CHANID; } @@ -6703,7 +6966,7 @@ int SendChannelClose(WOLFSSH* ssh, word32 peerChannelId) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { - channel = ChannelFind(ssh, peerChannelId, FIND_PEER); + channel = ChannelFind(ssh, peerChannelId, WS_CHANNEL_ID_PEER); if (channel == NULL) ret = WS_INVALID_CHANID; else if (channel->closeSent) { @@ -6757,7 +7020,7 @@ int SendChannelData(WOLFSSH* ssh, word32 peerChannel, } if (ret == WS_SUCCESS) { - channel = ChannelFind(ssh, peerChannel, FIND_PEER); + channel = ChannelFind(ssh, peerChannel, WS_CHANNEL_ID_PEER); if (channel == NULL) { WLOG(WS_LOG_DEBUG, "Invalid peer channel"); ret = WS_INVALID_CHANID; @@ -6823,7 +7086,7 @@ int SendChannelWindowAdjust(WOLFSSH* ssh, word32 peerChannel, if (ssh == NULL) ret = WS_BAD_ARGUMENT; - channel = ChannelFind(ssh, peerChannel, FIND_PEER); + channel = ChannelFind(ssh, peerChannel, WS_CHANNEL_ID_PEER); if (channel == NULL) { WLOG(WS_LOG_DEBUG, "Invalid peer channel"); ret = WS_INVALID_CHANID; @@ -6880,7 +7143,8 @@ int SendChannelRequest(WOLFSSH* ssh, byte* name, word32 nameSz) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { - channel = ChannelFind(ssh, ssh->defaultPeerChannelId, FIND_PEER); + channel = ChannelFind(ssh, + ssh->defaultPeerChannelId, WS_CHANNEL_ID_PEER); if (channel == NULL) ret = WS_INVALID_CHANID; } @@ -6981,7 +7245,7 @@ int SendChannelSuccess(WOLFSSH* ssh, word32 channelId, int success) ret = WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { - channel = ChannelFind(ssh, channelId, FIND_SELF); + channel = ChannelFind(ssh, channelId, WS_CHANNEL_ID_SELF); if (channel == NULL) { WLOG(WS_LOG_DEBUG, "Invalid channel"); ret = WS_INVALID_CHANID; diff --git a/src/ssh.c b/src/ssh.c index aeb06a8..a6e5ea1 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -553,11 +553,26 @@ int wolfSSH_connect(WOLFSSH* ssh) FALL_THROUGH /* no break */ case CONNECT_SERVER_USERAUTH_ACCEPT_DONE: - if ( (ssh->error = SendChannelOpenSession(ssh, DEFAULT_WINDOW_SZ, - DEFAULT_MAX_PACKET_SZ)) < WS_SUCCESS) { - WLOG(WS_LOG_DEBUG, connectError, - "SERVER_USERAUTH_ACCEPT_DONE", ssh->error); - return WS_FATAL_ERROR; + { + WOLFSSH_CHANNEL* newChannel; + + newChannel = ChannelNew(ssh, ID_CHANTYPE_SESSION, + ssh->ctx->windowSz, ssh->ctx->maxPacketSz); + if (newChannel == NULL) { + ssh->error = WS_MEMORY_E; + WLOG(WS_LOG_DEBUG, connectError, + "SERVER_USERAUTH_ACCEPT_DONE", ssh->error); + return WS_FATAL_ERROR; + } + if ( (ssh->error = + SendChannelOpenSession(ssh, newChannel)) < WS_SUCCESS) { + + ChannelDelete(newChannel, ssh->ctx->heap); + WLOG(WS_LOG_DEBUG, connectError, + "SERVER_USERAUTH_ACCEPT_DONE", ssh->error); + return WS_FATAL_ERROR; + } + ChannelAppend(ssh, newChannel); } ssh->connectState = CONNECT_CLIENT_CHANNEL_OPEN_SESSION_SENT; WLOG(WS_LOG_DEBUG, connectState, @@ -661,7 +676,7 @@ int wolfSSH_stream_read(WOLFSSH* ssh, byte* buf, word32 bufSz) int ret = DoReceive(ssh); if (ssh->channelList == NULL || ssh->channelList->receivedEof) ret = WS_EOF; - if (ret < 0) { + if (ret < 0 && ret != WS_CHAN_RXD) { WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_stream_read(), ret = %d", ret); return ret; } @@ -744,6 +759,38 @@ int wolfSSH_stream_exit(WOLFSSH* ssh, int status) } +int wolfSSH_SendIgnore(WOLFSSH* ssh, const byte* buf, word32 bufSz) +{ + byte scratch[128]; + + (void)buf; + (void)bufSz; + WMEMSET(scratch, 0, sizeof(scratch)); + + return SendIgnore(ssh, scratch, sizeof(scratch)); +} + + +/* Sets up a timeout wrapper. */ +WOLFSSH_TIMEOUT wolfSSH_SetTimeout(int sec, int usec) +{ + WOLFSSH_TIMEOUT to = {sec, usec}; + return to; +} + + +int wolfSSH_Select(WOLFSSH* ssh, WOLFSSH_TIMEOUT to) +{ + (void)ssh; + (void)to; + + WLOG(WS_LOG_INFO, "Entering wolfSSH_Select()"); + WLOG(WS_LOG_INFO, "Entering wolfSSH_Select(), ret = %d", WS_SUCCESS); + + return WS_SUCCESS; +} + + void wolfSSH_SetUserAuth(WOLFSSH_CTX* ctx, WS_CallbackUserAuth cb) { if (ctx != NULL) { @@ -810,7 +857,7 @@ int wolfSSH_SetChannelType(WOLFSSH* ssh, byte type, byte* name, word32 nameSz) } return WS_SUCCESS; -} +} int wolfSSH_SetUsername(WOLFSSH* ssh, const char* username) { @@ -873,7 +920,27 @@ int wolfSSH_CTX_UsePrivateKey_buffer(WOLFSSH_CTX* ctx, const byte* in, word32 inSz, int format) { WLOG(WS_LOG_DEBUG, "Entering wolfSSH_CTX_UsePrivateKey_buffer()"); - return wolfSSH_ProcessBuffer(ctx, in, inSz, format, BUFTYPE_PRIVKEY); + return wolfSSH_ProcessBuffer(ctx, in, inSz, format, BUFTYPE_PRIVKEY); +} + + +int wolfSSH_CTX_SetWindowPacketSize(WOLFSSH_CTX* ctx, + word32 windowSz, word32 maxPacketSz) +{ + WLOG(WS_LOG_DEBUG, "Entering wolfSSH_CTX_SetWindowPacketSize()"); + + if (ctx == NULL) + return WS_BAD_ARGUMENT; + + if (windowSz == 0) + windowSz = DEFAULT_WINDOW_SZ; + if (maxPacketSz == 0) + maxPacketSz = DEFAULT_MAX_PACKET_SZ; + + ctx->windowSz = windowSz; + ctx->maxPacketSz = maxPacketSz; + + return WS_SUCCESS; } @@ -935,3 +1002,275 @@ const char* wolfSSH_GetSessionCommand(const WOLFSSH* ssh) return NULL; } + + +int wolfSSH_worker(WOLFSSH* ssh, word32* channelId) +{ + int ret = WS_SUCCESS; + + printf("Entering wolfSSH_worker()\n"); + WLOG(WS_LOG_DEBUG, "Entering wolfSSH_worker()"); + + if (ssh == NULL) + ret = WS_BAD_ARGUMENT; + + /* Attempt to send any data pending in the outputBuffer. */ + if (ret == WS_SUCCESS) { + if (ssh->outputBuffer.length != 0) + ret = SendBuffered(ssh); + } + + /* Attempt to receive data from the peer. */ + if (ret == WS_SUCCESS) + ret = DoReceive(ssh); + + if (ret == WS_CHAN_RXD) { + if (channelId != NULL) + *channelId = ssh->lastRxId; + } + + if (ret == WS_CHAN_RXD) { + printf("Leaving wolfSSH_worker(), " + "data received on channel %u\n", ssh->lastRxId); + WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_worker(), " + "data received on channel %u", ssh->lastRxId); + } + else { + printf("Leaving wolfSSH_worker(), ret = %d\n", ret); + WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_worker(), ret = %d", ret); + } + return ret; +} + + +#ifdef WOLFSSH_FWD + +WOLFSSH_CHANNEL* wolfSSH_ChannelFwdNew(WOLFSSH* ssh, + const char* host, word32 hostPort, + const char* origin, word32 originPort) +{ + WOLFSSH_CHANNEL* newChannel = NULL; + int ret = WS_SUCCESS; + + WLOG(WS_LOG_DEBUG, "Entering wolfSSH_ChannelFwdNew()"); + + if (ssh == NULL || host == NULL || origin == NULL) + ret = WS_BAD_ARGUMENT; + + if (ret == WS_SUCCESS) + newChannel = ChannelNew(ssh, ID_CHANTYPE_TCPIP_DIRECT, + ssh->ctx->windowSz, ssh->ctx->maxPacketSz); + if (ret == WS_SUCCESS) + ret = ChannelUpdateForward(newChannel, + host, hostPort, origin, originPort); + if (ret == WS_SUCCESS) + ret = SendChannelOpenForward(ssh, newChannel); + + if (ret != WS_SUCCESS) { + ChannelDelete(newChannel, ssh->ctx->heap); + newChannel = NULL; + } + + if (newChannel != NULL) + ChannelAppend(ssh, newChannel); + + WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_ChannelFwdNew(), newChannel = %p", + newChannel); + return newChannel; +} + +#endif /* WOLFSSH_FWD */ + + +int wolfSSH_ChannelFree(WOLFSSH_CHANNEL* channel) +{ + int ret; + + WLOG(WS_LOG_DEBUG, "Entering wolfSSH_ChannelFree()"); + + if (channel != NULL) { + ret = ChannelRemove(channel->ssh, + channel->channel, WS_CHANNEL_ID_SELF); + } + else + ret = WS_BAD_ARGUMENT; + + WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_ChannelFree(), ret = %d", ret); + return ret; +} + + +int wolfSSH_ChannelGetId(WOLFSSH_CHANNEL* channel, word32* id, byte peer) +{ + int ret = WS_SUCCESS; + + WLOG(WS_LOG_DEBUG, "Entering wolfSSH_ChannelGetId()"); + + if (channel == NULL || id == NULL) + ret = WS_BAD_ARGUMENT; + else { + *id = (peer == WS_CHANNEL_ID_SELF) ? + channel->channel : channel->peerChannel; + } + + WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_ChannelGetId(), ret = %d", ret); + return ret; +} + + +WOLFSSH_CHANNEL* wolfSSH_ChannelFind(WOLFSSH* ssh, word32 id, byte peer) +{ + return ChannelFind(ssh, id, peer); +} + + +#ifdef WOLFSSH_FWD + +int wolfSSH_ChannelSetFwdFd(WOLFSSH_CHANNEL* channel, int fwdFd) +{ + int ret = WS_SUCCESS; + + WLOG(WS_LOG_DEBUG, "Entering wolfSSH_ChannelSetFwdFd()"); + + if (channel != NULL) + channel->fwdFd = fwdFd; + else + ret = WS_BAD_ARGUMENT; + + WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_ChannelSetFwdFd(), ret = %d", ret); + return ret; +} + + +int wolfSSH_ChannelGetFwdFd(const WOLFSSH_CHANNEL* channel) +{ + int fwdFd = -1; + + WLOG(WS_LOG_DEBUG, "Entering wolfSSH_ChannelGetFwdFd()"); + + if (channel != NULL) + fwdFd = channel->fwdFd; + + WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_ChannelGetFwdFd(), ret = %d", fwdFd); + return fwdFd; +} + +#endif /* WOLFSSH_FWD */ + + +int wolfSSH_ChannelRead(WOLFSSH_CHANNEL* channel, byte* buf, word32 bufSz) +{ + Buffer* inputBuffer; + + WLOG(WS_LOG_DEBUG, "Entering wolfSSH_ChannelRead()"); + + if (channel == NULL || buf == NULL || bufSz == 0) + return WS_BAD_ARGUMENT; + + inputBuffer = &channel->inputBuffer; + bufSz = min(bufSz, inputBuffer->length - inputBuffer->idx); + WMEMCPY(buf, inputBuffer->buffer + inputBuffer->idx, bufSz); + inputBuffer->idx += bufSz; + + if (!channel->ssh->isKeying && + (inputBuffer->length > inputBuffer->bufferSz / 2)) { + + word32 usedSz = inputBuffer->length - inputBuffer->idx; + word32 bytesToAdd = inputBuffer->idx; + int sendResult; + + WLOG(WS_LOG_DEBUG, "Making more room: %u", usedSz); + if (usedSz) { + WLOG(WS_LOG_DEBUG, " ...moving data down"); + WMEMMOVE(inputBuffer->buffer, + inputBuffer->buffer + bytesToAdd, usedSz); + } + + sendResult = SendChannelWindowAdjust(channel->ssh, + channel->peerChannel, + bytesToAdd); + if (sendResult != WS_SUCCESS) + bufSz = sendResult; + + WLOG(WS_LOG_INFO, " bytesToAdd = %u", bytesToAdd); + WLOG(WS_LOG_INFO, " windowSz = %u", channel->windowSz); + channel->windowSz += bytesToAdd; + WLOG(WS_LOG_INFO, " update windowSz = %u", channel->windowSz); + + inputBuffer->length = usedSz; + inputBuffer->idx = 0; + } + + WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_ChannelRead(), bytesRxd = %d", + bufSz); + return bufSz; +} + + +int wolfSSH_ChannelSend(WOLFSSH_CHANNEL* channel, + const byte* buf, word32 bufSz) +{ + int bytesTxd = 0; + + WLOG(WS_LOG_DEBUG, "Entering wolfSSH_ChannelSend(), ID = %d, peerID = %d", channel->channel, channel->peerChannel); + +#ifdef DEBUG_WOLFSSH + DumpOctetString(buf, bufSz); +#endif + if (channel == NULL || buf == NULL) + bytesTxd = WS_BAD_ARGUMENT; + else if (!channel->openConfirmed) { + WLOG(WS_LOG_DEBUG, "Channel not confirmed yet."); + return -666; + } + else { + WLOG(WS_LOG_DEBUG, "Sending data."); + bytesTxd = SendChannelData(channel->ssh, channel->peerChannel, + (byte*)buf, bufSz); + } + + WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_ChannelSend(), bytesTxd = %d", + bytesTxd); + return bytesTxd; +} + + +int wolfSSH_ChannelExit(WOLFSSH_CHANNEL* channel) +{ + int ret = WS_SUCCESS; + + WLOG(WS_LOG_DEBUG, "Entering wolfSSH_ChannelExit()"); + + if (channel == NULL) + ret = WS_BAD_ARGUMENT; + + if (ret == WS_SUCCESS) + ret = SendChannelEof(channel->ssh, channel->peerChannel); + + if (ret == WS_SUCCESS) + ret = SendChannelClose(channel->ssh, channel->peerChannel); + + if (ret == WS_SUCCESS) + ret = ChannelRemove(channel->ssh, + channel->peerChannel, WS_CHANNEL_ID_PEER); + + WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_ChannelExit(), ret = %d", ret); + return ret; +} + + +WOLFSSH_CHANNEL* wolfSSH_ChannelNext(WOLFSSH* ssh, WOLFSSH_CHANNEL* channel) +{ + WOLFSSH_CHANNEL* nextChannel = NULL; + + WLOG(WS_LOG_DEBUG, "Entering wolfSSH_ChannelNext()"); + + if (ssh != NULL && channel == NULL) + nextChannel = ssh->channelList; + else if (channel != NULL) + nextChannel = channel->next; + + WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_ChannelNext(), %s", + nextChannel == NULL ? "none" : "NEXT!"); + return nextChannel; +} diff --git a/tests/include.am b/tests/include.am index 0026472..bcf2f13 100644 --- a/tests/include.am +++ b/tests/include.am @@ -8,20 +8,20 @@ noinst_PROGRAMS += tests/unit.test tests/api.test \ tests/testsuite.test tests_unit_test_SOURCES = tests/unit.c -tests_unit_test_CFLAGS = -DNO_MAIN_DRIVER $(AM_CFLAGS) -tests_unit_test_LDADD = src/libwolfssh.la $(LIB_STATIC_ADD) +tests_unit_test_CPPFLAGS = -DNO_MAIN_DRIVER +tests_unit_test_LDADD = src/libwolfssh.la tests_unit_test_DEPENDENCIES = src/libwolfssh.la tests_api_test_SOURCES = tests/api.c -tests_api_test_CFLAGS = -DNO_MAIN_DRIVER $(AM_CFLAGS) -tests_api_test_LDADD = src/libwolfssh.la $(LIB_STATIC_ADD) +tests_api_test_CPPFLAGS = -DNO_MAIN_DRIVER +tests_api_test_LDADD = src/libwolfssh.la tests_api_test_DEPENDENCIES = src/libwolfssh.la tests_testsuite_test_SOURCES = tests/testsuite.c \ examples/echoserver/echoserver.c \ examples/client/client.c -tests_testsuite_test_CFLAGS = -DNO_MAIN_DRIVER $(AM_CFLAGS) -tests_testsuite_test_LDADD = src/libwolfssh.la $(LIB_STATIC_ADD) +tests_testsuite_test_CPPFLAGS = -DNO_MAIN_DRIVER +tests_testsuite_test_LDADD = src/libwolfssh.la tests_testsuite_test_DEPENDENCIES = src/libwolfssh.la DISTCLEANFILES+= tests/.libs/unit.test tests/.libs/api.test \ diff --git a/wolfssh/error.h b/wolfssh/error.h index b787ecd..6eaaaad 100644 --- a/wolfssh/error.h +++ b/wolfssh/error.h @@ -94,8 +94,11 @@ enum WS_ErrorCodes { WS_PERMISSIONS = -54, WS_SFTP_COMPLETE = -55, /* SFTP connection established */ WS_NEXT_ERROR = -56, /* Getting next value/state results in error */ + WS_CHAN_RXD = -57, /* Status that channel data received. */ + WS_INVALID_EXTDATA = -58, /* invalid Channel Extended Data Type */ + WS_CHAN_PENDING = -59, /* peer hasn't confirmed channel open */ - WS_LAST_E = -56 /* Update this to indicate last error */ + WS_LAST_E = -59 /* Update this to indicate last error */ }; diff --git a/wolfssh/internal.h b/wolfssh/internal.h index f136082..8362da5 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -98,6 +98,8 @@ enum { /* Channel Type IDs */ ID_CHANTYPE_SESSION, + ID_CHANTYPE_TCPIP_FORWARD, + ID_CHANTYPE_TCPIP_DIRECT, ID_UNKNOWN }; @@ -185,6 +187,8 @@ struct WOLFSSH_CTX { word32 highwaterMark; const char* banner; word32 bannerSz; + word32 windowSz; + word32 maxPacketSz; byte side; /* client or server */ byte showBanner; }; @@ -339,6 +343,7 @@ struct WOLFSSH { word32 connectChannelId; byte channelName[WOLFSSH_MAX_CHN_NAMESZ]; byte channelNameSz; + word32 lastRxId; Buffer inputBuffer; Buffer outputBuffer; @@ -382,12 +387,20 @@ struct WOLFSSH_CHANNEL { byte sessionType; byte closeSent; byte receivedEof; + byte openConfirmed; word32 channel; word32 windowSz; word32 maxPacketSz; word32 peerChannel; word32 peerWindowSz; word32 peerMaxPacketSz; +#ifdef WOLFSSH_FWD + char* host; + word32 hostPort; + char* origin; + word32 originPort; + int fwdFd; +#endif /* WOLFSSH_FWD */ Buffer inputBuffer; char* command; struct WOLFSSH* ssh; @@ -401,7 +414,10 @@ WOLFSSH_LOCAL WOLFSSH* SshInit(WOLFSSH*, WOLFSSH_CTX*); WOLFSSH_LOCAL void SshResourceFree(WOLFSSH*, void*); WOLFSSH_LOCAL WOLFSSH_CHANNEL* ChannelNew(WOLFSSH*, byte, word32, word32); -WOLFSSH_LOCAL int ChannelUpdate(WOLFSSH_CHANNEL*, word32, word32, word32); +WOLFSSH_LOCAL int ChannelUpdatePeer(WOLFSSH_CHANNEL*, word32, word32, word32); +WOLFSSH_LOCAL int ChannelUpdateForward(WOLFSSH_CHANNEL*, + const char*, word32, const char*, word32); +WOLFSSH_LOCAL int ChannelAppend(WOLFSSH* ssh, WOLFSSH_CHANNEL* channel); WOLFSSH_LOCAL void ChannelDelete(WOLFSSH_CHANNEL*, void*); WOLFSSH_LOCAL WOLFSSH_CHANNEL* ChannelFind(WOLFSSH*, word32, byte); WOLFSSH_LOCAL int ChannelRemove(WOLFSSH*, word32, byte); @@ -422,6 +438,7 @@ WOLFSSH_LOCAL int wsEmbedSend(WOLFSSH*, void*, word32, void*); WOLFSSH_LOCAL int DoReceive(WOLFSSH*); WOLFSSH_LOCAL int DoProtoId(WOLFSSH*); +WOLFSSH_LOCAL int SendBuffered(WOLFSSH*); WOLFSSH_LOCAL int SendProtoId(WOLFSSH*); WOLFSSH_LOCAL int SendKexInit(WOLFSSH*); WOLFSSH_LOCAL int SendKexDhInit(WOLFSSH*); @@ -442,7 +459,8 @@ WOLFSSH_LOCAL int SendUserAuthBanner(WOLFSSH*); WOLFSSH_LOCAL int SendUserAuthPkOk(WOLFSSH*, const byte*, word32, const byte*, word32); WOLFSSH_LOCAL int SendRequestSuccess(WOLFSSH*, int); -WOLFSSH_LOCAL int SendChannelOpenSession(WOLFSSH*, word32, word32); +WOLFSSH_LOCAL int SendChannelOpenSession(WOLFSSH*, WOLFSSH_CHANNEL*); +WOLFSSH_LOCAL int SendChannelOpenForward(WOLFSSH*, WOLFSSH_CHANNEL*); WOLFSSH_LOCAL int SendChannelOpenConf(WOLFSSH*); WOLFSSH_LOCAL int SendChannelEof(WOLFSSH*, word32); WOLFSSH_LOCAL int SendChannelEow(WOLFSSH*, word32); @@ -562,6 +580,7 @@ enum WS_MessageIds { MSGID_CHANNEL_OPEN_FAIL = 92, MSGID_CHANNEL_WINDOW_ADJUST = 93, MSGID_CHANNEL_DATA = 94, + MSGID_CHANNEL_EXTENDED_DATA = 95, MSGID_CHANNEL_EOF = 96, MSGID_CHANNEL_CLOSE = 97, MSGID_CHANNEL_REQUEST = 98, @@ -570,6 +589,9 @@ enum WS_MessageIds { }; +#define CHANNEL_EXTENDED_DATA_STDERR 1 + + /* dynamic memory types */ enum WS_DynamicTypes { DYNTYPE_CTX, @@ -588,7 +610,8 @@ enum WS_DynamicTypes { DYNTYPE_MPINT, DYNTYPE_SCPCTX, DYNTYPE_SCPDIR, - DYNTYPE_SFTP + DYNTYPE_SFTP, + DYNTYPE_TEMP }; diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h index da5eb5b..5f305c0 100644 --- a/wolfssh/ssh.h +++ b/wolfssh/ssh.h @@ -62,6 +62,8 @@ WOLFSSH_API void wolfSSH_CTX_free(WOLFSSH_CTX*); WOLFSSH_API WOLFSSH* wolfSSH_new(WOLFSSH_CTX*); WOLFSSH_API void wolfSSH_free(WOLFSSH*); +WOLFSSH_API int wolfSSH_worker(WOLFSSH*, word32*); + WOLFSSH_API int wolfSSH_set_fd(WOLFSSH*, int); WOLFSSH_API int wolfSSH_get_fd(const WOLFSSH*); @@ -76,6 +78,22 @@ WOLFSSH_API void wolfSSH_SetHighwaterCtx(WOLFSSH*, void*); WOLFSSH_API void* wolfSSH_GetHighwaterCtx(WOLFSSH*); +#define WS_CHANNEL_ID_SELF 0 +#define WS_CHANNEL_ID_PEER 1 + +WOLFSSH_API WOLFSSH_CHANNEL* wolfSSH_ChannelFwdNew(WOLFSSH*, + const char*, word32, const char*, word32); +WOLFSSH_API int wolfSSH_ChannelFree(WOLFSSH_CHANNEL*); +WOLFSSH_API int wolfSSH_ChannelGetId(WOLFSSH_CHANNEL*, word32*, byte); +WOLFSSH_API WOLFSSH_CHANNEL* wolfSSH_ChannelFind(WOLFSSH*, word32, byte); +WOLFSSH_API WOLFSSH_CHANNEL* wolfSSH_ChannelNext(WOLFSSH*, WOLFSSH_CHANNEL*); +WOLFSSH_API int wolfSSH_ChannelSetFwdFd(WOLFSSH_CHANNEL*, int); +WOLFSSH_API int wolfSSH_ChannelGetFwdFd(const WOLFSSH_CHANNEL*); +WOLFSSH_API int wolfSSH_ChannelRead(WOLFSSH_CHANNEL*, byte*, word32); +WOLFSSH_API int wolfSSH_ChannelSend(WOLFSSH_CHANNEL*, const byte*, word32); +WOLFSSH_API int wolfSSH_ChannelExit(WOLFSSH_CHANNEL*); + + WOLFSSH_API int wolfSSH_get_error(const WOLFSSH*); WOLFSSH_API const char* wolfSSH_get_error_name(const WOLFSSH*); WOLFSSH_API const char* wolfSSH_ErrorToName(int); @@ -135,6 +153,7 @@ WOLFSSH_API int wolfSSH_SetUsername(WOLFSSH*, const char*); WOLFSSH_API int wolfSSH_CTX_SetBanner(WOLFSSH_CTX*, const char*); WOLFSSH_API int wolfSSH_CTX_UsePrivateKey_buffer(WOLFSSH_CTX*, const byte*, word32, int); +WOLFSSH_API int wolfSSH_CTX_SetWindowPacketSize(WOLFSSH_CTX*, word32, word32); WOLFSSH_API int wolfSSH_accept(WOLFSSH*); WOLFSSH_API int wolfSSH_connect(WOLFSSH*); @@ -143,6 +162,15 @@ WOLFSSH_API int wolfSSH_stream_read(WOLFSSH*, byte*, word32); WOLFSSH_API int wolfSSH_stream_send(WOLFSSH*, byte*, word32); WOLFSSH_API int wolfSSH_stream_exit(WOLFSSH*, int); WOLFSSH_API int wolfSSH_TriggerKeyExchange(WOLFSSH*); +WOLFSSH_API int wolfSSH_SendIgnore(WOLFSSH*, const byte*, word32); + +typedef struct WOLFSSH_TIMEOUT { + int sec; + int usec; +} WOLFSSH_TIMEOUT; + +WOLFSSH_API WOLFSSH_TIMEOUT wolfSSH_SetTimeout(int, int); +WOLFSSH_API int wolfSSH_Select(WOLFSSH*, WOLFSSH_TIMEOUT); WOLFSSH_API void wolfSSH_GetStats(WOLFSSH*, word32*, word32*, word32*, word32*);