mirror of https://github.com/wolfSSL/wolfssh.git
add chroot jailing to sshd
parent
82172d0e43
commit
e1f0a67c38
|
@ -51,6 +51,7 @@
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
|
#include <grp.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -937,4 +938,33 @@ long wolfSSHD_AuthGetGraceTime(const WOLFSSHD_AUTH* auth)
|
||||||
|
|
||||||
return ret;
|
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 */
|
#endif /* WOLFSSH_SSHD */
|
||||||
|
|
|
@ -61,4 +61,8 @@ int wolfSSHD_AuthRaisePermissions(WOLFSSHD_AUTH* auth);
|
||||||
int wolfSSHD_AuthReducePermissionsUser(WOLFSSHD_AUTH* auth, WUID_T uid,
|
int wolfSSHD_AuthReducePermissionsUser(WOLFSSHD_AUTH* auth, WUID_T uid,
|
||||||
WGID_T gid);
|
WGID_T gid);
|
||||||
long wolfSSHD_AuthGetGraceTime(const WOLFSSHD_AUTH* auth);
|
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 */
|
#endif /* WOLFAUTH_H */
|
||||||
|
|
|
@ -49,6 +49,8 @@
|
||||||
|
|
||||||
struct WOLFSSHD_CONFIG {
|
struct WOLFSSHD_CONFIG {
|
||||||
void* heap;
|
void* heap;
|
||||||
|
char* usrAppliesTo; /* NULL means all users */
|
||||||
|
char* groupAppliesTo; /* NULL means all groups */
|
||||||
char* banner;
|
char* banner;
|
||||||
char* chrootDir;
|
char* chrootDir;
|
||||||
char* ciphers;
|
char* ciphers;
|
||||||
|
@ -57,6 +59,8 @@ struct WOLFSSHD_CONFIG {
|
||||||
char* kekAlgos;
|
char* kekAlgos;
|
||||||
char* listenAddress;
|
char* listenAddress;
|
||||||
char* authKeysFile;
|
char* authKeysFile;
|
||||||
|
char* forceCmd;
|
||||||
|
WOLFSSHD_CONFIG* next; /* next config in list */
|
||||||
long loginTimer;
|
long loginTimer;
|
||||||
word16 port;
|
word16 port;
|
||||||
byte usePrivilegeSeparation;
|
byte usePrivilegeSeparation;
|
||||||
|
@ -66,6 +70,7 @@ struct WOLFSSHD_CONFIG {
|
||||||
byte permitEmptyPasswords:1;
|
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
|
/* convert a string into seconds, handles if 'm' for minutes follows the string
|
||||||
* number, i.e. 2m
|
* number, i.e. 2m
|
||||||
|
@ -110,11 +115,20 @@ static long GetConfigInt(const char* in, int inSz, int isTime, void* heap)
|
||||||
return ret;
|
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)
|
static int CreateString(char** out, const char* in, int inSz, void* heap)
|
||||||
{
|
{
|
||||||
int ret = WS_SUCCESS;
|
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 */
|
/* remove leading white spaces */
|
||||||
while (idx < inSz && in[idx] == ' ') idx++;
|
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;
|
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 */
|
/* malloc new string and set it */
|
||||||
if (ret == WS_SUCCESS) {
|
if (ret == WS_SUCCESS) {
|
||||||
*out = (char*)WMALLOC((inSz - idx) + 1, heap, DYNTYPE_SSHD);
|
*out = (char*)WMALLOC(sz + 1, heap, DYNTYPE_SSHD);
|
||||||
if (*out == NULL) {
|
if (*out == NULL) {
|
||||||
ret = WS_MEMORY_E;
|
ret = WS_MEMORY_E;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
XMEMCPY(*out, in + idx, inSz - idx);
|
XMEMCPY(*out, in + idx, sz);
|
||||||
*(*out + (inSz - idx)) = '\0';
|
*(*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)
|
void wolfSSHD_ConfigFree(WOLFSSHD_CONFIG* conf)
|
||||||
{
|
{
|
||||||
|
WOLFSSHD_CONFIG* current;
|
||||||
void* heap;
|
void* heap;
|
||||||
|
|
||||||
if (conf != NULL) {
|
current = conf;
|
||||||
heap = conf->heap;
|
while (current != NULL) {
|
||||||
|
WOLFSSHD_CONFIG* next = current->next;
|
||||||
|
heap = current->heap;
|
||||||
|
|
||||||
FreeString(&conf->authKeysFile, heap);
|
FreeString(¤t->authKeysFile, heap);
|
||||||
FreeString(&conf->hostKeyFile, 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_PORT = 13,
|
||||||
OPT_PERMIT_ROOT = 14,
|
OPT_PERMIT_ROOT = 14,
|
||||||
OPT_USE_DNS = 15,
|
OPT_USE_DNS = 15,
|
||||||
OPT_INCLUDE = 16
|
OPT_INCLUDE = 16,
|
||||||
|
OPT_CHROOT_DIR = 17,
|
||||||
|
OPT_MATCH = 18,
|
||||||
|
OPT_FORCE_CMD = 19,
|
||||||
};
|
};
|
||||||
enum {
|
enum {
|
||||||
NUM_OPTIONS = 17
|
NUM_OPTIONS = 20
|
||||||
};
|
};
|
||||||
|
|
||||||
static const CONFIG_OPTION options[NUM_OPTIONS] = {
|
static const CONFIG_OPTION options[NUM_OPTIONS] = {
|
||||||
|
@ -230,7 +344,10 @@ static const CONFIG_OPTION options[NUM_OPTIONS] = {
|
||||||
{OPT_PORT, "Port"},
|
{OPT_PORT, "Port"},
|
||||||
{OPT_PERMIT_ROOT, "PermitRootLogin"},
|
{OPT_PERMIT_ROOT, "PermitRootLogin"},
|
||||||
{OPT_USE_DNS, "UseDNS"},
|
{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 */
|
/* returns WS_SUCCESS on success */
|
||||||
|
@ -567,20 +684,154 @@ static int HandleInclude(WOLFSSHD_CONFIG *conf, const char *value)
|
||||||
return WS_SUCCESS;
|
return WS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* returns WS_SUCCESS on 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;
|
int ret = WS_BAD_ARGUMENT;
|
||||||
|
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case OPT_AUTH_KEYS_FILE:
|
case OPT_AUTH_KEYS_FILE:
|
||||||
ret = wolfSSHD_ConfigSetAuthKeysFile(conf, value);
|
ret = wolfSSHD_ConfigSetAuthKeysFile(*conf, value);
|
||||||
break;
|
break;
|
||||||
case OPT_PRIV_SEP:
|
case OPT_PRIV_SEP:
|
||||||
ret = HandlePrivSep(conf, value);
|
ret = HandlePrivSep(*conf, value);
|
||||||
break;
|
break;
|
||||||
case OPT_PERMIT_EMPTY_PW:
|
case OPT_PERMIT_EMPTY_PW:
|
||||||
ret = HandlePermitEmptyPw(conf, value);
|
ret = HandlePermitEmptyPw(*conf, value);
|
||||||
break;
|
break;
|
||||||
case OPT_SUBSYSTEM:
|
case OPT_SUBSYSTEM:
|
||||||
/* TODO */
|
/* TODO */
|
||||||
|
@ -608,30 +859,40 @@ static int HandleConfigOption(WOLFSSHD_CONFIG* conf, int opt, const char* value)
|
||||||
break;
|
break;
|
||||||
case OPT_PROTOCOL:
|
case OPT_PROTOCOL:
|
||||||
/* TODO */
|
/* TODO */
|
||||||
ret = HandleProtocol(conf, value);
|
ret = HandleProtocol(*conf, value);
|
||||||
break;
|
break;
|
||||||
case OPT_LOGIN_GRACE_TIME:
|
case OPT_LOGIN_GRACE_TIME:
|
||||||
ret = HandleLoginGraceTime(conf, value);
|
ret = HandleLoginGraceTime(*conf, value);
|
||||||
break;
|
break;
|
||||||
case OPT_HOST_KEY:
|
case OPT_HOST_KEY:
|
||||||
/* TODO: Add logic to check if file exists? */
|
/* TODO: Add logic to check if file exists? */
|
||||||
ret = wolfSSHD_ConfigSetHostKeyFile(conf, value);
|
ret = wolfSSHD_ConfigSetHostKeyFile(*conf, value);
|
||||||
break;
|
break;
|
||||||
case OPT_PASSWORD_AUTH:
|
case OPT_PASSWORD_AUTH:
|
||||||
ret = HandlePwAuth(conf, value);
|
ret = HandlePwAuth(*conf, value);
|
||||||
break;
|
break;
|
||||||
case OPT_PORT:
|
case OPT_PORT:
|
||||||
ret = HandlePort(conf, value);
|
ret = HandlePort(*conf, value);
|
||||||
break;
|
break;
|
||||||
case OPT_PERMIT_ROOT:
|
case OPT_PERMIT_ROOT:
|
||||||
ret = HandlePermitRoot(conf, value);
|
ret = HandlePermitRoot(*conf, value);
|
||||||
break;
|
break;
|
||||||
case OPT_USE_DNS:
|
case OPT_USE_DNS:
|
||||||
/* TODO */
|
/* TODO */
|
||||||
ret = WS_SUCCESS;
|
ret = WS_SUCCESS;
|
||||||
break;
|
break;
|
||||||
case OPT_INCLUDE:
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
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
|
/* helper function to count white spaces, returns the number of white spaces on
|
||||||
* success */
|
* success */
|
||||||
static int CountWhitespace(const char* in, int inSz, byte inv)
|
int CountWhitespace(const char* in, int inSz, byte inv)
|
||||||
{
|
{
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
|
@ -666,8 +927,9 @@ static int CountWhitespace(const char* in, int inSz, byte inv)
|
||||||
|
|
||||||
/* returns WS_SUCCESS on success
|
/* returns WS_SUCCESS on success
|
||||||
* Fails if any option is found that is unknown/unsupported
|
* 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 lSz)
|
||||||
{
|
{
|
||||||
int ret = WS_BAD_ARGUMENT;
|
int ret = WS_BAD_ARGUMENT;
|
||||||
|
@ -699,7 +961,7 @@ WOLFSSHD_STATIC int ParseConfigLine(WOLFSSHD_CONFIG* conf, const char* l,
|
||||||
else {
|
else {
|
||||||
WMEMCPY(tmp, l + idx, sz);
|
WMEMCPY(tmp, l + idx, sz);
|
||||||
tmp[sz] = 0;
|
tmp[sz] = 0;
|
||||||
ret = HandleConfigOption(conf, found->tag, tmp);
|
ret = HandleConfigOption(conf, found->tag, tmp, l + idx, lSz - idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -717,6 +979,7 @@ WOLFSSHD_STATIC int ParseConfigLine(WOLFSSHD_CONFIG* conf, const char* l,
|
||||||
int wolfSSHD_ConfigLoad(WOLFSSHD_CONFIG* conf, const char* filename)
|
int wolfSSHD_ConfigLoad(WOLFSSHD_CONFIG* conf, const char* filename)
|
||||||
{
|
{
|
||||||
XFILE f;
|
XFILE f;
|
||||||
|
WOLFSSHD_CONFIG* currentConfig;
|
||||||
int ret = WS_SUCCESS;
|
int ret = WS_SUCCESS;
|
||||||
char buf[MAX_LINE_SIZE];
|
char buf[MAX_LINE_SIZE];
|
||||||
const char* current;
|
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);
|
wolfSSH_Log(WS_LOG_INFO, "[SSHD] parsing config file %s", filename);
|
||||||
|
|
||||||
|
currentConfig = conf;
|
||||||
while ((current = XFGETS(buf, MAX_LINE_SIZE, f)) != NULL) {
|
while ((current = XFGETS(buf, MAX_LINE_SIZE, f)) != NULL) {
|
||||||
int currentSz = (int)XSTRLEN(current);
|
int currentSz = (int)XSTRLEN(current);
|
||||||
|
|
||||||
|
@ -749,7 +1013,7 @@ int wolfSSHD_ConfigLoad(WOLFSSHD_CONFIG* conf, const char* filename)
|
||||||
continue; /* commented out line */
|
continue; /* commented out line */
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = ParseConfigLine(conf, current, currentSz);
|
ret = ParseConfigLine(¤tConfig, current, currentSz);
|
||||||
if (ret != WS_SUCCESS) {
|
if (ret != WS_SUCCESS) {
|
||||||
fprintf(stderr, "Unable to parse config line : %s\n", current);
|
fprintf(stderr, "Unable to parse config line : %s\n", current);
|
||||||
break;
|
break;
|
||||||
|
@ -762,6 +1026,60 @@ int wolfSSHD_ConfigLoad(WOLFSSHD_CONFIG* conf, const char* filename)
|
||||||
return ret;
|
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* wolfSSHD_ConfigGetAuthKeysFile(const WOLFSSHD_CONFIG* conf)
|
||||||
{
|
{
|
||||||
char* ret = NULL;
|
char* ret = NULL;
|
||||||
|
@ -807,6 +1125,17 @@ char* wolfSSHD_ConfigGetBanner(const WOLFSSHD_CONFIG* conf)
|
||||||
return ret;
|
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* wolfSSHD_ConfigGetHostKeyFile(const WOLFSSHD_CONFIG* conf)
|
||||||
{
|
{
|
||||||
char* ret = NULL;
|
char* ret = NULL;
|
||||||
|
|
|
@ -34,7 +34,9 @@ WOLFSSHD_CONFIG* wolfSSHD_ConfigNew(void* heap);
|
||||||
void wolfSSHD_ConfigFree(WOLFSSHD_CONFIG* conf);
|
void wolfSSHD_ConfigFree(WOLFSSHD_CONFIG* conf);
|
||||||
int wolfSSHD_ConfigLoad(WOLFSSHD_CONFIG* conf, const char* filename);
|
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_ConfigGetBanner(const WOLFSSHD_CONFIG* conf);
|
||||||
|
char* wolfSSHD_ConfigGetChroot(const WOLFSSHD_CONFIG* conf);
|
||||||
char* wolfSSHD_ConfigGetHostKeyFile(const WOLFSSHD_CONFIG* conf);
|
char* wolfSSHD_ConfigGetHostKeyFile(const WOLFSSHD_CONFIG* conf);
|
||||||
int wolfSSHD_ConfigSetHostKeyFile(WOLFSSHD_CONFIG* conf, const char* file);
|
int wolfSSHD_ConfigSetHostKeyFile(WOLFSSHD_CONFIG* conf, const char* file);
|
||||||
word16 wolfSSHD_ConfigGetPort(const WOLFSSHD_CONFIG* conf);
|
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);
|
byte wolfSSHD_ConfigGetPrivilegeSeparation(const WOLFSSHD_CONFIG* conf);
|
||||||
long wolfSSHD_ConfigGetGraceTime(const WOLFSSHD_CONFIG* conf);
|
long wolfSSHD_ConfigGetGraceTime(const WOLFSSHD_CONFIG* conf);
|
||||||
byte wolfSSHD_ConfigGetPwAuth(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
|
#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
|
||||||
|
|
||||||
#endif /* WOLFSSHD_H */
|
#endif /* WOLFSSHD_H */
|
||||||
|
|
|
@ -122,7 +122,7 @@ static int test_ParseConfigLine(void)
|
||||||
for (i = 0; i < numVectors; ++i) {
|
for (i = 0; i < numVectors; ++i) {
|
||||||
Log(" Testing scenario: %s.", vectors[i].desc);
|
Log(" Testing scenario: %s.", vectors[i].desc);
|
||||||
|
|
||||||
ret = ParseConfigLine(conf, vectors[i].line,
|
ret = ParseConfigLine(&conf, vectors[i].line,
|
||||||
(int)WSTRLEN(vectors[i].line));
|
(int)WSTRLEN(vectors[i].line));
|
||||||
|
|
||||||
if ((ret == WS_SUCCESS && !vectors[i].shouldFail) ||
|
if ((ret == WS_SUCCESS && !vectors[i].shouldFail) ||
|
||||||
|
|
|
@ -377,7 +377,8 @@ static int SFTP_Subsystem(WOLFSSH* ssh, WOLFSSHD_CONNECTION* conn)
|
||||||
#define MAX_COMMAND_SZ 80
|
#define MAX_COMMAND_SZ 80
|
||||||
#endif
|
#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;
|
WS_SOCKET_T sshFd = 0;
|
||||||
int rc;
|
int rc;
|
||||||
|
@ -460,9 +461,14 @@ static int SHELL_Subsystem(WOLFSSHD_CONNECTION* conn, WOLFSSH* ssh)
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
if (forcedCmd) {
|
||||||
|
ret = execv(forcedCmd, NULL);
|
||||||
|
}
|
||||||
|
else {
|
||||||
ret = execv(cmd, (char**)args);
|
ret = execv(cmd, (char**)args);
|
||||||
|
}
|
||||||
if (ret && errno) {
|
if (ret && errno) {
|
||||||
perror("error executing shell command ");
|
wolfSSH_Log(WS_LOG_ERROR, "[SSHD] Issue opening shell");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
exit(0); /* exit child process and close down SSH connection */
|
exit(0); /* exit child process and close down SSH connection */
|
||||||
|
@ -633,7 +639,8 @@ static void* HandleConnection(void* arg)
|
||||||
error = WS_FATAL_ERROR;
|
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,
|
wolfSSH_Log(WS_LOG_ERROR,
|
||||||
"[SSHD] Failed to accept WOLFSSH connection from %s",
|
"[SSHD] Failed to accept WOLFSSH connection from %s",
|
||||||
conn->ip);
|
conn->ip);
|
||||||
|
@ -641,12 +648,72 @@ static void* HandleConnection(void* arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret == WS_SUCCESS || ret == WS_SFTP_COMPLETE) {
|
if (ret == WS_SUCCESS || ret == WS_SFTP_COMPLETE) {
|
||||||
|
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] 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] 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)) {
|
switch (wolfSSH_GetSessionType(ssh)) {
|
||||||
case WOLFSSH_SESSION_SHELL:
|
case WOLFSSH_SESSION_SHELL:
|
||||||
#ifdef WOLFSSH_SHELL
|
#ifdef WOLFSSH_SHELL
|
||||||
if (ret == WS_SUCCESS) {
|
if (ret == WS_SUCCESS) {
|
||||||
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Entering new shell");
|
if (cmd != NULL && XSTRCMP(cmd, "internal-sftp") == 0) {
|
||||||
SHELL_Subsystem(conn, ssh);
|
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
|
#else
|
||||||
wolfSSH_Log(WS_LOG_ERROR,
|
wolfSSH_Log(WS_LOG_ERROR,
|
||||||
|
@ -662,14 +729,16 @@ static void* HandleConnection(void* arg)
|
||||||
#ifdef WOLFSSH_SFTP
|
#ifdef WOLFSSH_SFTP
|
||||||
ret = SFTP_Subsystem(ssh, conn);
|
ret = SFTP_Subsystem(ssh, conn);
|
||||||
#else
|
#else
|
||||||
err_sys("SFTP not compiled in. Please use --enable-sftp");
|
err_sys("SFTP not compiled in. Please use "
|
||||||
|
"--enable-sftp");
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
wolfSSH_Log(WS_LOG_ERROR,
|
wolfSSH_Log(WS_LOG_ERROR,
|
||||||
"[SSHD] Unknown or build not supporting subsystem"
|
"[SSHD] Unknown or build not supporting sub"
|
||||||
" found [%s]", wolfSSH_GetSessionCommand(ssh));
|
"system found [%s]",
|
||||||
|
wolfSSH_GetSessionCommand(ssh));
|
||||||
ret = WS_NOT_COMPILED;
|
ret = WS_NOT_COMPILED;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -679,10 +748,12 @@ static void* HandleConnection(void* arg)
|
||||||
case WOLFSSH_SESSION_TERMINAL:
|
case WOLFSSH_SESSION_TERMINAL:
|
||||||
default:
|
default:
|
||||||
wolfSSH_Log(WS_LOG_ERROR,
|
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;
|
ret = WS_NOT_COMPILED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Attempting to close down connection");
|
wolfSSH_Log(WS_LOG_INFO, "[SSHD] Attempting to close down connection");
|
||||||
wolfSSH_shutdown(ssh);
|
wolfSSH_shutdown(ssh);
|
||||||
|
|
Loading…
Reference in New Issue