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
}