static int websTidyUrl(webs_t wp) { char_t *parts[64]; /* Array of ptr's to URL parts */ char_t *token, *url, *tidyurl; int i, len, npart; a_assert(websValid(wp)); /* * Copy the string so we don't destroy the original (yet) */ url = bstrdup(B_L, wp->url); websDecodeUrl(url, url, gstrlen(url)); len = npart = 0; parts[0] = NULL; token = gstrtok(url, T("/")); /* * Look at each directory segment and process "." and ".." segments * Don't allow the browser to pop outside the root web. */ while (token != NULL) { if (gstrcmp(token, T("..")) == 0) { if (npart > 0) { npart--; } } else if (gstrcmp(token, T(".")) != 0) { parts[npart] = token; len += gstrlen(token) + 1; npart++; } token = gstrtok(NULL, T("/")); } /* * Re-construct URL. Need extra space all "/" and null. */ if (npart || (gstrcmp(url, T("/")) == 0) || (url[0] == '\0')) { tidyurl = balloc(B_L, (len + 2) * sizeof(char_t)); *tidyurl = '\0'; for (i = 0; i < npart; i++) { gstrcat(tidyurl, T("/")); gstrcat(tidyurl, parts[i]); } bfree(B_L, url); bfree(B_L, wp->url); wp->url = tidyurl; return 0; } else { bfree(B_L, url); return -1; } }
int sent_xmsg_stats(User *usr, XMsg *x, char *name) { switch(x->type) { case XMSG_X: usr->xsent++; user_dirty(usr, "xsent"); update_stats(usr); inc_stats(STATS_XSENT); break; case XMSG_EMOTE: usr->esent++; user_dirty(usr, "esent"); update_stats(usr); inc_stats(STATS_ESENT); break; case XMSG_FEELING: usr->fsent++; user_dirty(usr, "fsent"); update_stats(usr); inc_stats(STATS_FSENT); break; case XMSG_QUESTION: usr->qsent++; user_dirty(usr, "qsent"); update_stats(usr); inc_stats(STATS_QSENT); break; case XMSG_ANSWER: usr->qansw++; user_dirty(usr, "qansw"); update_stats(usr); inc_stats(STATS_QANSW); break; default: ; } if (name != NULL) { /* add to talked_to list */ if (usr->talked_to.len <= 0) gstrcpy(&(usr->talked_to), name); else { if (!cstrfind(usr->talked_to.str, name, ',')) { gstrcat(&(usr->talked_to), ","); gstrcat(&(usr->talked_to), name); } } } return 0; }
int write_IOBuf(IOBuf *ob, void *data, int len) { int n; if (ob->redirect != NULL) { /* NB. output redirection may not work correctly when data contains a 0-byte In practice, this never happens because it works with strings and strlen() all the way */ return gstrcat(ob->redirect, (char *)data); } if (len <= 0) return 0; if (len > OUTPUTBUF_SIZE) { /* too much data to hold in IOBuf structure */ if (flush_IOBuf(ob) == -1) return -1; /* too much data, simply write it out directly without buffering in between */ while(len > 0) { n = write(ob->fd, data, len); if (n == -1) { if (errno == EINTR) continue; /* the write() would block; we can wait for it */ if (errno == EAGAIN || errno == EWOULDBLOCK) { if (wait_fd_write(ob->fd, NULL) == -1) { ob->out_idx = -1; return -1; } continue; /* retry write() */ } return -1; /* some kind of error, probably EBADF ? */ } len -= n; } return 0; } if (ob->out_idx + len > OUTPUTBUF_SIZE) { if (flush_IOBuf(ob) == -1) return -1; } memcpy(ob->outbuf + ob->out_idx, data, len); /* buffer data */ ob->out_idx += len; return 0; }
int websValidateUrl(webs_t wp, char_t *path) { char_t *parts[64]; /* Array of ptr's to URL parts */ char_t *token, *dir, *lpath; int i, len, npart; a_assert(websValid(wp)); a_assert(path); dir = websGetRequestDir(wp); if (dir == NULL || *dir == '\0') { return -1; } /* * Copy the string so we don't destroy the original */ path = bstrdup(B_L, path); websDecodeUrl(path, path, gstrlen(path)); len = npart = 0; parts[0] = NULL; /* * 22 Jul 02 -- there were reports that a directory traversal exploit was * possible in the WebServer running under Windows if directory paths * outside the server's specified root web were given by URL-encoding the * backslash character, like: * * GoAhead is vulnerable to a directory traversal bug. A request such as * * GoAhead-server/../../../../../../../ results in an error message * 'Cannot open URL'. * However, by encoding the '/' character, it is possible to break out of * the * web root and read arbitrary files from the server. * Hence a request like: * * GoAhead-server/..%5C..%5C..%5C..%5C..%5C..%5C/winnt/win.ini returns the * contents of the win.ini file. * (Note that the description uses forward slashes (0x2F), but the example * uses backslashes (0x5C). In my tests, forward slashes are correctly * trapped, but backslashes are not. The code below substitutes forward * slashes for backslashes before attempting to validate that there are no * unauthorized paths being accessed. */ token = gstrchr(path, '\\'); while (token != NULL) { *token = '/'; token = gstrchr(token, '\\'); } token = gstrtok(path, T("/")); /* * Look at each directory segment and process "." and ".." segments * Don't allow the browser to pop outside the root web. */ while (token != NULL) { if (gstrcmp(token, T("..")) == 0) { if (npart > 0) { npart--; } } else if (gstrcmp(token, T(".")) != 0) { parts[npart] = token; len += gstrlen(token) + 1; npart++; } token = gstrtok(NULL, T("/")); } /* * Create local path for document. Need extra space all "/" and null. */ if (npart || (gstrcmp(path, T("/")) == 0) || (path[0] == '\0')) { lpath = balloc(B_L, (gstrlen(dir) + 1 + len + 1) * sizeof(char_t)); gstrcpy(lpath, dir); for (i = 0; i < npart; i++) { gstrcat(lpath, T("/")); gstrcat(lpath, parts[i]); } websSetRequestLpath(wp, lpath); bfree(B_L, path); bfree(B_L, lpath); } else { bfree(B_L, path); return -1; } return 0; }
int websValidateUrl(webs_t wp, char_t *path) { /* Thanks to Dhanwa T ([email protected]) for this fix -- previously, if an URL was requested having more than (the hardcoded) 64 parts, the webServer would experience a hard crash as it attempted to write past the end of the array 'parts'. Also fixes: http://www.securiteam.com/securitynews/5MP0C1580W.html */ char_t *parts[MAX_URL_DEPTH]; /* Array of ptr's to URL parts */ char_t *token, *dir, *lpath; int i, len, npart; a_assert(websValid(wp)); a_assert(path); dir = websGetRequestDir(wp); if (dir == NULL || *dir == '\0') { return -1; } /* * Copy the string so we don't destroy the original */ path = bstrdup(B_L, path); websDecodeUrl(path, path, gstrlen(path)); len = npart = 0; parts[0] = NULL; /* * Fixed by Matt Moore, 22 Jul 02 * http://www.securiteam.com/securitynews/5RP0I007PG.html * http://www.securiteam.com/securitynews/5QP010U3FS.html * * There were reports that a directory traversal exploit was * possible in the WebServer running under Windows if directory paths * outside the server's specified root web were given by URL-encoding the * backslash character, like: * * GoAhead is vulnerable to a directory traversal bug. A request such as * * GoAhead-server/../../../../../../../ results in an error message * 'Cannot open URL'. * However, by encoding the '/' character, it is possible to break out of * the web root and read arbitrary files from the server. * Hence a request like: * * GoAhead-server/..%5C..%5C..%5C..%5C..%5C..%5C/winnt/win.ini returns the * contents of the win.ini file. * (Note that the description uses forward slashes (0x2F), but the example * uses backslashes (0x5C). In my tests, forward slashes are correctly * trapped, but backslashes are not. The code below substitutes forward * slashes for backslashes before attempting to validate that there are no * unauthorized paths being accessed. */ token = gstrchr(path, '\\'); while (token != NULL) { *token = '/'; token = gstrchr(token, '\\'); } token = gstrtok(path, T("/")); /* * Look at each directory segment and process "." and ".." segments * Don't allow the browser to pop outside the root web. */ while (token != NULL) { if (npart >= MAX_URL_DEPTH) { /* * malformed URL -- too many parts for us to process. */ bfree(B_L, path); return -1; } if (gstrcmp(token, T("..")) == 0) { if (npart > 0) { npart--; } } else if (gstrcmp(token, T(".")) != 0) { parts[npart] = token; len += gstrlen(token) + 1; npart++; } token = gstrtok(NULL, T("/")); } #ifdef WIN32 if (isBadWindowsPath(parts, npart)) { bfree(B_L, path); return -1; } #endif /* * Create local path for document. Need extra space all "/" and null. */ if (npart || (gstrcmp(path, T("/")) == 0) || (path[0] == '\0')) { lpath = balloc(B_L, (gstrlen(dir) + 1 + len + 1) * sizeof(char_t)); gstrcpy(lpath, dir); for (i = 0; i < npart; i++) { gstrcat(lpath, T("/")); gstrcat(lpath, parts[i]); } websSetRequestLpath(wp, lpath); bfree(B_L, path); bfree(B_L, lpath); } else { bfree(B_L, path); return -1; } return 0; }
int websLaunchCgiProc( char_t* cgiPath, char_t** argp, char_t** envp, char_t* stdIn, char_t* stdOut ) { STARTUPINFO newinfo; SECURITY_ATTRIBUTES security; PROCESS_INFORMATION procinfo; /* Information about created proc */ DWORD dwCreateFlags; char_t* cmdLine; char_t** pArgs; BOOL bReturn; int i, nLen; unsigned char* pEnvData; /* * Replace directory delimiters with Windows-friendly delimiters */ nLen = gstrlen( cgiPath ); for ( i = 0; i < nLen; i++ ) { if ( cgiPath[i] == '/' ) { cgiPath[i] = '\\'; } } /* * Calculate length of command line */ nLen = 0; pArgs = argp; while ( pArgs && *pArgs &&** pArgs ) { nLen += gstrlen( *pArgs ) + 1; pArgs++; } /* * Construct command line */ cmdLine = balloc( B_L, sizeof( char_t ) * nLen ); a_assert( cmdLine ); gstrcpy( cmdLine, "" ); pArgs = argp; while ( pArgs && *pArgs &&** pArgs ) { gstrcat( cmdLine, *pArgs ); gstrcat( cmdLine, T( " " ) ); pArgs++; } /* * Create the process start-up information */ memset( &newinfo, 0, sizeof( newinfo ) ); newinfo.cb = sizeof( newinfo ); newinfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; newinfo.wShowWindow = SW_HIDE; newinfo.lpTitle = NULL; /* * Create file handles for the spawned processes stdin and stdout files */ security.nLength = sizeof( SECURITY_ATTRIBUTES ); security.lpSecurityDescriptor = NULL; security.bInheritHandle = TRUE; /* * Stdin file should already exist. */ newinfo.hStdInput = CreateFile( stdIn, GENERIC_READ, FILE_SHARE_READ, &security, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); /* * Stdout file is created and file pointer is reset to start. */ newinfo.hStdOutput = CreateFile( stdOut, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ + FILE_SHARE_WRITE, &security, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ); SetFilePointer( newinfo.hStdOutput, 0, NULL, FILE_END ); /* * Stderr file is set to Stdout. */ newinfo.hStdError = newinfo.hStdOutput; dwCreateFlags = CREATE_NEW_CONSOLE; pEnvData = tableToBlock( envp ); /* * CreateProcess returns errors sometimes, even when the process was * started correctly. The cause is not evident. For now: we detect * an error by checking the value of procinfo.hProcess after the call. */ procinfo.hProcess = NULL; bReturn = CreateProcess( NULL, /* Name of executable module */ cmdLine, /* Command line string */ NULL, /* Process security attributes */ NULL, /* Thread security attributes */ TRUE, /* Handle inheritance flag */ dwCreateFlags, /* Creation flags */ pEnvData, /* New environment block */ NULL, /* Current directory name */ &newinfo, /* STARTUPINFO */ &procinfo ); /* PROCESS_INFORMATION */ if ( procinfo.hThread != NULL ) { CloseHandle( procinfo.hThread ); } if ( newinfo.hStdInput ) { CloseHandle( newinfo.hStdInput ); } if ( newinfo.hStdOutput ) { CloseHandle( newinfo.hStdOutput ); } bfree( B_L, pEnvData ); bfree( B_L, cmdLine ); if ( bReturn == 0 ) { return -1; } else { return ( int ) procinfo.hProcess; } }