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

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,

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

View File

@@ -0,0 +1,641 @@
/*
* umui.c -- User Management GoForm Processing
*
* 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 provides GoForm functions for User management
*/
/********************************* Includes ***********************************/
#include "wsIntrn.h"
#include "um.h"
/********************************* Defines ************************************/
#define NONE_OPTION T("<NONE>")
#define MSG_START T("<body><h2>")
#define MSG_END T("</h2></body>")
/**************************** Forward Declarations ****************************/
static void formAddUser(webs_t wp, char_t *path, char_t *query);
static void formDeleteUser(webs_t wp, char_t *path, char_t *query);
static void formDisplayUser(webs_t wp, char_t *path, char_t *query);
static int aspGenerateUserList(int eid, webs_t wp,
int argc, char_t **argv);
static void formAddGroup(webs_t wp, char_t *path, char_t *query);
static void formDeleteGroup(webs_t wp, char_t *path, char_t *query);
static int aspGenerateGroupList(int eid, webs_t wp,
int argc, char_t **argv);
static void formAddAccessLimit(webs_t wp, char_t *path, char_t *query);
static void formDeleteAccessLimit(webs_t wp, char_t *path, char_t *query);
static int aspGenerateAccessLimitList(int eid, webs_t wp,
int argc, char_t **argv);
static int aspGenerateAccessMethodList(int eid, webs_t wp,
int argc, char_t **argv);
static int aspGeneratePrivilegeList(int eid, webs_t wp,
int argc, char_t **argv);
static void formSaveUserManagement(webs_t wp, char_t *path, char_t *query);
static void formLoadUserManagement(webs_t wp, char_t *path, char_t *query);
static void websMsgStart(webs_t wp);
static void websMsgEnd(webs_t wp);
/*********************************** Code *************************************/
/*
* Set up the User Management form handlers
*/
void formDefineUserMgmt(void)
{
websAspDefine(T("MakeGroupList"), aspGenerateGroupList);
websAspDefine(T("MakeUserList"), aspGenerateUserList);
websAspDefine(T("MakeAccessLimitList"), aspGenerateAccessLimitList);
websAspDefine(T("MakeAccessMethodList"), aspGenerateAccessMethodList);
websAspDefine(T("MakePrivilegeList"), aspGeneratePrivilegeList);
websFormDefine(T("AddUser"), formAddUser);
websFormDefine(T("DeleteUser"), formDeleteUser);
websFormDefine(T("DisplayUser"), formDisplayUser);
websFormDefine(T("AddGroup"), formAddGroup);
websFormDefine(T("DeleteGroup"), formDeleteGroup);
websFormDefine(T("AddAccessLimit"), formAddAccessLimit);
websFormDefine(T("DeleteAccessLimit"), formDeleteAccessLimit);
websFormDefine(T("SaveUserManagement"), formSaveUserManagement);
websFormDefine(T("LoadUserManagement"), formLoadUserManagement);
}
/******************************************************************************/
/*
* Add a user
*/
static void formAddUser(webs_t wp, char_t *path, char_t *query)
{
char_t *userid, *pass1, *pass2, *group, *enabled, *ok;
bool_t bDisable;
int nCheck;
a_assert(wp);
userid = websGetVar(wp, T("user"), T(""));
pass1 = websGetVar(wp, T("password"), T(""));
pass2 = websGetVar(wp, T("passconf"), T(""));
group = websGetVar(wp, T("group"), T(""));
enabled = websGetVar(wp, T("enabled"), T(""));
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Add User Cancelled"));
} else if (gstrcmp(pass1, pass2) != 0) {
websWrite(wp, T("Confirmation Password did not match."));
} else {
if (enabled && *enabled && (gstrcmp(enabled, T("on")) == 0)) {
bDisable = FALSE;
} else {
bDisable = TRUE;
}
nCheck = umAddUser(userid, pass1, group, 0, bDisable);
if (nCheck != 0) {
char_t * strError;
switch (nCheck) {
case UM_ERR_DUPLICATE:
strError = T("User already exists.");
break;
case UM_ERR_BAD_NAME:
strError = T("Invalid user name.");
break;
case UM_ERR_BAD_PASSWORD:
strError = T("Invalid password.");
break;
case UM_ERR_NOT_FOUND:
strError = T("Invalid or unselected group.");
break;
default:
strError = T("Error writing user record.");
break;
}
websWrite(wp, T("Unable to add user, \"%s\". %s"),
userid, strError);
} else {
websWrite(wp, T("User, \"%s\" was successfully added."),
userid);
}
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Delete a user
*/
static void formDeleteUser(webs_t wp, char_t *path, char_t *query)
{
char_t *userid, *ok;
a_assert(wp);
userid = websGetVar(wp, T("user"), T(""));
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Delete User Cancelled"));
} else if (umUserExists(userid) == FALSE) {
websWrite(wp, T("ERROR: User \"%s\" not found"), userid);
} else if (umGetUserProtected(userid)) {
websWrite(wp, T("ERROR: User, \"%s\" is delete-protected."), userid);
} else if (umDeleteUser(userid) != 0) {
websWrite(wp, T("ERROR: Unable to delete user, \"%s\" "), userid);
} else {
websWrite(wp, T("User, \"%s\" was successfully deleted."), userid);
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Display the user info
*/
static void formDisplayUser(webs_t wp, char_t *path, char_t *query)
{
char_t *userid, *ok, *temp;
bool_t enabled;
a_assert(wp);
userid = websGetVar(wp, T("user"), T(""));
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websWrite(wp, T("<body>"));
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Display User Cancelled"));
} else if (umUserExists(userid) == FALSE) {
websWrite(wp, T("ERROR: User <b>%s</b> not found.\n"), userid);
} else {
websWrite(wp, T("<h2>User ID: <b>%s</b></h2>\n"), userid);
temp = umGetUserGroup(userid);
websWrite(wp, T("<h3>User Group: <b>%s</b></h3>\n"), temp);
enabled = umGetUserEnabled(userid);
websWrite(wp, T("<h3>Enabled: <b>%d</b></h3>\n"), enabled);
}
websWrite(wp, T("</body>\n"));
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Generate HTML to create a list box containing the users
*/
static int aspGenerateUserList(int eid, webs_t wp, int argc, char_t **argv)
{
char_t *userid;
int row, nBytesSent, nBytes;
a_assert(wp);
nBytes = websWrite(wp,
T("<SELECT NAME=\"user\" SIZE=\"3\" TITLE=\"Select a User\">"));
row = 0;
userid = umGetFirstUser();
nBytesSent = 0;
while (userid && (nBytes > 0)) {
nBytes = websWrite(wp, T("<OPTION VALUE=\"%s\">%s\n"),
userid, userid);
userid = umGetNextUser(userid);
nBytesSent += nBytes;
}
nBytesSent += websWrite(wp, T("</SELECT>"));
return nBytesSent;
}
/******************************************************************************/
/*
* Add a group
*/
static void formAddGroup(webs_t wp, char_t *path, char_t *query)
{
char_t *group, *enabled, *privilege, *method, *ok, *pChar;
int nCheck;
short priv;
accessMeth_t am;
bool_t bDisable;
a_assert(wp);
group = websGetVar(wp, T("group"), T(""));
method = websGetVar(wp, T("method"), T(""));
enabled = websGetVar(wp, T("enabled"), T(""));
privilege = websGetVar(wp, T("privilege"), T(""));
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Add Group Cancelled."));
} else if ((group == NULL) || (*group == 0)) {
websWrite(wp, T("No Group Name was entered."));
} else if (umGroupExists(group)) {
websWrite(wp, T("ERROR: Group, \"%s\" already exists."), group);
} else {
if (privilege && *privilege) {
/*
* privilege is a mulitple <SELECT> var, and must be parsed.
* Values for these variables are space delimited.
*/
priv = 0;
for (pChar = privilege; *pChar; pChar++) {
if (*pChar == ' ') {
*pChar = '\0';
priv |= gatoi(privilege);
*pChar = ' ';
privilege = pChar + 1;
}
}
priv |= gatoi(privilege);
} else {
priv = 0;
}
if (method && *method) {
am = (accessMeth_t) gatoi(method);
} else {
am = AM_FULL;
}
if (enabled && *enabled && (gstrcmp(enabled, T("on")) == 0)) {
bDisable = FALSE;
} else {
bDisable = TRUE;
}
nCheck = umAddGroup(group, priv, am, 0, bDisable);
if (nCheck != 0) {
websWrite(wp, T("Unable to add group, \"%s\", code: %d "),
group, nCheck);
} else {
websWrite(wp, T("Group, \"%s\" was successfully added."),
group);
}
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Delete a group
*/
static void formDeleteGroup(webs_t wp, char_t *path, char_t *query)
{
char_t *group, *ok;
a_assert(wp);
group = websGetVar(wp, T("group"), T(""));
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Delete Group Cancelled."));
} else if ((group == NULL) || (*group == '\0')) {
websWrite(wp, T("ERROR: No group was selected."));
} else if (umGetGroupProtected(group)) {
websWrite(wp, T("ERROR: Group, \"%s\" is delete-protected."), group);
} else if (umGetGroupInUse(group)) {
websWrite(wp, T("ERROR: Group, \"%s\" is being used."), group);
} else if (umDeleteGroup(group) != 0) {
websWrite(wp, T("ERROR: Unable to delete group, \"%s\" "), group);
} else {
websWrite(wp, T("Group, \"%s\" was successfully deleted."), group);
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Generate HTML to create a list box containing the groups
*/
static int aspGenerateGroupList(int eid, webs_t wp, int argc, char_t **argv)
{
char_t *group;
int row, nBytesSent, nBytes;
a_assert(wp);
row = 0;
nBytesSent = 0;
nBytes = websWrite(wp,
T("<SELECT NAME=\"group\" SIZE=\"3\" TITLE=\"Select a Group\">"));
/*
* Add a special "<NONE>" element to allow de-selection
*/
nBytes = websWrite(wp, T("<OPTION VALUE=\"\">[NONE]\n"));
group = umGetFirstGroup();
while (group && (nBytes > 0)) {
nBytes = websWrite(wp, T("<OPTION VALUE=\"%s\">%s\n"), group, group);
group = umGetNextGroup(group);
nBytesSent += nBytes;
}
nBytesSent += websWrite(wp, T("</SELECT>"));
return nBytesSent;
}
/******************************************************************************/
/*
* Add an access limit
*/
static void formAddAccessLimit(webs_t wp, char_t *path, char_t *query)
{
char_t *url, *method, *group, *secure, *ok;
int nCheck;
accessMeth_t am;
short nSecure;
a_assert(wp);
url = websGetVar(wp, T("url"), T(""));
group = websGetVar(wp, T("group"), T(""));
method = websGetVar(wp, T("method"), T(""));
secure = websGetVar(wp, T("secure"), T(""));
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Add Access Limit Cancelled."));
} else if ((url == NULL) || (*url == 0)) {
websWrite(wp, T("ERROR: No URL was entered."));
} else if (umAccessLimitExists(url)) {
websWrite(wp, T("ERROR: An Access Limit for [%s] already exists."),
url);
} else {
if (method && *method) {
am = (accessMeth_t) gatoi(method);
} else {
am = AM_FULL;
}
if (secure && *secure) {
nSecure = (short) gatoi(secure);
} else {
nSecure = 0;
}
nCheck = umAddAccessLimit(url, am, nSecure, group);
if (nCheck != 0) {
websWrite(wp, T("Unable to add Access Limit for [%s]"), url);
} else {
websWrite(wp, T("Access limit for [%s], was successfully added."),
url);
}
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Delete an Access Limit
*/
static void formDeleteAccessLimit(webs_t wp, char_t *path, char_t *query)
{
char_t *url, *ok;
a_assert(wp);
url = websGetVar(wp, T("url"), T(""));
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Delete Access Limit Cancelled"));
} else if (umDeleteAccessLimit(url) != 0) {
websWrite(wp, T("ERROR: Unable to delete Access Limit for [%s]"),
url);
} else {
websWrite(wp, T("Access Limit for [%s], was successfully deleted."),
url);
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Generate HTML to create a list box containing the access limits
*/
static int aspGenerateAccessLimitList(int eid, webs_t wp,
int argc, char_t **argv)
{
char_t *url;
int row, nBytesSent, nBytes;
a_assert(wp);
row = nBytesSent = 0;
url = umGetFirstAccessLimit();
nBytes = websWrite(wp,
T("<SELECT NAME=\"url\" SIZE=\"3\" TITLE=\"Select a URL\">"));
while (url && (nBytes > 0)) {
nBytes = websWrite(wp, T("<OPTION VALUE=\"%s\">%s\n"), url, url);
url = umGetNextAccessLimit(url);
nBytesSent += nBytes;
}
nBytesSent += websWrite(wp, T("</SELECT>"));
return nBytesSent;
}
/******************************************************************************/
/*
* Generate HTML to create a list box containing the access methods
*/
static int aspGenerateAccessMethodList(int eid, webs_t wp,
int argc, char_t **argv)
{
int nBytes;
a_assert(wp);
nBytes = websWrite(wp,
T("<SELECT NAME=\"method\" SIZE=\"3\" TITLE=\"Select a Method\">"));
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">FULL ACCESS\n"),
AM_FULL);
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">BASIC ACCESS\n"),
AM_BASIC);
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\" SELECTED>DIGEST ACCESS\n"),
AM_DIGEST);
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">NO ACCESS\n"),
AM_NONE);
nBytes += websWrite(wp, T("</SELECT>"));
return nBytes;
}
/******************************************************************************/
/*
* Generate HTML to create a list box containing privileges
*/
static int aspGeneratePrivilegeList(int eid, webs_t wp,
int argc, char_t **argv)
{
int nBytes;
a_assert(wp);
nBytes = websWrite(wp, T("<SELECT NAME=\"privilege\" SIZE=\"3\" "));
nBytes += websWrite(wp, T("MULTIPLE TITLE=\"Choose Privileges\">"));
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">READ\n"), PRIV_READ);
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">EXECUTE\n"), PRIV_WRITE);
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">ADMINISTRATE\n"),
PRIV_ADMIN);
nBytes += websWrite(wp, T("</SELECT>"));
return nBytes;
}
/******************************************************************************/
/*
* Save the user management configuration to a file
*/
static void formSaveUserManagement(webs_t wp, char_t *path, char_t *query)
{
char_t *ok;
a_assert(wp);
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Save Cancelled."));
} else if (umCommit(NULL) != 0) {
websWrite(wp, T("ERROR: Unable to save user configuration."));
} else {
websWrite(wp, T("User configuration was saved successfully."));
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Load the user management configuration from a file
*/
static void formLoadUserManagement(webs_t wp, char_t *path, char_t *query)
{
char_t *ok;
a_assert(wp);
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Load Cancelled."));
} else if (umRestore(NULL) != 0) {
websWrite(wp, T("ERROR: Unable to load user configuration."));
} else {
websWrite(wp, T("User configuration was re-loaded successfully."));
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Message start and end convenience functions
*/
static void websMsgStart(webs_t wp)
{
websWrite(wp, MSG_START);
}
static void websMsgEnd(webs_t wp)
{
websWrite(wp, MSG_END);
}
/******************************************************************************/

View File

@@ -0,0 +1,706 @@
/*
* websSSL.c -- SSL envrionment creation
*
* 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 a patch into SSL implementations for the webs
* module.
*/
/********************************* Includes ***********************************/
#include "wsIntrn.h"
#include "webs.h"
#include "websSSL.h"
/******************************* Definitions **********************************/
#define DEFAULT_CERT_FILE "./server.pem"
#define DEFAULT_KEY_FILE "./certs/cakey.pem"
#define DEFAULT_CA_FILE "./certs/cacert.pem"
#define DEFAULT_CA_PATH "./certs/"
#define SSL_PORT 443
/*
* Define the components of the apps_startup() macro
*/
#ifdef SIGPIPE
#define do_pipe_sig() signal(SIGPIPE,SIG_IGN)
#else
#define do_pipe_sig()
#endif
#ifdef OPENSSL
#define SSLC_add_all_algorithms() SSLeay_add_all_algorithms()
#else
extern void SSLC_add_all_algorithms(void);
#endif
/*
* Define the apps_startup() macro
*/
# if defined(MSDOS) || defined(WIN16) || defined(WIN32)
# ifdef _O_BINARY
# define apps_startup() \
_fmode=_O_BINARY; do_pipe_sig(); CRYPTO_malloc_init(); \
SSLC_add_all_algorithms()
# else
# define apps_startup() \
_fmode=O_BINARY; do_pipe_sig(); CRYPTO_malloc_init(); \
SSLC_add_all_algorithms()
# endif
# else
# define apps_startup() do_pipe_sig(); SSLC_add_all_algorithms();
# endif
/*************************** Forward Declarations *****************************/
static int websSSLSetCertStuff(SSL_CTX *ctx,
char *cert_file,
char *key_file);
static int websSSLVerifyCallback(int ok, X509_STORE_CTX *ctx);
static RSA *websSSLTempRSACallback(SSL *s, int is_export, int keylength);
static int websSSLReadEvent (webs_t wp);
static int websSSLAccept(int sid, char *ipaddr, int port, int listenSid);
static void websSSLSocketEvent(int sid, int mask, int data);
/*********************************** Locals ***********************************/
static int sslListenSock = -1; /* Listen socket */
static SSL_CTX *sslctx = NULL;
/******************************************************************************/
/*
* Start up the SSL Context for the application, and start a listen on the
* SSL port (usually 443, and defined by SSL_PORT)
* Return 0 on success, -1 on failure.
*/
int websSSLOpen()
{
char *certFile, *keyFile, *CApath, *CAfile;
SSL_METHOD *meth;
/*
* Install and initialize the SSL library
*/
apps_startup();
trace(7, T("SSL: Initializing SSL\n"));
#ifdef SSLC
SSL_library_init();
#endif
SSL_load_error_strings();
#ifdef OPENSSL
SSLeay_add_ssl_algorithms();
#endif
/*
* Important! Enable both SSL versions 2 and 3
*/
meth = SSLv23_server_method();
sslctx = SSL_CTX_new(meth);
a_assert(sslctx);
if (sslctx == NULL) {
trace(2, T("SSL: Unable to create SSL context!\n"));
return -1;
}
/*
* Adjust some SSL Context variables
*/
SSL_CTX_set_quiet_shutdown(sslctx, 1);
SSL_CTX_set_options(sslctx, 0);
SSL_CTX_sess_set_cache_size(sslctx, 128);
/*
* Set the certificate verification locations
*/
CApath = DEFAULT_CA_PATH;
CAfile = DEFAULT_CA_FILE;
if ((!SSL_CTX_load_verify_locations(sslctx, CAfile, CApath)) ||
(!SSL_CTX_set_default_verify_paths(sslctx))) {
trace(2, T("SSL: Unable to set cert verification locations!\n"));
websSSLClose();
return -1;
}
/*
* Set the certificate and key files for the SSL context
*/
certFile = DEFAULT_CERT_FILE;
keyFile = NULL;
if (websSSLSetCertStuff(sslctx, certFile, keyFile) != 0) {
websSSLClose();
return -1;
}
/*
* Set the RSA callback for the SSL context
*/
SSL_CTX_set_tmp_rsa_callback(sslctx, websSSLTempRSACallback);
/*
* Set the verification callback for the SSL context
*/
SSL_CTX_set_verify(sslctx, SSL_VERIFY_NONE, websSSLVerifyCallback);
/*
* Set the certificate authority list for the client
*/
SSL_CTX_set_client_CA_list(sslctx, SSL_load_client_CA_file(CAfile));
/*
* Open the socket
*/
sslListenSock = socketOpenConnection(NULL, SSL_PORT,
websSSLAccept, SOCKET_BLOCK);
if (sslListenSock < 0) {
trace(2, T("SSL: Unable to open SSL socket on port <%d>!\n"),
SSL_PORT);
return -1;
}
return 0;
}
/******************************************************************************/
/*
* Return TRUE if websSSL has been opened
*/
int websSSLIsOpen()
{
return (sslListenSock != -1);
}
/******************************************************************************/
/*
* Stops the SSL
*/
void websSSLClose()
{
trace(7, T("SSL: Closing SSL\n"));
if (sslctx != NULL) {
SSL_CTX_free(sslctx);
sslctx = NULL;
}
if (sslListenSock != -1) {
socketCloseConnection(sslListenSock);
sslListenSock = -1;
}
#ifdef SSLC
SSL_library_cleanup();
#endif
}
/******************************************************************************/
/*
* Accept a connection
*/
int websSSLAccept(int sid, char *ipaddr, int port, int listenSid)
{
webs_t wp;
int wid;
a_assert(ipaddr && *ipaddr);
a_assert(sid >= 0);
a_assert(port >= 0);
/*
* Allocate a new handle for this accepted connection. This will allocate
* a webs_t structure in the webs[] list
*/
if ((wid = websAlloc(sid)) < 0) {
return -1;
}
wp = webs[wid];
a_assert(wp);
wp->listenSid = listenSid;
ascToUni(wp->ipaddr, ipaddr, min(sizeof(wp->ipaddr), strlen(ipaddr)+1));
/*
* Check if this is a request from a browser on this system. This is useful
* to know for permitting administrative operations only for local access
*/
if (gstrcmp(wp->ipaddr, T("127.0.0.1")) == 0 ||
gstrcmp(wp->ipaddr, websIpaddr) == 0 ||
gstrcmp(wp->ipaddr, websHost) == 0) {
wp->flags |= WEBS_LOCAL_REQUEST;
}
/*
* Since the acceptance came in on this channel, it must be secure
*/
wp->flags |= WEBS_SECURE;
/*
* Arrange for websSocketEvent to be called when read data is available
*/
socketCreateHandler(sid, SOCKET_READABLE, websSSLSocketEvent, (int) wp);
/*
* Arrange for a timeout to kill hung requests
*/
wp->timeout = emfSchedCallback(WEBS_TIMEOUT, websTimeout, (void *) wp);
trace(8, T("webs: accept request\n"));
return 0;
}
/******************************************************************************/
/*
* The webs socket handler. Called in response to I/O. We just pass control
* to the relevant read or write handler. A pointer to the webs structure
* is passed as an (int) in iwp.
*/
static void websSSLSocketEvent(int sid, int mask, int iwp)
{
webs_t wp;
wp = (webs_t) iwp;
a_assert(wp);
if (! websValid(wp)) {
return;
}
if (mask & SOCKET_READABLE) {
websSSLReadEvent(wp);
}
if (mask & SOCKET_WRITABLE) {
if (wp->writeSocket) {
(*wp->writeSocket)(wp);
}
}
}
/******************************************************************************/
/*
* Handler for SSL Read Events
*/
static int websSSLReadEvent (webs_t wp)
{
int ret, sock;
socket_t *sptr;
SSL *ssl;
BIO *bio, *bioSSL, *bioSock;
#ifdef DEV
const char *ciphers;
#endif
a_assert (wp);
a_assert(websValid(wp));
sptr = socketPtr(wp->sid);
a_assert(sptr);
sock = sptr->sock;
/*
* Create a new BIO and SSL session for this web request
*/
bio = BIO_new(BIO_f_buffer());
a_assert(bio);
if (!BIO_set_write_buffer_size(bio, 128)) {
return -1;
}
ssl = (SSL *) SSL_new(sslctx);
a_assert(ssl);
if (ssl == NULL) {
return -1;
}
SSL_set_session(ssl, NULL);
bioSSL = BIO_new(BIO_f_ssl());
a_assert(bioSSL);
bioSock = BIO_new_socket(sock, BIO_NOCLOSE);
a_assert(bioSock);
SSL_set_bio(ssl, bioSock, bioSock);
SSL_set_accept_state(ssl);
ret = BIO_set_ssl(bioSSL, ssl, BIO_CLOSE);
BIO_push(bio, bioSSL);
#ifdef DEV
ciphers = SSL_get_cipher_list(ssl, 10);
#endif
/*
* Create the SSL data structure in the wp.
*/
#ifdef WEBS_SSL_SUPPORT
wp->wsp = balloc(B_L, sizeof(websSSL_t));
a_assert (wp->wsp);
(wp->wsp)->bio = bio;
(wp->wsp)->ssl = ssl;
#endif
/*
* Call the default Read Event
*/
websReadEvent(wp);
return ret;
}
/******************************************************************************/
/*
* SSL Verification Callback
*/
static int sslVerifyDepth = 0;
static int sslVerifyError = X509_V_OK;
int websSSLVerifyCallback(int ok, X509_STORE_CTX *ctx)
{
char buf[256];
X509 *errCert;
int err;
int depth;
errCert = X509_STORE_CTX_get_current_cert(ctx);
err = X509_STORE_CTX_get_error(ctx);
depth = X509_STORE_CTX_get_error_depth(ctx);
X509_NAME_oneline(X509_get_subject_name(errCert), buf, 256);
if (!ok) {
if (sslVerifyDepth >= depth) {
ok = 1;
sslVerifyError = X509_V_OK;
} else {
ok=0;
sslVerifyError = X509_V_ERR_CERT_CHAIN_TOO_LONG;
}
}
switch (err) {
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
#ifdef OPENSSL
X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
#endif
break;
case X509_V_ERR_CERT_NOT_YET_VALID:
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
case X509_V_ERR_CERT_HAS_EXPIRED:
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
break;
}
return ok;
}
/******************************************************************************/
/*
* Set the SSL certificate and key for the SSL context
*/
int websSSLSetCertStuff(SSL_CTX *ctx, char *certFile, char *keyFile)
{
a_assert (ctx);
a_assert (certFile);
if (certFile != NULL) {
if (SSL_CTX_use_certificate_file(ctx, certFile,
SSL_FILETYPE_PEM) <= 0) {
trace(2, T("SSL: Unable to set certificate file <%s>\n"),
certFile);
return -1;
}
if (keyFile == NULL) {
keyFile = certFile;
}
if (SSL_CTX_use_PrivateKey_file(ctx, keyFile, SSL_FILETYPE_PEM) <= 0) {
trace(2, T("SSL: Unable to set private key file <%s>\n"),
keyFile);
return -1;
}
/*
* Now we know that a key and cert have been set against
* the SSL context
*/
if (!SSL_CTX_check_private_key(ctx)) {
trace(2, T("SSL: Check of private key file <%s> FAILED!\n"),
keyFile);
return -1;
}
}
return 0;
}
/******************************************************************************/
/*
* Set certificate file for SSL context
*/
int websSSLSetCertFile(char_t *certFile)
{
a_assert (sslctx);
a_assert (certFile);
if (sslctx == NULL) {
return -1;
}
if (SSL_CTX_use_certificate_file(sslctx, certFile,
SSL_FILETYPE_PEM) <= 0) {
return -1;
}
/*
* Confirm that the certificate and the private key jive.
*/
if (!SSL_CTX_check_private_key(sslctx)) {
return -1;
}
return 0;
}
/******************************************************************************/
/*
* Set key file for SSL context
*/
int websSSLSetKeyFile(char_t *keyFile)
{
a_assert (sslctx);
a_assert (keyFile);
if (sslctx == NULL) {
return -1;
}
if (SSL_CTX_use_PrivateKey_file(sslctx, keyFile, SSL_FILETYPE_PEM) <= 0) {
return -1;
}
/*
* Confirm that the certificate and the private key jive.
*/
if (!SSL_CTX_check_private_key(sslctx)) {
return -1;
}
return 0;
}
#ifdef SSLC
extern RSA *RSA_new(void);
#endif
/******************************************************************************/
/*
* the Temporary RSA callback
*/
static RSA *websSSLTempRSACallback(SSL *ssl, int isExport, int keyLength)
{
static RSA *rsaTemp = NULL;
if (rsaTemp == NULL) {
#ifdef OPENSSL
rsaTemp = RSA_generate_key(keyLength, RSA_F4, NULL, NULL);
#endif
#ifdef SSLC
rsaTemp = RSA_new();
#endif
}
return rsaTemp;
}
/******************************************************************************/
/*
* Free SSL resources
*/
int websSSLFree(websSSL_t *wsp)
{
if (wsp == NULL) {
return -1;
}
/*
* Make sure we re-use sessions
*/
if (wsp->ssl != NULL) {
SSL_set_shutdown(wsp->ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
}
if (wsp->bio != NULL) {
BIO_free_all(wsp->bio);
}
bfree(B_L, wsp);
return 0;
}
/******************************************************************************/
/*
* Return Eof for the SSL BIO
*/
int websSSLEof(websSSL_t *wsp)
{
a_assert(wsp);
if ((wsp == NULL) || (wsp->bio == NULL)) {
return -1;
}
return BIO_eof(wsp->bio);
}
/******************************************************************************/
/*
* Perform a read of the SSL BIO
*/
int websSSLRead(websSSL_t *wsp, char_t *buf, int len)
{
a_assert(wsp);
a_assert(buf);
if ((wsp == NULL) || (wsp->bio == NULL)) {
return -1;
}
return BIO_read(wsp->bio, buf, len);
}
/******************************************************************************/
/*
* Perform a gets of the SSL BIO, returning an balloc'ed string
*/
#define BUF_BLOCK 256
int websSSLGets(websSSL_t *wsp, char_t **buf)
{
int rc, len, lenBuf;
char c;
a_assert(wsp);
a_assert(buf);
lenBuf = 0;
len = 0;
if ((wsp == NULL) || (wsp->bio == NULL)) {
return -1;
}
while (1) {
if ((rc = BIO_read(wsp->bio, &c, 1)) < 0) {
return rc;
}
if (rc == 0) {
/*
* If there is a partial line and we are at EOF, pretend we saw a '\n'
*/
if (len > 0 && BIO_eof(wsp->bio)) {
c = '\n';
} else {
return -1;
}
}
/*
* If a newline is seen, return the data excluding the new line to the
* caller. If carriage return is seen, just eat it.
*/
if (c == '\n') {
if ((len > 0) && (len < lenBuf)) {
(*buf)[len] = 0;
}
return len;
} else if (c == '\r') {
continue;
}
/*
* Append character to buf
*/
if (len >= lenBuf) {
lenBuf += BUF_BLOCK;
*buf = brealloc(B_L, *buf, lenBuf);
}
a_assert(*buf);
(*buf)[len] = c;
len++;
}
}
/******************************************************************************/
/*
* Perform a write to the SSL BIO
*/
int websSSLWrite(websSSL_t *wsp, char_t *buf, int len)
{
a_assert(wsp);
a_assert(buf);
if ((wsp == NULL) || (wsp->bio == NULL)) {
return -1;
}
return BIO_write(wsp->bio, buf, len);
}
/******************************************************************************/
/*
* Perform a flush of the SSL BIO
*/
int websSSLFlush(websSSL_t *wsp)
{
a_assert(wsp);
if ((wsp == NULL) || (wsp->bio == NULL)) {
return -1;
}
return BIO_flush(wsp->bio);
}
/******************************************************************************/

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 */
/*****************************************************************************/

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 */
}
/******************************************************************************/

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 */
/******************************************************************************/

331
cpukit/httpd/cgi.c Normal file
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);
}
}
}
}
/******************************************************************************/

1044
cpukit/httpd/sockGen.c Normal file

File diff suppressed because it is too large Load Diff

641
cpukit/httpd/umui.c Normal file
View File

@@ -0,0 +1,641 @@
/*
* umui.c -- User Management GoForm Processing
*
* 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 provides GoForm functions for User management
*/
/********************************* Includes ***********************************/
#include "wsIntrn.h"
#include "um.h"
/********************************* Defines ************************************/
#define NONE_OPTION T("<NONE>")
#define MSG_START T("<body><h2>")
#define MSG_END T("</h2></body>")
/**************************** Forward Declarations ****************************/
static void formAddUser(webs_t wp, char_t *path, char_t *query);
static void formDeleteUser(webs_t wp, char_t *path, char_t *query);
static void formDisplayUser(webs_t wp, char_t *path, char_t *query);
static int aspGenerateUserList(int eid, webs_t wp,
int argc, char_t **argv);
static void formAddGroup(webs_t wp, char_t *path, char_t *query);
static void formDeleteGroup(webs_t wp, char_t *path, char_t *query);
static int aspGenerateGroupList(int eid, webs_t wp,
int argc, char_t **argv);
static void formAddAccessLimit(webs_t wp, char_t *path, char_t *query);
static void formDeleteAccessLimit(webs_t wp, char_t *path, char_t *query);
static int aspGenerateAccessLimitList(int eid, webs_t wp,
int argc, char_t **argv);
static int aspGenerateAccessMethodList(int eid, webs_t wp,
int argc, char_t **argv);
static int aspGeneratePrivilegeList(int eid, webs_t wp,
int argc, char_t **argv);
static void formSaveUserManagement(webs_t wp, char_t *path, char_t *query);
static void formLoadUserManagement(webs_t wp, char_t *path, char_t *query);
static void websMsgStart(webs_t wp);
static void websMsgEnd(webs_t wp);
/*********************************** Code *************************************/
/*
* Set up the User Management form handlers
*/
void formDefineUserMgmt(void)
{
websAspDefine(T("MakeGroupList"), aspGenerateGroupList);
websAspDefine(T("MakeUserList"), aspGenerateUserList);
websAspDefine(T("MakeAccessLimitList"), aspGenerateAccessLimitList);
websAspDefine(T("MakeAccessMethodList"), aspGenerateAccessMethodList);
websAspDefine(T("MakePrivilegeList"), aspGeneratePrivilegeList);
websFormDefine(T("AddUser"), formAddUser);
websFormDefine(T("DeleteUser"), formDeleteUser);
websFormDefine(T("DisplayUser"), formDisplayUser);
websFormDefine(T("AddGroup"), formAddGroup);
websFormDefine(T("DeleteGroup"), formDeleteGroup);
websFormDefine(T("AddAccessLimit"), formAddAccessLimit);
websFormDefine(T("DeleteAccessLimit"), formDeleteAccessLimit);
websFormDefine(T("SaveUserManagement"), formSaveUserManagement);
websFormDefine(T("LoadUserManagement"), formLoadUserManagement);
}
/******************************************************************************/
/*
* Add a user
*/
static void formAddUser(webs_t wp, char_t *path, char_t *query)
{
char_t *userid, *pass1, *pass2, *group, *enabled, *ok;
bool_t bDisable;
int nCheck;
a_assert(wp);
userid = websGetVar(wp, T("user"), T(""));
pass1 = websGetVar(wp, T("password"), T(""));
pass2 = websGetVar(wp, T("passconf"), T(""));
group = websGetVar(wp, T("group"), T(""));
enabled = websGetVar(wp, T("enabled"), T(""));
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Add User Cancelled"));
} else if (gstrcmp(pass1, pass2) != 0) {
websWrite(wp, T("Confirmation Password did not match."));
} else {
if (enabled && *enabled && (gstrcmp(enabled, T("on")) == 0)) {
bDisable = FALSE;
} else {
bDisable = TRUE;
}
nCheck = umAddUser(userid, pass1, group, 0, bDisable);
if (nCheck != 0) {
char_t * strError;
switch (nCheck) {
case UM_ERR_DUPLICATE:
strError = T("User already exists.");
break;
case UM_ERR_BAD_NAME:
strError = T("Invalid user name.");
break;
case UM_ERR_BAD_PASSWORD:
strError = T("Invalid password.");
break;
case UM_ERR_NOT_FOUND:
strError = T("Invalid or unselected group.");
break;
default:
strError = T("Error writing user record.");
break;
}
websWrite(wp, T("Unable to add user, \"%s\". %s"),
userid, strError);
} else {
websWrite(wp, T("User, \"%s\" was successfully added."),
userid);
}
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Delete a user
*/
static void formDeleteUser(webs_t wp, char_t *path, char_t *query)
{
char_t *userid, *ok;
a_assert(wp);
userid = websGetVar(wp, T("user"), T(""));
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Delete User Cancelled"));
} else if (umUserExists(userid) == FALSE) {
websWrite(wp, T("ERROR: User \"%s\" not found"), userid);
} else if (umGetUserProtected(userid)) {
websWrite(wp, T("ERROR: User, \"%s\" is delete-protected."), userid);
} else if (umDeleteUser(userid) != 0) {
websWrite(wp, T("ERROR: Unable to delete user, \"%s\" "), userid);
} else {
websWrite(wp, T("User, \"%s\" was successfully deleted."), userid);
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Display the user info
*/
static void formDisplayUser(webs_t wp, char_t *path, char_t *query)
{
char_t *userid, *ok, *temp;
bool_t enabled;
a_assert(wp);
userid = websGetVar(wp, T("user"), T(""));
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websWrite(wp, T("<body>"));
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Display User Cancelled"));
} else if (umUserExists(userid) == FALSE) {
websWrite(wp, T("ERROR: User <b>%s</b> not found.\n"), userid);
} else {
websWrite(wp, T("<h2>User ID: <b>%s</b></h2>\n"), userid);
temp = umGetUserGroup(userid);
websWrite(wp, T("<h3>User Group: <b>%s</b></h3>\n"), temp);
enabled = umGetUserEnabled(userid);
websWrite(wp, T("<h3>Enabled: <b>%d</b></h3>\n"), enabled);
}
websWrite(wp, T("</body>\n"));
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Generate HTML to create a list box containing the users
*/
static int aspGenerateUserList(int eid, webs_t wp, int argc, char_t **argv)
{
char_t *userid;
int row, nBytesSent, nBytes;
a_assert(wp);
nBytes = websWrite(wp,
T("<SELECT NAME=\"user\" SIZE=\"3\" TITLE=\"Select a User\">"));
row = 0;
userid = umGetFirstUser();
nBytesSent = 0;
while (userid && (nBytes > 0)) {
nBytes = websWrite(wp, T("<OPTION VALUE=\"%s\">%s\n"),
userid, userid);
userid = umGetNextUser(userid);
nBytesSent += nBytes;
}
nBytesSent += websWrite(wp, T("</SELECT>"));
return nBytesSent;
}
/******************************************************************************/
/*
* Add a group
*/
static void formAddGroup(webs_t wp, char_t *path, char_t *query)
{
char_t *group, *enabled, *privilege, *method, *ok, *pChar;
int nCheck;
short priv;
accessMeth_t am;
bool_t bDisable;
a_assert(wp);
group = websGetVar(wp, T("group"), T(""));
method = websGetVar(wp, T("method"), T(""));
enabled = websGetVar(wp, T("enabled"), T(""));
privilege = websGetVar(wp, T("privilege"), T(""));
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Add Group Cancelled."));
} else if ((group == NULL) || (*group == 0)) {
websWrite(wp, T("No Group Name was entered."));
} else if (umGroupExists(group)) {
websWrite(wp, T("ERROR: Group, \"%s\" already exists."), group);
} else {
if (privilege && *privilege) {
/*
* privilege is a mulitple <SELECT> var, and must be parsed.
* Values for these variables are space delimited.
*/
priv = 0;
for (pChar = privilege; *pChar; pChar++) {
if (*pChar == ' ') {
*pChar = '\0';
priv |= gatoi(privilege);
*pChar = ' ';
privilege = pChar + 1;
}
}
priv |= gatoi(privilege);
} else {
priv = 0;
}
if (method && *method) {
am = (accessMeth_t) gatoi(method);
} else {
am = AM_FULL;
}
if (enabled && *enabled && (gstrcmp(enabled, T("on")) == 0)) {
bDisable = FALSE;
} else {
bDisable = TRUE;
}
nCheck = umAddGroup(group, priv, am, 0, bDisable);
if (nCheck != 0) {
websWrite(wp, T("Unable to add group, \"%s\", code: %d "),
group, nCheck);
} else {
websWrite(wp, T("Group, \"%s\" was successfully added."),
group);
}
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Delete a group
*/
static void formDeleteGroup(webs_t wp, char_t *path, char_t *query)
{
char_t *group, *ok;
a_assert(wp);
group = websGetVar(wp, T("group"), T(""));
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Delete Group Cancelled."));
} else if ((group == NULL) || (*group == '\0')) {
websWrite(wp, T("ERROR: No group was selected."));
} else if (umGetGroupProtected(group)) {
websWrite(wp, T("ERROR: Group, \"%s\" is delete-protected."), group);
} else if (umGetGroupInUse(group)) {
websWrite(wp, T("ERROR: Group, \"%s\" is being used."), group);
} else if (umDeleteGroup(group) != 0) {
websWrite(wp, T("ERROR: Unable to delete group, \"%s\" "), group);
} else {
websWrite(wp, T("Group, \"%s\" was successfully deleted."), group);
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Generate HTML to create a list box containing the groups
*/
static int aspGenerateGroupList(int eid, webs_t wp, int argc, char_t **argv)
{
char_t *group;
int row, nBytesSent, nBytes;
a_assert(wp);
row = 0;
nBytesSent = 0;
nBytes = websWrite(wp,
T("<SELECT NAME=\"group\" SIZE=\"3\" TITLE=\"Select a Group\">"));
/*
* Add a special "<NONE>" element to allow de-selection
*/
nBytes = websWrite(wp, T("<OPTION VALUE=\"\">[NONE]\n"));
group = umGetFirstGroup();
while (group && (nBytes > 0)) {
nBytes = websWrite(wp, T("<OPTION VALUE=\"%s\">%s\n"), group, group);
group = umGetNextGroup(group);
nBytesSent += nBytes;
}
nBytesSent += websWrite(wp, T("</SELECT>"));
return nBytesSent;
}
/******************************************************************************/
/*
* Add an access limit
*/
static void formAddAccessLimit(webs_t wp, char_t *path, char_t *query)
{
char_t *url, *method, *group, *secure, *ok;
int nCheck;
accessMeth_t am;
short nSecure;
a_assert(wp);
url = websGetVar(wp, T("url"), T(""));
group = websGetVar(wp, T("group"), T(""));
method = websGetVar(wp, T("method"), T(""));
secure = websGetVar(wp, T("secure"), T(""));
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Add Access Limit Cancelled."));
} else if ((url == NULL) || (*url == 0)) {
websWrite(wp, T("ERROR: No URL was entered."));
} else if (umAccessLimitExists(url)) {
websWrite(wp, T("ERROR: An Access Limit for [%s] already exists."),
url);
} else {
if (method && *method) {
am = (accessMeth_t) gatoi(method);
} else {
am = AM_FULL;
}
if (secure && *secure) {
nSecure = (short) gatoi(secure);
} else {
nSecure = 0;
}
nCheck = umAddAccessLimit(url, am, nSecure, group);
if (nCheck != 0) {
websWrite(wp, T("Unable to add Access Limit for [%s]"), url);
} else {
websWrite(wp, T("Access limit for [%s], was successfully added."),
url);
}
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Delete an Access Limit
*/
static void formDeleteAccessLimit(webs_t wp, char_t *path, char_t *query)
{
char_t *url, *ok;
a_assert(wp);
url = websGetVar(wp, T("url"), T(""));
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Delete Access Limit Cancelled"));
} else if (umDeleteAccessLimit(url) != 0) {
websWrite(wp, T("ERROR: Unable to delete Access Limit for [%s]"),
url);
} else {
websWrite(wp, T("Access Limit for [%s], was successfully deleted."),
url);
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Generate HTML to create a list box containing the access limits
*/
static int aspGenerateAccessLimitList(int eid, webs_t wp,
int argc, char_t **argv)
{
char_t *url;
int row, nBytesSent, nBytes;
a_assert(wp);
row = nBytesSent = 0;
url = umGetFirstAccessLimit();
nBytes = websWrite(wp,
T("<SELECT NAME=\"url\" SIZE=\"3\" TITLE=\"Select a URL\">"));
while (url && (nBytes > 0)) {
nBytes = websWrite(wp, T("<OPTION VALUE=\"%s\">%s\n"), url, url);
url = umGetNextAccessLimit(url);
nBytesSent += nBytes;
}
nBytesSent += websWrite(wp, T("</SELECT>"));
return nBytesSent;
}
/******************************************************************************/
/*
* Generate HTML to create a list box containing the access methods
*/
static int aspGenerateAccessMethodList(int eid, webs_t wp,
int argc, char_t **argv)
{
int nBytes;
a_assert(wp);
nBytes = websWrite(wp,
T("<SELECT NAME=\"method\" SIZE=\"3\" TITLE=\"Select a Method\">"));
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">FULL ACCESS\n"),
AM_FULL);
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">BASIC ACCESS\n"),
AM_BASIC);
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\" SELECTED>DIGEST ACCESS\n"),
AM_DIGEST);
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">NO ACCESS\n"),
AM_NONE);
nBytes += websWrite(wp, T("</SELECT>"));
return nBytes;
}
/******************************************************************************/
/*
* Generate HTML to create a list box containing privileges
*/
static int aspGeneratePrivilegeList(int eid, webs_t wp,
int argc, char_t **argv)
{
int nBytes;
a_assert(wp);
nBytes = websWrite(wp, T("<SELECT NAME=\"privilege\" SIZE=\"3\" "));
nBytes += websWrite(wp, T("MULTIPLE TITLE=\"Choose Privileges\">"));
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">READ\n"), PRIV_READ);
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">EXECUTE\n"), PRIV_WRITE);
nBytes += websWrite(wp, T("<OPTION VALUE=\"%d\">ADMINISTRATE\n"),
PRIV_ADMIN);
nBytes += websWrite(wp, T("</SELECT>"));
return nBytes;
}
/******************************************************************************/
/*
* Save the user management configuration to a file
*/
static void formSaveUserManagement(webs_t wp, char_t *path, char_t *query)
{
char_t *ok;
a_assert(wp);
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Save Cancelled."));
} else if (umCommit(NULL) != 0) {
websWrite(wp, T("ERROR: Unable to save user configuration."));
} else {
websWrite(wp, T("User configuration was saved successfully."));
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Load the user management configuration from a file
*/
static void formLoadUserManagement(webs_t wp, char_t *path, char_t *query)
{
char_t *ok;
a_assert(wp);
ok = websGetVar(wp, T("ok"), T(""));
websHeader(wp);
websMsgStart(wp);
if (gstricmp(ok, T("ok")) != 0) {
websWrite(wp, T("Load Cancelled."));
} else if (umRestore(NULL) != 0) {
websWrite(wp, T("ERROR: Unable to load user configuration."));
} else {
websWrite(wp, T("User configuration was re-loaded successfully."));
}
websMsgEnd(wp);
websFooter(wp);
websDone(wp, 200);
}
/******************************************************************************/
/*
* Message start and end convenience functions
*/
static void websMsgStart(webs_t wp)
{
websWrite(wp, MSG_START);
}
static void websMsgEnd(webs_t wp)
{
websWrite(wp, MSG_END);
}
/******************************************************************************/

706
cpukit/httpd/websSSL.c Normal file
View File

@@ -0,0 +1,706 @@
/*
* websSSL.c -- SSL envrionment creation
*
* 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 a patch into SSL implementations for the webs
* module.
*/
/********************************* Includes ***********************************/
#include "wsIntrn.h"
#include "webs.h"
#include "websSSL.h"
/******************************* Definitions **********************************/
#define DEFAULT_CERT_FILE "./server.pem"
#define DEFAULT_KEY_FILE "./certs/cakey.pem"
#define DEFAULT_CA_FILE "./certs/cacert.pem"
#define DEFAULT_CA_PATH "./certs/"
#define SSL_PORT 443
/*
* Define the components of the apps_startup() macro
*/
#ifdef SIGPIPE
#define do_pipe_sig() signal(SIGPIPE,SIG_IGN)
#else
#define do_pipe_sig()
#endif
#ifdef OPENSSL
#define SSLC_add_all_algorithms() SSLeay_add_all_algorithms()
#else
extern void SSLC_add_all_algorithms(void);
#endif
/*
* Define the apps_startup() macro
*/
# if defined(MSDOS) || defined(WIN16) || defined(WIN32)
# ifdef _O_BINARY
# define apps_startup() \
_fmode=_O_BINARY; do_pipe_sig(); CRYPTO_malloc_init(); \
SSLC_add_all_algorithms()
# else
# define apps_startup() \
_fmode=O_BINARY; do_pipe_sig(); CRYPTO_malloc_init(); \
SSLC_add_all_algorithms()
# endif
# else
# define apps_startup() do_pipe_sig(); SSLC_add_all_algorithms();
# endif
/*************************** Forward Declarations *****************************/
static int websSSLSetCertStuff(SSL_CTX *ctx,
char *cert_file,
char *key_file);
static int websSSLVerifyCallback(int ok, X509_STORE_CTX *ctx);
static RSA *websSSLTempRSACallback(SSL *s, int is_export, int keylength);
static int websSSLReadEvent (webs_t wp);
static int websSSLAccept(int sid, char *ipaddr, int port, int listenSid);
static void websSSLSocketEvent(int sid, int mask, int data);
/*********************************** Locals ***********************************/
static int sslListenSock = -1; /* Listen socket */
static SSL_CTX *sslctx = NULL;
/******************************************************************************/
/*
* Start up the SSL Context for the application, and start a listen on the
* SSL port (usually 443, and defined by SSL_PORT)
* Return 0 on success, -1 on failure.
*/
int websSSLOpen()
{
char *certFile, *keyFile, *CApath, *CAfile;
SSL_METHOD *meth;
/*
* Install and initialize the SSL library
*/
apps_startup();
trace(7, T("SSL: Initializing SSL\n"));
#ifdef SSLC
SSL_library_init();
#endif
SSL_load_error_strings();
#ifdef OPENSSL
SSLeay_add_ssl_algorithms();
#endif
/*
* Important! Enable both SSL versions 2 and 3
*/
meth = SSLv23_server_method();
sslctx = SSL_CTX_new(meth);
a_assert(sslctx);
if (sslctx == NULL) {
trace(2, T("SSL: Unable to create SSL context!\n"));
return -1;
}
/*
* Adjust some SSL Context variables
*/
SSL_CTX_set_quiet_shutdown(sslctx, 1);
SSL_CTX_set_options(sslctx, 0);
SSL_CTX_sess_set_cache_size(sslctx, 128);
/*
* Set the certificate verification locations
*/
CApath = DEFAULT_CA_PATH;
CAfile = DEFAULT_CA_FILE;
if ((!SSL_CTX_load_verify_locations(sslctx, CAfile, CApath)) ||
(!SSL_CTX_set_default_verify_paths(sslctx))) {
trace(2, T("SSL: Unable to set cert verification locations!\n"));
websSSLClose();
return -1;
}
/*
* Set the certificate and key files for the SSL context
*/
certFile = DEFAULT_CERT_FILE;
keyFile = NULL;
if (websSSLSetCertStuff(sslctx, certFile, keyFile) != 0) {
websSSLClose();
return -1;
}
/*
* Set the RSA callback for the SSL context
*/
SSL_CTX_set_tmp_rsa_callback(sslctx, websSSLTempRSACallback);
/*
* Set the verification callback for the SSL context
*/
SSL_CTX_set_verify(sslctx, SSL_VERIFY_NONE, websSSLVerifyCallback);
/*
* Set the certificate authority list for the client
*/
SSL_CTX_set_client_CA_list(sslctx, SSL_load_client_CA_file(CAfile));
/*
* Open the socket
*/
sslListenSock = socketOpenConnection(NULL, SSL_PORT,
websSSLAccept, SOCKET_BLOCK);
if (sslListenSock < 0) {
trace(2, T("SSL: Unable to open SSL socket on port <%d>!\n"),
SSL_PORT);
return -1;
}
return 0;
}
/******************************************************************************/
/*
* Return TRUE if websSSL has been opened
*/
int websSSLIsOpen()
{
return (sslListenSock != -1);
}
/******************************************************************************/
/*
* Stops the SSL
*/
void websSSLClose()
{
trace(7, T("SSL: Closing SSL\n"));
if (sslctx != NULL) {
SSL_CTX_free(sslctx);
sslctx = NULL;
}
if (sslListenSock != -1) {
socketCloseConnection(sslListenSock);
sslListenSock = -1;
}
#ifdef SSLC
SSL_library_cleanup();
#endif
}
/******************************************************************************/
/*
* Accept a connection
*/
int websSSLAccept(int sid, char *ipaddr, int port, int listenSid)
{
webs_t wp;
int wid;
a_assert(ipaddr && *ipaddr);
a_assert(sid >= 0);
a_assert(port >= 0);
/*
* Allocate a new handle for this accepted connection. This will allocate
* a webs_t structure in the webs[] list
*/
if ((wid = websAlloc(sid)) < 0) {
return -1;
}
wp = webs[wid];
a_assert(wp);
wp->listenSid = listenSid;
ascToUni(wp->ipaddr, ipaddr, min(sizeof(wp->ipaddr), strlen(ipaddr)+1));
/*
* Check if this is a request from a browser on this system. This is useful
* to know for permitting administrative operations only for local access
*/
if (gstrcmp(wp->ipaddr, T("127.0.0.1")) == 0 ||
gstrcmp(wp->ipaddr, websIpaddr) == 0 ||
gstrcmp(wp->ipaddr, websHost) == 0) {
wp->flags |= WEBS_LOCAL_REQUEST;
}
/*
* Since the acceptance came in on this channel, it must be secure
*/
wp->flags |= WEBS_SECURE;
/*
* Arrange for websSocketEvent to be called when read data is available
*/
socketCreateHandler(sid, SOCKET_READABLE, websSSLSocketEvent, (int) wp);
/*
* Arrange for a timeout to kill hung requests
*/
wp->timeout = emfSchedCallback(WEBS_TIMEOUT, websTimeout, (void *) wp);
trace(8, T("webs: accept request\n"));
return 0;
}
/******************************************************************************/
/*
* The webs socket handler. Called in response to I/O. We just pass control
* to the relevant read or write handler. A pointer to the webs structure
* is passed as an (int) in iwp.
*/
static void websSSLSocketEvent(int sid, int mask, int iwp)
{
webs_t wp;
wp = (webs_t) iwp;
a_assert(wp);
if (! websValid(wp)) {
return;
}
if (mask & SOCKET_READABLE) {
websSSLReadEvent(wp);
}
if (mask & SOCKET_WRITABLE) {
if (wp->writeSocket) {
(*wp->writeSocket)(wp);
}
}
}
/******************************************************************************/
/*
* Handler for SSL Read Events
*/
static int websSSLReadEvent (webs_t wp)
{
int ret, sock;
socket_t *sptr;
SSL *ssl;
BIO *bio, *bioSSL, *bioSock;
#ifdef DEV
const char *ciphers;
#endif
a_assert (wp);
a_assert(websValid(wp));
sptr = socketPtr(wp->sid);
a_assert(sptr);
sock = sptr->sock;
/*
* Create a new BIO and SSL session for this web request
*/
bio = BIO_new(BIO_f_buffer());
a_assert(bio);
if (!BIO_set_write_buffer_size(bio, 128)) {
return -1;
}
ssl = (SSL *) SSL_new(sslctx);
a_assert(ssl);
if (ssl == NULL) {
return -1;
}
SSL_set_session(ssl, NULL);
bioSSL = BIO_new(BIO_f_ssl());
a_assert(bioSSL);
bioSock = BIO_new_socket(sock, BIO_NOCLOSE);
a_assert(bioSock);
SSL_set_bio(ssl, bioSock, bioSock);
SSL_set_accept_state(ssl);
ret = BIO_set_ssl(bioSSL, ssl, BIO_CLOSE);
BIO_push(bio, bioSSL);
#ifdef DEV
ciphers = SSL_get_cipher_list(ssl, 10);
#endif
/*
* Create the SSL data structure in the wp.
*/
#ifdef WEBS_SSL_SUPPORT
wp->wsp = balloc(B_L, sizeof(websSSL_t));
a_assert (wp->wsp);
(wp->wsp)->bio = bio;
(wp->wsp)->ssl = ssl;
#endif
/*
* Call the default Read Event
*/
websReadEvent(wp);
return ret;
}
/******************************************************************************/
/*
* SSL Verification Callback
*/
static int sslVerifyDepth = 0;
static int sslVerifyError = X509_V_OK;
int websSSLVerifyCallback(int ok, X509_STORE_CTX *ctx)
{
char buf[256];
X509 *errCert;
int err;
int depth;
errCert = X509_STORE_CTX_get_current_cert(ctx);
err = X509_STORE_CTX_get_error(ctx);
depth = X509_STORE_CTX_get_error_depth(ctx);
X509_NAME_oneline(X509_get_subject_name(errCert), buf, 256);
if (!ok) {
if (sslVerifyDepth >= depth) {
ok = 1;
sslVerifyError = X509_V_OK;
} else {
ok=0;
sslVerifyError = X509_V_ERR_CERT_CHAIN_TOO_LONG;
}
}
switch (err) {
case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
#ifdef OPENSSL
X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256);
#endif
break;
case X509_V_ERR_CERT_NOT_YET_VALID:
case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
case X509_V_ERR_CERT_HAS_EXPIRED:
case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
break;
}
return ok;
}
/******************************************************************************/
/*
* Set the SSL certificate and key for the SSL context
*/
int websSSLSetCertStuff(SSL_CTX *ctx, char *certFile, char *keyFile)
{
a_assert (ctx);
a_assert (certFile);
if (certFile != NULL) {
if (SSL_CTX_use_certificate_file(ctx, certFile,
SSL_FILETYPE_PEM) <= 0) {
trace(2, T("SSL: Unable to set certificate file <%s>\n"),
certFile);
return -1;
}
if (keyFile == NULL) {
keyFile = certFile;
}
if (SSL_CTX_use_PrivateKey_file(ctx, keyFile, SSL_FILETYPE_PEM) <= 0) {
trace(2, T("SSL: Unable to set private key file <%s>\n"),
keyFile);
return -1;
}
/*
* Now we know that a key and cert have been set against
* the SSL context
*/
if (!SSL_CTX_check_private_key(ctx)) {
trace(2, T("SSL: Check of private key file <%s> FAILED!\n"),
keyFile);
return -1;
}
}
return 0;
}
/******************************************************************************/
/*
* Set certificate file for SSL context
*/
int websSSLSetCertFile(char_t *certFile)
{
a_assert (sslctx);
a_assert (certFile);
if (sslctx == NULL) {
return -1;
}
if (SSL_CTX_use_certificate_file(sslctx, certFile,
SSL_FILETYPE_PEM) <= 0) {
return -1;
}
/*
* Confirm that the certificate and the private key jive.
*/
if (!SSL_CTX_check_private_key(sslctx)) {
return -1;
}
return 0;
}
/******************************************************************************/
/*
* Set key file for SSL context
*/
int websSSLSetKeyFile(char_t *keyFile)
{
a_assert (sslctx);
a_assert (keyFile);
if (sslctx == NULL) {
return -1;
}
if (SSL_CTX_use_PrivateKey_file(sslctx, keyFile, SSL_FILETYPE_PEM) <= 0) {
return -1;
}
/*
* Confirm that the certificate and the private key jive.
*/
if (!SSL_CTX_check_private_key(sslctx)) {
return -1;
}
return 0;
}
#ifdef SSLC
extern RSA *RSA_new(void);
#endif
/******************************************************************************/
/*
* the Temporary RSA callback
*/
static RSA *websSSLTempRSACallback(SSL *ssl, int isExport, int keyLength)
{
static RSA *rsaTemp = NULL;
if (rsaTemp == NULL) {
#ifdef OPENSSL
rsaTemp = RSA_generate_key(keyLength, RSA_F4, NULL, NULL);
#endif
#ifdef SSLC
rsaTemp = RSA_new();
#endif
}
return rsaTemp;
}
/******************************************************************************/
/*
* Free SSL resources
*/
int websSSLFree(websSSL_t *wsp)
{
if (wsp == NULL) {
return -1;
}
/*
* Make sure we re-use sessions
*/
if (wsp->ssl != NULL) {
SSL_set_shutdown(wsp->ssl, SSL_SENT_SHUTDOWN | SSL_RECEIVED_SHUTDOWN);
}
if (wsp->bio != NULL) {
BIO_free_all(wsp->bio);
}
bfree(B_L, wsp);
return 0;
}
/******************************************************************************/
/*
* Return Eof for the SSL BIO
*/
int websSSLEof(websSSL_t *wsp)
{
a_assert(wsp);
if ((wsp == NULL) || (wsp->bio == NULL)) {
return -1;
}
return BIO_eof(wsp->bio);
}
/******************************************************************************/
/*
* Perform a read of the SSL BIO
*/
int websSSLRead(websSSL_t *wsp, char_t *buf, int len)
{
a_assert(wsp);
a_assert(buf);
if ((wsp == NULL) || (wsp->bio == NULL)) {
return -1;
}
return BIO_read(wsp->bio, buf, len);
}
/******************************************************************************/
/*
* Perform a gets of the SSL BIO, returning an balloc'ed string
*/
#define BUF_BLOCK 256
int websSSLGets(websSSL_t *wsp, char_t **buf)
{
int rc, len, lenBuf;
char c;
a_assert(wsp);
a_assert(buf);
lenBuf = 0;
len = 0;
if ((wsp == NULL) || (wsp->bio == NULL)) {
return -1;
}
while (1) {
if ((rc = BIO_read(wsp->bio, &c, 1)) < 0) {
return rc;
}
if (rc == 0) {
/*
* If there is a partial line and we are at EOF, pretend we saw a '\n'
*/
if (len > 0 && BIO_eof(wsp->bio)) {
c = '\n';
} else {
return -1;
}
}
/*
* If a newline is seen, return the data excluding the new line to the
* caller. If carriage return is seen, just eat it.
*/
if (c == '\n') {
if ((len > 0) && (len < lenBuf)) {
(*buf)[len] = 0;
}
return len;
} else if (c == '\r') {
continue;
}
/*
* Append character to buf
*/
if (len >= lenBuf) {
lenBuf += BUF_BLOCK;
*buf = brealloc(B_L, *buf, lenBuf);
}
a_assert(*buf);
(*buf)[len] = c;
len++;
}
}
/******************************************************************************/
/*
* Perform a write to the SSL BIO
*/
int websSSLWrite(websSSL_t *wsp, char_t *buf, int len)
{
a_assert(wsp);
a_assert(buf);
if ((wsp == NULL) || (wsp->bio == NULL)) {
return -1;
}
return BIO_write(wsp->bio, buf, len);
}
/******************************************************************************/
/*
* Perform a flush of the SSL BIO
*/
int websSSLFlush(websSSL_t *wsp)
{
a_assert(wsp);
if ((wsp == NULL) || (wsp->bio == NULL)) {
return -1;
}
return BIO_flush(wsp->bio);
}
/******************************************************************************/

67
cpukit/httpd/websSSL.h Normal file
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
cpukit/httpd/websda.c Normal file
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
cpukit/httpd/websda.h Normal file
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 */
/******************************************************************************/