aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README19
-rw-r--r--doc/Auth.txt104
-rw-r--r--doc/Steering.txt30
-rw-r--r--src/Authorisation.c356
-rw-r--r--src/Content.c67
-rw-r--r--src/Startup.c18
-rw-r--r--src/Steer.c370
-rw-r--r--src/base64.c330
-rw-r--r--src/base64.h29
-rw-r--r--src/http_Auth.h31
-rw-r--r--src/http_Steer.h27
-rw-r--r--src/make.code.defn13
12 files changed, 1385 insertions, 9 deletions
diff --git a/README b/README
index a267fad..5fb88ea 100644
--- a/README
+++ b/README
@@ -18,7 +18,9 @@ The current interface for this webserver is contained in
http_Request.h
(Note that this will change once we have an agreed common protocol for
-other thorns to talk to web-serving thorns.)
+other thorns to talk to web-serving thorns.) There are also utility
+interface for parameter steering and HTTP authentication, which are
+described in the files in the doc directory.
The primary mechanism is to
@@ -105,7 +107,8 @@ file.
Structure of the thorn:
----------------------
-The thorn is split into two parts - web serving and content provision.
+The thorn is split into three parts - basic web serving, utilities,
+and content provision
Web serving:
-----------
@@ -124,6 +127,17 @@ The above files should not need to be touched apart from debugging
purposes, to add more HTTP methods, or otherwise to enhance the
interaction with the network and protocols.
+Utilities:
+_________
+
+The web server provided utilities to help content provision -
+
+Steer.c - parameter steering interface
+ - see doc/Steering.txt
+
+Authorisation.c - HTTP authentication
+ - see doc/Auth.txt
+
Content Provision:
-----------------
@@ -136,3 +150,4 @@ provide content. In principle this could be in another thorn, but
that should wait until we have an agreed set of interfaces to allow
web-server thorns to be interchangeable, at least at compile time, but
hopefully at run-time.
+
diff --git a/doc/Auth.txt b/doc/Auth.txt
new file mode 100644
index 0000000..9587b4f
--- /dev/null
+++ b/doc/Auth.txt
@@ -0,0 +1,104 @@
+ /*@@
+ @file Auth.txt
+ @date Fri Sep 15 14:05:49 2000
+ @author Tom Goodale
+ @desc
+ Description of http authentication interface interface.
+ @enddesc
+ @version $Header$
+ @@*/
+
+There is an HTTP authentication interface, which is accessed by
+including http_Auth.h.
+
+This provides two functions:
+
+int HTTP_AuthAddUser(const char *database,
+ const char *name,
+ const char *password,
+ const char *encryption_scheme);
+
+which allows databases of users and passwords to be created.
+
+The encryption scheme says how the password which is being passed in
+is encrypted. Currently supported schemes are 'none' for plaintext,
+or 'crypt' for a password encrypted using crypt(3), such as is produced
+by the unix passwd command, plus many other tools. The use of
+crypt(3) relies on Cactus determining that the function exists. Other
+encryption systems are easily added.
+
+This allows the password stored in parameter files or displayed on a
+web page to be encrypted.
+
+The other function is
+
+int HTTP_AuthenticateBasic(httpRequest *request,
+ const char *database);
+
+which takes an HTTP request, and a password database, and sees if the
+'Authorization' header field declares a user and password which are in
+the database. This function supports the 'Basic' authentication
+scheme supplied by HTTP/1.0.
+
+This function has three possible return codes.
+
++1 - the Authorization header was missing.
+0 - header there. User and password match.
+-1 - header there. User and password don't match.
+
+Usage:
+------
+
+Create a set of users and password in a database, e.g.
+
+ HTTP_AuthAddUser("developers","goodale","foo","none");
+
+which declares a database called 'developers' and adds a user
+'goodale; with password 'foo' which is plaintext. An equivalent
+declaration would have been
+
+HTTP_AuthAddUser("developers","goodale","fSzQC4Ssz0ab.","crypt");
+
+if the configuration supports crypt(3) passwords.
+
+Then when a page comes in, one does
+
+ notauthorised = HTTP_AuthenticateBasic(request, "users");
+
+ if(!notauthorised)
+ {
+ /* Access allowed */
+ strcpy(message,"HTTP/1.0 200 Ok\r\n");
+
+ write(request->filedes, message, strlen(message));
+
+ strcpy(message,"WWW-Authenticate: Basic realm=\"foo\"\r\n");
+
+ write(request->filedes, message, strlen(message));
+
+ strcpy(message,"Content-Type: text/html\r\n\r\n");
+
+ write(request->filedes, message, strlen(message));
+
+ ...
+ }
+ else
+ {
+ /* Access not allowed. */
+ strcpy(message,"HTTP/1.0 401 Unauthorized\r\n");
+
+ write(request->filedes, message, strlen(message));
+
+ strcpy(message,"WWW-Authenticate: Basic realm=\"foo\"\r\n");
+
+ write(request->filedes, message, strlen(message));
+
+ strcpy(message,"Content-Type: text/html\r\n\r\n");
+
+ write(request->filedes, message, strlen(message));
+
+ ...
+ }
+
+ Additionally you could check whether 'notauthorised' = +1 or -1 and
+in the latter case log some message about a failed access request.
diff --git a/doc/Steering.txt b/doc/Steering.txt
new file mode 100644
index 0000000..26053ec
--- /dev/null
+++ b/doc/Steering.txt
@@ -0,0 +1,30 @@
+ /*@@
+ @file Steering.txt
+ @date Fri Sep 15 14:05:49 2000
+ @author Tom Goodale
+ @desc
+ Description of parameter steering interface.
+ @enddesc
+ @version $Header$
+ @@*/
+
+There is a parameter steering interface, which is accessed by
+including http_Steer.h.
+
+This defines two functions:
+
+
+int HTTP_SteerQueue(const char *thorn,
+ const char *parameter,
+ const char *value);
+
+which schedules a parameter to be steered, and
+
+int HTTP_SteerDispatch(void);
+
+which broadcasts the data to other processors and then
+steers all the parameters which were queued.
+
+This is to allow steering requests to be queued up over several
+iterations, and then broadcast at once, which should reduce the
+number of barriers called by the code.
diff --git a/src/Authorisation.c b/src/Authorisation.c
new file mode 100644
index 0000000..3be4c3b
--- /dev/null
+++ b/src/Authorisation.c
@@ -0,0 +1,356 @@
+ /*@@
+ @file Authorisation.c
+ @date Fri Sep 15 12:34:59 2000
+ @author Tom Goodale
+ @desc
+ Authorisation stuff for webserver
+ @enddesc
+ @version $Header
+ @@*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "cctk.h"
+
+#include "util_Hash.h"
+#include "util_String.h"
+
+#include "http_Request.h"
+#include "http_Auth.h"
+
+#include "base64.h"
+
+static char *rcsid = "$Header$";
+
+CCTK_FILEVERSION(DevThorns_httpd_Authorisation_c)
+
+/********************************************************************
+ ********************* Local Data Types ***********************
+ ********************************************************************/
+
+struct httpUserData
+{
+ char *password;
+ char *encryption_scheme;
+};
+
+/********************************************************************
+ ********************* Local Routine Prototypes *********************
+ ********************************************************************/
+
+static int AddUser(uHash *database,
+ const char *name,
+ const char *password,
+ const char *encryption_scheme);
+
+static int VerifyPassword(const char *database,
+ const char *user,
+ const char *password);
+
+/********************************************************************
+ ********************* Other Routine Prototypes *********************
+ ********************************************************************/
+
+/********************************************************************
+ ********************* Local Data *****************************
+ ********************************************************************/
+
+static uHash *AuthDatabase = NULL;
+
+#define INITIAL_SIZE 32
+#define DECODED_SIZE 100
+
+/********************************************************************
+ ********************* External Routines **********************
+ ********************************************************************/
+
+ /*@@
+ @routine HTTP_AuthAddUser
+ @date Fri Sep 15 12:52:09 2000
+ @author Tom Goodale
+ @desc
+ Adds a user to a http authentication database.
+ @enddesc
+ @calls
+ @calledby
+ @history
+
+ @endhistory
+
+@@*/
+int HTTP_AuthAddUser(const char *database,
+ const char *name,
+ const char *password,
+ const char *encryption_scheme)
+{
+ int retcode;
+ uHash *this_database;
+
+ /* Create the master database if necessary */
+ if(!AuthDatabase)
+ {
+ AuthDatabase = Util_HashCreate(INITIAL_SIZE);
+ }
+
+ if(AuthDatabase)
+ {
+ /* Does this database exist ? */
+ this_database = (uHash *)Util_HashData(AuthDatabase, strlen(database), database, 0);
+
+ if(!this_database)
+ {
+ this_database = Util_HashCreate(INITIAL_SIZE);
+
+ if(this_database)
+ {
+ Util_HashStore(AuthDatabase, strlen(database), database, 0, (void *)this_database);
+ }
+ else
+ {
+ retcode = -2;
+ }
+ }
+ }
+ else
+ {
+ retcode = -1;
+ }
+
+ /* Now add the user to the database */
+ if(this_database)
+ {
+ retcode = AddUser(this_database, name, password, encryption_scheme);
+ }
+
+ return retcode;
+}
+
+
+ /*@@
+ @routine HTTP_AuthenticateBasic
+ @date Fri Sep 15 13:12:43 2000
+ @author Tom Goodale
+ @desc
+ Authenticates an HTTP request against
+ a particular database.
+ @enddesc
+ @calls
+ @calledby
+ @history
+
+ @endhistory
+
+ @returntype int
+ @returndesc
+ The authorisation status.
+ +1 means that there was no Authorization header.
+ 0 succesful authentication
+ -1 failed authentication
+ @endreturndesc
+
+@@*/
+int HTTP_AuthenticateBasic(httpRequest *request,
+ const char *database)
+{
+ int retval;
+ char message[1024];
+
+ const char *value;
+ char *auth_string;
+ char *token;
+
+ int decoded_size;
+ unsigned char decoded[DECODED_SIZE+1];
+
+ unsigned char *password;
+
+ int authorised;
+
+ value = HTTP_HeaderValue(request, "Authorization");
+
+ auth_string = NULL;
+
+ authorised = 0;
+
+ /* Ok, there's an authentication string here. */
+ if(value)
+ {
+ auth_string = Util_Strdup(value);
+
+ token = strtok(auth_string, " ");
+
+ if(token)
+ {
+ if(CCTK_Equals(token, "Basic"))
+ {
+ token = strtok(NULL, " ,\t");
+ decoded_size = HTTP_b64_pton(token, decoded, DECODED_SIZE);
+
+ /* Null terminate string */
+ decoded[decoded_size] = 0;
+
+ password = strchr(decoded, ':');
+
+ if(password)
+ {
+ *password = 0;
+ password++;
+
+ authorised = VerifyPassword(database, decoded, password);
+ }
+ }
+ }
+
+ if(auth_string)
+ {
+ free(auth_string);
+ }
+
+ if(authorised)
+ {
+ retval = 0;
+ }
+ else
+ {
+ retval = -1;
+ }
+ }
+ else
+ {
+ /* There's no authentication string here */
+
+ retval = 1;
+
+ }
+
+ return retval;
+}
+
+/********************************************************************
+ ********************* Local Routines *************************
+ ********************************************************************/
+
+ /*@@
+ @routine AddUser
+ @date Fri Sep 15 12:52:37 2000
+ @author Tom Goodale
+ @desc
+ Adds a user to a particular database.
+ @enddesc
+ @calls
+ @calledby
+ @history
+
+ @endhistory
+
+@@*/
+static int AddUser(uHash *database,
+ const char *name,
+ const char *password,
+ const char *encryption_scheme)
+{
+ int retcode;
+ struct httpUserData *this_user;
+
+ /* Does this user already exist ? */
+ this_user = (struct httpUserData *)Util_HashData(database, strlen(name), name, 0);
+
+ if(!this_user)
+ {
+ /* New user */
+
+ this_user = (struct httpUserData *)malloc(sizeof(struct httpUserData *));
+
+ if(this_user)
+ {
+ this_user->password = Util_Strdup(password);
+ this_user->encryption_scheme = Util_Strdup(encryption_scheme);
+
+ retcode = Util_HashStore(database, strlen(name), name, 0, (void *)this_user);
+ }
+ else
+ {
+ retcode = -1;
+ }
+ }
+ else
+ {
+ /* Replace user's current data */
+ free(this_user->password);
+ free(this_user->encryption_scheme);
+
+ this_user->password = Util_Strdup(password);
+ this_user->encryption_scheme = Util_Strdup(encryption_scheme);
+
+ retcode = 0;
+ }
+
+ return retcode;
+}
+
+ /*@@
+ @routine VerifyPassword
+ @date Fri Sep 15 13:28:50 2000
+ @author Tom Goodale
+ @desc
+ Verifies a user and password against a database.
+ @enddesc
+ @calls
+ @calledby
+ @history
+
+ @endhistory
+
+@@*/
+static int VerifyPassword(const char *database,
+ const char *user,
+ const char *password)
+{
+ int retcode;
+ uHash *this_database;
+ struct httpUserData *data;
+
+ retcode = 0;
+
+ if(AuthDatabase)
+ {
+ /* Does this database exist ? */
+ this_database = (uHash *)Util_HashData(AuthDatabase, strlen(database), database, 0);
+
+ if(this_database)
+ {
+ data = (struct httpUserData *) Util_HashData(this_database, strlen(user), user, 0);
+
+ if(data)
+ {
+ /* Ok, now verify the password. */
+ if(CCTK_Equals(data->encryption_scheme, "none"))
+ {
+ if(!strcmp(data->password, password))
+ {
+ retcode = 1;
+ }
+ }
+ else if(CCTK_Equals(data->encryption_scheme, "crypt"))
+ {
+#ifdef HAVE_CRYPT
+ if(!strcmp(data->password, crypt(password, data->password)))
+ {
+ retcode = 1;
+ }
+#else
+ fprintf(stderr, "Sorry, crypt(3) not supported in this configuration.\n");
+#endif
+ }
+ else
+ {
+ fprintf(stderr, "Unknown encryption algorithm '%s'\n", data->encryption_scheme);
+ }
+ }
+ }
+ }
+
+ return retcode;
+}
diff --git a/src/Content.c b/src/Content.c
index 3e95e74..b1f6c34 100644
--- a/src/Content.c
+++ b/src/Content.c
@@ -12,6 +12,7 @@
@@*/
#include <stdio.h>
+#include <string.h>
#include "cctk.h"
@@ -19,6 +20,8 @@
#include "http_Request.h"
+#include "http_Auth.h"
+
static char *rcsid = "$Header$";
CCTK_FILEVERSION(DevThorns_httpd_Content_c)
@@ -47,6 +50,8 @@ static int ShowStaticPage(cGH *cctkGH, httpRequest *request, void *data);
static int TestPage(cGH *cctkGH, httpRequest *request, void *data);
+static int AuthPage(cGH *cctkGH, httpRequest *request, void *data);
+
static int CompareStrings(const void *string1, const void *string2);
/********************************************************************
@@ -91,6 +96,10 @@ int HTTP_RegisterPages(void)
/* Register a test page */
HTTP_RegisterPage("/test_page", TestPage, NULL);
+ HTTP_RegisterPage("/auth_page", AuthPage, NULL);
+
+ HTTP_AuthAddUser("user","goodale","foo","none");
+
/* Registrer images */
RegisterImages();
}
@@ -696,9 +705,9 @@ static int TestPage(cGH *cctkGH, httpRequest *request, void *data)
write(request->filedes, message, strlen(message));
- value = HTTP_ArgumentValue(request, "cmd");
+ value = HTTP_ArgumentValue(request, "text");
- sprintf(message, "cmd = %s<hr>\n", value);
+ sprintf(message, "text = %s<hr>\n", value);
write(request->filedes, message, strlen(message));
@@ -715,3 +724,57 @@ static int TestPage(cGH *cctkGH, httpRequest *request, void *data)
return retval;
}
+
+
+static const char *notauthorized_page =
+"<HTML>\n<HEAD><TITLE>Error 401: Not Authorized</TITLE></HEAD>\
+<BODY>You are not authorized to access this page</BODY>\n<HTML>\n";
+
+static const char *authorized_page =
+"<HTML>\n<HEAD><TITLE>Authorized</TITLE></HEAD>\
+<BODY>Congratulations !</BODY>\n<HTML>\n";
+
+static int AuthPage(cGH *cctkGH, httpRequest *request, void *data)
+{
+ int retval;
+ char message[1024];
+
+ int notauthorised;
+
+ notauthorised = HTTP_AuthenticateBasic(request, "user");
+
+ if(!notauthorised)
+ {
+ strcpy(message,"HTTP/1.0 200 Ok\r\n");
+
+ write(request->filedes, message, strlen(message));
+
+ strcpy(message,"WWW-Authenticate: Basic realm=\"foo\"\r\n");
+
+ write(request->filedes, message, strlen(message));
+
+ strcpy(message,"Content-Type: text/html\r\n\r\n");
+
+ write(request->filedes, message, strlen(message));
+
+ write(request->filedes, authorized_page, strlen(authorized_page));
+ }
+ else
+ {
+ strcpy(message,"HTTP/1.0 401 Unauthorized\r\n");
+
+ write(request->filedes, message, strlen(message));
+
+ strcpy(message,"WWW-Authenticate: Basic realm=\"foo\"\r\n");
+
+ write(request->filedes, message, strlen(message));
+
+ strcpy(message,"Content-Type: text/html\r\n\r\n");
+
+ write(request->filedes, message, strlen(message));
+
+ write(request->filedes, notauthorized_page, strlen(notauthorized_page));
+ }
+
+ return 0;
+}
diff --git a/src/Startup.c b/src/Startup.c
index ef2b4ba..495de8b 100644
--- a/src/Startup.c
+++ b/src/Startup.c
@@ -48,7 +48,10 @@ int HTTP_Startup(void)
{
while(1)
{
- HTTP_Poll(NULL, 10000,0);
+ if(CCTK_MyProc(NULL) == 0)
+ {
+ HTTP_Poll(NULL, 10000,0);
+ }
}
}
@@ -74,11 +77,14 @@ void HTTP_Work(CCTK_ARGUMENTS)
DECLARE_CCTK_ARGUMENTS
DECLARE_CCTK_PARAMETERS
- HTTP_Poll(cctkGH, timeout_seconds, timeout_useconds);
+ if(CCTK_MyProc(cctkGH) == 0)
+ {
+ HTTP_Poll(cctkGH, timeout_seconds, timeout_useconds);
+ }
}
/*@@
- @routine HTTP_Startup
+ @routine HTTP_Shutdown
@date Wed Sep 13 21:26:56 2000
@author Tom Goodale
@desc
@@ -93,7 +99,11 @@ void HTTP_Work(CCTK_ARGUMENTS)
@@*/
int HTTP_Shutdown(void)
{
- HTTP_ShutdownServer();
+
+ if(CCTK_MyProc(NULL) == 0)
+ {
+ HTTP_ShutdownServer();
+ }
return 0;
}
diff --git a/src/Steer.c b/src/Steer.c
new file mode 100644
index 0000000..3935ded
--- /dev/null
+++ b/src/Steer.c
@@ -0,0 +1,370 @@
+ /*@@
+ @file Steer.c
+ @date Fri Sep 15 09:51:01 2000
+ @author Tom Goodale
+ @desc
+ Parameter steering interface for the webserver.
+ Perhaps should make these required driver functions ?
+ @enddesc
+ @version $Header$
+ @@*/
+
+#ifndef TEST_HTTP_STEER
+#include "cctk.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef CCTK_MPI
+#include "mpi.h"
+#endif
+
+#ifndef TEST_HTTP_STEER
+#include "cctk_Parameter.h"
+#endif
+
+#include "http_Steer.h"
+
+static char *rcsid = "$Header$";
+
+#ifdef CCTK_FILEVERSION
+CCTK_FILEVERSION(DevThorns_httpd_Steer_c)
+#endif
+
+/********************************************************************
+ ********************* Local Data Types ***********************
+ ********************************************************************/
+
+/********************************************************************
+ ********************* Local Routine Prototypes *********************
+ ********************************************************************/
+
+static int CommunicateBuffer(void);
+static int SteerParameters(void);
+
+/********************************************************************
+ ********************* Other Routine Prototypes *********************
+ ********************************************************************/
+
+/********************************************************************
+ ********************* Local Data *****************************
+ ********************************************************************/
+
+static char *queuebuffer = NULL;
+static int queuebuffer_size = 0;
+
+/********************************************************************
+ ********************* External Routines **********************
+ ********************************************************************/
+
+ /*@@
+ @routine HTTP_SteerQueue
+ @date Fri Sep 15 09:52:13 2000
+ @author Tom Goodale
+ @desc
+ Adds a paremeter and its new value to the queue to be steered.
+ @enddesc
+ @calls
+ @calledby
+ @history
+
+ @endhistory
+
+@@*/
+int HTTP_SteerQueue(const char *thorn, const char *parameter, const char *value)
+{
+ int retval;
+ int buffer_length;
+ int parameter_length;
+ char *tmp;
+
+ retval = 0;
+
+ buffer_length = queuebuffer ? strlen(queuebuffer) : 0;
+
+ /* Added length will be lengthof(thorn::par=val\n) */
+ parameter_length=strlen(thorn) + 2 + strlen(parameter)+ 1 + strlen(value)+1;
+
+ if(buffer_length+parameter_length+1 > queuebuffer_size)
+ {
+ tmp = (char *)realloc(queuebuffer, buffer_length+parameter_length+1);
+
+ if(tmp)
+ {
+ queuebuffer = tmp;
+ retval = 0;
+ }
+ else
+ {
+ retval = -1;
+ }
+ }
+
+ if(!retval)
+ {
+ sprintf(queuebuffer,"%s%s::%s=%s\n", queuebuffer,thorn,parameter, value);
+ }
+
+ return retval;
+}
+
+ /*@@
+ @routine HTTP_SteerDispatch
+ @date Fri Sep 15 09:58:07 2000
+ @author Tom Goodale
+ @desc
+
+ @enddesc
+ @calls
+ @calledby
+ @history
+
+ @endhistory
+
+@@*/
+int HTTP_SteerDispatch(void)
+{
+ CommunicateBuffer();
+
+ SteerParameters();
+
+ return 0;
+}
+
+/********************************************************************
+ ********************* Local Routines *************************
+ ********************************************************************/
+
+ /*@@
+ @routine CommunicateBuffer
+ @date Fri Sep 15 10:22:11 2000
+ @author Tom Goodale
+ @desc
+ Communicates the contents of the queue buffer to all procs.
+ @enddesc
+ @calls
+ @calledby
+ @history
+
+ @endhistory
+
+@@*/
+static int CommunicateBuffer(void)
+{
+#ifdef CCTK_MPI
+ int rank;
+ int nprocs;
+ int buffer_size;
+
+ /* Work out how many processes there are. */
+ MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
+
+ if(nprocs > 1)
+ {
+ /* Work out if this is proc 0 or not. */
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+ if(rank == 0)
+ {
+ /* Sending process */
+
+ /* How much data must we send. */
+ buffer_size = queuebuffer ? strlen(queuebuffer) : 0;
+
+ /* Now account for final \0 */
+ if(buffer_size)
+ {
+ buffer_size++;
+ }
+
+ /* Tell other procs how much data to receive. */
+ MPI_Bcast(&buffer_size, 1, MPI_INT, 0, MPI_COMM_WORLD);
+
+ if(buffer_size > 0)
+ {
+ /* Send data to other procs */
+ MPI_Bcast(queuebuffer, buffer_size, MPI_BYTE, 0, MPI_COMM_WORLD);
+ }
+ }
+ else
+ {
+ /* Receiving process */
+
+ /* Find out how much data to receive. */
+ MPI_Bcast(&buffer_size, 1, MPI_INT, 0, MPI_COMM_WORLD);
+
+#ifdef TEST_HTTP_STEER
+ fprintf(stderr, "%d - buffer size %d queuebuffer size %d\n", rank, buffer_size, queuebuffer_size);
+#endif
+
+ if(buffer_size > queuebuffer_size)
+ {
+ /* Don't use realloc, as don't need to copy data */
+ if(queuebuffer)
+ {
+ free(queuebuffer);
+ }
+
+ queuebuffer = (char *)malloc(buffer_size);
+
+ if(!queuebuffer)
+ {
+ /* Have no choice except to abort as other processes would
+ block.
+ */
+ MPI_Abort(MPI_COMM_WORLD, 99);
+ }
+
+ queuebuffer_size = buffer_size;
+ }
+
+ /* Receive data from processor 0 */
+
+ if(buffer_size > 0)
+ {
+ MPI_Bcast(queuebuffer, buffer_size, MPI_BYTE, 0, MPI_COMM_WORLD);
+ }
+ }
+ }
+
+#endif /* CCTK_MPI */
+
+ return 0;
+}
+
+ /*@@
+ @routine SteerParameters
+ @date Fri Sep 15 10:38:40 2000
+ @author Tom Goodale
+ @desc
+ Steers parameters from queuebuffer.
+ @enddesc
+ @calls
+ @calledby
+ @history
+
+ @endhistory
+
+@@*/
+static int SteerParameters(void)
+{
+ int retval;
+
+ char *token;
+ char *thorn;
+ char *parameter;
+ char *value;
+
+ retval = 0;
+
+ if(queuebuffer)
+ {
+ token = strtok(queuebuffer, "\n");
+
+ while(token)
+ {
+ thorn = token;
+
+ parameter = strchr(token, ':');
+
+ if(parameter)
+ {
+ /* Get rid of two colons */
+ *parameter = 0;
+ parameter++;
+ *parameter = 0;
+ parameter++;
+
+ value = strchr(parameter,'=');
+
+ if(value)
+ {
+ *value = 0;
+ value++;
+
+ CCTK_ParameterSet(parameter, /* The name of the parameter */
+ thorn, /* The originating thorn */
+ value); /* The value of the parameter */
+
+ retval++;
+ }
+ }
+ token = strtok(NULL,"\n");
+ }
+ }
+
+ if(queuebuffer)
+ {
+ *queuebuffer = 0;
+ }
+
+ return retval;
+}
+
+#ifdef TEST_HTTP_STEER
+
+int CCTK_ParameterSet(char *parameter, char *thorn, char *value)
+{
+ int rank;
+
+#ifdef CCTK_MPI
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+#else
+ rank = 0;
+#endif
+
+ fprintf(stderr, "%d - %s::%s='%s'\n", rank, thorn, parameter, value);
+
+ return 0;
+}
+
+int main(int argc, char *argv[])
+{
+ int i;
+ int rank;
+ char value[20];
+
+#ifdef CCTK_MPI
+ MPI_Init(&argc, &argv);
+#endif
+
+#ifdef CCTK_MPI
+ MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+#else
+ rank = 0;
+#endif
+
+ for(i = 0; i < 6; i++)
+ {
+ if(rank == 0)
+ {
+ sprintf(value,"iter %d\n", i);
+
+ switch(i)
+ {
+ case 3 :
+ case 5 :
+ HTTP_SteerQueue("a","b",value);
+ HTTP_SteerQueue("b","c",value);
+ HTTP_SteerQueue("c","d",value);
+ case 1 :
+ HTTP_SteerQueue("d","e",value);
+ HTTP_SteerQueue("e","f",value);
+ HTTP_SteerQueue("f","g",value);
+ default :
+ }
+ }
+
+ HTTP_SteerDispatch();
+ }
+
+#ifdef CCTK_MPI
+ MPI_Finalize();
+#endif
+
+ return 0;
+}
+
+#endif /* TEST_HTTP_STEER */
diff --git a/src/base64.c b/src/base64.c
new file mode 100644
index 0000000..cc9f13b
--- /dev/null
+++ b/src/base64.c
@@ -0,0 +1,330 @@
+ /*@@
+ @file base64.c
+ @date 1995
+ @author Various people, see below.
+ @desc
+
+ @enddesc
+ @history
+ @hdate Fri Sep 15 14:32:47 2000 @hauthor Tom Goodale
+ @hdesc Put into the httpd thorn.
+ @endhistory
+
+ @version $Header$
+ @@*/
+/*
+ * Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+/*
+ * Portions Copyright (c) 1995 by International Business Machines, Inc.
+ *
+ * International Business Machines, Inc. (hereinafter called IBM) grants
+ * permission under its copyrights to use, copy, modify, and distribute this
+ * Software with or without fee, provided that the above copyright notice and
+ * all paragraphs of this notice appear in all copies, and that the name of IBM
+ * not be used in connection with the marketing of any product incorporating
+ * the Software or modifications thereof, without specific, written prior
+ * permission.
+ *
+ * To the extent it has a right to do so, IBM grants an immunity from suit
+ * under its patents, if any, for the use, sale or manufacture of products to
+ * the extent that such products are used for performing Domain Name System
+ * dynamic updates in TCP/IP networks by means of the Software. No immunity is
+ * granted for any product per se or for any other function of any product.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL,
+ * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING
+ * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN
+ * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <sys/types.h>
+
+#include <ctype.h>
+#include <stdio.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#define Assert(Cond) if (!(Cond)) abort()
+
+#include "base64.h"
+
+static const char Base64[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+static const char Pad64 = '=';
+
+/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt)
+ The following encoding technique is taken from RFC 1521 by Borenstein
+ and Freed. It is reproduced here in a slightly edited form for
+ convenience.
+
+ A 65-character subset of US-ASCII is used, enabling 6 bits to be
+ represented per printable character. (The extra 65th character, "=",
+ is used to signify a special processing function.)
+
+ The encoding process represents 24-bit groups of input bits as output
+ strings of 4 encoded characters. Proceeding from left to right, a
+ 24-bit input group is formed by concatenating 3 8-bit input groups.
+ These 24 bits are then treated as 4 concatenated 6-bit groups, each
+ of which is translated into a single digit in the base64 alphabet.
+
+ Each 6-bit group is used as an index into an array of 64 printable
+ characters. The character referenced by the index is placed in the
+ output string.
+
+ Table 1: The Base64 Alphabet
+
+ Value Encoding Value Encoding Value Encoding Value Encoding
+ 0 A 17 R 34 i 51 z
+ 1 B 18 S 35 j 52 0
+ 2 C 19 T 36 k 53 1
+ 3 D 20 U 37 l 54 2
+ 4 E 21 V 38 m 55 3
+ 5 F 22 W 39 n 56 4
+ 6 G 23 X 40 o 57 5
+ 7 H 24 Y 41 p 58 6
+ 8 I 25 Z 42 q 59 7
+ 9 J 26 a 43 r 60 8
+ 10 K 27 b 44 s 61 9
+ 11 L 28 c 45 t 62 +
+ 12 M 29 d 46 u 63 /
+ 13 N 30 e 47 v
+ 14 O 31 f 48 w (pad) =
+ 15 P 32 g 49 x
+ 16 Q 33 h 50 y
+
+ Special processing is performed if fewer than 24 bits are available
+ at the end of the data being encoded. A full encoding quantum is
+ always completed at the end of a quantity. When fewer than 24 input
+ bits are available in an input group, zero bits are added (on the
+ right) to form an integral number of 6-bit groups. Padding at the
+ end of the data is performed using the '=' character.
+
+ Since all base64 input is an integral number of octets, only the
+ -------------------------------------------------
+ following cases can arise:
+
+ (1) the final quantum of encoding input is an integral
+ multiple of 24 bits; here, the final unit of encoded
+ output will be an integral multiple of 4 characters
+ with no "=" padding,
+ (2) the final quantum of encoding input is exactly 8 bits;
+ here, the final unit of encoded output will be two
+ characters followed by two "=" padding characters, or
+ (3) the final quantum of encoding input is exactly 16 bits;
+ here, the final unit of encoded output will be three
+ characters followed by one "=" padding character.
+ */
+
+int HTTP_b64_ntop(unsigned char *src, size_t srclength,
+ char *target, size_t targsize)
+{
+ size_t datalength = 0;
+ u_char input[3];
+ u_char output[4];
+ size_t i;
+
+ while (2 < srclength) {
+ input[0] = *src++;
+ input[1] = *src++;
+ input[2] = *src++;
+ srclength -= 3;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ output[3] = input[2] & 0x3f;
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+ Assert(output[3] < 64);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Base64[output[3]];
+ }
+
+ /* Now we worry about padding. */
+ if (0 != srclength) {
+ /* Get what's left. */
+ input[0] = input[1] = input[2] = '\0';
+ for (i = 0; i < srclength; i++)
+ input[i] = *src++;
+
+ output[0] = input[0] >> 2;
+ output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4);
+ output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6);
+ Assert(output[0] < 64);
+ Assert(output[1] < 64);
+ Assert(output[2] < 64);
+
+ if (datalength + 4 > targsize)
+ return (-1);
+ target[datalength++] = Base64[output[0]];
+ target[datalength++] = Base64[output[1]];
+ if (srclength == 1)
+ target[datalength++] = Pad64;
+ else
+ target[datalength++] = Base64[output[2]];
+ target[datalength++] = Pad64;
+ }
+ if (datalength >= targsize)
+ return (-1);
+ target[datalength] = '\0'; /* Returned value doesn't count \0. */
+ return (datalength);
+}
+
+/* skips all whitespace anywhere.
+ converts characters, four at a time, starting at (or after)
+ src from base - 64 numbers into three 8 bit bytes in the target area.
+ it returns the number of data bytes stored at the target, or -1 on error.
+ */
+
+int HTTP_b64_pton(const char *src, unsigned char *target, size_t targsize)
+{
+ size_t tarindex;
+ int state, ch;
+ char *pos;
+
+ state = 0;
+ tarindex = 0;
+
+ while ((ch = *src++) != '\0') {
+ if (isspace(ch)) /* Skip whitespace anywhere. */
+ continue;
+
+ if (ch == Pad64)
+ break;
+
+ pos = strchr(Base64, ch);
+ if (pos == 0) /* A non-base64 character. */
+ return (-1);
+
+ switch (state) {
+ case 0:
+ if (target) {
+ if (tarindex >= targsize)
+ return (-1);
+ target[tarindex] = (pos - Base64) << 2;
+ }
+ state = 1;
+ break;
+ case 1:
+ if (target) {
+ if (tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 4;
+ target[tarindex+1] = ((pos - Base64) & 0x0f)
+ << 4 ;
+ }
+ tarindex++;
+ state = 2;
+ break;
+ case 2:
+ if (target) {
+ if (tarindex + 1 >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64) >> 2;
+ target[tarindex+1] = ((pos - Base64) & 0x03)
+ << 6;
+ }
+ tarindex++;
+ state = 3;
+ break;
+ case 3:
+ if (target) {
+ if (tarindex >= targsize)
+ return (-1);
+ target[tarindex] |= (pos - Base64);
+ }
+ tarindex++;
+ state = 0;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ /*
+ * We are done decoding Base-64 chars. Let's see if we ended
+ * on a byte boundary, and/or with erroneous trailing characters.
+ */
+
+ if (ch == Pad64) { /* We got a pad char. */
+ ch = *src++; /* Skip it, get next. */
+ switch (state) {
+ case 0: /* Invalid = in first position */
+ case 1: /* Invalid = in second position */
+ return (-1);
+
+ case 2: /* Valid, means one byte of info */
+ /* Skip any number of spaces. */
+#ifdef _LIBC
+ /* To avoid warnings. */
+ for ( ; ch != '\0'; ch = *src++)
+#else
+ for (NULL; ch != '\0'; ch = *src++)
+#endif
+ if (!isspace(ch))
+ break;
+ /* Make sure there is another trailing = sign. */
+ if (ch != Pad64)
+ return (-1);
+ ch = *src++; /* Skip the = */
+ /* Fall through to "single trailing =" case. */
+ /* FALLTHROUGH */
+
+ case 3: /* Valid, means two bytes of info */
+ /*
+ * We know this char is an =. Is there anything but
+ * whitespace after it?
+ */
+#ifdef _LIBC
+ /* To avoid warnings. */
+ for ( ; ch != '\0'; ch = *src++)
+#else
+ for (NULL; ch != '\0'; ch = *src++)
+#endif
+ if (!isspace(ch))
+ return (-1);
+
+ /*
+ * Now make sure for cases 2 and 3 that the "extra"
+ * bits that slopped past the last full byte were
+ * zeros. If we don't check them, they become a
+ * subliminal channel.
+ */
+ if (target && target[tarindex] != 0)
+ return (-1);
+ }
+ } else {
+ /*
+ * We ended by seeing the end of the string. Make sure we
+ * have no partial bytes lying around.
+ */
+ if (state != 0)
+ return (-1);
+ }
+
+ return (tarindex);
+}
diff --git a/src/base64.h b/src/base64.h
new file mode 100644
index 0000000..d466d28
--- /dev/null
+++ b/src/base64.h
@@ -0,0 +1,29 @@
+ /*@@
+ @header base64.h
+ @date Fri Sep 15 12:03:21 2000
+ @author Tom Goodale
+ @desc
+ Header for base64 encoding stuff.
+ @enddesc
+ @version $Header$
+ @@*/
+
+#ifndef __BASE64_H__
+#define __BASE64_H__ 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+int HTTP_b64_ntop(unsigned char *src, size_t srclength,
+ char *target, size_t targsize);
+
+int HTTP_b64_pton(const char *src, unsigned char *target, size_t targsize);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BASE64_H__ */
+
diff --git a/src/http_Auth.h b/src/http_Auth.h
new file mode 100644
index 0000000..89442ec
--- /dev/null
+++ b/src/http_Auth.h
@@ -0,0 +1,31 @@
+ /*@@
+ @header http_Auth.h
+ @date Fri Sep 15 13:20:01 2000
+ @author Tom Goodale
+ @desc
+
+ @enddesc
+ @version $Header$
+ @@*/
+
+#ifndef __HTTP_AUTH_H__
+#define __HTTP_AUTH_H__ 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+int HTTP_AuthAddUser(const char *database,
+ const char *name,
+ const char *password,
+ const char *encryption_scheme);
+
+int HTTP_AuthenticateBasic(httpRequest *request,
+ const char *database);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __HTTP_AUTH_H__ */
diff --git a/src/http_Steer.h b/src/http_Steer.h
new file mode 100644
index 0000000..3c02842
--- /dev/null
+++ b/src/http_Steer.h
@@ -0,0 +1,27 @@
+ /*@@
+ @header http_Steer.h
+ @date Fri Sep 15 11:31:04 2000
+ @author Tom Goodale
+ @desc
+ Webserver parameter steering routines.
+ @enddesc
+ @version $Header$
+ @@*/
+
+#ifndef __HTTP_STEER_H__
+#define __HTTP_STEER_H__ 1
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+int HTTP_SteerQueue(const char *thorn, const char *parameter, const char *value);
+
+int HTTP_SteerDispatch(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __HTTP_STEER_H__ */
diff --git a/src/make.code.defn b/src/make.code.defn
index a2f26b5..fcc4c5d 100644
--- a/src/make.code.defn
+++ b/src/make.code.defn
@@ -2,7 +2,18 @@
# $Header$
# Source files in this directory
-SRCS = Startup.c Server.c Sockets.c http.c Content.c
+
+MISC_SRC = Startup.c
+
+SERVER_SRC = Server.c Sockets.c http.c
+
+CONTENT_SRC = Content.c
+
+STEERING_SRC = Steer.c
+
+AUTHENTICATION_SRC = Authorisation.c base64.c
+
+SRCS = $(MISC_SRC) $(SERVER_SRC) $(CONTENT_SRC) $(STEERING_SRC) $(AUTHENTICATION_SRC)
# Subdirectories containing source files
SUBDIRS =