cd ftp && $(MAKE) $@
cd ftpd && $(MAKE) $@
cd ftpd200 && $(MAKE) $@
+ cd httpd && $(MAKE) $@
cd ibm && $(MAKE) $@
cd indent && $(MAKE) $@
cd m4 && $(MAKE) $@
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
--- /dev/null
+# 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
+
+
--- /dev/null
+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)
--- /dev/null
+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.
--- /dev/null
+#!/bin/sh
+make clean
+make && make install
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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;
--- /dev/null
+/* 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 ? ">" : " ");
+ 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);
+}
--- /dev/null
+# 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
--- /dev/null
+/* 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));
--- /dev/null
+.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
--- /dev/null
+.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
+
--- /dev/null
+/* 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);
+}
--- /dev/null
+# 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
--- /dev/null
+.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
--- /dev/null
+# 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
--- /dev/null
+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
\ No newline at end of file
--- /dev/null
+/* 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;
+ }
+ }
+}
--- /dev/null
+/* 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];
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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;
+ }
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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';
+}
--- /dev/null
+/* 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);
+}
--- /dev/null
+/* 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));