forked from Imagelibrary/rtems
2003-04-11 Joel Sherrill <joel@OARcorp.com>
* rtems_webserver/cgi.c, rtems_webserver/sockGen.c, rtems_webserver/umui.c, rtems_webserver/websSSL.c, rtems_webserver/websSSL.h, rtems_webserver/websda.c, rtems_webserver/websda.h: New files. Not included in previous commit.
This commit is contained in:
@@ -1,3 +1,10 @@
|
||||
2003-04-11 Joel Sherrill <joel@OARcorp.com>
|
||||
|
||||
* rtems_webserver/cgi.c, rtems_webserver/sockGen.c,
|
||||
rtems_webserver/umui.c, rtems_webserver/websSSL.c,
|
||||
rtems_webserver/websSSL.h, rtems_webserver/websda.c,
|
||||
rtems_webserver/websda.h: New files. Not included in previous commit.
|
||||
|
||||
2002-04-10 Mike Siers <mikes@poliac.com>
|
||||
|
||||
* rtems_webserver/NOTES, rtems_webserver/asp.c,
|
||||
|
||||
331
c/src/libnetworking/rtems_webserver/cgi.c
Normal file
331
c/src/libnetworking/rtems_webserver/cgi.c
Normal 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
c/src/libnetworking/rtems_webserver/sockGen.c
Normal file
1044
c/src/libnetworking/rtems_webserver/sockGen.c
Normal file
File diff suppressed because it is too large
Load Diff
641
c/src/libnetworking/rtems_webserver/umui.c
Normal file
641
c/src/libnetworking/rtems_webserver/umui.c
Normal 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
c/src/libnetworking/rtems_webserver/websSSL.c
Normal file
706
c/src/libnetworking/rtems_webserver/websSSL.c
Normal 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
c/src/libnetworking/rtems_webserver/websSSL.h
Normal file
67
c/src/libnetworking/rtems_webserver/websSSL.h
Normal 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
c/src/libnetworking/rtems_webserver/websda.c
Normal file
244
c/src/libnetworking/rtems_webserver/websda.c
Normal 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
c/src/libnetworking/rtems_webserver/websda.h
Normal file
41
c/src/libnetworking/rtems_webserver/websda.h
Normal 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
331
cpukit/httpd/cgi.c
Normal 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
1044
cpukit/httpd/sockGen.c
Normal file
File diff suppressed because it is too large
Load Diff
641
cpukit/httpd/umui.c
Normal file
641
cpukit/httpd/umui.c
Normal 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
706
cpukit/httpd/websSSL.c
Normal 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
67
cpukit/httpd/websSSL.h
Normal 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
244
cpukit/httpd/websda.c
Normal 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
41
cpukit/httpd/websda.h
Normal 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 */
|
||||
|
||||
/******************************************************************************/
|
||||
Reference in New Issue
Block a user