Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 88 additions & 2 deletions apps/wolfsshd/wolfsshd.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@
#include "auth.h"

#include <signal.h>
#ifdef _WIN32
#include <userenv.h> /* CreateEnvironmentBlock */
#endif

#ifdef NO_INLINE
#include <wolfssh/misc.h>
Expand Down Expand Up @@ -2130,6 +2133,80 @@ static SHELL_SEND_STATE SHELL_BacklogState(WOLFSSH* ssh, int sendRet,

#ifdef WIN32

/* The PATH entry ("Path=...") of an environment block, or NULL */
static const WCHAR* EnvBlockPath(const WCHAR* blk)
{
const WCHAR* p;

for (p = blk; *p != L'\0'; p += wcslen(p) + 1) {
if (_wcsnicmp(p, L"PATH=", 5) == 0) {
return p;
}
}
return NULL;
}


/* The session's environment, as Win32-OpenSSH builds it: the user's block
* on top of the service's, so variables such as ProgramFiles are set when
* registry values that refer to them (PSModulePath) are expanded. PATH alone
* comes from the user-only block, so the service account's own user PATH
* stays out. Returns a block to WFREE, or NULL to inherit the service's. */
static WCHAR* SHELL_UserEnvironment(HANDLE token)
{
LPVOID full = NULL;
LPVOID user = NULL;
const WCHAR* fullPath;
const WCHAR* userPath = NULL;
const WCHAR* p;
WCHAR* env;
WCHAR* out;
size_t sz = 2; /* the terminators of an empty block */

if (CreateEnvironmentBlock(&full, token, TRUE) != TRUE) {
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Issue building user environment, Windows error %d",
GetLastError());
return NULL;
}
if (CreateEnvironmentBlock(&user, token, FALSE) == TRUE) {
userPath = EnvBlockPath((const WCHAR*)user);
}
else {
user = NULL;
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Issue building user PATH, Windows error %d",
GetLastError());
}
fullPath = EnvBlockPath((const WCHAR*)full);

for (p = (const WCHAR*)full; *p != L'\0'; p += wcslen(p) + 1) {
sz += wcslen((p == fullPath && userPath != NULL) ? userPath : p) + 1;
}

env = (WCHAR*)WMALLOC(sizeof(WCHAR) * sz, NULL, DYNTYPE_SSHD);
if (env != NULL) {
out = env;
for (p = (const WCHAR*)full; *p != L'\0'; p += wcslen(p) + 1) {
const WCHAR* src = (p == fullPath && userPath != NULL) ?
userPath : p;
size_t len = wcslen(src) + 1;

WMEMCPY(out, src, sizeof(WCHAR) * len);
out += len;
}
out[0] = L'\0';
out[1] = L'\0';
}

if (user != NULL) {
DestroyEnvironmentBlock(user);
}
DestroyEnvironmentBlock(full);
return env;
}


/* 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 */
Expand Down Expand Up @@ -2169,6 +2246,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
size_t conCmdSz = 0;
PROCESS_INFORMATION processInfo;
int processCreated = 0;
WCHAR* env = NULL;
size_t sz = 0;
WCHAR h[MAX_PATH];
char* forcedCmd;
Expand Down Expand Up @@ -2326,9 +2404,14 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
si.dwFlags = STARTF_USESTDHANDLES;
si.lpDesktop = NULL;

/* The user's own variables (USERPROFILE, APPDATA, user PATH), not the
* service account's. The profile is loaded by now, so they resolve.
* NULL falls back to the service's environment. */
env = SHELL_UserEnvironment(wolfSSHD_GetAuthToken(conn->auth));

if (CreateProcessAsUserW(wolfSSHD_GetAuthToken(conn->auth), NULL, conCmdPtr,
NULL, NULL, TRUE, DETACHED_PROCESS, NULL, h,
&si, &processInfo) != TRUE) {
NULL, NULL, TRUE, DETACHED_PROCESS | CREATE_UNICODE_ENVIRONMENT,
env, h, &si, &processInfo) != TRUE) {
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Issue creating process, Windows error %d", GetLastError());
ret = WS_FATAL_ERROR;
Expand Down Expand Up @@ -2636,6 +2719,9 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
}

cleanup:
if (env != NULL) {
WFREE(env, NULL, DYNTYPE_SSHD);
}
if (conCmdPtr != NULL) {
WFREE(conCmdPtr, NULL, DYNTYPE_SSHD);
}
Expand Down
Loading