/**************************************************************************/
// websrv.cpp - Integrated webserver written by Michael Garratt
/***************************************************************************
* The Dawn of Time v1.69r (c)1997-2004 Michael Garratt *
* >> A number of people have contributed to the Dawn codebase, with the *
* majority of code written by Michael Garratt - www.dawnoftime.org *
* >> To use this source code, you must fully comply with the dawn license *
* in licenses.txt... In particular, you may not remove this copyright *
* notice. *
**************************************************************************/
#include "network.h"
#include "websrv.h"
#include "include.h"
#include "nanny.h"
#include "colour.h"
#include "gameset.h"
#include "bitflags.h"
#define LOGALLWEB false
#define IS_NULLSTR(str) ((str)==NULL || (str)[0]=='\0')
// prototypes
void logWebf (char * fmt, ...);
void logWeb( const char *str );
void filterWebRequest(connection_data *w);
int is_space( char c );
void closeConnection(web_request_data *w);
bool readFromWebConnection ( web_request_data *w );
extern int webHits;
extern int webHelpHits;
extern int webWhoHits;
//mud2web.cpp
char *getwebAreas(int level);
char *getwebWho(int level);
char *getwebWizlist();
char *getwebSockets(int level);
char *getwebMudstats(int level);
char *getwebClassStats();
char *getwebRaceStats();
char *getwebRaceInfo();
char *getwebClassInfo(char *racename);
char *getwebAlignStats();
char *getwebLastonImm(int level);
char *getwebHelp(char *, char *entry_buf, int length);
char *getwebGameSettings();
// laston.cpp
int laston_web_level(char *username, char *password);
// handler.cpp
void append_string_to_file( const char *file, const char *str, bool newline );
// dawnlib.cpp
int str_len(const char *s);
/**************************************************************************/
void badRequestFormat(web_request_data *w, char * reason){
w->outBodyLen=sprintf(w->outBodyBuf, "badRequestFormat: %s\r\n", reason);
return;
}
/**************************************************************************/
void processHTTP0_9Request(web_request_data *w){
w->outBodyLen=sprintf(w->outBodyBuf,"HTTP/0.9 is not supported (or bad request)\r\n");
return;
}
/**************************************************************************/
// returns true if there was an error
bool processWebHeader(web_request_data *w){
// NEEDS TO PROCESS THE HEADER FROM pCRLFCRLF
char *pStr, *pLine;
char workingline[WEBIN_HEADER_BUF+100];
char method[21];
// TODO - tidy up check request isn't too long
if (w->inHeaderLen> WEBIN_HEADER_BUF){
badRequestFormat(w, "Request-Line too long");
return false;
}
strncpy(workingline, w->inHeaderBuf, w->inHeaderLen);
workingline[w->inHeaderLen]='\0';
pLine=workingline;
// copy parameters, checking the
// length of each command as we go
// extract the METHOD
pStr=strstr( pLine, " ");
if (!pStr){
badRequestFormat(w, "Request-Line invalid");
return true;
}
if (pStr-pLine>20){
badRequestFormat(w, "method in Request-Line too long");
return true;
}
strncpy(method, pLine, pStr-pLine);
method[pStr-pLine]='\0';
pLine=pStr+1;
// extract the LOCATION
pStr=strstr( pLine, " ");
if (!pStr){
badRequestFormat(w, "Request-Line invalid");
return true;
}
if (pStr-pLine>MAXLOCATION){
badRequestFormat(w, "Request-URI (location) in Request-Line too long");
return true;
}
strncpy(w->requestedLocation, pLine, pStr-pLine);
w->requestedLocation[pStr-pLine]='\0';
pLine=pStr+1;
// extract the VERSION
if (strstr( pLine, "HTTP/" )==NULL)
{
badRequestFormat(w, "no HTTP version in Request-Line");
}
if (str_len(pLine)>20){
badRequestFormat(w, "HTTP-Version in Request-Line too long");
return true;
}
strcpy(w->version, pLine);
// now identify the method
if (!strcmp(method,"GET")){
w->requestType=GET;
}else
if (!strcmp(method,"HEAD")){
w->requestType=HEAD;
}else
if (!strcmp(method,"POST")){
w->requestType=POST;
}else{
w->requestType=UNDEFINED;
}
// check for an "Authorization:" header
pLine=strstr( w->inHeaderBuf, "Authorization:");
if (pLine){
// we have an Authorization - process it
pStr=strstr( pLine, "\r\n");
if (pStr){
strncpy(workingline, pLine, pStr-pLine);
workingline[pStr-pLine]='\0';
pLine=workingline;
//we have the authorization string in newline
logWebf("Processing Authorization: '%s'",workingline);
pStr=strstr( pLine, "Basic ");
if (pStr){
pLine=pStr+6;
if (str_len(pLine)>0 && str_len(pLine)<200){
char decoded[200];
char *d;
d =decodeBase64(pLine);
if (d){
sprintf(decoded,d);
// now separate the username:password
pLine=decoded;
pStr=strstr( pLine, ":");
if (pStr){
if (pStr-pLine<MAXPASSLENGTH){
strncpy(w->username, pLine, pStr-pLine);
w->username[pStr-pLine]='\0';
pLine=pStr+1;
if (str_len(pLine)>MAXPASSLENGTH){
// not a valid password - so authuenticate invalid
w->username[0]='\0';
}else{
strcpy(w->password, pLine);
}
}
}
}
}
}else{
logWeb("Authorization type not recognised");
}
}
}
return true;
}
/**************************************************************************/
void greet_http(connection_data *c)
{
logWebf("New web connection from %s", c->remote_ip);
web_request_data *w=new web_request_data;
w->receivingHeader=true;
w->inHeaderBuf[0]='\0';
w->inHeaderLen=0;
w->inBodyBuf[0]='\0';
w->inBodyLen=0;
w->outHeaderBuf[0]='\0';
w->outHeaderLen=0;
w->outBodyBuf[0]='\0';
w->outBodyLen=0;
w->contentLength=0;
// set some defaults
w->username[0]='\0';
w->password[0]='\0';
w->requestType= UNDEFINED;
w->contentLength=0;// request message doesn't have a body
w->statusCode=503; // service unavailable
w->contentType= CONTENT_TYPE_HTML;
c->web_request=w;
}
/**************************************************************************/
// return true if everything is okay - i.e. we read something or are
// waiting for something.
bool websrv_process_input(connection_data *c)
{
int bytesIn;
char *pDest;
int maxDestLength;
int *currentLength;
if (c->web_request->receivingHeader){
maxDestLength =WEBIN_HEADER_BUF-c->web_request->inHeaderLen;
pDest = &c->web_request->inHeaderBuf[c->web_request->inHeaderLen];
currentLength=&c->web_request->inHeaderLen;
}else{
maxDestLength=WEBIN_BODY_BUF-c->web_request->inBodyLen;
pDest = &c->web_request->inBodyBuf[c->web_request->inBodyLen];
currentLength=&c->web_request->inBodyLen;
}
bytesIn=recv(c->connected_socket, pDest, maxDestLength,0);
if (bytesIn>0){
logWeb("Getting input");
*(pDest+bytesIn)='\0';
*currentLength+=bytesIn;
if(LOGALLWEB){
logWeb(c->web_request->inHeaderBuf);
}
if (c->web_request->inHeaderLen>=WEBIN_HEADER_BUF){
logWebf("Buffer overflow from %s",c->remote_ip);
logWeb(c->web_request->inHeaderBuf);
}
filterWebRequest(c);
}else{
// connection closed at the other end
logWebf("closing connection - 0 bytes in (%d).", bytesIn);
connection_close( c );
return false;
}
return true;
}
/**************************************************************************/
void websrv_process_output(connection_data *c)
{
if (c->web_request->outBodyLen>0){
send(c->connected_socket,
&c->web_request->outHeaderBuf[0],
c->web_request->outHeaderLen,
0);
send(c->connected_socket,
&c->web_request->outBodyBuf[0],
c->web_request->outBodyLen,
0);
logWeb("closing connection - sent data.");
connection_close(c);
}
}
/**************************************************************************/
/**************************************************************************/
/*
* Writes a string to the log.
*/
void logWeb( const char *str )
{
logWebf("%s", str);
return;
}
/**************************************************************************/
// create a HTTP/1.0 header
void createHeader(web_request_data *w){
char reason[50];
time_t ltime;
char GMTdate[100];
// get the date first
time( <ime );
strftime(GMTdate, 99, "%A, %d-%b-", gmtime( <ime ));
char t2buf[20]; // budget fix to get rid of y2k compiler warning
strftime(t2buf, 20, "%Y %T GMT", gmtime( <ime ));
strcat(GMTdate,&t2buf[2]);
switch (w->statusCode){
// 2xx: Success
case 200: sprintf(reason, "OK"); break;
case 201: sprintf(reason, "Created"); break;
case 202: sprintf(reason, "Accepted"); break;
case 204: sprintf(reason, "No Content"); break;
// 3xx: Redirection
case 301: sprintf(reason, "Moved Permanently"); break;
case 302: sprintf(reason, "Moved Temporarily"); break;
case 304: sprintf(reason, "Not Modified"); break;
// 4xx: Client Error
case 400: sprintf(reason, "Bad Request"); break;
case 401: sprintf(reason, "Unauthorized"); break;
case 403: sprintf(reason, "Forbidden"); break;
case 404: sprintf(reason, "Not Found"); break;
// 5xx: Server Error
case 500: sprintf(reason, "Internal Server Error"); break;
case 501: sprintf(reason, "Not Implemented"); break;
case 502: sprintf(reason, "Bad Gateway"); break;
case 503: sprintf(reason, "Service Unavailable"); break;
default:
w->statusCode=500;
sprintf(reason, "Internal Server Error"); break;
}
w->outHeaderLen= sprintf(w->outHeaderBuf,
"HTTP/1.0 %d %s\r\n"
"Date: %s\r\n"
"WWW-Authenticate: Basic realm=\"%s Integrated WebServer\"\r\n"
"Cache-Control: private, pre-check=0, post-check=0, max-age=0\r\n"
"Expires: %s\r\n"
"Last-Modified: %s\r\n"
"Content-Type: %s\r\n"
"Content-Length: %d\r\n"
"\r\n"
,w->statusCode, reason, GMTdate,
MUD_NAME,
GMTdate,
GMTdate,
w->contentType==CONTENT_TYPE_HTML?"text/html":"text/plain",
w->outBodyLen);
}
/**************************************************************************/
char *websvr_generate_head_and_start_body(char *title)
{
static char head[8192];
sprintf(head,
DOCTYPE
"<HTML><HEAD>\n"
"<TITLE>Dawn - %.8000s</TITLE>\n"
"<link rel=\"StyleSheet\" href=\"/stat.css\" type=\"text/css\" />\n"
"</HEAD>\n"
"\n"
"<BODY BGCOLOR=\"#000000\" TEXT=\"#BFBFBF\">\n",
title);
return head;
}
/**************************************************************************/
void websvr_handle_insufficient_immweb_level(web_request_data *w, char *buf, int immweb_level)
{
if (immweb_level==-1){
w->statusCode=200;
buf=process_colour("`WYou haven't set a webpassword for your character,`1"
"Use the webpass command within the game to do this.", NULL);
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"%s" // doctype, header, and start of body tag
"<PRE><FONT>%s</PRE>"
"<p><A HREF=\"/\">[Back to root]</A> <A HREF=\"/sockets\">[sockets]</A> <A HREF=\"/mudstats\">[mudstats]</A>"
,websvr_generate_head_and_start_body("web password setting required!")
,buf);
}else{
w->statusCode=401;
logWeb("401 - Authorisation denied");
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"<html><head><title>Incorrect username/password</title></head>\n"
"<body><h1>Incorrect username/password</h1>\n"
"<p>You got the username or password incorrect.\n"
"<p><A HREF=\"/\">Back to root</A>");
}
}
/**************************************************************************/
// This function is the most ugly piece of code I have written in my
// life, it was a hack to get things working quickly then evolved
// into this hideous beast - Kal, Oct 2001.
void processGET(web_request_data *w)
{
char *buf="";
webHits++;
if(!str_cmp(w->requestedLocation,"/stat.css")){
// stats.css - the style sheet
w->statusCode=200;
w->contentType=CONTENT_TEXT_PLAIN;
strcpy(w->outBodyBuf, IS_NULLSTR(game_settings->style_sheet)?"":game_settings->style_sheet);
w->outBodyLen=str_len(w->outBodyBuf);
}else
if (!str_cmp(w->requestedLocation,"/areas")){
webWhoHits++;
w->statusCode=200;
buf=getwebAreas(20);
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"%s" // doctype, header, and start of body tag
"<H2><FONT COLOR=\"#BFBFBF\">Areas within %s</FONT></H2>"
"\n<PRE><FONT>%s"
" [<A HREF=\"/\">back</A>]\n"
"</PRE>"
,websvr_generate_head_and_start_body("Areas")
,MUD_NAME
,buf);
}else
if (!str_cmp(w->requestedLocation,"/who")){
webWhoHits++;
w->statusCode=200;
buf=getwebWho(20);
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"%s" // doctype, header, and start of body tag
"<H2><FONT COLOR=\"#BFBFBF\">Who is online %s</FONT></H2>"
"\n<PRE><FONT>%s"
" [<A HREF=\"/\">back</A>]\n"
"</PRE>"
,websvr_generate_head_and_start_body("Wholist")
,MUD_NAME
,buf);
}else
if (!str_cmp(w->requestedLocation,"/mudstats")){
w->statusCode=200;
buf=getwebMudstats(20);
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"%s" // doctype, header, and start of body tag
"<p><A HREF=\"http://www.dawnoftime.org/\">Go to the official Dawn of Time website</A>\n"
" <A HREF=\"/\">Back to mud integrated website</A>\n"
"</p>\n<H2><FONT COLOR=\"#BFBFBF\">%s Mudstats</FONT></H2>"
#ifdef VALIDATE_HTML
"\n<TT><FONT>%s</FONT></TT>"
#else
"\n<PRE><FONT>%s</PRE>"
#endif
"<p><A HREF=\"http://www.dawnoftime.org/\">Go to the official Dawn of Time website</A>\n"
" <A HREF=\"/\">Back to mud integrated website</A>\n"
,websvr_generate_head_and_start_body("Mudstats")
,MUD_NAME ,buf);
}else
if (!str_cmp(w->requestedLocation,"/robots.txt")){
// robots.txt - to prevent webcrawlers indexing the online helps
w->statusCode=200;
w->contentType=CONTENT_TEXT_PLAIN;
strcpy(w->outBodyBuf, "User-agent: *\nDisallow: /help/\n");
w->outBodyLen=str_len(w->outBodyBuf);
}else
if (!str_cmp(w->requestedLocation,"/gamesettings")){
w->statusCode=200;
buf=getwebGameSettings();
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"%s" // doctype, header, and start of body tag
"<A HREF=\"/\">Back to root</A><BR>\n"
"<H2><FONT COLOR=\"#BFBFBF\">%s GAME SETTINGS</FONT></H2>"
#ifdef VALIDATE_HTML
"\n<TT><FONT>%s</FONT></TT>"
#else
"\n<PRE><FONT>%s</PRE>"
#endif
"<p><A HREF=\"/\">Back to root</A>"
,websvr_generate_head_and_start_body("GameSettings")
,MUD_NAME, buf);
}else
if (!str_cmp(w->requestedLocation,"/wizlist")){
w->statusCode=200;
buf=getwebWizlist();
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"%s" // doctype, header, and start of body tag
"<A HREF=\"/\">Back to root</A><BR>\n"
"<H2><FONT COLOR=\"#BFBFBF\">%s WIZLIST</FONT></H2>"
#ifdef VALIDATE_HTML
"\n<TT><FONT>%s</FONT></TT>"
#else
"\n<PRE><FONT>%s</PRE>"
#endif
"<p><A HREF=\"/\">Back to root</A>"
,websvr_generate_head_and_start_body("Wizlist")
,MUD_NAME, buf);
}else
if (!str_prefix("/help/",w->requestedLocation)
|| !str_cmp("/help",w->requestedLocation))
{
webHelpHits++;
char entry_buf[10000];
char entry_buf2[10050];
char *webhelp_buf=(char*)malloc(128000);// temporary storage allocated
buf=webhelp_buf;
w->statusCode=200;
if(w->requestedLocation[5]=='/'){
convertColour( getwebHelp( w->requestedLocation+6, entry_buf, 10000),buf, CT_HTML, true);
}else{
convertColour( getwebHelp( w->requestedLocation+5, entry_buf, 10000),buf, CT_HTML, true);
}
sprintf(entry_buf2, "WebHelp - %s", entry_buf);
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"%s" // doctype, header, and start of body tag
"<H2><FONT COLOR=\"#BFBFBF\">%s WebHelp </H2><H3>- %s</H3></FONT>"
#ifdef VALIDATE_HTML
"<TT><FONT>%s</FONT></TT>"
#else
"<PRE><FONT>%s</PRE>"
#endif
,websvr_generate_head_and_start_body(entry_buf2)
, MUD_NAME, entry_buf, buf);
free(webhelp_buf); // temporary storage freed
}else
if (!str_cmp(w->requestedLocation,"/classstats")){
w->statusCode=200;
buf=getwebClassStats();
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"%s" // doctype, header, and start of body tag
"<A HREF=\"/\">Back to root</A><BR>\n"
"<H2><FONT COLOR=\"#BFBFBF\">%s CLASS STATS</FONT></H2>"
#ifdef VALIDATE_HTML
"\n<TT><FONT>%s</FONT></TT>"
#else
"\n<PRE><FONT>%s</PRE>"
#endif
"<p><A HREF=\"/\">Back to root</A>"
,websvr_generate_head_and_start_body("Class Stats")
,MUD_NAME,buf);
}else
if (!str_cmp(w->requestedLocation,"/racestats")){
w->statusCode=200;
buf=getwebRaceStats();
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"%s" // doctype, header, and start of body tag
"<A HREF=\"/\">Back to root</A><BR>\n"
"<H2><FONT COLOR=\"#BFBFBF\">%s RACE STATS</FONT></H2>"
#ifdef VALIDATE_HTML
"\n<TT><FONT>%s</FONT></TT>"
#else
"\n<PRE><FONT>%s</PRE>"
#endif
"<p><A HREF=\"/\">Back to root</A>"
,websvr_generate_head_and_start_body("Race Stats")
,MUD_NAME,buf);
}else
if (!GAMESETTING5(GAMESET5_RACEINFO_DISABLED_IN_WEBSERVER)
&& !str_cmp(w->requestedLocation,"/raceinfo"))
{
w->statusCode=200;
buf=getwebRaceInfo();
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"%s" // doctype, header, and start of body tag
"<A HREF=\"/\">Back to root</A><BR>\n"
"<H2><FONT COLOR=\"#BFBFBF\">%s Race Info</FONT></H2>"
#ifdef VALIDATE_HTML
"\n<TT><FONT>%s</FONT></TT>"
#else
"\n<PRE><FONT>%s</PRE>"
#endif
"<p><A HREF=\"/\">Back to root</A>"
,websvr_generate_head_and_start_body("Race Info")
,MUD_NAME,buf);
}else
if (!GAMESETTING5(GAMESET5_CLASSINFO_DISABLED_IN_WEBSERVER)
&& (!str_prefix("/classinfo/",w->requestedLocation)
|| !str_cmp("/classinfo",w->requestedLocation)))
{
w->statusCode=200;
if(w->requestedLocation[10]=='/'){
buf=getwebClassInfo(w->requestedLocation+11);
}else{
buf=getwebClassInfo("");
}
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"%s" // doctype, header, and start of body tag
"<A HREF=\"/\">Back to root</A><BR>\n"
"<H2><FONT COLOR=\"#BFBFBF\">%s Race Info</FONT></H2>"
#ifdef VALIDATE_HTML
"\n<TT><FONT>%s</FONT></TT>"
#else
"\n<PRE><FONT>%s</PRE>"
#endif
"<p><A HREF=\"/\">Back to root</A>"
,websvr_generate_head_and_start_body("Class Info")
,MUD_NAME,buf);
}else
if (!str_cmp(w->requestedLocation,"/alignstats")){
w->statusCode=200;
buf=getwebAlignStats();
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"%s" // doctype, header, and start of body tag
"<A HREF=\"/\">Back to root</A><BR>\n"
"<H2><FONT COLOR=\"#BFBFBF\">%s ALIGNMENT MATRIX</FONT></H2>"
#ifdef VALIDATE_HTML
"\n<TT><FONT>%s</FONT></TT>"
#else
"\n<PRE><FONT>%s</PRE>"
#endif
"<p><A HREF=\"/\">Back to root</A>"
,websvr_generate_head_and_start_body("Active Player Alignment Matrix")
,MUD_NAME,buf);
}else
if (!str_cmp(w->requestedLocation,"/immwho")){
int immweb_level=laston_web_level(w->username, w->password);
// laston_web_level() returns the level/trust of the imm if the password is correct
// returns -1 if it is an imm name, but no webpass has been set
// otherwise returns 0 if incorrect or not imm
if (immweb_level>0){
w->statusCode=200;
buf=getwebWho(immweb_level);
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"%s" // doctype, header, and start of body tag
"\n<PRE><FONT>%s</PRE>"
"<p><A HREF=\"/\">[Back to root]</A> <A HREF=\"/sockets\">[sockets]</A> <A HREF=\"/mudstats\">[mudstats]</A>"
,websvr_generate_head_and_start_body("Immortal Wholist")
,buf);
}else if (immweb_level==-1){
w->statusCode=200;
buf=process_colour("`WYou haven't set a webpassword for your character,`1"
"Use the webpass command within the game to do this.", NULL);
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"%s" // doctype, header, and start of body tag
"<PRE><FONT>%s</PRE>"
"<p><A HREF=\"/\">[Back to root]</A> <A HREF=\"/sockets\">[sockets]</A> <A HREF=\"/mudstats\">[mudstats]</A>"
,websvr_generate_head_and_start_body("web password setting required!")
,buf);
}else{
w->statusCode=401;
logWeb("401 - Authorisation denied");
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"<html><head><title>Incorrect username/password</title></head>\n"
"<body><h1>Incorrect username/password</h1>\n"
"<p>You got the username or password incorrect.\n"
"<p><A HREF=\"/\">Back to root</A>");
}
}else
if (!str_cmp(w->requestedLocation,"/lastonimm")){
int immweb_level=laston_web_level(w->username, w->password);
// laston_web_level() returns the level/trust of the imm if the password is correct
// returns -1 if it is an imm name, but no webpass has been set
// otherwise returns 0 if incorrect or not imm
if (immweb_level>0){
w->statusCode=200;
buf=getwebLastonImm(immweb_level);
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"%s" // doctype, header, and start of body tag
"\n<PRE><FONT>%s</PRE>"
"<p><A HREF=\"/\">[Back to root]</A> <A HREF=\"/sockets\">[sockets]</A> <A HREF=\"/immwho\">[immwho]</A> <A HREF=\"/mudstats\">[mudstats]</A>"
,websvr_generate_head_and_start_body("Immortal Laston")
,buf);
}else{
websvr_handle_insufficient_immweb_level(w, buf, immweb_level);
}
}else
if (!str_cmp(w->requestedLocation,"/sockets")){
int immweb_level=laston_web_level(w->username, w->password);
// laston_web_level() returns the level/trust of the imm if the password is correct
// returns -1 if it is an imm name, but no webpass has been set
// otherwise returns 0 if incorrect or not imm
if (immweb_level>0){
w->statusCode=200;
buf=getwebSockets(immweb_level);
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"%s" // doctype, header, and start of body tag
"<FONT COLOR=\"#BFBFBF\">"
"\n<PRE><FONT>%s</PRE>"
"<p><A HREF=\"/\">[Back to root]</A> <A HREF=\"/immwho\">[immwho]</A> <A HREF=\"/mudstats\">[mudstats]</A>"
,websvr_generate_head_and_start_body("Immortal Sockets")
,buf);
}else{
websvr_handle_insufficient_immweb_level(w, buf, immweb_level);
}
}else
if (!str_cmp(w->requestedLocation,"/")){
w->statusCode=200;
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"%s" // doctype, header, and start of body tag
"<H2 ALIGN=\"CENTER\">%s Mud Integrated Webserver</FONT></H2>"
"<P ALIGN=\"CENTER\"><A HREF=\"/who\">Who list</A><BR>"
"<P ALIGN=\"CENTER\"><A HREF=\"/help\">WebHelp</A><BR>"
"<P ALIGN=\"CENTER\"><A HREF=\"/areas\">Areas</A><BR>"
"<P ALIGN=\"CENTER\"><A HREF=\"/mudstats\">Mudstats</A><BR>"
"<A HREF=\"/wizlist\">The Wizlist</A><BR>"
"<A HREF=\"/classstats\">Active Player Class Stats</A><BR>"
"<A HREF=\"/racestats\">Active Player Race Stats</A><BR>"
"%s" // raceinfo - optional with gamesetting
"%s" // classinfo - optional with gamesetting
"<A HREF=\"/alignstats\">Active Player Alignment Matrix</A><BR>"
"<A HREF=\"/gamesettings\">Game Settings</A><BR>"
"<A HREF=\"/immwho\">Immortal version of the who list - immonly</A><BR>"
"<A HREF=\"/lastonimm\">List of imms recently on - immonly</A><BR>"
"<A HREF=\"/sockets\">Connections - immonly</A></P>"
"<P ALIGN=\"CENTER\"><A HREF=\"/locked\">Reset password</A><BR>"
"<P ALIGN=\"CENTER\"><A HREF=\"http://www.dawnoftime.org/\">Go to the official Dawn of Time website</A></P>"
"</P></BODY>"
"</HTML>"
,websvr_generate_head_and_start_body(MUD_NAME)
, MUD_NAME,
GAMESETTING5(GAMESET5_RACEINFO_DISABLED_IN_WEBSERVER)?"":"<A HREF=\"/raceinfo\">Race Info</A><BR>",
GAMESETTING5(GAMESET5_CLASSINFO_DISABLED_IN_WEBSERVER)?"":"<A HREF=\"/classinfo\">Class Info</A><BR>");
}else
if (!str_cmp(w->requestedLocation,"/locked")){
w->statusCode=401;
logWeb("401 - Authorisation denied");
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"<html><head><title>Incorrect username/password</title></head>\n"
"<body><h1>Incorrect username/password</h1>\n"
"<p>You got the username/password incorrect.\n"
"<p>Try username=user and password=password at <A HREF=\"/locked2\">locked2</A> for a test.\n"
"<p><A HREF=\"/\">Back to root</A>");
}else
if (!str_cmp(w->requestedLocation,"/locked2")){
if (!strcmp(w->username,"user") && !strcmp(w->password,"password")){
w->statusCode=200;
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"<html><head><title>Access granted!</title></head>\n"
"<body><h1>Access granted!</h1>\n"
"<p>You got the password etc correct.\n"
"<p>Click on <A HREF=\"/locked\">locked</A> to be denied.\n"
"<p><A HREF=\"/\">Back to root</A>");
}else{
w->statusCode=401;
logWeb("401 - Authorisation denied");
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"<html><head><title>Incorrect username/password</title></head>\n"
"<body><h1>Incorrect username/password</h1>\n"
"<p>You got the username/password incorrect.\n"
"<p>try username=user and password=password\n"
"<p><A HREF=\"/\">Back to root</A>");
}
}else{
w->statusCode=200;
w->outBodyLen=snprintf(w->outBodyBuf,WEBOUT_BODY_BUF,
"<html><head><title>Not found</title></head>\n"
"<body><h1>couldn't find the url you wanted</h1>\n"
"<p><A HREF=\"/\">Back to root</A>");
}
if(w->outBodyLen<0){
logWebf("Body %d bytes!!! - invalid length, attempting to repair!", w->outBodyLen);
if(str_len(buf)>WEBOUT_BODY_BUF-10){
w->outBodyBuf[WEBOUT_BODY_BUF-10]='\0';
w->outBodyLen=WEBOUT_BODY_BUF-9;
}else{
w->outBodyLen=snprintf(w->outBodyBuf, WEBOUT_BODY_BUF,
"an error occured while processing this webpage, please report this to the admin!");
w->statusCode=500; // Internal Error
}
}
logWebf("Making header - Body %d bytes", w->outBodyLen);
createHeader(w);
}
/**************************************************************************/
void processPOST(web_request_data *w){
webHits++;
if (!str_cmp(w->requestedLocation,"/")){
w->statusCode=200;
w->outBodyLen=sprintf(w->outBodyBuf,
"<HTML>"
"<HEAD>"
"<TITLE>%s</TITLE>"
"</HEAD>"
"<BODY LINK=\"#0000ff\" VLINK=\"#800080\">"
"<H2 ALIGN=\"CENTER\">%s Mud Integrated Webserver</FONT></H2>"
"<P ALIGN=\"CENTER\"><A HREF=\"http://www.dawnoftime.org/\">Go to the official Dawn of Time website</A></P>"
"<P ALIGN=\"CENTER\"><A HREF=\"/who\">Who list</A><BR>"
"<P ALIGN=\"CENTER\"><A HREF=\"/mudstats\">Mudstats</A><BR>"
"<A HREF=\"/wizlist\">The wizlist</A><BR>"
"<A HREF=\"/immwho\">Immortal version of the who list</A><BR>"
"<A HREF=\"/sockets\">Connections - immonly</A></P>"
"<P ALIGN=\"CENTER\"><A HREF=\"/locked\">Reset password</A><BR>"
"</P></BODY>"
"</HTML>", MUD_NAME, MUD_NAME);
}else
if (!str_cmp(w->requestedLocation,"/locked2")){
if (!strcmp(w->username,"user") && !strcmp(w->password,"password")){
w->statusCode=200;
w->outBodyLen=sprintf(w->outBodyBuf,
"<html><head><title>Access granted!</title></head>\n"
"<body><h1>Access granted!</h1>\n"
"<p>You got the password etc correct.\n"
"<p><A HREF=\"/\">Back to root</A>");
}else{
w->statusCode=401;
logWeb("401 - Authorisation denied");
w->outBodyLen=sprintf(w->outBodyBuf,
"<html><head><title>Incorrect username/password</title></head>\n"
"<body><h1>Incorrect username/password</h1>\n"
"<p>You got the username/password incorrect.\n"
"<p>try username=user and password=password\n"
"<p><A HREF=\"/\">Back to root</A>");
}
}else{
w->statusCode=200;
w->outBodyLen=sprintf(w->outBodyBuf,
"<html><head><title>Not found</title></head>\n"
"<body><h1>couldn't find the url you wanted</h1>\n"
"<p><A HREF=\"/\">Back to root</A>");
}
logWebf("making header");
createHeader(w);
}
/**************************************************************************/
void processWebRequest(connection_data *c){
web_request_data *w=c->web_request;
char loguname[100];
logWebf("processWebRequest");
logWebf("REQUEST: %d LOCATION: '%s'", w->requestType, w->requestedLocation);
if (w->username && str_len(w->username)>0){
strncpy(loguname, w->username, 99);
loguname[99]='\0';
logWebf("USERNAME: '%s'", w->username);
// logWebf("PASSWORD: '%s'", w->password);
}else{
loguname[0]='-';
loguname[1]='\0';
}
switch (w->requestType){
case GET:
processGET(w);
break;
case HEAD:
badRequestFormat(w, "HEAD - Unsupported method");
break;
case POST:
processPOST(w);
// badRequestFormat(w, "POST - Unsupported method");
break;
case UNDEFINED:
default:
badRequestFormat(w, "Undefined method");
break;
}
// Web log stuff - can use with webalizer (http://www.mrunix.net/webalizer)
// and other website stat generating software
if(!(game_settings->flags2 & GAMESET2_NO_WEBLOG))
{
char logdate[100];
time_t ltime;
time( <ime );
#ifdef WIN32 // VC++6 compiler doesn't support %z, doesn't really matter
// hard coded it to NZDT :)
strftime(logdate, 100, "[%d/%b/%Y:%H:%M:%S +1300]", localtime( <ime));
#else
strftime(logdate, 100, "[%d/%b/%Y:%H:%M:%S %z]", localtime( <ime));
#endif
char weblogbuf[4096];
sprintf(weblogbuf,"%s - %s %s \"%s\" %d %d \"%s\" \"%s\"",
c->remote_ip, // 50 bytes
loguname, // 100 bytes
logdate, // 100 bytes
w->firstline, // 1024 max
w->statusCode, // 3 bytes
w->outBodyLen, // 6 bytes max
w->referer, // 1024 max
w->user_agent); // 1024 max
char weblogfname[30];
sprintf(weblogfname, "weblog%d.txt", c->local_port);
append_string_to_file(weblogfname, weblogbuf, true);
}
}
/**************************************************************************/
void filterWebRequest(connection_data *c){
web_request_data *w=c->web_request;
char *pCRLF, *pHTTP, *pCRLFCRLF;
pCRLF=NULL;
if (w->receivingHeader){
// dont filter it if there isn't enough to consist a valid
// html header request
if (w->inHeaderLen<2)
return;
// next check if the first line has been receieved
// an HTML request must finish with CRLF as per RFC 1945
pCRLF = strstr( w->inHeaderBuf, "\r\n" );
if (!pCRLF){
return;
}
// check if it is a HTTP/0.9 request
// i.e. no "HTTP/" before the first CRLF
pHTTP = strstr( w->inHeaderBuf, "HTTP/" );
if (!pHTTP || pHTTP>pCRLF){
// it must be a Simple-Request (HTTP/0.9)
logWebf("HTTP/0.9 request from %s request:%s",
c->remote_ip,w->inHeaderBuf);
processHTTP0_9Request(w);
return;
}
// PRE: Request is HTTP/1.0 or higher
// next check if the header has been completed
// If so the end of the header is marked with CRLFCRLF
pCRLFCRLF = strstr( w->inHeaderBuf, "\r\n\r\n" );
if (pCRLFCRLF){
*(pCRLFCRLF+2)='\0';
// logWebf ("%d %d", (int)*pCRLFCRLF, (int) *(pCRLFCRLF+4));
processWebHeader(w);
// now if we have a content length
if (w->contentLength){
strcpy(w->inBodyBuf,pCRLFCRLF+4);
w->inBodyLen = str_len(w->inBodyBuf);
// pHTTP = strstr( w->inHeaderBuf, "contentlength" );
// strcpy(w->inBodyBuf,pCRLFCRLF+4);
}
}else{ // isn't the end of the header yet
// do nothing really
}
}
// read the in body
if (!w->receivingHeader && (w->inBodyLen>=w->contentLength)){
}
//Content-Length:
logWebf("HTTP/1.0 request from %s",c->remote_ip);
// logf("%s", w->inHeaderBuf);
// filter it in here
{
char *pStr, *pLine;
char workingline[WEBIN_HEADER_BUF+100];
char method[21];
// check request isn't too long
if (pCRLF>w->inHeaderBuf+WEBIN_HEADER_BUF){
badRequestFormat(w, "Request-Line too long");
return;
}
strncpy(workingline, w->inHeaderBuf, pCRLF-w->inHeaderBuf);
workingline[pCRLF-w->inHeaderBuf]='\0';
pLine=workingline;
// copy parameters, checking the
// length of each command as we go
strncpy(w->firstline, workingline, 1024);
w->firstline[1023]='\0';
// extract the METHOD
pStr=strstr( pLine, " ");
if (!pStr){
badRequestFormat(w, "Request-Line invalid");
return;
}
if (pStr-pLine>20){
badRequestFormat(w, "method in Request-Line too long");
return;
}
strncpy(method, pLine, pStr-pLine);
method[pStr-pLine]='\0';
pLine=pStr+1;
// extract the LOCATION
pStr=strstr( pLine, " ");
if (!pStr){
badRequestFormat(w, "Request-Line invalid");
return;
}
if (pStr-pLine>MAXLOCATION){
badRequestFormat(w, "Request-URI (location) in Request-Line too long");
return;
}
strncpy(w->requestedLocation, pLine, pStr-pLine);
w->requestedLocation[pStr-pLine]='\0';
pLine=pStr+1;
// extract the VERSION
if (strstr( pLine, "HTTP/" )==NULL)
{
badRequestFormat(w, "no HTTP version in Request-Line");
}
if (str_len(pLine)>20){
badRequestFormat(w, "HTTP-Version in Request-Line too long");
return;
}
strcpy(w->version, pLine);
// now identify the method
if (!strcmp(method,"GET")){
w->requestType=GET;
}else
if (!strcmp(method,"HEAD")){
w->requestType=HEAD;
}else
if (!strcmp(method,"POST")){
w->requestType=POST;
}else{
w->requestType=UNDEFINED;
}
// check for a "Referer:" header
pLine=strstr( w->inHeaderBuf, "Referer:");
if(pLine){
pLine+=str_len("Referer:");
while(is_space(*pLine)){
pLine++;
}
// we have an Referer - extract it
pStr=strstr( pLine, "\r\n");
if (pStr){
strncpy(workingline, pLine, pStr-pLine);
workingline[pStr-pLine]='\0';
strncpy(w->referer,workingline, 1024);
w->referer[1023]='\0';
}else{
strcpy(w->referer,"-");
}
}else{
strcpy(w->referer,"-");
}
// check for a "User-Agent:" header
pLine=strstr( w->inHeaderBuf, "User-Agent:");
if(pLine){
pLine+=str_len("User-Agent:");
while(is_space(*pLine)){
pLine++;
}
// we have an User-Agent - extract it
pStr=strstr( pLine, "\r\n");
if (pStr){
strncpy(workingline, pLine, pStr-pLine);
workingline[pStr-pLine]='\0';
strncpy(w->user_agent,workingline, 1024);
w->user_agent[1023]='\0';
}else{
strcpy(w->user_agent,"-");
}
}else{
strcpy(w->user_agent,"-");
}
// check for an "Authorization:" header
pLine=strstr( w->inHeaderBuf, "Authorization:");
if(pLine){
// we have an Authorization - process it
pStr=strstr( pLine, "\r\n");
if (pStr){
strncpy(workingline, pLine, pStr-pLine);
workingline[pStr-pLine]='\0';
pLine=workingline;
//we have the authorization string in newline
logWebf("Processing Authorization: '%s'",workingline);
pStr=strstr( pLine, "Basic");
if (pStr){
pLine=pStr+6;
if (str_len(pLine)>0 && str_len(pLine)<200){
char decoded[200];
char *d;
d =decodeBase64(pLine);
if (d){
sprintf(decoded,d);
// now separate the username:password
pLine=decoded;
pStr=strstr( pLine, ":");
if (pStr){
if (pStr-pLine<MAXPASSLENGTH){
strncpy(w->username, pLine, pStr-pLine);
w->username[pStr-pLine]='\0';
pLine=pStr+1;
if (str_len(pLine)>MAXPASSLENGTH){
// not a valid password - so authuenticate invalid
w->username[0]='\0';
}else{
strcpy(w->password, pLine);
}
}
}
}
}
}else{
logWeb("Authorization type not recognised");
}
}
}
// filtering completed - now process the request
processWebRequest(c);
}
return;
}
/**************************************************************************/
/**************************************************************************/