diff --git a/Common/cm_string.h b/Common/cm_string.h index 945ba74..0132139 100644 --- a/Common/cm_string.h +++ b/Common/cm_string.h @@ -6,6 +6,8 @@ #include int cm_hex(const char* str, int len); +bool cm_nocase_endswith(const char* str, const char* end); +bool cm_endswith(const char* str, const char* end); char* cm_html_escape(const char* str); char* cm_url_escape(const char* str); char* cm_strcat(const char* a, const char* b); diff --git a/Common/string.c b/Common/string.c index 6b7af53..ebb7805 100644 --- a/Common/string.c +++ b/Common/string.c @@ -7,6 +7,8 @@ #include char* cm_strcat(const char* a, const char* b) { + if(a == NULL) a = ""; + if(b == NULL) b = ""; char* str = malloc(strlen(a) + strlen(b) + 1); memcpy(str, a, strlen(a)); memcpy(str + strlen(a), b, strlen(b)); @@ -23,6 +25,24 @@ char* cm_strcat3(const char* a, const char* b, const char* c) { char* cm_strdup(const char* str) { return cm_strcat(str, ""); } +bool cm_endswith(const char* str, const char* end) { + if(strlen(str) < strlen(end)) return false; + int i; + for(i = strlen(str) - strlen(end); i < strlen(str); i++) { + if(str[i] != end[i - strlen(str) + strlen(end)]) return false; + } + return true; +} + +bool cm_nocase_endswith(const char* str, const char* end) { + if(strlen(str) < strlen(end)) return false; + int i; + for(i = strlen(str) - strlen(end); i < strlen(str); i++) { + if(tolower(str[i]) != tolower(end[i - strlen(str) + strlen(end)])) return false; + } + return true; +} + char* cm_trimstart(const char* str) { int i; for(i = 0; str[i] != 0; i++) { diff --git a/Server/http.c b/Server/http.c index fbbbf8d..5b7fc8d 100644 --- a/Server/http.c +++ b/Server/http.c @@ -82,7 +82,7 @@ int tw_http_parse(SSL* ssl, int sock, struct tw_http_request* req) { } #endif int len = tw_read(ssl, sock, buffer, 512); - if(len <= 0){ + if(len <= 0) { bad = true; break; } @@ -284,11 +284,13 @@ getout: if(req->path[i] == '%') { if(req->path[i + 1] == 0) continue; cbuf[0] = cm_hex(req->path + i + 1, 2); - char* tmp = result; - result = cm_strcat(tmp, cbuf); - free(tmp); + if(cbuf[0] != '\\') { + char* tmp = result; + result = cm_strcat(tmp, cbuf); + free(tmp); + } i += 2; - } else { + } else if(req->path[i] != '\\') { cbuf[0] = req->path[i]; char* tmp = result; result = cm_strcat(tmp, cbuf); @@ -324,7 +326,7 @@ getout: p = cm_strdup("/"); } } else if(strcmp(pth, ".") == 0) { - } else if(oldc != '\\') { + } else { char* tmp = p; p = cm_strcat3(tmp, pth, cbuf); free(tmp); diff --git a/Server/main.c b/Server/main.c index 6105f9c..3f36e09 100644 --- a/Server/main.c +++ b/Server/main.c @@ -36,17 +36,17 @@ int startup(int argc, char** argv); SERVICE_STATUS status; SERVICE_STATUS_HANDLE status_handle; -void WINAPI servhandler(DWORD control){ - switch(control){ - case SERVICE_CONTROL_STOP: - case SERVICE_CONTROL_SHUTDOWN: - status.dwCurrentState = SERVICE_STOP_PENDING; - break; +void WINAPI servhandler(DWORD control) { + switch(control) { + case SERVICE_CONTROL_STOP: + case SERVICE_CONTROL_SHUTDOWN: + status.dwCurrentState = SERVICE_STOP_PENDING; + break; } SetServiceStatus(status_handle, &status); } -void WINAPI servmain(DWORD argc, LPSTR* argv){ +void WINAPI servmain(DWORD argc, LPSTR* argv) { logfile = fopen(PREFIX "/logs/tewi.log", "a"); if(logfile == NULL) logfile = stderr; status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; @@ -60,7 +60,7 @@ void WINAPI servmain(DWORD argc, LPSTR* argv){ if(status_handle == NULL) return; if(SetServiceStatus(status_handle, &status) == 0) return; int st = startup(argc, argv); - if(st != -1){ + if(st != -1) { status.dwWin32ExitCode = NO_ERROR; status.dwServiceSpecificExitCode = st; status.dwCurrentState = SERVICE_STOPPED; @@ -87,20 +87,20 @@ int main(int argc, char** argv) { #endif } -int startup(int argc, char** argv){ +int startup(int argc, char** argv) { int i; const char* confpath = PREFIX "/etc/tewi.conf"; - if(argv != NULL){ + if(argv != NULL) { for(i = 1; i < argc; i++) { if(argv[i][0] == '-') { if(strcmp(argv[i], "--verbose") == 0 || strcmp(argv[i], "-v") == 0) { if(!cm_do_log) { cm_do_log = true; - #ifndef NO_SSL +#ifndef NO_SSL cm_log("", "This is Tewi HTTPd, version %s, using %s", tw_get_version(), OPENSSL_VERSION_TEXT); - #else +#else cm_log("", "This is Tewi HTTPd, version %s", tw_get_version()); - #endif +#endif } else { cm_do_log = true; } diff --git a/Server/server.c b/Server/server.c index 4618e65..1c78386 100644 --- a/Server/server.c +++ b/Server/server.c @@ -51,6 +51,10 @@ int sockcount = 0; SOCKADDR addresses[MAX_PORTS]; int sockets[MAX_PORTS]; +#ifdef __MINGW32__ +const char* reserved_names[] = {"CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}; +#endif + /* https://qiita.com/gyu-don/items/5a640c6d2252a860c8cd */ int tw_wildcard_match(const char* wildcard, const char* target) { const char *pw = wildcard, *pt = target; @@ -428,7 +432,7 @@ void tw_server_pass(int sock, bool ssl, int port, SOCKADDR addr) { char* vhost = cm_strdup(config.hostname); int i; time_t cmtime = 0; - if(req.headers != NULL){ + if(req.headers != NULL) { for(i = 0; req.headers[i] != NULL; i += 2) { if(cm_strcaseequ(req.headers[i], "Host")) { free(vhost); @@ -479,8 +483,31 @@ void tw_server_pass(int sock, bool ssl, int port, SOCKADDR addr) { cm_log("Server", "Document root is %s", vhost_entry->root == NULL ? "not set" : vhost_entry->root); char* path = cm_strcat(vhost_entry->root == NULL ? "" : vhost_entry->root, req.path); cm_log("Server", "Filesystem path is %s", path); + bool rej = false; +#ifdef __MINGW32__ + for(i = 0; i < sizeof(reserved_names) / sizeof(reserved_names[0]); i++) { + char* n = cm_strcat("/", reserved_names[i]); + if(cm_nocase_endswith(path, n)) { + tw_http_error(s, sock, 403, name, port); + free(n); + rej = true; + cm_log("Server", "XP Patch ; rejecting access to device"); + break; + } + free(n); + char* y = cm_strcat3("/", reserved_names[i], ":"); + if(cm_nocase_endswith(path, y)) { + tw_http_error(s, sock, 403, name, port); + free(y); + rej = true; + cm_log("Server", "XP Patch ; rejecting access to device"); + break; + } + free(y); + } +#endif struct stat st; - if(stat(path, &st) == 0) { + if(!rej && stat(path, &st) == 0) { if(!tw_permission_allowed(path, addr, req, vhost_entry)) { tw_http_error(s, sock, 403, name, port); } else if(S_ISDIR(st.st_mode)) { @@ -647,6 +674,7 @@ void tw_server_pass(int sock, bool ssl, int port, SOCKADDR addr) { fread(rmbuf, s.st_size, 1, fr); addstring(&str, "
%h
\n", rmbuf); fclose(fr); + free(rmbuf); } free(fpth); } @@ -681,11 +709,11 @@ void tw_server_pass(int sock, bool ssl, int port, SOCKADDR addr) { } free(vhost); free(host); - tw_free_request(&req); } else if(ret == -1) { } else { tw_http_error(s, sock, 400, name, port); } + tw_free_request(&req); cleanup: #ifndef NO_SSL if(sslworks) { @@ -717,7 +745,7 @@ void tw_server_loop(void) { int i; #ifdef __MINGW32__ struct thread_entry threads[2048]; - for(i = 0; i < sizeof(threads) / sizeof(threads[0]); i++){ + for(i = 0; i < sizeof(threads) / sizeof(threads[0]); i++) { threads[i].used = false; } #endif @@ -731,13 +759,13 @@ void tw_server_loop(void) { int ret = select(FD_SETSIZE, &fdset, NULL, NULL, &tv); if(ret == -1) { break; - }else if(ret == 0){ + } else if(ret == 0) { #ifdef __MINGW32__ - for(i = 0; i < sizeof(threads) / sizeof(threads[0]); i++){ - if(threads[i].used){ + for(i = 0; i < sizeof(threads) / sizeof(threads[0]); i++) { + if(threads[i].used) { DWORD ex; GetExitCodeThread(threads[i].handle, &ex); - if(ex != STILL_ACTIVE){ + if(ex != STILL_ACTIVE) { CloseHandle(threads[i].handle); threads[i].used = false; } @@ -745,7 +773,7 @@ void tw_server_loop(void) { } #endif #ifdef SERVICE - if(status.dwCurrentState == SERVICE_STOP_PENDING){ + if(status.dwCurrentState == SERVICE_STOP_PENDING) { break; } #endif @@ -765,18 +793,18 @@ void tw_server_loop(void) { e->port = config.ports[i]; e->addr = claddr; int j; - for(j = 0; j < sizeof(threads) / sizeof(threads[0]); j++){ - if(threads[j].used){ + for(j = 0; j < sizeof(threads) / sizeof(threads[0]); j++) { + if(threads[j].used) { DWORD ex; GetExitCodeThread(threads[j].handle, &ex); - if(ex != STILL_ACTIVE){ + if(ex != STILL_ACTIVE) { CloseHandle(threads[j].handle); threads[j].used = false; } } } - for(j = 0; j < sizeof(threads) / sizeof(threads[0]); j++){ - if(!threads[j].used){ + for(j = 0; j < sizeof(threads) / sizeof(threads[0]); j++) { + if(!threads[j].used) { threads[j].handle = (HANDLE)_beginthreadex(NULL, 0, tw_server_pass, e, 0, NULL); threads[j].used = true; break; diff --git a/Server/tw_version.h b/Server/tw_version.h index 568ed38..24beee1 100644 --- a/Server/tw_version.h +++ b/Server/tw_version.h @@ -3,7 +3,7 @@ #ifndef __TW_VERSION_H__ #define __TW_VERSION_H__ -#define TW_VERSION "1.00\0" +#define TW_VERSION "1.01\0" const char* tw_get_version(void); const char* tw_get_platform(void);