diff --git a/.gitignore b/.gitignore index 8db4d74d..86575574 100644 --- a/.gitignore +++ b/.gitignore @@ -58,6 +58,7 @@ examples/scpclient/wolfscp # applications apps/wolfsshd/wolfsshd +apps/wolfsshd/test/test_configuration # test output tests/*.test diff --git a/apps/wolfsshd/configuration.c b/apps/wolfsshd/configuration.c index 31178a22..dc92b82c 100644 --- a/apps/wolfsshd/configuration.c +++ b/apps/wolfsshd/configuration.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -59,7 +60,7 @@ struct WOLFSSHD_CONFIG { char* authKeysFile; long loginTimer; word16 port; - byte usePrivilegeSeparation; + byte usePrivilegeSeparation:2; byte passwordAuth:1; byte pubKeyAuth:1; byte permitRootLogin:1; @@ -436,135 +437,204 @@ static int HandleInclude(WOLFSSHD_CONFIG *conf, const char *value) const char *prefix = NULL; int prefixLen = 0; int found = 0; + int ret = WS_SUCCESS; /* No value, nothing to do */ if (!value || value[0] == '\0') { - return WS_BAD_ARGUMENT; + ret = WS_BAD_ARGUMENT; } - /* Ignore trailing whitespace */ - ptr = value + WSTRLEN(value) - 1; - while (ptr != value) { - if (!WISSPACE(*ptr)) { - ptr--; - } - else { - break; - } - } - - /* Find wildcards */ - ptr2 = ptr; - while (ptr2 != value) { - if (*ptr2 == '*') { - /* Wildcard found */ - found = 1; - if (ptr != ptr2) { - postfix = ptr2 + 1; + if (ret == WS_SUCCESS) { + /* Ignore trailing whitespace */ + ptr = value + WSTRLEN(value) - 1; + while (ptr != value) { + if (WISSPACE(*ptr)) { + ptr--; + } + else { + break; } - break; } - if (*ptr2 == '/') { - /* Found slash before wildcard directory-wildcards not supported */ - break; - } - ptr2--; - } - ptr = ptr2; - /* Use wildcard */ - if (found) { -#ifdef __unix__ - int ret; - struct dirent *dir; - DIR *d; - char *path; - char *filepath = (char*)WMALLOC(PATH_MAX, NULL, 0); - - /* Back find the full path */ + /* Find wildcards */ + ptr2 = ptr; while (ptr2 != value) { + if (*ptr2 == '*') { + /* Wildcard found */ + found = 1; + if (ptr != ptr2) { + postfix = ptr2 + 1; + } + break; + } if (*ptr2 == '/') { + /* Found slash before wildcard directory-wildcards + * not supported */ break; } ptr2--; } + ptr = ptr2; - if (ptr2 != value) { - path = (char*)WMALLOC(ptr2 - value + 1, NULL, 0); - memcpy(path, value, ptr2 - value); - path[ptr2 - value] = '\0'; - prefix = ptr2 + 1; - prefixLen = (int)(ptr - ptr2 - 1); - } else { - path = (char*)WMALLOC(2, NULL, 0); - memcpy(path, ".", 1); - path[1] = '\0'; - prefix = value; - prefixLen = (int)(ptr - value); - } + /* Use wildcard */ + if (found) { +#if defined(__unix__) || defined(__unix) || \ + (defined(__APPLE__) && defined(__MACH__)) + struct dirent *dir; + WDIR d; + char *path = NULL; + char *filepath = (char*)WMALLOC(PATH_MAX, conf->heap, DYNTYPE_PATH); - d = opendir(path); - if (d) { - while ((dir = readdir(d)) != NULL) { - if (dir->d_type == DT_DIR) { - /* Skip sub-directories */ - continue; - } - else { - /* Check if filename prefix matches */ - if (prefixLen > 0) { - if ((int)WSTRLEN(dir->d_name) <= prefixLen) { - continue; - } - if (WSTRNCMP(dir->d_name, prefix, prefixLen) != 0) { - continue; - } + if (filepath == NULL) { + ret = WS_MEMORY_E; + } + + if (ret == WS_SUCCESS) { + /* Back find the full path */ + while (ptr2 != value) { + if (*ptr2 == '/') { + break; } - if (postfix) { - /* Skip if file is too short */ - if (WSTRLEN(dir->d_name) <= WSTRLEN(postfix)) { - continue; - } - if (WSTRNCMP(dir->d_name + WSTRLEN(dir->d_name) - - WSTRLEN(postfix), postfix, WSTRLEN(postfix)) - == 0) { - snprintf(filepath, PATH_MAX, "%s/%s", path, - dir->d_name); - } - else { - /* Not a match */ - continue; - } + ptr2--; + } + + if (ptr2 != value) { + path = (char*)WMALLOC(ptr2 - value + 1, + conf->heap, DYNTYPE_PATH); + if (path == NULL) { + ret = WS_MEMORY_E; } else { - snprintf(filepath, PATH_MAX, "%s/%s", path, - dir->d_name); + WMEMCPY(path, value, ptr2 - value); + path[ptr2 - value] = '\0'; + prefix = ptr2 + 1; + prefixLen = (int)(ptr - ptr2 - 1); } - ret = wolfSSHD_ConfigLoad(conf, filepath); - if (ret != WS_SUCCESS) { - return ret; + } + else { + path = (char*)WMALLOC(2, conf->heap, DYNTYPE_PATH); + if (path == NULL) { + ret = WS_MEMORY_E; + } + else { + WMEMCPY(path, ".", 1); + path[1] = '\0'; + prefix = value; + prefixLen = (int)(ptr - value); } } } + + if (ret == WS_SUCCESS) { + if (!WOPENDIR(NULL, conf->heap, &d, path)) { + word32 fileCount = 0, i, j; + char** fileNames = NULL; + + /* Count up the number of files */ + while ((dir = WREADDIR(&d)) != NULL) { + /* Skip sub-directories */ + if (dir->d_type != DT_DIR) { + fileCount++; + } + } + WREWINDDIR(&d); + + if (fileCount > 0) { + fileNames = (char**)WMALLOC(fileCount * sizeof(char*), + conf->heap, DYNTYPE_PATH); + if (fileNames == NULL) { + ret = WS_MEMORY_E; + } + } + + if (ret == WS_SUCCESS) { + i = 0; + while (i < fileCount && (dir = WREADDIR(&d)) != NULL) { + /* Skip sub-directories */ + if (dir->d_type != DT_DIR) { + /* Insert in string order */ + for (j = 0; j < i; j++) { + if (WSTRCMP(dir->d_name, fileNames[j]) + < 0) { + WMEMMOVE(fileNames+j+1, fileNames+j, + (i - j)*sizeof(char*)); + break; + } + } + fileNames[j] = dir->d_name; + i++; + } + } + + for (i = 0; i < fileCount; i++) { + /* Check if filename prefix matches */ + if (prefixLen > 0) { + if ((int)WSTRLEN(fileNames[i]) <= prefixLen) { + continue; + } + if (WSTRNCMP(fileNames[i], prefix, prefixLen) + != 0) { + continue; + } + } + if (postfix) { + /* Skip if file is too short */ + if (WSTRLEN(fileNames[i]) <= WSTRLEN(postfix)) { + continue; + } + if (WSTRNCMP(fileNames[i] + + WSTRLEN(fileNames[i]) - + WSTRLEN(postfix), + postfix, WSTRLEN(postfix)) + == 0) { + WSNPRINTF(filepath, PATH_MAX, "%s/%s", path, + fileNames[i]); + } + else { + /* Not a match */ + continue; + } + } + else { + WSNPRINTF(filepath, PATH_MAX, "%s/%s", path, + fileNames[i]); + } + ret = wolfSSHD_ConfigLoad(conf, filepath); + if (ret != WS_SUCCESS) { + break; + } + } + + if (fileNames != NULL) { + WFREE(fileNames, conf->heap, DYNTYPE_PATH); + } + } + WCLOSEDIR(&d); + } + else { + /* Bad directory */ + ret = WS_INVALID_PATH_E; + } + } + if (path != NULL) { + WFREE(path, conf->heap, DYNTYPE_PATH); + } + if (filepath != NULL) { + WFREE(filepath, conf->heap, DYNTYPE_PATH); + } +#else + (void)postfix; + (void)prefixLen; + (void)prefix; + /* Don't support wildcards here */ + ret = WS_BAD_ARGUMENT; +#endif } else { - /* Bad directory */ - WFREE(filepath, NULL, 0); - return WS_BAD_ARGUMENT; + ret = wolfSSHD_ConfigLoad(conf, value); } - WFREE(filepath, NULL, 0); -#else - (void)postfix; - (void)prefixLen; - (void)prefix; - /* Don't support wildcards here */ - return WS_BAD_ARGUMENT; -#endif } - else { - return wolfSSHD_ConfigLoad(conf, value); - } - return WS_SUCCESS; + return ret; } /* returns WS_SUCCESS on success */ @@ -726,7 +796,7 @@ int wolfSSHD_ConfigLoad(WOLFSSHD_CONFIG* conf, const char* filename) f = XFOPEN(filename, "rb"); if (f == XBADFILE) { - wolfSSH_Log(WS_LOG_ERROR, "Unable to open SSHD config file %s\n", + wolfSSH_Log(WS_LOG_ERROR, "Unable to open SSHD config file %s", filename); return BAD_FUNC_ARG; } diff --git a/apps/wolfsshd/include.am b/apps/wolfsshd/include.am index cc20dee1..9342a24e 100644 --- a/apps/wolfsshd/include.am +++ b/apps/wolfsshd/include.am @@ -15,7 +15,7 @@ apps_wolfsshd_test_test_configuration_SOURCES = apps/wolfsshd/test/test_configur apps/wolfsshd/auth.c apps_wolfsshd_test_test_configuration_LDADD = src/libwolfssh.la apps_wolfsshd_test_test_configuration_DEPENDENCIES = src/libwolfssh.la -apps_wolfsshd_test_test_configuration_CPPFLAGS = -DWOLFSSH_SSHD -DWOLFSSHD_UNIT_TEST -Iapps/wolfsshd/ +apps_wolfsshd_test_test_configuration_CPPFLAGS = $(AM_CPPFLAGS) -DWOLFSSH_SSHD -DWOLFSSHD_UNIT_TEST -Iapps/wolfsshd/ DISTCLEANFILES+= apps/wolfsshd/.libs/wolfsshd \ apps/wolfsshd/test/.libs/test_configuration diff --git a/apps/wolfsshd/test/test_configuration.c b/apps/wolfsshd/test/test_configuration.c index 4b1fe5b7..df31cbf7 100644 --- a/apps/wolfsshd/test/test_configuration.c +++ b/apps/wolfsshd/test/test_configuration.c @@ -26,6 +26,77 @@ void Log(const char *const fmt, ...) va_end(vlist); } +static void CleanupWildcardTest(void) +{ + WDIR dir; + struct dirent* d; + char filepath[MAX_PATH*2]; /* d_name is max_path long */ + + if (!WOPENDIR(NULL, NULL, &dir, "./sshd_config.d/")) { + while ((d = WREADDIR(&dir)) != NULL) { + if (d->d_type != DT_DIR) { + WSNPRINTF(filepath, sizeof filepath, "%s%s", + "./sshd_config.d/", d->d_name); + WREMOVE(0, filepath); + } + } + WCLOSEDIR(&dir); + WRMDIR(0, "./sshd_config.d/"); + } +} + +static int SetupWildcardTest(void) +{ + WFILE* f; + const byte fileIds[] = { 0, 1, 50, 59, 99 }; + word32 fileIdsSz = (word32)(sizeof(fileIds) / sizeof(byte)); + word32 i; + int ret; + char filepath[MAX_PATH]; + + ret = WMKDIR(0, "./sshd_config.d/", 0755); + + if (ret == 0) { + for (i = 0; i < fileIdsSz; i++) { + if (fileIds[i] != 0) { + WSNPRINTF(filepath, sizeof filepath, "%s%02u-test.conf", + "./sshd_config.d/", fileIds[i]); + } + else { + WSNPRINTF(filepath, sizeof filepath, "%stest.bad", + "./sshd_config.d/"); + } + + WFOPEN(&f, filepath, "w"); + if (f) { + word32 sz, wr; + char contents[20]; + WSNPRINTF(contents, sizeof contents, "LoginGraceTime %02u", + fileIds[i]); + sz = (word32)WSTRLEN(contents); + wr = (word32)WFWRITE(contents, sizeof(char), sz, f); + WFCLOSE(f); + if (sz != wr) { + Log("Couldn't write the contents of file %s\n", filepath); + ret = WS_FATAL_ERROR; + break; + } + } + else { + Log("Couldn't create the file %s\n", filepath); + ret = WS_FATAL_ERROR; + break; + } + } + } + else { + Log("Couldn't make the test config directory\n"); + ret = WS_FATAL_ERROR; + } + + return ret; +} + typedef int (*TEST_FUNC)(void); typedef struct { const char *name; @@ -110,6 +181,13 @@ static int test_ParseConfigLine(void) {"Password auth no", "PasswordAuthentication no", 0}, {"Password auth yes", "PasswordAuthentication yes", 0}, {"Password auth invalid", "PasswordAuthentication wolfsshd", 1}, + + /* Include files tests. */ + {"Include file bad", "Include sshd_config.d/test.bad", 1}, + {"Include file exists", "Include sshd_config.d/01-test.conf", 0}, + {"Include file DNE", "Include sshd_config.d/test-dne.conf", 1}, + {"Include wildcard exists", "Include sshd_config.d/*.conf", 0}, + {"Include wildcard NDE", "Include sshd_config.d/*.dne", 0}, }; const int numVectors = (int)(sizeof(vectors) / sizeof(*vectors)); @@ -136,6 +214,7 @@ static int test_ParseConfigLine(void) break; } } + wolfSSHD_ConfigFree(conf); } return ret; @@ -153,12 +232,19 @@ int main(int argc, char** argv) (void)argc; (void)argv; - for (i = 0; i < TEST_CASE_CNT; ++i) { - ret = RunTest(&testCases[i]); - if (ret != WS_SUCCESS) { - break; + CleanupWildcardTest(); + ret = SetupWildcardTest(); + + if (ret == 0) { + for (i = 0; i < TEST_CASE_CNT; ++i) { + ret = RunTest(&testCases[i]); + if (ret != WS_SUCCESS) { + break; + } } } + CleanupWildcardTest(); + return ret; } diff --git a/examples/portfwd/portfwd.c b/examples/portfwd/portfwd.c index 93ee600c..c68fbb91 100644 --- a/examples/portfwd/portfwd.c +++ b/examples/portfwd/portfwd.c @@ -267,6 +267,8 @@ THREAD_RETURN WOLFSSH_THREAD portfwd_worker(void* args) break; case 'f': + if (myoptarg == NULL) + err_sys("null argument found"); fwdFromPort = (word16)atoi(myoptarg); break; @@ -281,6 +283,8 @@ THREAD_RETURN WOLFSSH_THREAD portfwd_worker(void* args) break; case 't': + if (myoptarg == NULL) + err_sys("null argument found"); fwdToPort = (word16)atoi(myoptarg); break; diff --git a/wolfssh/port.h b/wolfssh/port.h index 5652d77b..acda08ba 100644 --- a/wolfssh/port.h +++ b/wolfssh/port.h @@ -342,7 +342,8 @@ extern "C" { #define WCHMOD(fs,f,m) _chmod((f),(m)) #endif - #if (defined(WOLFSSH_SCP) || defined(WOLFSSH_SFTP)) && \ + #if (defined(WOLFSSH_SCP) || \ + defined(WOLFSSH_SFTP) || defined(WOLFSSH_SSHD)) && \ !defined(WOLFSSH_SCP_USER_CALLBACKS) #ifdef USE_WINDOWS_API @@ -476,8 +477,9 @@ extern "C" { #define WLOCALTIME(c,r) (localtime_r((c),(r))!=NULL) #endif -#if (defined(WOLFSSH_SFTP) || defined(WOLFSSH_SCP)) && \ - !defined(NO_WOLFSSH_SERVER) && !defined(NO_FILESYSTEM) +#if (defined(WOLFSSH_SFTP) || \ + defined(WOLFSSH_SCP) || defined(WOLFSSH_SSHD)) && \ + !defined(NO_WOLFSSH_SERVER) && !defined(NO_FILESYSTEM) #ifndef SIZEOF_OFF_T /* if not using autoconf then make a guess on off_t size based on sizeof @@ -1219,8 +1221,9 @@ extern "C" { /* returns 0 on success */ #define WOPENDIR(fs,h,c,d) ((*(c) = opendir((d))) == NULL) - #define WCLOSEDIR(d) closedir(*(d)) - #define WREADDIR(d) readdir(*(d)) + #define WCLOSEDIR(d) closedir(*(d)) + #define WREADDIR(d) readdir(*(d)) + #define WREWINDDIR(d) rewinddir(*(d)) #endif /* NO_WOLFSSH_DIR */ #endif #endif /* WOLFSSH_SFTP or WOLFSSH_SCP */