2003-04-11 Joel Sherrill <joel@OARcorp.com>

* rtems_webserver/cgi.c, rtems_webserver/sockGen.c,
	rtems_webserver/umui.c, rtems_webserver/websSSL.c,
	rtems_webserver/websSSL.h, rtems_webserver/websda.c,
	rtems_webserver/websda.h: New files. Not included in previous commit.
This commit is contained in:
Joel Sherrill
2003-04-11 16:34:49 +00:00
parent ee3afa2e2a
commit 2e7f00fce6
15 changed files with 6155 additions and 0 deletions
+7
View File
@@ -1,3 +1,10 @@
2003-04-11 Joel Sherrill <joel@OARcorp.com>
* rtems_webserver/cgi.c, rtems_webserver/sockGen.c,
rtems_webserver/umui.c, rtems_webserver/websSSL.c,
rtems_webserver/websSSL.h, rtems_webserver/websda.c,
rtems_webserver/websda.h: New files. Not included in previous commit.
2002-04-10 Mike Siers <mikes@poliac.com>
* rtems_webserver/NOTES, rtems_webserver/asp.c,
+331
View File
@@ -0,0 +1,331 @@
/*
* cgi.c -- CGI processing (for the GoAhead Web server
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/********************************** Description *******************************/
/*
* This module implements the /cgi-bin handler. CGI processing differs from
* goforms processing in that each CGI request is executed as a separate
* process, rather than within the webserver process. For each CGI request the
* environment of the new process must be set to include all the CGI variables
* and its standard input and output must be directed to the socket. This
* is done using temporary files.
*/
/*********************************** Includes *********************************/
#include "wsIntrn.h"
#ifdef UEMF
#include "uemf.h"
#else
#include "basic/basicInternal.h"
#endif
/************************************ Locals **********************************/
typedef struct { /* Struct for CGI tasks which have completed */
webs_t wp; /* pointer to session websRec */
char_t *stdIn; /* file desc. for task's temp input fd */
char_t *stdOut; /* file desc. for task's temp output fd */
char_t *cgiPath; /* path to executable process file */
char_t **argp; /* pointer to buf containing argv tokens */
char_t **envp; /* pointer to array of environment strings */
int handle; /* process handle of the task */
long fplacemark; /* seek location for CGI output file */
} cgiRec;
static cgiRec **cgiList; /* hAlloc chain list of wp's to be closed */
static int cgiMax; /* Size of hAlloc list */
/************************************* Code ***********************************/
/*
* 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 *));
}
}
}
*(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();
}
stdIn = wp->cgiStdin;
stdOut = websGetCgiCommName();
/*
* 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) {
wp = cgip->wp;
websCgiGatherOutput (cgip);
if (websCheckCgiProc(cgip->handle) == 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);
}
}
}
}
/******************************************************************************/
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,67 @@
/*
* websSSL.h -- SSL Patch header
*
* Copyright (c) GoAhead Software Inc., 1992-2000. All Rights Reserved.
*
* See the file "license.txt" for information on usage and redistribution
*
* $Id$
*/
#ifndef _h_websSSL
#define _h_websSSL 1
/******************************** Description *********************************/
/*
* Header file for the GoAhead Patch for SSL. This defines the interface to
* integrate SSL into the GoAhead Webserver.
*/
/********************************* Includes ***********************************/
#ifdef OPENSSL
#define SSLEAY /* turn off a few special case MONOLITH macros */
#define USE_SOCKETS /* needed for the _O_BINARY defs in the MS world */
#include <openssl/ssl.h>
#else
#include <sslc.h>
#endif
#ifndef UEMF
#include "basic/basic.h"
#include "emf/emf.h"
#else
#include "uemf.h"
#endif
/********************************** Defines ***********************************/
typedef struct {
SSL *ssl;
BIO *bio;
} websSSL_t;
/******************************** Prototypes **********************************/
extern int websSSLOpen();
extern int websSSLIsOpen();
extern void websSSLClose();
extern int websSSLWrite(websSSL_t *wsp, char_t *buf, int nChars);
extern int websSSLGets(websSSL_t *wsp, char_t **buf);
extern int websSSLRead(websSSL_t *wsp, char_t *buf, int nChars);
extern int websSSLEof(websSSL_t *wsp);
extern int websSSLFree(websSSL_t *wsp);
extern int websSSLFlush(websSSL_t *wsp);
extern int websSSLSetKeyFile(char_t *keyFile);
extern int websSSLSetCertFile(char_t *certFile);
#endif /* _h_websSSL */
/*****************************************************************************/
@@ -0,0 +1,244 @@
/*
* websda.c -- Digest Access Authentication routines
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/******************************** Description *********************************/
/*
* Routines for generating DAA data. The module uses the
* "RSA Data Security, Inc. MD5 Message-Digest Algorithm" found in md5c.c
*/
/********************************* Includes ***********************************/
#ifndef CE
#include <time.h>
#endif
#include "websda.h"
#include "md5.h"
/******************************** Local Data **********************************/
#define RANDOMKEY T("onceuponatimeinparadise")
#define NONCE_SIZE 34
#define HASH_SIZE 16
/*********************************** Code *************************************/
/*
* websMD5binary returns the MD5 hash
*/
char *websMD5binary(unsigned char *buf, int length)
{
const char *hex = "0123456789abcdef";
MD5_CONTEXT md5ctx;
unsigned char hash[HASH_SIZE];
char *r, *strReturn;
char result[(HASH_SIZE * 2) + 1];
int i;
/*
* Take the MD5 hash of the string argument.
*/
MD5Init(&md5ctx);
MD5Update(&md5ctx, buf, (unsigned int)length);
MD5Final(hash, &md5ctx);
/*
* Prepare the resulting hash string
*/
for (i = 0, r = result; i < 16; i++) {
*r++ = hex[hash[i] >> 4];
*r++ = hex[hash[i] & 0xF];
}
/*
* Zero terminate the hash string
*/
*r = '\0';
/*
* Allocate a new copy of the hash string
*/
strReturn = balloc(B_L, sizeof(result));
strcpy(strReturn, result);
return strReturn;
}
/*****************************************************************************/
/*
* Convenience call to websMD5binary
* (Performs char_t to char conversion and back)
*/
char_t *websMD5(char_t *string)
{
char_t *strReturn;
a_assert(string && *string);
if (string && *string) {
char *strTemp, *strHash;
int nLen;
/*
* Convert input char_t string to char string
*/
nLen = gstrlen(string);
strTemp = ballocUniToAsc(string, nLen + 1);
/*
* Execute the digest calculation
*/
strHash = websMD5binary((unsigned char *)strTemp, nLen);
/*
* Convert the returned char string digest to a char_t string
*/
nLen = strlen(strHash);
strReturn = ballocAscToUni(strHash, nLen);
/*
* Free up the temporary allocated resources
*/
bfree(B_L, strTemp);
bfree(B_L, strHash);
} else {
strReturn = NULL;
}
return strReturn;
}
/******************************************************************************/
/*
* Get a Nonce value for passing along to the client. This function
* composes the string "RANDOMKEY:timestamp:myrealm" and
* calculates the MD5 digest placing it in output.
*/
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;
}
/******************************************************************************/
/*
* Get an Opaque value for passing along to the client
*/
char_t *websCalcOpaque(webs_t wp)
{
char_t *opaque;
a_assert(wp);
/*
* Temporary stub!
*/
opaque = bstrdup(B_L, T("5ccc069c403ebaf9f0171e9517f40e41"));
return opaque;
}
/******************************************************************************/
/*
* Get a Digest value using the MD5 algorithm
*/
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 */
}
/******************************************************************************/
@@ -0,0 +1,41 @@
/*
* websda.h -- GoAhead Digest Access Authentication public header
*
* Copyright (c) GoAhead Software Inc., 1992-2000. All Rights Reserved.
*
* See the file "license.txt" for information on usage and redistribution
*
* $Id$
*/
#ifndef _h_WEBSDA
#define _h_WEBSDA 1
/******************************** Description *********************************/
/*
* GoAhead Digest Access Authentication header. This defines the Digest
* access authentication public APIs. Include this header for files that
* use DAA functions
*/
/********************************* Includes ***********************************/
#ifndef UEMF
#include "basic/basic.h"
#include "emf/emf.h"
#else
#include "uemf.h"
#endif
#include "webs.h"
/****************************** Definitions ***********************************/
extern char_t *websCalcNonce(webs_t wp);
extern char_t *websCalcOpaque(webs_t wp);
extern char_t *websCalcDigest(webs_t wp);
#endif /* _h_WEBSDA */
/******************************************************************************/
+331
View File
@@ -0,0 +1,331 @@
/*
* cgi.c -- CGI processing (for the GoAhead Web server
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/********************************** Description *******************************/
/*
* This module implements the /cgi-bin handler. CGI processing differs from
* goforms processing in that each CGI request is executed as a separate
* process, rather than within the webserver process. For each CGI request the
* environment of the new process must be set to include all the CGI variables
* and its standard input and output must be directed to the socket. This
* is done using temporary files.
*/
/*********************************** Includes *********************************/
#include "wsIntrn.h"
#ifdef UEMF
#include "uemf.h"
#else
#include "basic/basicInternal.h"
#endif
/************************************ Locals **********************************/
typedef struct { /* Struct for CGI tasks which have completed */
webs_t wp; /* pointer to session websRec */
char_t *stdIn; /* file desc. for task's temp input fd */
char_t *stdOut; /* file desc. for task's temp output fd */
char_t *cgiPath; /* path to executable process file */
char_t **argp; /* pointer to buf containing argv tokens */
char_t **envp; /* pointer to array of environment strings */
int handle; /* process handle of the task */
long fplacemark; /* seek location for CGI output file */
} cgiRec;
static cgiRec **cgiList; /* hAlloc chain list of wp's to be closed */
static int cgiMax; /* Size of hAlloc list */
/************************************* Code ***********************************/
/*
* 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 *));
}
}
}
*(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();
}
stdIn = wp->cgiStdin;
stdOut = websGetCgiCommName();
/*
* 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) {
wp = cgip->wp;
websCgiGatherOutput (cgip);
if (websCheckCgiProc(cgip->handle) == 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);
}
}
}
}
/******************************************************************************/
File diff suppressed because it is too large Load Diff
+641
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+67
View File
@@ -0,0 +1,67 @@
/*
* websSSL.h -- SSL Patch header
*
* Copyright (c) GoAhead Software Inc., 1992-2000. All Rights Reserved.
*
* See the file "license.txt" for information on usage and redistribution
*
* $Id$
*/
#ifndef _h_websSSL
#define _h_websSSL 1
/******************************** Description *********************************/
/*
* Header file for the GoAhead Patch for SSL. This defines the interface to
* integrate SSL into the GoAhead Webserver.
*/
/********************************* Includes ***********************************/
#ifdef OPENSSL
#define SSLEAY /* turn off a few special case MONOLITH macros */
#define USE_SOCKETS /* needed for the _O_BINARY defs in the MS world */
#include <openssl/ssl.h>
#else
#include <sslc.h>
#endif
#ifndef UEMF
#include "basic/basic.h"
#include "emf/emf.h"
#else
#include "uemf.h"
#endif
/********************************** Defines ***********************************/
typedef struct {
SSL *ssl;
BIO *bio;
} websSSL_t;
/******************************** Prototypes **********************************/
extern int websSSLOpen();
extern int websSSLIsOpen();
extern void websSSLClose();
extern int websSSLWrite(websSSL_t *wsp, char_t *buf, int nChars);
extern int websSSLGets(websSSL_t *wsp, char_t **buf);
extern int websSSLRead(websSSL_t *wsp, char_t *buf, int nChars);
extern int websSSLEof(websSSL_t *wsp);
extern int websSSLFree(websSSL_t *wsp);
extern int websSSLFlush(websSSL_t *wsp);
extern int websSSLSetKeyFile(char_t *keyFile);
extern int websSSLSetCertFile(char_t *certFile);
#endif /* _h_websSSL */
/*****************************************************************************/
+244
View File
@@ -0,0 +1,244 @@
/*
* websda.c -- Digest Access Authentication routines
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* See the file "license.txt" for usage and redistribution license requirements
*
* $Id$
*/
/******************************** Description *********************************/
/*
* Routines for generating DAA data. The module uses the
* "RSA Data Security, Inc. MD5 Message-Digest Algorithm" found in md5c.c
*/
/********************************* Includes ***********************************/
#ifndef CE
#include <time.h>
#endif
#include "websda.h"
#include "md5.h"
/******************************** Local Data **********************************/
#define RANDOMKEY T("onceuponatimeinparadise")
#define NONCE_SIZE 34
#define HASH_SIZE 16
/*********************************** Code *************************************/
/*
* websMD5binary returns the MD5 hash
*/
char *websMD5binary(unsigned char *buf, int length)
{
const char *hex = "0123456789abcdef";
MD5_CONTEXT md5ctx;
unsigned char hash[HASH_SIZE];
char *r, *strReturn;
char result[(HASH_SIZE * 2) + 1];
int i;
/*
* Take the MD5 hash of the string argument.
*/
MD5Init(&md5ctx);
MD5Update(&md5ctx, buf, (unsigned int)length);
MD5Final(hash, &md5ctx);
/*
* Prepare the resulting hash string
*/
for (i = 0, r = result; i < 16; i++) {
*r++ = hex[hash[i] >> 4];
*r++ = hex[hash[i] & 0xF];
}
/*
* Zero terminate the hash string
*/
*r = '\0';
/*
* Allocate a new copy of the hash string
*/
strReturn = balloc(B_L, sizeof(result));
strcpy(strReturn, result);
return strReturn;
}
/*****************************************************************************/
/*
* Convenience call to websMD5binary
* (Performs char_t to char conversion and back)
*/
char_t *websMD5(char_t *string)
{
char_t *strReturn;
a_assert(string && *string);
if (string && *string) {
char *strTemp, *strHash;
int nLen;
/*
* Convert input char_t string to char string
*/
nLen = gstrlen(string);
strTemp = ballocUniToAsc(string, nLen + 1);
/*
* Execute the digest calculation
*/
strHash = websMD5binary((unsigned char *)strTemp, nLen);
/*
* Convert the returned char string digest to a char_t string
*/
nLen = strlen(strHash);
strReturn = ballocAscToUni(strHash, nLen);
/*
* Free up the temporary allocated resources
*/
bfree(B_L, strTemp);
bfree(B_L, strHash);
} else {
strReturn = NULL;
}
return strReturn;
}
/******************************************************************************/
/*
* Get a Nonce value for passing along to the client. This function
* composes the string "RANDOMKEY:timestamp:myrealm" and
* calculates the MD5 digest placing it in output.
*/
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;
}
/******************************************************************************/
/*
* Get an Opaque value for passing along to the client
*/
char_t *websCalcOpaque(webs_t wp)
{
char_t *opaque;
a_assert(wp);
/*
* Temporary stub!
*/
opaque = bstrdup(B_L, T("5ccc069c403ebaf9f0171e9517f40e41"));
return opaque;
}
/******************************************************************************/
/*
* Get a Digest value using the MD5 algorithm
*/
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 */
}
/******************************************************************************/
+41
View File
@@ -0,0 +1,41 @@
/*
* websda.h -- GoAhead Digest Access Authentication public header
*
* Copyright (c) GoAhead Software Inc., 1992-2000. All Rights Reserved.
*
* See the file "license.txt" for information on usage and redistribution
*
* $Id$
*/
#ifndef _h_WEBSDA
#define _h_WEBSDA 1
/******************************** Description *********************************/
/*
* GoAhead Digest Access Authentication header. This defines the Digest
* access authentication public APIs. Include this header for files that
* use DAA functions
*/
/********************************* Includes ***********************************/
#ifndef UEMF
#include "basic/basic.h"
#include "emf/emf.h"
#else
#include "uemf.h"
#endif
#include "webs.h"
/****************************** Definitions ***********************************/
extern char_t *websCalcNonce(webs_t wp);
extern char_t *websCalcOpaque(webs_t wp);
extern char_t *websCalcDigest(webs_t wp);
#endif /* _h_WEBSDA */
/******************************************************************************/