Added Michael Temari's httpd

This commit is contained in:
Ben Gras 2005-09-16 13:37:29 +00:00
parent 38e6ba9eec
commit 5d8f18a091
30 changed files with 4889 additions and 1 deletions

View file

@ -56,6 +56,7 @@ all install clean::
cd ftp && $(MAKE) $@
cd ftpd && $(MAKE) $@
cd ftpd200 && $(MAKE) $@
cd httpd && $(MAKE) $@
cd ibm && $(MAKE) $@
cd indent && $(MAKE) $@
cd m4 && $(MAKE) $@

View file

@ -32,7 +32,7 @@ include ../bigmake.inc
all: all_notest test_nodep
all_notest: libbz2.a bzip2 bzip2recover
chmem =2750000 bzip2
chmem =8000000 bzip2
bzip2: libbz2.a bzip2.o
$(CC) $(CFLAGS) $(LDFLAGS) -o bzip2 bzip2.o -L. -lbz2

65
commands/httpd/Makefile Normal file
View file

@ -0,0 +1,65 @@
# Makefile for httpd
#
# 02/17/1996 Michael Temari <Michael@TemWare.Com>
# 07/07/1996 Initial Release Michael Temari <Michael@TemWare.Com>
# 12/29/2002 Michael Temari <Michael@TemWare.Com>
# 07/07/2003 Al Woodhull <awoodhull@hampshire.edu>
#
CFLAGS= -O -D_MINIX -D_POSIX_SOURCE -DDAEMON=1
#CFLAGS= -O -D_MINIX -D_POSIX_SOURCE -DDAEMON=1 -DDEBUG=9
LDFLAGS=-i
BINDIR=/usr/local/bin
HTTPD_OBJS= httpd.o utility.o request.o process.o reply.o \
police.o cgiexec.o net.o config.o pass.o proxy.o
DIR2HTML_OBJS= dir2html.o
all: httpd dir2html
httpd: $(HTTPD_OBJS)
$(CC) $(LDFLAGS) -o $@ $(HTTPD_OBJS)
install -S 16kw $@
dir2html: $(DIR2HTML_OBJS)
$(CC) $(LDFLAGS) -o $@ $(DIR2HTML_OBJS)
install -S 8kw $@
clean:
rm -f httpd $(HTTPD_OBJS) dir2html $(DIR2HTML_OBJS) *.bak
install: $(BINDIR)/httpd $(BINDIR)/in.httpd $(BINDIR)/dir2html
tar:
tar cvf ../httpd.tar Makefile README *.c *.h *.sh *.conf *.mtype
$(BINDIR)/httpd: httpd
install -cs -o bin $? $@
$(BINDIR)/in.httpd: $(BINDIR)/httpd
install -l $? $@
$(BINDIR)/dir2html: dir2html
install -cs -o bin $? $@
httpd.o: httpd.c http.h utility.h net.h config.h
utility.o: utility.c utility.h config.h
request.o: request.c http.h utility.h config.h
process.o: process.c http.h utility.h
reply.o: reply.c http.h utility.h net.h config.h
police.o: police.c http.h utility.h config.h pass.h
cgiexec.o: cgiexec.c http.h config.h
net.o: net.c net.h
config.o: config.c utility.h config.h
pass.o: pass.c pass.h
proxy.o: proxy.c http.h
dir2html.o: dir2html.c
installman:
mkdir -p /usr/local/man/man5
mkdir -p /usr/local/man/man8
cp -p httpd.conf.5 http_status.5 /usr/local/man/man5
cp -p httpd.8 /usr/local/man/man8
makewhatis /usr/local/man

242
commands/httpd/README Normal file
View file

@ -0,0 +1,242 @@
httpd documentation 7/16/96 by Michael Temari <Michael@TemWare.Com>
updated 2003-07-05 by Al Woodhull <awoodhull@hampshire.edu>
DISCLAIMER:
Use at own risk etc...
COMMENTS:
Please send me any bug reports, comments, questions, etc... My email
address is Michael@TemWare.Com
BACKGROUND:
httpd is a World Wide Web (WWW) server. I wrote it from scratch so
the setup and configuration will not be like other web servers though
hopefully by reading this document there will be no problems in getting
my web server up and running on your Minix system.
COMPILING:
To compile httpd all you need to do is type "make" in the httpd source
directory. There should be no errors or warnings. If you should run
out of memory when compiling try adding the -m option to the CFLAGS
list in the Makefile.
INSTALLING:
To install httpd all you need to do is type "make install" in the httpd
source directory. By default the place to install httpd is into
/usr/local/bin. If you would like to change this then change BINDIR in
the Makefile. Httpd will be linked to in.httpd, which is the preferred
name for a program started by the tcpd internet access control program.
The program dir2html is also installed -- this provides a directory
listing when a web client accesses a directory which does not contain a
file named index.html (or an alternative designated in /etc/httpd.conf).
The man pages are installed by typing "make installman".
CONFIGURING:
Before running httpd it must be configured. The name of the default
configuration file is /etc/httpd.conf or you may pass the configuration
file name to httpd. Upon starting up, httpd will parse the configuration
file and then process requests. This README file and the sample httpd.conf
may also help in configuring. The httpd.conf.5 man page presents the same
information for reference use.
The configuration file is an ascii file which consists of lines of the
following form:
directive LWS [parameters separated by LWS]
NOTE: LWS denotes Linear White Space which is spaces and/or tabs
The following are valid configuration file directives:
serverroot user chroot logfile dbgfile dirsend direxec vhost auth
proxyauth vpath include mtype
To make the file more readable, on directives which occupy multiple
lines you may omit the directive on lines after the first and begin
these lines with LWS.
serverroot path
The serverroot directive sets the translation for // to the given path.
user username
The user directive causes the server to run as the given username, otherwise
the server will run as whoever started it (normally root).
chroot directory
The chroot directive causes the server to chroot to the given directory after
the configuration and log files have been opened. Normally this will be the
home directory of the given username in the user directive.
NOTE: /~user will be translated to the home directory of the given user
// will be translated to the serverroot directory
NOTE: if this directive is used then beware of the consequences.
logfile filename
The logfile directive tells the server where to log http transactions.
NOTE: the file must exist to enable logging
dbgfile filename
The dbgfile directive tells the server where to log debug http transactions.
NOTE: the file must exist to enable logging
dirsend filelist
The dirsend directive tells the server that when a directory is requested
that it should send the first file that it finds in the directory from the
filelist for the request.
direxec program
The direxec directive tells the server that when a directory is requested
and no file is found from the dirsend directive that it should run the
given program.
NOTE: the program normally generates a directory listing on the fly
NOTE: the program access is considered X with no access restrictions.
vhost hostname VhostRoot
vhost is for defining access for virtual hosts. If none are configured then
any host is accepted. If specified then access is only granted for requests
for hosts which are configured here. In the Vpath section below the /// gets
translated to the corresponding VhostRoot.
auth authname authdescription access [passwdfile [users]]
The auth directive sets up different authorizations with the server. The
authname is the name given to the authorization and is case insensitive.
The authdescription is the description of the authorization and is what
the user will see when asked to enter a username and password. The
access is one or more of (rwx). R tells the server the url can be
read. W tells the server the url can be overwritten. X tells the server
that the url can and should be executed. Access is in addition to normal
unix security considerations. For instance a file that can be written to
that does not have the W access will have an error returned. The
passwdfile is the name of the passwdfile to validate users against. If
the passwdfile is given as '.' then the system password file will be used
which is /etc/passwd. If no passwdfile is given then no authorization is
allowed for anyone. If no users are given then any validated users is
authorized, otherwise only the given users are allowed.
proxyauth authname authdescription access [passwdfile [users]]
proxyauth defines any access authorization to be used for Proxy access
authname = Same as auth above
authdescription = Same as auth above
access = Must be R to allow proxy
passwdfile = Same as auth above
users = Same as auth above
vpath from to [auth [access]]
The vpath directive sets up url path translations and authorizations. A
requested url that matches from will be translated to to with the given
auth and access. If auth does not exist then the url will have no access.
If access is not given then the access is taken from the auth record (see
above). A '.' in place of the to means that the server should use a
translation from another vpath record, but associate the given auth and
access with the requested url. A '*' maybe at the end only of the from
which is a wildcard match. For example if the from has /AB* then any of
/ABCDEF or /AB or /ABmichael will match, but /AD or /a will not. The
requested url is first checked against each vpath record until an exact
match (meaning url match from and from had no '*') is found or the end of
the list. Therefore a wildcard match will match the last from is the list
in which it matched.
NOTE: if at the beginning of the to field
/~user will get translated to the home directory of the given user
// wile get translated to the serverroot directory
include filename
The include directive tells the server to read configuration information
from the given filename.
NOTE: normally mtype directives are included from another file
mtype mimetype extensions
The mtype directive tells the server what mimetype to associate with files
which have any of the given extensions. If no match is found then the file
will be treated as application/octet-stream.
NOTE: normally you get mtype directives in included file
USAGE:
httpd [-v|-t] [configuration-file]
The -t tells the server to just parse the configuration file so that you
can test it to see if it is the way you want it. You may also pass the
name of your configuration file if it is not the default /etc/httpd.conf.
The -v option prints the server version and then exits.
STARTING:
First of all httpd is a server and therefore you will need to start it
with tcpd. Tcpd is a program which listens for incoming TCP connections
on the passed port and when a connection comes in it forks and starts the
given daemon program. Therefore to start httpd you use:
tcpd http /usr/local/bin/in.httpd &
You will more than likely have this line in your /etc/rc or /etc/rc.net
file so that whenever your system is restarted the web server will also
be started. The first parameter http is the port that tcpd is going
to be listening for connections on. Here http (which should be defined
in /etc/services as 80) is the standard port for a web server. The second
parameter is the program that tcpd will fork and exec when a connection
comes in. The program will then have its stdin and stderr connected to
the client Then the web server program will start running with the tcpd
program waiting for the next connection. Currently there is no ability to
limit the number of simultaneous web servers running. NOTE: At some point
I will be adding the ability for httpd to start itself without the need of
tcpd. That way httpd will already be in memory and have parsed its
configuration file.
In Minix 2.0.3 and later versions you may use:
daemonize tcpd http /usr/local/bin/in.httpd
(daemonize is a shell function defined in /usr/etc/rc which starts programs
as daemons).
FINAL WORDS
I wanted to get the server out as soon as possible so I hurried up and
created this document to help out. Hopefully it will HELP more than
it HURTS. If anyone is interested in writing man pages for httpd or any
of the other network programs please let me know.
Michael Temari
Michael@TemWare.Com
Please note also the SECURITY document in this directory. (asw 2003-07-05)

48
commands/httpd/SECURITY Normal file
View file

@ -0,0 +1,48 @@
SECURITY NOTE
Al Woodhull <awoodhull@hampshire.edu> 2003-07-05
Running a web server is fun, but it's also not without risks. If, like
many Minix users, you are a guest on someone else's network, you need
to be very careful to operate your server in ways that will not put
your system at risk or interfere with others on the net. Here are some
points to consider:
- Be sure to touch /usr/adm/httpd.log (or whatever you specify as the log
file in httpd.conf) before you start your web server for the first time
-- nothing will be logged if the log file does not exist. Then look at
your log file frequently and be alert for any unusual activity.
- You may also want to be sure that tcpd is configured to operate in
PARANOID mode. That will enable logging of connection attempts and
allow you to use the serv.access (5) file to limit the kinds of
connections that your system allows.
- If you enable proxy webserving, be very careful, it can be used by
people you don't know to visit sites that don't welcome visitors whose
identity is hidden. This may cause your network host and ultimately you
some unpleasantness.
- The Minix httpd can also support CGI applications. These are also
dangerous -- a CGI application allows someone else to execute a program
on your computer. Make sure anything you allow this way cannot be
abused. Many security violations are due to effects of input that was not
expected by the original author of a program.
- It's an understatement to say that Minix is not a well-known
operating system. There are not many Minix systems operating as
servers on the internet. A consequence of this is that there few, if
any, people engaged in finding ways to attack weaknesses in Minix. But
the idea of "security through obscurity" is deprecated by serious
computer security experts. Any operating system or program of any
degree of complexity is likely to have bugs or features that can be
exploited in ways the original programmers did not foresee. You can't
count on the "good guys" being the first ones to discover a risk.
There are two things you should be sure to do if you are running a
network server of any kind:
(1) be alert for new versions of the program that may fix bugs
discovered by other users, and
(2) be sure to report to the program author or maintainer anything you
observe that looks like a bug or a way the program can be misused.

3
commands/httpd/build Executable file
View file

@ -0,0 +1,3 @@
#!/bin/sh
make clean
make && make install

255
commands/httpd/cgiexec.c Normal file
View file

@ -0,0 +1,255 @@
/* cgiexec.c by Michael Temari 02/17/96
*
* This file is part of httpd.
*
* 02/17/1996 Michael Temari <Michael@TemWare.Com>
* 07/07/1996 Initial Release Michael Temari <Michael@TemWare.Com>
* 12/29/2002 Michael Temari <Michael@TemWare.Com>
* 02/08/2005 Michael Temari <Michael@TemWare.Com>
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include "http.h"
#include "config.h"
#include "net.h"
_PROTOTYPE(char **cgienv, (struct http_request *rq, struct http_reply *rp));
_PROTOTYPE(static int addenv, (char *name, char *value, char **buf, int *len));
int cgiexec(rq, rp)
struct http_request *rq;
struct http_reply *rp;
{
struct stat st;
char *prog;
int cmdpid;
int status;
char *argv[5];
int ifds[2];
int ofds[2];
static char cmd[2048];
char **cmdenv;
int dirflag = 0;
if(stat(rp->realurl, &st)) {
if(errno == EACCES)
rp->status = HTTP_STATUS_FORBIDDEN;
else
rp->status = HTTP_STATUS_NOT_FOUND;
strcpy(rp->statusmsg, strerror(errno));
return(-1);
}
if((st.st_mode & S_IFMT) == S_IFDIR)
if(direxec != NULL) {
prog = direxec; dirflag = 1;
} else
return(0);
else
prog = rp->realurl;
/* check if prog is allowed to be exec'd */
if(!dirflag && !(rp->urlaccess & URLA_EXEC))
return(0);
/* if cannot exec mode then return */
if( (st.st_mode & S_IXUSR) == 0 &&
(st.st_mode & S_IXGRP) == 0 &&
(st.st_mode & S_IXOTH) == 0 )
return(0);
if((cmdenv = cgienv(rq, rp)) == NULL) {
rp->status = HTTP_STATUS_SERVER_ERROR;
strcpy(rp->statusmsg, "Could not setup cgi environment");
return(-1);
}
argv[0] = prog;
argv[1] = rp->realurl;
argv[2] = rq->url;
argv[3] = (char *)NULL;
if(pipe(ifds) < 0) {
rp->status = HTTP_STATUS_NOT_FOUND;
strcpy(rp->statusmsg, strerror(errno));
return(-1);
}
if(pipe(ofds) < 0) {
rp->status = HTTP_STATUS_NOT_FOUND;
strcpy(rp->statusmsg, strerror(errno));
close(ifds[0]); close(ifds[1]);
return(-1);
}
if((cmdpid = fork()) < 0) {
close(ifds[0]); close(ofds[0]);
close(ifds[1]); close(ofds[1]);
rp->status = HTTP_STATUS_NOT_FOUND;
strcpy(rp->statusmsg, strerror(errno));
return(-1);
}
/* We don't know how much data is going to be passed back */
rp->size = 0;
if(cmdpid == 0) { /* Child */
#if 0
if((cmdpid = fork()) < 0) {
close(ifds[0]); close(ofds[0]);
close(ifds[1]); close(ofds[1]);
exit(-1);
}
if(cmdpid != 0) {
close(ifds[0]); close(ofds[0]);
close(ifds[1]); close(ofds[1]);
exit(0);
}
#endif
setsid();
close(ifds[0]); close(ofds[1]);
dup2(ofds[0], 0);
dup2(ifds[1], 1);
dup2(ifds[1], 2);
close(ifds[1]); close(ofds[0]);
execve(argv[0], argv, cmdenv);
exit(0);
}
#if 0
/* Get rid of Zombie child */
(void) wait(&status);
#endif
close(ifds[1]); close(ofds[0]);
rp->fd = ifds[0];
rp->ofd = ofds[1];
rp->pid = cmdpid;
if(rp->urlaccess & URLA_HEADERS)
rp->headers = -1;
return(-1);
}
char **cgienv(rq, rp)
struct http_request *rq;
struct http_reply *rp;
{
static char buffer[4096];
char *p, *p2;
char **e;
int len;
char temp[20];
p = buffer;
len = sizeof(buffer);
if(addenv("PATH", "/usr/local/bin:/bin:/usr/bin", &p, &len)) return(NULL);
if(getenv("TZ") != (char *)NULL)
if(addenv("TZ", getenv("TZ"), &p, &len)) return(NULL);
/* HACK - some of these are hardcoded and should not be MAT 3/17/96 */
/* HTTP_ */
if(addenv("SERVER_SOFTWARE", "Temari httpd/1.0", &p, &len)) return(NULL);
if(addenv("SERVER_NAME", myhostname, &p, &len)) return(NULL);
if(addenv("GATEWAY_INTERFACE", "CGI/1.1", &p, &len)) return(NULL);
if(addenv("SERVER_PROTOCOL", "HTTP/1.0", &p, &len)) return(NULL);
if(rq->port)
sprintf(temp, "%u", rq->port);
else
strcpy(temp, "80");
if(addenv("SERVER_PORT", temp, &p, &len)) return(NULL);
switch(rq->method) {
case HTTP_METHOD_GET:
if(addenv("REQUEST_METHOD", "GET", &p, &len)) return(NULL);
break;
case HTTP_METHOD_POST:
if(addenv("REQUEST_METHOD", "POST", &p, &len)) return(NULL);
break;
case HTTP_METHOD_HEAD:
if(addenv("REQUEST_METHOD", "HEAD", &p, &len)) return(NULL);
break;
case HTTP_METHOD_PUT:
if(addenv("REQUEST_METHOD", "PUT", &p, &len)) return(NULL);
break;
default:
if(addenv("REQUEST_METHOD", "UNKNOWN", &p, &len)) return(NULL);
}
if(addenv("PATH_INFO", "?", &p, &len)) return(NULL);
if(addenv("PATH_TRANSLATED", "?", &p, &len)) return(NULL);
if(addenv("SCRIPT_NAME", rq->url, &p, &len)) return(NULL);
if(addenv("QUERY_STRING", rq->query, &p, &len)) return(NULL);
if(addenv("REMOTE_HOST", rmthostname, &p, &len)) return(NULL);
if(addenv("REMOTE_ADDR", rmthostaddr, &p, &len)) return(NULL);
if(rq->authuser != (char *)NULL)
if(addenv("AUTH_USER", rq->authuser, &p, &len)) return(NULL);
/* AUTH_TYPE */
/* REMOTE_USER */
/* REMOTE_IDENT */
if(rq->method == HTTP_METHOD_POST) {
if(addenv("CONTENT_TYPE", "application/x-www-form-urlencoded", &p, &len)) return(NULL);
sprintf(temp, "%lu", rq->size);
if(addenv("CONTENT_LENGTH", temp, &p, &len)) return(NULL);
}
/* COOKIE */
if(rq->cookie[0] != '\0')
if(addenv("COOKIE", rq->cookie, &p, &len)) return(NULL);
/* HOST */
if(addenv("HOST", rq->host, &p, &len)) return(NULL);
if(len < 1) return(NULL);
*p++ = '\0';
p2 = buffer;
e = (char **)p;
while(*p2) {
if(len < sizeof(e)) return(NULL);
len -= sizeof(e);
*e++ = p2;
while(*p2) p2++;
p2++;
}
if(len < sizeof(e)) return(NULL);
*e++ = NULL;
return((char **)p);
}
static int addenv(name, value, buf, len)
char *name;
char *value;
char **buf;
int *len;
{
char *p;
int size;
p = *buf;
size = strlen(name)+1+strlen(value)+1;
if(size > *len)
return(-1);
sprintf(p, "%s=%s", name, value);
p += size;
*buf = p;
*len -= size;
return(0);
}

813
commands/httpd/config.c Normal file
View file

@ -0,0 +1,813 @@
/* config.c by Michael Temari 02/26/96
*
* This file is part of httpd.
*
* 02/26/1996 Michael Temari <Michael@TemWare.Com>
* 07/07/1996 Initial Release Michael Temari <Michael@TemWare.Com>
* 12/29/2002 Michael Temari <Michael@TemWare.Com>
*
*/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <pwd.h>
#include "utility.h"
#include "config.h"
struct mtype *mtype = NULL;
struct msufx *msufx = NULL;
struct vhost *vhost = NULL;
struct vpath *vpath = NULL;
struct dirsend *dirsend = NULL;
struct auth *auth = NULL;
struct auth *proxyauth = NULL;
char *direxec = NULL;
char *srvrroot = "";
char *LogFile = NULL;
char *DbgFile = NULL;
char *User = NULL;
char *Chroot = NULL;
_PROTOTYPE(static int doconfig, (char *cfg_file));
_PROTOTYPE(static int doinclude, (char *parms[], int np));
_PROTOTYPE(static int domtype, (char *parms[], int np));
_PROTOTYPE(static struct auth *findauth, (char *name));
_PROTOTYPE(static int dovhost, (char *parms[], int np));
_PROTOTYPE(static int dovpath, (char *parms[], int np));
_PROTOTYPE(static int dosrvrroot, (char *parms[], int np));
_PROTOTYPE(static int dodirsend, (char *parms[], int np));
_PROTOTYPE(static int dodirexec, (char *parms[], int np));
_PROTOTYPE(static char *subvpath, (char *s));
_PROTOTYPE(static int dologfile, (char *parms[], int np));
_PROTOTYPE(static int dodbgfile, (char *parms[], int np));
_PROTOTYPE(static int douser, (char *parms[], int np));
_PROTOTYPE(static int dochroot, (char *parms[], int np));
_PROTOTYPE(static int adduser, (struct auth *pauth, char *user));
_PROTOTYPE(static int doauth, (char *parms[], int np));
_PROTOTYPE(static int doproxyauth, (char *parms[], int np));
int readconfig(cfg_file, testing)
char *cfg_file;
int testing;
{
int s;
char *cfg;
struct msufx *ps;
struct mtype *pt;
struct vhost *ph;
struct vpath *pv;
struct dirsend *pd;
struct auth *pa;
cfg = HTTPD_CONFIG_FILE;
if(cfg_file != (char *)NULL)
if(*cfg_file)
cfg = cfg_file;
s = doconfig(cfg);
if(testing) {
printf("ServerRoot: %s\n", srvrroot);
printf("UserName: %s\n", User == NULL ? "" : User);
printf("Chroot: %s\n", Chroot == NULL ? "" : Chroot);
printf("LogFile: %s\n", LogFile == NULL ? "" : LogFile);
printf("DbgFile: %s\n", DbgFile == NULL ? "" : DbgFile);
printf("DirSend:");
for(pd = dirsend; pd != NULL; pd = pd->next)
printf(" %s", pd->file);
printf("\n");
printf("DirExec: %s\n", direxec == NULL ? "" : direxec);
for(ph = vhost; ph != NULL; ph = ph->next)
printf("VHost: %s %s\n", ph->hname, ph->root);
for(pa = auth; pa != NULL; pa = pa->next)
printf("Auth: %s %s %d %s\n",
pa->name, pa->desc, pa->urlaccess, pa->passwdfile);
for(pa = proxyauth; pa != NULL; pa = pa->next)
printf("ProxyAuth: %s %s %d %s\n",
pa->name, pa->desc, pa->urlaccess, pa->passwdfile);
for(pv = vpath; pv != NULL; pv = pv->next)
printf("Vpath: %s %s %s %d\n",
pv->from, pv->to, pv->auth->name, pv->urlaccess);
for(pt = mtype; pt != NULL; pt = pt->next) {
printf("MType: %s :", pt->mimetype);
for(ps = pt->msufx; ps != NULL; ps = ps->tnext)
printf(" '%s'", ps->suffix);
printf("\n");
}
for(ps = msufx; ps != NULL; ps = ps->snext)
printf("Suffix: %s\t%s\n", ps->suffix, ps->mtype->mimetype);
}
return(s);
}
static int doconfig(cfg_file)
char *cfg_file;
{
FILE *fp;
int np;
int s;
char *p;
char ltype[40];
char *parms[30];
static char buffer[2048];
if((fp = fopen(cfg_file, "r")) == (FILE *)NULL) {
fprintf(stderr, "httpd: Could not read %s config file.\n", cfg_file);
return(-1);
}
*ltype = '\0';
while(fgets(buffer, sizeof(buffer), fp) != (char *)NULL) {
if(buffer[0] == '#') continue; /* skip comments */
np = getparms(buffer, parms, sizeof(parms)/sizeof(parms[0]));
if(np == 0) continue; /* blank line */
if(parms[0] == (char *)NULL)
parms[0] = ltype;
else {
p = parms[0];
while(*p) *p++ = tolower(*p);
strncpy(ltype, parms[0], sizeof(ltype));
}
s = 0;
if(!strcmp(parms[0], "mtype")) s = domtype(parms, np);
else
if(!strcmp(parms[0], "vhost")) s = dovhost(parms, np);
else
if(!strcmp(parms[0], "vpath")) s = dovpath(parms, np);
else
if(!strcmp(parms[0], "serverroot")) s = dosrvrroot(parms, np);
else
if(!strcmp(parms[0], "dirsend")) s = dodirsend(parms, np);
else
if(!strcmp(parms[0], "direxec")) s = dodirexec(parms, np);
else
if(!strcmp(parms[0], "logfile")) s = dologfile(parms, np);
else
if(!strcmp(parms[0], "dbgfile")) s = dodbgfile(parms, np);
else
if(!strcmp(parms[0], "user")) s = douser(parms, np);
else
if(!strcmp(parms[0], "chroot")) s = dochroot(parms, np);
else
if(!strcmp(parms[0], "auth")) s = doauth(parms, np);
else
if(!strcmp(parms[0], "proxyauth")) s = doproxyauth(parms, np);
else
if(!strcmp(parms[0], "include")) s = doinclude(parms, np);
else
fprintf(stderr, "httpd: Unknown directive: %s\n", parms[0]);
if(s) {
fprintf(stderr, "httpd: Error processing config file\n");
fclose(fp);
return(-1);
}
}
fclose(fp);
return(0);
}
static int doinclude(parms, np)
char *parms[];
int np;
{
char *p;
if(np < 2) return(0);
p = subvpath(parms[1]);
return(doconfig(p));
}
static int domtype(parms, np)
char *parms[];
int np;
{
int i;
struct mtype *pt, *lpt, *newpt;
struct msufx *ps, *lps, *newps, *psend;
if(np < 2) return(0);
/* check if this mime type already exists in the list */
for(pt = mtype, lpt = NULL; pt != NULL; lpt = pt, pt = pt->next)
if(!strcmp(parms[1], pt->mimetype))
break;
if(pt == NULL) { /* not there so add it */
newpt = malloc(sizeof(struct mtype));
if(newpt == NULL) {
fprintf(stderr, "httpd: malloc failed in domtype\n");
return(-1);
}
newpt->mimetype = malloc(strlen(parms[1])+1);
if(newpt->mimetype == NULL) {
fprintf(stderr, "httpd: malloc failed in domtype\n");
return(-1);
}
strcpy(newpt->mimetype, parms[1]);
newpt->msufx = NULL;
newpt->next = NULL;
if(lpt == NULL)
mtype = newpt;
else
lpt->next = newpt;
} else
newpt = pt;
/* find end of suffix list */
for(ps = newpt->msufx, lps = NULL; ps != NULL; lps = ps, ps = ps->tnext) ;
psend = lps;
/* if no suffix given then add empty suffix for default */
if(np == 2)
strcpy(parms[np++], "");
/* add each suffix to the mime type */
for(i = 2; i < np; i++) {
/* a suffix can only be for a single mime type */
for(ps = msufx, lps = NULL; ps != NULL; lps = ps, ps = ps->snext) {
if(!strcmp(ps->suffix, parms[i])) {
fprintf(stderr, "httpd: Suffix already found\n");
return(-1);
}
if(strlen(parms[i]) > strlen(ps->suffix)) break;
}
newps = malloc(sizeof(struct msufx));
if(newps == NULL) {
fprintf(stderr, "httpd: malloc failed in domtype\n");
return(-1);
}
newps->suffix = malloc(strlen(parms[i])+1);
if(newps->suffix == NULL) {
fprintf(stderr, "httpd: malloc failed in domtype\n");
return(-1);
}
strcpy(newps->suffix, parms[i]);
newps->mtype = newpt;
newps->snext = NULL;
newps->tnext = NULL;
if(lps == NULL) {
msufx = newps;
newps->snext = ps;
} else {
lps->snext = newps;
newps->snext = ps;
}
if(psend == NULL)
newpt->msufx = newps;
else
psend->tnext = newps;
psend = newps;
}
return(0);
}
static struct auth *findauth(name)
char *name;
{
char lname[80];
char *p, *p2;
struct auth *a = NULL;
if(sizeof(lname) < (strlen(name)+1)) {
fprintf(stderr, "httpd: lname too small in findauth\n");
return(a);
}
p = name; p2 = lname;
while(*p)
*p2++ = tolower(*p++);
*p2 = '\0';
for(a = auth; a != NULL; a = a->next)
if(!strcmp(a->name, lname)) break;
return(a);
}
static int dovhost(parms, np)
char *parms[];
int np;
{
char *hname, *root;
struct vhost *ph, *lph, *newph;
if(np < 2) return(0);
hname = parms[1];
if(np < 3)
root = "";
else
root = parms[2];
for(ph = vhost, lph = NULL; ph != NULL; lph = ph, ph = ph->next)
;
newph = malloc(sizeof(struct vhost));
if(newph == NULL) {
fprintf(stderr, "httpd: malloc failed in dovhost\n");
return(-1);
}
newph->hname = malloc(strlen(hname)+1);
if(newph->hname == NULL) {
fprintf(stderr, "httpd: malloc failed in dovhost\n");
return(-1);
}
strcpy(newph->hname, hname);
root = subvpath(root);
newph->root = malloc(strlen(root)+1);
if(newph->root == NULL) {
fprintf(stderr, "httpd: malloc failed in dovhost\n");
return(-1);
}
strcpy(newph->root, root);
if(np > 3)
if(parms[3][0] != '#') {
fprintf(stderr, "httpd: junk at end of vhost line\n");
return(-1);
}
newph->next = NULL;
if(lph == NULL) {
vhost = newph;
newph->next = ph;
} else {
lph->next = newph;
newph->next = ph;
}
return(0);
}
static int dovpath(parms, np)
char *parms[];
int np;
{
char *from, *to;
struct vpath *pv, *lpv, *newpv;
if(np < 3) return(0);
from = parms[1];
to = parms[2];
for(pv = vpath, lpv = NULL; pv != NULL; lpv = pv, pv = pv->next)
;
newpv = malloc(sizeof(struct vpath));
if(newpv == NULL) {
fprintf(stderr, "httpd: malloc failed in dovpath\n");
return(-1);
}
newpv->from = malloc(strlen(from)+1);
if(newpv->from == NULL) {
fprintf(stderr, "httpd: malloc failed in dovpath\n");
return(-1);
}
strcpy(newpv->from, from);
to = subvpath(to);
newpv->to = malloc(strlen(to)+1);
if(newpv->to == NULL) {
fprintf(stderr, "httpd: malloc failed in dovpath\n");
return(-1);
}
strcpy(newpv->to, to);
newpv->auth = NULL;
newpv->urlaccess = -1;
if(np > 3)
if(parms[3][0] != '#') {
newpv->auth = findauth(parms[3]);
if(np > 4)
if(parms[4][0] != '#') {
newpv->urlaccess = mkurlaccess(parms[4]);
if(np > 5)
if(parms[5][0] != '#') {
fprintf(stderr, "httpd: junk at end of vpath line\n");
return(-1);
}
}
}
newpv->next = NULL;
if(lpv == NULL) {
vpath = newpv;
newpv->next = pv;
} else {
lpv->next = newpv;
newpv->next = pv;
}
return(0);
}
static int dosrvrroot(parms, np)
char *parms[];
int np;
{
char *newroot;
if(np < 2) return(0);
newroot = subvpath(parms[1]);
srvrroot = malloc(strlen(newroot)+1);
if(srvrroot == NULL) {
fprintf(stderr, "httpd: malloc failed in dosrvrroot\n");
return(-1);
}
strcpy(srvrroot, newroot);
if(srvrroot[strlen(srvrroot)-1] == '/')
srvrroot[strlen(srvrroot)-1] = '\0';
return(0);
}
static int dodirsend(parms, np)
char *parms[];
int np;
{
char *file;
int i;
struct dirsend *pd, *lpd, *npd;
if(np < 2) return(0);
/* find end of the list */
for(pd = dirsend, lpd = NULL; pd != NULL; lpd = pd, pd = pd->next) ;
for(i = 1; i < np; i++) {
file = parms[i];
if(file[0] == '#') break;
npd = malloc(sizeof(struct dirsend));
if(npd == NULL) {
fprintf(stderr, "httpd: malloc failed in dodirsend\n");
return(-1);
}
npd->file = malloc(strlen(file)+1);
if(npd->file == NULL) {
fprintf(stderr, "httpd: malloc failed in dodirsend\n");
return(-1);
}
strcpy(npd->file, file);
npd->next = NULL;
if(lpd == NULL)
dirsend = npd;
else
lpd->next = npd;
lpd = npd;
}
return(0);
}
static int dodirexec(parms, np)
char *parms[];
int np;
{
char *file;
if(np < 2) return(0);
if(direxec != NULL) {
fprintf(stderr, "httpd: Error direxec line already present\n");
return(-1);
}
file = subvpath(parms[1]);
direxec = malloc(strlen(file)+1);
if(direxec == NULL) {
fprintf(stderr, "httpd: malloc failed in dodirexec\n");
return(-1);
}
strcpy(direxec, file);
if(np > 2)
if(parms[2][0] != '#') {
fprintf(stderr, "httpd: garbage on end of direxec line\n");
return(-1);
}
return(0);
}
static char *subvpath(s)
char *s;
{
char *p, *p2;
int len;
static char buffer[1024];
char user[80];
struct passwd *pwd;
/* replace beginning // with srvrroot */
if(s[0] == '/' && s[1] == '/')
/* but not /// if we have VHOST's */
if(vhost == NULL || s[2] != '/') {
strcpy(buffer, srvrroot);
strncat(buffer, s+1, sizeof(buffer) - strlen(buffer));
buffer[sizeof(buffer)-1] = '\0';
return(buffer);
}
if(s[0] != '/' || s[1] != '~') return(s);
/* replace beginning /~user with user home directory */
p = s + 2;
p2 = user;
len = sizeof(user) - 1;
while(*p && *p != '/' && len-- > 0) *p2++ = *p++;
*p2 = '\0';
if(*p != '\0' && *p != '/') return(s);
if((pwd = getpwnam(user)) == (struct passwd *)NULL) return(s);
strcpy(buffer, pwd->pw_dir);
strncat(buffer, p, sizeof(buffer) - strlen(buffer));
buffer[sizeof(buffer)-1] = '\0';
return(buffer);
}
static int dologfile(parms, np)
char *parms[];
int np;
{
char *p;
if(np < 2) return(0);
p = subvpath(parms[1]);
LogFile = malloc(strlen(p)+1);
if(LogFile == NULL) {
fprintf(stderr, "httpd: malloc failed in dologfile\n");
return(-1);
}
strcpy(LogFile, p);
return(0);
}
static int dodbgfile(parms, np)
char *parms[];
int np;
{
char *p;
if(np < 2) return(0);
p = subvpath(parms[1]);
DbgFile = malloc(strlen(p)+1);
if(DbgFile == NULL) {
fprintf(stderr, "httpd: malloc failed in dodbgfile\n");
return(-1);
}
strcpy(DbgFile, p);
return(0);
}
static int douser(parms, np)
char *parms[];
int np;
{
if(np < 2) return(0);
User = malloc(strlen(parms[1])+1);
if(User == NULL) {
fprintf(stderr, "httpd: malloc failed in douser\n");
return(-1);
}
strcpy(User, parms[1]);
return(0);
}
static int dochroot(parms, np)
char *parms[];
int np;
{
char *newroot;
if(np < 2) return(0);
newroot = subvpath(parms[1]);
Chroot = malloc(strlen(newroot)+1);
if(Chroot == NULL) {
fprintf(stderr, "httpd: malloc failed in dochroot\n");
return(-1);
}
strcpy(Chroot, newroot);
return(0);
}
static int adduser(pauth, user)
struct auth *pauth;
char *user;
{
struct authuser *pa, *lpa, *newpa;
for(pa = pauth->users, lpa = NULL; pa != NULL; lpa = pa, pa = pa->next)
;
newpa = malloc(sizeof(struct authuser));
if(newpa == NULL) {
fprintf(stderr, "httpd: malloc failed in adduser\n");
return(-1);
}
newpa->user = malloc(strlen(user)+1);
if(newpa->user == NULL) {
fprintf(stderr, "httpd: malloc failed in adduser\n");
return(-1);
}
strcpy(newpa->user, user);
newpa->next = NULL;
if(lpa == NULL) {
pauth->users = newpa;
newpa->next = pa;
} else {
lpa->next = newpa;
newpa->next = pa;
}
return(0);
}
static int doauth(parms, np)
char *parms[];
int np;
{
int i;
char *name, *desc, *pf;
char *p, *p2;
struct auth *pa, *lpa, *newpa;
if(np < 3) return(0);
name = parms[1];
desc = parms[2];
for(pa = auth, lpa = NULL; pa != NULL; lpa = pa, pa = pa->next)
;
newpa = malloc(sizeof(struct auth));
if(newpa == NULL) {
fprintf(stderr, "httpd: malloc failed in doauth\n");
return(-1);
}
newpa->name = malloc(strlen(name)+1);
if(newpa->name == NULL) {
fprintf(stderr, "httpd: malloc failed in doauth\n");
return(-1);
}
p = name; p2 = newpa->name;
while(*p)
*p2++ = tolower(*p++);
*p2 = '\0';
newpa->desc = malloc(strlen(desc)+1);
if(newpa->desc == NULL) {
fprintf(stderr, "httpd: malloc failed in doauth\n");
return(-1);
}
strcpy(newpa->desc, desc);
newpa->urlaccess = mkurlaccess(parms[3]);
newpa->passwdfile = NULL;
newpa->users = NULL;
if(np > 4)
if(parms[4][0] != '#') {
if(!strcmp(parms[4], "."))
pf = "/etc/passwd";
else
pf = subvpath(parms[4]);
newpa->passwdfile = malloc(strlen(pf)+1);
if(newpa->passwdfile == NULL) {
fprintf(stderr, "httpd: malloc failed in doauth\n");
return(-1);
}
strcpy(newpa->passwdfile, pf);
i = 5;
while(i < np) {
if(parms[i][0] == '#')
break;
if(adduser(newpa, parms[i]))
return(-1);
i++;
}
}
newpa->next = NULL;
if(lpa == NULL) {
auth = newpa;
newpa->next = pa;
} else {
lpa->next = newpa;
newpa->next = pa;
}
return(0);
}
static int doproxyauth(parms, np)
char *parms[];
int np;
{
int i;
char *name, *desc, *pf;
char *p, *p2;
struct auth *pa, *lpa, *newpa;
if(np < 3) return(0);
name = parms[1];
desc = parms[2];
if(proxyauth != (struct auth *)NULL) {
fprintf(stderr, "httpd: ProxyAuth defined multiple times using 1st only\n");
return(0);
}
for(pa = proxyauth, lpa = NULL; pa != NULL; lpa = pa, pa = pa->next)
;
newpa = malloc(sizeof(struct auth));
if(newpa == NULL) {
fprintf(stderr, "httpd: malloc failed in doproxyauth\n");
return(-1);
}
newpa->name = malloc(strlen(name)+1);
if(newpa->name == NULL) {
fprintf(stderr, "httpd: malloc failed in doproxyauth\n");
return(-1);
}
p = name; p2 = newpa->name;
while(*p)
*p2++ = tolower(*p++);
*p2 = '\0';
newpa->desc = malloc(strlen(desc)+1);
if(newpa->desc == NULL) {
fprintf(stderr, "httpd: malloc failed in doproxyauth\n");
return(-1);
}
strcpy(newpa->desc, desc);
newpa->urlaccess = mkurlaccess(parms[3]);
newpa->passwdfile = NULL;
newpa->users = NULL;
if(np > 4)
if(parms[4][0] != '#') {
if(!strcmp(parms[4], "."))
pf = "/etc/passwd";
else
pf = subvpath(parms[4]);
newpa->passwdfile = malloc(strlen(pf)+1);
if(newpa->passwdfile == NULL) {
fprintf(stderr, "httpd: malloc failed in doauth\n");
return(-1);
}
strcpy(newpa->passwdfile, pf);
i = 5;
while(i < np) {
if(parms[i][0] == '#')
break;
if(adduser(newpa, parms[i]))
return(-1);
i++;
}
}
newpa->next = NULL;
if(lpa == NULL) {
proxyauth = newpa;
newpa->next = pa;
} else {
lpa->next = newpa;
newpa->next = pa;
}
return(0);
}

84
commands/httpd/config.h Normal file
View file

@ -0,0 +1,84 @@
/* config.h
*
* This file is part of httpd.
*
* 02/26/1996 Michael Temari <Michael@TemWare.Com>
* 07/07/1996 Initial Release Michael Temari <Michael@TemWare.Com>
* 12/29/2002 Michael Temari <Michael@TemWare.Com>
* 07/04/2003 Al Woodhull <awoodhull@hampshire.edu>
* 02/08/2005 Michael Temari <Michael@TemWare.Com>
*
*/
#define VERSION "Minix httpd 0.994"
struct authuser {
char *user;
struct authuser *next;
};
struct auth {
char *name;
char *desc;
int urlaccess;
char *passwdfile;
struct authuser *users;
struct auth *next;
};
struct msufx {
char *suffix;
struct mtype *mtype;
struct msufx *snext;
struct msufx *tnext;
};
struct mtype {
char *mimetype;
struct msufx *msufx;
struct mtype *next;
};
struct vhost {
char *hname;
char *root;
struct vhost *next;
};
struct vpath {
char *from;
char *to;
struct auth *auth;
int urlaccess;
struct vpath *next;
};
struct dirsend {
char *file;
struct dirsend *next;
};
/* urlaccess bits */
#define URLA_READ 1
#define URLA_WRITE 2
#define URLA_EXEC 4
#define URLA_HEADERS 8
#define HTTPD_CONFIG_FILE "/etc/httpd.conf"
_PROTOTYPE(int readconfig, (char *cfg_file, int testing));
extern struct mtype *mtype;
extern struct msufx *msufx;
extern struct vhost *vhost;
extern struct vpath *vpath;
extern struct dirsend *dirsend;
extern struct auth *auth;
extern struct auth *proxyauth;
extern char *direxec;
extern char *srvrroot;
extern char *LogFile;
extern char *DbgFile;
extern char *User;
extern char *Chroot;

187
commands/httpd/dir2html.c Normal file
View file

@ -0,0 +1,187 @@
/* dir2html.c by Michael Temari 3/3/96 */
#include <sys/types.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <sys/stat.h>
typedef struct namelist { /* Obviously a list of names. */
struct namelist *next;
char name[1];
} namelist_t;
_PROTOTYPE(static void sort, (namelist_t **anl));
_PROTOTYPE(static namelist_t *collect, (char *dir));
_PROTOTYPE(int main, (int argc, char *argv[]));
static void sort(anl)
namelist_t **anl;
/* A stable mergesort disguised as line noise. Must be called like this:
* if (L != NULL && L->next != NULL) sort(&L);
*/
{
/* static */ namelist_t *nl1, **mid; /* Need not be local */
namelist_t *nl2;
nl1 = *(mid = &(*anl)->next);
do {
if ((nl1 = nl1->next) == NULL) break;
mid = &(*mid)->next;
} while ((nl1 = nl1->next) != NULL);
nl2 = *mid;
*mid = NULL;
if ((*anl)->next != NULL) sort(anl);
if (nl2->next != NULL) sort(&nl2);
nl1 = *anl;
for (;;) {
if (strcmp(nl1->name, nl2->name) <= 0) {
if ((nl1 = *(anl = &nl1->next)) == NULL) {
*anl = nl2;
break;
}
} else {
*anl = nl2;
nl2 = *(anl = &nl2->next);
*anl = nl1;
if (nl2 == NULL) break;
}
}
}
static namelist_t *collect(dir)
char *dir;
/* Return a sorted list of directory entries. Returns null with errno != 0
* on error.
*/
{
namelist_t *names, **pn = &names;
DIR *dp;
struct dirent *entry;
if ((dp = opendir(dir)) == NULL) return NULL;
while ((entry = readdir(dp)) != NULL) {
if (strcmp(entry->d_name, ".") == 0) continue;
*pn = malloc(offsetof(namelist_t, name) + strlen(entry->d_name) + 1);
if (*pn == NULL) {
closedir(dp);
errno = ENOMEM;
return NULL;
}
strcpy((*pn)->name, entry->d_name);
pn = &(*pn)->next;
}
closedir(dp);
*pn = NULL;
if (names != NULL && names->next != NULL) sort(&names);
errno = 0;
return names;
}
int main(argc, argv)
int argc;
char *argv[];
{
namelist_t *np;
char *rpath, *vpath;
static char cwd[1024];
static char work[64];
char *filename;
struct stat st;
struct tm *tmp;
static char month[][4] = {
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
};
if(argc > 1) {
rpath = argv[1];
if (chdir(rpath) < 0) {
fprintf(stderr, "dir2html: %s: %s\n", rpath, strerror(errno));
return(-1);
}
} else {
if(getcwd(cwd, sizeof(cwd)) == NULL) {
fprintf(stderr, "dir2html: getcwd(): %s", strerror(errno));
return(-1);
}
rpath = cwd;
}
if(argc > 2) {
vpath = argv[2];
} else {
vpath = rpath;
}
if ((np = collect(".")) == NULL && errno != 0) {
fprintf(stderr, "dir2html: %s: %s\n", vpath, strerror(errno));
return(-1);
}
printf("<HTML><HEAD><TITLE>Index of %s</TITLE></HEAD>\n", vpath);
printf("<BODY>\n");
printf("<H1>Index of %s</H1>\n", vpath);
printf("<PRE>\n");
printf("%-22s %-17s %s\n", "Name", "Last modified", "Size/Type");
printf("<HR>\n");
while (np != NULL) {
errno = 0;
filename = np->name;
np= np->next;
if (stat(filename, &st) < 0) continue;
printf("<A HREF=\"%s%s\">",
filename, S_ISDIR(st.st_mode) ? "/" : "");
sprintf(work, "%.23s%s",
filename, S_ISDIR(st.st_mode) ? "/" : "");
if (strcmp(filename, "..") == 0) strcpy(work, "Parent Directory");
printf("%-22.22s%s</A>",
work, strlen(work) > 22 ? "&gt;" : " ");
tmp = localtime(&st.st_mtime);
printf(" %02d %s %d %02d:%02d",
tmp->tm_mday, month[tmp->tm_mon], 1900+tmp->tm_year,
tmp->tm_hour, tmp->tm_min);
if (S_ISREG(st.st_mode)) {
if (st.st_size < 10240) {
sprintf(work, "%lu ", (unsigned long) st.st_size);
} else
if (st.st_size < 10240 * 1024L) {
sprintf(work, "%luK",
((unsigned long) st.st_size - 1) / 1024 + 1);
} else {
sprintf(work, "%luM",
((unsigned long) st.st_size - 1) / (1024 * 1024L) + 1);
}
} else {
strcpy(work,
S_ISDIR(st.st_mode) ? "[dir]" :
S_ISBLK(st.st_mode) ? "[block]" :
S_ISCHR(st.st_mode) ? "[char]" :
S_ISFIFO(st.st_mode) ? "[pipe]" :
"[???]");
}
printf(" %8s\n", work);
}
printf("</PRE>\n");
printf("<HR>\n");
printf("<SMALL><i>Minix httpd 0.99</i></SMALL>\n");
printf("</BODY>\n");
printf("</HTML>\n");
return(0);
}

42
commands/httpd/dir2html.sh Executable file
View file

@ -0,0 +1,42 @@
# dir2html.sh by Michael Temari 03/03/96
#
#!/bin/sh
if [ $# != 0 ]
then
cd $1
fi
dname=`pwd`
fdname=$2
if [ $dname != / ]
then
dname=${dname}/
fi
echo "<HTML>"
echo "<TITLE>"
echo Directory of $fdname
echo "</TITLE>"
echo "<H1>"
echo Directory of $fdname
echo "</H1>"
echo "<HR>"
#
ls $dname |
{
while read fname
do
lname=$fdname$fname
echo "<H3>"
echo -n "<A HREF=\""
echo -n $lname
echo -n "\">"
echo -n $fname
echo "</A><BR>"
echo "</H3>"
done
}
echo "<HR>"
echo "<H6>"
echo Directory Generated at `date`
echo "</H6>"
echo "</HTML>"
exit 0

118
commands/httpd/http.h Normal file
View file

@ -0,0 +1,118 @@
/* http.h
*
* This file is part of httpd.
*
* 02/17/1996 Michael Temari <Michael@TemWare.Com>
* 07/07/1996 Initial Release Michael Temari <Michael@TemWare.Com>
* 12/29/2002 Michael Temari <Michael@TemWare.Com>
*
*/
#define INDEX_FILE_NAME "index.html"
#define HTTP_REQUEST_TYPE_SIMPLE 0
#define HTTP_REQUEST_TYPE_FULL 1
#define HTTP_REQUEST_TYPE_PROXY 2
#define HTTP_METHOD_UNKNOWN 0
#define HTTP_METHOD_OPTIONS 1
#define HTTP_METHOD_GET 2
#define HTTP_METHOD_HEAD 3
#define HTTP_METHOD_POST 4
#define HTTP_METHOD_PUT 5
#define HTTP_METHOD_PATCH 6
#define HTTP_METHOD_COPY 7
#define HTTP_METHOD_MOVE 8
#define HTTP_METHOD_DELETE 9
#define HTTP_METHOD_LINK 10
#define HTTP_METHOD_UNLINK 11
#define HTTP_METHOD_TRACE 12
#define HTTP_METHOD_WRAPPED 13
#define HTTP_STATUS_OK 200
#define HTTP_STATUS_CREATED 201
#define HTTP_STATUS_ACCEPTED 202
#define HTTP_STATUS_NO_CONTENT 204
#define HTTP_STATUS_MOVED_PERM 301
#define HTTP_STATUS_MOVED_TEMP 302
#define HTTP_STATUS_NOT_MODIFIED 304
#define HTTP_STATUS_USE_PROXY 305
#define HTTP_STATUS_BAD_REQUEST 400
#define HTTP_STATUS_UNAUTHORIZED 401
#define HTTP_STATUS_FORBIDDEN 403
#define HTTP_STATUS_NOT_FOUND 404
#define HTTP_STATUS_METHOD_NOT_ALLOWED 405
#define HTTP_STATUS_PROXY_AUTH_REQRD 407
#define HTTP_STATUS_LENGTH_REQUIRED 411
#define HTTP_STATUS_SERVER_ERROR 500
#define HTTP_STATUS_NOT_IMPLEMENTED 501
#define HTTP_STATUS_BAD_GATEWAY 502
#define HTTP_STATUS_SERVICE_UNAVAILABLE 503
#define HTTP_STATUS_GATEWAY_TIMEOUT 504
#define HTTP_STATUS_UNSUPPORTED_VERSION 505
struct http_request {
int type;
int method;
char uri[256];
char url[256];
char query[256];
char host[256];
int port;
char useragent[256];
int vmajor;
int vminor;
time_t ifmodsince;
off_t size;
time_t msgdate;
int keepopen;
char wwwauth[128];
char authuser[128];
char authpass[128];
char cookie[128];
};
struct http_reply {
int status;
char statusmsg[128];
int keepopen;
int headers;
char *mtype;
char realurl[256];
struct auth *auth;
int urlaccess;
off_t size;
time_t modtime;
int fd;
int ofd;
int pid;
};
/* from httpd.c */
extern FILE *stdlog;
extern FILE *dbglog;
/* from reply.c */
_PROTOTYPE(int sendreply, (struct http_reply *rp, struct http_request *rq));
/* from request.c */
_PROTOTYPE(int getrequest, (struct http_request *rq));
/* from process.c */
_PROTOTYPE(int processrequest, (struct http_request *rq, struct http_reply *rp));
/* from police.c */
_PROTOTYPE(int police, (struct http_request *rq, struct http_reply *rp));
/* from cgiexec.c */
_PROTOTYPE(int cgiexec, (struct http_request *rq, struct http_reply *rp));
/* from proxy.c */
_PROTOTYPE(void proxy, (struct http_request *rq, struct http_reply *rp));

View file

@ -0,0 +1,73 @@
.TH HTTP_STATUS 5
.SH
http_status \- HTTP status numbers and their meanings
.SH DESCRIPTION
These are the HTTP status numbers defined in
.BI http.h
in the source directory,
.BI /usr/local/src/httpdxxx.
The message you see on your screen when a page cannot be accessed is
normally generated by your browser.
.P
HTTP_STATUS_OK 200
.br
HTTP_STATUS_CREATED 201
.br
HTTP_STATUS_ACCEPTED 202
.br
HTTP_STATUS_NO_CONTENT 204
.br
HTTP_STATUS_MOVED_PERM 301
.br
HTTP_STATUS_MOVED_TEMP 302
.br
HTTP_STATUS_NOT_MODIFIED 304
.br
HTTP_STATUS_USE_PROXY 305
.br
HTTP_STATUS_BAD_REQUEST 400
.br
HTTP_STATUS_UNAUTHORIZED 401
.br
HTTP_STATUS_FORBIDDEN 403
.br
HTTP_STATUS_NOT_FOUND 404
.br
HTTP_STATUS_METHOD_NOT_ALLOWED 405
.br
HTTP_STATUS_PROXY_AUTH_REQRD 407
.br
HTTP_STATUS_LENGTH_REQUIRED 411
.br
HTTP_STATUS_SERVER_ERROR 500
.br
HTTP_STATUS_NOT_IMPLEMENTED 501
.br
HTTP_STATUS_BAD_GATEWAY 502
.br
HTTP_STATUS_SERVICE_UNAVAILABLE 503
.br
HTTP_STATUS_GATEWAY_TIMEOUT 504
.br
HTTP_STATUS_UNSUPPORTED_VERSION 505
.br
.SH FILES
.TP 25n
.B /usr/local/src/httpdxxx/http.h
.SH "SEE ALSO"
The definitive source of information on the HTTP protocol is the
.B "World Wide Web Consortium"
web page at
.B http://www.w3c.org .
.P
A draft version of the HTTP 1.1 specification is available on the Minix1
websites. For more information on status codes go to this URL:
.B http://minix1.hampshire.edu/http11.html#Status-Codes
.SH AUTHOR
The Minix httpd server was created by and is maintained by Michael Temari
<Michael@TemWare.Com>
.br
This man page was compiled by Al Woodhull <awoodhull@hampshire.edu>
.P
updated 2003-07-06

104
commands/httpd/httpd.8 Normal file
View file

@ -0,0 +1,104 @@
.TH HTTPD 8
.SH NAME
httpd, in.httpd, dir2html \- a web server for Minix
.SH SYNOPSIS
.B httpd
.RB [\-t|\-v]
.RI [ config_file ]
.br
.B "tcpd http /usr/local/bin/in.httpd"
.br
.B dir2html
.RB [directory]
.SH DESCRIPTION
.B httpd
is a World Wide Web (WWW) server written by Michael Temari. It was
written from scratch so the setup and configuration will not be like
other web servers.
.P
.B in.httpd
is linked to
.B httpd.
This alternate name is used to indicate the program is a server that is
started by
.B tcpd,
a program which listens for incoming TCP connections on the passed
port (defined in
.BI /etc/services ).
When a connection comes in
.B tcpd
forks and starts the given daemon program, after possibly checking for access
restrictions and logging the connection. Therefore to start
.B httpd
you use:
.br
.B "tcpd http /usr/local/bin/in.httpd &"
.br
or
.br
.B "daemonize tcpd http /usr/local/bin/in.httpd"
.P
.B (daemonize
is a shell function defined in
.BI/usr/etc/rc
in Minix 2.0.3 and later releases which starts programs as daemons).
.P
.B dir2html
is an accessory program that produces a directory listing formatted as
web page for the current directory or for a directory specified as an
argument. It is called by
.B httpd
when a web client references a directory that includes no index.html
file (or whatever alternative to index.html that may be defined in
/etc/httpd.conf). Since it writes to standard output it may also be called
as a standalone program.
.P
Options for
.B httpd
are:
.SH OPTIONS
.TP
.B \-t
This tells the server to parse the configuration file so that you can
see if it is the way you want it. You may also pass the name of your
configuration file if it is not the default /etc/httpd.conf.
.TP
.B \-v
Shows the server version, then exits.
.br
.IR config_file
normally /etc/httpd.conf
.SH FILES
.TP 25n
.B /etc/httpd.conf
The configuration file.
.P
.B /etc/httpd.mtype
Extension to configuration file defining MIME types.
.P
.B /usr/adm/httpd.log
Log file. The file must exist for logging to begin.
.SH "SEE ALSO"
.BR httpd.conf (5)
.br
.BR http_status (5)
.br
.BR serv.access (5)
.br
.BR tcpd (8)
.SH NOTES
Running a server exposed to the Internet is risky to the host system and
to the local network. Consult with the owner of your net before you go
public. Read the
.B SECURITY
document in the source directory.
.SH BUGS
None are known, but there are surely some unknown ones. Be careful!
.SH AUTHOR
The Minix httpd server was created by and is maintained by Michael Temari
<Michael@TemWare.Com>
.br
This man page was compiled by Al Woodhull <awoodhull@hampshire.edu>
.P
updated 2003-07-06

175
commands/httpd/httpd.c Normal file
View file

@ -0,0 +1,175 @@
/* httpd.c
*
* httpd A Server implementing the HTTP protocol.
*
* usage: tcpd http httpd &
*
* 02/17/1996 Michael Temari <Michael@TemWare.Com>
* 07/07/1996 Initial Release Michael Temari <Michael@TemWare.Com>
* 12/29/2002 Michael Temari <Michael@TemWare.Com>
* 07/04/2003 Al Woodhull <awoodhull@hampshire.edu>
*
*/
#include <stdlib.h>
#include <sys/types.h>
#include <pwd.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "http.h"
#include "utility.h"
#include "net.h"
#include "config.h"
FILE *stdlog = (FILE *)NULL;
FILE *dbglog = (FILE *)NULL;
char umsg[80];
_PROTOTYPE(int main, (int argc, char *argv[]));
struct http_request request;
struct http_reply reply;
int main(argc, argv)
int argc;
char *argv[];
{
char *prog;
int opt_t;
char *cfg = (char *)NULL;
struct passwd *pwd;
int s;
strcpy(umsg, "Usage: ");
strcat(umsg, argv[0]);
strcat(umsg, " [-t|v] [config_file]\n");
/* parse program name */
prog = strrchr(*argv, '/');
if(prog == (char *)NULL)
prog = *argv;
else
prog++;
argv++;
argc--;
/* Any options */
if(argc)
if(argv[0][0] == '-') {
switch (argv[0][1]) {
case 't' : opt_t = 1;
argv++;
argc--;
break;
case 'v' : fprintf(stderr, VERSION"\n");
exit(EXIT_SUCCESS);
break;
default : fprintf(stderr, VERSION"\n");
fprintf(stderr, umsg);
exit(EXIT_FAILURE);
}
}
/* Did they specify an alternate configuration file? */
if(argc) {
cfg = *argv++;
argc--;
}
/* Read the configuration settings */
if(readconfig(cfg, opt_t)) {
fprintf(stderr, "httpd: Error reading configuration file.\n");
return(-1);
}
/* Option t is to test configuration only */
if(opt_t)
return(0);
/* Open log file for append if it exists */
if(LogFile != NULL)
if((stdlog = fopen(LogFile, "r")) != (FILE *)NULL) {
fclose(stdlog);
stdlog = fopen(LogFile, "a");
}
/* Open debug log file for append if it exists */
if(DbgFile != NULL)
if((dbglog = fopen(DbgFile, "r")) != (FILE *)NULL) {
fclose(dbglog);
dbglog = fopen(DbgFile, "a");
}
#if 0
/* Get some network information */
GetNetInfo();
#endif
/* If user defined then prepare to secure as user given */
if(User != NULL)
if((pwd = getpwnam(User)) == (struct passwd *)NULL) {
fprintf(stderr, "httpd: unable to find user %s\n", User);
return(-1);
}
/* If Chroot defined then secure even more by doing a chroot */
if(Chroot != NULL) {
if(chroot(Chroot)) {
fprintf(stderr, "httpd: unable to chroot\n");
return(-1);
}
if(chdir("/")) {
fprintf(stderr, "httpd: unable to chroot\n");
return(-1);
}
}
/* If user defined then secure as user given */
if(User != NULL)
if(setgid(pwd->pw_gid) || setuid(pwd->pw_uid)) {
fprintf(stderr, "httpd: unable to set user\n");
return(-1);
}
#if DAEMON
/* Standalone? */
if (strncmp(prog, "in.", 3) != 0) {
/* Does not start with "in.", so not started from inetd/tcpd. */
/* XXX - Port name/number should be a config file option. */
daemonloop("http");
}
#endif
/* Get some network information */
GetNetInfo();
/* log a connection */
if(dbglog != (FILE *)NULL) {
fprintf(dbglog, "CONNECT: %d %s %s\n", getpid(),
rmthostname, logdate((time_t *)NULL));
fflush(dbglog);
}
/* loop getting, processing and replying to requests */
while(!(s = getrequest(&request))) {
if(processrequest(&request, &reply)) break;
if(stdlog != (FILE *)NULL) {
fprintf(stdlog, "%s %s %d %d %s\n",
logdate((time_t *)NULL), rmthostname,
request.method, reply.status, request.url);
fflush(stdlog);
}
if(sendreply(&reply, &request)) break;
if(!reply.keepopen) break;
}
if(s == 1 && stdlog != (FILE *)NULL) {
fprintf(stdlog, "%s %s %d %d %s\n",
logdate((time_t *)NULL), rmthostname,
request.method, 999, request.url);
fflush(stdlog);
}
return(0);
}

159
commands/httpd/httpd.conf Normal file
View file

@ -0,0 +1,159 @@
# httpd.conf Sample httpd.conf file By Michael Temari 7/03/2003
#serverroot path
#
# path = sets the translation for //
#
# these have special meaning if at beginning of path
#
# /~user = gets replaced with user home directory
serverroot /~www
#user username
#
# if present the server will run as the given username otherwise the
# server will run as who ever started it (normally root).
user www
#chroot directory
#
# if present the server will be chroot'ed to the given directory name
# normally the home directory of username given above. Be aware if this
# is set then you can only access stuff off this new root.
#
# these have special meaning if at beginning of the directory
#
# // = gets replaced by serverroot directory
# /~user = gets replaced with user home directory
#chroot /~www
#logfile filename
#
# the file must exist also and a log of http transactions will be kept
#
# these have special meaning if at the beginning of the filename
#
# // = gets replaced by serverroot directory
# /~user = gets replaced with user home directory
logfile /usr/adm/httpd.log
#dbgfile filename
#
# the file must exist also and a debug log of http transactions will be kept
#
# these have special meaning if at the beginning of the filename
#
# // = gets replaced by serverroot directory
# /~user = gets replaced with user home directory
dbgfile /usr/adm/httpd.dbg
# dirsend [list of files to try until 1st one is found]
#
dirsend index.htm
# direxec [script to run for automatic directory page output]
#
#
# these have special meaning if at beginning of script
#
# // = gets replaced by serverroot directory
# /~user = gets replaced with user home directory
#
direxec /usr/local/bin/dir2html
# vhost hostname VhostRoot
#
# vhost is for defining access for virtual hosts. If none are configured then
# any host is accepted. If specified then access is only granted for requests
# for hosts which are configured here. In the Vpath section below the /// gets
# translated to the corresponding VhostRoot.
# vhost temware.dyndns.org //doc/
# vhost minix.homeip.net //doc2/
# auth authname authdescription access [passwdfile [users]]
#
# auth defines any access authorization to be used in vpath
#
# authname = name to give to this authorization (case insensitive)
# authdescription = Description of this authorization
# access = r=read, w=write, x=execute, h=headers (other than rwxh then no access)
# NOTE: r=file should be read, w=file can be overwrote
# NOTE: x=file should be executed
# NOTE: h=headers (executing program will produce all http headers)
# NOTE: access is on top of unix access
# passwdfile = Name of passwd file to be used (. means /etc/passwd)
# (if none given then no user check)
# users = valid users for this authorization (if none given then all users valid)
#
# these have special meaning if at beginning of passwdfile
#
# // = gets replaced by serverroot directory
# /~user = gets replaced with user home directory
#
auth AnyBody AnyBody R
System System_User R .
Uploads Uploads RW . root
# proxyauth authname authdescription access [passwdfile [users]]
#
# proxyauth defines any access authorization to be used for Proxy access
#
# authname = Same as auth above
# authdescription = Same as auth above
# access = Must be R to allow proxy
# passwdfile = Same as auth above
# users = Same as auth above
#
# proxyauth
# Proxy Proxy R .
# vpath from to auth
#
# vpath sets up a list of url path translations and authorizations
#
# from = user specified url
# *=wildcard, $=wildard, but keep path for passing to program
# to = real location
# auth = authname from above (null for no authorization)
# access = r-read, w-write, x-execute (if not given taken from auth record)
# = h-headers (executing program will produce all http headers)
#
# these have special meaning if at beginning of to or serverroot fields
#
# // = gets replaced by serverroot directory
# /// = gets replaced by vhost root directory if configured otherwise same as //
# . = specified authorization only, use other translation elsewhere
# /~user = gets replaced with user home directory
#
vpath * . AnyBody
/* /// AnyBody
/index.htm . AnyBody X
/ip . AnyBody X
/c1d1$ //exec/cdrom AnyBody X
/c1d2$ //exec/cdrom AnyBody X
/uploads* . Uploads
/src* /usr/src AnyBody R
# include filename
#
# include tells the server to continue parsing configuration information
# in the given filename
#
# these have special meaning if at beginning of filename
#
# // = gets replaced by serverroot directory
# /~user = gets replaced with user home directory
include //etc/httpd.mtype

328
commands/httpd/httpd.conf.5 Normal file
View file

@ -0,0 +1,328 @@
.TH HTTPD.CONF 5
.SH NAME
httpd.conf httpd.mtype \- configuration files for the Minix httpd web server
.SH SYNOPSIS
.B /etc/httpd.conf
.B /etc/httpd.mtype
.SH DESCRIPTION
.B /etc/httpd.conf
is the configuration file for the Minix httpd web server written by
Michael Temari. A sample version is included with the distribution
archive and is unpacked in the source directory (normally
.BI /usr/local/src/httpdxxx).
Also provided is an example
.B httpd.mtype
file. This is an extension of the main configuration file which is normally
included when the main file is read.
.P
The makefile does not install
.B httpd.conf
and
.B httpd.mtype
automatically. The sample files included in the distribution are only
examples, you must copy it and edit them for the needs of your own
installation.
.SH CONFIGURATION FILE FORMAT
.B httpd.conf
is an ascii file which consists of lines of the following form:
.P
.B directive LWS [parameters separated by LWS]
.br
NOTE: LWS denotes Linear White Space which is spaces and/or tabs
.SH CONFIGURATION FILE DIRECTIVES
The following are valid configuration file directives (listed in the order
they appear in the sample
.B httpd.conf
file provided in the distribution):
.P
.B serverroot user chroot logfile dbgfile dirsend direxec vhost auth
.B proxyauth vpath include mtype
.P
To make the file more readable, for directives which occupy multiple
lines you may eliminate the directive on lines after the first and begin
these lines with LWS.
.SH DESCRIPTIONS OF DIRECTIVES
.P
.B serverroot path
The
.B serverroot
directive sets the translation for
.B //
to the given
.B path.
.B user username
The
.B user
directive causes the server to run as the given
.B username
otherwise the server will run as whoever started it (normally root).
.B chroot directory
The
.B chroot
directive causes the server to chroot to the given directory after
the configuration and log files have been opened. Normally this will be the
home directory of the given username in the user directive.
.br
NOTE:
.B /~user
will be translated to the home directory of
.B user.
.br
NOTE:
.B //
will be translated to the serverroot directory.
.br
NOTE: if this directive is used then beware of the consequences.
.B logfile filename
The
.B logfile
directive tells the server where to log http transactions.
.br
NOTE: the log file must exist to enable logging.
.B dbgfile filename
The
.B dbgfile
directive tells the server where to log debugging of http transactions.
.br
NOTE: the debug log file must exist to enable debug logging.
.B dirsend filelist
The
.B dirsend
directive tells the server that when a directory is requested
that it should send the first file that it finds in the directory from the
.B filelist
for the request.
.B direxec program
The
.B direxec
directive tells the server that when a directory is requested
and no file is found from the
.B dirsend
directive that it should run the given
.B program.
.br
NOTE: the program normally generates a directory listing on the fly using
the
.B dir2html
program.
.br
NOTE: the program access is considered
.B X
with no access restrictions.
.B vhost hostname vhostroot
The
.B vhost
directive is for defining access for virtual hosts. If none are configured
then any host is accepted. If specified then access is only granted for
requests for hosts which are configured here. In the
.B vpath
section below the
.B ///
gets translated to the corresponding
.B vhostroot.
.B auth authname authdescription access [passwdfile [users]]
The
.B auth
directive sets up different authorizations with the server. The
.B authname
is the name given to the authorization and is case insensitive.
The
.B authdescription
is the description of the authorization and is what
the user will see when asked to enter a username and password. The
access is one or more of
.B (RWX).
.B R
tells the server the URL can be read.
.B W
tells the server the URL can be overwritten.
.B X
tells the server
that the URL can and should be executed. Access is in addition to normal
Unix security considerations. For instance a file that can be written to
that does not have the
.B W
access will have an error returned. The
.B passwdfile
is the name of the password file to validate users against. If
.B passwdfile
is given as
.B '.'
then the system password file
.B (/etc/passwd)
will be used. If no
.B passwdfile
is given then no authorization is allowed for anyone. If no
.B users
are given then any validated user is authorized, otherwise only the given
.B users
are allowed.
.B proxyauth authname authdescription access [passwdfile [users]]
The
.B proxyauth
directive defines access authorization to be used for Proxy access.
.br
.B authname
= Same as auth above
.br
.B authdescription
= Same as auth above
.br
.B access
= Must be R to allow proxy
.br
.B passwdfile
= Same as auth above
.br
.B users
= Same as auth above
.B vpath from to [auth [access]]
The
.B vpath
directive sets up URL path translations and authorizations. A
requested URL that matches
.B from
will be translated to
.B to
with the given
.B auth
and
.B access.
If
.B auth
does not exist then the URL will have no
.B access.
If
.B access
is not given then the access is taken from the
.B auth
record (see above). A
.B '.'
in place of the
.B to
means that the server should use a translation from another
.B vpath
record, but associate the given
.B auth
and access with the requested URL. A
.B '*'
may be at the end only of the
.B from
to provide a wildcard match. For example if the
.B from
has
.B /AB*
then any of
.B /ABCDEF
or
.B /AB
or
.B /ABmichael
will match, but
.B /AD or
.B /a
will not. The requested URL is first checked against each
.B vpath
record until an exact match (meaning URL match
.B from
and
.B from
had no
.B '*')
is found or the end of the list. Therefore a wildcard match will match
the last
.B from in the list in which it matched.
.br
NOTE: if at the beginning of the to field
.br
/~user will get translated to the home directory of the given user
.br
// wile get translated to the serverroot directory
.B include filename
The
.B include
directive tells the server to read configuration information
from the given filename.
.br
NOTE: normally you get
.B mtype
directives in an included file.
.B mtype mimetype extensions
The
.B mtype
directive tells the server what
.B mimetype
to associate with files which have any of the given
.B extensions.
If no match is found then the file will be treated as
.B application/octet-stream.
.SH FILES
.B /etc/httpd.conf
.B /etc/httpd.mtype
.B /etc/passwd
.SH "SEE ALSO"
.BR httpd (8)
.BR http_status (5)
.SH NOTES
The source directory contains a commented sample
.B httpd.conf
and
.B httpd.mtype
files
P.
You can run the server as
.B httpd -t /etc/httpd.conf
to see whether the configuration file is being parsed correctly.
.P
Although standard Minix does not have a graphical interface to support
browsers such as Netscape and Microsoft Internet Explorer, the
.B lynx
browser can be used on 32-bit Minix systems with enough memory. You can point
lynx to your own site to browse your own pages.
When debugging a web server there is nothing quite like browsing your own
pages to see whether things are working right. That said, be aware that
different web browsers may vary in how they interpet standard web page
features, and will certainly vary in how they interpret "extensions" to
the HTML standards. So checking a page with several browsers on several
platforms is always a good idea.
.SH BUGS
Not really a bug, but you can get in trouble if a real directory you want
to access shares the first part of its name with a
.B vpath
definition. You just have to pay attention to the directory names you use.
.SH AUTHOR
The Minix httpd server was created by and is maintained by Michael Temari
<Michael@TemWare.Com>
.br
This man page was compiled by Al Woodhull <awoodhull@hampshire.edu>
.P
updated 2003-07-06

View file

@ -0,0 +1,40 @@
# mime types By Michael Temari 12/29/2002 Ver 0.40
# if a file extension is not found in the configuration below the default
# mime type will be application/octet-stream. This default can be changed
# by entering a line with a mime type only with no extension.
mtype
application/octet-stream
application/compress .Z
application/msword .doc
application/octet-stream .bin .exe
application/pdf .pdf
application/postscript .ps .ai .eps
application/smil .smil
application/x-gtar .gtar
application/x-gzip .gz
application/x-sh .sh
application/x-pn-realaudio .ra .ram
application/x-tar .tar
application/zip .zip
audio/basic .au .snd
audio/mpeg .mp3
audio/x-aiff .aif .aiff .aifc
audio/x-midi .mid
audio/x-wav .wav
image/bmp .bmp
image/gif .gif
image/jpeg .jpg .jpeg .jpe
image/png .png
image/tiff .tiff .tif
image/x-rgb .rgb
image/x-xbitmap .xbm
multipart/x-www-form-urlencoded .wfu
text/html .html .htm
text/plain .txt .c .h
text/richtext .rtf .rtx
video/mpeg .mpg .mpeg .mpe
video/quicktime .qt .mov
video/x-msvideo .avi
video/x-sgi-movie .movie

View file

@ -0,0 +1,41 @@
httpd0993 --- A www server for Minix 2.0
written by Michael Temari <Michael@TemWare.Com> release 0.993 2003-07-??
Httpd is a World Wide Web (WWW) server. I wrote it from scratch so
the setup and configuration will not be like other web servers though
hopefully by reading this document there will be no problems in getting
my web server up and running on your Minix system.
This is the web server in use on minix1.hampshire.edu and
minix1.bio.umass.edu.
Installation: unpack the tarball in /usr/local/src or another directory
of your choice:
zcat < httpd0993.tar.Z | tar xvfp -
An httpd0993 directory will be created and files will be unpacked
there. The README file explains compilation, installation,
configuration, and use.
Changes for release 0.993:
- a new method of authorizing proxy. You will no longer need the Proxy
entry in Auth and can remove the http://* entry in vpath. The old way
allowed for having different authorizations depending on what URLs were
asked for via proxy, i.e., you could allow proxy access only to
http:://www.hampshire.edu/. Now it is just a simple authorization for
allowing proxy or not.
- avoids using a Minix 2.0.3 library call that was not present in Minix
2.0.2, and thus can be compiled with either of the two most recent
Minix releases.
- a -v option has been added to display the current version then exit.
- man pages added, other documentation updated.
Changes for release 0.99: You can set a default in the httpd.mtype
file. A mime type with no extensions on a line will be the default.
Previously recompilation was needed to change the default mime type.
updated 2003-07-07

240
commands/httpd/net.c Normal file
View file

@ -0,0 +1,240 @@
/* net.c
*
* This file is part of httpd.
*
* 01/25/1996 Michael Temari <Michael@TemWare.Com>
* 07/07/1996 Initial Release Michael Temari <Michael@TemWare.Com>
* 12/29/2002 Michael Temari <Michael@TemWare.Com>
*
*/
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <net/netlib.h>
#include <net/hton.h>
#include <net/gen/in.h>
#include <net/gen/inet.h>
#include <net/gen/tcp.h>
#include <net/gen/tcp_io.h>
#include <net/gen/socket.h>
#include <net/gen/netdb.h>
#include "net.h"
_PROTOTYPE(static void release, (int *fd));
ipaddr_t myipaddr, rmtipaddr;
tcpport_t myport, rmtport;
char myhostname[256];
char rmthostname[256];
char rmthostaddr[3+1+3+1+3+1+3+1];
void GetNetInfo()
{
nwio_tcpconf_t tcpconf;
int s;
struct hostent *hostent;
/* Ask the system what our hostname is. */
if(gethostname(myhostname, sizeof(myhostname)) < 0)
strcpy(myhostname, "unknown");
/* lets get our ip address and the clients ip address */
s = ioctl(0, NWIOGTCPCONF, &tcpconf);
if(s < 0) {
myipaddr = 0;
myport = 0;
rmtipaddr = 0;
rmtport = 0;
strcpy(rmthostname, "??Unknown??");
strcpy(rmthostaddr, "???.???.???.???");
return;
}
myipaddr = tcpconf.nwtc_locaddr;
myport = tcpconf.nwtc_locport;
rmtipaddr = tcpconf.nwtc_remaddr;
rmtport = tcpconf.nwtc_remport;
/* Look up the host name of the remote host. */
hostent = gethostbyaddr((char *) &rmtipaddr, sizeof(rmtipaddr), AF_INET);
if(!hostent)
strncpy(rmthostname, inet_ntoa(rmtipaddr), sizeof(rmthostname)-1);
else
strncpy(rmthostname, hostent->h_name, sizeof(rmthostname)-1);
strcpy(rmthostaddr, inet_ntoa(rmtipaddr));
rmthostname[sizeof(rmthostname)-1] = '\0';
return;
}
static void release(fd)
int *fd;
{
if(*fd != -1) {
close(*fd);
*fd= -1;
}
}
void daemonloop(service)
char *service;
{
tcpport_t port;
struct nwio_tcpcl tcplistenopt;
struct nwio_tcpconf tcpconf;
struct nwio_tcpopt tcpopt;
struct servent *servent;
char *tcp_device;
int tcp_fd, client_fd, r;
int pfd[2];
unsigned stall= 0;
if((servent= getservbyname(service, "tcp")) == NULL) {
unsigned long p;
char *end;
p = strtoul(service, &end, 0);
if(p <= 0 || p > 0xFFFF || *end != 0) {
fprintf(stderr, "httpd: %s: Unknown service\n", service);
exit(1);
}
port= htons((tcpport_t) p);
} else
port= servent->s_port;
/* No client yet. */
client_fd= -1;
while (1) {
if((tcp_device = getenv("TCP_DEVICE")) == NULL)
tcp_device = TCP_DEVICE;
if ((tcp_fd= open(tcp_device, O_RDWR)) < 0) {
fprintf(stderr, "httpd: Can't open %s: %s",
tcp_device, strerror(errno));
if (errno == ENOENT || errno == ENODEV
|| errno == ENXIO) {
exit(1);
}
goto bad;
}
tcpconf.nwtc_flags= NWTC_LP_SET | NWTC_UNSET_RA | NWTC_UNSET_RP;
tcpconf.nwtc_locport= port;
if (ioctl(tcp_fd, NWIOSTCPCONF, &tcpconf) < 0) {
fprintf(stderr, "httpd: Can't configure TCP channel",
strerror(errno));
exit(1);
}
#ifdef NWTO_DEL_RST
tcpopt.nwto_flags= NWTO_DEL_RST;
if (ioctl(tcp_fd, NWIOSTCPOPT, &tcpopt) < 0) {
fprintf(stderr, "httpd: Can't set TCP options",
strerror(errno));
exit(1);
}
#endif
if (client_fd != -1) {
/* We have a client, so start a server for it. */
#ifdef NWTO_DEL_RST
tcpopt.nwto_flags= 0;
(void) ioctl(client_fd, NWIOSTCPOPT, &tcpopt);
#endif
fflush(NULL);
/* Create a pipe to serve as an error indicator. */
if (pipe(pfd) < 0) {
fprintf(stderr, "httpd: pipe", strerror(errno));
goto bad;
}
/* Fork twice to daemonize child. */
switch (fork()) {
case -1:
fprintf(stderr, "httpd: fork", strerror(errno));
close(pfd[0]);
close(pfd[1]);
goto bad;
case 0:
close(tcp_fd);
close(pfd[0]);
switch (fork()) {
case -1:
fprintf(stderr, "httpd: fork",
strerror(errno));
write(pfd[1], &errno, sizeof(errno));
exit(1);
case 0:
break;
default:
exit(0);
}
dup2(client_fd, 0);
dup2(client_fd, 1);
close(client_fd);
close(pfd[1]);
/* Break out of the daemon loop, continuing with
* the normal httpd code to serve the client.
*/
return;
default:
release(&client_fd);
close(pfd[1]);
wait(NULL);
r= read(pfd[0], &errno, sizeof(errno));
close(pfd[0]);
if (r != 0) goto bad;
break;
}
}
/* Wait for a new connection. */
tcplistenopt.nwtcl_flags= 0;
while (ioctl(tcp_fd, NWIOTCPLISTEN, &tcplistenopt) < 0) {
if (errno != EAGAIN) {
fprintf(stderr, "httpd: Unable to listen: %s",
strerror(errno));
}
goto bad;
}
/* We got a connection. */
client_fd= tcp_fd;
tcp_fd= -1;
/* All is well, no need to stall. */
stall= 0;
continue;
bad:
/* All is not well, release resources. */
release(&tcp_fd);
release(&client_fd);
/* Wait a bit if this happens more than once. */
if (stall != 0) {
sleep(stall);
stall <<= 1;
} else {
stall= 1;
}
}
}

17
commands/httpd/net.h Normal file
View file

@ -0,0 +1,17 @@
/* net.h
*
* This file is part of httpd.
*
*
* 01/25/1996 Michael Temari <Michael@TemWare.Com>
* 07/07/1996 Initial Release Michael Temari <Michael@TemWare.Com>
* 12/29/2002 Michael Temari <Michael@TemWare.Com>
*
*/
_PROTOTYPE(void GetNetInfo, (void));
_PROTOTYPE(void daemonloop, (char *service));
extern char myhostname[256];
extern char rmthostname[256];
extern char rmthostaddr[3+1+3+1+3+1+3+1];

213
commands/httpd/pass.c Normal file
View file

@ -0,0 +1,213 @@
/* pass.c
*
* This file is part of httpd.
*
* 07/07/1996 Initial Release Michael Temari <Michael@TemWare.Com>
* 12/29/2002 Michael Temari <Michael@TemWare.Com>
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <pwd.h>
#ifdef _MINIX
#include <minix/minlib.h>
#endif
#define STD_PASSWD_FILE "/etc/passwd"
#include "pass.h"
static char buffer[1024];
static char *pwduser;
static char *pwdpass;
static char *pwde[4];
_PROTOTYPE(static int getuser, (char *pwdfile, char *user));
static int getuser(pwdfile, user)
char *pwdfile;
char *user;
{
FILE *fp;
char *p;
int i;
if((fp = fopen(pwdfile, "r")) == (FILE *)NULL)
return(-1);
for(i = 0; i < 4; i ++) pwde[i] = "";
while(1) {
if(fgets(buffer, sizeof(buffer), fp) == (char *)NULL) {
fclose(fp);
return(-1);
}
p = buffer;
pwduser = p;
while(*p && *p != ':') p++;
if(*p != ':') continue;
*p++ = '\0';
if(strcmp(pwduser, user)) continue;
pwdpass = p;
while(*p && *p != ':' && *p != '\r' && *p != '\n') p++;
if(*p == ':')
*p++ = '\0';
else {
if(*p) *p = '\0';
fclose(fp);
}
for(i = 0; i < 4; i++) {
pwde[i] = p;
while(*p && *p != ':' && *p != '\r' && *p != '\n') p++;
if(*p == ':')
*p++ = '\0';
else {
if(*p) *p = '\0';
break;
}
}
fclose(fp);
return(0);
}
}
int passfile(pwdfile)
char *pwdfile;
{
FILE *fp;
if(!strcmp(pwdfile, STD_PASSWD_FILE))
return(0);
if((fp = fopen(pwdfile, "r")) == (FILE *)NULL)
return(-1);
fclose(fp);
return(0);
}
int passuser(pwdfile, user)
char *pwdfile;
char *user;
{
if(!strcmp(pwdfile, STD_PASSWD_FILE))
if(getpwnam(user) == (struct passwd *)NULL)
return(-1);
else
return(0);
return(getuser(pwdfile, user));
}
int passnone(pwdfile, user)
char *pwdfile;
char *user;
{
struct passwd *pwd;
if(!strcmp(pwdfile, STD_PASSWD_FILE))
if((pwd = getpwnam(user)) == (struct passwd *)NULL)
return(-1);
else
if(!strcmp(pwd->pw_passwd, crypt("", pwd->pw_passwd)))
return(-1);
else
return(0);
if(getuser(pwdfile, user))
return(-1);
if(!strcmp(pwdpass, crypt("", pwdpass)))
return(-1);
else
return(0);
}
int passpass(pwdfile, user, pass)
char *pwdfile;
char *user;
char *pass;
{
struct passwd *pwd;
if(!strcmp(pwdfile, STD_PASSWD_FILE))
if((pwd = getpwnam(user)) == (struct passwd *)NULL)
return(-1);
else
if(strcmp(pwd->pw_passwd, crypt(pass, pwd->pw_passwd)))
return(-1);
else
return(0);
if(getuser(pwdfile, user))
return(-1);
if(strcmp(pwdpass, crypt(pass, pwdpass)))
return(-1);
else
return(0);
}
int passadd(pwdfile, user, pass, e1, e2, e3, e4)
char *pwdfile;
char *user;
char *pass;
char *e1;
char *e2;
char *e3;
char *e4;
{
FILE *fp;
time_t salt;
char sl[2];
int cn;
char *ee1;
char *ee2;
char *ee3;
char *ee4;
if(pwdfile == (char *)NULL ||
user == (char *)NULL ||
pass == (char *)NULL)
return(PASS_ERROR);
if(!strcmp(pwdfile, STD_PASSWD_FILE))
return(PASS_ERROR);
if(!getuser(pwdfile, user))
return(PASS_USEREXISTS);
time(&salt);
sl[0] = (salt & 077) + '.';
sl[1] = ((salt >> 6) & 077) + '.';
for (cn = 0; cn < 2; cn++) {
if (sl[cn] > '9') sl[cn] += 7;
if (sl[cn] > 'Z') sl[cn] += 6;
}
if(e1 == (char *)NULL) ee1 = ""; else ee1 = e1;
if(e2 == (char *)NULL) ee2 = ""; else ee2 = e2;
if(e3 == (char *)NULL) ee3 = ""; else ee3 = e3;
if(e4 == (char *)NULL) ee4 = ""; else ee4 = e4;
/* XXX need to add locking mechanics to add new user */
if((fp = fopen(pwdfile, "a")) == (FILE *)NULL)
return(PASS_ERROR);
fprintf(fp, "%s:%s:%s:%s:%s:%s\n", user, crypt(pass, sl), ee1, ee2, ee3, ee4);
fclose(fp);
/* XXX need to add unlocking mechanics to add new user */
return(PASS_GOOD);
}

18
commands/httpd/pass.h Normal file
View file

@ -0,0 +1,18 @@
/* pass.h
*
* This file is part of httpd.
*
* 07/07/1996 Initial Release Michael Temari <Michael@TemWare.Com>
* 12/29/2002 Initial Release Michael Temari <Michael@TemWare.Com>
*
*/
_PROTOTYPE(int passfile, (char *pwdfile));
_PROTOTYPE(int passuser, (char *pwdfile, char *user));
_PROTOTYPE(int passnone, (char *pwdfile, char *user));
_PROTOTYPE(int passpass, (char *pwdfile, char *user, char *pass));
_PROTOTYPE(int passadd, (char *pwdfile, char *user, char *pass, char *e1, char *e2, char *e3, char *e4));
#define PASS_GOOD 0
#define PASS_USEREXISTS 1
#define PASS_ERROR -1

407
commands/httpd/police.c Normal file
View file

@ -0,0 +1,407 @@
/* police.c
*
* This file is part of httpd.
*
* 02/17/1996 Michael Temari <Michael@TemWare.Com>
* 07/07/1996 Initial Release Michael Temari <Michael@TemWare.Com>
* 12/29/2002 Michael Temari <Michael@TemWare.Com>
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include "http.h"
#include "utility.h"
#include "config.h"
#include "pass.h"
#define MATCH_NONE 0
#define MATCH_WILD 1
#define MATCH_FULL 2
_PROTOTYPE(static int authaccess, (struct http_request *rq, struct http_reply *rp));
_PROTOTYPE(static void purl, (struct http_request *rq, struct http_reply *rp));
_PROTOTYPE(static char *virt, (char *to, char *host));
static int authaccess(rq, rp)
struct http_request *rq;
struct http_reply *rp;
{
struct auth *auth;
struct authuser *pu;
/* set authorization to be checked against */
if(rq->type == HTTP_REQUEST_TYPE_PROXY)
auth = proxyauth;
else
auth = rp->auth;
/* no authorization so no access to anyone */
if(auth == NULL) {
rp->status = HTTP_STATUS_FORBIDDEN;
strcpy(rp->statusmsg, "No Authoriation");
return(-1);
}
/* access must be R for PROXY */
if(rq->type == HTTP_REQUEST_TYPE_PROXY)
if(!(auth->urlaccess & URLA_READ)) {
rp->status = HTTP_STATUS_FORBIDDEN;
strcpy(rp->statusmsg, "Proxy not authorized");
return(-1);
}
/* no password file so it is a free for all */
if(auth->passwdfile == NULL)
return(0);
/* they did not give us an authorized user */
if(rq->authuser[0] == '\0') {
if(rq->type == HTTP_REQUEST_TYPE_PROXY)
rp->status = HTTP_STATUS_PROXY_AUTH_REQRD;
else
rp->status = HTTP_STATUS_UNAUTHORIZED;
strcpy(rp->statusmsg, "No Authorized User Given");
return(-1);
}
/* check if user okay */
pu = auth->users;
if(pu == NULL)
; /* no user list we allow anyone in file */
else {
while(pu != NULL) {
if(!strcmp(pu->user, rq->authuser))
break;
pu = pu->next;
}
/* user is not in list so no access */
if(pu == NULL) {
if(rq->type == HTTP_REQUEST_TYPE_PROXY)
rp->status = HTTP_STATUS_PROXY_AUTH_REQRD;
else
rp->status = HTTP_STATUS_UNAUTHORIZED;
strcpy(rp->statusmsg, "Forbidden User not authorized");
return(-1);
}
}
/* check if password file exists, if not no access */
if(passfile(auth->passwdfile)) {
rp->status = HTTP_STATUS_FORBIDDEN;
strcpy(rp->statusmsg, "Invalid passwd file");
return(-1);
}
/* check if user in password file, if not no access */
if(passuser(auth->passwdfile, rq->authuser)) {
if(rq->type == HTTP_REQUEST_TYPE_PROXY)
rp->status = HTTP_STATUS_PROXY_AUTH_REQRD;
else
rp->status = HTTP_STATUS_UNAUTHORIZED;
strcpy(rp->statusmsg, "Forbidden Bad User");
return(-1);
}
/* check if a password exists, if not no access */
if(passnone(auth->passwdfile, rq->authuser)) {
if(rq->type == HTTP_REQUEST_TYPE_PROXY)
rp->status = HTTP_STATUS_PROXY_AUTH_REQRD;
else
rp->status = HTTP_STATUS_UNAUTHORIZED;
strcpy(rp->statusmsg, "Forbidden no password");
return(-1);
}
/* check if password matches, if not no access */
if(passpass(auth->passwdfile, rq->authuser, rq->authpass)) {
if(rq->type == HTTP_REQUEST_TYPE_PROXY)
rp->status = HTTP_STATUS_PROXY_AUTH_REQRD;
else
rp->status = HTTP_STATUS_UNAUTHORIZED;
strcpy(rp->statusmsg, "Forbidden bad password");
return(-1);
}
/* whew, all the checks passed so I guess we let them have it */
return(0);
}
int police(rq, rp)
struct http_request *rq;
struct http_reply *rp;
{
int size;
struct stat st;
struct dirsend *ds;
purl(rq, rp);
rp->mtype = "text/html";
#ifdef DEBUG
fprintf(stderr, "httpd: Trying %s\n", rp->realurl);
#endif
/* now check authorizations */
if(authaccess(rq, rp)) {
/* Don't give them any details why authorization failed */
strcpy(rp->statusmsg, "No Access Granted");
return(0);
}
/* a proxy request only needs an authorization check */
if(rq->type == HTTP_REQUEST_TYPE_PROXY)
return(0);
/* check access to real url */
if(stat(rp->realurl, &st)) {
if(errno == EACCES)
rp->status = HTTP_STATUS_FORBIDDEN;
else
rp->status = HTTP_STATUS_NOT_FOUND;
strcpy(rp->statusmsg, strerror(errno));
/* a PUT and NOT FOUND is okay since we are creating */
if(rq->method != HTTP_METHOD_PUT || rp->status != HTTP_STATUS_NOT_FOUND)
return(0);
}
/* If it is a directory do the appropriate thang! */
if(rq->method == HTTP_METHOD_GET || rq->method == HTTP_METHOD_HEAD)
if((st.st_mode & S_IFMT) == S_IFDIR) {
if(rq->url[strlen(rq->url) - 1] != '/') {
strncat(rq->url, "/", sizeof(rq->url) - strlen(rq->url));
rp->status = HTTP_STATUS_MOVED_TEMP;
sprintf(rp->statusmsg, "Moved to %s", rq->url);
return(0);
}
size = strlen(rq->url);
ds = dirsend;
while(ds != NULL) {
strncpy(rq->url+size, ds->file, sizeof(rq->url)-size);
purl(rq, rp);
if(stat(rp->realurl, &st)) {
if(errno == EACCES)
rp->status = HTTP_STATUS_FORBIDDEN;
else
if(errno != ENOENT)
rp->status = HTTP_STATUS_NOT_FOUND;
} else
break;
if(rp->status != HTTP_STATUS_OK) {
strcpy(rp->statusmsg, strerror(errno));
return(0);
}
ds = ds->next;
}
if(ds == NULL) {
rq->url[size] = '\0';
purl(rq, rp);
if(stat(rp->realurl, &st)) {
if(errno == EACCES)
rp->status = HTTP_STATUS_FORBIDDEN;
else
rp->status = HTTP_STATUS_NOT_FOUND;
strcpy(rp->statusmsg, strerror(errno));
return(0);
}
}
}
if(rq->method == HTTP_METHOD_PUT && !(rp->urlaccess & URLA_WRITE)) {
rp->status = HTTP_STATUS_METHOD_NOT_ALLOWED;
strcpy(rp->statusmsg, "Method not allowed");
return(0);
}
if(rp->status == HTTP_STATUS_OK) {
/* Here is where we check if it is a program or script to run */
if(cgiexec(rq, rp))
return(0);
if((st.st_mode & S_IFMT) == S_IFDIR) {
rp->status = HTTP_STATUS_NOT_FOUND;
strcpy(rp->statusmsg, "Directory listing not available");
return(0);
}
if((st.st_mode & S_IFMT) != S_IFREG) {
rp->status = HTTP_STATUS_NOT_FOUND;
strcpy(rp->statusmsg, "Not a regular file");
return(0);
}
}
/* open the URL for updating */
if(rq->method == HTTP_METHOD_PUT) {
rp->status = HTTP_STATUS_OK;
strcpy(rp->statusmsg, "OK");
rp->ofd = open(rp->realurl, O_WRONLY | O_CREAT | O_TRUNC);
if(rp->ofd < 0) {
if(errno == EACCES)
rp->status = HTTP_STATUS_FORBIDDEN;
else
rp->status = HTTP_STATUS_NOT_FOUND;
strcpy(rp->statusmsg, strerror(errno));
return(0);
}
return(0);
}
if(!(rp->urlaccess & URLA_READ)) {
rp->status = HTTP_STATUS_FORBIDDEN;
strcpy(rp->statusmsg, "No way...");
return(0);
}
rp->mtype = mimetype(rp->realurl);
rp->size = st.st_size;
rp->modtime = st.st_mtime;
/* open the url if it is a file */
rp->fd = open(rp->realurl, O_RDONLY);
if(rp->fd < 0) {
if(errno == EACCES)
rp->status = HTTP_STATUS_FORBIDDEN;
else
rp->status = HTTP_STATUS_NOT_FOUND;
strcpy(rp->statusmsg, strerror(errno));
return(0);
}
return(0);
}
static void purl(rq, rp)
struct http_request *rq;
struct http_reply *rp;
{
struct vpath *pv;
int gotreal, gotperm;
char *p;
int match;
int len;
gotreal = 0; gotperm = 0;
#ifdef DEBUG
fprintf(stderr, "httpd: Processing url = \"%s\"\n", rq->url);
#endif
/* remove any .. references */
p = rq->url;
while(*p) {
while(*p && *p != '/') p++;
if(*p != '/') continue;
p++;
if(*p != '.') continue;
p++;
if(*p != '.') continue;
p++;
strcpy(p - 3, p);
p = p - 3;
}
for(pv = vpath; pv != NULL; pv = pv->next) {
len = strlen(pv->from) - 1;
if(pv->from[len] == '*' || pv->from[len] == '$')
if(len == 0)
match = MATCH_WILD;
else
match = strncmp(rq->url, pv->from, len) ? MATCH_NONE : MATCH_WILD;
else
if(!strcmp(rq->url, pv->from))
match = MATCH_FULL;
else
match = MATCH_NONE;
#ifdef DEBUG
fprintf(stderr, "httpd: Trying \"%s\" %d %d %d %s\n",
pv->from, match, gotreal, gotperm, pv->auth->name);
#endif
if(match != MATCH_NONE) {
gotperm = 1;
rp->auth = pv->auth;
if(pv->urlaccess == -1 && rp->auth != NULL)
rp->urlaccess = rp->auth->urlaccess;
else
rp->urlaccess = pv->urlaccess;
if(strcmp(pv->to, ".")) {
gotreal = 1;
strncpy(rp->realurl, virt(pv->to, rq->host), sizeof(rp->realurl));
rp->realurl[sizeof(rp->realurl)-1] = '\0';
if(match == MATCH_WILD && pv->from[len] != '$') {
strncat(rp->realurl, rq->url+len, sizeof(rp->realurl) - strlen(rp->realurl));
rp->realurl[sizeof(rp->realurl)-1] = '\0';
}
}
}
if(match == MATCH_FULL) break;
}
if(rp->urlaccess == -1) rp->urlaccess = mkurlaccess("");
if(!gotreal) {
strncpy(rp->realurl, rq->url, sizeof(rp->realurl));
rp->realurl[sizeof(rp->realurl)-1] = '\0';
}
if(!gotperm)
rp->auth = NULL;
#ifdef DEBUG
fprintf(stderr, "DEBUG: url = \"%s\" realurl = \"%s\" auth = \"%s\"\n",
rq->url, rp->realurl, ((rp->auth == NULL) ? "No Access" : rp->auth->name));
fprintf(stderr, "DEBUG: query = %s\n", rq->query);
#endif
return;
}
static char *virt(to, host)
char *to;
char *host;
{
static char vroot[256];
struct vhost *ph;
#ifdef DEBUG
fprintf(stderr, "virt: %s %s\n", to, host);
#endif
if(vhost == NULL) return(to);
if(to[0] != '/') return(to);
if(to[1] != '/') return(to);
if(to[2] != '/') return(to);
vroot[0] = '\0';
for(ph = vhost; ph != NULL; ph = ph->next) {
#ifdef DEBUG
fprintf(stderr, "ph: %s %s %s\n", ph->hname, ph->root, vroot);
#endif
if(!strcmp(ph->hname, "*") && vroot[0] == '\0')
strncpy(vroot, ph->root, sizeof(vroot));
if(!strcasecmp(ph->hname, host)) {
strncpy(vroot, ph->root, sizeof(vroot));
break;
}
}
strncat(vroot, to+3, sizeof(vroot));
#ifdef DEBUG
fprintf(stderr, "vroot: %s\n", vroot);
#endif
return(vroot);
}

81
commands/httpd/process.c Normal file
View file

@ -0,0 +1,81 @@
/* process.c
*
* This file is part of httpd.
*
* 02/17/1996 Michael Temari <Michael@TemWare.Com>
* 07/07/1996 Initial Relase Michael Temari <Michael@TemWare.Com>
* 12/29/2002 Michael Temari <Michael@TemWare.Com>
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include "config.h"
#include "http.h"
#include "utility.h"
int processrequest(rq, rp)
struct http_request *rq;
struct http_reply *rp;
{
/* clear out http_reply */
memset(rp, 0, sizeof(*rp));
rp->status = HTTP_STATUS_OK;
strcpy(rp->statusmsg, "OK");
rp->modtime = (time_t) -1;
rp->urlaccess = -1;
rp->size = 0;
rp->fd = -1;
rp->ofd = -1;
rp->pid = 0;
/* Simple requests can only be a GET */
if(rq->type == HTTP_REQUEST_TYPE_SIMPLE && rq->method != HTTP_METHOD_GET) {
rp->status = HTTP_STATUS_BAD_REQUEST;
strcpy(rp->statusmsg, "Bad request");
return(0);
}
/* I don't know this method */
if(rq->method == HTTP_METHOD_UNKNOWN) {
rp->status = HTTP_STATUS_NOT_IMPLEMENTED;
strcpy(rp->statusmsg, "Method not implemented");
return(0);
}
/* Check for access and real location of url */
if(police(rq, rp))
return(-1);
/* We're done if there was an error accessing the url */
if(rp->status != HTTP_STATUS_OK)
return(0);
/* Check to see if we have a newer version for them */
if(rq->method == HTTP_METHOD_GET)
if(rq->ifmodsince != (time_t) -1)
if(rq->ifmodsince < time((time_t *)NULL))
if(rp->modtime != (time_t) -1 && rp->modtime <= rq->ifmodsince) {
rp->status = HTTP_STATUS_NOT_MODIFIED;
strcpy(rp->statusmsg, "Not modified");
close(rp->fd);
rp->fd = -1;
return(0);
}
rp->status = HTTP_STATUS_OK;
strcpy(rp->statusmsg, "OK");
if(rp->size != 0)
rp->keepopen = rq->keepopen;
return(0);
}

292
commands/httpd/proxy.c Normal file
View file

@ -0,0 +1,292 @@
/* proxy.c Copyright 2000 by Michael Temari All Rights Reserved */
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <unistd.h>
#include <time.h>
#include <net/netlib.h>
#include <net/hton.h>
#include <net/gen/in.h>
#include <net/gen/inet.h>
#include <net/gen/tcp.h>
#include <net/gen/tcp_io.h>
#include <net/gen/socket.h>
#include <net/gen/netdb.h>
#include "config.h"
#include "http.h"
#include "utility.h"
#include "net.h"
_PROTOTYPE(static int connect, (char *host));
#if 0
_PROTOTYPE(static int readline, (char *p, int len));
#endif
_PROTOTYPE(static int sendout, (int fd, char *data));
static int connect(host)
char *host;
{
nwio_tcpconf_t tcpconf;
nwio_tcpcl_t tcpcopt;
char *tcp_device;
int netfd;
ipaddr_t nethost;
tcpport_t netport = 0;
struct hostent *hp;
struct servent *sp;
char *p;
int s;
int tries;
p = host;
while(*p && *p != ':') p++;
if(*p == ':') {
*p++ = '\0';
netport = htons(atoi(p));
}
if((hp = gethostbyname(host)) == (struct hostent *)NULL) {
fprintf(stderr, "Unknown host %s!\n", host);
return(-1);
} else
memcpy((char *) &nethost, (char *) hp->h_addr, hp->h_length);
/* Now, to which port must we connect? */
if(netport == 0)
if((sp = getservbyname("http", "tcp")) == (struct servent *)NULL) {
fprintf(stderr, "HTTP port is unknown????\n");
return(-1);
} else
netport = sp->s_port;
/* Connect to the host */
if((tcp_device = getenv("TCP_DEVICE")) == NULL)
tcp_device = TCP_DEVICE;
if((netfd = open(tcp_device, O_RDWR)) < 0) {
perror("httpget: opening tcp");
return(-1);
}
tcpconf.nwtc_flags = NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP;
tcpconf.nwtc_remaddr = nethost;
tcpconf.nwtc_remport = netport;
s = ioctl(netfd, NWIOSTCPCONF, &tcpconf);
if(s < 0) {
perror("httpget: NWIOSTCPCONF");
close(netfd);
return(-1);
}
s = ioctl(netfd, NWIOGTCPCONF, &tcpconf);
if(s < 0) {
perror("httpget: NWIOGTCPCONF");
close(netfd);
return(-1);
}
tcpcopt.nwtcl_flags = 0;
tries = 0;
do {
s = ioctl(netfd, NWIOTCPCONN, &tcpcopt);
if(s == -1 && errno == EAGAIN) {
if(tries++ >= 10)
break;
sleep(10);
} else
break;
} while(1);
if(s < 0) {
perror("httpget: NWIOTCPCONN");
close(netfd);
return(-1);
}
return(netfd);
}
char buffer[8192];
#if 0
static int readline(p, len)
char *p;
int len;
{
int c;
int cr = 0;
int n = 0;
len--;
if(len < 0) return(-1);
while(len > 0 && (c = getchar()) != EOF) {
if(c == '\n' && cr) {
*p = '\0';
return(n);
}
if(c == '\r') {
cr = 1;
continue;
}
n++;
*p++ = c;
}
*p = '\0';
return(n);
}
#endif
static int sendout(fd, data)
int fd;
char *data;
{
if(strlen(data) > 0)
write(fd, data, strlen(data));
write(fd, "\r\n", 2);
if(dbglog != (FILE *)NULL) {
fprintf(dbglog, "REPLY: %s\n", data);
fflush(dbglog);
}
return(0);
}
void proxy(rq, rp)
struct http_request *rq;
struct http_reply *rp;
{
int s;
char *p;
char *ps;
char *b;
char *host;
static char user[256];
static char pass[256];
char *url;
char *at;
int fd;
int bad;
while(1) {
bad = 0;
p = rq->uri;
if(tolower(*p++) != 'h') bad++;
if(tolower(*p++) != 't') bad++;
if(tolower(*p++) != 't') bad++;
if(tolower(*p++) != 'p') bad++;
if(tolower(*p++) != ':') bad++;
if(tolower(*p++) != '/') bad++;
if(tolower(*p++) != '/') bad++;
if(bad) {
sprintf(buffer, "HTTP/%d.%d 400 Bad Request",
rq->vmajor, rq->vminor);
sendout(1, buffer);
sendout(1, "");
sendout(1, "Proxy Request was not http:");
return;
}
host = p;
while(*p && *p != '/') p++;
url = p;
*url = '\0';
at = strchr(host, '@');
if(at != (char *)NULL) {
*at = '\0';
p = host;
while(*p && *p != ':') p++;
if(*p)
*p++ = '\0';
strcpy(user, host);
strcpy(pass, p);
host = at + 1;
} else {
user[0] = '\0';
pass[0] = '\0';
}
fd = connect(host);
if(fd < 0) {
sprintf(buffer, "HTTP/%d.%d 400 Bad Request",
rq->vmajor, rq->vminor);
sendout(1, buffer);
sendout(1, "");
sendout(1, "Could not connect to host");
return;
}
if(rq->method == HTTP_METHOD_GET)
write(fd, "GET ", 4); else
if(rq->method == HTTP_METHOD_POST)
write(fd, "POST ", 5);
*url = '/';
if(strlen(url) > 0)
write(fd, url, strlen(url));
write(fd, " ", 1);
sprintf(buffer, "HTTP/%d.%d", rq->vmajor, rq->vminor);
sendout(fd, buffer);
if(rq->ifmodsince != -1) {
write(fd, "If-Mod-Since: ", 14);
sendout(fd, httpdate(&rq->ifmodsince));
}
if(rq->size != 0) {
sendout(fd, "Content-Type: application/x-www-form-urlencoded");
sprintf(buffer, "Content-Length: %lu", rq->size);
sendout(fd, buffer);
}
if(*rq->cookie) {
sprintf(buffer, "Cookie: %s", rq->cookie);
sendout(fd, buffer);
}
if(*rq->useragent) {
sprintf(buffer, "User-Agent: %s", rq->useragent);
sendout(fd, buffer);
}
if(*rq->host) {
sprintf(buffer, "Host: %s", rq->host);
sendout(fd, buffer);
}
if(*rq->wwwauth) {
sprintf(buffer, "Authorization: %s", rq->wwwauth);
sendout(fd, buffer);
}
sprintf(buffer, "X-Forwarded-From: %s", rmthostaddr);
sendout(fd, buffer);
sendout(fd, "");
if(rq->size != 0) {
if(stdlog != (FILE *)NULL) {
fprintf(stdlog, "%s %s %d %d ",
logdate((time_t *)NULL), rmthostname,
rq->method, rp->status);
fprintf(stdlog, "proxy %s?", rq->uri);
}
while((s = read(0, buffer, rq->size >
sizeof(buffer) ? sizeof(buffer) : rq->size)) > 0) {
write(fd, buffer, s);
rq->size -= s;
b = buffer;
if(stdlog != (FILE *)NULL)
while(s--) fputc(*b++, stdlog);
if(rq->size == 0) break;
}
if(stdlog != (FILE *)NULL) {
fprintf(stdlog, "\n");
fflush(stdlog);
}
}
while((s = read(fd, buffer, sizeof(buffer))) > 0) {
write(1, buffer, s);
}
close(fd);
return;
}
}

189
commands/httpd/reply.c Normal file
View file

@ -0,0 +1,189 @@
/* reply.c
*
* This file is part of httpd.
*
* 02/17/1996 Michael Temari <Michael@TemWare.Com>
* 07/07/1996 Initial Release Michael Temari <Michael@TemWare.Com>
* 12/29/2002 Michael Temari <Michael@TemWare.Com>
*
*/
#include <sys/types.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include "http.h"
#include "utility.h"
#include "net.h"
#include "config.h"
#define SERVER "Server: "VERSION
_PROTOTYPE(static void GotAlarm, (int sig));
_PROTOTYPE(static int sendout, (char *data));
static void GotAlarm(sig)
int sig;
{
}
static int sendout(data)
char *data;
{
if(strlen(data) > 0)
write(1, data, strlen(data));
write(1, "\r\n", 2);
if(dbglog != (FILE *)NULL) {
fprintf(dbglog, "REPLY: %s\n", data);
fflush(dbglog);
}
return(0);
}
int sendreply(rp, rq)
struct http_reply *rp;
struct http_request *rq;
{
int s;
int s2;
int e;
static char buffer[8192];
if(rq->type != HTTP_REQUEST_TYPE_PROXY)
/* We're receiving data from a */
if(rq->method == HTTP_METHOD_POST ||
(rq->method == HTTP_METHOD_PUT && rp->status == HTTP_STATUS_OK)) {
if(rq->type != HTTP_REQUEST_TYPE_FULL)
return(0);
if(rq->method == HTTP_METHOD_PUT)
rp->status = HTTP_STATUS_CREATED;
else
rp->status = HTTP_STATUS_OK;
while(rq->size != 0) {
s = read(0, buffer, (rq->size > sizeof(buffer)) ? sizeof(buffer) : rq->size);
if(s <= 0) {
rp->status = HTTP_STATUS_SERVER_ERROR;
strcpy(rp->statusmsg, strerror(errno));
close(rp->fd);
close(rp->ofd);
break;
}
rq->size -= s;
s2 = write(rp->ofd, buffer, s);
if(s2 != s) break;
}
}
if(rp->status != HTTP_STATUS_OK && rp->status != HTTP_STATUS_CREATED &&
rp->status != HTTP_STATUS_NOT_MODIFIED)
rp->keepopen = 0;
if(rp->status == HTTP_STATUS_NOT_MODIFIED) {
sprintf(buffer, "<h2>Error %03d %s</h2>",
rp->status, rp->statusmsg);
rp->size = strlen(buffer);
rp->keepopen = rq->keepopen;
}
if(!rp->headers) {
if((rq->type == HTTP_REQUEST_TYPE_PROXY && rp->status != HTTP_STATUS_OK) ||
rq->type == HTTP_REQUEST_TYPE_FULL) {
sprintf(buffer, "HTTP/%d.%d %03d %s",
rq->vmajor, rq->vminor, rp->status, rp->statusmsg);
sendout(buffer);
sendout(SERVER);
if(rp->status == HTTP_STATUS_MOVED_PERM ||
rp->status == HTTP_STATUS_MOVED_TEMP) {
#if 1
sprintf(buffer, "Location: %s", rq->url);
#else
sprintf(buffer, "Location: http://%s%s", myhostname, rq->url);
#endif
sendout(buffer);
}
if(rp->keepopen)
sendout("Connection: Keep-Alive");
else
sendout("Connection: Close");
if(rp->status == HTTP_STATUS_UNAUTHORIZED && rp->auth != NULL) {
sprintf(buffer, "WWW-Authenticate: Basic realm=\"%s\"", rp->auth->desc);
sendout(buffer);
}
if(rp->status == HTTP_STATUS_PROXY_AUTH_REQRD && proxyauth != NULL) {
sprintf(buffer, "Proxy-Authenticate: Basic realm=\"%s\"", proxyauth->desc);
sendout(buffer);
}
if(rp->modtime != (time_t) -1) {
sprintf(buffer, "Last-Modified: %s", httpdate(&rp->modtime));
sendout(buffer);
}
if(rp->size != 0) {
sprintf(buffer, "Content-Length: %lu", rp->size);
sendout(buffer);
}
if(rp->status == HTTP_STATUS_OK) {
sprintf(buffer, "Content-Type: %s", rp->mtype);
sendout(buffer);
} else
sendout("Content-Type: text/html");
if(!rp->headers)
sendout("");
} else
if(rp->status != HTTP_STATUS_OK)
return(0);
}
if(rp->status != HTTP_STATUS_OK && rp->status != HTTP_STATUS_CREATED) {
sprintf(buffer, "<h2>Error %03d %s</h2>",
rp->status, rp->statusmsg);
sendout(buffer);
return(0);
}
if(rq->type == HTTP_REQUEST_TYPE_PROXY) {
proxy(rq, rp);
return(0);
}
/* send out entity body */
if(rq->method == HTTP_METHOD_GET || rq->method == HTTP_METHOD_POST) {
errno = 0;
while(1) {
alarm(0);
signal(SIGALRM, GotAlarm);
alarm(10);
s = read(rp->fd, buffer, sizeof(buffer));
e = errno;
alarm(0);
if(s > 0) {
s2 = write(1, buffer, s);
e = errno;
if(s2 != s) break;
continue;
}
if(s == 0) break;
if(s < 0 && e != EINTR) break;
signal(SIGALRM, GotAlarm);
alarm(2);
s = read(0, buffer, 1);
e = errno;
alarm(0);
if(s < 0 && e != EINTR) break;
}
}
close(rp->fd);
rp->fd = -1;
if(rp->ofd != -1)
close(rp->ofd);
if(rp->pid != 0 && e != 0) {
kill(-rp->pid, SIGHUP);
rp->pid = 0;
}
return(0);
}

369
commands/httpd/request.c Normal file
View file

@ -0,0 +1,369 @@
/* request.c
*
* This file is part of httpd.
*
* 02/17/1996 Michael Temari <Michael@TemWare.Com>
* 07/07/1996 Initial Release Michael Temari <Michael@TemWare.Com>
* 12/29/2002 Michael Temari <Michael@TemWare.Com>
*
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <pwd.h>
#ifdef _MINIX
#include <minix/minlib.h>
#endif
#include <errno.h>
#include "http.h"
#include "utility.h"
#include "config.h"
_PROTOTYPE(static void Timeout, (int sig));
_PROTOTYPE(static int getline, (char *buffer, int size));
_PROTOTYPE(static void authorize, (char *p, struct http_request *rq));
_PROTOTYPE(static void decurl, (char *u));
static int TimeOut;
static void Timeout(sig)
int sig;
{
TimeOut = 1;
}
static int getline(buffer, size)
char *buffer;
int size;
{
char *p;
int s;
p = buffer;
while(p < (buffer + size - 1)) {
TimeOut = 0;
signal(SIGALRM, Timeout);
alarm(5*60);
s = read(0, p, 1);
alarm(0);
if(TimeOut)
return(-1);
if(s != 1)
return(-1);
if(*p == '\n') break;
p++;
}
*++p = '\0';
p = &buffer[strlen(buffer) - 1];
if(p >= buffer && (*p == '\r' || *p == '\n')) *p-- ='\0';
if(p >= buffer && (*p == '\r' || *p == '\n')) *p-- ='\0';
return(strlen(buffer));
}
static void authorize(p, rq)
char *p;
struct http_request *rq;
{
char *s;
if(toupper(*p++) == 'B' &&
toupper(*p++) == 'A' &&
toupper(*p++) == 'S' &&
toupper(*p++) == 'I' &&
toupper(*p++) == 'C' &&
toupper(*p++) == ' ') ;
else
return;
s = decode64(p);
if((p = strchr(s, ':')) == (char *)NULL)
p = "";
else
*p++ = '\0';
strncpy(rq->authuser, s, sizeof(rq->authuser));
strncpy(rq->authpass, p, sizeof(rq->authpass));
return;
}
int getrequest(rq)
struct http_request *rq;
{
static char line[4096];
char *p, *p2, *ps;
int s, len;
struct vhost *ph;
/* get request, it may be simple */
s = getline(line, sizeof(line));
if(s < 0)
return(-1);
if(dbglog != (FILE *)NULL) {
fprintf(dbglog, "REQUEST: %s\n", line);
fflush(dbglog);
}
/* clear http_request */
memset(rq, 0, sizeof(*rq));
rq->ifmodsince = (time_t) -1;
/* assume simple request */
rq->type = HTTP_REQUEST_TYPE_SIMPLE;
/* parse the method */
p = line;
while(*p && !LWS(*p)) {
*p = toupper(*p);
p++;
}
if(*p) *p++ = '\0';
if(!strcmp(line, "GET"))
rq->method = HTTP_METHOD_GET; else
if(!strcmp(line, "HEAD"))
rq->method = HTTP_METHOD_HEAD; else
if(!strcmp(line, "POST"))
rq->method = HTTP_METHOD_POST; else
if(!strcmp(line, "PUT"))
rq->method = HTTP_METHOD_PUT; else
#if 0
if(!strcmp(line, "OPTIONS"))
rq->method = HTTP_METHOD_OPTIONS; else
if(!strcmp(line, "PATCH"))
rq->method = HTTP_METHOD_PATCH; else
if(!strcmp(line, "COPY"))
rq->method = HTTP_METHOD_COPY; else
if(!strcmp(line, "MOVE"))
rq->method = HTTP_METHOD_MOVE; else
if(!strcmp(line, "DELETE"))
rq->method = HTTP_METHOD_DELETE; else
if(!strcmp(line, "LINK"))
rq->method = HTTP_METHOD_LINK; else
if(!strcmp(line, "UNLINK"))
rq->method = HTTP_METHOD_UNLINK; else
if(!strcmp(line, "TRACE"))
rq->method = HTTP_METHOD_TRACE; else
if(!strcmp(line, "WRAPPED"))
rq->method = HTTP_METHOD_WRAPPED; else
#endif
rq->method = HTTP_METHOD_UNKNOWN;
/* parse the requested URI */
p2 = rq->uri;
len = sizeof(rq->uri) - 1;
while(*p && !LWS(*p) && len > 0) {
*p2++ = *p++;
len--;
}
*p2 = '\0';
/* eat up any leftovers if uri was too big */
while(*p && !LWS(*p))
p++;
/* save for continued processing later */
ps = p;
/* parse the requested URL */
p = rq->uri;
p2 = rq->url;
len = sizeof(rq->url) - 1;
while(*p && !LWS(*p) && *p != '?' && len > 0) {
*p2++ = *p++;
len--;
}
*p2 = '\0';
/* See if there is a query string */
if(*p == '?') {
p++;
p2 = rq->query;
len = sizeof(rq->query) - 1;
while(*p && !LWS(*p) && len > 0) {
*p2++ = *p++;
len--;
}
}
/* eat up any leftovers */
while(*p && !LWS(*p)) p++;
if(rq->url[0] == '\0') {
rq->url[0] = '/';
rq->url[1] = '\0';
}
/* url is a decoded copy of the uri */
decurl(rq->url);
/* restore and continue processing */
p = ps;
/* if this is true it is a simple request */
if(*p == '\0')
return(0);
/* parse HTTP version */
while(*p && LWS(*p)) p++;
if(toupper(*p++) != 'H') return(0);
if(toupper(*p++) != 'T') return(0);
if(toupper(*p++) != 'T') return(0);
if(toupper(*p++) != 'P') return(0);
if( *p++ != '/') return(0);
/* version major */
rq->vmajor = 0;
while((*p >= '0') && (*p <= '9'))
rq->vmajor = rq->vmajor * 10 + (*p++ - '0');
if(*p != '.')
return(0);
p++;
/* version minor */
rq->vminor = 0;
while((*p >= '0') && (*p <= '9'))
rq->vminor = rq->vminor * 10 + (*p++ - '0');
if(*p)
return(0);
rq->type = HTTP_REQUEST_TYPE_FULL;
p = rq->uri;
/* check if it is a proxy request */
if(toupper(*p++) == 'H' &&
toupper(*p++) == 'T' &&
toupper(*p++) == 'T' &&
toupper(*p++) == 'P' &&
toupper(*p++) == ':')
rq->type = HTTP_REQUEST_TYPE_PROXY;
/* parse any header fields */
while((s = getline(line, sizeof(line))) > 0) {
if(toupper(line[0]) == 'A' &&
toupper(line[1]) == 'U')
if(dbglog != (FILE *)NULL) {
fprintf(dbglog, "REQUEST: Authorization:\n");
fflush(dbglog);
} else ;
else
if(dbglog != (FILE *)NULL) {
fprintf(dbglog, "REQUEST: %s\n", line);
fflush(dbglog);
}
p = line;
while(*p && *p != ':') {
*p = toupper(*p);
p++;
}
if(*p != ':') continue; /* bad header field, skip it */
*p++ = '\0';
while(*p && LWS(*p)) p++;
/* header field value parsing here */
if(!strcmp(line, "HOST")) {
strncpy(rq->host, p, sizeof(rq->host));
p2 = strrchr(rq->host, ':');
if(p2 != (char *)NULL) {
*p2++ = '\0';
rq->port = atoi(p2);
}
/* if unknown virtual host then exit quietly */
for(ph = vhost; ph != NULL; ph = ph->next) {
if(!strcasecmp(ph->hname, "*")) break;
if(!strcasecmp(ph->hname, rq->host)) break;
}
if(rq->type != HTTP_REQUEST_TYPE_PROXY)
if(ph == NULL && vhost != NULL) return(1);
} else
if(!strcmp(line, "USER-AGENT"))
strncpy(rq->useragent, p, sizeof(rq->useragent)); else
if(!strcmp(line, "CONNECTION"))
rq->keepopen = strcasecmp(p, "Keep-Alive") ? 0 : 1; else
if(!strcmp(line, "IF-MODIFIED-SINCE"))
rq->ifmodsince = httptime(p); else
if(!strcmp(line, "CONTENT-LENGTH"))
rq->size = atol(p); else
if(!strcmp(line, "AUTHORIZATION")) {
strncpy(rq->wwwauth, p, sizeof(rq->wwwauth));
if(rq->type != HTTP_REQUEST_TYPE_PROXY)
authorize(p, rq);
} else
if(!strcmp(line, "PROXY-AUTHORIZATION")) {
if(rq->type == HTTP_REQUEST_TYPE_PROXY)
authorize(p, rq);
} else
if(!strcmp(line, "DATE"))
rq->msgdate = httptime(p); else
if(!strcmp(line, "COOKIE")) {
strncpy(rq->cookie, p, sizeof(rq->cookie)-1);
rq->cookie[sizeof(rq->cookie)-1] = '\0';
}
}
if(rq->type != HTTP_REQUEST_TYPE_PROXY)
if(*rq->host == '\0' && vhost != NULL) return(1);
if(dbglog != (FILE *)NULL && rq->authuser[0] != '\0') {
fprintf(dbglog, "REQUEST: AuthUser=%s\n", rq->authuser);
fflush(dbglog);
}
if(s < 0) {
fprintf(stderr, "httpd: getrequest: Error getline (header fields)\n");
return(-1);
}
return(0);
}
static void decurl(u)
char *u;
{
char *p;
char h1, h2;
char c;
p = u;
while(*p) {
switch(*p) {
case '\0':
c = '\0';
break;
case '+':
c = ' ';
p++;
break;
case '%':
h1 = '0';
h2 = '0';
p++;
h1 = tolower(*p);
if(*p) p++;
h2 = tolower(*p);
if(*p) p++;
c = (h1 > '9') ? (10 + h1 - 'a') : (h1 - '0');
c = 16 * c + ((h2 > '9') ? (10 + h2 - 'a') : (h2 - '0'));
break;
default:
c = *p++;
}
*u++ = c;
}
*u = '\0';
}

265
commands/httpd/utility.c Normal file
View file

@ -0,0 +1,265 @@
/* utility.c
*
* This file is part of httpd
*
* 02/17/1996 Michael Temari <Michael@TemWare.Com>
* 07/07/1996 Initial Release Michael Temari <Michael@TemWare.Com>
* 12/29/2002 Initial Release Michael Temari <Michael@TemWare.Com>
*
*/
#include <sys/types.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "utility.h"
#include "config.h"
const char *days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
const char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
char *logdate(t)
time_t *t;
{
time_t worktime;
struct tm *tm;
static char datebuffer[80];
if(t == (time_t *)NULL)
(void) time(&worktime);
else
worktime = *t;
tm = localtime(&worktime);
sprintf(datebuffer, "%4d%02d%02d%02d%02d%02d",
1900+tm->tm_year,
tm->tm_mon + 1,
tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
return(datebuffer);
}
char *httpdate(t)
time_t *t;
{
time_t worktime;
struct tm *tm;
static char datebuffer[80];
if(t == (time_t *)NULL)
(void) time(&worktime);
else
worktime = *t;
tm = gmtime(&worktime);
sprintf(datebuffer, "%s, %02d %s %4d %02d:%02d:%02d GMT",
days[tm->tm_wday],
tm->tm_mday, months[tm->tm_mon], 1900+tm->tm_year,
tm->tm_hour, tm->tm_min, tm->tm_sec);
return(datebuffer);
}
time_t httptime(p)
char *p;
{
time_t worktime, gtime, ltime;
struct tm tm;
struct tm *tm2;
int i;
worktime = (time_t) -1;
tm.tm_yday = 0;
tm.tm_isdst = -1;
/* day of week */
for(i = 0; i < 7; i++)
if(!strncmp(p, days[i], 3)) break;
if(i < 7)
tm.tm_wday = i;
else
return(worktime);
while(*p && *p != ' ') p++;
if(!*p) return(worktime);
while(*p && *p == ' ') p++;
if(!*p) return(worktime);
if(*p >= '0' && *p <= '9') {
/* day */
if(*(p+1) >= '0' && *(p+1) <= '9')
tm.tm_mday = 10 * (*p - '0') + (*(p+1) - '0');
else
return(worktime);
p += 3;
/* month */
for(i = 0; i < 12; i++)
if(!strncmp(p, months[i], 3)) break;
if(i < 12)
tm.tm_mon = i;
else
return(worktime);
p += 3;
if(!*p++) return(worktime);
/* year */
tm.tm_year = atoi(p);
while(*p && *p != ' ') p++;
if(*p) p++;
} else {
/* day */
tm.tm_mday = atoi(p);
while(*p && *p != ' ') p++;
while(*p && *p == ' ') p++;
if(!*p) return(worktime);
}
/* hour */
if(*p < '0' || *p > '9' || *(p+1) < '0' || *(p+1) > '9' || *(p+2) != ':') return(worktime);
tm.tm_hour = 10 * (*p - '0') + (*(p+1) - '0');
p += 3;
/* minute */
if(*p < '0' || *p > '9' || *(p+1) < '0' || *(p+1) > '9' || *(p+2) != ':') return(worktime);
tm.tm_min = 10 * (*p - '0') + (*(p+1) - '0');
p += 3;
/* second */
if(*p < '0' || *p > '9' || *(p+1) < '0' || *(p+1) > '9' || *(p+2) != ' ') return(worktime);
tm.tm_sec = 10 * (*p - '0') + (*(p+1) - '0');
p += 3;
while(*p && *p == ' ') p++;
if(!*p) return(worktime);
if(*p >= '0' && *p <= '9')
tm.tm_year = atoi(p);
else
if(*p++ != 'G' || *p++ != 'M' || *p++ != 'T')
return(worktime);
if(tm.tm_year == 0)
return(worktime);
if(tm.tm_year > 1900)
tm.tm_year -= 1900;
worktime = mktime(&tm);
gtime = mktime(gmtime(&worktime));
tm2 = localtime(&worktime);
tm2->tm_isdst = 0;
ltime = mktime(tm2);
worktime = worktime - (gtime - ltime);
return(worktime);
}
char *mimetype(url)
char *url;
{
char *p;
struct msufx *ps;
char *dmt;
dmt = (char *) NULL;
p = url;
while(*p) {
if(*p != '.') {
p++;
continue;
}
for(ps = msufx; ps != NULL; ps = ps->snext)
if(!strcmp(ps->suffix, "") && dmt == (char *) NULL)
dmt = ps->mtype->mimetype;
else
if(!strcmp(p, ps->suffix))
return(ps->mtype->mimetype);
p++;
}
if(dmt == (char *) NULL)
dmt = "application/octet-stream";
return(dmt);
}
char *decode64(p)
char *p;
{
static char decode[80];
char c[4];
int i;
int d;
i = 0;
d = 0;
while(*p) {
if(*p >= 'A' && *p <= 'Z') c[i++] = *p++ - 'A'; else
if(*p >= 'a' && *p <= 'z') c[i++] = *p++ - 'a' + 26; else
if(*p >= '0' && *p <= '9') c[i++] = *p++ - '0' + 52; else
if(*p == '+') c[i++] = *p++ - '+' + 62; else
if(*p == '/') c[i++] = *p++ - '/' + 63; else
if(*p == '=') c[i++] = *p++ - '='; else
return("");
if(i < 4) continue;
decode[d++] = ((c[0] << 2) | (c[1] >> 4));
decode[d++] = ((c[1] << 4) | (c[2] >> 2));
decode[d++] = ((c[2] << 6) | c[3]);
decode[d] = '\0';
i = 0;
}
return(decode);
}
int getparms(p, parms, maxparms)
char *p;
char *parms[];
int maxparms;
{
int np;
np = 0;
if(LWS(*p)) {
while(*p && LWS(*p)) p++;
if(!*p) return(0);
parms[np++] = (char *)NULL;
} else
np = 0;
while(np < maxparms && *p) {
parms[np++] = p;
while(*p && !LWS(*p)) p++;
if(*p) *p++ = '\0';
while(*p && LWS(*p)) p++;
}
return(np);
}
int mkurlaccess(p)
char *p;
{
int ua;
ua = 0;
while(*p) {
if(toupper(*p) == 'R') ua |= URLA_READ; else
if(toupper(*p) == 'W') ua |= URLA_WRITE; else
if(toupper(*p) == 'X') ua |= URLA_EXEC; else
if(toupper(*p) == 'H') ua |= URLA_HEADERS; else
return(0);
p++;
}
return(ua);
}

19
commands/httpd/utility.h Normal file
View file

@ -0,0 +1,19 @@
/* utility.h
*
* This file is part of httpd.
*
* 02/17/1996 Michael Temari <Michael@TemWare.Com>
* 07/07/1996 Initial Release Michael Temari <Michael@TemWare.Com>
* 12/29/2002 Michael Temari <Michael@TemWare.Com>
*
*/
#define LWS(c) ((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n'))
_PROTOTYPE(char *logdate, (time_t *t));
_PROTOTYPE(char *httpdate, (time_t *t));
_PROTOTYPE(time_t httptime, (char *p));
_PROTOTYPE(char *mimetype, (char *url));
_PROTOTYPE(char *decode64, (char *p));
_PROTOTYPE(int getparms, (char *p, char *parms[], int maxparms));
_PROTOTYPE(int mkurlaccess, (char *p));