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*);