Merge pull request #441 from JacobBarthelmeh/sshd

add chroot jailing to sshd
pull/452/head
John Safranek 2022-09-01 13:28:52 -07:00 committed by GitHub
commit c8bdf7d3d2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 600 additions and 124 deletions

View File

@ -51,6 +51,7 @@
#ifndef _WIN32
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <errno.h>
#endif
@ -937,4 +938,33 @@ long wolfSSHD_AuthGetGraceTime(const WOLFSSHD_AUTH* auth)
return ret;
}
/* return the user configuration */
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)
{
struct group* g = NULL;
WOLFSSHD_CONFIG* ret = NULL;
if (auth != NULL) {
struct passwd *p_passwd;
p_passwd = getpwnam((const char *)usr);
if (p_passwd == NULL) {
return NULL;
}
g = getgrgid(p_passwd->pw_gid);
if (g == NULL) {
return NULL;
}
ret = wolfSSHD_GetUserConf(auth->conf, usr, g->gr_name, host, localAdr,
localPort, RDomain, adr);
}
return ret;
}
#endif /* WOLFSSH_SSHD */

View File

@ -61,4 +61,8 @@ int wolfSSHD_AuthRaisePermissions(WOLFSSHD_AUTH* auth);
int wolfSSHD_AuthReducePermissionsUser(WOLFSSHD_AUTH* auth, WUID_T uid,
WGID_T gid);
long wolfSSHD_AuthGetGraceTime(const WOLFSSHD_AUTH* auth);
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);
#endif /* WOLFAUTH_H */

View File

@ -50,6 +50,8 @@
struct WOLFSSHD_CONFIG {
void* heap;
char* usrAppliesTo; /* NULL means all users */
char* groupAppliesTo; /* NULL means all groups */
char* banner;
char* chrootDir;
char* ciphers;
@ -58,6 +60,8 @@ struct WOLFSSHD_CONFIG {
char* kekAlgos;
char* listenAddress;
char* authKeysFile;
char* forceCmd;
WOLFSSHD_CONFIG* next; /* next config in list */
long loginTimer;
word16 port;
byte usePrivilegeSeparation:2;
@ -67,6 +71,7 @@ struct WOLFSSHD_CONFIG {
byte permitEmptyPasswords:1;
};
int CountWhitespace(const char* in, int inSz, byte inv);
/* convert a string into seconds, handles if 'm' for minutes follows the string
* number, i.e. 2m
@ -111,11 +116,20 @@ static long GetConfigInt(const char* in, int inSz, int isTime, void* heap)
return ret;
}
/* returns WS_SUCCESS on success */
/* returns WS_SUCCESS on success, removes trailng newlines */
static int CreateString(char** out, const char* in, int inSz, void* heap)
{
int ret = WS_SUCCESS;
int idx = 0;
int idx = 0, tail, sz = 0;
if (in == NULL && inSz != 0) {
return WS_BAD_ARGUMENT;
}
if (in == NULL) {
/* "created" an empty string */
return ret;
}
/* remove leading white spaces */
while (idx < inSz && in[idx] == ' ') idx++;
@ -124,15 +138,28 @@ static int CreateString(char** out, const char* in, int inSz, void* heap)
ret = WS_BAD_ARGUMENT;
}
if (ret == WS_SUCCESS) {
for (tail = inSz - 1; tail > idx; tail--) {
if (in[tail] != '\n' && in[tail] != ' ' && in[tail] != '\r') {
break;
}
}
sz = tail - idx + 1; /* +1 to account for index of 0 */
if (sz > inSz - idx) {
ret = WS_BAD_ARGUMENT;
}
}
/* malloc new string and set it */
if (ret == WS_SUCCESS) {
*out = (char*)WMALLOC((inSz - idx) + 1, heap, DYNTYPE_SSHD);
*out = (char*)WMALLOC(sz + 1, heap, DYNTYPE_SSHD);
if (*out == NULL) {
ret = WS_MEMORY_E;
}
else {
XMEMCPY(*out, in + idx, inSz - idx);
*(*out + (inSz - idx)) = '\0';
XMEMCPY(*out, in + idx, sz);
*(*out + sz) = '\0';
}
}
@ -170,17 +197,101 @@ WOLFSSHD_CONFIG* wolfSSHD_ConfigNew(void* heap)
}
/* on success return a newly create WOLFSSHD_CONFIG structure that has the
* same values set as the input 'conf'. User and group match values are not
* copied */
static WOLFSSHD_CONFIG* wolfSSHD_ConfigCopy(WOLFSSHD_CONFIG* conf)
{
int ret = WS_SUCCESS;
WOLFSSHD_CONFIG* newConf;
newConf = wolfSSHD_ConfigNew(conf->heap);
if (newConf != NULL) {
if (conf->banner) {
ret = CreateString(&newConf->banner, conf->banner,
(int)WSTRLEN(conf->banner),
newConf->heap);
}
if (ret == WS_SUCCESS && conf->chrootDir) {
ret = CreateString(&newConf->chrootDir, conf->chrootDir,
(int)WSTRLEN(conf->chrootDir),
newConf->heap);
}
if (ret == WS_SUCCESS && conf->ciphers) {
ret = CreateString(&newConf->ciphers, conf->ciphers,
(int)WSTRLEN(conf->ciphers),
newConf->heap);
}
if (ret == WS_SUCCESS && conf->hostKeyFile) {
ret = CreateString(&newConf->hostKeyFile, conf->hostKeyFile,
(int)WSTRLEN(conf->hostKeyFile),
newConf->heap);
}
if (ret == WS_SUCCESS && conf->hostKeyAlgos) {
ret = CreateString(&newConf->hostKeyAlgos, conf->hostKeyAlgos,
(int)WSTRLEN(conf->hostKeyAlgos),
newConf->heap);
}
if (ret == WS_SUCCESS && conf->kekAlgos) {
ret = CreateString(&newConf->kekAlgos, conf->kekAlgos,
(int)WSTRLEN(conf->kekAlgos),
newConf->heap);
}
if (ret == WS_SUCCESS && conf->listenAddress) {
ret = CreateString(&newConf->listenAddress, conf->listenAddress,
(int)WSTRLEN(conf->listenAddress),
newConf->heap);
}
if (ret == WS_SUCCESS && conf->authKeysFile) {
ret = CreateString(&newConf->authKeysFile, conf->authKeysFile,
(int)WSTRLEN(conf->authKeysFile),
newConf->heap);
}
if (ret == WS_SUCCESS) {
newConf->loginTimer = conf->loginTimer;
newConf->port = conf->port;
newConf->passwordAuth = conf->passwordAuth;
newConf->pubKeyAuth = conf->pubKeyAuth;
newConf->usePrivilegeSeparation = conf->usePrivilegeSeparation;
newConf->permitRootLogin = conf->permitRootLogin;
newConf->permitEmptyPasswords = conf->permitEmptyPasswords;
}
}
return newConf;
}
void wolfSSHD_ConfigFree(WOLFSSHD_CONFIG* conf)
{
WOLFSSHD_CONFIG* current;
void* heap;
if (conf != NULL) {
heap = conf->heap;
current = conf;
while (current != NULL) {
WOLFSSHD_CONFIG* next = current->next;
heap = current->heap;
FreeString(&conf->authKeysFile, heap);
FreeString(&conf->hostKeyFile, heap);
FreeString(&current->banner, heap);
FreeString(&current->chrootDir, heap);
FreeString(&current->ciphers, heap);
FreeString(&current->kekAlgos, heap);
FreeString(&current->hostKeyAlgos, heap);
FreeString(&current->listenAddress, heap);
FreeString(&current->authKeysFile, heap);
FreeString(&current->hostKeyFile, heap);
WFREE(conf, heap, DYNTYPE_SSHD);
WFREE(current, heap, DYNTYPE_SSHD);
current = next;
}
}
@ -208,10 +319,13 @@ enum {
OPT_PORT = 13,
OPT_PERMIT_ROOT = 14,
OPT_USE_DNS = 15,
OPT_INCLUDE = 16
OPT_INCLUDE = 16,
OPT_CHROOT_DIR = 17,
OPT_MATCH = 18,
OPT_FORCE_CMD = 19,
};
enum {
NUM_OPTIONS = 17
NUM_OPTIONS = 20
};
static const CONFIG_OPTION options[NUM_OPTIONS] = {
@ -231,7 +345,10 @@ static const CONFIG_OPTION options[NUM_OPTIONS] = {
{OPT_PORT, "Port"},
{OPT_PERMIT_ROOT, "PermitRootLogin"},
{OPT_USE_DNS, "UseDNS"},
{OPT_INCLUDE, "Include"}
{OPT_INCLUDE, "Include"},
{OPT_CHROOT_DIR, "ChrootDirectory"},
{OPT_MATCH, "Match"},
{OPT_FORCE_CMD, "ForceCommand"},
};
/* returns WS_SUCCESS on success */
@ -637,20 +754,154 @@ static int HandleInclude(WOLFSSHD_CONFIG *conf, const char *value)
return ret;
}
/* returns WS_SUCCESS on success */
static int HandleConfigOption(WOLFSSHD_CONFIG* conf, int opt, const char* value)
static int HandleChrootDir(WOLFSSHD_CONFIG* conf, const char* value)
{
int ret = WS_SUCCESS;
if (conf == NULL || value == NULL) {
ret = WS_BAD_ARGUMENT;
}
if (ret == WS_SUCCESS) {
if (conf->chrootDir != NULL) {
FreeString(&conf->chrootDir, conf->heap);
conf->chrootDir = NULL;
}
ret = CreateString(&conf->chrootDir, value,
(int)WSTRLEN(value), conf->heap);
}
return ret;
}
/* returns WS_SUCCESS on success, helps with adding a restricted case to the
* config */
static int AddRestrictedCase(WOLFSSHD_CONFIG* config, const char* mtch,
const char* value, char** out)
{
int ret = WS_SUCCESS;
char* pt;
pt = XSTRSTR(value, mtch);
if (pt != NULL) {
int sz, i;
pt += (int)XSTRLEN(mtch);
sz = (int)XSTRLEN(pt);
/* remove spaces between 'mtch' and the user name */
for (i = 0; i < sz; i++) {
if (pt[i] != ' ') break;
}
if (i == sz) {
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] No valid input found with Match");
ret = WS_FATAL_ERROR;
}
if (ret == WS_SUCCESS) {
pt += i;
sz -= i;
/* get the actual size of the user name */
for (i = 0; i < sz; i++) {
if (pt[i] == ' ' || pt[i] == '\r' || pt[i] == '\n') break;
}
sz = i;
ret = CreateString(out, pt, sz, config->heap);
}
}
return ret;
}
/* returns WS_SUCCESS on success, on success it update the conf pointed to
* and makes it point to the newly created conf node */
static int HandleMatch(WOLFSSHD_CONFIG** conf, const char* value, int valueSz)
{
WOLFSSHD_CONFIG* newConf;
int ret = WS_SUCCESS;
if (conf == NULL || *conf == NULL || value == NULL) {
ret = WS_BAD_ARGUMENT;
}
/* create new configure for altered options specific to the match */
if (ret == WS_SUCCESS) {
newConf = wolfSSHD_ConfigCopy(*conf);
if (newConf == NULL) {
ret = WS_MEMORY_E;
}
}
/* users the settings apply to */
if (ret == WS_SUCCESS) {
ret = AddRestrictedCase(newConf, "User", value,
&newConf->usrAppliesTo);
}
/* groups the settings apply to */
if (ret == WS_SUCCESS) {
ret = AddRestrictedCase(newConf, "Group", value,
&newConf->groupAppliesTo);
}
/* @TODO handle , seperated user/group list */
/* update current config being processed */
if (ret == WS_SUCCESS) {
(*conf)->next = newConf;
(*conf) = newConf;
}
(void)valueSz;
return ret;
}
/* returns WS_SUCCESS on success */
static int HandleForcedCommand(WOLFSSHD_CONFIG* conf, const char* value,
int valueSz)
{
int ret = WS_SUCCESS;
if (conf == NULL || value == NULL) {
ret = WS_BAD_ARGUMENT;
}
if (ret == WS_SUCCESS) {
if (conf->forceCmd != NULL) {
FreeString(&conf->forceCmd, conf->heap);
conf->forceCmd = NULL;
}
ret = CreateString(&conf->forceCmd, value, valueSz, conf->heap);
}
(void)valueSz;
return ret;
}
/* returns WS_SUCCESS on success */
static int HandleConfigOption(WOLFSSHD_CONFIG** conf, int opt,
const char* value, const char* full, int fullSz)
{
int ret = WS_BAD_ARGUMENT;
switch (opt) {
case OPT_AUTH_KEYS_FILE:
ret = wolfSSHD_ConfigSetAuthKeysFile(conf, value);
ret = wolfSSHD_ConfigSetAuthKeysFile(*conf, value);
break;
case OPT_PRIV_SEP:
ret = HandlePrivSep(conf, value);
ret = HandlePrivSep(*conf, value);
break;
case OPT_PERMIT_EMPTY_PW:
ret = HandlePermitEmptyPw(conf, value);
ret = HandlePermitEmptyPw(*conf, value);
break;
case OPT_SUBSYSTEM:
/* TODO */
@ -678,30 +929,40 @@ static int HandleConfigOption(WOLFSSHD_CONFIG* conf, int opt, const char* value)
break;
case OPT_PROTOCOL:
/* TODO */
ret = HandleProtocol(conf, value);
ret = HandleProtocol(*conf, value);
break;
case OPT_LOGIN_GRACE_TIME:
ret = HandleLoginGraceTime(conf, value);
ret = HandleLoginGraceTime(*conf, value);
break;
case OPT_HOST_KEY:
/* TODO: Add logic to check if file exists? */
ret = wolfSSHD_ConfigSetHostKeyFile(conf, value);
ret = wolfSSHD_ConfigSetHostKeyFile(*conf, value);
break;
case OPT_PASSWORD_AUTH:
ret = HandlePwAuth(conf, value);
ret = HandlePwAuth(*conf, value);
break;
case OPT_PORT:
ret = HandlePort(conf, value);
ret = HandlePort(*conf, value);
break;
case OPT_PERMIT_ROOT:
ret = HandlePermitRoot(conf, value);
ret = HandlePermitRoot(*conf, value);
break;
case OPT_USE_DNS:
/* TODO */
ret = WS_SUCCESS;
break;
case OPT_INCLUDE:
ret = HandleInclude(conf, value);
ret = HandleInclude(*conf, value);
break;
case OPT_CHROOT_DIR:
ret = HandleChrootDir(*conf, value);
break;
case OPT_MATCH:
/* makes new config and appends it to the list */
ret = HandleMatch(conf, full, fullSz);
break;
case OPT_FORCE_CMD:
ret = HandleForcedCommand(*conf, full, fullSz);
break;
default:
break;
@ -712,7 +973,7 @@ static int HandleConfigOption(WOLFSSHD_CONFIG* conf, int opt, const char* value)
/* helper function to count white spaces, returns the number of white spaces on
* success */
static int CountWhitespace(const char* in, int inSz, byte inv)
int CountWhitespace(const char* in, int inSz, byte inv)
{
int i = 0;
@ -736,8 +997,9 @@ static int CountWhitespace(const char* in, int inSz, byte inv)
/* returns WS_SUCCESS on success
* Fails if any option is found that is unknown/unsupported
* Match command will create new configs for specific matching cases
*/
WOLFSSHD_STATIC int ParseConfigLine(WOLFSSHD_CONFIG* conf, const char* l,
WOLFSSHD_STATIC int ParseConfigLine(WOLFSSHD_CONFIG** conf, const char* l,
int lSz)
{
int ret = WS_BAD_ARGUMENT;
@ -769,7 +1031,7 @@ WOLFSSHD_STATIC int ParseConfigLine(WOLFSSHD_CONFIG* conf, const char* l,
else {
WMEMCPY(tmp, l + idx, sz);
tmp[sz] = 0;
ret = HandleConfigOption(conf, found->tag, tmp);
ret = HandleConfigOption(conf, found->tag, tmp, l + idx, lSz - idx);
}
}
else {
@ -787,6 +1049,7 @@ WOLFSSHD_STATIC int ParseConfigLine(WOLFSSHD_CONFIG* conf, const char* l,
int wolfSSHD_ConfigLoad(WOLFSSHD_CONFIG* conf, const char* filename)
{
XFILE f;
WOLFSSHD_CONFIG* currentConfig;
int ret = WS_SUCCESS;
char buf[MAX_LINE_SIZE];
const char* current;
@ -802,6 +1065,7 @@ int wolfSSHD_ConfigLoad(WOLFSSHD_CONFIG* conf, const char* filename)
}
wolfSSH_Log(WS_LOG_INFO, "[SSHD] parsing config file %s", filename);
currentConfig = conf;
while ((current = XFGETS(buf, MAX_LINE_SIZE, f)) != NULL) {
int currentSz = (int)XSTRLEN(current);
@ -819,7 +1083,7 @@ int wolfSSHD_ConfigLoad(WOLFSSHD_CONFIG* conf, const char* filename)
continue; /* commented out line */
}
ret = ParseConfigLine(conf, current, currentSz);
ret = ParseConfigLine(&currentConfig, current, currentSz);
if (ret != WS_SUCCESS) {
fprintf(stderr, "Unable to parse config line : %s\n", current);
break;
@ -832,6 +1096,60 @@ int wolfSSHD_ConfigLoad(WOLFSSHD_CONFIG* conf, const char* filename)
return ret;
}
/* returns the config associated with the user */
WOLFSSHD_CONFIG* wolfSSHD_GetUserConf(const WOLFSSHD_CONFIG* conf,
const char* usr, const char* grp, const char* host,
const char* localAdr, word16* localPort, const char* RDomain,
const char* adr)
{
WOLFSSHD_CONFIG* ret;
WOLFSSHD_CONFIG* current;
/* default to return head of list */
ret = current = (WOLFSSHD_CONFIG*)conf;
while (current != NULL) {
/* compare current configs user */
if (usr != NULL && current->usrAppliesTo != NULL) {
if (XSTRCMP(current->usrAppliesTo, usr) == 0) {
ret = current;
break;
}
}
/* compare current configs group */
if (grp != NULL && current->groupAppliesTo != NULL) {
if (XSTRCMP(current->groupAppliesTo, grp) == 0) {
ret = current;
break;
}
}
current = current->next;
}
/* @TODO */
(void)host;
(void)localAdr;
(void)localPort;
(void)RDomain;
(void)adr;
return ret;
}
char* wolfSSHD_ConfigGetForcedCmd(const WOLFSSHD_CONFIG* conf)
{
char* ret = NULL;
if (conf != NULL) {
ret = conf->forceCmd;
}
return ret;
}
char* wolfSSHD_ConfigGetAuthKeysFile(const WOLFSSHD_CONFIG* conf)
{
char* ret = NULL;
@ -877,6 +1195,17 @@ char* wolfSSHD_ConfigGetBanner(const WOLFSSHD_CONFIG* conf)
return ret;
}
char* wolfSSHD_ConfigGetChroot(const WOLFSSHD_CONFIG* conf)
{
char* ret = NULL;
if (conf != NULL) {
ret = conf->chrootDir;
}
return ret;
}
char* wolfSSHD_ConfigGetHostKeyFile(const WOLFSSHD_CONFIG* conf)
{
char* ret = NULL;

View File

@ -34,7 +34,9 @@ WOLFSSHD_CONFIG* wolfSSHD_ConfigNew(void* heap);
void wolfSSHD_ConfigFree(WOLFSSHD_CONFIG* conf);
int wolfSSHD_ConfigLoad(WOLFSSHD_CONFIG* conf, const char* filename);
char* wolfSSHD_ConfigGetForcedCmd(const WOLFSSHD_CONFIG* conf);
char* wolfSSHD_ConfigGetBanner(const WOLFSSHD_CONFIG* conf);
char* wolfSSHD_ConfigGetChroot(const WOLFSSHD_CONFIG* conf);
char* wolfSSHD_ConfigGetHostKeyFile(const WOLFSSHD_CONFIG* conf);
int wolfSSHD_ConfigSetHostKeyFile(WOLFSSHD_CONFIG* conf, const char* file);
word16 wolfSSHD_ConfigGetPort(const WOLFSSHD_CONFIG* conf);
@ -45,9 +47,13 @@ byte wolfSSHD_ConfigGetPermitRoot(const WOLFSSHD_CONFIG* conf);
byte wolfSSHD_ConfigGetPrivilegeSeparation(const WOLFSSHD_CONFIG* conf);
long wolfSSHD_ConfigGetGraceTime(const WOLFSSHD_CONFIG* conf);
byte wolfSSHD_ConfigGetPwAuth(const WOLFSSHD_CONFIG* conf);
WOLFSSHD_CONFIG* wolfSSHD_GetUserConf(const WOLFSSHD_CONFIG* conf,
const char* usr, const char* grp, const char* host,
const char* localAdr, word16* localPort, const char* RDomain,
const char* adr);
#ifdef WOLFSSHD_UNIT_TEST
int ParseConfigLine(WOLFSSHD_CONFIG* conf, const char* l, int lSz);
int ParseConfigLine(WOLFSSHD_CONFIG** conf, const char* l, int lSz);
#endif
#endif /* WOLFSSHD_H */

View File

@ -200,7 +200,7 @@ static int test_ParseConfigLine(void)
for (i = 0; i < numVectors; ++i) {
Log(" Testing scenario: %s.", vectors[i].desc);
ret = ParseConfigLine(conf, vectors[i].line,
ret = ParseConfigLine(&conf, vectors[i].line,
(int)WSTRLEN(vectors[i].line));
if ((ret == WS_SUCCESS && !vectors[i].shouldFail) ||

View File

@ -281,27 +281,41 @@ static int SetupCTX(WOLFSSHD_CONFIG* conf, WOLFSSH_CTX** ctx)
}
/* return 1 if set, 0 if not set and negative values on error */
static int SetupChroot(WOLFSSHD_CONFIG* usrConf)
{
int ret = 0;
char* chrootPath;
/* check for chroot set */
chrootPath = wolfSSHD_ConfigGetChroot(usrConf);
if (chrootPath != NULL) {
ret = 1;
wolfSSH_Log(WS_LOG_INFO, "[SSHD] chroot to path %s", chrootPath);
if (chroot(chrootPath) != 0) {
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] chroot failed to path %s", chrootPath);
ret = WS_FATAL_ERROR;
}
}
return ret;
}
#ifdef WOLFSSH_SFTP
#define TEST_SFTP_TIMEOUT 1
/* handle SFTP operations
* returns 0 on success
* returns WS_SUCCESS on success
*/
static int SFTP_Subsystem(WOLFSSH* ssh, WOLFSSHD_CONNECTION* conn)
static int SFTP_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh,
WPASSWD* pPasswd, WOLFSSHD_CONFIG* usrConf)
{
byte tmp[1];
int ret = WS_SUCCESS;
int error = WS_SUCCESS;
WS_SOCKET_T sockfd;
int select_ret = 0;
const char *userName;
struct passwd *p_passwd;
userName = wolfSSH_GetUsername(ssh);
if (userName == NULL) {
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Failure get user name");
return WS_FATAL_ERROR;
}
/* temporarily elevate permissions to get users information */
if (wolfSSHD_AuthRaisePermissions(conn->auth) != WS_SUCCESS) {
@ -309,18 +323,39 @@ static int SFTP_Subsystem(WOLFSSH* ssh, WOLFSSHD_CONNECTION* conn)
return WS_FATAL_ERROR;
}
p_passwd = getpwnam((const char *)userName);
if (p_passwd == NULL) {
if (wolfSSHD_AuthReducePermissions(conn->auth) != WS_SUCCESS) {
/* stop everything if not able to reduce permissions level */
exit(1);
if (ret == WS_SUCCESS) {
error = SetupChroot(usrConf);
if (error == 1) {
/* chroot was executed */
if (wolfSSH_SFTP_SetDefaultPath(ssh, "/") != WS_SUCCESS) {
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Error setting SFTP default path");
ret = WS_FATAL_ERROR;
}
}
else if (error < 0) {
ret = error; /* error case with setup chroot */
}
}
return WS_FATAL_ERROR;
/* set starting SFTP directory */
if (ret == WS_SUCCESS) {
WDIR dir;
/* if home directory exists than set it as the default */
if (WOPENDIR(NULL, NULL, &dir, pPasswd->pw_dir) == 0) {
if (wolfSSH_SFTP_SetDefaultPath(ssh, pPasswd->pw_dir)
!= WS_SUCCESS) {
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Error setting SFTP default home path");
ret = WS_FATAL_ERROR;
}
WCLOSEDIR(&dir);
}
}
if (wolfSSHD_AuthReducePermissionsUser(conn->auth, p_passwd->pw_uid,
p_passwd->pw_gid) != WS_SUCCESS) {
if (wolfSSHD_AuthReducePermissionsUser(conn->auth, pPasswd->pw_uid,
pPasswd->pw_gid) != WS_SUCCESS) {
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error setting user ID");
if (wolfSSHD_AuthReducePermissions(conn->auth) != WS_SUCCESS) {
/* stop everything if not able to reduce permissions level */
@ -378,12 +413,14 @@ static int SFTP_Subsystem(WOLFSSH* ssh, WOLFSSHD_CONNECTION* conn)
#define MAX_COMMAND_SZ 80
#endif
static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh)
/* 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)
{
WS_SOCKET_T sshFd = 0;
int rc;
const char *userName;
struct passwd *p_passwd;
WS_SOCKET_T childFd = 0;
pid_t childPid;
#ifndef EXAMPLE_BUFFER_SZ
@ -391,10 +428,13 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh)
#endif
byte shellBuffer[EXAMPLE_BUFFER_SZ];
byte channelBuffer[EXAMPLE_BUFFER_SZ];
char* forcedCmd;
userName = wolfSSH_GetUsername(ssh);
if (userName == NULL) {
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Failure get user name");
forcedCmd = wolfSSHD_ConfigGetForcedCmd(usrConf);
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;
}
@ -404,30 +444,7 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh)
return WS_FATAL_ERROR;
}
p_passwd = getpwnam((const char *)userName);
if (p_passwd == NULL) {
/* Not actually a user on the system. */
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Invalid user name found");
if (wolfSSHD_AuthReducePermissions(conn->auth) != WS_SUCCESS) {
/* stop everything if not able to reduce permissions level */
exit(1);
}
return WS_FATAL_ERROR;
}
ChildRunning = 1;
if (wolfSSHD_AuthReducePermissionsUser(conn->auth, p_passwd->pw_uid,
p_passwd->pw_gid) != WS_SUCCESS) {
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error setting user ID");
if (wolfSSHD_AuthReducePermissions(conn->auth) != WS_SUCCESS) {
/* stop everything if not able to reduce permissions level */
exit(1);
}
return WS_FATAL_ERROR;
}
childPid = forkpty(&childFd, NULL, NULL, NULL);
if (childPid < 0) {
/* forkpty failed, so return */
@ -444,31 +461,85 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh)
signal(SIGINT, SIG_DFL);
signal(SIGCHLD, SIG_DFL);
setenv("HOME", p_passwd->pw_dir, 1);
setenv("LOGNAME", p_passwd->pw_name, 1);
rc = chdir(p_passwd->pw_dir);
if (rc != 0) {
rc = SetupChroot(usrConf);
if (rc < 0) {
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error setting chroot");
if (wolfSSHD_AuthReducePermissions(conn->auth) != WS_SUCCESS) {
/* stop everything if not able to reduce permissions level */
exit(1);
}
return WS_FATAL_ERROR;
}
else if (rc == 1) {
rc = chdir("/");
if (rc != 0) {
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Error going to / after chroot");
if (wolfSSHD_AuthReducePermissions(conn->auth) != WS_SUCCESS) {
/* stop everything if not able to reduce permissions level */
exit(1);
}
return WS_FATAL_ERROR;
}
}
if (wolfSSHD_AuthReducePermissionsUser(conn->auth, pPasswd->pw_uid,
pPasswd->pw_gid) != WS_SUCCESS) {
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error setting user ID");
if (wolfSSHD_AuthReducePermissions(conn->auth) != WS_SUCCESS) {
/* stop everything if not able to reduce permissions level */
exit(1);
}
return WS_FATAL_ERROR;
}
setenv("HOME", pPasswd->pw_dir, 1);
setenv("LOGNAME", pPasswd->pw_name, 1);
rc = chdir(pPasswd->pw_dir);
if (rc != 0) {
/* not error'ing out if unable to find home directory */
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error going to user home dir %s",
pPasswd->pw_dir);
}
/* default to /bin/sh if user shell is not set */
WMEMSET(cmd, 0, sizeof(cmd));
if (XSTRLEN(p_passwd->pw_shell) == 0) {
if (XSTRLEN(pPasswd->pw_shell) == 0) {
XSNPRINTF(cmd, sizeof(cmd), "%s", "/bin/sh");
}
else {
XSNPRINTF(cmd, sizeof(cmd),"%s", p_passwd->pw_shell);
XSNPRINTF(cmd, sizeof(cmd),"%s", pPasswd->pw_shell);
}
errno = 0;
if (forcedCmd) {
args[0] = NULL;
ret = execv(forcedCmd, (char**)args);
}
else {
ret = execv(cmd, (char**)args);
}
if (ret && errno) {
perror("error executing shell command ");
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue opening shell");
exit(1);
}
exit(0); /* exit child process and close down SSH connection */
}
if (wolfSSHD_AuthReducePermissionsUser(conn->auth, pPasswd->pw_uid,
pPasswd->pw_gid) != WS_SUCCESS) {
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error setting user ID");
if (wolfSSHD_AuthReducePermissions(conn->auth) != WS_SUCCESS) {
/* stop everything if not able to reduce permissions level */
exit(1);
}
return WS_FATAL_ERROR;
}
sshFd = wolfSSH_get_fd(ssh);
struct termios tios;
@ -634,7 +705,8 @@ static void* HandleConnection(void* arg)
error = WS_FATAL_ERROR;
}
if (ret != WS_SUCCESS && ret != WS_SFTP_COMPLETE) {
if (ret != WS_SUCCESS && ret != WS_SFTP_COMPLETE &&
ret != WS_SCP_COMPLETE) {
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Failed to accept WOLFSSH connection from %s",
conn->ip);
@ -642,12 +714,36 @@ static void* HandleConnection(void* arg)
}
if (ret == WS_SUCCESS || ret == WS_SFTP_COMPLETE) {
WPASSWD* pPasswd;
WOLFSSHD_CONFIG* usrConf;
char* usr;
/* get configuration for user */
usr = wolfSSH_GetUsername(ssh);
usrConf = wolfSSHD_AuthGetUserConf(conn->auth, usr, NULL, NULL,
NULL, NULL, NULL);
if (usrConf == NULL) {
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Error getting user configuration");
ret = WS_FATAL_ERROR;
}
if (ret == WS_SUCCESS || ret == WS_SFTP_COMPLETE) {
pPasswd = getpwnam((const char *)usr);
if (pPasswd == NULL) {
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Error igetting user info");
ret = WS_FATAL_ERROR;
}
}
if (ret != WS_FATAL_ERROR) {
/* check for any forced command set for the user */
switch (wolfSSH_GetSessionType(ssh)) {
case WOLFSSH_SESSION_SHELL:
#ifdef WOLFSSH_SHELL
if (ret == WS_SUCCESS) {
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Entering new shell");
SHELL_Subsystem(conn, ssh);
SHELL_Subsystem(conn, ssh, pPasswd, usrConf);
}
#else
wolfSSH_Log(WS_LOG_ERROR,
@ -661,16 +757,18 @@ static void* HandleConnection(void* arg)
switch (ret) {
case WS_SFTP_COMPLETE:
#ifdef WOLFSSH_SFTP
ret = SFTP_Subsystem(ssh, conn);
ret = SFTP_Subsystem(conn, ssh, pPasswd, usrConf);
#else
err_sys("SFTP not compiled in. Please use --enable-sftp");
err_sys("SFTP not compiled in. Please use "
"--enable-sftp");
#endif
break;
default:
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Unknown or build not supporting subsystem"
" found [%s]", wolfSSH_GetSessionCommand(ssh));
"[SSHD] Unknown or build not supporting sub"
"system found [%s]",
wolfSSH_GetSessionCommand(ssh));
ret = WS_NOT_COMPILED;
}
break;
@ -680,10 +778,12 @@ static void* HandleConnection(void* arg)
case WOLFSSH_SESSION_TERMINAL:
default:
wolfSSH_Log(WS_LOG_ERROR,
"[SSHD] Unknown or build not supporting session type found");
"[SSHD] Unknown or build not supporting session type "
"found");
ret = WS_NOT_COMPILED;
}
}
}
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Attempting to close down connection");
wolfSSH_shutdown(ssh);

View File

@ -1230,6 +1230,12 @@ static int wolfSSH_SFTP_RecvRealPath(WOLFSSH* ssh, int reqId, byte* data,
rSz -= 1;
}
/* special case of /. */
if (rSz == 2 && r[0] == WS_DELIM && r[1] == '.') {
r[1] = '\0';
rSz -= 1;
}
/* for real path always send '/' chars */
for (i = 0; i < rSz; i++) {
if (r[i] == WS_DELIM) r[i] = '/';

View File

@ -50,6 +50,7 @@ extern "C" {
#endif
#define WUID_T uid_t
#define WGID_T gid_t
#define WPASSWD struct passwd
#endif
/* setup memory handling */