diff options
Diffstat (limited to 'c/src/libnetworking/rtems_webserver/webs.c')
-rw-r--r-- | c/src/libnetworking/rtems_webserver/webs.c | 205 |
1 files changed, 164 insertions, 41 deletions
diff --git a/c/src/libnetworking/rtems_webserver/webs.c b/c/src/libnetworking/rtems_webserver/webs.c index 3181c602ec..ae6730dfb2 100644 --- a/c/src/libnetworking/rtems_webserver/webs.c +++ b/c/src/libnetworking/rtems_webserver/webs.c @@ -19,7 +19,7 @@ #include "wsIntrn.h" #ifdef DIGEST_ACCESS_SUPPORT -#include "websda.h" + #include "websda.h" #endif /******************************** Global Data *********************************/ @@ -44,7 +44,7 @@ websErrorType websErrors[] = { { 204, T("No Content") }, { 301, T("Redirect") }, { 302, T("Redirect") }, - { 304, T("User local copy") }, + { 304, T("Use local copy") }, { 400, T("Page not found") }, { 401, T("Unauthorized") }, { 403, T("Forbidden") }, @@ -56,7 +56,7 @@ websErrorType websErrors[] = { { 0, NULL } }; -#if WEBS_LOG_SUPPORT +#ifdef WEBS_LOG_SUPPORT static char_t websLogname[64] = T("log.txt"); /* Log filename */ static int websLogFd; /* Log file handle */ #endif @@ -69,17 +69,17 @@ static int websOpenCount = 0; /* count of apps using this module */ /**************************** Forward Declarations ****************************/ -static char_t *websErrorMsg(int code); +/*static char_t *websErrorMsg(int code);*/ static int websGetInput(webs_t wp, char_t **ptext, int *nbytes); static int websParseFirst(webs_t wp, char_t *text); static void websParseRequest(webs_t wp); static void websSocketEvent(int sid, int mask, int data); static int websGetTimeSinceMark(webs_t wp); -#if WEBS_LOG_SUPPORT +#ifdef WEBS_LOG_SUPPORT static void websLog(webs_t wp, int code); #endif -#if WEBS_IF_MODIFIED_SUPPORT +#ifdef WEBS_IF_MODIFIED_SUPPORT static time_t dateParse(time_t tip, char_t *cmd); #endif @@ -99,7 +99,7 @@ int websOpenServer(int port, int retries) a_assert(port > 0); a_assert(retries >= 0); -#if WEBS_PAGE_ROM +#ifdef WEBS_PAGE_ROM websRomOpen(); #endif @@ -123,7 +123,7 @@ int websOpenServer(int port, int retries) } websFormOpen(); -#if WEBS_LOG_SUPPORT +#ifdef WEBS_LOG_SUPPORT /* * Optional request log support */ @@ -165,14 +165,14 @@ void websCloseServer() websFree(wp); } -#if WEBS_LOG_SUPPORT +#ifdef WEBS_LOG_SUPPORT if (websLogFd >= 0) { close(websLogFd); websLogFd = -1; } #endif -#if WEBS_PAGE_ROM +#ifdef WEBS_PAGE_ROM websRomClose(); #endif symClose(websMime); @@ -272,7 +272,7 @@ int websAccept(int sid, char *ipaddr, int port, int listenSid) a_assert(wp); wp->listenSid = listenSid; - ascToUni(wp->ipaddr, ipaddr, sizeof(wp->ipaddr)); + ascToUni(wp->ipaddr, ipaddr, min(sizeof(wp->ipaddr), strlen(ipaddr) + 1)); /* * Check if this is a request from a browser on this system. This is useful @@ -319,7 +319,7 @@ static void websSocketEvent(int sid, int mask, int iwp) websReadEvent(wp); } if (mask & SOCKET_WRITABLE) { - if (wp->writeSocket) { + if (websValid(wp) && wp->writeSocket) { (*wp->writeSocket)(wp); } } @@ -340,7 +340,7 @@ void websReadEvent(webs_t wp) a_assert(wp); a_assert(websValid(wp)); - websMarkTime(wp); + websSetTimeMark(wp); /* * Read as many lines as possible. socketGets is called to read the header @@ -410,8 +410,18 @@ void websReadEvent(webs_t wp) 0666); } gwrite(fd, text, gstrlen(text)); - gwrite(fd, T("\n"), sizeof(char_t)); + /* + * NOTE that the above comment is wrong -- if the content length + * is set, websGetInput() does NOT use socketGets(), it uses + * socketRead(), so the line below that adds an additional newline + * is destructive. + */ + /*gwrite(fd, T("\n"), sizeof(char_t));*/ +/* + * Line removed as per BUG02488 + * nbytes += 1; + */ } else #endif if (wp->query) { @@ -433,12 +443,15 @@ void websReadEvent(webs_t wp) * The existing query data came from the POST request so just * append it. */ - len = gstrlen(wp->query); - wp->query = brealloc(B_L, wp->query, (len + gstrlen(text) + - 1) * sizeof(char_t)); - if (wp->query) { - gstrcpy(&wp->query[len], text); - } + if (text != NULL) + { + len = gstrlen(wp->query); + wp->query = brealloc(B_L, wp->query, (len + gstrlen(text) + + 1) * sizeof(char_t)); + if (wp->query) { + gstrcpy(&wp->query[len], text); + } + } } } else { @@ -457,8 +470,13 @@ void websReadEvent(webs_t wp) break; } /* - * No more data so process the request + * No more data so process the request, (but be sure to close + * the input file first!). */ + if (fd != -1) { + gclose (fd); + fd = -1; + } websUrlHandlerRequest(wp); done++; break; @@ -624,16 +642,33 @@ static int websGetInput(webs_t wp, char_t **ptext, int *pnbytes) } else { websDone(wp, 0); } + } else { +/* + * If an error occurred and it wasn't an eof, close the connection + */ +#ifdef HP_FIX + websDone(wp, 0); +#endif /*HP_FIX*/ + } /* * If state is WEBS_HEADER and the ringq is empty, then this is a * simple request with no additional header fields to process and * no empty line terminator. */ +/* + * NOTE: this fix for earlier versions of browsers is troublesome + * because if we don't receive the entire header in the first pass + * this code assumes we were only expecting a one line header, which + * is not necessarily the case. So we weren't processing the whole + * header and weren't fufilling requests properly. + */ +#ifdef UNUSED if (wp->state == WEBS_HEADER && ringqLen(&wp->header) <= 0) { websParseRequest(wp); websUrlHandlerRequest(wp); } +#endif return -1; } else if (nbytes == 0) { @@ -761,7 +796,7 @@ static int websParseFirst(webs_t wp, char_t *text) websUrlType(url, wp->type, TSZ(wp->type)); -#if WEBS_PROXY_SUPPORT +#ifdef WEBS_PROXY_SUPPORT /* * Determine if this is a request for local webs data. If it is not a proxied * request from the browser, we won't see the "http://" or the system name, so @@ -872,6 +907,12 @@ static void websParseRequest(webs_t wp) */ if ((cp = gstrchr(value, ' ')) != NULL) { *cp = '\0'; + /* + * bugfix 5/24/02 -- we were leaking the memory pointed to by + * wp->authType that was allocated just before the if() + * statement that we are currently in. Thanks to Simon Byholm. + */ + bfree(B_L, wp->authType); wp->authType = bstrdup(B_L, value); websDecode64(userAuth, ++cp, sizeof(userAuth)); } else { @@ -1000,9 +1041,22 @@ static void websParseRequest(webs_t wp) * Parse the content length */ } else if (gstrcmp(key, T("content-length")) == 0) { - wp->flags |= WEBS_CLEN; - wp->clen = gatoi(value); - websSetVar(wp, T("CONTENT_LENGTH"), value); + /* + * 11 Oct 02 BgP -- The server would crash if an attacker sent a POST + * message with a content-length value <= 0. We assume that anyone + * sending this is malicious, and the POST is read from the socket, + * but it is ignored, and the socket is closed. + */ + wp->clen = gatoi(value); + if (wp->clen > 0) + { + wp->flags |= WEBS_CLEN; + websSetVar(wp, T("CONTENT_LENGTH"), value); + } + else + { + wp->clen = 0; + } /* * Parse the content type @@ -1010,7 +1064,7 @@ static void websParseRequest(webs_t wp) } else if (gstrcmp(key, T("content-type")) == 0) { websSetVar(wp, T("CONTENT_TYPE"), value); -#if WEBS_KEEP_ALIVE_SUPPORT +#ifdef WEBS_KEEP_ALIVE_SUPPORT } else if (gstrcmp(key, T("connection")) == 0) { strlower(value); if (gstrcmp(value, T("keep-alive")) == 0) { @@ -1018,7 +1072,7 @@ static void websParseRequest(webs_t wp) } #endif -#if WEBS_PROXY_SUPPORT +#ifdef WEBS_PROXY_SUPPORT /* * This may be useful if you wish to keep a local cache of web pages * for proxied requests. @@ -1039,7 +1093,7 @@ static void websParseRequest(webs_t wp) wp->flags |= WEBS_COOKIE; wp->cookie = bstrdup(B_L, value); -#if WEBS_IF_MODIFIED_SUPPORT +#ifdef WEBS_IF_MODIFIED_SUPPORT /* * See if the local page has been modified since the browser last * requested this document. If not, just return a 302 @@ -1127,7 +1181,7 @@ void websSetEnv(webs_t wp) keyword = gstrtok(NULL, T("&")); } -#if EMF +#ifdef EMF /* * Add GoAhead Embedded Management Framework defines */ @@ -1256,7 +1310,15 @@ void websResponse(webs_t wp, int code, char_t *message, char_t *redirect) */ if ( !(wp->flags & WEBS_HEADER_DONE)) { wp->flags |= WEBS_HEADER_DONE; - websWrite(wp, T("HTTP/1.1 %d %s\r\n"), code, websErrorMsg(code)); +/* + * Redirect behaves much better when sent with HTTP/1.0 + */ + if (redirect != NULL) { + websWrite(wp, T("HTTP/1.0 %d %s\r\n"), code, websErrorMsg(code)); + } else { + websWrite(wp, T("HTTP/1.1 %d %s\r\n"), code, websErrorMsg(code)); + } + /* * By license terms the following line of code must not be modified. */ @@ -1280,8 +1342,13 @@ void websResponse(webs_t wp, int code, char_t *message, char_t *redirect) } else { char_t *nonce, *opaque; + /* $$$ before... (note commas instead of semicolons...) nonce = websCalcNonce(wp), opaque = websCalcOpaque(wp), + $$$ after */ + nonce = websCalcNonce(wp); + opaque = websCalcOpaque(wp); + /* ...$$$ end */ websWrite(wp, T("WWW-Authenticate: Digest realm=\"%s\", domain=\"%s\",") T("qop=\"%s\", nonce=\"%s\", opaque=\"%s\",") @@ -1381,10 +1448,17 @@ void websRedirect(webs_t wp, char_t *url) * Output an error message and cleanup */ +#ifdef qRichErrorPage +extern int dmfRichError(webs_t wp, int code, char_t* userMsg); +#endif void websError(webs_t wp, int code, char_t *fmt, ...) { va_list args; char_t *msg, *userMsg, *buf; +#ifdef qRichErrorPage + static int reEntry = 0; + int errorOk; +#endif a_assert(websValid(wp)); a_assert(fmt); @@ -1396,6 +1470,30 @@ void websError(webs_t wp, int code, char_t *fmt, ...) fmtValloc(&userMsg, WEBS_BUFSIZE, fmt, args); va_end(args); +#ifdef qRichErrorPage + if (!reEntry) + { + /* + * The dmfRichError function that we're about to call may very well call + * websError() as part of its work. If that happens, we do NOT want to + * get into a never-ending recursive call chain. When we get back here + * in a call from inside dmfRichError(), we check to see if we're + * already trying to call dmfRichError. If we are, we just revert to the + * old non-rich behavior and display a black on white error page. + */ + + reEntry = 1; + errorOk = dmfRichError(wp, code, userMsg); + reEntry = 0; + if (errorOk) + { + return; + } + /* ...else we need to fall through and execute the simple error page. */ + } + /* implicit else... */ +#endif + msg = T("<html><head><title>Document Error: %s</title></head>\r\n\ <body><h2>Access Error: %s</h2>\r\n\ when trying to obtain <b>%s</b><br><p>%s</p></body></html>\r\n"); @@ -1416,7 +1514,8 @@ void websError(webs_t wp, int code, char_t *fmt, ...) * Return the error message for a given code */ -static char_t *websErrorMsg(int code) +/*static char_t *websErrorMsg(int code)*/ +char_t *websErrorMsg(int code) { websErrorType *ep; @@ -1447,9 +1546,11 @@ int websWrite(webs_t wp, char_t *fmt, ...) buf = NULL; rc = 0; + if (fmtValloc(&buf, WEBS_BUFSIZE, fmt, vargs) >= WEBS_BUFSIZE) { trace(0, T("webs: websWrite lost data, buffer overflow\n")); } + va_end(vargs); a_assert(buf); if (buf) { @@ -1597,7 +1698,7 @@ void websDecodeUrl(char_t *decoded, char_t *token, int len) } /******************************************************************************/ -#if WEBS_LOG_SUPPORT +#ifdef WEBS_LOG_SUPPORT /* * Output a log message */ @@ -1607,12 +1708,30 @@ static void websLog(webs_t wp, int code) char_t *buf; char *abuf; int len; - +#define qAnlLog 1 +#ifdef qAnlLog + time_t timer; + char_t* newLine = NULL; + char_t* timeStr = NULL; +#endif a_assert(websValid(wp)); buf = NULL; + +#ifdef qAnlLog + time(&timer); + timeStr = ctime(&timer); + newLine = gstrchr(timeStr, '\n'); + if (newLine) + { + *newLine = '\0'; + } + fmtAlloc(&buf, WEBS_MAX_URL + 80, T("%s\t%s\t%s\tcode = %d\n"), + timeStr, wp->ipaddr, wp->url, code); +#else fmtAlloc(&buf, WEBS_MAX_URL + 80, T("%d %s %d %d\n"), time(0), wp->url, code, wp->written); +#endif len = gstrlen(buf); abuf = ballocUniToAsc(buf, len+1); write(websLogFd, abuf, len); @@ -1647,7 +1766,6 @@ void websTimeout(void *arg, int id) */ wp->timeout = -1; websDone(wp, 404); - } else { delay = WEBS_TIMEOUT - tm; a_assert(delay > 0); @@ -1673,13 +1791,13 @@ void websDone(webs_t wp, int code) wp->flags &= ~WEBS_KEEP_ALIVE; } -#if WEBS_PROXY_SUPPORT +#ifdef WEBS_PROXY_SUPPORT if (! (wp->flags & WEBS_LOCAL_PAGE)) { websStats.activeNetRequests--; } #endif -#if WEBS_LOG_SUPPORT +#ifdef WEBS_LOG_SUPPORT if (! (wp->flags & WEBS_REQUEST_DONE)) { websLog(wp, code); } @@ -1960,7 +2078,7 @@ char_t *websGetRequestLpath(webs_t wp) { a_assert(websValid(wp)); -#if WEBS_PAGE_ROM +#ifdef WEBS_PAGE_ROM return wp->path; #else return wp->lpath; @@ -2209,7 +2327,7 @@ char_t *websGetDateString(websStatType *sbuf) * "real" time, but rather a relative marker. */ -void websMarkTime(webs_t wp) +void websSetTimeMark(webs_t wp) { wp->timestamp = time(0); } @@ -2247,7 +2365,7 @@ char_t *websGetRealm() } -#if WEBS_IF_MODIFIED_SUPPORT +#ifdef WEBS_IF_MODIFIED_SUPPORT /******************************************************************************/ /* * These functions are intended to closely mirror the syntax for HTTP-date @@ -2582,7 +2700,13 @@ static time_t dateToTimet(int year, int month, int day) { long dayDifference; - dayDifference = FixedFromGregorian(month, day, year) - + /* + * Bug fix by Jeff Reeder (Jun 14, 2002): The 'month' parameter is + * numbered from 0 (Jan == 0), but FixedFromGregorian() takes + * months numbered from 1 (January == 1). We need to add 1 + * to the month + */ + dayDifference = FixedFromGregorian(month + 1, day, year) - FixedFromGregorian(1, 1, 1970); return dayDifference * SECONDS_PER_DAY; @@ -2834,5 +2958,4 @@ static time_t dateParse(time_t tip, char_t *cmd) #endif /* WEBS_IF_MODIFIED_SUPPORT */ - /******************************************************************************/ |