From e1f0a67c38b7caefa711f703274bde0639d673c5 Mon Sep 17 00:00:00 2001 From: JacobBarthelmeh Date: Fri, 19 Aug 2022 14:32:13 -0700 Subject: [PATCH] add chroot jailing to sshd --- apps/wolfsshd/auth.c | 30 ++ apps/wolfsshd/auth.h | 4 + apps/wolfsshd/configuration.c | 385 ++++++++++++++++++++++-- apps/wolfsshd/configuration.h | 8 +- apps/wolfsshd/test/test_configuration.c | 2 +- apps/wolfsshd/wolfsshd.c | 155 +++++++--- 6 files changed, 512 insertions(+), 72 deletions(-) diff --git a/apps/wolfsshd/auth.c b/apps/wolfsshd/auth.c index 6f915f63..2e520b83 100644 --- a/apps/wolfsshd/auth.c +++ b/apps/wolfsshd/auth.c @@ -51,6 +51,7 @@ #ifndef _WIN32 #include #include +#include #include #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 */ diff --git a/apps/wolfsshd/auth.h b/apps/wolfsshd/auth.h index 4fb0c894..9274652f 100644 --- a/apps/wolfsshd/auth.h +++ b/apps/wolfsshd/auth.h @@ -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 */ diff --git a/apps/wolfsshd/configuration.c b/apps/wolfsshd/configuration.c index 31178a22..3766cd51 100644 --- a/apps/wolfsshd/configuration.c +++ b/apps/wolfsshd/configuration.c @@ -49,6 +49,8 @@ struct WOLFSSHD_CONFIG { void* heap; + char* usrAppliesTo; /* NULL means all users */ + char* groupAppliesTo; /* NULL means all groups */ char* banner; char* chrootDir; char* ciphers; @@ -57,6 +59,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; @@ -66,6 +70,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 @@ -110,11 +115,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++; @@ -123,15 +137,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'; } } @@ -169,17 +196,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 && conf->chrootDir) { + ret = CreateString(&newConf->chrootDir, conf->chrootDir, + (int)WSTRLEN(conf->chrootDir), + 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(¤t->authKeysFile, heap); + FreeString(¤t->hostKeyFile, heap); - WFREE(conf, heap, DYNTYPE_SSHD); + WFREE(current, heap, DYNTYPE_SSHD); + current = next; } } @@ -207,10 +318,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] = { @@ -230,7 +344,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 */ @@ -567,20 +684,154 @@ static int HandleInclude(WOLFSSHD_CONFIG *conf, const char *value) return WS_SUCCESS; } + /* 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 */ @@ -608,30 +859,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; @@ -642,7 +903,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; @@ -666,8 +927,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; @@ -699,7 +961,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 { @@ -717,6 +979,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; @@ -732,6 +995,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); @@ -749,7 +1013,7 @@ int wolfSSHD_ConfigLoad(WOLFSSHD_CONFIG* conf, const char* filename) continue; /* commented out line */ } - ret = ParseConfigLine(conf, current, currentSz); + ret = ParseConfigLine(¤tConfig, current, currentSz); if (ret != WS_SUCCESS) { fprintf(stderr, "Unable to parse config line : %s\n", current); break; @@ -762,6 +1026,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; @@ -807,6 +1125,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; diff --git a/apps/wolfsshd/configuration.h b/apps/wolfsshd/configuration.h index 3d352408..7504f210 100644 --- a/apps/wolfsshd/configuration.h +++ b/apps/wolfsshd/configuration.h @@ -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 */ diff --git a/apps/wolfsshd/test/test_configuration.c b/apps/wolfsshd/test/test_configuration.c index 4b1fe5b7..1e7a2eff 100644 --- a/apps/wolfsshd/test/test_configuration.c +++ b/apps/wolfsshd/test/test_configuration.c @@ -122,7 +122,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) || diff --git a/apps/wolfsshd/wolfsshd.c b/apps/wolfsshd/wolfsshd.c index caaa3477..c0bfe373 100644 --- a/apps/wolfsshd/wolfsshd.c +++ b/apps/wolfsshd/wolfsshd.c @@ -377,7 +377,8 @@ static int SFTP_Subsystem(WOLFSSH* ssh, WOLFSSHD_CONNECTION* conn) #define MAX_COMMAND_SZ 80 #endif -static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh) +static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh, + char* forcedCmd) { WS_SOCKET_T sshFd = 0; int rc; @@ -460,9 +461,14 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh) } errno = 0; - ret = execv(cmd, (char**)args); + if (forcedCmd) { + ret = execv(forcedCmd, NULL); + } + 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 */ @@ -633,7 +639,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); @@ -641,46 +648,110 @@ static void* HandleConnection(void* arg) } if (ret == WS_SUCCESS || ret == WS_SFTP_COMPLETE) { - 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); - } - #else + WOLFSSHD_CONFIG* usrConf; + char* cmd; + 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; + } + + + #ifdef WOLFSSH_SFTP + /* set starting SFTP directory */ + if (ret == WS_SFTP_COMPLETE) { + struct passwd *p_passwd; + p_passwd = getpwnam((const char *)usr); + if (p_passwd == NULL || wolfSSH_SFTP_SetDefaultPath(ssh, + p_passwd->pw_dir) != WS_SUCCESS) { wolfSSH_Log(WS_LOG_ERROR, - "[SSHD] Shell support is disabled"); - ret = WS_NOT_COMPILED; - #endif - break; - - case WOLFSSH_SESSION_SUBSYSTEM: - /* test for known subsystems */ - switch (ret) { - case WS_SFTP_COMPLETE: - #ifdef WOLFSSH_SFTP - ret = SFTP_Subsystem(ssh, conn); - #else - 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)); - ret = WS_NOT_COMPILED; - } - break; - - case WOLFSSH_SESSION_UNKNOWN: - case WOLFSSH_SESSION_EXEC: - case WOLFSSH_SESSION_TERMINAL: - default: + "[SSHD] Error setting SFTP default home path"); + ret = WS_FATAL_ERROR; + } + } + #endif + /* check for chroot set */ + cmd = wolfSSHD_ConfigGetChroot(usrConf); + if (cmd != NULL) { + if (chroot(cmd) != 0) { wolfSSH_Log(WS_LOG_ERROR, - "[SSHD] Unknown or build not supporting session type found"); - ret = WS_NOT_COMPILED; + "[SSHD] chroot failed to path %s", cmd); + ret = WS_FATAL_ERROR; + } + + #ifdef WOLFSSH_SFTP + if (ret == WS_SFTP_COMPLETE) { + if (wolfSSH_SFTP_SetDefaultPath(ssh, "/") != WS_SUCCESS) { + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Error setting SFTP default path"); + ret = WS_FATAL_ERROR; + } + } + #endif + } + + if (ret != WS_FATAL_ERROR) { + /* check for any forced command set for the user */ + cmd = wolfSSHD_ConfigGetForcedCmd(usrConf); + switch (wolfSSH_GetSessionType(ssh)) { + case WOLFSSH_SESSION_SHELL: + #ifdef WOLFSSH_SHELL + if (ret == WS_SUCCESS) { + if (cmd != NULL && XSTRCMP(cmd, "internal-sftp") == 0) { + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Only SFTP connections allowed for user " + "%s", usr); + ret = WS_FATAL_ERROR; + } + else { + wolfSSH_Log(WS_LOG_INFO, + "[SSHD] Entering new shell"); + SHELL_Subsystem(conn, ssh, cmd); + } + } + #else + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Shell support is disabled"); + ret = WS_NOT_COMPILED; + #endif + break; + + case WOLFSSH_SESSION_SUBSYSTEM: + /* test for known subsystems */ + switch (ret) { + case WS_SFTP_COMPLETE: + #ifdef WOLFSSH_SFTP + ret = SFTP_Subsystem(ssh, conn); + #else + err_sys("SFTP not compiled in. Please use " + "--enable-sftp"); + #endif + break; + + default: + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Unknown or build not supporting sub" + "system found [%s]", + wolfSSH_GetSessionCommand(ssh)); + ret = WS_NOT_COMPILED; + } + break; + + case WOLFSSH_SESSION_UNKNOWN: + case WOLFSSH_SESSION_EXEC: + case WOLFSSH_SESSION_TERMINAL: + default: + wolfSSH_Log(WS_LOG_ERROR, + "[SSHD] Unknown or build not supporting session type " + "found"); + ret = WS_NOT_COMPILED; + } } }