From ab742ca766794bb5911a232f3c9bff425a0ebb44 Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Mon, 24 Apr 2023 06:42:53 -0600 Subject: [PATCH 01/11] wolfSSHd port to Windows handling of terminal size adjustments stub case for ECH virtual terminal command --- .gitignore | 1 + apps/wolfsshd/auth.c | 632 +++++++++++++--- apps/wolfsshd/auth.h | 8 +- apps/wolfsshd/configuration.c | 18 +- apps/wolfsshd/wolfsshd.c | 891 ++++++++++++++++++++--- examples/client/client.c | 119 ++- examples/scpclient/scpclient.c | 17 +- examples/sftpclient/sftpclient.c | 11 +- ide/winvs/README.md | 16 + ide/winvs/include.am | 2 + ide/winvs/user_settings.h | 52 +- ide/winvs/wolfssh.sln | 21 + ide/winvs/wolfssh/wolfssh.vcxproj | 4 +- ide/winvs/wolfsshd/wolfsshd.vcxproj | 152 ++++ ide/winvs/wolfsshd/wolfsshd.vcxproj.user | 13 + src/internal.c | 146 +++- src/ssh.c | 35 + src/wolfscp.c | 122 +++- src/wolfsftp.c | 7 +- src/wolfterm.c | 5 + wolfssh/internal.h | 8 + wolfssh/port.h | 10 +- wolfssh/ssh.h | 6 + wolfssh/wolfscp.h | 11 +- 24 files changed, 2029 insertions(+), 278 deletions(-) create mode 100644 ide/winvs/wolfsshd/wolfsshd.vcxproj create mode 100644 ide/winvs/wolfsshd/wolfsshd.vcxproj.user diff --git a/.gitignore b/.gitignore index 865755744..6f0f4214a 100644 --- a/.gitignore +++ b/.gitignore @@ -76,6 +76,7 @@ client.plist *.vcxproj.filters *.opensdf *.pdb +.vs Debug Release DLL Debug diff --git a/apps/wolfsshd/auth.c b/apps/wolfsshd/auth.c index 89adb5ce3..f260ff3a8 100644 --- a/apps/wolfsshd/auth.c +++ b/apps/wolfsshd/auth.c @@ -22,6 +22,10 @@ #include #endif +#ifdef WOLFSSL_USER_SETTINGS + #include +#endif + #ifdef WOLFSSH_SSHD #ifdef __linux__ @@ -30,7 +34,10 @@ #define _GNU_SOURCE #endif #endif + +#ifndef _WIN32 #include +#endif #include #include @@ -69,6 +76,9 @@ struct WOLFSSHD_AUTH { CallbackCheckPassword checkPasswordCb; CallbackCheckPublicKey checkPublicKeyCb; const WOLFSSHD_CONFIG* conf; +#if defined(_WIN32) + HANDLE token; /* a users token */ +#endif int gid; int uid; int sGid; /* saved gid */ @@ -143,12 +153,13 @@ static int CheckAuthKeysLine(char* line, word32 lineSz, const byte* key, word32 keySz) { int ret = WSSHD_AUTH_SUCCESS; - char* type; - char* keyCandBase64; /* cand == candidate */ + char* type = NULL; + char* keyCandBase64 = NULL; /* cand == candidate */ word32 keyCandBase64Sz; byte* keyCand = NULL; - word32 keyCandSz; - char* last; + word32 keyCandSz = 0; + char* last = NULL; + enum { #ifdef WOLFSSH_CERTS NUM_ALLOWED_TYPES = 9 @@ -329,7 +340,7 @@ static int CheckPasswordHashUnix(const char* input, char* stored) } #endif /* WOLFSSH_HAVE_LIBCRYPT || WOLFSSH_HAVE_LIBLOGIN */ -static int CheckPasswordUnix(const char* usr, const byte* pw, word32 pwSz) +static int CheckPasswordUnix(const char* usr, const byte* pw, word32 pwSz, WOLFSSHD_AUTH* authCtx) { int ret = WS_SUCCESS; char* pwStr = NULL; @@ -413,35 +424,16 @@ static int CheckPasswordUnix(const char* usr, const byte* pw, word32 pwSz) WFREE(storedHashCpy, NULL, DYNTYPE_STRING); } + WOLFSSH_UNUSED(authCtx); return ret; } #endif /* WOLFSSH_USE_PAM */ #endif /* !_WIN32 */ -#ifndef _WIN32 -static int CheckUserUnix(const char* name) { - int ret = WSSHD_AUTH_FAILURE; - struct passwd* pwInfo; - - wolfSSH_Log(WS_LOG_INFO, "[SSHD] Unix check user"); - errno = 0; - pwInfo = getpwnam(name); - if (pwInfo == NULL) { - if (errno != 0) { - wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error calling getpwnam for user " - "%s.", name); - ret = WS_FATAL_ERROR; - } - } - else { - ret = WSSHD_AUTH_SUCCESS; - } - return ret; -} static const char authKeysDefault[] = ".ssh/authorized_keys"; -static char authKeysPattern[MAX_PATH_SZ] = {0}; +static char authKeysPattern[MAX_PATH_SZ] = { 0 }; void SetAuthKeysPattern(const char* pattern) { @@ -451,6 +443,7 @@ void SetAuthKeysPattern(const char* pattern) } } + static int ResolveAuthKeysPath(const char* homeDir, char* resolved) { int ret = WS_SUCCESS; @@ -481,7 +474,7 @@ static int ResolveAuthKeysPath(const char* homeDir, char* resolved) if (homeDirSz + 1 + WSTRLEN(suffix) >= MAX_PATH_SZ) { wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Path for key file larger than max allowed"); - ret = WS_FATAL_ERROR; + ret = WS_FATAL_ERROR; } if (ret == WS_SUCCESS) { @@ -496,23 +489,111 @@ static int ResolveAuthKeysPath(const char* homeDir, char* resolved) return ret; } -static int CheckPublicKeyUnix(const char* name, - const WS_UserAuthData_PublicKey* pubKeyCtx, - const char* usrCaKeysFile) +static int SearchForPubKey(const char* path, const WS_UserAuthData_PublicKey* pubKeyCtx) { int ret = WSSHD_AUTH_SUCCESS; - int rc; - struct passwd* pwInfo; - char* authKeysFile = NULL; - XFILE f = XBADFILE; + char authKeysPath[MAX_PATH_SZ]; + WFILE *f = XBADFILE; char* lineBuf = NULL; char* current; word32 currentSz; int foundKey = 0; - char authKeysPath[MAX_PATH_SZ]; + int rc = 0; + + WMEMSET(authKeysPath, 0, sizeof(authKeysPath)); + rc = ResolveAuthKeysPath(path, authKeysPath); + if (rc != WS_SUCCESS) { + wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Failed to resolve authorized keys" + " file path."); + ret = rc; + } + + if (ret == WSSHD_AUTH_SUCCESS) { + if (WFOPEN(&f, authKeysPath, "rb") != 0) { + wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Unable to open %s", + authKeysPath); + ret = WS_BAD_FILE_E; + } + } + if (ret == WSSHD_AUTH_SUCCESS) { + lineBuf = (char*)WMALLOC(MAX_LINE_SZ, NULL, DYNTYPE_BUFFER); + if (lineBuf == NULL) { + ret = WS_MEMORY_E; + } + } + while (ret == WSSHD_AUTH_SUCCESS && + (current = XFGETS(lineBuf, MAX_LINE_SZ, f)) != NULL) { + currentSz = (word32)XSTRLEN(current); + + /* remove leading spaces */ + while (currentSz > 0 && current[0] == ' ') { + currentSz = currentSz - 1; + current = current + 1; + } + + if (currentSz <= 1) { + continue; /* empty line */ + } + + if (current[0] == '#') { + continue; /* commented out line */ + } + + rc = CheckAuthKeysLine(current, currentSz, pubKeyCtx->publicKey, + pubKeyCtx->publicKeySz); + if (rc == WSSHD_AUTH_SUCCESS) { + foundKey = 1; + break; + } + else if (rc < 0) { + ret = rc; + break; + } + } + + if (f != XBADFILE) { + WFCLOSE(f); + } + + if (ret == WSSHD_AUTH_SUCCESS && !foundKey) { + ret = WSSHD_AUTH_FAILURE; + } + + return ret; +} + +#ifndef _WIN32 +static int CheckUserUnix(const char* name) { + int ret = WSSHD_AUTH_FAILURE; + struct passwd* pwInfo; + + wolfSSH_Log(WS_LOG_INFO, "[SSHD] Unix check user"); + errno = 0; + pwInfo = getpwnam(name); + if (pwInfo == NULL) { + if (errno != 0) { + wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error calling getpwnam for user " + "%s.", name); + ret = WS_FATAL_ERROR; + } + } + else { + ret = WSSHD_AUTH_SUCCESS; + } + + return ret; +} + +static int CheckPublicKeyUnix(const char* name, + const WS_UserAuthData_PublicKey* pubKeyCtx, + const char* usrCaKeysFile, WOLFSSHD_AUTH* authCtx) +{ + int ret = WSSHD_AUTH_SUCCESS; + struct passwd* pwInfo; #ifdef WOLFSSH_OSSH_CERTS if (pubKeyCtx->isOsshCert) { + int rc; byte* caKey = NULL; word32 caKeySz; const byte* caKeyType = NULL; @@ -584,80 +665,353 @@ static int CheckPublicKeyUnix(const char* name, } if (ret == WSSHD_AUTH_SUCCESS) { - WMEMSET(authKeysPath, 0, sizeof(authKeysPath)); - rc = ResolveAuthKeysPath(pwInfo->pw_dir, authKeysPath); - if (rc != WS_SUCCESS) { - wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Failed to resolve authorized keys" - " file path."); - ret = rc; - } + ret = SearchForPubKey(pwInfo->pw_dir, pubKeyCtx); } - if (ret == WSSHD_AUTH_SUCCESS) { - f = XFOPEN(authKeysPath, "rb"); - if (f == XBADFILE) { - wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Unable to open %s", - authKeysPath); - ret = WS_BAD_FILE_E; - } + } + + WOLFSSH_UNUSED(usrCaKeysFile); + WOLFSSH_UNUSED(authCtx); + return ret; +} +#endif /* !_WIN32*/ + +#ifdef _WIN32 + +#include +#include +#include + +#include +#include +#define MAX_USERNAME 256 + +static int _GetHomeDirectory(WOLFSSHD_AUTH* auth, const char* usr, WCHAR* out, int outSz) +{ + int ret = WS_SUCCESS; + WCHAR usrW[MAX_USERNAME]; + wchar_t* homeDir; + HRESULT hr; + size_t wr; + + /* convert user name to Windows wchar type */ + mbstowcs_s(&wr, usrW, MAX_USERNAME, usr, MAX_USERNAME-1); + + hr = SHGetKnownFolderPath((REFKNOWNFOLDERID)&FOLDERID_Profile, + 0, wolfSSHD_GetAuthToken(auth), &homeDir); + if (SUCCEEDED(hr)) { + wcscpy_s(out, outSz, homeDir); + CoTaskMemFree(homeDir); + } + else { + PROFILEINFO pInfo = { sizeof(PROFILEINFO) }; + + /* failed with get known folder path, try with loading the user profile */ + pInfo.dwFlags = PI_NOUI; + pInfo.lpUserName = usrW; + if (LoadUserProfileW(wolfSSHD_GetAuthToken(auth), &pInfo) != TRUE) { + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Error %d loading user %s", GetLastError(), usr); + ret = WS_FATAL_ERROR; } - if (ret == WSSHD_AUTH_SUCCESS) { - lineBuf = (char*)WMALLOC(MAX_LINE_SZ, NULL, DYNTYPE_BUFFER); - if (lineBuf == NULL) { - ret = WS_MEMORY_E; - } + + /* get home directory env. for user */ + if (ret == WS_SUCCESS && + ExpandEnvironmentStringsW(L"%USERPROFILE%", out, outSz) == 0) { + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Error getting user %s's home path", usr); + ret = WS_FATAL_ERROR; } - while (ret == WSSHD_AUTH_SUCCESS && - (current = XFGETS(lineBuf, MAX_LINE_SZ, f)) != NULL) { - currentSz = (word32)XSTRLEN(current); - /* remove leading spaces */ - while (currentSz > 0 && current[0] == ' ') { - currentSz = currentSz - 1; - current = current + 1; - } + /* @TODO is unload of user needed here? + UnloadUserProfileW(wolfSSHD_GetAuthToken(conn->auth), pInfo.hProfile); + */ + } - if (currentSz <= 1) { - continue; /* empty line */ - } + return ret; +} - if (current[0] == '#') { - continue; /* commented out line */ - } - rc = CheckAuthKeysLine(current, currentSz, pubKeyCtx->publicKey, - pubKeyCtx->publicKeySz); - if (rc == WSSHD_AUTH_SUCCESS) { - foundKey = 1; - break; - } - else if (rc < 0) { - ret = rc; - break; - } +int wolfSSHD_GetHomeDirectory(WOLFSSHD_AUTH* auth, WOLFSSH* ssh, WCHAR* out, int outSz) +{ + return _GetHomeDirectory(auth, wolfSSH_GetUsername(ssh), out, outSz); +} + + +/* Returns the users token from LogonUserW call */ +HANDLE wolfSSHD_GetAuthToken(const WOLFSSHD_AUTH* auth) +{ + if (auth == NULL) + return NULL; + return auth->token; +} + +static int CheckPasswordWIN(const char* usr, const byte* pw, word32 pwSz, WOLFSSHD_AUTH* authCtx) +{ + int ret; + WCHAR* usrW = NULL; + WCHAR* pwW = NULL; + WCHAR dmW[] = L"."; /* currently hard set to use local domain */ + size_t usrWSz = 0; + int pwWSz = 0; + + wolfSSH_Log(WS_LOG_INFO, "[SSHD] Windows check password"); + + ret = WSSHD_AUTH_SUCCESS; + + usrWSz = WSTRLEN(usr) * sizeof(WCHAR); + + usrW = (WCHAR*)WMALLOC(usrWSz + 1, authCtx->heap, DYNTYPE_SSHD); + if (usrW == NULL) { + wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Ran out of memory"); + ret = WSSHD_AUTH_FAILURE; + } + + if (ret == WSSHD_AUTH_SUCCESS) { + size_t wr = 0; + if (mbstowcs_s(&wr, usrW, usrWSz, usr, usrWSz-1) != 0) { + ret = WSSHD_AUTH_FAILURE; } } - if (f != XBADFILE) { - XFCLOSE(f); + if (ret == WSSHD_AUTH_SUCCESS) { + pwWSz = MultiByteToWideChar(CP_UTF8, 0, pw, pwSz, NULL, 0); + if (pwWSz <= 0) { + ret = WSSHD_AUTH_FAILURE; + } } - if (ret == WSSHD_AUTH_SUCCESS && !foundKey) { - ret = WSSHD_AUTH_FAILURE; + if (ret == WSSHD_AUTH_SUCCESS) { + pwW = (WCHAR*)WMALLOC((pwWSz * sizeof(WCHAR)) + sizeof(WCHAR), authCtx->heap, DYNTYPE_SSHD); + if (pwW == NULL) { + ret = WSSHD_AUTH_FAILURE; + } + } + + if (ret == WSSHD_AUTH_SUCCESS) { + if (MultiByteToWideChar(CP_UTF8, 0, pw, pwSz, pwW, pwWSz) != pwSz) { + ret = WSSHD_AUTH_FAILURE; + } + else { + pwW[pwWSz] = L'\0'; + } + } + + if (ret == WSSHD_AUTH_SUCCESS) { + if (LogonUserExExW(usrW, dmW, pwW, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, NULL, + &authCtx->token, NULL, NULL, NULL, NULL) != TRUE) { + wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Windows failed with error %d when login in as user %s, " + "bad username or password", GetLastError(), usr); + wolfSSH_Log(WS_LOG_INFO, "[SSHD] Check user is allowed to 'Log on as batch job'"); + ret = WSSHD_AUTH_FAILURE; + } } - if (lineBuf != NULL) { - WFREE(lineBuf, NULL, DYNTYPE_BUFFER); + if (usrW != NULL) { + WFREE(usrW, authCtx->heap, DYNTYPE_SSHD); } - if (authKeysFile != NULL) { - WFREE(authKeysFile, NULL, DYNTYPE_STRING); + + if (pwW != NULL) { + WFREE(pwW, authCtx->heap, DYNTYPE_SSHD); } - (void)usrCaKeysFile; return ret; } -#endif /* !_WIN32*/ +static int CheckUserWIN(const char* name) +{ + int ret = WSSHD_AUTH_FAILURE; + + wolfSSH_Log(WS_LOG_INFO, "[SSHD] Windows user check happens with password/public key check"); + + ret = WSSHD_AUTH_SUCCESS; + + return ret; +} + + +/* Helper function to setup the user token in cases where public key + * auth is used. Return WSSHD_AUTH_SUCCESS on success */ +static int SetupUserTokenWin(const char* usr, + const WS_UserAuthData_PublicKey* pubKeyCtx, + const char* usrCaKeysFile, WOLFSSHD_AUTH* authCtx) +{ + int ret; + WCHAR* usrW = NULL; + WCHAR dmW[] = L"."; /* currently hard set to use local domain */ + ULONG rc; + HANDLE lsaHandle = NULL; + ULONG authId = 0; + void* authInfo = NULL; + ULONG authInfoSz = 0; + TOKEN_SOURCE sourceContext; + + size_t usrWSz; + + wolfSSH_Log(WS_LOG_INFO, "[SSHD] Windows public key get user token"); + + ret = WSSHD_AUTH_SUCCESS; + + usrWSz = WSTRLEN(usr); + usrW = (WCHAR*)WMALLOC((usrWSz + 1) * sizeof(WCHAR), NULL, DYNTYPE_SSHD); + if (usrW == NULL) { + ret = WS_MEMORY_E; + } + + if (ret == WSSHD_AUTH_SUCCESS) { + size_t wr; + if (mbstowcs_s(&wr, usrW, usrWSz + 1, usr, usrWSz) != 0) { + ret = WSSHD_AUTH_FAILURE; + } + } + + if (ret == WSSHD_AUTH_SUCCESS) { + LSA_OPERATIONAL_MODE oMode; + LSA_STRING processName; + + WMEMSET(&processName, 0, sizeof(LSA_STRING)); + processName.Buffer = "wolfsshd"; + processName.Length = (USHORT)WSTRLEN("wolfsshd"); + processName.MaximumLength = processName.Length + 1; + + + if ((rc = LsaRegisterLogonProcess(&processName, &lsaHandle, &oMode)) != STATUS_SUCCESS) { + wolfSSH_Log(WS_LOG_ERROR, "[SSHD] LSA Register Logon Process Error %d", LsaNtStatusToWinError(rc)); + ret = WSSHD_AUTH_FAILURE; + } + } + + if (ret == WSSHD_AUTH_SUCCESS) { + LSA_STRING authName; + + WMEMSET(&authName, 0, sizeof(LSA_STRING)); + authName.Buffer = MSV1_0_PACKAGE_NAME; + authName.Length = (USHORT)WSTRLEN(MSV1_0_PACKAGE_NAME); + authName.MaximumLength = authName.Length + 1; + if (rc = LsaLookupAuthenticationPackage(lsaHandle, &authName, &authId) != STATUS_SUCCESS) { + wolfSSH_Log(WS_LOG_ERROR, "[SSHD] LSA Lookup Authentication Package Error %d", rc); + ret = WSSHD_AUTH_FAILURE; + } + } + + if (ret == WSSHD_AUTH_SUCCESS) { + /* size of logon struct plus computer and user name */ + authInfoSz = (ULONG)(sizeof(MSV1_0_S4U_LOGON) + + (wcslen(usrW) + wcslen(dmW)) * sizeof(wchar_t)); + authInfo = (void*)WMALLOC(authInfoSz, NULL, DYNTYPE_SSHD); + if (authInfo == NULL) { + ret = WSSHD_AUTH_FAILURE; + } + else { + MSV1_0_S4U_LOGON* l; + + WMEMSET(authInfo, 0, authInfoSz); + l = (MSV1_0_S4U_LOGON*)authInfo; + l->MessageType = MsV1_0S4ULogon; + + /* write user name after the MSV1_0_S4U_LOGON structure in buffer */ + l->UserPrincipalName.Length = (USHORT)(wcslen(usrW) * sizeof(wchar_t)); + l->UserPrincipalName.MaximumLength = l->UserPrincipalName.Length; + l->UserPrincipalName.Buffer = (WCHAR*)((byte*)l + sizeof(MSV1_0_S4U_LOGON)); + memcpy_s(l->UserPrincipalName.Buffer, l->UserPrincipalName.Length, usrW, l->UserPrincipalName.Length); + + /* write domain name after the user name in buffer */ + l->DomainName.Length = (USHORT)(wcslen(dmW) * sizeof(wchar_t)); + l->DomainName.MaximumLength = l->UserPrincipalName.Length; + l->DomainName.Buffer = (WCHAR*)((byte*)(l->UserPrincipalName.Buffer) + l->UserPrincipalName.Length); + memcpy_s(l->DomainName.Buffer, l->DomainName.Length, dmW, l->DomainName.Length); + } + } + + if (ret == WSSHD_AUTH_SUCCESS) { + strcpy_s(sourceContext.SourceName, TOKEN_SOURCE_LENGTH, "sshd"); + if (AllocateLocallyUniqueId(&sourceContext.SourceIdentifier) != TRUE) { + wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Windows failed to allocate locally unique source context id"); + ret = WSSHD_AUTH_FAILURE; + } + } + + if (ret == WSSHD_AUTH_SUCCESS) { + LSA_STRING originName; + NTSTATUS subStatus; + QUOTA_LIMITS quotas; + DWORD profileSz; + PKERB_INTERACTIVE_PROFILE profile = NULL; + LUID logonId = { 0, 0 }; + + WMEMSET(&originName, 0, sizeof(LSA_STRING)); + originName.Buffer = "wolfsshd"; + originName.Length = (USHORT)WSTRLEN("wolfsshd"); + originName.MaximumLength = originName.Length + 1; + + if ((rc = LsaLogonUser(lsaHandle, &originName, Network, authId, authInfo, authInfoSz, NULL, &sourceContext, &profile, &profileSz, &logonId, &authCtx->token, "as, &subStatus)) != STATUS_SUCCESS) { + wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Windows failed with status %X, SubStatus %d, when login in as user %s", + rc, subStatus, usr); + ret = WSSHD_AUTH_FAILURE; + } + + /* currently not using the profile returned, free it here */ + if (profile != NULL) { + LsaFreeReturnBuffer(profile); + } + } + + if (authInfo != NULL) { + WFREE(authInfo, NULL, DYNTYPE_SSHD); + } + + if (lsaHandle != NULL) { + LsaDeregisterLogonProcess(lsaHandle); + } + + return ret; +} + +/* Uses Windows LSA for getting an impersination token */ +static int CheckPublicKeyWIN(const char* usr, + const WS_UserAuthData_PublicKey* pubKeyCtx, + const char* usrCaKeysFile, WOLFSSHD_AUTH* authCtx) +{ + int ret; + + wolfSSH_Log(WS_LOG_INFO, "[SSHD] Windows check public key"); + + ret = SetupUserTokenWin(usr, pubKeyCtx,usrCaKeysFile, authCtx); + + /* after successful logon check the public key sent */ + if (ret == WSSHD_AUTH_SUCCESS) { + WCHAR h[MAX_PATH]; + + if (_GetHomeDirectory(authCtx, usr, h, MAX_PATH) == WS_SUCCESS) { + CHAR r[MAX_PATH]; + size_t rSz; + + if (wcstombs_s(&rSz, r, MAX_PATH, h, MAX_PATH - 1) != 0) { + ret = WSSHD_AUTH_FAILURE; + } + + if (ret == WSSHD_AUTH_SUCCESS) { + r[rSz-1] = L'\0'; + + ret = SearchForPubKey(r, pubKeyCtx); + if (ret != WSSHD_AUTH_SUCCESS) { + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Failed to find public key for user %s", usr); + ret = WSSHD_AUTH_FAILURE; + } + } + } + else { + wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Windows failed to get home directory for user %s", + usr); + ret = WSSHD_AUTH_FAILURE; + } + } + + return ret; +} +#endif /* _WIN32*/ + /* return WOLFSSH_USERAUTH_SUCCESS on success */ static int DoCheckUser(const char* usr, WOLFSSHD_AUTH* auth) { @@ -734,7 +1088,7 @@ static int RequestAuthentication(WS_UserAuthData* authData, } else { rc = authCtx->checkPasswordCb(usr, authData->sf.password.password, - authData->sf.password.passwordSz); + authData->sf.password.passwordSz, authCtx); if (rc == WSSHD_AUTH_SUCCESS) { wolfSSH_Log(WS_LOG_INFO, "[SSHD] Password ok."); } @@ -832,12 +1186,26 @@ static int RequestAuthentication(WS_UserAuthData* authData, !wolfSSHD_ConfigGetAuthKeysFileSet(authCtx->conf)) { wolfSSH_Log(WS_LOG_INFO, "[SSHD] Relying on CA for public key check"); + #ifdef WIN32 + /* Still need to get users token on Windows */ + rc = SetupUserTokenWin(usr, &authData->sf.publicKey, + wolfSSHD_ConfigGetUserCAKeysFile(authCtx->conf), authCtx); + if (rc == WSSHD_AUTH_SUCCESS) { + wolfSSH_Log(WS_LOG_INFO, "[SSHD] Got users token ok."); + ret = WOLFSSH_USERAUTH_SUCCESS; + } + else { + wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error getting users token."); + ret = WOLFSSH_USERAUTH_FAILURE; + } + #else ret = WOLFSSH_USERAUTH_SUCCESS; + #endif } else { /* if not a certificate then parse through authorized key file */ rc = authCtx->checkPublicKeyCb(usr, &authData->sf.publicKey, - wolfSSHD_ConfigGetUserCAKeysFile(authCtx->conf)); + wolfSSHD_ConfigGetUserCAKeysFile(authCtx->conf), authCtx); if (rc == WSSHD_AUTH_SUCCESS) { wolfSSH_Log(WS_LOG_INFO, "[SSHD] Public key ok."); ret = WOLFSSH_USERAUTH_SUCCESS; @@ -939,7 +1307,9 @@ static int SetDefaultUserCheck(WOLFSSHD_AUTH* auth) int ret = WS_NOT_COMPILED; #ifdef _WIN32 - /* TODO: Implement for Windows. */ + wolfSSH_Log(WS_LOG_INFO, "[SSHD] Setting default Windows user name check"); + auth->checkUserCb = CheckUserWIN; + ret = WS_SUCCESS; #else wolfSSH_Log(WS_LOG_INFO, "[SSHD] Setting default Unix user name check"); auth->checkUserCb = CheckUserUnix; @@ -955,7 +1325,9 @@ static int SetDefaultPasswordCheck(WOLFSSHD_AUTH* auth) int ret = WS_NOT_COMPILED; #ifdef _WIN32 - /* TODO: Add CheckPasswordWin. */ + wolfSSH_Log(WS_LOG_INFO, "[SSHD] Setting Windows password check"); + auth->checkPasswordCb = CheckPasswordWIN; + ret = WS_SUCCESS; #elif defined(WOLFSSH_USE_PAM) wolfSSH_Log(WS_LOG_INFO, "[SSHD] Setting PAM password check"); auth->checkPasswordCb = CheckPasswordPAM; @@ -974,7 +1346,9 @@ static int SetDefaultPublicKeyCheck(WOLFSSHD_AUTH* auth) int ret = WS_NOT_COMPILED; #ifdef _WIN32 - /* TODO: Implement for Windows. */ + wolfSSH_Log(WS_LOG_INFO, "[SSHD] Setting Windows public key check"); + auth->checkPublicKeyCb = CheckPublicKeyWIN; + ret = WS_SUCCESS; #else wolfSSH_Log(WS_LOG_INFO, "[SSHD] Setting Unix public key check"); auth->checkPublicKeyCb = CheckPublicKeyUnix; @@ -983,6 +1357,33 @@ static int SetDefaultPublicKeyCheck(WOLFSSHD_AUTH* auth) return ret; } +static int SetDefualtUserID(WOLFSSHD_AUTH* auth) +{ +#ifdef _WIN32 + /* TODO: Implement for Windows. */ + return 0; +#else + struct passwd* pwInfo; + const char* usr = "sshd"; + int ret = WS_SUCCESS; + + pwInfo = getpwnam(usr); + if (pwInfo == NULL) { + /* user name not found on system */ + wolfSSH_Log(WS_LOG_INFO, "[SSHD] No sshd user found to use"); + ret = WS_FATAL_ERROR; + } + + if (ret == WS_SUCCESS) { + auth->gid = pwInfo->pw_gid; + auth->uid = pwInfo->pw_uid; + auth->sGid = getgid(); + auth->sUid = getuid(); + } + return ret; +#endif +} + /* Sets the default functions to be used for authentication of peer. * Later the default functions could be overriden if needed. @@ -994,8 +1395,6 @@ WOLFSSHD_AUTH* wolfSSHD_AuthCreateUser(void* heap, const WOLFSSHD_CONFIG* conf) auth = (WOLFSSHD_AUTH*)WMALLOC(sizeof(WOLFSSHD_AUTH), heap, DYNTYPE_SSHD); if (auth != NULL) { int ret; - struct passwd* pwInfo; - const char* usr = "sshd"; auth->heap = heap; auth->conf = conf; @@ -1026,21 +1425,13 @@ WOLFSSHD_AUTH* wolfSSHD_AuthCreateUser(void* heap, const WOLFSSHD_CONFIG* conf) } if (ret == WS_SUCCESS) { - pwInfo = getpwnam(usr); - if (pwInfo == NULL) { - /* user name not found on system */ - wolfSSH_Log(WS_LOG_INFO, "[SSHD] No sshd user found to use"); - ret = WS_FATAL_ERROR; + ret = SetDefualtUserID(auth); + if (ret != WS_SUCCESS) { + wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error setting default " + "user ID."); } } - if (ret == WS_SUCCESS) { - auth->gid = pwInfo->pw_gid; - auth->uid = pwInfo->pw_uid; - auth->sGid = getgid(); - auth->sUid = getuid(); - } - /* error case in setting one of the default callbacks */ if (ret != WS_SUCCESS) { (void)wolfSSHD_AuthFreeUser(auth); @@ -1069,6 +1460,7 @@ int wolfSSHD_AuthRaisePermissions(WOLFSSHD_AUTH* auth) int ret = 0; wolfSSH_Log(WS_LOG_INFO, "[SSHD] Attempting to raise permissions level"); +#ifndef WIN32 if (auth) { if (setegid(auth->sGid) != 0) { wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error rasing gid"); @@ -1083,6 +1475,7 @@ int wolfSSHD_AuthRaisePermissions(WOLFSSHD_AUTH* auth) else { ret = WS_BAD_ARGUMENT; } +#endif return ret; } @@ -1092,6 +1485,7 @@ int wolfSSHD_AuthRaisePermissions(WOLFSSHD_AUTH* auth) int wolfSSHD_AuthReducePermissionsUser(WOLFSSHD_AUTH* auth, WUID_T uid, WGID_T gid) { +#ifndef WIN32 if (setregid(gid, gid) != 0) { wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error setting user gid"); return WS_FATAL_ERROR; @@ -1101,6 +1495,7 @@ int wolfSSHD_AuthReducePermissionsUser(WOLFSSHD_AUTH* auth, WUID_T uid, wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error setting user uid"); return WS_FATAL_ERROR; } +#endif (void)auth; return WS_SUCCESS; } @@ -1113,6 +1508,7 @@ int wolfSSHD_AuthReducePermissions(WOLFSSHD_AUTH* auth) int ret = WS_SUCCESS; flag = wolfSSHD_ConfigGetPrivilegeSeparation(auth->conf); +#ifndef WIN32 if (flag == WOLFSSHD_PRIV_SEPARAT || flag == WOLFSSHD_PRIV_SANDBOX) { wolfSSH_Log(WS_LOG_INFO, "[SSHD] Lowering permissions level"); if (auth) { @@ -1130,23 +1526,26 @@ int wolfSSHD_AuthReducePermissions(WOLFSSHD_AUTH* auth) ret = WS_BAD_ARGUMENT; } } +#endif return ret; } - +#ifndef WIN32 #if defined(__OSX__) || defined( __APPLE__) #define WGETGROUPLIST(x,y,z,w) getgrouplist((x),(y),(int*)(z),(w)) #else #define WGETGROUPLIST(x,y,z,w) getgrouplist((x),(y),(z),(w)) #endif +#endif /* WIN32 */ /* sets the extended groups the user is in, returns WS_SUCCESS on success */ int wolfSSHD_AuthSetGroups(const WOLFSSHD_AUTH* auth, const char* usr, WGID_T gid) { + int ret = WS_SUCCESS; +#ifndef WIN32 int grpListSz = 0; gid_t* grpList = NULL; - int ret = WS_SUCCESS; #if defined(__QNX__) || defined(__QNXNTO__) /* QNX does not support getting the exact group list size ahead of time, @@ -1183,7 +1582,11 @@ int wolfSSHD_AuthSetGroups(const WOLFSSHD_AUTH* auth, const char* usr, WFREE(grpList, auth->heap, DYNTYPE_SSHD); } } - +#else + WOLFSSH_UNUSED(auth); + WOLFSSH_UNUSED(usr); + WOLFSSH_UNUSED(gid); +#endif return ret; } @@ -1207,14 +1610,18 @@ WOLFSSHD_CONFIG* wolfSSHD_AuthGetUserConf(const WOLFSSHD_AUTH* auth, const char* localAdr, word16* localPort, const char* RDomain, const char* adr) { - struct group* g = NULL; WOLFSSHD_CONFIG* ret = NULL; if (auth != NULL) { - struct passwd *p_passwd; char* gName = NULL; if (usr != NULL) { +#ifdef WIN32 + //LogonUserEx() +#else + struct passwd* p_passwd; + struct group* g = NULL; + p_passwd = getpwnam((const char *)usr); if (p_passwd == NULL) { return NULL; @@ -1225,6 +1632,7 @@ WOLFSSHD_CONFIG* wolfSSHD_AuthGetUserConf(const WOLFSSHD_AUTH* auth, return NULL; } gName = g->gr_name; +#endif } ret = wolfSSHD_GetUserConf(auth->conf, usr, gName, host, localAdr, diff --git a/apps/wolfsshd/auth.h b/apps/wolfsshd/auth.h index fc868576f..ddc6e90aa 100644 --- a/apps/wolfsshd/auth.h +++ b/apps/wolfsshd/auth.h @@ -46,7 +46,7 @@ typedef int (*CallbackCheckUser)(const char* usr); * found, and negative values if an error occurs during checking. */ typedef int (*CallbackCheckPassword)(const char* usr, const byte* psw, - word32 pswSz); + word32 pswSz, WOLFSSHD_AUTH* authCtx); /* * Returns WSSHD_AUTH_SUCCESS if public key ok, WSSHD_AUTH_FAILURE if key not @@ -54,7 +54,7 @@ typedef int (*CallbackCheckPassword)(const char* usr, const byte* psw, */ typedef int (*CallbackCheckPublicKey)(const char* usr, const WS_UserAuthData_PublicKey* pubKey, - const char* usrCaKeysFile); + const char* usrCaKeysFile, WOLFSSHD_AUTH* authCtx); WOLFSSHD_AUTH* wolfSSHD_AuthCreateUser(void* heap, const WOLFSSHD_CONFIG* conf); int wolfSSHD_AuthFreeUser(WOLFSSHD_AUTH* auth); @@ -69,4 +69,8 @@ WOLFSSHD_CONFIG* wolfSSHD_AuthGetUserConf(const WOLFSSHD_AUTH* auth, const char* usr, const char* host, const char* localAdr, word16* localPort, const char* RDomain, const char* adr); +#ifdef _WIN32 +HANDLE wolfSSHD_GetAuthToken(const WOLFSSHD_AUTH* auth); +int wolfSSHD_GetHomeDirectory(WOLFSSHD_AUTH* auth, WOLFSSH* ssh, WCHAR* out, int outSz); +#endif #endif /* WOLFAUTH_H */ diff --git a/apps/wolfsshd/configuration.c b/apps/wolfsshd/configuration.c index b2c4262fe..8f0ffd715 100644 --- a/apps/wolfsshd/configuration.c +++ b/apps/wolfsshd/configuration.c @@ -22,6 +22,10 @@ #include #endif +#ifdef WOLFSSL_USER_SETTINGS + #include +#endif + #ifdef WOLFSSH_SSHD /* functions for parsing out options from a config file and for handling loading * key/certs using the env. filesystem */ @@ -47,7 +51,10 @@ #endif #include "configuration.h" + +#ifndef WIN32 #include +#endif struct WOLFSSHD_CONFIG { void* heap; @@ -854,7 +861,7 @@ static int AddRestrictedCase(WOLFSSHD_CONFIG* config, const char* mtch, * and makes it point to the newly created conf node */ static int HandleMatch(WOLFSSHD_CONFIG** conf, const char* value, int valueSz) { - WOLFSSHD_CONFIG* newConf; + WOLFSSHD_CONFIG* newConf = NULL; int ret = WS_SUCCESS; if (conf == NULL || *conf == NULL || value == NULL) { @@ -1096,7 +1103,7 @@ WOLFSSHD_STATIC int ParseConfigLine(WOLFSSHD_CONFIG** conf, const char* l, */ int wolfSSHD_ConfigLoad(WOLFSSHD_CONFIG* conf, const char* filename) { - XFILE f; + WFILE *f; WOLFSSHD_CONFIG* currentConfig; int ret = WS_SUCCESS; char buf[MAX_LINE_SIZE]; @@ -1105,8 +1112,7 @@ int wolfSSHD_ConfigLoad(WOLFSSHD_CONFIG* conf, const char* filename) if (conf == NULL || filename == NULL) return BAD_FUNC_ARG; - f = XFOPEN(filename, "rb"); - if (f == XBADFILE) { + if (WFOPEN(&f, filename, "rb") != 0) { wolfSSH_Log(WS_LOG_ERROR, "Unable to open SSHD config file %s", filename); return BAD_FUNC_ARG; @@ -1124,7 +1130,7 @@ int wolfSSHD_ConfigLoad(WOLFSSHD_CONFIG* conf, const char* filename) current = current + 1; } - if (currentSz <= 1) { + if (currentSz <= 2) { /* \n or \r\n */ continue; /* empty line */ } @@ -1138,7 +1144,7 @@ int wolfSSHD_ConfigLoad(WOLFSSHD_CONFIG* conf, const char* filename) break; } } - XFCLOSE(f); + WFCLOSE(f); SetAuthKeysPattern(conf->authKeysFile); diff --git a/apps/wolfsshd/wolfsshd.c b/apps/wolfsshd/wolfsshd.c index 0202c7e9e..fba72295f 100644 --- a/apps/wolfsshd/wolfsshd.c +++ b/apps/wolfsshd/wolfsshd.c @@ -22,6 +22,10 @@ #include #endif +#ifdef WOLFSSL_USER_SETTINGS + #include +#endif + #ifdef WOLFSSH_SSHD #include @@ -51,7 +55,7 @@ #define WOLFSSHD_TIMEOUT 1 #endif -#ifdef WOLFSSH_SHELL +#if defined(WOLFSSH_SHELL) && !defined(_WIN32) #ifdef HAVE_PTY_H #include #endif @@ -80,18 +84,20 @@ static void ConnClose(int sig) { +#ifndef WIN32 pid_t p; int ret; p = wait(&ret); if (p == 0 || p == -1) return; /* parent or error state*/ (void)ret; +#endif (void)sig; } #endif /* WOLFSSH_SHELL */ static volatile byte debugMode = 0; /* default to off */ -static FILE* logFile = NULL; +static WFILE* logFile = NULL; /* catch interrupts and close down gracefully */ static volatile byte quit = 0; @@ -104,6 +110,7 @@ typedef struct WOLFSSHD_CONNECTION { int fd; int listenFd; char ip[INET_ADDRSTRLEN]; + byte isThreaded; } WOLFSSHD_CONNECTION; #ifdef __unix__ @@ -141,6 +148,28 @@ static void SyslogCb(enum wolfSSH_LogLevel level, const char *const msgStr) #endif +#ifdef _WIN32 +static void ServiceDebugCb(enum wolfSSH_LogLevel level, const char* const msgStr) +{ + WCHAR* wc; + size_t szWord = WSTRLEN(msgStr) + 3; /* + 3 for null terminator and new line */ + size_t sz = szWord *sizeof(wchar_t); + wc = (WCHAR*)WMALLOC(sz, NULL, DYNAMIC_TYPE_LOG); + if (wc) { + size_t con; + + if (mbstowcs_s(&con, wc, szWord, msgStr, szWord-1) == 0) { + wc[con - 1] = L'\r'; + wc[con] = L'\n'; + wc[con + 1] = L'\0'; + OutputDebugString(wc); + } + WFREE(wc, NULL, DYNAMIC_TYPE_LOG); + } + WOLFSSH_UNUSED(level); +} +#endif + static void ShowUsage(void) { printf("wolfsshd %s\n", LIBWOLFSSH_VERSION_STRING); @@ -164,16 +193,22 @@ static void interruptCatch(int in) quit = 1; } +#ifdef WIN32 + #include + #define WGETPID GetCurrentProcessId +#else + #define WGETPID getpid +#endif /* redirect logging to a specific file and add the PID value */ static void wolfSSHDLoggingCb(enum wolfSSH_LogLevel lvl, const char *const str) { /* always log errors and optionally log other info/debug level messages */ if (lvl == WS_LOG_ERROR) { - fprintf(logFile, "[PID %d]: %s\n", getpid(), str); + fprintf(logFile, "[PID %d]: %s\n", WGETPID(), str); } else if (debugMode) { - fprintf(logFile, "[PID %d]: %s\n", getpid(), str); + fprintf(logFile, "[PID %d]: %s\n", WGETPID(), str); } } @@ -247,6 +282,10 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx) word32 privBufSz; void* heap = NULL; + if (ctx == NULL) { + return WS_BAD_ARGUMENT; + } + /* create a new WOLFSSH_CTX */ *ctx = wolfSSH_CTX_new(WOLFSSH_ENDPOINT_SERVER, NULL); if (ctx == NULL) { @@ -404,7 +443,10 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx) } } #endif - wolfSSH_SetUserAuthTypes(*ctx, DefaultUserAuthTypes); + + if (ret == WS_SUCCESS) { + wolfSSH_SetUserAuthTypes(*ctx, DefaultUserAuthTypes); + } /* @TODO Load in host public key */ @@ -414,7 +456,7 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx) return ret; } - +#ifndef _WIN32 /* return 1 if set, 0 if not set and negative values on error */ static int SetupChroot(WOLFSSHD_CONFIG* usrConf) { @@ -444,6 +486,7 @@ static int SetupChroot(WOLFSSHD_CONFIG* usrConf) } return ret; } +#endif #ifdef WOLFSSH_SCP static int SCP_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, @@ -453,6 +496,7 @@ static int SCP_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, int error = WS_SUCCESS; int select_ret = 0; +#ifndef _WIN32 /* temporarily elevate permissions to get users information */ if (wolfSSHD_AuthRaisePermissions(conn->auth) != WS_SUCCESS) { wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Failure to raise permissions for auth"); @@ -483,6 +527,14 @@ static int SCP_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, return WS_FATAL_ERROR; } +#else + /* impersonate the logged on user for file permissions */ + if (ImpersonateLoggedOnUser(wolfSSHD_GetAuthToken(conn->auth)) == FALSE) { + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Error impersonating logged on user"); + ret = WS_FATAL_ERROR; + } +#endif if (ret == WS_SUCCESS) { ret = wolfSSH_accept(ssh); @@ -512,6 +564,10 @@ static int SCP_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, } (void)conn; +#ifdef _WIN32 + /* stop impersonating the user */ + RevertToSelf(); +#endif return ret; } #endif /* WOLFSSH_SCP */ @@ -533,6 +589,7 @@ static int SFTP_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, int timeout = TEST_SFTP_TIMEOUT_NONE; byte peek_buf[1]; +#ifndef _WIN32 /* temporarily elevate permissions to get users information */ if (wolfSSHD_AuthRaisePermissions(conn->auth) != WS_SUCCESS) { wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Failure to raise permissions for auth"); @@ -561,6 +618,7 @@ static int SFTP_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, } } + /* set starting SFTP directory */ if (ret == WS_SUCCESS) { WDIR dir; @@ -587,6 +645,37 @@ static int SFTP_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, return WS_FATAL_ERROR; } +#else + char r[MAX_PATH]; + size_t rSz = 0; + WCHAR h[MAX_PATH]; + + ret = wolfSSHD_GetHomeDirectory(conn->auth, ssh, h, MAX_PATH); + + /* convert home directory from wchar type to char */ + if (ret == WS_SUCCESS) { + if (wcstombs_s(&rSz, r, MAX_PATH, h, MAX_PATH - 1) != 0) { + ret = WS_FATAL_ERROR; + } + } + + if (ret == WS_SUCCESS) { + r[rSz] = '\0'; + wolfSSH_Log(WS_LOG_INFO, "[SSHD] Using directory %s for SFTP connection", r); + if (wolfSSH_SFTP_SetDefaultPath(ssh, r) != WS_SUCCESS) { + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Error setting SFTP default home path"); + ret = WS_FATAL_ERROR; + } + } + + /* impersonate the logged on user for file permissions */ + if (ImpersonateLoggedOnUser(wolfSSHD_GetAuthToken(conn->auth)) == FALSE) { + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Error impersonating logged on user"); + ret = WS_FATAL_ERROR; + } +#endif if (ret == WS_SUCCESS) { sockfd = (WS_SOCKET_T)wolfSSH_get_fd(ssh); @@ -677,6 +766,10 @@ static int SFTP_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, } (void)conn; +#ifdef _WIN32 + /* stop impersonating the user */ + RevertToSelf(); +#endif return ret; } #endif @@ -685,9 +778,343 @@ static int SFTP_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, #ifdef WOLFSSH_SHELL #ifndef MAX_COMMAND_SZ - #define MAX_COMMAND_SZ 80 +#define MAX_COMMAND_SZ 80 #endif +#ifdef WIN32 + +/* handles creating a new shell env. and maintains SSH connection for incoming + * user input as well as output of the shell. + * return WS_SUCCESS on success */ +static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, + WPASSWD* pPasswd, WOLFSSHD_CONFIG* usrConf, const char* subCmd) +{ + BOOL ret; + word32 shellChannelId = 0; +#ifndef EXAMPLE_BUFFER_SZ +#define EXAMPLE_BUFFER_SZ 4096 +#endif + byte shellBuffer[EXAMPLE_BUFFER_SZ]; + int cnt_r, cnt_w; + HANDLE ptyIn = NULL, ptyOut = NULL; + HANDLE cnslIn = NULL, cnslOut = NULL; + HPCON pCon = 0; + COORD cord; + STARTUPINFOEX ext; + PCWSTR sysCmd = L"c:\\windows\\system32\\cmd.exe"; +#if 0 + /* start powershell instead */ + PCWSTR sysCmd = L"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe"; +#endif + PWSTR cmd = NULL; + size_t cmdSz = 0; + PROCESS_INFORMATION processInfo; + size_t sz = 0; + WCHAR h[MAX_PATH]; + char* forcedCmd; + + forcedCmd = wolfSSHD_ConfigGetForcedCmd(usrConf); + + /* @TODO check for conpty support LoadLibrary()and GetProcAddress(). */ + + + if (forcedCmd != NULL && XSTRCMP(forcedCmd, "internal-sftp") == 0) { + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Only SFTP connections allowed for user " + "%s", wolfSSH_GetUsername(ssh)); + return WS_FATAL_ERROR; + } + + ret = wolfSSHD_GetHomeDirectory(conn->auth, ssh, h, MAX_PATH); + if (ret == WS_SUCCESS) { + ZeroMemory(&ext, sizeof(STARTUPINFOEX)); + ZeroMemory(&processInfo, sizeof(PROCESS_INFORMATION)); + + /* use forced command if set over subCmd */ + if (forcedCmd == NULL && subCmd != NULL) { + forcedCmd = (char*)subCmd; + } + + if (forcedCmd != NULL) { /* copy over set command if present */ + /* +1 for terminator and +2 for quotes */ + cmdSz = WSTRLEN(forcedCmd) + wcslen(sysCmd) + WSTRLEN(" /C ") + 3; + cmd = (PWSTR)WMALLOC(sizeof(wchar_t) * cmdSz, NULL, DYNTYPE_SSHD); + if (cmd == NULL) { + ret = WS_MEMORY_E; + } + else { + WCHAR* tmp = (WCHAR*)WMALLOC(sizeof(wchar_t) * cmdSz, NULL, DYNTYPE_SSHD); + if (tmp == NULL) { + ret = WS_MEMORY_E; + } + + if (ret == WS_SUCCESS) { + size_t wr = 0; + if (mbstowcs_s(&wr, tmp, cmdSz, forcedCmd, cmdSz - 1) != 0) { + ret = WS_FATAL_ERROR; + } + } + + if (ret == WS_SUCCESS) { + swprintf(cmd, cmdSz, L"%s /C \"%s\"", sysCmd, tmp); + } + + if (tmp != NULL) { + WFREE(tmp, NULL, DYNTYPE_SSHD); + } + } + } + else { /* when set command is not present start 'cmd.exe' */ + cmdSz = wcslen(sysCmd) + 1; /* +1 for terminator */ + cmd = (PWSTR)WMALLOC(sizeof(wchar_t) * cmdSz, NULL, DYNTYPE_SSHD); + if (cmd == NULL) { + ret = WS_MEMORY_E; + } + else { + wcscpy_s(cmd, cmdSz, sysCmd); + } + } + } + + if (ret == WS_SUCCESS) { + HRESULT err; + + CreatePipe(&cnslIn, &ptyIn, NULL, 0); + CreatePipe(&ptyOut, &cnslOut, NULL, 0); + + cord.X = ssh->curX; + cord.Y = ssh->curY; + + /* Sanity check on cord values, if 0 than assume was not set. + * (can happen with exec and not req-pty message) + * If not set yet then use sane default values. */ + if (cord.X == 0) { + cord.X = 80; + } + + if (cord.Y == 0) { + cord.Y = 24; + } + + err = CreatePseudoConsole(cord, cnslIn, cnslOut, 0, &pCon); + if (err != S_OK) { + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Issue creating pseudo console"); + ret = WS_FATAL_ERROR; + } + else { + CloseHandle(cnslIn); + CloseHandle(cnslOut); + wolfSSH_SetTerminalResizeCtx(ssh, (void*)&pCon); + } + } + + /* setup startup extended info for pseudo terminal */ + if (ret == WS_SUCCESS) { + ext.StartupInfo.cb = sizeof(STARTUPINFOEX); + (void)InitializeProcThreadAttributeList(NULL, 1, 0, &sz); + if (sz == 0) { + ret = WS_FATAL_ERROR; + } + + if (ret == WS_SUCCESS) { + /* Using HeapAlloc for better support when possibly passing + memory between Windows Modules */ + ext.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, sz); + if (ext.lpAttributeList == NULL) { + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Issue getting memory for attribute list"); + ret = WS_FATAL_ERROR; + } + } + + if (ret == WS_SUCCESS) { + if (InitializeProcThreadAttributeList(ext.lpAttributeList, 1, 0, &sz) != TRUE) { + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Issue initializing proc thread attribute"); + ret = WS_FATAL_ERROR; + } + } + + if (ret == WS_SUCCESS) { + if (UpdateProcThreadAttribute(ext.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, + pCon, sizeof(HPCON), NULL, NULL) != TRUE) { + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Issue updating proc thread attribute"); + ret = WS_FATAL_ERROR; + } + } + } + + + if (ret == WS_SUCCESS) { +#if 1 + if (CreateProcessAsUserW(wolfSSHD_GetAuthToken(conn->auth), NULL, cmd, + NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, h, + &ext.StartupInfo, &processInfo) != TRUE) { + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Issue creating process, Windows error %d", GetLastError()); + return WS_FATAL_ERROR; + } +#else + /* Needs enabled when running as non-service, compiled out for now to + * make sure it can not accediently be used since the permissions of the + * created process match the current process. */ + if (CreateProcessW(NULL, cmd, NULL, NULL, FALSE, + EXTENDED_STARTUPINFO_PRESENT, NULL, h, &ext.StartupInfo, &processInfo) + != TRUE) { + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Issue creating process, windows error %d", WSAGetLastError()); + if (cmd != NULL) { + WFREE(cmd, NULL, DYNTYPE_SSHD); + } + return WS_FATAL_ERROR; + } +#endif + else { + SOCKET sshFd; + byte tmp[2]; + fd_set readFds; + WS_SOCKET_T maxFd; + int pending = 0; + int readPending = 0; + int rc = 0; + DWORD processState; + DWORD ava; + struct timeval t; + + t.tv_sec = 0; + t.tv_usec = 800; + + sshFd = wolfSSH_get_fd(ssh); + maxFd = sshFd; + + FD_ZERO(&readFds); + FD_SET(sshFd, &readFds); + + wolfSSH_Log(WS_LOG_INFO, + "[SSHD] Successfully created process for console, waiting for it to start"); + + WaitForInputIdle(processInfo.hProcess, 1000); + + do { + /* @TODO currently not blocking till data comes in */ + if (PeekNamedPipe(ptyOut, NULL, 0, NULL, &ava, NULL) == TRUE) { + if (ava > 0) { + readPending = 1; + } + } + + if (readPending == 0) { + /* check if process is still running before waiting to read */ + if (GetExitCodeProcess(processInfo.hProcess, &processState) == TRUE) { + if (processState != STILL_ACTIVE) { + wolfSSH_Log(WS_LOG_INFO, + "[SSHD] Process has exited, exit state = %d, close down SSH connection", processState); + Sleep(100); /* give the stdout/stderr of process a little time to write to pipe */ + if (PeekNamedPipe(ptyOut, NULL, 0, NULL, &ava, NULL) == TRUE) { + if (ava > 0) { + /* if data still pending then continue sneding it over SSH */ + readPending = 1; + continue; + } + } + break; + } + } + if (wolfSSH_stream_peek(ssh, tmp, 1) <= 0) { + rc = select((int)maxFd + 1, &readFds, NULL, NULL, &t); + if (rc == -1) { + wolfSSH_Log(WS_LOG_INFO, + "[SSHD] select call waiting on socket failed"); + break; + } + /* when select times out and no socket is set as ready + Windows overwrites readFds with 0. Reset the fd here for next select call */ + if (rc == 0) { + FD_SET(sshFd, &readFds); + } + } + else { + pending = 1; + } + } + + if (rc != 0 && (pending || FD_ISSET(sshFd, &readFds))) { + word32 lastChannel = 0; + + /* The following tries to read from the first channel inside + the stream. If the pending data in the socket is for + another channel, this will return an error with id + WS_CHAN_RXD. That means the agent has pending data in its + channel. The additional channel is only used with the + agent. */ + cnt_r = wolfSSH_worker(ssh, &lastChannel); + if (cnt_r < 0) { + rc = wolfSSH_get_error(ssh); + if (rc == WS_CHAN_RXD) { + if (lastChannel == shellChannelId) { + cnt_r = wolfSSH_ChannelIdRead(ssh, shellChannelId, + shellBuffer, + sizeof shellBuffer); + if (cnt_r <= 0) + break; + pending = 0; + if (WriteFile(ptyIn, shellBuffer, cnt_r, &cnt_r, NULL) != TRUE) { + wolfSSH_Log(WS_LOG_INFO, + "[SSHD] Error writing to pipe for console"); + break; + } + } + } + else if (rc == WS_CHANNEL_CLOSED) { + continue; + } + else if (rc != WS_WANT_READ) { + break; + } + } + } + + if (readPending) { + WMEMSET(shellBuffer, 0, EXAMPLE_BUFFER_SZ); + + if (ReadFile(ptyOut, shellBuffer, EXAMPLE_BUFFER_SZ, &cnt_r, NULL) != TRUE) { + wolfSSH_Log(WS_LOG_INFO, + "[SSHD] Error reading from pipe for console"); + break; + } + else { + readPending = 0; + if (cnt_r > 0) { + cnt_w = wolfSSH_ChannelIdSend(ssh, shellChannelId, + shellBuffer, cnt_r); + if (cnt_w < 0) + break; + } + } + } + } while (1); + + if (cmd != NULL) { + WFREE(cmd, NULL, DYNTYPE_SSHD); + } + wolfSSH_Log(WS_LOG_INFO, + "[SSHD] Closing down process for console"); + + if (ext.lpAttributeList != NULL) { + HeapFree(GetProcessHeap(), 0, ext.lpAttributeList); + } + + ClosePseudoConsole(pCon); + CloseHandle(processInfo.hThread); + CloseHandle(wolfSSHD_GetAuthToken(conn->auth)); + } + } + return ret; +} +#else + /* handles creating a new shell env. and maintains SSH connection for incoming * user input as well as output of the shell. * return WS_SUCCESS on success */ @@ -698,6 +1125,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, int rc; WS_SOCKET_T childFd = 0; pid_t childPid; + #ifndef EXAMPLE_BUFFER_SZ #define EXAMPLE_BUFFER_SZ 4096 #endif @@ -952,8 +1380,13 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, return WS_SUCCESS; } #endif +#endif +#ifdef WIN32 +static volatile int timeOut = 0; +#else static __thread int timeOut = 0; +#endif static void alarmCatch(int signum) { wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Failed login within grace period"); @@ -968,14 +1401,21 @@ static int UserAuthResult(byte result, (void)userAuthResultCtx; if (result == WOLFSSH_USERAUTH_SUCCESS) { + #ifndef WIN32 + /* @TODO alarm catch on windows */ alarm(0); + #endif } return WS_SUCCESS; } /* handle wolfSSH accept and directing to correct subsystem */ +#ifdef _WIN32 +static DWORD HandleConnection(void* arg) +#else static void* HandleConnection(void* arg) +#endif { int ret = WS_SUCCESS; int error; @@ -1007,8 +1447,12 @@ static void* HandleConnection(void* arg) /* set alarm for login grace time */ graceTime = wolfSSHD_AuthGetGraceTime(conn->auth); if (graceTime > 0) { + #ifdef WIN32 + //@TODO SetTimer(NULL, NULL, graceTime, alarmCatch); + #else signal(SIGALRM, alarmCatch); alarm((unsigned int)graceTime); + #endif } ret = wolfSSH_accept(ssh); @@ -1054,6 +1498,7 @@ static void* HandleConnection(void* arg) ret = WS_FATAL_ERROR; } + #ifndef WIN32 if (ret == WS_SUCCESS || ret == WS_SFTP_COMPLETE || ret == WS_SCP_INIT) { pPasswd = getpwnam((const char *)usr); @@ -1062,6 +1507,7 @@ static void* HandleConnection(void* arg) ret = WS_FATAL_ERROR; } } + #endif if (ret != WS_FATAL_ERROR) { /* check for any forced command set for the user */ @@ -1111,6 +1557,7 @@ static void* HandleConnection(void* arg) case WOLFSSH_SESSION_UNKNOWN: case WOLFSSH_SESSION_EXEC: + #if defined(WOLFSSH_SHELL) if (ret == WS_SUCCESS) { wolfSSH_Log(WS_LOG_INFO, "[SSHD] Entering exec session [%s]", @@ -1118,6 +1565,7 @@ static void* HandleConnection(void* arg) SHELL_Subsystem(conn, ssh, pPasswd, usrConf, wolfSSH_GetSessionCommand(ssh)); } + #endif /* WOLFSH_SHELL */ /* SCP can be an exec type */ if (ret == WS_SCP_INIT) { @@ -1190,15 +1638,21 @@ static void* HandleConnection(void* arg) } wolfSSH_Log(WS_LOG_INFO, "[SSHD] Return from closing connection = %d", ret); +#ifdef _WIN32 + return 0; +#else return NULL; +#endif } /* returns WS_SUCCESS on success */ static int NewConnection(WOLFSSHD_CONNECTION* conn) { - int pd; + int ret = WS_SUCCESS; +#ifndef WIN32 + int pd = 0; pd = fork(); if (pd < 0) { @@ -1219,6 +1673,25 @@ static int NewConnection(WOLFSSHD_CONNECTION* conn) WCLOSESOCKET(conn->fd); } } +#else + HANDLE t; + DWORD id; + + if (conn->isThreaded) { + t = CreateThread(NULL, 0, HandleConnection, (void*)conn, 0, &id); + if (t == NULL) { + wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue creating new thread"); + ret = WS_FATAL_ERROR; + } + else { + wolfSSH_Log(WS_LOG_INFO, "[SSHD] Spawned new thread %d\n", id); + CloseHandle(t); + } + } + else { + HandleConnection((void*)conn); + } +#endif return ret; } @@ -1241,7 +1714,7 @@ static int PendingConnection(WS_SOCKET_T fd) FD_SET(fd, &r); errno = 0; - ret = select(nfds, &r, &w, &e, &t); + ret = select((int)nfds, &r, &w, &e, &t); if (ret < 0) { /* a socket level issue happend, could just be a system call int. */ if (errno != EINTR) { @@ -1262,34 +1735,115 @@ static int PendingConnection(WS_SOCKET_T fd) return ret; } - int myoptind = 0; char* myoptarg = NULL; -int main(int argc, char** argv) +#ifdef _WIN32 +#include + +SERVICE_STATUS serviceStatus = { 0 }; +SERVICE_STATUS_HANDLE serviceStatusHandle = NULL; +HANDLE serviceStop = INVALID_HANDLE_VALUE; + +#define WOLFSSHD_SERVICE_NAME _T("wolfSSHd") + + +static void wolfSSHD_ServiceCb(DWORD CtrlCode) { - int ret = WS_SUCCESS; + switch (CtrlCode) { + case SERVICE_CONTROL_STOP: + if (serviceStatus.dwCurrentState != SERVICE_RUNNING) + break; + serviceStatus.dwControlsAccepted = 0; + serviceStatus.dwCurrentState = SERVICE_STOP_PENDING; + serviceStatus.dwWin32ExitCode = 0; + serviceStatus.dwCheckPoint = 4; + + if (SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE) { + wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue setting service status"); + } + + /* send out signal that the service is stopping */ + SetEvent(serviceStop); + break; + + default: + break; + } +} + + +static char* _convertHelper(WCHAR* in, void* heap) { + int retSz; + char* ret; + + retSz = (int)wcslen(in) * 2; + ret = (char*)WMALLOC(retSz + 1, heap, DYNTYPE_SSHD); + if (ret != NULL) { + size_t numConv = 0; + if (wcstombs_s(&numConv, ret, retSz, in, retSz) != 0) { + XFREE(ret, heap, DYNTYPE_SSHD); + ret = NULL; + } + } + return ret; +} + +static void StartSSHD(DWORD argc, LPTSTR* wargv) +#else +static int StartSSHD(int argc, char** argv) +#endif +{ + int ret = WS_SUCCESS; word16 port = 0; WS_SOCKET_T listenFd = 0; int ch; WOLFSSHD_CONFIG* conf = NULL; - WOLFSSHD_AUTH* auth = NULL; + WOLFSSHD_AUTH* auth = NULL; WOLFSSH_CTX* ctx = NULL; byte isDaemon = 1; byte testMode = 0; - const char* configFile = "/etc/ssh/sshd_config"; + const char* configFile = "/etc/ssh/sshd_config"; const char* hostKeyFile = NULL; - signal(SIGINT, interruptCatch); - + logFile = stderr; wolfSSH_SetLoggingCb(wolfSSHDLoggingCb); - wolfSSH_Debugging_ON(); #ifdef DEBUG_WOLFSSL wolfSSL_Debugging_ON(); #endif - logFile = stderr; +#ifdef _WIN32 + char** argv = NULL; + DWORD i; + + for (i = 0; i < argc; i++) { + if (WSTRCMP((char*)(wargv[i]), "-D") == 0) { + isDaemon = 0; + } + } + + if (isDaemon) { + /* Set the logging to go to OutputDebugString */ + wolfSSH_SetLoggingCb(ServiceDebugCb); + + /* we want the arguments to be normal char strings not wchar_t */ + argv = WMALLOC(argc * sizeof(char*), NULL, DYNTYPE_SSHD); + { + unsigned int z; + for (z = 0; z < argc; z++) { + argv[z] = _convertHelper(wargv[z], NULL); + } + } + } + else { + argv = (char**)wargv; + } +#endif + + signal(SIGINT, interruptCatch); + WSTARTTCP(); + if (ret == WS_SUCCESS) { wolfSSH_Init(); } @@ -1303,83 +1857,92 @@ int main(int argc, char** argv) while ((ch = mygetopt(argc, argv, "?f:p:h:dDE:o:t")) != -1) { switch (ch) { - case 'f': - configFile = myoptarg; - break; + case 'f': + configFile = myoptarg; + break; - case 'p': - if (ret == WS_SUCCESS) { - if (myoptarg == NULL) { - ret = WS_BAD_ARGUMENT; - break; - } + case 'p': + if (ret == WS_SUCCESS) { + if (myoptarg == NULL) { + ret = WS_BAD_ARGUMENT; + break; + } - ret = XATOI(myoptarg); - if (ret < 0) { - fprintf(stderr, "Issue parsing port number %s\n", - myoptarg); - ret = WS_BAD_ARGUMENT; + ret = XATOI(myoptarg); + if (ret < 0) { + fprintf(stderr, "Issue parsing port number %s\n", + myoptarg); + ret = WS_BAD_ARGUMENT; + } + else { + if (ret <= (word16)-1) { + port = (word16)ret; + ret = WS_SUCCESS; } else { - if (ret <= (word16)-1) { - port = (word16)ret; - ret = WS_SUCCESS; - } - else { - fprintf(stderr, "Port number %d too big.\n", ret); - ret = WS_BAD_ARGUMENT; - } + fprintf(stderr, "Port number %d too big.\n", ret); + ret = WS_BAD_ARGUMENT; } } - break; + } + break; - case 'h': - hostKeyFile = myoptarg; - break; + case 'h': + hostKeyFile = myoptarg; + break; - case 'd': - debugMode = 1; /* turn on debug mode */ - break; + case 'd': + debugMode = 1; /* turn on debug mode */ + break; - case 'D': - isDaemon = 0; - break; + case 'D': + isDaemon = 0; + break; - case 'E': - logFile = fopen(myoptarg, "ab"); - if (logFile == NULL) { - fprintf(stderr, "Unable to open log file %s\n", myoptarg); - ret = WS_FATAL_ERROR; - } - break; + case 'E': + ret = WFOPEN(&logFile, myoptarg, "ab"); + if (ret != 0 || logFile == WBADFILE) { + fprintf(stderr, "Unable to open log file %s\n", myoptarg); + ret = WS_FATAL_ERROR; + } + break; - case 'o': - #ifdef WOLFSSH_IGNORE_UNKNOWN_CONFIG - wolfSSH_Log(WS_LOG_DEBUG, "[SSHD] ignoring -o."); - break; - #else - ShowUsage(); - return WS_FATAL_ERROR; - #endif + case 'o': + #ifdef WOLFSSH_IGNORE_UNKNOWN_CONFIG + wolfSSH_Log(WS_LOG_DEBUG, "[SSHD] ignoring -o."); + break; + #else + ShowUsage(); + return WS_FATAL_ERROR; + #endif - case 't': - testMode = 1; - break; + case 't': + testMode = 1; + break; - case '?': - ShowUsage(); - return WS_SUCCESS; + case '?': + ShowUsage(); + #ifndef _WIN32 + return WS_SUCCESS; + #else + return; + #endif - default: - ShowUsage(); - return WS_SUCCESS; + default: + ShowUsage(); + #ifndef _WIN32 + return WS_SUCCESS; + #else + return; + #endif } } if (ret == WS_SUCCESS) { ret = wolfSSHD_ConfigLoad(conf, configFile); if (ret != WS_SUCCESS) { - fprintf(stderr, "Error reading in configure file %s\n", configFile); + wolfSSH_Log(WS_LOG_ERROR, "Error reading in configure file %s\n", + configFile); } } @@ -1397,9 +1960,6 @@ int main(int argc, char** argv) wolfSSH_Log(WS_LOG_INFO, "[SSHD] Starting wolfSSH SSHD application"); ret = SetupCTX(conf, &ctx); } - else { - /* TODO: handle error. */ - } if (ret == WS_SUCCESS) { auth = wolfSSHD_AuthCreateUser(NULL, conf); @@ -1413,7 +1973,8 @@ int main(int argc, char** argv) logFile = stderr; } - /* run as a daemon */ + /* run as a daemon or service */ +#ifndef WIN32 if (ret == WS_SUCCESS && isDaemon) { pid_t p; @@ -1459,8 +2020,8 @@ int main(int argc, char** argv) } else { if (dup2(fd, STDIN_FILENO) < 0 || - dup2(fd, STDOUT_FILENO) < 0 || - dup2(fd, STDERR_FILENO) < 0) { + dup2(fd, STDOUT_FILENO) < 0 || + dup2(fd, STDERR_FILENO) < 0) { ret = WS_FATAL_ERROR; } close(fd); @@ -1468,6 +2029,38 @@ int main(int argc, char** argv) } } } +#else + if (isDaemon) { + /* Set function to handle service query and commands */ + serviceStatusHandle = RegisterServiceCtrlHandler(WOLFSSHD_SERVICE_NAME, wolfSSHD_ServiceCb); + if (serviceStatusHandle == NULL) { + ret = WS_FATAL_ERROR; + } + else { + /* Update service status as 'start pending' */ + ZeroMemory(&serviceStatus, sizeof(serviceStatus)); + serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + serviceStatus.dwCurrentState = SERVICE_START_PENDING; + if (SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE) { + wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue updating service status"); + } + } + + /* Create a stop event to watch on */ + serviceStop = CreateEvent(NULL, TRUE, FALSE, NULL); + if (serviceStop == NULL) { + serviceStatus.dwControlsAccepted = 0; + serviceStatus.dwCurrentState = SERVICE_STOPPED; + serviceStatus.dwWin32ExitCode = GetLastError(); + serviceStatus.dwCheckPoint = 1; + + if (SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE) { + wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue updating service status"); + } + return; + } + } +#endif if (ret == WS_SUCCESS) { wolfSSHD_ConfigSavePID(conf); @@ -1482,61 +2075,149 @@ int main(int argc, char** argv) tcp_listen(&listenFd, &port, 1); wolfSSH_Log(WS_LOG_INFO, "[SSHD] Listening on port %d", port); + #ifdef WIN32 + if (ret == WS_SUCCESS && isDaemon) { + /* update service status as started */ + serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; + serviceStatus.dwCurrentState = SERVICE_RUNNING; + serviceStatus.dwWin32ExitCode = 0; + serviceStatus.dwCheckPoint = 0; + + if (SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE) { + wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue updating service status"); + } + } + #endif /* wait for incoming connections and fork them off */ while (ret == WS_SUCCESS && quit == 0) { WOLFSSHD_CONNECTION conn; - #ifdef WOLFSSL_NUCLEUS +#ifdef WOLFSSL_NUCLEUS struct addr_struct clientAddr; - #else +#else SOCKADDR_IN_T clientAddr; socklen_t clientAddrSz = sizeof(clientAddr); - #endif +#endif conn.auth = auth; - conn.listenFd = listenFd; + conn.listenFd = (int)listenFd; + conn.isThreaded = isDaemon; /* wait for a connection */ if (PendingConnection(listenFd)) { conn.ctx = ctx; - #ifdef WOLFSSL_NUCLEUS +#ifdef WOLFSSL_NUCLEUS conn.fd = NU_Accept(listenFd, &clientAddr, 0); - #else - conn.fd = accept(listenFd, (struct sockaddr*)&clientAddr, - &clientAddrSz); +#else + conn.fd = (int)accept(listenFd, (struct sockaddr*)&clientAddr, + &clientAddrSz); if (conn.fd >= 0) { inet_ntop(AF_INET, &clientAddr.sin_addr, conn.ip, INET_ADDRSTRLEN); } - #endif +#endif { - #ifdef USE_WINDOWS_API - unsigned long blocking = 1; - int ret = ioctlsocket(conn.fd, FIONBIO, &blocking); - if (ret == SOCKET_ERROR) - err_sys("ioctlsocket failed"); - #elif defined(WOLFSSL_MDK_ARM) || defined(WOLFSSL_KEIL_TCP_NET) \ +#ifdef USE_WINDOWS_API + unsigned long blocking = 1; + if (ioctlsocket(conn.fd, FIONBIO, &blocking) + == SOCKET_ERROR) + err_sys("ioctlsocket failed"); +#elif defined(WOLFSSL_MDK_ARM) || defined(WOLFSSL_KEIL_TCP_NET) \ || defined (WOLFSSL_TIRTOS)|| defined(WOLFSSL_VXWORKS) || \ defined(WOLFSSL_NUCLEUS) - /* non blocking not supported, for now */ - #else - int flags = fcntl(conn.fd, F_GETFL, 0); - if (flags < 0) - err_sys("fcntl get failed"); - flags = fcntl(conn.fd, F_SETFL, flags | O_NONBLOCK); - if (flags < 0) - err_sys("fcntl set failed"); - #endif + /* non blocking not supported, for now */ +#else + int flags = fcntl(conn.fd, F_GETFL, 0); + if (flags < 0) + err_sys("fcntl get failed"); + flags = fcntl(conn.fd, F_SETFL, flags | O_NONBLOCK); + if (flags < 0) + err_sys("fcntl set failed"); +#endif } ret = NewConnection(&conn); } +#ifdef _WIN32 + /* check if service has been shutdown */ + if (isDaemon && WaitForSingleObject(serviceStop, 0) == WAIT_OBJECT_0) { + quit = 1; + } +#endif } } +#ifdef _WIN32 + /* close down windows service */ + if (isDaemon) { + CloseHandle(serviceStop); + + serviceStatus.dwControlsAccepted = 0; + serviceStatus.dwCurrentState = SERVICE_STOPPED; + serviceStatus.dwWin32ExitCode = 0; + serviceStatus.dwCheckPoint = 3; + + if (serviceStatusHandle != NULL && + SetServiceStatus(serviceStatusHandle, &serviceStatus) == FALSE) { + wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue updating service status"); + } + } +#endif + CleanupCTX(conf, &ctx); wolfSSHD_ConfigFree(conf); wolfSSHD_AuthFreeUser(auth); wolfSSH_Cleanup(); +#ifdef _WIN32 + if (isDaemon) { /* free up temporary memory used for conversion of args from wchar_t */ + unsigned int z; + for (z = 0; z < argc; z++) { + WFREE(argv[z], NULL, DYNTYPE_SSHD); + } + WFREE(argv, NULL, DYNTYPE_SSHD); + } +#else + return 0; +#endif +} + +int main(int argc, char** argv) +{ +#ifdef _WIN32 + /* First look if this is a service being started */ + int i, isService = 1; + for (i = 0; i < argc; i++) { + if (WSTRCMP(argv[i], "-D") == 0) { + isService = 0; + } + } + + if (isService) { + SERVICE_TABLE_ENTRY ServiceTable[] = + { + {_T("wolfSSHd"), (LPSERVICE_MAIN_FUNCTION)StartSSHD}, + {NULL, NULL} + }; + + if (StartServiceCtrlDispatcher(ServiceTable) == FALSE) { + printf("StartServiceCtrlDispatcher failed\n"); + return GetLastError(); + } + } + else { + StartSSHD(argc, (LPSTR*)argv); + } return 0; +#else + return StartSSHD(argc, argv); +#endif +} + +#else +/* helpful print out if compiling without SSHD feature enabled */ +int main(int argc, char** argv) +{ + printf("Not compiled in. Please recompile wolfSSH with :\n"); + printf("--enable-sshd (user_settings.h macro define WOLFSSH_SSHD\n"); + return -1; } #endif /* WOLFSSH_SSHD */ diff --git a/examples/client/client.c b/examples/client/client.c index 88c48d9fa..b1cc0bf33 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -188,6 +188,52 @@ typedef struct thread_args { #define THREAD_RET_SUCCESS 0 #endif + +#ifndef _MSC_VER +#include +static sem_t windowSem; + +/* capture window change signales */ +static void WindowChangeSignal(int sig) +{ + sem_post(&windowSem); + (void)sig; +} + + +static int sendCurrentWindowSize(thread_args* args) +{ + struct winsize windowSize = {0,0,0,0}; + int ret; + + wc_LockMutex(&args->lock); + ioctl(STDOUT_FILENO, TIOCGWINSZ, &windowSize); + ret = wolfSSH_ChangeTerminalSize(args->ssh, + windowSize.ws_col, windowSize.ws_row, + windowSize.ws_xpixel, windowSize.ws_ypixel); + wc_UnLockMutex(&args->lock); + + return ret; +} + + +/* thread for handling window size adjustments */ +static THREAD_RET windowMonitor(void* in) +{ + thread_args* args; + int ret; + + args = (thread_args*)in; + do { + sem_wait(&windowSem); + ret = sendCurrentWindowSize(args); + (void)ret; + } while (1); + + return THREAD_RET_SUCCESS; +} +#endif + static THREAD_RET readInput(void* in) { byte buf[256]; @@ -240,7 +286,7 @@ static THREAD_RET readInput(void* in) static THREAD_RET readPeer(void* in) { - byte buf[80]; + byte buf[256]; int bufSz = sizeof(buf); thread_args* args = (thread_args*)in; int ret = 0; @@ -257,6 +303,13 @@ static THREAD_RET readPeer(void* in) FD_SET(fd, &readSet); FD_SET(fd, &errSet); +#ifdef USE_WINDOWS_API + /* set handle to use for window resize */ + wc_LockMutex(&args->lock); + wolfSSH_SetTerminalResizeCtx(args->ssh, stdoutHandle); + wc_UnLockMutex(&args->lock); +#endif + while (ret >= 0) { bytes = select(fd + 1, &readSet, NULL, &errSet, NULL); wc_LockMutex(&args->lock); @@ -271,7 +324,13 @@ static THREAD_RET readPeer(void* in) if (ret < 0) err_sys("Extended data read failed."); buf[bufSz - 1] = '\0'; + #ifdef USE_WINDOWS_API fprintf(stderr, "%s", buf); + #else + if (write(STDERR_FILENO, buf, ret) < 0) { + perror("Issue with stderr write "); + } + #endif } while (ret > 0); } else if (ret <= 0) { @@ -334,7 +393,9 @@ static THREAD_RET readPeer(void* in) fflush(stdout); } #else - printf("%s", buf); + if (write(STDOUT_FILENO, buf, ret) < 0) { + perror("write to stdout error "); + } fflush(stdout); #endif } @@ -636,7 +697,7 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) } else #endif - { + if (pubKeyName) { ret = ClientUsePubKey(pubKeyName, userEcc); } if (ret != 0) { @@ -735,18 +796,43 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) if (cmd != NULL || keepOpen == 1) { #if defined(_POSIX_THREADS) thread_args arg; - pthread_t thread[2]; + pthread_t thread[3]; arg.ssh = ssh; wc_InitMutex(&arg.lock); - pthread_create(&thread[0], NULL, readInput, (void*)&arg); - pthread_create(&thread[1], NULL, readPeer, (void*)&arg); - pthread_join(thread[1], NULL); + sem_init(&windowSem, 0, 0); + + /* send current terminal size */ + ret = sendCurrentWindowSize(&arg); + + signal(SIGWINCH, WindowChangeSignal); + pthread_create(&thread[0], NULL, windowMonitor, (void*)&arg); + pthread_create(&thread[1], NULL, readInput, (void*)&arg); + pthread_create(&thread[2], NULL, readPeer, (void*)&arg); + pthread_join(thread[2], NULL); pthread_cancel(thread[0]); + pthread_cancel(thread[1]); + sem_destroy(&windowSem); #elif defined(_MSC_VER) thread_args arg; HANDLE thread[2]; + /* send the console size to server */ + { + CONSOLE_SCREEN_BUFFER_INFO cs; + word32 col = 80, row = 24; + + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cs) == 0) { + fprintf(stderr, "Failed to get the current console size\r\n"); + fprintf(stderr, "Using default col = 80 row = 24\r\n"); + } + else { + col = cs.srWindow.Right - cs.srWindow.Left + 1; + row = cs.srWindow.Bottom - cs.srWindow.Top + 1; + } + wolfSSH_ChangeTerminalSize(ssh, col, row, 0, 0); + } + arg.ssh = ssh; arg.rawMode = rawMode; wc_InitMutex(&arg.lock); @@ -792,18 +878,21 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) #endif } ret = wolfSSH_shutdown(ssh); - if (ret != WS_SUCCESS) { - err_sys("Sending the shutdown messages failed."); - } - ret = wolfSSH_worker(ssh, NULL); - if (ret != WS_SUCCESS) { - err_sys("Failed to listen for close messages from the peer."); + /* do not continue on with shutdown process if peer already disconnected */ + if (ret != WS_SOCKET_ERROR_E && wolfSSH_get_error(ssh) != WS_SOCKET_ERROR_E) { + if (ret != WS_SUCCESS) { + err_sys("Sending the shutdown messages failed."); + } + ret = wolfSSH_worker(ssh, NULL); + if (ret != WS_SUCCESS) { + err_sys("Failed to listen for close messages from the peer."); + } } WCLOSESOCKET(sockFd); wolfSSH_free(ssh); wolfSSH_CTX_free(ctx); - if (ret != WS_SUCCESS) - err_sys("Closing client stream failed. Connection could have been closed by peer"); + if (ret != WS_SUCCESS && ret != WS_SOCKET_ERROR_E) + err_sys("Closing client stream failed"); ClientFreeBuffers(pubKeyName, privKeyName); #if !defined(WOLFSSH_NO_ECC) && defined(FP_ECC) && defined(HAVE_THREAD_LS) diff --git a/examples/scpclient/scpclient.c b/examples/scpclient/scpclient.c index b28210639..3ee5a5334 100644 --- a/examples/scpclient/scpclient.c +++ b/examples/scpclient/scpclient.c @@ -310,17 +310,20 @@ THREAD_RETURN WOLFSSH_THREAD scp_client(void* args) err_sys("Couldn't copy the file."); ret = wolfSSH_shutdown(ssh); - if (ret != WS_SUCCESS) { - err_sys("Sending the shutdown messages failed."); - } - ret = wolfSSH_worker(ssh, NULL); - if (ret != WS_SUCCESS && ret != WS_CHANNEL_CLOSED) { - err_sys("Failed to listen for close messages from the peer."); + /* do not continue on with shutdown process if peer already disconnected */ + if (ret != WS_SOCKET_ERROR_E && wolfSSH_get_error(ssh) != WS_SOCKET_ERROR_E) { + if (ret != WS_SUCCESS) { + err_sys("Sending the shutdown messages failed."); + } + ret = wolfSSH_worker(ssh, NULL); + if (ret != WS_SUCCESS && ret != WS_CHANNEL_CLOSED) { + err_sys("Failed to listen for close messages from the peer."); + } } WCLOSESOCKET(sockFd); wolfSSH_free(ssh); wolfSSH_CTX_free(ctx); - if (ret != WS_SUCCESS) + if (ret != WS_SUCCESS && ret != WS_SOCKET_ERROR_E) err_sys("Closing scp stream failed. Connection could have been closed by peer"); ClientFreeBuffers(pubKeyName, privKeyName); diff --git a/examples/sftpclient/sftpclient.c b/examples/sftpclient/sftpclient.c index 5f084adcf..44208f16c 100644 --- a/examples/sftpclient/sftpclient.c +++ b/examples/sftpclient/sftpclient.c @@ -1032,8 +1032,9 @@ static int doAutopilot(int cmd, char* local, char* remote) } if (remoteAbsPath) { - WMEMSET(fullpath, 0, sizeof(fullpath)); - WSTRNCPY(fullpath, remote, sizeof(fullpath) - 1); + /* use remote absolute path if provided */ + WMEMSET(fullpath, 0, sizeof(fullpath)); + WSTRNCPY(fullpath, remote, sizeof(fullpath) - 1); } else { do { @@ -1332,7 +1333,11 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args) WFREE(workingDir, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (ret == WS_SUCCESS) { if (wolfSSH_shutdown(ssh) != WS_SUCCESS) { - printf("error with wolfSSH_shutdown(), already disconnected?\n"); + int rc; + rc = wolfSSH_get_error(ssh); + + if (rc != WS_SOCKET_ERROR_E && rc != WS_EOF) + printf("error with wolfSSH_shutdown()\n"); } } WCLOSESOCKET(sockFd); diff --git a/ide/winvs/README.md b/ide/winvs/README.md index 3edc9c49a..9b516e766 100644 --- a/ide/winvs/README.md +++ b/ide/winvs/README.md @@ -55,3 +55,19 @@ This value is used in the debugging environment for the echoserver's When you run the echoserver from the debugger, it finds the wolfSSL DLL in that directory. + + +SSHD Service +----------- + +Creating a new servie +`sc.exe create wolfSSHd binpath=D:\work\wolfssh\ide\winvs\Debug\x64\wolfsshd.exe` + +Starting wolfSSHd service run the following command in an adminstrator power shell session: +`sc.exe start wolfSSHd -f -h -p ` + +To stop the service run the following in an adminstrator power shell session: +`sc.exe stop wolfSSHd` + +To delete the service run +`sc.exe delete wolfSSHd` \ No newline at end of file diff --git a/ide/winvs/include.am b/ide/winvs/include.am index 647adaf6d..d5a90eaf4 100644 --- a/ide/winvs/include.am +++ b/ide/winvs/include.am @@ -18,3 +18,5 @@ EXTRA_DIST+= ide/winvs/testsuite/testsuite.vcxproj EXTRA_DIST+= ide/winvs/testsuite/testsuite.vcxproj.user EXTRA_DIST+= ide/winvs/wolfsftp-client/wolfsftp-client.vcxproj EXTRA_DIST+= ide/winvs/wolfsftp-client/wolfsftp-client.vcxproj.user +EXTRA_DIST+= ide/winvs/wolfsshd/wolfsshd.vcxproj +EXTRA_DIST+= ide/winvs/wolfsshd/wolfsshd.vcxproj.user diff --git a/ide/winvs/user_settings.h b/ide/winvs/user_settings.h index 0d1fa1f07..d923629bf 100644 --- a/ide/winvs/user_settings.h +++ b/ide/winvs/user_settings.h @@ -13,6 +13,7 @@ #define HAVE_AESGCM #define HAVE_HASHDRBG #define WOLFSSL_AES_COUNTER +#define WOLFSSL_AES_DIRECT #define WOLFSSL_SHA384 #define WOLFSSL_SHA512 #define NO_PSK @@ -23,9 +24,58 @@ #define NO_MD4 #define WC_RSA_BLINDING #define WOLFSSL_PUBLIC_MP -#define SINGLE_THREADED #define WC_NO_HARDEN #define WOLFSSH_TERM +#ifndef WOLFSSH_TERM + /* Threading is needed for opening a psuedo terminal in the examples */ + #define SINGLE_THREADED +#endif + +/* adding X509 support */ +#if 0 + /* Uses CertManager which is in the TLS layer */ + #undef WOLFCRYPT_ONLY + + #undef WOLFSSL_CERT_GEN + #define WOLFSSL_CERT_GEN + + /* Used for comparing IP of peer with IP found in certificate */ + #undef WOLFSSL_IP_ALT_NAME + #define WOLFSSL_IP_ALT_NAME + + #undef HAVE_TLS_EXTENSIONS + #define HAVE_TLS_EXTENSIONS + + #undef OPENSSL_ALL + #define OPENSSL_ALL + + /* Turn off additional FPKI support checks (Federal PKI) on certificates */ + #undef WOLFSSH_NO_FPKI + #define WOLFSSH_NO_FPKI + + #undef WOLFSSH_CERTS + #define WOLFSSH_CERTS +#endif + + +/* default SSHD options */ +#if 0 + #undef WOLFSSH_SSHD + #define WOLFSSH_SSHD + + /* handle shell connections */ + #undef WOLFSSH_SHELL + #define WOLFSSH_SHELL + + /* handle SCP connection requests */ + #undef WOLFSSH_SCP + #define WOLFSSH_SCP + + /* handle SFTP connection requests */ + #undef WOLFSSH_SFTP + #define WOLFSSH_SFTP + +#endif #endif /* _WIN_USER_SETTINGS_H_ */ diff --git a/ide/winvs/wolfssh.sln b/ide/winvs/wolfssh.sln index 91cb79d4d..9f4878726 100644 --- a/ide/winvs/wolfssh.sln +++ b/ide/winvs/wolfssh.sln @@ -21,6 +21,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testsuite", "testsuite\test EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wolfsftp-client", "wolfsftp-client\wolfsftp-client.vcxproj", "{8DD810D6-159B-4C40-B682-FCA11F9B3680}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wolfsshd", "wolfsshd\wolfsshd.vcxproj", "{9A31DAB4-6292-4ECB-BE35-C60D925C571E}" + ProjectSection(ProjectDependencies) = postProject + {7C2CCF0D-A155-4914-BD1C-9A47C0530E65} = {7C2CCF0D-A155-4914-BD1C-9A47C0530E65} + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -141,6 +146,22 @@ Global {8DD810D6-159B-4C40-B682-FCA11F9B3680}.Release|Win32.Build.0 = Release|Win32 {8DD810D6-159B-4C40-B682-FCA11F9B3680}.Release|x64.ActiveCfg = Release|x64 {8DD810D6-159B-4C40-B682-FCA11F9B3680}.Release|x64.Build.0 = Release|x64 + {9A31DAB4-6292-4ECB-BE35-C60D925C571E}.Debug|Win32.ActiveCfg = Debug|Win32 + {9A31DAB4-6292-4ECB-BE35-C60D925C571E}.Debug|Win32.Build.0 = Debug|Win32 + {9A31DAB4-6292-4ECB-BE35-C60D925C571E}.Debug|x64.ActiveCfg = Debug|x64 + {9A31DAB4-6292-4ECB-BE35-C60D925C571E}.Debug|x64.Build.0 = Debug|x64 + {9A31DAB4-6292-4ECB-BE35-C60D925C571E}.DLL Debug|Win32.ActiveCfg = Debug|Win32 + {9A31DAB4-6292-4ECB-BE35-C60D925C571E}.DLL Debug|Win32.Build.0 = Debug|Win32 + {9A31DAB4-6292-4ECB-BE35-C60D925C571E}.DLL Debug|x64.ActiveCfg = Debug|x64 + {9A31DAB4-6292-4ECB-BE35-C60D925C571E}.DLL Debug|x64.Build.0 = Debug|x64 + {9A31DAB4-6292-4ECB-BE35-C60D925C571E}.DLL Release|Win32.ActiveCfg = Release|Win32 + {9A31DAB4-6292-4ECB-BE35-C60D925C571E}.DLL Release|Win32.Build.0 = Release|Win32 + {9A31DAB4-6292-4ECB-BE35-C60D925C571E}.DLL Release|x64.ActiveCfg = Release|x64 + {9A31DAB4-6292-4ECB-BE35-C60D925C571E}.DLL Release|x64.Build.0 = Release|x64 + {9A31DAB4-6292-4ECB-BE35-C60D925C571E}.Release|Win32.ActiveCfg = Release|Win32 + {9A31DAB4-6292-4ECB-BE35-C60D925C571E}.Release|Win32.Build.0 = Release|Win32 + {9A31DAB4-6292-4ECB-BE35-C60D925C571E}.Release|x64.ActiveCfg = Release|x64 + {9A31DAB4-6292-4ECB-BE35-C60D925C571E}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ide/winvs/wolfssh/wolfssh.vcxproj b/ide/winvs/wolfssh/wolfssh.vcxproj index ab5ea5ca3..7cbf362f9 100644 --- a/ide/winvs/wolfssh/wolfssh.vcxproj +++ b/ide/winvs/wolfssh/wolfssh.vcxproj @@ -35,12 +35,14 @@ + + @@ -313,4 +315,4 @@ - + \ No newline at end of file diff --git a/ide/winvs/wolfsshd/wolfsshd.vcxproj b/ide/winvs/wolfsshd/wolfsshd.vcxproj new file mode 100644 index 000000000..b4d4b216a --- /dev/null +++ b/ide/winvs/wolfsshd/wolfsshd.vcxproj @@ -0,0 +1,152 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + + + + + + 16.0 + Win32Proj + {9a31dab4-6292-4ecb-be35-c60d925c571e} + wolfsshd + + + + Application + true + v100 + Unicode + + + Application + false + v100 + true + Unicode + + + Application + true + v100 + Unicode + + + Application + false + v100 + true + Unicode + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)$(Configuration)\$(Platform)\ + $(Configuration)\$(Platform)\ + + + $(SolutionDir)$(Configuration)\$(Platform)\ + $(Configuration)\$(Platform)\ + + + + Level3 + true + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + ..\..\..\..\wolfssl\Debug\Win32;..\Debug\Win32 + + + + + Level3 + true + true + true + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + + + Console + true + true + true + ..\..\..\..\wolfssl\Release\Win32;..\Release\Win32 + + + + + Level3 + true + _CRT_SECURE_NO_DEPRECATE;WOLFSSL_USER_SETTINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + ..;..\..\..;..\..\..\..\wolfssl;..\..\..\apps\wolfsshd\;%(AdditionalIncludeDirectories) + + + Console + true + ..\..\..\..\wolfssl\Debug\x64;..\Debug\x64 + wolfssl.lib;wolfssh.lib;ws2_32.lib;secur32.lib;userenv.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) + + + + + Level3 + true + true + true + WOLFSSL_USER_SETTINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + ..;..\..\..;..\..\..\..\wolfssl;..\..\..\apps\wolfsshd\;%(AdditionalIncludeDirectories) + + + Console + true + true + true + wolfssl.lib;wolfssh.lib;ws2_32.lib;secur32.lib;userenv.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) + ..\..\..\..\wolfssl\Release\x64;..\Release\x64 + + + + + + diff --git a/ide/winvs/wolfsshd/wolfsshd.vcxproj.user b/ide/winvs/wolfsshd/wolfsshd.vcxproj.user new file mode 100644 index 000000000..e9f3ec837 --- /dev/null +++ b/ide/winvs/wolfsshd/wolfsshd.vcxproj.user @@ -0,0 +1,13 @@ + + + + + + WindowsLocalDebugger + + + + + WindowsLocalDebugger + + \ No newline at end of file diff --git a/src/internal.c b/src/internal.c index f927bdc2b..b1a678e52 100644 --- a/src/internal.c +++ b/src/internal.c @@ -630,6 +630,35 @@ void CtxResourceFree(WOLFSSH_CTX* ctx) } +#ifdef WOLFSSH_TERM +/* default terminal resize handling callbacks */ + +#ifdef USE_WINDOWS_API +static int WS_WindowsTermResize(WOLFSSH* ssh, word32 col, word32 row, word32 colP, + word32 rowP, void* usrCtx) +{ + HPCON* term = (HPCON*)usrCtx; + int ret = WS_SUCCESS; + + if (term != NULL) { + HRESULT ret; + COORD sz; + + sz.X = col; + sz.Y = row; + ret = ResizePseudoConsole(*term, sz); + if (ret != S_OK) { + WLOG(WS_LOG_ERROR, "Issue with pseudo console resize"); + ret = WS_FATAL_ERROR; + } + } + + return ret; +} +#endif + +#endif /* WOLFSSH_TERM */ + WOLFSSH* SshInit(WOLFSSH* ssh, WOLFSSH_CTX* ctx) { #if defined(STM32F2) || defined(STM32F4) || defined(FREESCALE_MQX) @@ -722,6 +751,12 @@ WOLFSSH* SshInit(WOLFSSH* ssh, WOLFSSH_CTX* ctx) ssh->agentEnabled = ctx->agentEnabled; #endif +#ifdef WOLFSSH_TERM + #if defined(USE_WINDOWS_API) + ssh->termResizeCb = WS_WindowsTermResize; + #endif +#endif + if (BufferInit(&ssh->inputBuffer, 0, ctx->heap) != WS_SUCCESS || BufferInit(&ssh->outputBuffer, 0, ctx->heap) != WS_SUCCESS || BufferInit(&ssh->extDataBuffer, 0, ctx->heap) != WS_SUCCESS) { @@ -6731,7 +6766,7 @@ static int DoChannelRequest(WOLFSSH* ssh, char term[32]; word32 termSz; word32 widthChar, heightRows, widthPixels, heightPixels; - word32 modesSz; + byte opCode = 0; termSz = (word32)sizeof(term); ret = GetString(term, &termSz, buf, len, &begin); @@ -6743,8 +6778,14 @@ static int DoChannelRequest(WOLFSSH* ssh, ret = GetUint32(&widthPixels, buf, len, &begin); if (ret == WS_SUCCESS) ret = GetUint32(&heightPixels, buf, len, &begin); - if (ret == WS_SUCCESS) - ret = GetUint32(&modesSz, buf, len, &begin); + + /* itterate over op codes */ + if (ret == WS_SUCCESS) { + do { + opCode = buf[begin]; + begin++; + } while (opCode != 0 && begin < len); + } if (ret == WS_SUCCESS) { WLOG(WS_LOG_DEBUG, " term = %s", term); @@ -6752,7 +6793,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); - WLOG(WS_LOG_DEBUG, " modes = %u", (modesSz - 1) / 5); + ssh->curX = widthChar; + ssh->curY = heightRows; + if (ssh->termResizeCb) { + if (ssh->termResizeCb(ssh, widthChar, heightRows, widthPixels, + heightPixels, ssh->termCtx) != WS_SUCCESS) { + ret = WS_FATAL_ERROR; + } + } } } else @@ -6802,6 +6850,34 @@ static int DoChannelRequest(WOLFSSH* ssh, WLOG(WS_LOG_AGENT, "Agent callback not set, not using."); } #endif /* WOLFSSH_AGENT */ +#ifdef WOLFSSH_SHELL + else if (WSTRNCMP(type, "window-change", typeSz) == 0) { + word32 widthChar, heightRows, widthPixels, heightPixels; + + ret = GetUint32(&widthChar, buf, len, &begin); + if (ret == WS_SUCCESS) + ret = GetUint32(&heightRows, buf, len, &begin); + if (ret == WS_SUCCESS) + ret = GetUint32(&widthPixels, buf, len, &begin); + if (ret == WS_SUCCESS) + ret = GetUint32(&heightPixels, buf, len, &begin); + + if (ret == WS_SUCCESS) { + 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; + if (ssh->termResizeCb) { + if (ssh->termResizeCb(ssh, widthChar, heightRows, widthPixels, + heightPixels, ssh->termCtx) != WS_SUCCESS) { + ret = WS_FATAL_ERROR; + } + } + } + } +#endif } if (ret == WS_SUCCESS) @@ -12906,6 +12982,68 @@ static int CreateMode(WOLFSSH* ssh, byte* mode) } +int SendChannelTerminalResize(WOLFSSH* ssh, word32 columns, word32 rows, + word32 widthPixels, word32 heightPixels) +{ + int ret = WS_SUCCESS; + byte* output; + word32 idx; + WOLFSSH_CHANNEL* channel = NULL; + const char* cType = "window-change"; + word32 typeSz = 0; + + if (ret == WS_SUCCESS) { + channel = ChannelFind(ssh, + ssh->defaultPeerChannelId, WS_CHANNEL_ID_PEER); + if (channel == NULL) + ret = WS_INVALID_CHANID; + } + + if (ret == WS_SUCCESS) { + typeSz = (word32)sizeof(cType) - 1; + ret = PreparePacket(ssh, MSG_ID_SZ + UINT32_SZ + LENGTH_SZ + + typeSz + BOOLEAN_SZ + (4 * UINT32_SZ)); + } + + if (ret == WS_SUCCESS) { + output = ssh->outputBuffer.buffer; + idx = ssh->outputBuffer.length; + + output[idx++] = MSGID_CHANNEL_REQUEST; + c32toa(channel->peerChannel, output + idx); + idx += UINT32_SZ; + c32toa(typeSz, output + idx); + idx += LENGTH_SZ; + WMEMCPY(output + idx, cType, typeSz); + idx += typeSz; + output[idx++] = 0; + + c32toa(columns, output + idx); + idx += UINT32_SZ; + c32toa(rows, output + idx); + idx += UINT32_SZ; + c32toa(widthPixels, output + idx); + idx += UINT32_SZ; + c32toa(heightPixels, output + idx); + idx += UINT32_SZ; + + ssh->outputBuffer.length = idx; + + WLOG(WS_LOG_INFO, "Sending Channel Request: "); + WLOG(WS_LOG_INFO, " channelId = %u", channel->peerChannel); + WLOG(WS_LOG_INFO, " type = %s", cType); + WLOG(WS_LOG_INFO, " wantReply = %u", 0); + + ret = BundlePacket(ssh); + } + + if (ret == WS_SUCCESS) + ret = wolfSSH_SendPacket(ssh); + + return ret; +} + + /* sends request for pseudo-terminal (rfc 4254) * returns WS_SUCCESS on success */ int SendChannelTerminalRequest(WOLFSSH* ssh) diff --git a/src/ssh.c b/src/ssh.c index b94debaef..e08091a46 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -1316,6 +1316,41 @@ void* wolfSSH_GetPublicKeyCheckCtx(WOLFSSH* ssh) } +/* Used to resize terminal window with shell connections + * returns WS_SUCCESS on success */ +int wolfSSH_ChangeTerminalSize(WOLFSSH* ssh, word32 columns, word32 rows, + word32 widthPixels, word32 heightPixels) +{ + int ret = WS_SUCCESS; + + WLOG(WS_LOG_DEBUG, "Entering wolfSSH_ChangeWindowDimension()"); + + if (ssh == NULL) + ret = WS_BAD_ARGUMENT; + + if (ret == WS_SUCCESS) { + ret = SendChannelTerminalResize(ssh, columns, rows, widthPixels, + heightPixels); + } + + WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_ChangeWindowDimension(), ret = %d", + ret); + return ret; +} + + +void wolfSSH_SetTerminalResizeCb(WOLFSSH* ssh, WS_CallbackTerminalSize cb) +{ + ssh->termResizeCb = cb; +} + + +void wolfSSH_SetTerminalResizeCtx(WOLFSSH* ssh, void* usrCtx) +{ + ssh->termCtx = usrCtx; +} + + /* Used to set the channel request type sent in wolfSSH connect. The default * type set is shell if this function is not called. * diff --git a/src/wolfscp.c b/src/wolfscp.c index f3db331ef..46c6eaffc 100644 --- a/src/wolfscp.c +++ b/src/wolfscp.c @@ -1095,7 +1095,7 @@ static int ScpCheckForRename(WOLFSSH* ssh, int cmdSz) WSTRNCPY(buf, ssh->scpBasePath, cmdSz); buf[sz] = '\0'; - WSTRNCAT(buf, "/..", sizeof("/..")); + WSTRNCAT(buf, "/..", DEFAULT_SCP_MSG_SZ); idx = wolfSSH_CleanPath(ssh, buf); if (idx < 0) { @@ -1143,7 +1143,7 @@ static int ScpCheckForRename(WOLFSSH* ssh, int cmdSz) WLOG(WS_LOG_DEBUG, "scp: renaming from %s to %s", ssh->scpFileName, ssh->scpBasePath + idx); ssh->scpFileReName = ssh->scpFileName; - WSTRNCPY(ssh->scpFileName, ssh->scpBasePath + idx, sz); + WSTRNCPY(ssh->scpFileName, ssh->scpBasePath + idx, sz + 1); ssh->scpFileName[sz] = '\0'; ssh->scpFileNameSz = sz; *((char*)ssh->scpBasePath + idx) = '\0'; @@ -1158,15 +1158,16 @@ static int ScpCheckForRename(WOLFSSH* ssh, int cmdSz) * returns WS_SUCCESS on success */ static int ParseBasePathHelper(WOLFSSH* ssh, int cmdSz) { - int ret = 0; + int ret; ret = ScpCheckForRename(ssh, cmdSz); #ifndef NO_FILESYSTEM - { + if (ret == WS_SUCCESS) { ScpSendCtx ctx; WMEMSET(&ctx, 0, sizeof(ScpSendCtx)); if (ScpPushDir(&ctx, ssh->scpBasePath, ssh->ctx->heap) != WS_SUCCESS) { WLOG(WS_LOG_DEBUG, "scp : issue opening base dir"); + ret = WS_FATAL_ERROR; } else { ret = ScpPopDir(&ctx, ssh->ctx->heap); @@ -1261,7 +1262,8 @@ int ParseScpCommand(WOLFSSH* ssh) ssh->scpBasePath = cmd + idx; #endif ret = ParseBasePathHelper(ssh, cmdSz); - if (wolfSSH_CleanPath(ssh, (char*)ssh->scpBasePath) < 0) + if (ret == WS_SUCCESS && + wolfSSH_CleanPath(ssh, (char*)ssh->scpBasePath) < 0) ret = WS_FATAL_ERROR; } break; @@ -1766,29 +1768,42 @@ static INLINE int wolfSSH_LastError(void) return errno; } + /* set file access and modification times * Returns WS_SUCCESS on success, or negative upon error */ static int SetTimestampInfo(const char* fileName, word64 mTime, word64 aTime) { int ret = WS_SUCCESS; +#ifdef USE_WINDOWS_API + struct _utimbuf tmp; + int fd; +#else struct timeval tmp[2]; +#endif if (fileName == NULL) ret= WS_BAD_ARGUMENT; if (ret == WS_SUCCESS) { +#ifdef USE_WINDOWS_API + tmp.actime = aTime; + tmp.modtime = mTime; + _sopen_s(&fd, fileName, _O_RDWR, _SH_DENYNO, 0); + _futime(fd, &tmp); + _close(fd); +#else tmp[0].tv_sec = (time_t)aTime; tmp[0].tv_usec = 0; tmp[1].tv_sec = (time_t)mTime; tmp[1].tv_usec = 0; ret = WUTIMES(fileName, tmp); +#endif } return ret; } - /* Default SCP receive callback, called by wolfSSH when application has called * wolfSSH_accept() and a new SCP request has been received for an incomming * file or directory. @@ -2079,7 +2094,7 @@ int wsScpRecvCallback(WOLFSSH* ssh, int state, const char* basePath, return ret; } -static int GetFileSize(WFILE* fp, word32* fileSz) +static int _GetFileSize(WFILE* fp, word32* fileSz) { if (fp == NULL || fileSz == NULL) return WS_BAD_ARGUMENT; @@ -2103,6 +2118,22 @@ static int GetFileStats(ScpSendCtx* ctx, const char* fileName, } /* get file stats for times and mode */ +#if defined(USE_WINDOWS_API) + BOOL error; + + error = !WS_GetFileAttributesExA(fileName, &ctx->s, NULL); + if (error) + return WS_BAD_FILE_E; + + *aTime = ((word64)ctx->s.ftLastAccessTime.dwHighDateTime << 32) | + (word64)ctx->s.ftLastAccessTime.dwLowDateTime; + *mTime = ((word64)ctx->s.ftLastWriteTime.dwHighDateTime << 32) | + (word64)ctx->s.ftLastWriteTime.dwLowDateTime; + + *fileMode = 0555 | + (ctx->s.dwFileAttributes | FILE_ATTRIBUTE_READONLY ? 0 : 0200); + *fileMode |= (ctx->s.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? 0x4000 : 0; +#else if (WSTAT(fileName, &ctx->s) < 0) { ret = WS_BAD_FILE_E; #ifdef WOLFSSL_NUCLEUS @@ -2112,7 +2143,8 @@ static int GetFileStats(ScpSendCtx* ctx, const char* fileName, ret = WS_SUCCESS; } #endif - } else { + } + else { #ifdef WOLFSSL_NUCLEUS if (ctx->s.fattribute & ARDONLY) { *fileMode = 0x124; /* octal 444 */ @@ -2132,6 +2164,7 @@ static int GetFileStats(ScpSendCtx* ctx, const char* fileName, *fileMode = ctx->s.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); #endif } +#endif return ret; } @@ -2155,6 +2188,24 @@ static ScpDir* ScpNewDir(const char* path, void* heap) } entry->next = NULL; +#ifdef USE_WINDOWS_API + { + char sPath[MAX_PATH]; + int isDir; + + /* add wildcard to get full directory */ + WSNPRINTF(sPath, MAX_PATH, "%s/*", path); + + entry->dir = (HANDLE)WS_FindFirstFileA(sPath, + sPath, sizeof(sPath), &isDir, heap); + if (entry->dir == INVALID_HANDLE_VALUE) { + WFREE(entry, heap, DYNTYPE_SCPDIR); + WLOG(WS_LOG_ERROR, scpError, "opendir failed on directory", + WS_INVALID_PATH_E); + return NULL; + } + } +#else if (WOPENDIR(NULL, heap, &entry->dir, path) != 0 #ifndef WOLFSSL_NUCLEUS || entry->dir == NULL @@ -2165,7 +2216,7 @@ static ScpDir* ScpNewDir(const char* path, void* heap) WS_INVALID_PATH_E); return NULL; } - +#endif return entry; } @@ -2209,7 +2260,11 @@ int ScpPopDir(ScpSendCtx* ctx, void* heap) } if (entry != NULL) { + #ifdef USE_WINDOWS_API + FindClose(entry->dir); + #else WCLOSEDIR(&entry->dir); + #endif WFREE(entry, heap, DYNTYPE_SCPDIR); } @@ -2268,6 +2323,31 @@ static int FindNextDirEntry(ScpSendCtx* ctx) } } ctx->nextError = 1; +#elif defined(USE_WINDOWS_API) + do { + char realFileName[MAX_PATH]; + int sz; + + if (WS_FindNextFileA(ctx->currentDir->dir, + realFileName, sizeof(realFileName)) == 0) { + return WS_FATAL_ERROR; + } + + sz = (int)WSTRLEN(realFileName); + if (ctx->entry != NULL) { + WFREE(ctx->entry, NULL, DYNTYPE_SCPDIR); + ctx->entry = NULL; + } + + ctx->entry = (char*)WMALLOC(sz + 1, NULL, DYNTYPE_SCPDIR); + if (ctx->entry == NULL) { + return WS_MEMORY_E; + } + WMEMCPY(ctx->entry, realFileName, sz); + ctx->entry[sz] = '\0'; + } while ((ctx->entry != NULL) && + (WSTRNCMP(ctx->entry, ".", 1) == 0 || + WSTRNCMP(ctx->entry, "..", 2) == 0)); #else do { ctx->entry = WREADDIR(&ctx->currentDir->dir); @@ -2293,6 +2373,8 @@ int ScpFileIsDir(ScpSendCtx* ctx) { #ifdef WOLFSSL_NUCLEUS return (ctx->s.fattribute & ADIRENT); +#elif defined(USE_WINDOWS_API) + return (ctx->s.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); #else return S_ISDIR(ctx->s.st_mode); #endif @@ -2302,6 +2384,8 @@ static int ScpFileIsFile(ScpSendCtx* ctx) { #ifdef WOLFSSL_NUCLEUS return (ctx->s.fattribute != ADIRENT); +#elif defined(USE_WINDOWS_API) + return ((ctx->s.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0); #else return S_ISREG(ctx->s.st_mode); #endif @@ -2332,8 +2416,15 @@ static int ScpProcessEntry(WOLFSSH* ssh, char* fileName, word64* mTime, if (ret == WS_SUCCESS) { dirNameLen = (int)WSTRLEN(sendCtx->dirName); - #ifdef WOLFSSL_NUCLEUS - dNameLen = (int)WSTRLEN(sendCtx->currentDir->dir.lfname); + #if defined(WOLFSSL_NUCLEUS) + dNameLen = (int)WSTRLEN(sendCtx->currentDir->dir.lfname); + #elif defined(USE_WINDOWS_API) + { + char path[MAX_PATH]; + + GetFullPathNameA(fileName, MAX_PATH, path, NULL); + dNameLen = (int)WSTRLEN(path); + } #else dNameLen = (int)WSTRLEN(sendCtx->entry->d_name); #endif @@ -2354,6 +2445,11 @@ static int ScpProcessEntry(WOLFSSH* ssh, char* fileName, word64* mTime, if (wolfSSH_CleanPath(ssh, filePath) < 0) { ret = WS_SCP_ABORT; } + #elif defined(USE_WINDOWS_API) + WSTRNCAT(filePath, sendCtx->entry, + DEFAULT_SCP_FILE_NAME_SZ); + WSTRNCPY(fileName, sendCtx->entry, + DEFAULT_SCP_FILE_NAME_SZ); #else WSTRNCAT(filePath, sendCtx->entry->d_name, DEFAULT_SCP_FILE_NAME_SZ); @@ -2387,7 +2483,7 @@ static int ScpProcessEntry(WOLFSSH* ssh, char* fileName, word64* mTime, } if (ret == WS_SUCCESS) { - ret = GetFileSize(sendCtx->fp, totalFileSz); + ret = _GetFileSize(sendCtx->fp, totalFileSz); if (ret == WS_SUCCESS) ret = (word32)WFREAD(buf, 1, bufSz, sendCtx->fp); @@ -2538,7 +2634,7 @@ int wsScpSendCallback(WOLFSSH* ssh, int state, const char* peerRequest, } if (ret == WS_SUCCESS) - ret = GetFileSize(sendCtx->fp, totalFileSz); + ret = _GetFileSize(sendCtx->fp, totalFileSz); if (ret == WS_SUCCESS) ret = GetFileStats(sendCtx, peerRequest, mTime, aTime, fileMode); diff --git a/src/wolfsftp.c b/src/wolfsftp.c index ddd9137ca..90b3f6cad 100644 --- a/src/wolfsftp.c +++ b/src/wolfsftp.c @@ -2500,16 +2500,15 @@ static void getDate(char* buf, int len, struct tm* t) * return WS_SUCCESS on success */ static int SFTP_CreateLongName(WS_SFTPNAME* name) { +#if defined(XGMTIME) && defined(XSNPRINTF) char sizeStr[32]; char perm[11]; int linkCount = 1; /* @TODO set to correct value */ -#if defined(XGMTIME) && defined(XSNPRINTF) char date[WS_DATE_SIZE + 1]; /* +1 for null terminator */ struct tm* localTime = NULL; -#endif - WS_SFTP_FILEATRB* atr; int i; - + WS_SFTP_FILEATRB* atr; +#endif int totalSz = 0; if (name == NULL) { diff --git a/src/wolfterm.c b/src/wolfterm.c index 1bcea8f19..659256838 100644 --- a/src/wolfterm.c +++ b/src/wolfterm.c @@ -582,6 +582,11 @@ static int wolfSSH_DoControlSeq(WOLFSSH* ssh, WOLFSSH_HANDLE handle, byte* buf, i += 1; /* for 'h' or 'l' */ break; + case 'X': + /* @TODO (ECH) Erase number of characters on current line */ + break; + + default: WLOG(WS_LOG_DEBUG, "Unknown control sequence char:%c", c); i = *idx; diff --git a/wolfssh/internal.h b/wolfssh/internal.h index e30cfc89f..f0d7b63f6 100644 --- a/wolfssh/internal.h +++ b/wolfssh/internal.h @@ -799,6 +799,12 @@ struct WOLFSSH { #ifdef WOLFSSH_FWD void* fwdCbCtx; #endif /* WOLFSSH_FWD */ +#ifdef WOLFSSH_TERM + WS_CallbackTerminalSize termResizeCb; + void* termCtx; + word32 curX; /* current terminal width */ + word32 curY; /* current terminal height */ +#endif }; @@ -922,6 +928,8 @@ WOLFSSH_LOCAL int SendChannelExit(WOLFSSH*, word32, int); WOLFSSH_LOCAL int SendChannelData(WOLFSSH*, word32, byte*, word32); WOLFSSH_LOCAL int SendChannelWindowAdjust(WOLFSSH*, word32, word32); WOLFSSH_LOCAL int SendChannelRequest(WOLFSSH*, byte*, word32); +WOLFSSH_LOCAL int SendChannelTerminalResize(WOLFSSH*, word32, word32, word32, + word32); WOLFSSH_LOCAL int SendChannelTerminalRequest(WOLFSSH* ssh); WOLFSSH_LOCAL int SendChannelAgentRequest(WOLFSSH* ssh); WOLFSSH_LOCAL int SendChannelSuccess(WOLFSSH*, word32, int); diff --git a/wolfssh/port.h b/wolfssh/port.h index dbb47702b..de7de36e4 100644 --- a/wolfssh/port.h +++ b/wolfssh/port.h @@ -48,10 +48,16 @@ extern "C" { #else #define WISSPACE isspace #endif +#ifdef USE_WINDOWS_API + #define WUID_T int + #define WGID_T int + #define WPASSWD struct passwd +#else #define WUID_T uid_t #define WGID_T gid_t #define WPASSWD struct passwd #endif +#endif /* setup memory handling */ #ifndef WMALLOC_USER @@ -366,6 +372,8 @@ extern "C" { #define WBADFILE NULL #ifdef WOLFSSL_VXWORKS #define WUTIMES(f,t) (WS_SUCCESS) + #elif defined(USE_WINDOWS_API) + #include #else #define WUTIMES(f,t) utimes((f),(t)) #endif @@ -451,7 +459,7 @@ extern "C" { #ifdef USE_WINDOWS_API #define WSTRNCPY(s1,s2,n) strncpy_s((s1),(n),(s2),(n)) #define WSTRNCASECMP(s1,s2,n) _strnicmp((s1),(s2),(n)) - #define WSNPRINTF(s,n,f,...) _snprintf_s((s),(n),(n),(f),##__VA_ARGS__) + #define WSNPRINTF(s,n,f,...) _snprintf_s((s),(n),_TRUNCATE,(f),##__VA_ARGS__) #define WVSNPRINTF(s,n,f,...) _vsnprintf_s((s),(n),(n),(f),##__VA_ARGS__) #define WSTRTOK(s1,s2,s3) strtok_s((s1),(s2),(s3)) #elif defined(MICROCHIP_MPLAB_HARMONY) || defined(MICROCHIP_PIC32) diff --git a/wolfssh/ssh.h b/wolfssh/ssh.h index 5dce49fc8..7fd7454f1 100644 --- a/wolfssh/ssh.h +++ b/wolfssh/ssh.h @@ -283,6 +283,12 @@ typedef enum { 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); +WOLFSSH_API int wolfSSH_ChangeTerminalSize(WOLFSSH* ssh, word32, word32, + word32, word32); +typedef int (*WS_CallbackTerminalSize)(WOLFSSH*, word32, word32, word32, + word32, void*); +void wolfSSH_SetTerminalResizeCb(WOLFSSH*, WS_CallbackTerminalSize); +void wolfSSH_SetTerminalResizeCtx(WOLFSSH*, void*); enum WS_HighwaterSide { diff --git a/wolfssh/wolfscp.h b/wolfssh/wolfscp.h index d944624db..de57895d9 100644 --- a/wolfssh/wolfscp.h +++ b/wolfssh/wolfscp.h @@ -76,13 +76,16 @@ enum WS_ScpFileStates { #include typedef struct ScpSendCtx { - #ifndef WOLFSSL_NUCLEUS - struct dirent* entry; /* file entry, from readdir() */ - struct stat s; /* stat info from file */ - #else + #ifdef WOLFSSL_NUCLEUS int fd; /* file descriptor, in the case of Nucleus fp points to fd */ DSTAT s; int nextError; + #elif defined(USE_WINDOWS_API) + char* entry; + WIN32_FILE_ATTRIBUTE_DATA s; + #else + struct dirent* entry; /* file entry, from readdir() */ + struct stat s; /* stat info from file */ #endif WFILE* fp; /* file pointer */ struct ScpDir* currentDir; /* dir being copied, stack */ From ecd47ddfd6d3ece2f61ab5721797708503cb2ac8 Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Mon, 24 Jul 2023 16:14:16 -0600 Subject: [PATCH 02/11] add OSX semaphore use, and fix warning --- apps/wolfsshd/wolfsshd.c | 3 +++ examples/client/client.c | 43 ++++++++++++++++++++++++++++++---------- src/internal.c | 4 ++-- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/apps/wolfsshd/wolfsshd.c b/apps/wolfsshd/wolfsshd.c index fba72295f..cd597d72e 100644 --- a/apps/wolfsshd/wolfsshd.c +++ b/apps/wolfsshd/wolfsshd.c @@ -2213,6 +2213,9 @@ int main(int argc, char** argv) } #else + +#include + /* helpful print out if compiling without SSHD feature enabled */ int main(int argc, char** argv) { diff --git a/examples/client/client.c b/examples/client/client.c index b1cc0bf33..699aaf878 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -190,13 +190,23 @@ typedef struct thread_args { #ifndef _MSC_VER + +#if (defined(__OSX__) || defined(__APPLE__)) +#include +dispatch_semaphore_t windowSem; +#else #include static sem_t windowSem; +#endif /* capture window change signales */ static void WindowChangeSignal(int sig) { +#if (defined(__OSX__) || defined(__APPLE__)) + dispatch_semaphore_signal(windowSem); +#else sem_post(&windowSem); +#endif (void)sig; } @@ -225,7 +235,11 @@ static THREAD_RET windowMonitor(void* in) args = (thread_args*)in; do { + #if (defined(__OSX__) || defined(__APPLE__)) + dispatch_semaphore_wait(windowSem, DISPATCH_TIME_FOREVER); + #else sem_wait(&windowSem); + #endif ret = sendCurrentWindowSize(args); (void)ret; } while (1); @@ -290,7 +304,7 @@ static THREAD_RET readPeer(void* in) int bufSz = sizeof(buf); thread_args* args = (thread_args*)in; int ret = 0; - int fd = wolfSSH_get_fd(args->ssh); + int fd = (int)wolfSSH_get_fd(args->ssh); word32 bytes; #ifdef USE_WINDOWS_API HANDLE stdoutHandle = GetStdHandle(STD_OUTPUT_HANDLE); @@ -800,19 +814,28 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) arg.ssh = ssh; wc_InitMutex(&arg.lock); + #if (defined(__OSX__) || defined(__APPLE__)) + windowSem = dispatch_semaphore_create(0); + #else sem_init(&windowSem, 0, 0); + #endif /* send current terminal size */ ret = sendCurrentWindowSize(&arg); - - signal(SIGWINCH, WindowChangeSignal); - pthread_create(&thread[0], NULL, windowMonitor, (void*)&arg); - pthread_create(&thread[1], NULL, readInput, (void*)&arg); - pthread_create(&thread[2], NULL, readPeer, (void*)&arg); - pthread_join(thread[2], NULL); - pthread_cancel(thread[0]); - pthread_cancel(thread[1]); - sem_destroy(&windowSem); + if (ret == WS_SUCCESS) { + signal(SIGWINCH, WindowChangeSignal); + pthread_create(&thread[0], NULL, windowMonitor, (void*)&arg); + pthread_create(&thread[1], NULL, readInput, (void*)&arg); + pthread_create(&thread[2], NULL, readPeer, (void*)&arg); + pthread_join(thread[2], NULL); + pthread_cancel(thread[0]); + pthread_cancel(thread[1]); + #if (defined(__OSX__) || defined(__APPLE__)) + dispatch_release(windowSem); + #else + sem_destroy(&windowSem); + #endif + } #elif defined(_MSC_VER) thread_args arg; HANDLE thread[2]; diff --git a/src/internal.c b/src/internal.c index b1a678e52..73a7e6f05 100644 --- a/src/internal.c +++ b/src/internal.c @@ -633,7 +633,7 @@ void CtxResourceFree(WOLFSSH_CTX* ctx) #ifdef WOLFSSH_TERM /* default terminal resize handling callbacks */ -#ifdef USE_WINDOWS_API +#if defined(USE_WINDOWS_API) && defined(WOLFSSH_SSHD) static int WS_WindowsTermResize(WOLFSSH* ssh, word32 col, word32 row, word32 colP, word32 rowP, void* usrCtx) { @@ -752,7 +752,7 @@ WOLFSSH* SshInit(WOLFSSH* ssh, WOLFSSH_CTX* ctx) #endif #ifdef WOLFSSH_TERM - #if defined(USE_WINDOWS_API) + #if defined(USE_WINDOWS_API) && defined(WOLFSSH_SSHD) ssh->termResizeCb = WS_WindowsTermResize; #endif #endif From a37b709e209a487d7667a3d981f5a94535b2e24b Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Wed, 26 Jul 2023 15:23:40 -0700 Subject: [PATCH 03/11] add better initial setting of terminal size with pty-req packet --- src/internal.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/internal.c b/src/internal.c index 73a7e6f05..8c145fdb5 100644 --- a/src/internal.c +++ b/src/internal.c @@ -13044,6 +13044,28 @@ int SendChannelTerminalResize(WOLFSSH* ssh, word32 columns, word32 rows, } +#ifdef __linux__ +#ifdef HAVE_PTY_H + #include +#endif +#endif + +static void GetTerminalSize(word32* width, word32* height) +{ +#ifdef __linux__ + struct winsize windowSize = {0,0,0,0}; + + ioctl(STDOUT_FILENO, TIOCGWINSZ, &windowSize); + *width = (word32)windowSize.ws_col; + *height = (word32)windowSize.ws_row; +#else + /* sane defaults for terminal size if not yet supported */ + *width = 80; + *height = 24; +#endif +} + + /* sends request for pseudo-terminal (rfc 4254) * returns WS_SUCCESS on success */ int SendChannelTerminalRequest(WOLFSSH* ssh) @@ -13056,7 +13078,7 @@ int SendChannelTerminalRequest(WOLFSSH* ssh) const char envVar[] = "xterm"; byte mode[4096]; word32 envSz, typeSz, modeSz; - word32 w = 80, h = 24; + word32 w, h; word32 pxW = 0, pxH = 0; WLOG(WS_LOG_DEBUG, "Entering SendChannelTerminalRequest()"); @@ -13064,6 +13086,7 @@ int SendChannelTerminalRequest(WOLFSSH* ssh) if (ssh == NULL) ret = WS_BAD_ARGUMENT; + GetTerminalSize(&w, &h); envSz = (word32)WSTRLEN(envVar); typeSz = (word32)WSTRLEN(cType); modeSz = CreateMode(ssh, mode); From 0bd4539ef6ce6fdb9b31ea6e04c6bf1b382629f7 Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Thu, 27 Jul 2023 10:45:52 -0600 Subject: [PATCH 04/11] adjust req-pty terminal size sent with Windows --- examples/client/client.c | 126 +++++++++++++++++++------------ examples/sftpclient/sftpclient.c | 8 +- src/internal.c | 9 ++- 3 files changed, 92 insertions(+), 51 deletions(-) diff --git a/examples/client/client.c b/examples/client/client.c index 699aaf878..4ed916e24 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -189,6 +189,39 @@ typedef struct thread_args { #endif +static int sendCurrentWindowSize(thread_args* args) +{ + int ret; + word32 col = 80, row = 24, xpix = 0, ypix = 0; + + wc_LockMutex(&args->lock); +#if defined(_MSC_VER) + { + CONSOLE_SCREEN_BUFFER_INFO cs; + + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cs) != 0) { + col = cs.srWindow.Right - cs.srWindow.Left + 1; + row = cs.srWindow.Bottom - cs.srWindow.Top + 1; + } + } +#else + { + struct winsize windowSize = { 0,0,0,0 }; + + ioctl(STDOUT_FILENO, TIOCGWINSZ, &windowSize); + col = windowSize.ws_col; + row = windowSize.ws_row; + xpix = windowSize.ws_xpixel; + ypix = windowSize.ws_ypixel; + } +#endif + ret = wolfSSH_ChangeTerminalSize(args->ssh, col, row, xpix, ypix); + wc_UnLockMutex(&args->lock); + + return ret; +} + + #ifndef _MSC_VER #if (defined(__OSX__) || defined(__APPLE__)) @@ -210,23 +243,6 @@ static void WindowChangeSignal(int sig) (void)sig; } - -static int sendCurrentWindowSize(thread_args* args) -{ - struct winsize windowSize = {0,0,0,0}; - int ret; - - wc_LockMutex(&args->lock); - ioctl(STDOUT_FILENO, TIOCGWINSZ, &windowSize); - ret = wolfSSH_ChangeTerminalSize(args->ssh, - windowSize.ws_col, windowSize.ws_row, - windowSize.ws_xpixel, windowSize.ws_ypixel); - wc_UnLockMutex(&args->lock); - - return ret; -} - - /* thread for handling window size adjustments */ static THREAD_RET windowMonitor(void* in) { @@ -246,8 +262,35 @@ static THREAD_RET windowMonitor(void* in) return THREAD_RET_SUCCESS; } +#else +/* no SIGWINCH on Windows, poll current terminal size */ +static word32 prevCol, prevRow; + +static int windowMonitor(thread_args* args) +{ + word32 row, col; + int ret = WS_SUCCESS; + CONSOLE_SCREEN_BUFFER_INFO cs; + + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cs) != 0) { + col = cs.srWindow.Right - cs.srWindow.Left + 1; + row = cs.srWindow.Bottom - cs.srWindow.Top + 1; + + if (prevCol != col || prevRow != row) { + prevCol = col; + prevRow = row; + + wc_LockMutex(&args->lock); + ret = wolfSSH_ChangeTerminalSize(args->ssh, col, row, 0, 0); + wc_UnLockMutex(&args->lock); + } + } + + return ret; +} #endif + static THREAD_RET readInput(void* in) { byte buf[256]; @@ -265,6 +308,7 @@ static THREAD_RET readInput(void* in) /* Using A version to avoid potential 2 byte chars */ ret = ReadConsoleA(stdinHandle, (void*)buf, bufSz - 1, (DWORD*)&sz, NULL); + (void)windowMonitor(args); #else ret = (int)read(STDIN_FILENO, buf, bufSz -1); sz = (word32)ret; @@ -325,6 +369,10 @@ static THREAD_RET readPeer(void* in) #endif while (ret >= 0) { + #ifdef USE_WINDOWS_API + (void)windowMonitor(args); + #endif + bytes = select(fd + 1, &readSet, NULL, &errSet, NULL); wc_LockMutex(&args->lock); while (bytes > 0 && (FD_ISSET(fd, &readSet) || FD_ISSET(fd, &errSet))) { @@ -820,42 +868,22 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) sem_init(&windowSem, 0, 0); #endif - /* send current terminal size */ - ret = sendCurrentWindowSize(&arg); - if (ret == WS_SUCCESS) { - signal(SIGWINCH, WindowChangeSignal); - pthread_create(&thread[0], NULL, windowMonitor, (void*)&arg); - pthread_create(&thread[1], NULL, readInput, (void*)&arg); - pthread_create(&thread[2], NULL, readPeer, (void*)&arg); - pthread_join(thread[2], NULL); - pthread_cancel(thread[0]); - pthread_cancel(thread[1]); - #if (defined(__OSX__) || defined(__APPLE__)) - dispatch_release(windowSem); - #else - sem_destroy(&windowSem); - #endif - } + signal(SIGWINCH, WindowChangeSignal); + pthread_create(&thread[0], NULL, windowMonitor, (void*)&arg); + pthread_create(&thread[1], NULL, readInput, (void*)&arg); + pthread_create(&thread[2], NULL, readPeer, (void*)&arg); + pthread_join(thread[2], NULL); + pthread_cancel(thread[0]); + pthread_cancel(thread[1]); + #if (defined(__OSX__) || defined(__APPLE__)) + dispatch_release(windowSem); + #else + sem_destroy(&windowSem); + #endif #elif defined(_MSC_VER) thread_args arg; HANDLE thread[2]; - /* send the console size to server */ - { - CONSOLE_SCREEN_BUFFER_INFO cs; - word32 col = 80, row = 24; - - if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cs) == 0) { - fprintf(stderr, "Failed to get the current console size\r\n"); - fprintf(stderr, "Using default col = 80 row = 24\r\n"); - } - else { - col = cs.srWindow.Right - cs.srWindow.Left + 1; - row = cs.srWindow.Bottom - cs.srWindow.Top + 1; - } - wolfSSH_ChangeTerminalSize(ssh, col, row, 0, 0); - } - arg.ssh = ssh; arg.rawMode = rawMode; wc_InitMutex(&arg.lock); diff --git a/examples/sftpclient/sftpclient.c b/examples/sftpclient/sftpclient.c index 44208f16c..3cd51bc53 100644 --- a/examples/sftpclient/sftpclient.c +++ b/examples/sftpclient/sftpclient.c @@ -24,6 +24,12 @@ #define WOLFSSH_TEST_CLIENT +#ifdef WOLFSSL_USER_SETTINGS +#include +#else +#include +#endif + #include #include #include @@ -1245,7 +1251,7 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args) else wolfSSH_SetUserAuth(ctx, ((func_args*)args)->user_auth); -#ifndef WS_NO_SIGNAL +#if !defined(WS_NO_SIGNAL) && !defined(USE_WINDOWS_API) /* handle interrupt with get and put */ signal(SIGINT, sig_handler); #endif diff --git a/src/internal.c b/src/internal.c index 8c145fdb5..d7f422fa4 100644 --- a/src/internal.c +++ b/src/internal.c @@ -13053,11 +13053,18 @@ int SendChannelTerminalResize(WOLFSSH* ssh, word32 columns, word32 rows, static void GetTerminalSize(word32* width, word32* height) { #ifdef __linux__ - struct winsize windowSize = {0,0,0,0}; + struct winsize windowSize = { 0,0,0,0 }; ioctl(STDOUT_FILENO, TIOCGWINSZ, &windowSize); *width = (word32)windowSize.ws_col; *height = (word32)windowSize.ws_row; +#elif defined(_MSC_VER) + CONSOLE_SCREEN_BUFFER_INFO cs; + + if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cs) != 0) { + *width = cs.srWindow.Right - cs.srWindow.Left + 1; + *height = cs.srWindow.Bottom - cs.srWindow.Top + 1; + } #else /* sane defaults for terminal size if not yet supported */ *width = 80; From 3e270cd0dfcf1c3308b8d40a85325ed6dc57aa85 Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Fri, 28 Jul 2023 11:26:35 -0600 Subject: [PATCH 05/11] still need to send initial terminal size with exec command --- examples/client/client.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/examples/client/client.c b/examples/client/client.c index 4ed916e24..58f7fc809 100644 --- a/examples/client/client.c +++ b/examples/client/client.c @@ -868,6 +868,17 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) sem_init(&windowSem, 0, 0); #endif + if (cmd) { + int err; + + /* exec command does not contain initial terminal size, unlike pty-req. + * Send an inital terminal size for recieving the results of the command */ + err = sendCurrentWindowSize(&arg); + if (err != WS_SUCCESS) { + fprintf(stderr, "Issue sending exec initial terminal size\n\r"); + } + } + signal(SIGWINCH, WindowChangeSignal); pthread_create(&thread[0], NULL, windowMonitor, (void*)&arg); pthread_create(&thread[1], NULL, readInput, (void*)&arg); @@ -887,6 +898,18 @@ THREAD_RETURN WOLFSSH_THREAD client_test(void* args) arg.ssh = ssh; arg.rawMode = rawMode; wc_InitMutex(&arg.lock); + + if (cmd) { + int err; + + /* exec command does not contain initial terminal size, unlike pty-req. + * Send an inital terminal size for recieving the results of the command */ + err = sendCurrentWindowSize(&arg); + if (err != WS_SUCCESS) { + fprintf(stderr, "Issue sending exec initial terminal size\n\r"); + } + } + thread[0] = CreateThread(NULL, 0, readInput, (void*)&arg, 0, 0); thread[1] = CreateThread(NULL, 0, readPeer, (void*)&arg, 0, 0); WaitForSingleObject(thread[1], INFINITE); From 1b1f2d709089968404046d8b9d4203740ed14fe6 Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Fri, 28 Jul 2023 17:16:46 -0600 Subject: [PATCH 06/11] with windows check for window-change packet before creating psudo terminal --- apps/wolfsshd/wolfsshd.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/apps/wolfsshd/wolfsshd.c b/apps/wolfsshd/wolfsshd.c index cd597d72e..8ff48a3e4 100644 --- a/apps/wolfsshd/wolfsshd.c +++ b/apps/wolfsshd/wolfsshd.c @@ -843,6 +843,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, ret = WS_MEMORY_E; } else { + byte pol[2]; WCHAR* tmp = (WCHAR*)WMALLOC(sizeof(wchar_t) * cmdSz, NULL, DYNTYPE_SSHD); if (tmp == NULL) { ret = WS_MEMORY_E; @@ -862,6 +863,19 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, if (tmp != NULL) { WFREE(tmp, NULL, DYNTYPE_SSHD); } + + /* read in case a window-change packet might be queued */ + { + int rc; + word32 lastChannel = 0; + + do { + rc = wolfSSH_worker(ssh, &lastChannel); + if (rc < 0) { + rc = wolfSSH_get_error(ssh); + } + } while (rc == WS_WANT_WRITE); + } } } else { /* when set command is not present start 'cmd.exe' */ From 6b22fedec9eaa06792fe7d2479b2ca5baa62583b Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Wed, 2 Aug 2023 07:13:30 -0700 Subject: [PATCH 07/11] check SFTP pending data before processing more --- apps/wolfsshd/wolfsshd.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/apps/wolfsshd/wolfsshd.c b/apps/wolfsshd/wolfsshd.c index 8ff48a3e4..ee2d2115a 100644 --- a/apps/wolfsshd/wolfsshd.c +++ b/apps/wolfsshd/wolfsshd.c @@ -685,6 +685,22 @@ static int SFTP_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, break; } + if (wolfSSH_SFTP_PendingSend(ssh)) { + /* Yes, process the SFTP data. */ + ret = wolfSSH_SFTP_read(ssh); + error = wolfSSH_get_error(ssh); + timeout = (ret == WS_REKEYING) ? + TEST_SFTP_TIMEOUT : TEST_SFTP_TIMEOUT_NONE; + if (error == WS_WANT_READ || error == WS_WANT_WRITE || + error == WS_CHAN_RXD || error == WS_REKEYING || + error == WS_WINDOW_FULL) + ret = error; + if (error == WS_EOF) { + break; + } + continue; + } + if (ret == WS_WANT_READ || ret == WS_WANT_WRITE || select_ret == WS_SELECT_RECV_READY) { ret = wolfSSH_worker(ssh, NULL); @@ -711,22 +727,6 @@ static int SFTP_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, } } - if (wolfSSH_SFTP_PendingSend(ssh)) { - /* Yes, process the SFTP data. */ - ret = wolfSSH_SFTP_read(ssh); - error = wolfSSH_get_error(ssh); - timeout = (ret == WS_REKEYING) ? - TEST_SFTP_TIMEOUT : TEST_SFTP_TIMEOUT_NONE; - if (error == WS_WANT_READ || error == WS_WANT_WRITE || - error == WS_CHAN_RXD || error == WS_REKEYING || - error == WS_WINDOW_FULL) - ret = error; - if (error == WS_EOF) { - break; - } - continue; - } - ret = wolfSSH_stream_peek(ssh, peek_buf, sizeof(peek_buf)); if (ret > 0) { /* Yes, process the SFTP data. */ From da32306628cb1a309cf2792672b19b8df8249cc2 Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Thu, 3 Aug 2023 09:43:53 -0600 Subject: [PATCH 08/11] fix for rekey with wolfsshd, improve wolfsshd vs project --- apps/wolfsshd/wolfsshd.c | 2 -- ide/winvs/wolfsshd/wolfsshd.vcxproj | 19 ++++++++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/apps/wolfsshd/wolfsshd.c b/apps/wolfsshd/wolfsshd.c index ee2d2115a..310be1e14 100644 --- a/apps/wolfsshd/wolfsshd.c +++ b/apps/wolfsshd/wolfsshd.c @@ -698,7 +698,6 @@ static int SFTP_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, if (error == WS_EOF) { break; } - continue; } if (ret == WS_WANT_READ || ret == WS_WANT_WRITE || @@ -843,7 +842,6 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, ret = WS_MEMORY_E; } else { - byte pol[2]; WCHAR* tmp = (WCHAR*)WMALLOC(sizeof(wchar_t) * cmdSz, NULL, DYNTYPE_SSHD); if (tmp == NULL) { ret = WS_MEMORY_E; diff --git a/ide/winvs/wolfsshd/wolfsshd.vcxproj b/ide/winvs/wolfsshd/wolfsshd.vcxproj index b4d4b216a..29b6b4049 100644 --- a/ide/winvs/wolfsshd/wolfsshd.vcxproj +++ b/ide/winvs/wolfsshd/wolfsshd.vcxproj @@ -23,6 +23,11 @@ + + + {7c2ccf0d-a155-4914-bd1c-9a47c0530e65} + + 16.0 Win32Proj @@ -63,15 +68,19 @@ + + + + @@ -118,13 +127,13 @@ true _CRT_SECURE_NO_DEPRECATE;WOLFSSL_USER_SETTINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true - ..;..\..\..;..\..\..\..\wolfssl;..\..\..\apps\wolfsshd\;%(AdditionalIncludeDirectories) + ..;..\..\..;$(wolfCryptDir);..\..\..\apps\wolfsshd\;%(AdditionalIncludeDirectories) Console true ..\..\..\..\wolfssl\Debug\x64;..\Debug\x64 - wolfssl.lib;wolfssh.lib;ws2_32.lib;secur32.lib;userenv.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) + wolfssl.lib;ws2_32.lib;secur32.lib;userenv.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) @@ -135,18 +144,18 @@ true WOLFSSL_USER_SETTINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true - ..;..\..\..;..\..\..\..\wolfssl;..\..\..\apps\wolfsshd\;%(AdditionalIncludeDirectories) + ..;..\..\..;$(wolfCryptDir);..\..\..\apps\wolfsshd\;%(AdditionalIncludeDirectories) Console true true true - wolfssl.lib;wolfssh.lib;ws2_32.lib;secur32.lib;userenv.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) + wolfssl.lib;ws2_32.lib;secur32.lib;userenv.lib;$(CoreLibraryDependencies);%(AdditionalDependencies) ..\..\..\..\wolfssl\Release\x64;..\Release\x64 - + \ No newline at end of file From 9993a26addc2cf6a01122bc8bd36c732b18c72d5 Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Thu, 17 Aug 2023 08:22:32 -0600 Subject: [PATCH 09/11] parse command line arguments for Windows service --- apps/wolfsshd/wolfsshd.c | 41 +++++++++++++++++++++++++++++++--------- ide/winvs/README.md | 4 ++-- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/apps/wolfsshd/wolfsshd.c b/apps/wolfsshd/wolfsshd.c index 310be1e14..4dd888c02 100644 --- a/apps/wolfsshd/wolfsshd.c +++ b/apps/wolfsshd/wolfsshd.c @@ -1752,6 +1752,7 @@ char* myoptarg = NULL; #ifdef _WIN32 #include +#include SERVICE_STATUS serviceStatus = { 0 }; SERVICE_STATUS_HANDLE serviceStatusHandle = NULL; @@ -1828,10 +1829,23 @@ static int StartSSHD(int argc, char** argv) #ifdef _WIN32 char** argv = NULL; DWORD i; + LPWSTR* cmdArgs = NULL; + LPWSTR cmdLn; + int cmdArgC = 0; + + /* get what the command line was and parse arguments from it */ + cmdLn = GetCommandLineW(); + cmdArgs = CommandLineToArgvW(cmdLn, &cmdArgC); + if (cmdArgs == NULL) { + ret = WS_FATAL_ERROR; + } + argc = cmdArgC; - for (i = 0; i < argc; i++) { - if (WSTRCMP((char*)(wargv[i]), "-D") == 0) { - isDaemon = 0; + if (ret == WS_SUCCESS) { + for (i = 0; i < argc; i++) { + if (WSTRCMP((char*)(cmdArgs[i]), "-D") == 0) { + isDaemon = 0; + } } } @@ -1839,12 +1853,17 @@ static int StartSSHD(int argc, char** argv) /* Set the logging to go to OutputDebugString */ wolfSSH_SetLoggingCb(ServiceDebugCb); - /* we want the arguments to be normal char strings not wchar_t */ - argv = WMALLOC(argc * sizeof(char*), NULL, DYNTYPE_SSHD); - { - unsigned int z; - for (z = 0; z < argc; z++) { - argv[z] = _convertHelper(wargv[z], NULL); + if (ret == WS_SUCCESS) { + /* we want the arguments to be normal char strings not wchar_t */ + argv = (char**)WMALLOC(argc * sizeof(char*), NULL, DYNTYPE_SSHD); + if (argv == NULL) { + ret = WS_MEMORY_E; + } + else { + unsigned int z; + for (z = 0; z < argc; z++) { + argv[z] = _convertHelper(cmdArgs[z], NULL); + } } } } @@ -2071,6 +2090,10 @@ static int StartSSHD(int argc, char** argv) } return; } + + if (cmdArgs != NULL) { + LocalFree(cmdArgs); + } } #endif diff --git a/ide/winvs/README.md b/ide/winvs/README.md index 9b516e766..14ce9df0f 100644 --- a/ide/winvs/README.md +++ b/ide/winvs/README.md @@ -61,10 +61,10 @@ SSHD Service ----------- Creating a new servie -`sc.exe create wolfSSHd binpath=D:\work\wolfssh\ide\winvs\Debug\x64\wolfsshd.exe` +`sc.exe create wolfSSHd binpath="D:\work\wolfssh\ide\winvs\Debug\x64\wolfsshd.exe -f -h -p "` Starting wolfSSHd service run the following command in an adminstrator power shell session: -`sc.exe start wolfSSHd -f -h -p ` +`sc.exe start wolfSSHd` To stop the service run the following in an adminstrator power shell session: `sc.exe stop wolfSSHd` From 4fd4d0458f323afda9347616934b76fe954866cc Mon Sep 17 00:00:00 2001 From: Jacob Barthelmeh Date: Mon, 28 Aug 2023 17:01:00 -0600 Subject: [PATCH 10/11] scan build warning of unread timeout --- apps/wolfsshd/wolfsshd.c | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/wolfsshd/wolfsshd.c b/apps/wolfsshd/wolfsshd.c index 4dd888c02..824631e3f 100644 --- a/apps/wolfsshd/wolfsshd.c +++ b/apps/wolfsshd/wolfsshd.c @@ -760,7 +760,6 @@ static int SFTP_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, } } - timeout = TEST_SFTP_TIMEOUT; } while (ret != WS_FATAL_ERROR); } From 034ed7fe9ffd763f49dbe64cc20a01b5b5d7d2af Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Wed, 30 Aug 2023 13:32:17 -0700 Subject: [PATCH 11/11] fix ups for format, spelling, includes, and string compare --- .gitignore | 1 + apps/wolfsshd/auth.c | 33 ++++---- apps/wolfsshd/configuration.c | 2 + apps/wolfsshd/wolfsshd.c | 75 ++++++++++++------- examples/sftpclient/sftpclient.c | 8 +- ide/winvs/README.md | 4 +- ide/winvs/api-test/api-test.vcxproj.user | 19 ----- ide/winvs/client/client.vcxproj.user | 19 ----- ide/winvs/echoserver/echoserver.vcxproj.user | 19 ----- ide/winvs/include.am | 7 -- ide/winvs/testsuite/testsuite.vcxproj.user | 19 ----- ide/winvs/unit-test/unit-test.vcxproj.user | 19 ----- .../wolfsftp-client.vcxproj.user | 19 ----- ide/winvs/wolfsshd/wolfsshd.vcxproj.user | 13 ---- src/wolfscp.c | 13 +++- 15 files changed, 85 insertions(+), 185 deletions(-) delete mode 100644 ide/winvs/api-test/api-test.vcxproj.user delete mode 100644 ide/winvs/client/client.vcxproj.user delete mode 100644 ide/winvs/echoserver/echoserver.vcxproj.user delete mode 100644 ide/winvs/testsuite/testsuite.vcxproj.user delete mode 100644 ide/winvs/unit-test/unit-test.vcxproj.user delete mode 100644 ide/winvs/wolfsftp-client/wolfsftp-client.vcxproj.user delete mode 100644 ide/winvs/wolfsshd/wolfsshd.vcxproj.user diff --git a/.gitignore b/.gitignore index 6f0f4214a..c73676e9b 100644 --- a/.gitignore +++ b/.gitignore @@ -74,6 +74,7 @@ client.plist *.sdf *.v11.suo *.vcxproj.filters +*.vcxproj.user *.opensdf *.pdb .vs diff --git a/apps/wolfsshd/auth.c b/apps/wolfsshd/auth.c index f260ff3a8..4b4040dab 100644 --- a/apps/wolfsshd/auth.c +++ b/apps/wolfsshd/auth.c @@ -24,6 +24,8 @@ #ifdef WOLFSSL_USER_SETTINGS #include +#else + #include #endif #ifdef WOLFSSH_SSHD @@ -522,8 +524,8 @@ static int SearchForPubKey(const char* path, const WS_UserAuthData_PublicKey* pu } } while (ret == WSSHD_AUTH_SUCCESS && - (current = XFGETS(lineBuf, MAX_LINE_SZ, f)) != NULL) { - currentSz = (word32)XSTRLEN(current); + (current = WFGETS(lineBuf, MAX_LINE_SZ, f)) != NULL) { + currentSz = (word32)WSTRLEN(current); /* remove leading spaces */ while (currentSz > 0 && current[0] == ' ') { @@ -551,7 +553,7 @@ static int SearchForPubKey(const char* path, const WS_UserAuthData_PublicKey* pu } } - if (f != XBADFILE) { + if (f != WBADFILE) { WFCLOSE(f); } @@ -977,7 +979,7 @@ static int CheckPublicKeyWIN(const char* usr, wolfSSH_Log(WS_LOG_INFO, "[SSHD] Windows check public key"); ret = SetupUserTokenWin(usr, pubKeyCtx,usrCaKeysFile, authCtx); - + /* after successful logon check the public key sent */ if (ret == WSSHD_AUTH_SUCCESS) { WCHAR h[MAX_PATH]; @@ -985,7 +987,7 @@ static int CheckPublicKeyWIN(const char* usr, if (_GetHomeDirectory(authCtx, usr, h, MAX_PATH) == WS_SUCCESS) { CHAR r[MAX_PATH]; size_t rSz; - + if (wcstombs_s(&rSz, r, MAX_PATH, h, MAX_PATH - 1) != 0) { ret = WSSHD_AUTH_FAILURE; } @@ -1002,8 +1004,8 @@ static int CheckPublicKeyWIN(const char* usr, } } else { - wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Windows failed to get home directory for user %s", - usr); + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Windows failed to get home directory for user %s", usr); ret = WSSHD_AUTH_FAILURE; } } @@ -1088,7 +1090,7 @@ static int RequestAuthentication(WS_UserAuthData* authData, } else { rc = authCtx->checkPasswordCb(usr, authData->sf.password.password, - authData->sf.password.passwordSz, authCtx); + authData->sf.password.passwordSz, authCtx); if (rc == WSSHD_AUTH_SUCCESS) { wolfSSH_Log(WS_LOG_INFO, "[SSHD] Password ok."); } @@ -1195,7 +1197,8 @@ static int RequestAuthentication(WS_UserAuthData* authData, ret = WOLFSSH_USERAUTH_SUCCESS; } else { - wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error getting users token."); + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Error getting users token."); ret = WOLFSSH_USERAUTH_FAILURE; } #else @@ -1205,17 +1208,20 @@ static int RequestAuthentication(WS_UserAuthData* authData, else { /* if not a certificate then parse through authorized key file */ rc = authCtx->checkPublicKeyCb(usr, &authData->sf.publicKey, - wolfSSHD_ConfigGetUserCAKeysFile(authCtx->conf), authCtx); + wolfSSHD_ConfigGetUserCAKeysFile(authCtx->conf), + authCtx); if (rc == WSSHD_AUTH_SUCCESS) { wolfSSH_Log(WS_LOG_INFO, "[SSHD] Public key ok."); ret = WOLFSSH_USERAUTH_SUCCESS; } else if (rc == WSSHD_AUTH_FAILURE) { - wolfSSH_Log(WS_LOG_INFO, "[SSHD] Public key not authorized."); + wolfSSH_Log(WS_LOG_INFO, + "[SSHD] Public key not authorized."); ret = WOLFSSH_USERAUTH_INVALID_PUBLICKEY; } else { - wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error checking public key."); + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Error checking public key."); ret = WOLFSSH_USERAUTH_FAILURE; } } @@ -1403,7 +1409,8 @@ WOLFSSHD_AUTH* wolfSSHD_AuthCreateUser(void* heap, const WOLFSSHD_CONFIG* conf) /* set the default user checking based on build */ ret = SetDefaultUserCheck(auth); if (ret != WS_SUCCESS) { - wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error setting default user check."); + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Error setting default user check."); } /* set the default password checking based on build */ diff --git a/apps/wolfsshd/configuration.c b/apps/wolfsshd/configuration.c index 8f0ffd715..498e93ff8 100644 --- a/apps/wolfsshd/configuration.c +++ b/apps/wolfsshd/configuration.c @@ -24,6 +24,8 @@ #ifdef WOLFSSL_USER_SETTINGS #include +#else + #include #endif #ifdef WOLFSSH_SSHD diff --git a/apps/wolfsshd/wolfsshd.c b/apps/wolfsshd/wolfsshd.c index 824631e3f..5b0f4c314 100644 --- a/apps/wolfsshd/wolfsshd.c +++ b/apps/wolfsshd/wolfsshd.c @@ -24,6 +24,8 @@ #ifdef WOLFSSL_USER_SETTINGS #include +#else + #include #endif #ifdef WOLFSSH_SSHD @@ -152,12 +154,13 @@ static void SyslogCb(enum wolfSSH_LogLevel level, const char *const msgStr) static void ServiceDebugCb(enum wolfSSH_LogLevel level, const char* const msgStr) { WCHAR* wc; - size_t szWord = WSTRLEN(msgStr) + 3; /* + 3 for null terminator and new line */ + size_t szWord = WSTRLEN(msgStr) + 3; /* + 3 for null terminator and new + * line */ size_t sz = szWord *sizeof(wchar_t); wc = (WCHAR*)WMALLOC(sz, NULL, DYNAMIC_TYPE_LOG); if (wc) { size_t con; - + if (mbstowcs_s(&con, wc, szWord, msgStr, szWord-1) == 0) { wc[con - 1] = L'\r'; wc[con] = L'\n'; @@ -499,7 +502,8 @@ static int SCP_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, #ifndef _WIN32 /* temporarily elevate permissions to get users information */ if (wolfSSHD_AuthRaisePermissions(conn->auth) != WS_SUCCESS) { - wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Failure to raise permissions for auth"); + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Failure to raise permissions for auth"); return WS_FATAL_ERROR; } @@ -592,7 +596,8 @@ static int SFTP_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, #ifndef _WIN32 /* temporarily elevate permissions to get users information */ if (wolfSSHD_AuthRaisePermissions(conn->auth) != WS_SUCCESS) { - wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Failure to raise permissions for auth"); + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Failure to raise permissions for auth"); return WS_FATAL_ERROR; } @@ -661,7 +666,8 @@ static int SFTP_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, if (ret == WS_SUCCESS) { r[rSz] = '\0'; - wolfSSH_Log(WS_LOG_INFO, "[SSHD] Using directory %s for SFTP connection", r); + wolfSSH_Log(WS_LOG_INFO, + "[SSHD] Using directory %s for SFTP connection", r); if (wolfSSH_SFTP_SetDefaultPath(ssh, r) != WS_SUCCESS) { wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error setting SFTP default home path"); @@ -816,7 +822,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, /* @TODO check for conpty support LoadLibrary()and GetProcAddress(). */ - if (forcedCmd != NULL && XSTRCMP(forcedCmd, "internal-sftp") == 0) { + if (forcedCmd != NULL && WSTRCMP(forcedCmd, "internal-sftp") == 0) { wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Only SFTP connections allowed for user " "%s", wolfSSH_GetUsername(ssh)); @@ -841,11 +847,12 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, ret = WS_MEMORY_E; } else { - WCHAR* tmp = (WCHAR*)WMALLOC(sizeof(wchar_t) * cmdSz, NULL, DYNTYPE_SSHD); + WCHAR* tmp = (WCHAR*)WMALLOC(sizeof(wchar_t) * cmdSz, NULL, + DYNTYPE_SSHD); if (tmp == NULL) { ret = WS_MEMORY_E; } - + if (ret == WS_SUCCESS) { size_t wr = 0; if (mbstowcs_s(&wr, tmp, cmdSz, forcedCmd, cmdSz - 1) != 0) { @@ -931,7 +938,8 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, if (ret == WS_SUCCESS) { /* Using HeapAlloc for better support when possibly passing memory between Windows Modules */ - ext.lpAttributeList = (PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, sz); + ext.lpAttributeList = + (PPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(GetProcessHeap(), 0, sz); if (ext.lpAttributeList == NULL) { wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue getting memory for attribute list"); @@ -940,7 +948,8 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, } if (ret == WS_SUCCESS) { - if (InitializeProcThreadAttributeList(ext.lpAttributeList, 1, 0, &sz) != TRUE) { + if (InitializeProcThreadAttributeList(ext.lpAttributeList, 1, 0, + &sz) != TRUE) { wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue initializing proc thread attribute"); ret = WS_FATAL_ERROR; @@ -948,8 +957,9 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, } if (ret == WS_SUCCESS) { - if (UpdateProcThreadAttribute(ext.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, - pCon, sizeof(HPCON), NULL, NULL) != TRUE) { + if (UpdateProcThreadAttribute(ext.lpAttributeList, 0, + PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE, + pCon, sizeof(HPCON), NULL, NULL) != TRUE) { wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue updating proc thread attribute"); ret = WS_FATAL_ERROR; @@ -969,8 +979,8 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, } #else /* Needs enabled when running as non-service, compiled out for now to - * make sure it can not accediently be used since the permissions of the - * created process match the current process. */ + * make sure it can not accidentally be used since the permissions of + * the created process match the current process. */ if (CreateProcessW(NULL, cmd, NULL, NULL, FALSE, EXTENDED_STARTUPINFO_PRESENT, NULL, h, &ext.StartupInfo, &processInfo) != TRUE) { @@ -1003,8 +1013,8 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, FD_ZERO(&readFds); FD_SET(sshFd, &readFds); - wolfSSH_Log(WS_LOG_INFO, - "[SSHD] Successfully created process for console, waiting for it to start"); + wolfSSH_Log(WS_LOG_INFO, "[SSHD] Successfully created process for " + "console, waiting for it to start"); WaitForInputIdle(processInfo.hProcess, 1000); @@ -1018,14 +1028,19 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, if (readPending == 0) { /* check if process is still running before waiting to read */ - if (GetExitCodeProcess(processInfo.hProcess, &processState) == TRUE) { + if (GetExitCodeProcess(processInfo.hProcess, &processState) + == TRUE) { if (processState != STILL_ACTIVE) { wolfSSH_Log(WS_LOG_INFO, - "[SSHD] Process has exited, exit state = %d, close down SSH connection", processState); - Sleep(100); /* give the stdout/stderr of process a little time to write to pipe */ - if (PeekNamedPipe(ptyOut, NULL, 0, NULL, &ava, NULL) == TRUE) { + "[SSHD] Process has exited, exit state = %d, " + "close down SSH connection", processState); + Sleep(100); /* give the stdout/stderr of process a + * little time to write to pipe */ + if (PeekNamedPipe(ptyOut, NULL, 0, NULL, &ava, NULL) + == TRUE) { if (ava > 0) { - /* if data still pending then continue sneding it over SSH */ + /* if data still pending then continue + * sending it over SSH */ readPending = 1; continue; } @@ -1041,7 +1056,8 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, break; } /* when select times out and no socket is set as ready - Windows overwrites readFds with 0. Reset the fd here for next select call */ + Windows overwrites readFds with 0. Reset the fd here + for next select call */ if (rc == 0) { FD_SET(sshFd, &readFds); } @@ -1065,15 +1081,17 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, rc = wolfSSH_get_error(ssh); if (rc == WS_CHAN_RXD) { if (lastChannel == shellChannelId) { - cnt_r = wolfSSH_ChannelIdRead(ssh, shellChannelId, - shellBuffer, + cnt_r = wolfSSH_ChannelIdRead(ssh, + shellChannelId, shellBuffer, sizeof shellBuffer); if (cnt_r <= 0) break; pending = 0; - if (WriteFile(ptyIn, shellBuffer, cnt_r, &cnt_r, NULL) != TRUE) { + if (WriteFile(ptyIn, shellBuffer, cnt_r, &cnt_r, + NULL) != TRUE) { wolfSSH_Log(WS_LOG_INFO, - "[SSHD] Error writing to pipe for console"); + "[SSHD] Error writing to pipe for " + "console"); break; } } @@ -1090,7 +1108,8 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, if (readPending) { WMEMSET(shellBuffer, 0, EXAMPLE_BUFFER_SZ); - if (ReadFile(ptyOut, shellBuffer, EXAMPLE_BUFFER_SZ, &cnt_r, NULL) != TRUE) { + if (ReadFile(ptyOut, shellBuffer, EXAMPLE_BUFFER_SZ, &cnt_r, + NULL) != TRUE) { wolfSSH_Log(WS_LOG_INFO, "[SSHD] Error reading from pipe for console"); break; @@ -1459,7 +1478,7 @@ static void* HandleConnection(void* arg) graceTime = wolfSSHD_AuthGetGraceTime(conn->auth); if (graceTime > 0) { #ifdef WIN32 - //@TODO SetTimer(NULL, NULL, graceTime, alarmCatch); + /* @TODO SetTimer(NULL, NULL, graceTime, alarmCatch); */ #else signal(SIGALRM, alarmCatch); alarm((unsigned int)graceTime); diff --git a/examples/sftpclient/sftpclient.c b/examples/sftpclient/sftpclient.c index 3cd51bc53..52b6b89f8 100644 --- a/examples/sftpclient/sftpclient.c +++ b/examples/sftpclient/sftpclient.c @@ -1339,11 +1339,11 @@ THREAD_RETURN WOLFSSH_THREAD sftpclient_test(void* args) WFREE(workingDir, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (ret == WS_SUCCESS) { if (wolfSSH_shutdown(ssh) != WS_SUCCESS) { - int rc; - rc = wolfSSH_get_error(ssh); + int rc; + rc = wolfSSH_get_error(ssh); - if (rc != WS_SOCKET_ERROR_E && rc != WS_EOF) - printf("error with wolfSSH_shutdown()\n"); + if (rc != WS_SOCKET_ERROR_E && rc != WS_EOF) + printf("error with wolfSSH_shutdown()\n"); } } WCLOSESOCKET(sockFd); diff --git a/ide/winvs/README.md b/ide/winvs/README.md index 14ce9df0f..9e6054b12 100644 --- a/ide/winvs/README.md +++ b/ide/winvs/README.md @@ -60,7 +60,7 @@ DLL in that directory. SSHD Service ----------- -Creating a new servie +Creating a new service `sc.exe create wolfSSHd binpath="D:\work\wolfssh\ide\winvs\Debug\x64\wolfsshd.exe -f -h -p "` Starting wolfSSHd service run the following command in an adminstrator power shell session: @@ -70,4 +70,4 @@ To stop the service run the following in an adminstrator power shell session: `sc.exe stop wolfSSHd` To delete the service run -`sc.exe delete wolfSSHd` \ No newline at end of file +`sc.exe delete wolfSSHd` diff --git a/ide/winvs/api-test/api-test.vcxproj.user b/ide/winvs/api-test/api-test.vcxproj.user deleted file mode 100644 index 23a5dce7e..000000000 --- a/ide/winvs/api-test/api-test.vcxproj.user +++ /dev/null @@ -1,19 +0,0 @@ - - - - WindowsLocalDebugger - PATH=$(wolfCryptDllDebug32);%PATH% - - - WindowsLocalDebugger - PATH=$(wolfCryptDllDebug64);%PATH% - - - WindowsLocalDebugger - PATH=$(wolfCryptDllRelease32);%PATH% - - - WindowsLocalDebugger - PATH=$(wolfCryptDllRelease64);%PATH% - - diff --git a/ide/winvs/client/client.vcxproj.user b/ide/winvs/client/client.vcxproj.user deleted file mode 100644 index 23a5dce7e..000000000 --- a/ide/winvs/client/client.vcxproj.user +++ /dev/null @@ -1,19 +0,0 @@ - - - - WindowsLocalDebugger - PATH=$(wolfCryptDllDebug32);%PATH% - - - WindowsLocalDebugger - PATH=$(wolfCryptDllDebug64);%PATH% - - - WindowsLocalDebugger - PATH=$(wolfCryptDllRelease32);%PATH% - - - WindowsLocalDebugger - PATH=$(wolfCryptDllRelease64);%PATH% - - diff --git a/ide/winvs/echoserver/echoserver.vcxproj.user b/ide/winvs/echoserver/echoserver.vcxproj.user deleted file mode 100644 index 23a5dce7e..000000000 --- a/ide/winvs/echoserver/echoserver.vcxproj.user +++ /dev/null @@ -1,19 +0,0 @@ - - - - WindowsLocalDebugger - PATH=$(wolfCryptDllDebug32);%PATH% - - - WindowsLocalDebugger - PATH=$(wolfCryptDllDebug64);%PATH% - - - WindowsLocalDebugger - PATH=$(wolfCryptDllRelease32);%PATH% - - - WindowsLocalDebugger - PATH=$(wolfCryptDllRelease64);%PATH% - - diff --git a/ide/winvs/include.am b/ide/winvs/include.am index d5a90eaf4..df1990fc4 100644 --- a/ide/winvs/include.am +++ b/ide/winvs/include.am @@ -7,16 +7,9 @@ EXTRA_DIST+= ide/winvs/wolfssh.sln EXTRA_DIST+= ide/winvs/wolfssh.props EXTRA_DIST+= ide/winvs/wolfssh/wolfssh.vcxproj EXTRA_DIST+= ide/winvs/api-test/api-test.vcxproj -EXTRA_DIST+= ide/winvs/api-test/api-test.vcxproj.user EXTRA_DIST+= ide/winvs/unit-test/unit-test.vcxproj -EXTRA_DIST+= ide/winvs/unit-test/unit-test.vcxproj.user EXTRA_DIST+= ide/winvs/client/client.vcxproj -EXTRA_DIST+= ide/winvs/client/client.vcxproj.user EXTRA_DIST+= ide/winvs/echoserver/echoserver.vcxproj -EXTRA_DIST+= ide/winvs/echoserver/echoserver.vcxproj.user EXTRA_DIST+= ide/winvs/testsuite/testsuite.vcxproj -EXTRA_DIST+= ide/winvs/testsuite/testsuite.vcxproj.user EXTRA_DIST+= ide/winvs/wolfsftp-client/wolfsftp-client.vcxproj -EXTRA_DIST+= ide/winvs/wolfsftp-client/wolfsftp-client.vcxproj.user EXTRA_DIST+= ide/winvs/wolfsshd/wolfsshd.vcxproj -EXTRA_DIST+= ide/winvs/wolfsshd/wolfsshd.vcxproj.user diff --git a/ide/winvs/testsuite/testsuite.vcxproj.user b/ide/winvs/testsuite/testsuite.vcxproj.user deleted file mode 100644 index 23a5dce7e..000000000 --- a/ide/winvs/testsuite/testsuite.vcxproj.user +++ /dev/null @@ -1,19 +0,0 @@ - - - - WindowsLocalDebugger - PATH=$(wolfCryptDllDebug32);%PATH% - - - WindowsLocalDebugger - PATH=$(wolfCryptDllDebug64);%PATH% - - - WindowsLocalDebugger - PATH=$(wolfCryptDllRelease32);%PATH% - - - WindowsLocalDebugger - PATH=$(wolfCryptDllRelease64);%PATH% - - diff --git a/ide/winvs/unit-test/unit-test.vcxproj.user b/ide/winvs/unit-test/unit-test.vcxproj.user deleted file mode 100644 index 23a5dce7e..000000000 --- a/ide/winvs/unit-test/unit-test.vcxproj.user +++ /dev/null @@ -1,19 +0,0 @@ - - - - WindowsLocalDebugger - PATH=$(wolfCryptDllDebug32);%PATH% - - - WindowsLocalDebugger - PATH=$(wolfCryptDllDebug64);%PATH% - - - WindowsLocalDebugger - PATH=$(wolfCryptDllRelease32);%PATH% - - - WindowsLocalDebugger - PATH=$(wolfCryptDllRelease64);%PATH% - - diff --git a/ide/winvs/wolfsftp-client/wolfsftp-client.vcxproj.user b/ide/winvs/wolfsftp-client/wolfsftp-client.vcxproj.user deleted file mode 100644 index ee6c1e37c..000000000 --- a/ide/winvs/wolfsftp-client/wolfsftp-client.vcxproj.user +++ /dev/null @@ -1,19 +0,0 @@ - - - - WindowsLocalDebugger - PATH=$(wolfCryptDllDebug32);%PATH% - - - WindowsLocalDebugger - PATH=$(wolfCryptDllDebug64);%PATH% - - - WindowsLocalDebugger - PATH=$(wolfCryptDllRelease32);%PATH% - - - WindowsLocalDebugger - PATH=$(wolfCryptDllRelease64);%PATH% - - diff --git a/ide/winvs/wolfsshd/wolfsshd.vcxproj.user b/ide/winvs/wolfsshd/wolfsshd.vcxproj.user deleted file mode 100644 index e9f3ec837..000000000 --- a/ide/winvs/wolfsshd/wolfsshd.vcxproj.user +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - WindowsLocalDebugger - - - - - WindowsLocalDebugger - - \ No newline at end of file diff --git a/src/wolfscp.c b/src/wolfscp.c index 46c6eaffc..aed1e66a9 100644 --- a/src/wolfscp.c +++ b/src/wolfscp.c @@ -2346,14 +2346,19 @@ static int FindNextDirEntry(ScpSendCtx* ctx) WMEMCPY(ctx->entry, realFileName, sz); ctx->entry[sz] = '\0'; } while ((ctx->entry != NULL) && - (WSTRNCMP(ctx->entry, ".", 1) == 0 || - WSTRNCMP(ctx->entry, "..", 2) == 0)); + (((WSTRLEN(ctx->entry) == 1) && WSTRNCMP(ctx->entry, ".", 1) == 0) || + ((WSTRLEN(ctx->entry) == 2) && WSTRNCMP(ctx->entry, "..", 2) == 0))); #else do { ctx->entry = WREADDIR(&ctx->currentDir->dir); } while ((ctx->entry != NULL) && - (WSTRNCMP(ctx->entry->d_name, ".", 1) == 0 || - WSTRNCMP(ctx->entry->d_name ,"..", 2) == 0)); + ( + ((WSTRLEN(ctx->entry->d_name) == 1) && + (WSTRNCMP(ctx->entry->d_name, ".", 1) == 0)) + || + ((WSTRLEN(ctx->entry->d_name) == 2) && + (WSTRNCMP(ctx->entry->d_name ,"..", 2) == 0)) + )); #endif return WS_SUCCESS;