char_t *websCalcDigest(webs_t wp) { #ifdef DIGEST_ACCESS_SUPPORT char_t *digest, *a1, *a1prime, *a2, *a2prime, *preDigest, *method; a_assert(wp); digest = NULL; /* * Calculate first portion of digest H(A1) */ a1 = NULL; fmtAlloc(&a1, 255, T("%s:%s:%s"), wp->userName, wp->realm, wp->password); a_assert(a1); a1prime = websMD5(a1); bfreeSafe(B_L, a1); /* * Calculate second portion of digest H(A2) */ method = websGetVar(wp, T("REQUEST_METHOD"), NULL); a_assert(method); a2 = NULL; fmtAlloc(&a2, 255, T("%s:%s"), method, wp->uri); a_assert(a2); a2prime = websMD5(a2); bfreeSafe(B_L, a2); /* * Construct final digest KD(H(A1):nonce:H(A2)) */ a_assert(a1prime); a_assert(a2prime); a_assert(wp->nonce); preDigest = NULL; if (!wp->qop) { fmtAlloc(&preDigest, 255, T("%s:%s:%s"), a1prime, wp->nonce, a2prime); } else { fmtAlloc(&preDigest, 255, T("%s:%s:%s:%s:%s:%s"), a1prime, wp->nonce, wp->nc, wp->cnonce, wp->qop, a2prime); } a_assert(preDigest); digest = websMD5(preDigest); /* * Now clean up */ bfreeSafe(B_L, a1prime); bfreeSafe(B_L, a2prime); bfreeSafe(B_L, preDigest); return digest; #else return NULL; #endif /* DIGEST_ACCESS_SUPPORT */ }
char_t *websCalcUrlDigest(webs_t wp) { char_t *digest, *a1, *a1prime, *a2, *a2prime, *preDigest, *method; a_assert(wp); digest = NULL; /* * Calculate first portion of digest H(A1) */ a1 = NULL; fmtAlloc(&a1, 255, T("%s:%s:%s"), wp->userName, wp->realm, wp->password); a_assert(a1); a1prime = websMD5(a1); bfreeSafe(B_L, a1); /* * Calculate second portion of digest H(A2) */ method = websGetVar(wp, T("REQUEST_METHOD"), NULL); a_assert(method); /* Fixes by Richard Laing, 2003/7/15 */ a2 = balloc(B_L, (gstrlen(method) +2 + gstrlen(wp->url) ) * sizeof(char_t)); a_assert(a2); gsprintf(a2, T("%s:%s"), method, wp->url); a2prime = websMD5(a2); bfreeSafe(B_L, a2); /* * Construct final digest KD(H(A1):nonce:H(A2)) */ a_assert(a1prime); a_assert(a2prime); a_assert(wp->nonce); preDigest = NULL; if (!wp->qop) { fmtAlloc(&preDigest, 255, T("%s:%s:%s"), a1prime, wp->nonce, a2prime); } else { fmtAlloc(&preDigest, 255, T("%s:%s:%s:%s:%s:%s"), a1prime, wp->nonce, wp->nc, wp->cnonce, wp->qop, a2prime); } a_assert(preDigest); digest = websMD5(preDigest); /* * Now clean up */ bfreeSafe(B_L, a1prime); bfreeSafe(B_L, a2prime); bfreeSafe(B_L, preDigest); return digest; }
char_t *websCalcNonce(webs_t wp) { char_t *nonce, *prenonce; time_t longTime; #if defined(WIN32) char_t buf[26]; errno_t error; struct tm newtime; #else struct tm *newtime; #endif a_assert(wp); /* * Get time as long integer. */ time(&longTime); /* * Convert to local time. */ #if !defined(WIN32) newtime = localtime(&longTime); #else error = localtime_s(&newtime, &longTime); #endif /* * Create prenonce string. */ #if !defined(WIN32) prenonce = NULL; fmtAlloc(&prenonce, 256, T("%s:%s:%s"), RANDOMKEY, gasctime(newtime), wp->realm); #else asctime_s(buf, elementsof(buf), &newtime); fmtAlloc(&prenonce, 256, T("%s:%s:%s"), RANDOMKEY, buf, RANDOMKEY); #endif a_assert(prenonce); /* * Create the nonce */ nonce = websMD5(prenonce); /* * Cleanup */ bfreeSafe(B_L, prenonce); return nonce; }
static int dbWriteKeyValue(int fd, char_t *key, char_t *value) { int rc; int len; char_t *pLineOut; a_assert(key && *key); a_assert(value); fmtAlloc(&pLineOut, BUF_MAX, T("%s=%s\n"), key, value); if (pLineOut) { len = gstrlen(pLineOut); #ifdef CE rc = writeUniToAsc(fd, pLineOut, len); #else rc = gwrite(fd, pLineOut, len); #endif bfree(B_L, pLineOut); } else { rc = -1; } return rc; }
/********************************************************************************************************* ** 函数名称: websGetCgiCommName ** 功能描述: Returns a pointer to an allocated qualified unique temporary file name. ** This filename must eventually be deleted with bfree(); ** 输 入 : ... ** 输 出 : ** 全局变量: ** 调用模块: *********************************************************************************************************/ char_t *websGetCgiCommName() { char_t *tname, buf[FNAMESIZE]; fmtAlloc(&tname, FNAMESIZE, T("%s/%s"), ggetcwd(buf, FNAMESIZE), tmpnam(NULL)); return tname; }
void error( E_ARGS_DEC, int etype, char_t* fmt, ... ) { va_list args; char_t* fmtBuf, *buf; va_start( args, fmt ); fmtValloc( &fmtBuf, E_MAX_ERROR, fmt, args ); if ( etype == E_LOG ) { fmtAlloc( &buf, E_MAX_ERROR, T( "%s\n" ), fmtBuf ); /*#ifdef DEV*/ } else if ( etype == E_ASSERT ) { fmtAlloc( &buf, E_MAX_ERROR, T( "Assertion %s, failed at %s %d\n" ), fmtBuf, E_ARGS ); /*#endif*/ } else if ( etype == E_USER ) { fmtAlloc( &buf, E_MAX_ERROR, T( "%s\n" ), fmtBuf ); } /* * bugfix -- if etype is not E_LOG, E_ASSERT, or E_USER, the call to * bfreeSafe(B_L, buf) below will fail, because 'buf' is randomly * initialized. To be nice, we format a message saying that this is an * unknown message type, and in doing so give buf a valid value. Thanks * to Simon Byholm. */ else { fmtAlloc( &buf, E_MAX_ERROR, T( "Unknown error" ) ); } va_end( args ); bfree( B_L, fmtBuf ); if ( errorHandler ) { errorHandler( etype, buf ); } bfreeSafe( B_L, buf ); }
char_t *websCalcNonce(webs_t wp) { char_t *nonce, *prenonce; struct tm *newtime; time_t longTime; a_assert(wp); /* * Get time as long integer. */ time(&longTime); /* * Convert to local time. */ newtime = localtime(&longTime); /* * Create prenonce string. */ prenonce = NULL; #ifdef DIGEST_ACCESS_SUPPORT fmtAlloc(&prenonce, 256, T("%s:%s:%s"), RANDOMKEY, gasctime(newtime), wp->realm); #else fmtAlloc(&prenonce, 256, T("%s:%s:%s"), RANDOMKEY, gasctime(newtime), RANDOMKEY); #endif a_assert(prenonce); /* * Create the nonce */ nonce = websMD5(prenonce); /* * Cleanup */ bfreeSafe(B_L, prenonce); return nonce; }
int websDefaultHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg, char_t *url, char_t *path, char_t *query) { websStatType sbuf; char_t *lpath, *tmp, *date; int bytes, flags, nchars; a_assert(websValid(wp)); a_assert(url && *url); a_assert(path); a_assert(query); /* * Validate the URL and ensure that ".."s don't give access to unwanted files */ flags = websGetRequestFlags(wp); if (websValidateUrl(wp, path) < 0) { websError(wp, 500, T("Invalid URL %s"), url); return 1; } lpath = websGetRequestLpath(wp); nchars = gstrlen(lpath) - 1; if (lpath[nchars] == '/' || lpath[nchars] == '\\') { lpath[nchars] = '\0'; } /* * If the file is a directory, redirect using the nominated default page */ if (websPageIsDirectory(lpath)) { nchars = gstrlen(path); if (path[nchars-1] == '/' || path[nchars-1] == '\\') { path[--nchars] = '\0'; } nchars += gstrlen(websDefaultPage) + 2; fmtAlloc(&tmp, nchars, T("%s/%s"), path, websDefaultPage); websRedirect(wp, tmp); bfreeSafe(B_L, tmp); return 1; } /* * Open the document. Stat for later use. */ if (websPageOpen(wp, lpath, path, SOCKET_RDONLY | SOCKET_BINARY, 0666) < 0) { websError(wp, 400, T("Cannot open URL <b>%s</b>"), url); return 1; } if (websPageStat(wp, lpath, path, &sbuf) < 0) { websError(wp, 400, T("Cannot stat page for URL <b>%s</b>"), url); return 1; } /* * If the page has not been modified since the user last received it and it * is not dynamically generated each time (ASP), then optimize request by * sending a 304 Use local copy response */ websStats.localHits++; #ifdef WEBS_IF_MODIFIED_SUPPORT if (flags & WEBS_IF_MODIFIED && !(flags & WEBS_ASP)) { if (sbuf.mtime <= wp->since) { websWrite(wp, T("HTTP/1.0 304 Use local copy\r\n")); /* * by license terms the following line of code must * not be modified. */ websWrite(wp, T("Server: %s\r\n"), WEBS_NAME); if (flags & WEBS_KEEP_ALIVE) { websWrite(wp, T("Connection: keep-alive\r\n")); } websWrite(wp, T("\r\n")); websSetRequestFlags(wp, flags |= WEBS_HEADER_DONE); websDone(wp, 304); return 1; } } #endif /* * Output the normal HTTP response header */ if ((date = websGetDateString(NULL)) != NULL) { websWrite(wp, T("HTTP/1.0 200 OK\r\nDate: %s\r\n"), date); /* * By license terms the following line of code must not be modified. */ websWrite(wp, T("Server: %s\r\n"), WEBS_NAME); bfree(B_L, date); } flags |= WEBS_HEADER_DONE; /* * If this is an ASP request, ensure the remote browser doesn't cache it. * Send back both HTTP/1.0 and HTTP/1.1 cache control directives */ if (flags & WEBS_ASP) { bytes = 0; websWrite(wp, T("Pragma: no-cache\r\nCache-Control: no-cache\r\n")); } else { if ((date = websGetDateString(&sbuf)) != NULL) { websWrite(wp, T("Last-modified: %s\r\n"), date); bfree(B_L, date); } bytes = sbuf.size; } if (bytes) { websWrite(wp, T("Content-length: %d\r\n"), bytes); websSetRequestBytes(wp, bytes); } websWrite(wp, T("Content-type: %s\r\n"), websGetRequestType(wp)); if ((flags & WEBS_KEEP_ALIVE) && !(flags & WEBS_ASP)) { websWrite(wp, T("Connection: keep-alive\r\n")); } websWrite(wp, T("\r\n")); /* * All done if the browser did a HEAD request */ if (flags & WEBS_HEAD_REQUEST) { websDone(wp, 200); return 1; } /* * Evaluate ASP requests */ if (flags & WEBS_ASP) { if (websAspRequest(wp, lpath) < 0) { return 1; } websDone(wp, 200); return 1; } #ifdef WEBS_SSL_SUPPORT if (wp->flags & WEBS_SECURE) { websDefaultWriteEvent(wp); } else { websSetRequestSocketHandler(wp, SOCKET_WRITABLE, websDefaultWriteEvent); } #else /* * For normal web documents, return the data via background write */ websSetRequestSocketHandler(wp, SOCKET_WRITABLE, websDefaultWriteEvent); #endif return 1; }
/* * LINUX, MACOSX, ETC: Build whitelist */ #else /* !WIN */ static int websBuildWhitelistRecursive(char *_path, fileNode_t *dir, int level) { struct dirent *findData, *result; DIR *fh; fileNode_t *cnode, *nnode; /* current node, next node */ int firstTime; char path[PATH_MAX]; char tmppath[PATH_MAX]; firstTime = 1; cnode = dir; /* On some platforms such as Solaris, struct dirent includes only one * byte for d_name field, meaning we would overflow the field when * readdir_r is called. So we check for this here. * Another potential issue is if somehow a filesystem is mounted or linked * in a subdirectory or file that has name longer than PATH_MAX. We * ignore that possibility here, and leave it to the user to ensure that * the wwwroot directory does not contain this configuration. * http://womble.decadentplace.org.uk/readdir_r-advisory.html */ if (sizeof(struct dirent) > PATH_MAX) { findData = balloc(B_L, sizeof(struct dirent)); } else { findData = balloc(B_L, sizeof(struct dirent) + PATH_MAX); } websMakePath(path, _path, NULL, 0); if ((fh = opendir(path)) == NULL) { bfree(B_L, findData); return -1; /* Likely no permission to access this directory */ } while ((readdir_r(fh, findData, &result) == 0) && result) { if ((strcmp(findData->d_name, ".") == 0) || (strcmp(findData->d_name, "..") == 0) || (findData->d_type != DT_REG && findData->d_type != DT_DIR)) { continue; } nnode = balloc(B_L, sizeof(fileNode_t)); memset(nnode, 0x0, sizeof(fileNode_t)); if (findData->d_type == DT_DIR) { fmtAlloc(&(nnode->name), PATH_MAX, "%s/", findData->d_name); nnode->flags |= WHITELIST_DIR; } else { nnode->name = bstrdup(B_L, findData->d_name); } if (firstTime) { cnode->child = nnode; firstTime = 0; } else { cnode->next = nnode; } cnode = nnode; if (strncmp(path + strlen(websDefaultDir), "/" CGI_BIN, strlen(CGI_BIN) + 1) == 0) { cnode->flags |= WHITELIST_CGI; } #ifdef WEBS_SSL_SUPPORT sslList_t *l; for (l = sslList; l != NULL; l = l->next) { if (strncmp(path + strlen(websDefaultDir), l->url, strlen(l->url)) == 0) { cnode->flags |= WHITELIST_SSL; break; } } #endif /* WEBS_SSL_SUPPORT */ if (findData->d_type == DT_DIR) { websMakePath(tmppath, path, findData->d_name, 0); if (level < MAX_URL_DEPTH) { if (websBuildWhitelistRecursive(tmppath, cnode, level + 1) < 0){ cnode->flags |= WHITELIST_BLOCKED; } } } } bfree(B_L, findData); closedir(fh); return 0; }
int websDefaultHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg, char_t *url, char_t *path, char_t *query) { websStatType sbuf; char_t *lpath, *tmp, *date; int bytes, flags, nchars, rc; a_assert(websValid(wp)); a_assert(url && *url); a_assert(path); a_assert(query); flags = websGetRequestFlags(wp); /* * We do whitelist validation in addition to standard URL validation. * The whitelist should really catch anything invalid first. * If the whitelist check fails, rebuild the list and try again. * Also validate if we are not on a secure connection, but the whitelist * entry has the SSL flag set, do not serve the page. */ #ifdef WEBS_WHITELIST_SUPPORT printf ("wp->url: (%s)\n", wp->url); if ((rc = websWhitelistCheck(wp->url)) < 0) { websBuildWhitelist(); if ((rc = websWhitelistCheck(wp->url)) < 0) { websError(wp, 404, T("Cannot open URL: type 1")); return 1; } } if (!(flags & WEBS_SECURE) && (rc & WHITELIST_SSL)) { websError(wp, 500, T("HTTPS access required")); return 1; } #endif /* WEBS_WHITELIST_SUPPORT */ /* * Validate the URL and ensure that ".."s don't give access to unwanted files */ if (websValidateUrl(wp, path) < 0) { /* * preventing a cross-site scripting exploit -- you may restore the * following line of code to revert to the original behavior... websError(wp, 500, T("Invalid URL %s"), url); */ websError(wp, 500, T("Invalid URL")); websBuildWhitelist(); return 1; } lpath = websGetRequestLpath(wp); nchars = gstrlen(lpath) - 1; if (lpath[nchars] == '/' || lpath[nchars] == '\\') { lpath[nchars] = '\0'; } /* * If the file is a directory, redirect using the nominated default page */ if (websPageIsDirectory(lpath)) { nchars = gstrlen(path); if (path[nchars-1] == '/' || path[nchars-1] == '\\') { path[--nchars] = '\0'; } nchars += gstrlen(websDefaultPage) + 2; fmtAlloc(&tmp, nchars, T("%s/%s"), path, websDefaultPage); printf ("websDefaultHandler: tmp(%s)\n", tmp); websRedirect(wp, tmp); bfreeSafe(B_L, tmp); return 1; } printf ("we now open the web pages\n"); printf ("lpath(%s), path(%s)\n", lpath, path); /* * Open the document. Stat for later use. */ if (websPageOpen(wp, lpath, path, O_RDONLY | O_BINARY, 0666) < 0) { /* 10 Dec 02 BgP -- according to * <http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html>, * the proper code to return here is NOT 400 (old code), which is used * to indicate a malformed request. Here, the request is good, but the * error we need to tell the client about is 404 (Not Found). */ /* * 17 Mar 03 BgP -- prevent a cross-site scripting exploit websError(wp, 404, T("Cannot open URL %s"), url); */ websError(wp, 404, T("Cannot open URL, type 2")); websBuildWhitelist(); return 1; } printf ("lpath(%s), path(%s)\n", lpath, path); if (websPageStat(wp, lpath, path, &sbuf) < 0) { /* * 17 Mar 03 BgP * prevent a cross-site scripting exploit websError(wp, 400, T("Cannot stat page for URL %s"), url); */ websError(wp, 400, T("Cannot stat page for URL")); websBuildWhitelist(); return 1; } /* * If the page has not been modified since the user last received it and it * is not dynamically generated each time (ASP), then optimize request by * sending a 304 Use local copy response */ websStats.localHits++; #ifdef WEBS_IF_MODIFIED_SUPPORT if (flags & WEBS_IF_MODIFIED && !(flags & WEBS_ASP)) { if (sbuf.mtime <= wp->since) { websWrite(wp, T("HTTP/1.0 304 Use local copy\r\n")); /* * by license terms the following line of code must * not be modified. */ websWrite(wp, T("Server: %s\r\n"), WEBS_NAME); if (flags & WEBS_KEEP_ALIVE) { websWrite(wp, T("Connection: keep-alive\r\n")); } websWrite(wp, T("\r\n")); websSetRequestFlags(wp, flags |= WEBS_HEADER_DONE); websDone(wp, 304); return 1; } } #endif /* * Output the normal HTTP response header */ if ((date = websGetDateString(NULL)) != NULL) { websWrite(wp, T("HTTP/1.0 200 OK\r\nDate: %s\r\n"), date); /* * The Server HTTP header below must not be modified unless * explicitly allowed by licensing terms. */ #ifdef WEBS_SSL_SUPPORT websWrite(wp, T("Server: %s/%s %s/%s\r\n"), WEBS_NAME, WEBS_VERSION, SSL_NAME, SSL_VERSION); #else websWrite(wp, T("Server: %s/%s\r\n"), WEBS_NAME, WEBS_VERSION); #endif bfree(B_L, date); } flags |= WEBS_HEADER_DONE; /* * If this is an ASP request, ensure the remote browser doesn't cache it. * Send back both HTTP/1.0 and HTTP/1.1 cache control directives */ if (flags & WEBS_ASP) { bytes = 0; websWrite(wp, T("Pragma: no-cache\r\nCache-Control: no-cache\r\n")); } else { if ((date = websGetDateString(&sbuf)) != NULL) { websWrite(wp, T("Last-modified: %s\r\n"), date); bfree(B_L, date); } bytes = sbuf.size; } if (bytes) { websWrite(wp, T("Content-length: %d\r\n"), bytes); websSetRequestBytes(wp, bytes); } websWrite(wp, T("Content-type: %s\r\n"), websGetRequestType(wp)); if ((flags & WEBS_KEEP_ALIVE) && !(flags & WEBS_ASP)) { websWrite(wp, T("Connection: keep-alive\r\n")); } websWrite(wp, T("\r\n")); /* * All done if the browser did a HEAD request */ if (flags & WEBS_HEAD_REQUEST) { websDone(wp, 200); return 1; } /* * Evaluate ASP requests */ if (flags & WEBS_ASP) { if (websAspRequest(wp, lpath) < 0) { return 1; } websDone(wp, 200); return 1; } /* * Return the data via background write */ websSetRequestSocketHandler(wp, SOCKET_WRITABLE, websDefaultWriteEvent); return 1; }
static int websBuildWhitelistRecursive(char *_path, fileNode_t *dir, int level) { WIN32_FIND_DATA findData; HANDLE fh; fileNode_t *cnode, *nnode; /* current node, next node */ #ifdef WEBS_SSL_SUPPORT sslList_t *l; #endif int rc = 0; int firstTime; char path[MAX_PATH]; char tmppath[MAX_PATH]; firstTime = 1; cnode = dir; websMakePath(path, _path, NULL, 1); fh = FindFirstFile((LPCSTR)path, &findData); while (fh != INVALID_HANDLE_VALUE) { if ((strcmp(findData.cFileName, ".") == 0) || (strcmp(findData.cFileName, "..") == 0) || (findData.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN) || (findData.dwFileAttributes & FILE_ATTRIBUTE_SYSTEM)) { goto nextFile; } nnode = balloc(B_L, sizeof(fileNode_t)); memset(nnode, 0x0, sizeof(fileNode_t)); if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { fmtAlloc(&(nnode->name), MAX_PATH, "%s/", findData.cFileName); nnode->flags |= WHITELIST_DIR; } else { nnode->name = bstrdup(B_L, findData.cFileName); } if (firstTime) { cnode->child = nnode; firstTime = 0; } else { cnode->next = nnode; } cnode = nnode; if (strncmp(path + strlen(websDefaultDir), "/" CGI_BIN, strlen(CGI_BIN) + 1) == 0) { cnode->flags |= WHITELIST_CGI; } #ifdef WEBS_SSL_SUPPORT for (l = sslList; l != NULL; l = l->next) { if (strncmp(path + strlen(websDefaultDir), l->url, strlen(l->url)) == 0) { cnode->flags |= WHITELIST_SSL; } } #endif /* WEBS_SSL_SUPPORT */ if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { websMakePath(tmppath, path, findData.cFileName, 1); if (level < MAX_URL_DEPTH) { if (websBuildWhitelistRecursive(tmppath, cnode, level + 1) < 0){ cnode->flags |= WHITELIST_BLOCKED; } } } nextFile: if (FindNextFile(fh, &findData) == 0) { if (GetLastError() != ERROR_NO_MORE_FILES) { rc = -1; } break; } } FindClose(fh); return rc; }
/* * Process a form request. Returns 1 always to indicate it handled the URL */ int websCgiHandler(webs_t wp, char_t *urlPrefix, char_t *webDir, int arg, char_t *url, char_t *path, char_t* query) { cgiRec *cgip; sym_t *s; char_t cgiBuf[FNAMESIZE], *stdIn, *stdOut, cwd[FNAMESIZE]; char_t *cp, *cgiName, *cgiPath, **argp, **envp, **ep; int n, envpsize, argpsize, pHandle, cid; a_assert(websValid(wp)); a_assert(url && *url); a_assert(path && *path == '/'); websStats.cgiHits++; /* * Extract the form name and then build the full path name. The form * name will follow the first '/' in path. */ gstrncpy(cgiBuf, path, TSZ(cgiBuf)); if ((cgiName = gstrchr(&cgiBuf[1], '/')) == NULL) { websError(wp, 200, T("Missing CGI name")); return 1; } cgiName++; if ((cp = gstrchr(cgiName, '/')) != NULL) { *cp = '\0'; } fmtAlloc(&cgiPath, FNAMESIZE, T("%s/%s/%s"), websGetDefaultDir(), CGI_BIN, cgiName); #ifndef VXWORKS /* * See if the file exists and is executable. If not error out. * Don't do this step for VxWorks, since the module may already * be part of the OS image, rather than in the file system. */ { gstat_t sbuf; if (gstat(cgiPath, &sbuf) != 0 || (sbuf.st_mode & S_IFREG) == 0) { websError(wp, 200, T("CGI process file does not exist")); bfree(B_L, cgiPath); return 1; } #if (defined (WIN) || defined (CE)) if (gstrstr(cgiPath, T(".exe")) == NULL && gstrstr(cgiPath, T(".bat")) == NULL) { #elif (defined (NW)) if (gstrstr(cgiPath, T(".nlm")) == NULL) { #else if (gaccess(cgiPath, X_OK) != 0) { #endif /* WIN || CE */ websError(wp, 200, T("CGI process file is not executable")); bfree(B_L, cgiPath); return 1; } } #endif /* ! VXWORKS */ /* * Get the CWD for resetting after launching the child process CGI */ ggetcwd(cwd, FNAMESIZE); /* * Retrieve the directory of the child process CGI */ if ((cp = gstrrchr(cgiPath, '/')) != NULL) { *cp = '\0'; gchdir(cgiPath); *cp = '/'; } /* * Build command line arguments. Only used if there is no non-encoded * = character. This is indicative of a ISINDEX query. POST separators * are & and others are +. argp will point to a balloc'd array of * pointers. Each pointer will point to substring within the * query string. This array of string pointers is how the spawn or * exec routines expect command line arguments to be passed. Since * we don't know ahead of time how many individual items there are in * the query string, the for loop includes logic to grow the array * size via brealloc. */ argpsize = 10; argp = balloc(B_L, argpsize * sizeof(char_t *)); *argp = cgiPath; n = 1; if (gstrchr(query, '=') == NULL) { websDecodeUrl(query, query, gstrlen(query)); for (cp = gstrtok(query, T(" ")); cp != NULL; ) { *(argp+n) = cp; n++; if (n >= argpsize) { argpsize *= 2; argp = brealloc(B_L, argp, argpsize * sizeof(char_t *)); } cp = gstrtok(NULL, T(" ")); } } *(argp+n) = NULL; /* * Add all CGI variables to the environment strings to be passed * to the spawned CGI process. This includes a few we don't * already have in the symbol table, plus all those that are in * the cgiVars symbol table. envp will point to a balloc'd array of * pointers. Each pointer will point to a balloc'd string containing * the keyword value pair in the form keyword=value. Since we don't * know ahead of time how many environment strings there will be the * for loop includes logic to grow the array size via brealloc. */ envpsize = WEBS_SYM_INIT; envp = balloc(B_L, envpsize * sizeof(char_t *)); n = 0; fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"),T("PATH_TRANSLATED"), cgiPath); n++; fmtAlloc(envp+n, FNAMESIZE, T("%s=%s/%s"),T("SCRIPT_NAME"), CGI_BIN, cgiName); n++; fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"),T("REMOTE_USER"), wp->userName); n++; fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"),T("AUTH_TYPE"), wp->authType); n++; for (s = symFirst(wp->cgiVars); s != NULL; s = symNext(wp->cgiVars)) { if (s->content.valid && s->content.type == string && gstrcmp(s->name.value.string, T("REMOTE_HOST")) != 0 && gstrcmp(s->name.value.string, T("HTTP_AUTHORIZATION")) != 0) { fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"), s->name.value.string, s->content.value.string); n++; if (n >= envpsize) { envpsize *= 2; envp = brealloc(B_L, envp, envpsize * sizeof(char_t *)); } } } if (wp->flags & WEBS_CGI_UPLOAD){ // set filename into enviornment variables fmtAlloc(envp+n, FNAMESIZE, T("%s=%s"), T("UPLOAD_FILENAME"), wp->cgiStdin); n++; } *(envp+n) = NULL; /* * Create temporary file name(s) for the child's stdin and stdout. * For POST data the stdin temp file (and name) should already exist. */ if (wp->cgiStdin == NULL) { wp->cgiStdin = websGetCgiCommName(wp); } stdIn = wp->cgiStdin; stdOut = websGetCgiCommName(wp); /* * Now launch the process. If not successful, do the cleanup of resources. * If successful, the cleanup will be done after the process completes. */ if ((pHandle = websLaunchCgiProc(cgiPath, argp, envp, stdIn, stdOut)) == -1) { websError(wp, 200, T("failed to spawn CGI task")); for (ep = envp; *ep != NULL; ep++) { bfreeSafe(B_L, *ep); } bfreeSafe(B_L, cgiPath); bfreeSafe(B_L, argp); bfreeSafe(B_L, envp); bfreeSafe(B_L, stdOut); } else { /* * If the spawn was successful, put this wp on a queue to be * checked for completion. */ cid = hAllocEntry((void***) &cgiList, &cgiMax, sizeof(cgiRec)); cgip = cgiList[cid]; cgip->handle = pHandle; cgip->stdIn = stdIn; cgip->stdOut = stdOut; cgip->cgiPath = cgiPath; cgip->argp = argp; cgip->envp = envp; cgip->wp = wp; cgip->fplacemark = 0; websTimeoutCancel(wp); } /* * Restore the current working directory after spawning child CGI */ gchdir(cwd); return 1; } /******************************************************************************/ /* * Any entry in the cgiList need to be checked to see if it has */ void websCgiGatherOutput (cgiRec *cgip) { gstat_t sbuf; char_t cgiBuf[FNAMESIZE]; if ((gstat(cgip->stdOut, &sbuf) == 0) && (sbuf.st_size > cgip->fplacemark)) { int fdout; fdout = gopen(cgip->stdOut, O_RDONLY | O_BINARY, 0444 ); /* * Check to see if any data is available in the * output file and send its contents to the socket. */ if (fdout >= 0) { webs_t wp = cgip->wp; int nRead; /* * Write the HTTP header on our first pass */ if (cgip->fplacemark == 0) { websWrite(wp, T("HTTP/1.0 200 OK\r\n")); } glseek(fdout, cgip->fplacemark, SEEK_SET); while ((nRead = gread(fdout, cgiBuf, FNAMESIZE)) > 0) { websWriteBlock(wp, cgiBuf, nRead); cgip->fplacemark += nRead; } gclose(fdout); } } } /******************************************************************************/ /* * Any entry in the cgiList need to be checked to see if it has * completed, and if so, process its output and clean up. */ void websCgiCleanup() { cgiRec *cgip; webs_t wp; char_t **ep; int cid, nTries; for (cid = 0; cid < cgiMax; cid++) { if ((cgip = cgiList[cid]) != NULL) { int exit_status; wp = cgip->wp; websCgiGatherOutput (cgip); if ( websCheckCgiProc(cgip->handle, &exit_status) == 0) { /* * We get here if the CGI process has terminated. Clean up. */ nTries = 0; /* * Make sure we didn't miss something during a task switch. * Maximum wait is 100 times 10 msecs (1 second). */ while ((cgip->fplacemark == 0) && (nTries < 100)) { websCgiGatherOutput(cgip); /* * There are some cases when we detect app exit * before the file is ready. */ if (cgip->fplacemark == 0) { #ifdef WIN Sleep(10); #endif /* WIN*/ } nTries++; } if (cgip->fplacemark == 0) { websError(wp, 200, T("CGI generated no output")); } else { websDone(wp, 200); } /* * Remove the temporary re-direction files */ gunlink(cgip->stdIn); gunlink(cgip->stdOut); /* * Free all the memory buffers pointed to by cgip. * The stdin file name (wp->cgiStdin) gets freed as * part of websFree(). */ cgiMax = hFree((void***) &cgiList, cid); for (ep = cgip->envp; ep != NULL && *ep != NULL; ep++) { bfreeSafe(B_L, *ep); } bfreeSafe(B_L, cgip->cgiPath); bfreeSafe(B_L, cgip->argp); bfreeSafe(B_L, cgip->envp); bfreeSafe(B_L, cgip->stdOut); bfreeSafe(B_L, cgip); #if 0 //DAVIDM - we do not want this, netflash does it for us if(wp->has_firmware_upload_clean){ if (WIFEXITED(exit_status) && WEXITSTATUS(exit_status) != 0) return; sync(); doSystem("sleep 3 && reboot &"); } #endif } } } }
int dbLoad(int did, char_t *filename, int flags) { gstat_t sbuf; char_t *buf, *keyword, *value, *path, *ptr; char_t *tablename; int fd, tid, row; dbTable_t *pTable; a_assert(did >= 0); fmtAlloc(&path, FNAMESIZE, T("%s/%s"), basicGetProductDir(), filename); trace(4, T("DB: About to read data file <%s>\n"), path); if (gstat(path, &sbuf) < 0) { trace(3, T("DB: Failed to stat persistent data file.\n")); bfree(B_L, path); return -1; } fd = gopen(path, O_RDONLY | O_BINARY, 0666); bfree(B_L, path); if (fd < 0) { trace(3, T("DB: No persistent data file present.\n")); return -1; } if (sbuf.st_size <= 0) { trace(3, T("DB: Persistent data file is empty.\n")); gclose(fd); return -1; } /* * Read entire file into temporary buffer */ buf = balloc(B_L, sbuf.st_size + 1); #ifdef CE if (readAscToUni(fd, &buf, sbuf.st_size) != (int)sbuf.st_size) { #else if (gread(fd, buf, sbuf.st_size) != (int)sbuf.st_size) { #endif trace(3, T("DB: Persistent data read failed.\n")); bfree(B_L, buf); gclose(fd); return -1; } gclose(fd); *(buf + sbuf.st_size) = '\0'; row = -1; tid = -1; pTable = NULL; ptr = gstrtok(buf, T("\n")); tablename = NULL; do { if (crack(ptr, &keyword, &value) < 0) { trace(5, T("DB: Failed to crack line %s\n"), ptr); continue; } a_assert(keyword && *keyword); if (gstrcmp(keyword, KEYWORD_TABLE) == 0) { /* * Table name found, check to see if it's registered */ if (tablename) { bfree(B_L, tablename); } tablename = bstrdup(B_L, value); tid = dbGetTableId(did, tablename); if (tid >= 0) { pTable = dbListTables[tid]; } else { pTable = NULL; } } else if (gstrcmp(keyword, KEYWORD_ROW) == 0) { /* * Row/Record indicator found, add a new row to table */ if (tid >= 0) { int nRows = dbGetTableNrow(did, tablename); if (dbSetTableNrow(did, tablename, nRows + 1) == 0) { row = nRows; } } } else if (row != -1) { /* * some other data found, assume it's a COLUMN=value */ int nColumn = GetColumnIndex(tid, keyword); if ((nColumn >= 0) && (pTable != NULL)) { int nColumnType = pTable->columnTypes[nColumn]; if (nColumnType == T_STRING) { dbWriteStr(did, tablename, keyword, row, value); } else { dbWriteInt(did, tablename, keyword, row, gstrtoi(value)); } } } } while ((ptr = gstrtok(NULL, T("\n"))) != NULL); if (tablename) { bfree(B_L, tablename); } bfree(B_L, buf); return 0; } /******************************************************************************/ /* * Return a table id given the table name */ int dbGetTableId(int did, char_t *tablename) { int tid; dbTable_t *pTable; a_assert(tablename); for (tid = 0; (tid < dbMaxTables); tid++) { if ((pTable = dbListTables[tid]) != NULL) { if (gstrcmp(tablename, pTable->name) == 0) { return tid; } } } return -1; }
int dbSave(int did, char_t *filename, int flags) { int row, column, nColumns, nRows, fd, rc; int *colTypes, *pRow, nRet, tid; char_t *path, *tmpFile, *tmpNum; char_t **colNames; dbTable_t *pTable; trace(5, T("DB: About to save database to file\n")); a_assert(dbMaxTables > 0); /* * First write to a temporary file, then switch around later. */ fmtAlloc(&tmpFile, FNAMESIZE, T("%s/data.tmp"), basicGetProductDir()); if ((fd = gopen(tmpFile, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0666)) < 0) { trace(1, T("WARNING: Failed to open file %s\n"), tmpFile); bfree(B_L, tmpFile); return -1; } nRet = 0; for (tid = 0; (tid < dbMaxTables) && (nRet != -1); tid++) { pTable = dbListTables[tid]; if (pTable) { /* * Print the TABLE=tableName directive to the file */ rc = dbWriteKeyValue(fd, KEYWORD_TABLE, pTable->name); nColumns = pTable->nColumns; nRows = pTable->nRows; for (row = 0; (row < nRows) && (nRet == 0); row++) { pRow = pTable->rows[row]; /* * if row is NULL, the row has been deleted, so don't * write it out. */ if ((pRow == NULL) || (pRow[0] == '\0') || (*(char_t *)(pRow[0]) == '\0')) { continue; } /* * Print the ROW=rowNumber directive to the file */ fmtAlloc(&tmpNum, 20, T("%d"), row); rc = dbWriteKeyValue(fd, KEYWORD_ROW, tmpNum); bfreeSafe(B_L, tmpNum); colNames = pTable->columnNames; colTypes = pTable->columnTypes; /* * Print the key-value pairs (COLUMN=value) for data cells */ for (column = 0; (column < nColumns) && (rc >= 0); column++, colNames++, colTypes++) { if (*colTypes == T_STRING) { rc = dbWriteKeyValue(fd, *colNames, (char_t *)(pRow[column])); } else { fmtAlloc(&tmpNum, 20, T("%d"), pRow[column]); rc = dbWriteKeyValue(fd, *colNames, tmpNum); bfreeSafe(B_L, tmpNum); } } if (rc < 0) { trace(1, T("WARNING: Failed to write to file %s\n"), tmpFile); nRet = -1; } } } } gclose(fd); /* * Replace the existing file with the temporary file, if no errors */ if (nRet == 0) { fmtAlloc(&path, FNAMESIZE, T("%s/%s"), basicGetProductDir(), filename); gunlink(path); if (grename(tmpFile, path) != 0) { trace(1, T("WARNING: Failed to rename %s to %s\n"), tmpFile, path); nRet = -1; } bfree(B_L, path); } bfree(B_L, tmpFile); return nRet; }
int websLaunchCgiProc(char_t *cgiPath, char_t **argp, char_t **envp, char_t *stdIn, char_t *stdOut) { SYM_TYPE ptype; char_t *p, *basename, *pEntry, *pname, *entryAddr, **pp; int priority, rc, fd; /* * Determine the basename, which is without path or the extension. */ if ((int)(p = gstrrchr(cgiPath, '/') + 1) == 1) { p = cgiPath; } basename = bstrdup(B_L, p); if ((p = gstrrchr(basename, '.')) != NULL) { *p = '\0'; } /* * Unload the module, if it is already loaded. Get the current task * priority. */ unld(cgiPath, 0); taskPriorityGet(taskIdSelf(), &priority); rc = fd = -1; /* * Set the entry point symbol name as described above. Look for an already * loaded entry point; if it exists, spawn the task accordingly. */ for (pp = envp, pEntry = NULL; pp != NULL && *pp != NULL; pp++) { if (gstrncmp(*pp, T("cgientry="), 9) == 0) { pEntry = bstrdup(B_L, *pp + 9); break; } } if (pEntry == NULL) { fmtAlloc(&pEntry, LF_PATHSIZE, T("%s_%s"), basename, T("cgientry")); } entryAddr = 0; if (symFindByName(sysSymTbl, pEntry, &entryAddr, &ptype) == -1) { fmtAlloc(&pname, VALUE_MAX_STRING, T("_%s"), pEntry); symFindByName(sysSymTbl, pname, &entryAddr, &ptype); bfreeSafe(B_L, pname); } if (entryAddr != 0) { rc = taskSpawn(pEntry, priority, 0, 20000, (void *)vxWebsCgiEntry, (int)entryAddr, (int)argp, (int)envp, (int)stdIn, (int)stdOut, 0, 0, 0, 0, 0); goto DONE; } /* * Try to load the module. */ if ((fd = gopen(cgiPath, O_RDONLY | O_BINARY, 0666)) < 0 || loadModule(fd, LOAD_GLOBAL_SYMBOLS) == NULL) { goto DONE; } if ((symFindByName(sysSymTbl, pEntry, &entryAddr, &ptype)) == -1) { fmtAlloc(&pname, VALUE_MAX_STRING, T("_%s"), pEntry); symFindByName(sysSymTbl, pname, &entryAddr, &ptype); bfreeSafe(B_L, pname); } if (entryAddr != 0) { rc = taskSpawn(pEntry, priority, 0, 20000, (void *)vxWebsCgiEntry, (int)entryAddr, (int)argp, (int)envp, (int)stdIn, (int)stdOut, 0, 0, 0, 0, 0); } DONE: if (fd != -1) { gclose(fd); } bfree(B_L, basename); bfree(B_L, pEntry); return rc; }