diff --git a/README.md b/README.md index 828ac0ba5..95ff39222 100644 --- a/README.md +++ b/README.md @@ -238,12 +238,6 @@ The sftpclient tool accepts the following command line options: -G get remote filename as local filename -server ------- - -This tool is a place holder. - - SCP === @@ -357,12 +351,12 @@ define `WOLFSSH_SFTP`: For full API usage and implementation details, please see the wolfSSH User Manual. -The SFTP client created is located in the directory examples/sftpclient/ and the -server is ran using the same echoserver as with wolfSSH. +The SFTP client created is located in the directory examples/sftpclient/ and +the example echoserver acts as a SFTP server. src/wolfssh$ ./examples/sftpclient/wolfsftp -A full list of supported commands can be seen with typeing "help" after a +A full list of supported commands can be seen with typing "help" after a connection. diff --git a/apps/wolfsshd/test/sshd_term_size_test.sh b/apps/wolfsshd/test/sshd_term_size_test.sh index 22d2f3a33..0a25fad54 100755 --- a/apps/wolfsshd/test/sshd_term_size_test.sh +++ b/apps/wolfsshd/test/sshd_term_size_test.sh @@ -26,16 +26,16 @@ COL=`tmux display -p -t test '#{pane_width}'` ROW=`tmux display -p -t test '#{pane_height}'` # get the terminals columns and lines -tmux send-keys -t test 'echo col=$COLUMNS row=$LINES' +tmux send-keys -t test 'echo;echo $COLUMNS $LINES;echo' tmux send-keys -t test 'ENTER' tmux capture-pane -t test -RESULT=`tmux show-buffer | grep -v echo | grep -v rejecting | grep "col="` +RESULT=$(tmux show-buffer | grep '^[0-9]* [0-9]*$') echo "$RESULT" echo "" echo "" -ROW_FOUND=`echo "$RESULT" | sed -e 's/.*[^0-9]\([0-9]\+\)[^0-9]*$/\1/'` -COL_FOUND=`echo "$RESULT" | sed -r 's/^[^0-9]*([0-9]+).*$/\1/'` +ROW_FOUND=$(echo "$RESULT" | sed -e 's/[0-9]* \([0-9]*\)/\1/') +COL_FOUND=$(echo "$RESULT" | sed -e 's/\([0-9]*\) [0-9]*/\1/') if [ "$COL" != "$COL_FOUND" ]; then echo "Col found was $COL_FOUND which does not match expected $COL" @@ -67,15 +67,13 @@ tmux new-session -d -x 50 -y 10 -s test "$TEST_CLIENT -t -u $USER -i $PRIVATE_KE # give the command a second to establish SSH connection sleep 0.5 -echo "New COL=$COL ROW=$ROW" - -tmux send-keys -t test 'echo col=$COLUMNS row=$LINES' +tmux send-keys -t test 'echo;echo $COLUMNS $LINES;echo' tmux send-keys -t test 'ENTER' tmux capture-pane -t test -RESULT=`tmux show-buffer | grep -v echo | grep -v rejecting | grep "col="` +RESULT=$(tmux show-buffer | grep '^[0-9]* [0-9]*$') -ROW_FOUND=`echo "$RESULT" | sed -e 's/.*[^0-9]\([0-9]\+\)[^0-9]*$/\1/'` -COL_FOUND=`echo "$RESULT" | sed -r 's/^[^0-9]*([0-9]+).*$/\1/'` +ROW_FOUND=$(echo "$RESULT" | sed -e 's/[0-9]* \([0-9]*\)/\1/') +COL_FOUND=$(echo "$RESULT" | sed -e 's/\([0-9]*\) [0-9]*/\1/') if [ "50" != "$COL_FOUND" ]; then echo "Col found was $COL_FOUND which does not match expected 50" diff --git a/apps/wolfsshd/wolfsshd.c b/apps/wolfsshd/wolfsshd.c index 5a98e5cf4..b8b3673f7 100644 --- a/apps/wolfsshd/wolfsshd.c +++ b/apps/wolfsshd/wolfsshd.c @@ -1204,6 +1204,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, /* Child process */ const char *args[] = {"-sh", NULL, NULL, NULL}; char cmd[MAX_COMMAND_SZ]; + char shell[MAX_COMMAND_SZ]; int ret; signal(SIGINT, SIG_DFL); @@ -1258,6 +1259,25 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, setenv("HOME", pPasswd->pw_dir, 1); setenv("LOGNAME", pPasswd->pw_name, 1); + setenv("SHELL", pPasswd->pw_shell, 1); + + if (pPasswd->pw_shell) { + word32 shellSz = (word32)WSTRLEN(pPasswd->pw_shell); + + if (shellSz < sizeof(shell)) { + char* cursor; + char* start; + + WSTRNCPY(shell, pPasswd->pw_shell, sizeof(shell)); + cursor = shell; + do { + start = cursor; + *cursor = '-'; + cursor = WSTRCHR(start, '/'); + } while (cursor && *cursor != '\0'); + args[0] = start; + } + } rc = chdir(pPasswd->pw_dir); if (rc != 0) { @@ -1323,19 +1343,21 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, /* set initial size of terminal based on saved size */ #if defined(HAVE_SYS_IOCTL_H) + wolfSSH_DoModes(ssh->modes, ssh->modesSz, childFd); { - struct winsize s; + struct winsize s = {0}; + + s.ws_col = ssh->widthChar; + s.ws_row = ssh->heightRows; + s.ws_xpixel = ssh->widthPixels; + s.ws_ypixel = ssh->heightPixels; - WMEMSET(&s, 0, sizeof s); - s.ws_col = ssh->curX; - s.ws_row = ssh->curY; - s.ws_xpixel = ssh->curXP; - s.ws_ypixel = ssh->curYP; ioctl(childFd, TIOCSWINSZ, &s); } #endif wolfSSH_SetTerminalResizeCtx(ssh, (void*)&childFd); + while (ChildRunning) { byte tmp[2]; fd_set readFds; diff --git a/examples/echoserver/echoserver.c b/examples/echoserver/echoserver.c index 63409c2f6..3d9b542e0 100644 --- a/examples/echoserver/echoserver.c +++ b/examples/echoserver/echoserver.c @@ -2159,21 +2159,18 @@ static void ShowUsage(void) } -static INLINE void SignalTcpReady(func_args* serverArgs, word16 port) +static INLINE void SignalTcpReady(tcp_ready* ready, word16 port) { #if defined(_POSIX_THREADS) && defined(NO_MAIN_DRIVER) && \ !defined(__MINGW32__) && !defined(SINGLE_THREADED) - tcp_ready* ready = serverArgs->signal; - if (ready != NULL) { - pthread_mutex_lock(&ready->mutex); - ready->ready = 1; - ready->port = port; - pthread_cond_signal(&ready->cond); - pthread_mutex_unlock(&ready->mutex); - } + pthread_mutex_lock(&ready->mutex); + ready->ready = 1; + ready->port = port; + pthread_cond_signal(&ready->cond); + pthread_mutex_unlock(&ready->mutex); #else - (void)serverArgs; - (void)port; + WOLFSSH_UNUSED(ready); + WOLFSSH_UNUSED(port); #endif } @@ -2543,6 +2540,8 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) #endif } + SignalTcpReady(serverArgs->signal, port); + do { WS_SOCKET_T clientFd = WOLFSSH_SOCKET_INVALID; #ifdef WOLFSSL_NUCLEUS @@ -2600,8 +2599,6 @@ THREAD_RETURN WOLFSSH_THREAD echoserver_test(void* args) } #endif - SignalTcpReady(serverArgs, port); - #ifdef WOLFSSL_NUCLEUS clientFd = NU_Accept(listenFd, &clientAddr, 0); #else diff --git a/examples/include.am b/examples/include.am index 6d11933f6..fb3d8a844 100644 --- a/examples/include.am +++ b/examples/include.am @@ -3,7 +3,6 @@ # All paths should be given relative to the root include examples/client/include.am -include examples/server/include.am include examples/echoserver/include.am include examples/portfwd/include.am include examples/sftpclient/include.am diff --git a/examples/server/include.am b/examples/server/include.am deleted file mode 100644 index 9a4f0cf7f..000000000 --- a/examples/server/include.am +++ /dev/null @@ -1,10 +0,0 @@ -# vim:ft=automake -# All paths should be given relative to the root - -if BUILD_EXAMPLE_SERVERS -noinst_PROGRAMS += examples/server/server -examples_server_server_SOURCES = examples/server/server.c \ - examples/server/server.h -examples_server_server_LDADD = src/libwolfssh.la -examples_server_server_DEPENDENCIES = src/libwolfssh.la -endif diff --git a/examples/server/server.c b/examples/server/server.c deleted file mode 100644 index c74f78922..000000000 --- a/examples/server/server.c +++ /dev/null @@ -1,827 +0,0 @@ -/* server.c - * - * Copyright (C) 2014-2023 wolfSSL Inc. - * - * This file is part of wolfSSH. - * - * wolfSSH is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSSH is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with wolfSSH. If not, see . - */ - -#ifdef HAVE_CONFIG_H - #include -#endif - -#define WOLFSSH_TEST_SERVER -#define WOLFSSH_TEST_THREADING - - -#ifdef WOLFSSL_USER_SETTINGS - #include -#else - #include -#endif - -#include -#include -#include -#include -#include -#include -#include "server.h" - -#ifdef NO_FILESYSTEM - #include - #ifdef WOLFSSH_SCP - #include - #endif -#endif - - -#ifndef NO_WOLFSSH_SERVER - -static const char serverBanner[] = "wolfSSH Example Server\n"; - - -typedef struct { - WOLFSSH* ssh; - SOCKET_T fd; - word32 id; - char nonBlock; -} thread_ctx_t; - - -#ifndef EXAMPLE_HIGHWATER_MARK - #define EXAMPLE_HIGHWATER_MARK 0x3FFF8000 /* 1GB - 32kB */ -#endif -#ifndef EXAMPLE_BUFFER_SZ - #define EXAMPLE_BUFFER_SZ 4096 -#endif -#define SCRATCH_BUFFER_SZ 1200 - - -static byte find_char(const byte* str, const byte* buf, word32 bufSz) -{ - const byte* cur; - - while (bufSz) { - cur = str; - while (*cur != '\0') { - if (*cur == *buf) - return *cur; - cur++; - } - buf++; - bufSz--; - } - - return 0; -} - - -static int dump_stats(thread_ctx_t* ctx) -{ - char stats[1024]; - word32 statsSz; - word32 txCount, rxCount, seq, peerSeq; - - wolfSSH_GetStats(ctx->ssh, &txCount, &rxCount, &seq, &peerSeq); - - WSNPRINTF(stats, sizeof(stats), - "Statistics for Thread #%u:\r\n" - " txCount = %u\r\n rxCount = %u\r\n" - " seq = %u\r\n peerSeq = %u\r\n", - ctx->id, txCount, rxCount, seq, peerSeq); - statsSz = (word32)strlen(stats); - - fprintf(stderr, "%s", stats); - return wolfSSH_stream_send(ctx->ssh, (byte*)stats, statsSz); -} - - -static int NonBlockSSH_accept(WOLFSSH* ssh) -{ - int ret; - int error; - SOCKET_T sockfd; - int select_ret = 0; - - ret = wolfSSH_accept(ssh); - error = wolfSSH_get_error(ssh); - sockfd = (SOCKET_T)wolfSSH_get_fd(ssh); - - while (ret != WS_SUCCESS && - (error == WS_WANT_READ || error == WS_WANT_WRITE)) - { - if (error == WS_WANT_READ) - printf("... client would read block\n"); - else if (error == WS_WANT_WRITE) - printf("... client would write block\n"); - - select_ret = tcp_select(sockfd, 1); - if (select_ret == WS_SELECT_RECV_READY || - select_ret == WS_SELECT_ERROR_READY || - error == WS_WANT_WRITE) - { - ret = wolfSSH_accept(ssh); - error = wolfSSH_get_error(ssh); - } - else if (select_ret == WS_SELECT_TIMEOUT) - error = WS_WANT_READ; - else - error = WS_FATAL_ERROR; - } - - return ret; -} - - -static THREAD_RETURN WOLFSSH_THREAD server_worker(void* vArgs) -{ - int ret; - thread_ctx_t* threadCtx = (thread_ctx_t*)vArgs; - -#if defined(WOLFSSH_SCP) && defined(NO_FILESYSTEM) - ScpBuffer scpBufferRecv, scpBufferSend; - byte fileBuffer[49000]; - byte fileTmp[] = "wolfSSH SCP buffer file"; - - WMEMSET(&scpBufferRecv, 0, sizeof(ScpBuffer)); - scpBufferRecv.buffer = fileBuffer; - scpBufferRecv.bufferSz = sizeof(fileBuffer); - wolfSSH_SetScpRecvCtx(threadCtx->ssh, (void*)&scpBufferRecv); - - /* make buffer file to send if asked */ - WMEMSET(&scpBufferSend, 0, sizeof(ScpBuffer)); - WMEMCPY(scpBufferSend.name, "test.txt", sizeof("test.txt")); - scpBufferSend.nameSz = WSTRLEN("test.txt"); - scpBufferSend.buffer = fileTmp; - scpBufferSend.bufferSz = sizeof(fileBuffer); - scpBufferSend.fileSz = sizeof(fileTmp); - scpBufferSend.mode = 0x1A4; - wolfSSH_SetScpSendCtx(threadCtx->ssh, (void*)&scpBufferSend); -#endif - - if (!threadCtx->nonBlock) - ret = wolfSSH_accept(threadCtx->ssh); - else - ret = NonBlockSSH_accept(threadCtx->ssh); - - if (ret == WS_SUCCESS) { - byte* buf = NULL; - byte* tmpBuf; - int bufSz, backlogSz = 0, rxSz, txSz, stop = 0, txSum; - - do { - bufSz = EXAMPLE_BUFFER_SZ + backlogSz; - - tmpBuf = (byte*)realloc(buf, bufSz); - if (tmpBuf == NULL) - stop = 1; - else - buf = tmpBuf; - - if (!stop) { - do { - rxSz = wolfSSH_stream_read(threadCtx->ssh, - buf + backlogSz, - EXAMPLE_BUFFER_SZ); - if (rxSz <= 0) - rxSz = wolfSSH_get_error(threadCtx->ssh); - } while (rxSz == WS_WANT_READ || rxSz == WS_WANT_WRITE); - - if (rxSz > 0) { - backlogSz += rxSz; - txSum = 0; - txSz = 0; - - while (backlogSz != txSum && txSz >= 0 && !stop) { - txSz = wolfSSH_stream_send(threadCtx->ssh, - buf + txSum, - backlogSz - txSum); - - if (txSz > 0) { - byte c; - const byte matches[] = { 0x03, 0x05, 0x06, 0x00 }; - - c = find_char(matches, buf + txSum, txSz); - switch (c) { - case 0x03: - stop = 1; - break; - case 0x06: - if (wolfSSH_TriggerKeyExchange(threadCtx->ssh) - != WS_SUCCESS) - stop = 1; - break; - case 0x05: - if (dump_stats(threadCtx) <= 0) - stop = 1; - break; - } - txSum += txSz; - } - else if (txSz != WS_REKEYING) - stop = 1; - } - - if (txSum < backlogSz) - memmove(buf, buf + txSum, backlogSz - txSum); - backlogSz -= txSum; - } - else - stop = 1; - } - } while (!stop); - - free(buf); - } else if (ret == WS_SCP_COMPLETE) { - printf("scp file transfer completed\n"); - #if defined(WOLFSSH_SCP) && defined(NO_FILESYSTEM) - if (scpBufferRecv.fileSz > 0) { - word32 z; - - printf("file name : %s\n", scpBufferRecv.name); - printf(" size : %d\n", scpBufferRecv.fileSz); - printf(" mode : %o\n", scpBufferRecv.mode); - printf(" mTime : %lu\n", scpBufferRecv.mTime); - printf("\n"); - - for (z = 0; z < scpBufferRecv.fileSz; z++) - printf("%c", scpBufferRecv.buffer[z]); - printf("\n"); - } - #endif - } else if (ret == WS_SFTP_COMPLETE) { - printf("Use example/echoserver/echoserver for SFTP\n"); - } - wolfSSH_stream_exit(threadCtx->ssh, 0); - WCLOSESOCKET(threadCtx->fd); - wolfSSH_free(threadCtx->ssh); - free(threadCtx); - - return 0; -} - -#ifndef NO_FILESYSTEM -static int load_file(const char* fileName, byte* buf, word32 bufSz) -{ - FILE* file; - word32 fileSz; - word32 readSz; - - if (fileName == NULL) return 0; - - if (WFOPEN(NULL, &file, fileName, "rb") != 0) - return 0; - fseek(file, 0, SEEK_END); - fileSz = (word32)ftell(file); - rewind(file); - - if (fileSz > bufSz) { - fclose(file); - return 0; - } - - readSz = (word32)fread(buf, 1, fileSz, file); - if (readSz < fileSz) { - fclose(file); - return 0; - } - - fclose(file); - - return fileSz; -} -#endif /* !NO_FILESYSTEM */ - -/* returns buffer size on success */ -static int load_key(byte isEcc, byte* buf, word32 bufSz) -{ - word32 sz = 0; - -#ifndef NO_FILESYSTEM - const char* bufName; - bufName = isEcc ? "./keys/server-key-ecc.der" : - "./keys/server-key-rsa.der" ; - sz = load_file(bufName, buf, bufSz); -#else - /* using buffers instead */ - if (isEcc) { - if ((word32)sizeof_ecc_key_der_256 > bufSz) { - return 0; - } - WMEMCPY(buf, ecc_key_der_256, sizeof_ecc_key_der_256); - sz = sizeof_ecc_key_der_256; - } - else { - if ((word32)sizeof_rsa_key_der_2048 > bufSz) { - return 0; - } - WMEMCPY(buf, rsa_key_der_2048, sizeof_rsa_key_der_2048); - sz = sizeof_rsa_key_der_2048; - } -#endif - - return sz; -} - - -static INLINE void c32toa(word32 u32, byte* c) -{ - c[0] = (u32 >> 24) & 0xff; - c[1] = (u32 >> 16) & 0xff; - c[2] = (u32 >> 8) & 0xff; - c[3] = u32 & 0xff; -} - - -/* Map user names to passwords */ -/* Use arrays for username and p. The password or public key can - * be hashed and the hash stored here. Then I won't need the type. */ -typedef struct PwMap { - byte type; - byte username[32]; - word32 usernameSz; - byte p[WC_SHA256_DIGEST_SIZE]; - struct PwMap* next; -} PwMap; - - -typedef struct PwMapList { - PwMap* head; -} PwMapList; - - -static PwMap* PwMapNew(PwMapList* list, byte type, const byte* username, - word32 usernameSz, const byte* p, word32 pSz) -{ - PwMap* map; - - map = (PwMap*)malloc(sizeof(PwMap)); - if (map != NULL) { - wc_Sha256 sha; - byte flatSz[4]; - - map->type = type; - if (usernameSz >= sizeof(map->username)) - usernameSz = sizeof(map->username) - 1; - memcpy(map->username, username, usernameSz + 1); - map->username[usernameSz] = 0; - map->usernameSz = usernameSz; - - wc_InitSha256(&sha); - c32toa(pSz, flatSz); - wc_Sha256Update(&sha, flatSz, sizeof(flatSz)); - wc_Sha256Update(&sha, p, pSz); - wc_Sha256Final(&sha, map->p); - - map->next = list->head; - list->head = map; - } - - return map; -} - - -static void PwMapListDelete(PwMapList* list) -{ - if (list != NULL) { - PwMap* head = list->head; - - while (head != NULL) { - PwMap* cur = head; - head = head->next; - memset(cur, 0, sizeof(PwMap)); - free(cur); - } - } -} - - -static const char samplePasswordBuffer[] = - "jill:upthehill\n" - "jack:fetchapail\n"; - - -static const char samplePublicKeyEccBuffer[] = - "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAA" - "BBBNkI5JTP6D0lF42tbxX19cE87hztUS6FSDoGvPfiU0CgeNSbI+aFdKIzTP5CQEJSvm25" - "qUzgDtH7oyaQROUnNvk= hansel\n" - "ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAA" - "BBBKAtH8cqaDbtJFjtviLobHBmjCtG56DMkP6A4M2H9zX2/YCg1h9bYS7WHd9UQDwXO1Hh" - "IZzRYecXh7SG9P4GhRY= gretel\n"; - - -static const char samplePublicKeyRsaBuffer[] = - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9P3ZFowOsONXHD5MwWiCciXytBRZGho" - "MNiisWSgUs5HdHcACuHYPi2W6Z1PBFmBWT9odOrGRjoZXJfDDoPi+j8SSfDGsc/hsCmc3G" - "p2yEhUZUEkDhtOXyqjns1ickC9Gh4u80aSVtwHRnJZh9xPhSq5tLOhId4eP61s+a5pwjTj" - "nEhBaIPUJO2C/M0pFnnbZxKgJlX7t1Doy7h5eXxviymOIvaCZKU+x5OopfzM/wFkey0EPW" - "NmzI5y/+pzU5afsdeEWdiQDIQc80H6Pz8fsoFPvYSG+s4/wz0duu7yeeV1Ypoho65Zr+pE" - "nIf7dO0B8EblgWt+ud+JI8wrAhfE4x hansel\n" - "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqDwRVTRVk/wjPhoo66+Mztrc31KsxDZ" - "+kAV0139PHQ+wsueNpba6jNn5o6mUTEOrxrz0LMsDJOBM7CmG0983kF4gRIihECpQ0rcjO" - "P6BSfbVTE9mfIK5IsUiZGd8SoE9kSV2pJ2FvZeBQENoAxEFk0zZL9tchPS+OCUGbK4SDjz" - "uNZl/30Mczs73N3MBzi6J1oPo7sFlqzB6ecBjK2Kpjus4Y1rYFphJnUxtKvB0s+hoaadru" - "biE57dK6BrH5iZwVLTQKux31uCJLPhiktI3iLbdlGZEctJkTasfVSsUizwVIyRjhVKmbdI" - "RGwkU38D043AR1h0mUoGCPIKuqcFMf gretel\n"; - - -static int LoadPasswordBuffer(byte* buf, word32 bufSz, PwMapList* list) -{ - char* str = (char*)buf; - char* delimiter; - char* username; - char* password; - - /* Each line of passwd.txt is in the format - * username:password\n - * This function modifies the passed-in buffer. */ - - if (list == NULL) - return -1; - - if (buf == NULL || bufSz == 0) - return 0; - - while (*str != 0) { - delimiter = strchr(str, ':'); - if (delimiter == NULL) { - return -1; - } - username = str; - *delimiter = 0; - password = delimiter + 1; - str = strchr(password, '\n'); - if (str == NULL) { - return -1; - } - *str = 0; - str++; - if (PwMapNew(list, WOLFSSH_USERAUTH_PASSWORD, - (byte*)username, (word32)strlen(username), - (byte*)password, (word32)strlen(password)) == NULL ) { - - return -1; - } - } - - return 0; -} - - -static int LoadPublicKeyBuffer(byte* buf, word32 bufSz, PwMapList* list) -{ - char* str = (char*)buf; - char* delimiter; - byte* publicKey64; - word32 publicKey64Sz; - byte* username; - word32 usernameSz; - byte publicKey[300]; - word32 publicKeySz; - - /* Each line of passwd.txt is in the format - * ssh-rsa AAAB3BASE64ENCODEDPUBLICKEYBLOB username\n - * This function modifies the passed-in buffer. */ - if (list == NULL) - return -1; - - if (buf == NULL || bufSz == 0) - return 0; - - while (*str != 0) { - /* Skip the public key type. This example will always be ssh-rsa. */ - delimiter = strchr(str, ' '); - if (delimiter == NULL) { - return -1; - } - str = delimiter + 1; - delimiter = strchr(str, ' '); - if (delimiter == NULL) { - return -1; - } - publicKey64 = (byte*)str; - *delimiter = 0; - publicKey64Sz = (word32)(delimiter - str); - str = delimiter + 1; - delimiter = strchr(str, '\n'); - if (delimiter == NULL) { - return -1; - } - username = (byte*)str; - *delimiter = 0; - usernameSz = (word32)(delimiter - str); - str = delimiter + 1; - publicKeySz = sizeof(publicKey); - - if (Base64_Decode(publicKey64, publicKey64Sz, - publicKey, &publicKeySz) != 0) { - - return -1; - } - - if (PwMapNew(list, WOLFSSH_USERAUTH_PUBLICKEY, - username, usernameSz, - publicKey, publicKeySz) == NULL ) { - - return -1; - } - } - - return 0; -} - - -static int wsUserAuth(byte authType, - WS_UserAuthData* authData, - void* ctx) -{ - PwMapList* list; - PwMap* map; - byte authHash[WC_SHA256_DIGEST_SIZE]; - - if (ctx == NULL) { - fprintf(stderr, "wsUserAuth: ctx not set"); - return WOLFSSH_USERAUTH_FAILURE; - } - - if (authType != WOLFSSH_USERAUTH_PASSWORD && - authType != WOLFSSH_USERAUTH_PUBLICKEY) { - - return WOLFSSH_USERAUTH_FAILURE; - } - - /* Hash the password or public key with its length. */ - { - wc_Sha256 sha; - byte flatSz[4]; - wc_InitSha256(&sha); - if (authType == WOLFSSH_USERAUTH_PASSWORD) { - c32toa(authData->sf.password.passwordSz, flatSz); - wc_Sha256Update(&sha, flatSz, sizeof(flatSz)); - wc_Sha256Update(&sha, - authData->sf.password.password, - authData->sf.password.passwordSz); - } - else if (authType == WOLFSSH_USERAUTH_PUBLICKEY) { - c32toa(authData->sf.publicKey.publicKeySz, flatSz); - wc_Sha256Update(&sha, flatSz, sizeof(flatSz)); - wc_Sha256Update(&sha, - authData->sf.publicKey.publicKey, - authData->sf.publicKey.publicKeySz); - } - wc_Sha256Final(&sha, authHash); - } - - list = (PwMapList*)ctx; - map = list->head; - - while (map != NULL) { - if (authData->usernameSz == map->usernameSz && - memcmp(authData->username, map->username, map->usernameSz) == 0) { - - if (authData->type == map->type) { - if (memcmp(map->p, authHash, WC_SHA256_DIGEST_SIZE) == 0) { - return WOLFSSH_USERAUTH_SUCCESS; - } - else { - return (authType == WOLFSSH_USERAUTH_PASSWORD ? - WOLFSSH_USERAUTH_INVALID_PASSWORD : - WOLFSSH_USERAUTH_INVALID_PUBLICKEY); - } - } - else { - return WOLFSSH_USERAUTH_INVALID_AUTHTYPE; - } - } - map = map->next; - } - - return WOLFSSH_USERAUTH_INVALID_USER; -} - - -static void ShowUsage(void) -{ - printf("server %s\n", LIBWOLFSSH_VERSION_STRING); - printf(" -h display this help and exit\n"); - printf(" -m allow multiple connections\n"); - printf(" -e use ECC private key\n"); - printf(" -N use non-blocking sockets\n"); -} - - -THREAD_RETURN WOLFSSH_THREAD server_test(void* args) -{ - WOLFSSH_CTX* ctx = NULL; - PwMapList pwMapList; - SOCKET_T listenFd = 0; - word32 defaultHighwater = EXAMPLE_HIGHWATER_MARK; - word32 threadCount = 0; - word16 port = wolfSshPort; - char multipleConnections = 0; - char useEcc = 0; - int ch; - char nonBlock = 0; - - int argc = ((func_args*)args)->argc; - char** argv = ((func_args*)args)->argv; - ((func_args*)args)->return_code = 0; - - while ((ch = mygetopt(argc, argv, "hmeN")) != -1) { - switch (ch) { - case 'h' : - ShowUsage(); - exit(EXIT_SUCCESS); - - case 'm' : - multipleConnections = 1; - break; - - case 'e' : - useEcc = 1; - break; - - case 'N' : - nonBlock = 1; - break; - - default: - ShowUsage(); - exit(MY_EX_USAGE); - } - } - myoptind = 0; /* reset for test cases */ - -#ifdef WOLFSSH_NO_RSA - /* If wolfCrypt isn't built with RSA, force ECC on. */ - useEcc = 1; -#endif - - if (wolfSSH_Init() != WS_SUCCESS) { - fprintf(stderr, "Couldn't initialize wolfSSH.\n"); - exit(EXIT_FAILURE); - } - - ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL); - if (ctx == NULL) { - fprintf(stderr, "Couldn't allocate SSH CTX data.\n"); - exit(EXIT_FAILURE); - } - - memset(&pwMapList, 0, sizeof(pwMapList)); - wolfSSH_SetUserAuth(ctx, wsUserAuth); - wolfSSH_CTX_SetBanner(ctx, serverBanner); - - { - const char* bufName; - byte buf[SCRATCH_BUFFER_SZ]; - word32 bufSz; - - bufSz = load_key(useEcc, buf, SCRATCH_BUFFER_SZ); - if (bufSz == 0) { - fprintf(stderr, "Couldn't load key.\n"); - exit(EXIT_FAILURE); - } - if (wolfSSH_CTX_UsePrivateKey_buffer(ctx, buf, bufSz, - WOLFSSH_FORMAT_ASN1) < 0) { - fprintf(stderr, "Couldn't use key buffer.\n"); - exit(EXIT_FAILURE); - } - - bufSz = (word32)strlen(samplePasswordBuffer); - memcpy(buf, samplePasswordBuffer, bufSz); - buf[bufSz] = 0; - LoadPasswordBuffer(buf, bufSz, &pwMapList); - - bufName = useEcc ? samplePublicKeyEccBuffer : - samplePublicKeyRsaBuffer; - bufSz = (word32)strlen(bufName); - memcpy(buf, bufName, bufSz); - buf[bufSz] = 0; - LoadPublicKeyBuffer(buf, bufSz, &pwMapList); - } - - tcp_listen(&listenFd, &port, 1); - - do { - SOCKET_T clientFd = 0; - SOCKADDR_IN_T clientAddr; - socklen_t clientAddrSz = sizeof(clientAddr); -#ifndef SINGLE_THREADED - THREAD_TYPE thread; -#endif - WOLFSSH* ssh; - thread_ctx_t* threadCtx; - - threadCtx = (thread_ctx_t*)malloc(sizeof(thread_ctx_t)); - if (threadCtx == NULL) { - fprintf(stderr, "Couldn't allocate thread context data.\n"); - exit(EXIT_FAILURE); - } - - ssh = wolfSSH_new(ctx); - if (ssh == NULL) { - fprintf(stderr, "Couldn't allocate SSH data.\n"); - exit(EXIT_FAILURE); - } - wolfSSH_SetUserAuthCtx(ssh, &pwMapList); - /* Use the session object for its own highwater callback ctx */ - if (defaultHighwater > 0) { - wolfSSH_SetHighwaterCtx(ssh, (void*)ssh); - wolfSSH_SetHighwater(ssh, defaultHighwater); - } - - clientFd = accept(listenFd, (struct sockaddr*)&clientAddr, - &clientAddrSz); - if (clientFd == -1) - err_sys("tcp accept failed"); - - if (nonBlock) - tcp_set_nonblocking(&clientFd); - - wolfSSH_set_fd(ssh, (int)clientFd); - - threadCtx->ssh = ssh; - threadCtx->fd = clientFd; - threadCtx->id = threadCount++; - threadCtx->nonBlock = nonBlock; - -#ifndef SINGLE_THREADED -#if defined(WOLFSSH_OLD_THREADING) || defined(WOLFSSL_THREAD_NO_JOIN) - if (multipleConnections) - ThreadStartNoJoin(server_worker, threadCtx); - else -#endif - { - ThreadStart(server_worker, threadCtx, &thread); - ThreadJoin(thread); - } -#else - server_worker(threadCtx); -#endif /* SINGLE_THREADED */ - } while (multipleConnections); - - PwMapListDelete(&pwMapList); - wolfSSH_CTX_free(ctx); - if (wolfSSH_Cleanup() != WS_SUCCESS) { - fprintf(stderr, "Couldn't clean up wolfSSH.\n"); - exit(EXIT_FAILURE); - } -#if !defined(WOLFSSH_NO_ECC) && defined(FP_ECC) && defined(HAVE_THREAD_LS) - wc_ecc_fp_free(); /* free per thread cache */ -#endif - - WOLFSSL_RETURN_FROM_THREAD(0); -} - -#endif /* NO_WOLFSSH_SERVER */ - - -#ifndef NO_MAIN_DRIVER - - int main(int argc, char** argv) - { - func_args args; - - args.argc = argc; - args.argv = argv; - args.return_code = 0; - - WSTARTTCP(); - - ChangeToWolfSshRoot(); - #ifdef DEBUG_WOLFSSH - wolfSSH_Debugging_ON(); - #endif - - wolfSSH_Init(); - -#ifndef NO_WOLFSSH_SERVER - server_test(&args); -#else - printf("wolfSSH compiled without server support\n"); -#endif - - wolfSSH_Cleanup(); - - return args.return_code; - } - - - int myoptind = 0; - char* myoptarg = NULL; - -#endif /* NO_MAIN_DRIVER */ diff --git a/examples/server/server.h b/examples/server/server.h deleted file mode 100644 index 6619892a3..000000000 --- a/examples/server/server.h +++ /dev/null @@ -1,29 +0,0 @@ -/* server.h - * - * Copyright (C) 2014-2023 wolfSSL Inc. - * - * This file is part of wolfSSH. - * - * wolfSSH is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * wolfSSH is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with wolfSSH. If not, see . - */ - - -#ifndef _WOLFSSH_EXAMPLES_SERVER_H_ -#define _WOLFSSH_EXAMPLES_SERVER_H_ - - -THREAD_RETURN WOLFSSH_THREAD server_test(void* args); - - -#endif /* _WOLFSSH_EXAMPLES_SERVER_H_ */ diff --git a/notes.md b/notes.md deleted file mode 100644 index 61b98d76a..000000000 --- a/notes.md +++ /dev/null @@ -1,35 +0,0 @@ -wolfssh notes -============= - -coding standard ---------------- - -1. Exceptions are allowed with good reason. - -2. Follow the existing style. - -3. Try not to shorthand variables, except for ijk as indicies. - -4. Lengths of arrays should have the array name followed by Sz. - -5. Single return per function. - -6. Check all incoming parameters. - -7. No gotos. - -8. Check all return codes. It feels a little tedious, but the preferred method -is running checks against success. This way if a function returns an error, the -code will drop to the end. - -``` - ret = functionCall(parameter); - if (ret == SUCCESS) - ret = secondFunctionCall(otherParameter); - if (ret == SUCCESS) - ret = thirdFunctionCall(aParameter, anotherParameter); - cleanUp(); - return ret; -``` - - diff --git a/src/internal.c b/src/internal.c index 987e670b0..7c1791155 100644 --- a/src/internal.c +++ b/src/internal.c @@ -7134,6 +7134,249 @@ static int DoChannelClose(WOLFSSH* ssh, } +#if !defined(NO_TERMIOS) && defined(WOLFSSH_TERM) +#if defined(HAVE_SYS_IOCTL_H) + +#define TTY_SET_CHAR(x,y,z) (x)[(y)] = (byte)(z) +#define TTY_SET_FLAG(x,y,z) (x) = (z) ? ((x) | (y)) : ((x) & ~(y)) + +int wolfSSH_DoModes(const byte* modes, word32 modesSz, int fd) +{ + WOLFSSH_TERMIOS term; + word32 idx = 0, arg; + + if (!modes || !modesSz || (modesSz % TERMINAL_MODE_SZ > 1)) + return -1; + /* + * Modes is a list of opcode-argument pairs. The opcodes are + * bytes and the arguments are uint32s. TTY_OP_END is an opcode + * that terminates the list. Of course, it isn't clear if + * TTY_OP_END has an arguement or note. The RFC doesn't say, + * but in operation it usually doesn't. Allow for an odd single + * byte left over. + */ + + tcgetattr(fd, &term); + + while (idx < modesSz && modes[idx] != WOLFSSH_TTY_OP_END + && modes[idx] < WOLFSSH_TTY_INVALID) { + + ato32(modes + idx + 1, &arg); + + switch (modes[idx]) { + /* Special Control Characters (c_cc) */ + case WOLFSSH_VINTR: + TTY_SET_CHAR(term.c_cc, VINTR, arg); + break; + case WOLFSSH_VQUIT: + TTY_SET_CHAR(term.c_cc, VQUIT, arg); + break; + case WOLFSSH_VERASE: + TTY_SET_CHAR(term.c_cc, VERASE, arg); + break; + case WOLFSSH_VKILL: + TTY_SET_CHAR(term.c_cc, VKILL, arg); + break; + case WOLFSSH_VEOF: + TTY_SET_CHAR(term.c_cc, VEOF, arg); + break; + case WOLFSSH_VEOL: + TTY_SET_CHAR(term.c_cc, VEOL, arg); + break; + case WOLFSSH_VEOL2: + TTY_SET_CHAR(term.c_cc, VEOL2, arg); + break; + case WOLFSSH_VSTART: + TTY_SET_CHAR(term.c_cc, VSTART, arg); + break; + case WOLFSSH_VSTOP: + TTY_SET_CHAR(term.c_cc, VSTOP, arg); + break; + case WOLFSSH_VSUSP: + TTY_SET_CHAR(term.c_cc, VSUSP, arg); + break; + case WOLFSSH_VDSUSP: + #ifdef VDSUSP + TTY_SET_CHAR(term.c_cc, VDSUSP, arg); + #endif + break; + case WOLFSSH_VREPRINT: + TTY_SET_CHAR(term.c_cc, VREPRINT, arg); + break; + case WOLFSSH_VWERASE: + TTY_SET_CHAR(term.c_cc, VWERASE, arg); + break; + case WOLFSSH_VLNEXT: + TTY_SET_CHAR(term.c_cc, VLNEXT, arg); + break; + case WOLFSSH_VFLUSH: + #ifdef VFLUSH + TTY_SET_CHAR(term.c_cc, VFLUSH, arg); + #endif + break; + case WOLFSSH_VSWTCH: + #ifdef VSWTCH + TTY_SET_CHAR(term.c_cc, VSWTCH, arg); + #endif + break; + case WOLFSSH_VSTATUS: + #ifdef VSTATUS + TTY_SET_CHAR(term.c_cc, VSTATUS, arg); + #endif + break; + case WOLFSSH_VDISCARD: + TTY_SET_CHAR(term.c_cc, VDISCARD, arg); + break; + + /* Input Modes (c_iflag) */ + case WOLFSSH_IGNPAR: + TTY_SET_FLAG(term.c_iflag, IGNPAR, arg); + break; + case WOLFSSH_PARMRK: + TTY_SET_FLAG(term.c_iflag, PARMRK, arg); + break; + case WOLFSSH_INPCK: + TTY_SET_FLAG(term.c_iflag, INPCK, arg); + break; + case WOLFSSH_ISTRIP: + TTY_SET_FLAG(term.c_iflag, ISTRIP, arg); + break; + case WOLFSSH_INLCR: + TTY_SET_FLAG(term.c_iflag, INLCR, arg); + break; + case WOLFSSH_IGNCR: + TTY_SET_FLAG(term.c_iflag, IGNCR, arg); + break; + case WOLFSSH_ICRNL: + TTY_SET_FLAG(term.c_iflag, ICRNL, arg); + break; + case WOLFSSH_IUCLC: + #ifdef IUCLC + TTY_SET_FLAG(term.c_iflag, IUCLC, arg); + #endif + break; + case WOLFSSH_IXON: + TTY_SET_FLAG(term.c_iflag, IXON, arg); + break; + case WOLFSSH_IXANY: + TTY_SET_FLAG(term.c_iflag, IXANY, arg); + break; + case WOLFSSH_IXOFF: + TTY_SET_FLAG(term.c_iflag, IXOFF, arg); + break; + case WOLFSSH_IMAXBEL: + TTY_SET_FLAG(term.c_iflag, IMAXBEL, arg); + break; + case WOLFSSH_IUTF8: + #ifdef IUTF8 + TTY_SET_FLAG(term.c_iflag, IUTF8, arg); + #endif + break; + + /* Local Modes (c_lflag) */ + case WOLFSSH_ISIG: + TTY_SET_FLAG(term.c_lflag, ISIG, arg); + break; + case WOLFSSH_ICANON: + TTY_SET_FLAG(term.c_lflag, ICANON, arg); + break; + case WOLFSSH_XCASE: + #ifdef XCASE + TTY_SET_FLAG(term.c_lflag, XCASE, arg); + #endif + break; + case WOLFSSH_ECHO: + TTY_SET_FLAG(term.c_lflag, ECHO, arg); + break; + case WOLFSSH_ECHOE: + TTY_SET_FLAG(term.c_lflag, ECHOE, arg); + break; + case WOLFSSH_ECHOK: + TTY_SET_FLAG(term.c_lflag, ECHOK, arg); + break; + case WOLFSSH_ECHONL: + TTY_SET_FLAG(term.c_lflag, ECHONL, arg); + break; + case WOLFSSH_NOFLSH: + TTY_SET_FLAG(term.c_lflag, NOFLSH, arg); + break; + case WOLFSSH_TOSTOP: + TTY_SET_FLAG(term.c_lflag, TOSTOP, arg); + break; + case WOLFSSH_IEXTEN: + TTY_SET_FLAG(term.c_lflag, IEXTEN, arg); + break; + case WOLFSSH_ECHOCTL: + TTY_SET_FLAG(term.c_lflag, ECHOCTL, arg); + break; + case WOLFSSH_ECHOKE: + TTY_SET_FLAG(term.c_lflag, ECHOKE, arg); + break; + case WOLFSSH_PENDIN: + #ifdef PENDIN + TTY_SET_FLAG(term.c_lflag, PENDIN, arg); + #endif + break; + + /* Output Modes (c_oflag) */ + case WOLFSSH_OPOST: + TTY_SET_FLAG(term.c_lflag, OPOST, arg); + break; + case WOLFSSH_OLCUC: + #ifdef OLCUC + TTY_SET_FLAG(term.c_lflag, OLCUC, arg); + #endif + break; + case WOLFSSH_ONLCR: + TTY_SET_FLAG(term.c_lflag, ONLCR, arg); + break; + case WOLFSSH_OCRNL: + TTY_SET_FLAG(term.c_lflag, OCRNL, arg); + break; + case WOLFSSH_ONOCR: + TTY_SET_FLAG(term.c_lflag, ONOCR, arg); + break; + case WOLFSSH_ONLRET: + TTY_SET_FLAG(term.c_lflag, ONLRET, arg); + break; + + /* Control Modes (c_cflag) */ + case WOLFSSH_CS7: + TTY_SET_FLAG(term.c_cflag, CS7, arg); + break; + case WOLFSSH_CS8: + TTY_SET_FLAG(term.c_cflag, CS8, arg); + break; + case WOLFSSH_PARENB: + TTY_SET_FLAG(term.c_cflag, PARENB, arg); + break; + case WOLFSSH_PARODD: + TTY_SET_FLAG(term.c_cflag, PARODD, arg); + break; + + /* Baud Rates */ + case WOLFSSH_TTY_OP_ISPEED: + cfsetispeed(&term, (speed_t)arg); + break; + case WOLFSSH_TTY_OP_OSPEED: + cfsetospeed(&term, (speed_t)arg); + break; + + default: + break; + } + idx += TERMINAL_MODE_SZ; + } + + tcsetattr(fd, TCSANOW, &term); + + return 0; +} + +#endif /* HAVE_SYS_IOCTL_H */ +#endif /* !NO_TERMIOS && WOLFSSH_TERM */ + + static int DoChannelRequest(WOLFSSH* ssh, byte* buf, word32 len, word32* idx) { @@ -7191,24 +7434,27 @@ static int DoChannelRequest(WOLFSSH* ssh, ret = GetUint32(&heightPixels, buf, len, &begin); if (ret == WS_SUCCESS) ret = GetStringRef(&modesSz, &modes, buf, len, &begin); - - WOLFSSH_UNUSED(modes); - WOLFSSH_UNUSED(modesSz); - if (ret == WS_SUCCESS) { + ssh->modes = (byte*)WMALLOC(modesSz, ssh->ctx->heap, 0); + if (ssh->modes == NULL) + ret = WS_MEMORY_E; + } + if (ret == WS_SUCCESS) { + ssh->modesSz = modesSz; + WMEMCPY(ssh->modes, modes, modesSz); WLOG(WS_LOG_DEBUG, " term = %s", term); WLOG(WS_LOG_DEBUG, " widthChar = %u", widthChar); WLOG(WS_LOG_DEBUG, " heightRows = %u", heightRows); WLOG(WS_LOG_DEBUG, " widthPixels = %u", widthPixels); WLOG(WS_LOG_DEBUG, " heightPixels = %u", heightPixels); - ssh->curX = widthChar; - ssh->curY = heightRows; - ssh->curXP = widthPixels; - ssh->curYP = heightPixels; + ssh->widthChar = widthChar; + ssh->heightRows = heightRows; + ssh->widthPixels = widthPixels; + ssh->heightPixels = heightPixels; if (ssh->termResizeCb) { if (ssh->termResizeCb(ssh, widthChar, heightRows, - widthPixels, heightPixels, ssh->termCtx) - != WS_SUCCESS) { + widthPixels, heightPixels, + ssh->termCtx) != WS_SUCCESS) { ret = WS_FATAL_ERROR; } } @@ -7278,11 +7524,14 @@ static int DoChannelRequest(WOLFSSH* ssh, WLOG(WS_LOG_DEBUG, " heightRows = %u", heightRows); WLOG(WS_LOG_DEBUG, " widthPixels = %u", widthPixels); WLOG(WS_LOG_DEBUG, " heightPixels = %u", heightPixels); - ssh->curX = widthChar; - ssh->curY = heightRows; + ssh->widthChar = widthChar; + ssh->heightRows = heightRows; + ssh->widthPixels = widthPixels; + ssh->heightPixels = heightPixels; if (ssh->termResizeCb) { - if (ssh->termResizeCb(ssh, widthChar, heightRows, widthPixels, - heightPixels, ssh->termCtx) != WS_SUCCESS) { + if (ssh->termResizeCb(ssh, widthChar, heightRows, + widthPixels, heightPixels, + ssh->termCtx) != WS_SUCCESS) { ret = WS_FATAL_ERROR; } } diff --git a/sshd_config b/sshd_config new file mode 100644 index 000000000..e69de29bb diff --git a/tests/api.c b/tests/api.c index 9353c4d2b..c417a1c56 100644 --- a/tests/api.c +++ b/tests/api.c @@ -974,7 +974,7 @@ static void test_wolfSSH_SFTP_SendReadPacket(void) ser.signal = &ready; InitTcpReady(ser.signal); ThreadStart(echoserver_test, (void*)&ser, &serThread); - WaitTcpReady(&ser); + WaitTcpReady(&ready); sftp_client_connect(&ctx, &ssh, ready.port); AssertNotNull(ctx); diff --git a/tests/sftp.c b/tests/sftp.c index ef19ca0b7..36b2cb081 100644 --- a/tests/sftp.c +++ b/tests/sftp.c @@ -208,7 +208,7 @@ int wolfSSH_SftpTest(int flag) ser.signal = &ready; InitTcpReady(ser.signal); ThreadStart(echoserver_test, (void*)&ser, &serThread); - WaitTcpReady(&ser); + WaitTcpReady(&ready); argsCount = 0; args[argsCount++] = "."; @@ -216,10 +216,10 @@ int wolfSSH_SftpTest(int flag) args[argsCount++] = "jill"; args[argsCount++] = "-P"; args[argsCount++] = "upthehill"; - args[argsCount++] = "-p"; #ifndef USE_WINDOWS_API /* use port that server has found */ + args[argsCount++] = "-p"; snprintf(portNumber, sizeof(portNumber), "%d", ready.port); args[argsCount++] = portNumber; #endif @@ -240,6 +240,7 @@ int wolfSSH_SftpTest(int flag) ThreadJoin(serThread); wolfSSH_Cleanup(); + FreeTcpReady(&ready); return ret; } diff --git a/tests/testsuite.c b/tests/testsuite.c index 8ee4a7c38..c9441b24d 100644 --- a/tests/testsuite.c +++ b/tests/testsuite.c @@ -145,7 +145,7 @@ int wolfSSH_TestsuiteTest(int argc, char** argv) serverArgs.signal = &ready; serverArgs.user_auth = NULL; ThreadStart(echoserver_test, &serverArgs, &serverThread); - WaitTcpReady(&serverArgs); + WaitTcpReady(&ready); WSTRNCPY(cA[clientArgc++], "client", ARGLEN); WSTRNCPY(cA[clientArgc++], "-u", ARGLEN); diff --git a/wolfssh/internal.h b/wolfssh/internal.h index 3cd5b3776..c31b229e7 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -378,6 +378,7 @@ enum { #define UINT32_SZ 4 #define LENGTH_SZ UINT32_SZ #define SSH_PROTO_SZ 7 /* "SSH-2.0" */ +#define TERMINAL_MODE_SZ 5 /* opcode byte + argument uint32 */ #define AEAD_IMP_IV_SZ 4 #define AEAD_EXP_IV_SZ 8 #define AEAD_NONCE_SZ (AEAD_IMP_IV_SZ+AEAD_EXP_IV_SZ) @@ -814,10 +815,12 @@ struct WOLFSSH { #ifdef WOLFSSH_TERM WS_CallbackTerminalSize termResizeCb; void* termCtx; - word32 curX; /* current terminal width */ - word32 curY; /* current terminal height */ - word32 curXP; /* pixel width */ - word32 curYP; /* pixel height */ + word32 widthChar; /* current terminal width */ + word32 heightRows; /* current terminal height */ + word32 widthPixels; /* pixel width */ + word32 heightPixels; /* pixel height */ + byte* modes; + word32 modesSz; #endif }; @@ -1262,7 +1265,8 @@ enum TerminalModes { WOLFSSH_PARENB, WOLFSSH_PARODD, WOLFSSH_TTY_OP_ISPEED = 128, - WOLFSSH_TTY_OP_OSPEED + WOLFSSH_TTY_OP_OSPEED, + WOLFSSH_TTY_INVALID = 160 }; #endif /* WOLFSSH_TERM */ diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h index ab315daad..10da1f1c7 100644 --- a/wolfssh/ssh.h +++ b/wolfssh/ssh.h @@ -282,6 +282,7 @@ typedef enum { WOLFSSH_SESSION_TERMINAL, } WS_SessionType; +WOLFSSH_API int wolfSSH_DoModes(const byte* modes, word32 modesSz, int fd); WOLFSSH_API WS_SessionType wolfSSH_GetSessionType(const WOLFSSH*); WOLFSSH_API const char* wolfSSH_GetSessionCommand(const WOLFSSH*); WOLFSSH_API int wolfSSH_SetChannelType(WOLFSSH*, byte, byte*, word32); diff --git a/wolfssh/test.h b/wolfssh/test.h index 9b767f08c..cf276b102 100644 --- a/wolfssh/test.h +++ b/wolfssh/test.h @@ -850,8 +850,8 @@ static INLINE void InitTcpReady(tcp_ready* ready) ready->srfName = NULL; #if defined(_POSIX_THREADS) && defined(NO_MAIN_DRIVER) && \ !defined(__MINGW32__) && !defined(SINGLE_THREADED) - pthread_mutex_init(&ready->mutex, 0); - pthread_cond_init(&ready->cond, 0); + pthread_mutex_init(&ready->mutex, NULL); + pthread_cond_init(&ready->cond, NULL); #endif } @@ -863,24 +863,30 @@ static INLINE void FreeTcpReady(tcp_ready* ready) pthread_mutex_destroy(&ready->mutex); pthread_cond_destroy(&ready->cond); #else - (void)ready; + WOLFSSH_UNUSED(ready); #endif } -static INLINE void WaitTcpReady(func_args* args) +static INLINE void WaitTcpReady(tcp_ready* ready) { #if defined(_POSIX_THREADS) && defined(NO_MAIN_DRIVER) && \ !defined(__MINGW32__) && !defined(SINGLE_THREADED) - pthread_mutex_lock(&args->signal->mutex); + pthread_mutex_lock(&ready->mutex); - if (!args->signal->ready) - pthread_cond_wait(&args->signal->cond, &args->signal->mutex); - args->signal->ready = 0; /* reset */ + while (!ready->ready) { + pthread_cond_wait(&ready->cond, &ready->mutex); + } - pthread_mutex_unlock(&args->signal->mutex); + pthread_mutex_unlock(&ready->mutex); +#ifdef WOLFSSH_ZEPHYR + /* It's like the server isn't ready to accept connections it is + * listening for despite this conditional variable. A 300ms wait + * seems to help. This is not ideal. (XXX) */ + k_sleep(Z_TIMEOUT_TICKS(300)); +#endif /* WOLFSSH_ZEPHYR */ #else - (void)args; + WOLFSSH_UNUSED(ready); #endif }