mirror of
https://gitlab.rtems.org/rtems/rtos/rtems.git
synced 2026-09-20 06:09:18 +08:00
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:
@@ -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,
|
||||
|
||||
@@ -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 */
|
||||
|
||||
/******************************************************************************/
|
||||
@@ -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 */
|
||||
|
||||
/******************************************************************************/
|
||||
Reference in New Issue
Block a user