]> Zhao Yanbai Git Server - minix.git/commitdiff
Initial revision
authorBen Gras <ben@minix3.org>
Mon, 19 Jun 2006 14:55:09 +0000 (14:55 +0000)
committerBen Gras <ben@minix3.org>
Mon, 19 Jun 2006 14:55:09 +0000 (14:55 +0000)
43 files changed:
commands/ftp101/Makefile [new file with mode: 0644]
commands/ftp101/README [new file with mode: 0644]
commands/ftp101/crc.c [new file with mode: 0644]
commands/ftp101/file.c [new file with mode: 0644]
commands/ftp101/file.h [new file with mode: 0644]
commands/ftp101/ftp.1 [new file with mode: 0644]
commands/ftp101/ftp.c [new file with mode: 0644]
commands/ftp101/ftp.h [new file with mode: 0644]
commands/ftp101/local.c [new file with mode: 0644]
commands/ftp101/local.h [new file with mode: 0644]
commands/ftp101/net.c [new file with mode: 0644]
commands/ftp101/net.h [new file with mode: 0644]
commands/ftp101/other.c [new file with mode: 0644]
commands/ftp101/other.h [new file with mode: 0644]
commands/ftp101/xfer.c [new file with mode: 0644]
commands/ftp101/xfer.h [new file with mode: 0644]
commands/httpd0995/Makefile [new file with mode: 0644]
commands/httpd0995/README [new file with mode: 0644]
commands/httpd0995/SECURITY [new file with mode: 0644]
commands/httpd0995/cgiexec.c [new file with mode: 0644]
commands/httpd0995/config.c [new file with mode: 0644]
commands/httpd0995/config.h [new file with mode: 0644]
commands/httpd0995/dir2html.c [new file with mode: 0644]
commands/httpd0995/dir2html.sh [new file with mode: 0755]
commands/httpd0995/http.h [new file with mode: 0644]
commands/httpd0995/http_status.5 [new file with mode: 0644]
commands/httpd0995/httpd.8 [new file with mode: 0644]
commands/httpd0995/httpd.c [new file with mode: 0644]
commands/httpd0995/httpd.conf [new file with mode: 0644]
commands/httpd0995/httpd.conf.5 [new file with mode: 0644]
commands/httpd0995/httpd.mtype [new file with mode: 0644]
commands/httpd0995/httpd0995.txt [new file with mode: 0644]
commands/httpd0995/net.c [new file with mode: 0644]
commands/httpd0995/net.h [new file with mode: 0644]
commands/httpd0995/pass.c [new file with mode: 0644]
commands/httpd0995/pass.h [new file with mode: 0644]
commands/httpd0995/police.c [new file with mode: 0644]
commands/httpd0995/process.c [new file with mode: 0644]
commands/httpd0995/proxy.c [new file with mode: 0644]
commands/httpd0995/reply.c [new file with mode: 0644]
commands/httpd0995/request.c [new file with mode: 0644]
commands/httpd0995/utility.c [new file with mode: 0644]
commands/httpd0995/utility.h [new file with mode: 0644]

diff --git a/commands/ftp101/Makefile b/commands/ftp101/Makefile
new file mode 100644 (file)
index 0000000..f854352
--- /dev/null
@@ -0,0 +1,42 @@
+# Makefile for ftp
+#
+# 01/25/96 Initial Release     Michael Temari
+# 03/08/00                     Michael Temari, <Michael@TemWare.Com>
+# 02/07/05 v. 1.01             Michael Temari, <Michael@TemWare.Com>
+
+CFLAGS=        -O -D_MINIX -D_POSIX_SOURCE -m
+LDFLAGS=-i
+BINDIR=/usr/bin
+PROG=  ftp
+MANPAGE= /usr/local/man/man1
+
+OBJS=  ftp.o local.o file.o xfer.o other.o net.o crc.o
+
+all:   $(PROG)
+
+$(PROG):       $(OBJS)
+       $(CC) $(LDFLAGS) -o $@ $(OBJS)
+       install -S 8kw $@
+
+clean:
+       rm -f $(PROG) $(OBJS)
+
+install:       $(BINDIR)/$(PROG)
+
+$(BINDIR)/$(PROG):     $(PROG)
+       install -cs -o bin $? $@
+
+installman:    $(MANPAGE)
+
+       cp ftp.1 /usr/local/man/man1
+       makewhatis /usr/local/man
+
+crc.o:         crc.c
+       $(CC) -c $(CFLAGS) -DCRC_ONLY $?
+
+ftp.o:         ftp.c   ftp.h   local.h file.h  other.h net.h
+local.o:       local.c ftp.h   local.h
+file.o:                file.c  ftp.h           file.h          net.h
+other.o:       other.c ftp.h                   other.h
+net.o:         net.c   ftp.h                   xfer.h  net.h
+xfer.o:                xfer.c  ftp.h                   xfer.h
diff --git a/commands/ftp101/README b/commands/ftp101/README
new file mode 100644 (file)
index 0000000..a600177
--- /dev/null
@@ -0,0 +1,39 @@
+ftp101 --- An FTP client program  for Minix 2.0 
+written by Michael Temari <Michael@TemWare.Com> release 1.01a 2006-06-07
+
+Full download: <a href="/pub/contrib/ftp101.tar.Z">ftp101.tar.Z</a>
+
+FTP is the File Transfer Protocol client that allows you to connect to
+a remote FTP server. 
+
+This version should work equally well with Minix 2 and Minix 3.
+
+Release 1.01a 2006-06-07: minor documentation edits
+Release 1.01  2005-02-07: minor bug fix 
+Release 1.00  2003-12-14: added "ver" command to display current version 
+                          and an ftp(1) man page.
+
+Installation: unpack the tarball, it will create an ftp101 directory. Although
+this is a replacement for the ftp client provided in the Minix 2.0.0 and later
+distributions, it is suggested you unpack and compile in the /usr/local/src
+directory.
+
+zcat < ftp101.tar.Z | tar xvfp -
+
+Invoking make -n will show you what the Makefile will do.
+
+make (or make ftp) compiles a new ftp binary, leaving it in the source
+directory.
+
+make install compiles the binary and installs it in /usr/bin.
+
+make installman installs the man page in /usr/local/man/man1. The
+directory must exist. 
+
+Note: there is a bug in the version of the ftp client distributed with
+Minix 2.0.2 and 2.0.3 that causes a \r (0xd) character to be appended
+to file names in the destination directory when files are downloaded in
+binary mode using the mget command. The bug was corrected in a release 
+prior to 1.00.  
+
+Notes by ASW revised 2006-06-07
diff --git a/commands/ftp101/crc.c b/commands/ftp101/crc.c
new file mode 100644 (file)
index 0000000..b6974cc
--- /dev/null
@@ -0,0 +1,132 @@
+/* Compute checksum                    Author: Johan W. Stevenson */
+
+/* Copyright 1988 by Johan W. Stevenson */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#if !CRC_ONLY
+
+int errs;
+
+#if __STDC__
+int main(int argc, char **argv);
+void crc(char *fname);
+#else
+void crc();
+#endif
+
+int main(argc, argv)
+int argc;
+char **argv;
+{
+  char line[256];
+
+  if (argc <= 1)
+       crc((char *) 0);
+  else if (argc == 2 && strcmp(argv[1], "-") == 0)
+       while (fgets(line, sizeof line, stdin) != NULL) {
+               if (line[strlen(line) - 1] == '\n')
+                       line[strlen(line) - 1] = '\0';
+               crc(line);
+       }
+  else
+       do {
+               crc(argv[1]);
+               argv++;
+               argc--;
+       } while (argc > 1);
+  return(errs != 0);
+}
+
+#endif
+/* Crctab calculated by Mark G. Mendel, Network Systems Corporation */
+static unsigned short crctab[256] = {
+       0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
+       0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
+       0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
+       0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
+       0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
+       0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
+       0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
+       0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
+       0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
+       0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
+       0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
+       0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
+       0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
+       0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
+       0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
+       0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
+       0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
+       0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
+       0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
+       0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
+       0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
+       0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
+       0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
+       0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
+       0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
+       0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
+       0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
+       0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
+       0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
+       0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
+       0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
+        0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
+};
+
+/* Updcrc macro derived from article Copyright (C) 1986 Stephen Satchell.
+ *  NOTE: First argument must be in range 0 to 255.
+ *        Second argument is referenced twice.
+ *
+ * Programmers may incorporate any or all code into their programs,
+ * giving proper credit within the source. Publication of the
+ * source routines is permitted so long as proper credit is given
+ * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg,
+ * Omen Technology.
+ */
+
+#define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp)
+
+#if CRC_ONLY
+unsigned short crc(char *fname)
+#else
+void crc(fname)
+char *fname;
+#endif
+{
+  register int c;
+  register long len = 0;
+  register unsigned short crc = 0;
+  register FILE *fp;
+
+#if CRC_ONLY
+   if((fp = fopen(fname, "r")) == NULL)
+       return 0;
+#else
+  if (fname == NULL)
+       fp = stdin;
+  else if ((fp = fopen(fname, "r")) == NULL) {
+       fprintf(stderr, "crc: cannot open %s\n", fname);
+       errs++;
+       return;
+  }
+#endif
+  while ((c = getc(fp)) != EOF) {
+       len++;
+       crc = updcrc(c, crc);
+  }
+#if CRC_ONLY
+  fclose(fp);
+  return crc;
+#else
+  printf("%05u %6ld", crc, len);
+  if (fname) {
+       printf(" %s", fname);
+       fclose(fp);
+  }
+  printf("\n");
+#endif
+}
diff --git a/commands/ftp101/file.c b/commands/ftp101/file.c
new file mode 100644 (file)
index 0000000..9fd2828
--- /dev/null
@@ -0,0 +1,934 @@
+/* file.c Copyright 1992-2000 by Michael Temari All Rights Reserved
+ *
+ * This file is part of ftp.
+ *
+ *
+ * 01/25/96 Initial Release    Michael Temari, <Michael@TemWare.Com>
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <time.h>
+#include <utime.h>
+#include <net/hton.h>
+
+#include "ftp.h"
+#include "file.h"
+#include "net.h"
+
+_PROTOTYPE(static char *dir, (char *path, int full));
+_PROTOTYPE(static int asciisize, (int fd, off_t *filesize));
+_PROTOTYPE(static off_t asciisetsize, (int fd, off_t filesize));
+_PROTOTYPE(static int cloneit, (char *file, int mode));
+
+#if (__WORD_SIZE == 4)
+static char buffer[8192];
+#else
+static char buffer[2048];
+#endif
+static char line2[512];
+
+static char *dir(path, full)
+char *path;
+int full;
+{
+char cmd[128];
+static char name[32];
+
+   tmpnam(name);
+
+   if(full)
+       sprintf(cmd, "ls -l %s > %s", path, name);
+   else
+       sprintf(cmd, "ls -dA %s > %s", path, name);
+
+   system(cmd);
+
+   return(name);
+}
+
+int DOascii()
+{
+int s;
+
+   if(DOcmdcheck())
+       return(0);
+
+   s = DOcommand("TYPE", "A");
+
+   type = TYPE_A;
+
+   return(s);
+}
+
+int DObinary()
+{
+int s;
+
+   if(DOcmdcheck())
+       return(0);
+
+   s = DOcommand("TYPE", "I");
+
+   type = TYPE_I;
+
+   return(s);
+}
+
+int DOblock()
+{
+int s;
+
+   if(DOcmdcheck())
+       return(0);
+
+   s = DOcommand("MODE", "B");
+
+   mode = MODE_B;
+
+   return(s);
+}
+
+int DOstream()
+{
+int s;
+
+   if(DOcmdcheck())
+       return(0);
+
+   s = DOcommand("MODE", "S");
+
+   mode = MODE_S;
+
+   return(s);
+}
+
+int DOpwd()
+{
+int s;
+
+   if(DOcmdcheck())
+       return(0);
+
+   s = DOcommand("PWD", "");
+
+   if(s == 500 || s == 502)
+       s = DOcommand("XPWD", "");
+
+   return(s);
+}
+
+int DOcd()
+{
+char *path;
+int s;
+
+   if(DOcmdcheck())
+       return(0);
+
+   path = cmdargv[1];
+
+   if(cmdargc < 2) {
+       if(readline("Path: ", line2, sizeof(line2)) < 0)
+               return(-1);
+       path = line2;
+   }
+
+   if(!strcmp(path, ".."))
+       s = DOcommand("CDUP", "");
+   else
+       s = DOcommand("CWD", path);
+
+   if(s == 500 || s == 502) {
+       if(!strcmp(path, ".."))
+               s = DOcommand("XCUP", "");
+       else
+               s = DOcommand("XCWD", path);
+   }
+
+   return(s);
+}
+
+int DOmkdir()
+{
+char *path;
+int s;
+
+   if(DOcmdcheck())
+       return(0);
+
+   path = cmdargv[1];
+
+   if(cmdargc < 2) {
+       if(readline("Directory: ", line2, sizeof(line2)) < 0)
+               return(-1);
+       path = line2;
+   }
+
+   s = DOcommand("MKD", path);
+
+   if(s == 500 || s == 502)
+       s = DOcommand("XMKD", path);
+
+   return(s);
+}
+
+int DOrmdir()
+{
+char *path;
+int s;
+
+   if(DOcmdcheck())
+       return(0);
+
+   path = cmdargv[1];
+
+   if(cmdargc < 2) {
+       if(readline("Directory: ", line2, sizeof(line2)) < 0)
+               return(-1);
+       path = line2;
+   }
+
+   s = DOcommand("RMD", path);
+
+   if(s == 500 || s == 502)
+       s = DOcommand("XRMD", path);
+
+   return(s);
+}
+
+int DOdelete()
+{
+char *file;
+
+   if(DOcmdcheck())
+       return(0);
+
+   file = cmdargv[1];
+
+   if(cmdargc < 2) {
+       if(readline("File: ", line2, sizeof(line2)) < 0)
+               return(-1);
+       file = line2;
+   }
+
+   return(DOcommand("DELE", file));
+}
+
+int DOmdtm()
+{
+char *file;
+
+   if(DOcmdcheck())
+       return(0);
+
+   file = cmdargv[1];
+
+   if(cmdargc < 2) {
+       if(readline("File: ", line2, sizeof(line2)) < 0)
+               return(-1);
+       file = line2;
+   }
+
+   return(DOcommand("MDTM", file));
+}
+
+int DOsize()
+{
+char *file;
+
+   if(DOcmdcheck())
+       return(0);
+
+   file = cmdargv[1];
+
+   if(cmdargc < 2) {
+       if(readline("File: ", line2, sizeof(line2)) < 0)
+               return(-1);
+       file = line2;
+   }
+
+   return(DOcommand("SIZE", file));
+}
+
+int DOstat()
+{
+char *file;
+
+   if(cmdargc < 2)
+       if(!linkopen) {
+               printf("You must \"OPEN\" a connection first.\n");
+               return(0);
+       } else
+               return(DOcommand("STAT", ""));
+
+   if(DOcmdcheck())
+       return(0);
+
+   file = cmdargv[1];
+
+   if(cmdargc < 2) {
+       if(readline("File: ", line2, sizeof(line2)) < 0)
+               return(-1);
+       file = line2;
+   }
+
+   return(DOcommand("STAT", file));
+}
+
+int DOlist()
+{
+char *path;
+char *local;
+int fd;
+int s;
+
+   if(DOcmdcheck())
+       return(0);
+
+   path = cmdargv[1];
+
+   if(cmdargc < 2)
+       path = "";
+
+   if(cmdargc < 3)
+       local = "";
+   else
+       local = cmdargv[2];
+
+   if(*local == '\0')
+       fd = 1;
+   else
+       fd = open(local, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+
+   if(fd < 0) {
+       printf("Could not open local file %s. Error %s\n", local, strerror(errno));
+       return(0);
+   }
+
+   s = DOdata("LIST", path, RETR, fd);
+
+   if(fd > 2)
+       close(fd);
+
+   return(s);
+}
+
+int DOnlst()
+{
+char *path;
+char *local;
+int fd;
+int s;
+
+   if(DOcmdcheck())
+       return(0);
+
+   path = cmdargv[1];
+
+   if(cmdargc < 2)
+       path = "";
+
+   if(cmdargc < 3)
+       local = "";
+   else
+       local = cmdargv[2];
+
+   if(*local == '\0')
+       fd = 1;
+   else
+       fd = open(local, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+
+   if(fd < 0) {
+       printf("Could not open local file %s. Error %s\n", local, strerror(errno));
+       return(0);
+   }
+
+   s = DOdata("NLST", path, RETR, fd);
+
+   if(fd > 2)
+       close(fd);
+
+   return(s);
+}
+
+int DOretr()
+{
+char *file, *localfile;
+int fd;
+int s;
+
+   if(DOcmdcheck())
+       return(0);
+
+   file = cmdargv[1];
+
+   if(cmdargc < 2) {
+       if(readline("Remote File: ", line2, sizeof(line2)) < 0)
+               return(-1);
+       file = line2;
+   }
+
+   if(cmdargc < 3)
+       localfile = file;
+   else
+       localfile = cmdargv[2];
+
+   fd = open(localfile, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+
+   if(fd < 0) {
+       printf("Could not open local file %s. Error %s\n", localfile, strerror(errno));
+       return(0);
+   }
+
+   s = DOdata("RETR", file, RETR, fd);
+
+   close(fd);
+
+   return(s);
+}
+
+int DOrretr()
+{
+char *file, *localfile;
+int fd;
+int s;
+off_t filesize;
+char restart[16];
+
+   if(DOcmdcheck())
+       return(0);
+
+   file = cmdargv[1];
+
+   if(cmdargc < 2) {
+       if(readline("Remote File: ", line2, sizeof(line2)) < 0)
+               return(-1);
+       file = line2;
+   }
+
+   if(cmdargc < 3)
+       localfile = file;
+   else
+       localfile = cmdargv[2];
+
+   fd = open(localfile, O_RDWR);
+
+   if(fd < 0) {
+       printf("Could not open local file %s. Error %s\n", localfile, strerror(errno));
+       return(0);
+   }
+
+   if(type == TYPE_A) {
+       if(asciisize(fd, &filesize)) {
+               printf("Could not determine ascii file size of %s\n", localfile);
+               close(fd);
+               return(0);
+       }
+   } else
+       filesize = lseek(fd, 0, SEEK_END);
+
+   sprintf(restart, "%lu", filesize);
+
+   s = DOcommand("REST", restart);
+
+   if(s != 350) {
+       close(fd);
+       return(s);
+   }
+
+   s = DOdata("RETR", file, RETR, fd);
+
+   close(fd);
+
+   return(s);
+}
+
+char *ttime(time_t t)
+{
+struct tm *tm;
+static char tbuf[16];
+
+   tm = localtime(&t);
+
+   sprintf(tbuf, "%04d%02d%02d%02d%02d.%02d",
+       tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday,
+       tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+   return(tbuf);
+}
+
+static int cloneit(file, mode)
+char *file;
+int mode;
+{
+int opr;
+int s;
+int ss;
+struct stat st;
+static unsigned short lcrc;
+static unsigned short ccrc;
+static unsigned long csize;
+static char ft;
+static unsigned long maj;
+static unsigned long min;
+static unsigned long uid;
+static unsigned long gid;
+static unsigned long fmode;
+static unsigned long size;
+static unsigned long mtime;
+struct utimbuf ut;
+unsigned short crc(char *fname);
+
+   if(mode == 1) {
+       /* see if file exists locally */
+       ss = stat(file, &st);
+
+       opr = printreply;
+       printreply = 0;
+       s = DOcommand("SITE FDET", file);
+       printreply = opr;
+
+       if((s / 100) != 2)
+               return(-1);
+
+       sscanf(reply, "%*d %c%lu%lu%lu%lu%lu%lu%lu",
+               &ft, &maj, &min, &uid, &gid, &fmode, &size, &mtime);
+
+       if(ft == 'f') {
+               opr = printreply;
+               printreply = 0;
+               s = DOcommand("SITE CCRC", file);
+               printreply = opr;
+               if((s / 100) != 2)
+                       return(-1);
+
+               sscanf(reply, "%*d %*s%u%lu", &ccrc, &csize);
+               if(ss < 0) return(-1);
+               lcrc = crc(file);
+               if(size != csize || size != st.st_size || ccrc != lcrc)
+                       return(-1);
+       } else
+       if(ss < 0 && ft == 'd') {
+               s = mkdir(file, fmode);
+               printf("mkdir %s\n", file);
+       } else
+       if((ss < 0) && (ft == 'b' || ft == 'c' || ft == 'p')) {
+               s = mknod(file, fmode, maj << 8 | min);
+               printf("mknod %c %u %u\n", file, maj, min);
+       } else
+               return(0);
+   }
+   ss = stat(file, &st);
+   if(ss < 0)
+       return(-1);
+   if(st.st_uid != uid || st.st_gid != gid) {
+       s = chown(file, uid, gid);
+       printf("chown %u:%u %s\n", uid, gid, file);
+   }
+   if(st.st_mode != fmode) {
+       s = chmod(file, fmode);
+       printf("chmod %04o %s\n", fmode, file);
+   }
+   if(st.st_mtime != mtime) {
+       ut.actime = mtime;
+       ut.modtime = mtime;
+       s = utime(file, &ut);
+       printf("touch -m -t %s %s\n", ttime(mtime), file);
+   }
+
+   return(0);
+}
+
+int DOMretr()
+{
+char *files;
+int fd, s;
+char *p;
+FILE *fp;
+char name[32];
+
+   if(DOcmdcheck())
+       return(0);
+
+   files = cmdargv[1];
+
+   if(cmdargc < 2) {
+       if(readline("Files: ", line2, sizeof(line2)) < 0)
+               return(-1);
+       files = line2;
+   }
+
+   tmpnam(name);
+
+   fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+
+   if(fd < 0) {
+       printf("Could not open local file %s. Error %s\n", name, strerror(errno));
+       return(0);
+   }
+
+   s = DOdata("NLST", files, RETR, fd);
+
+   close(fd);
+
+   if(s == 226 || s == 250) {
+       fp = fopen(name, "r");
+       unlink(name);
+       if(fp == (FILE *)NULL) {
+               printf("Unable to open file listing.\n");
+               return(0);
+       }
+       while(fgets(line2, sizeof(line2), fp) != (char *)NULL) {
+               p = line2 + strlen(line2) - 1;
+               if(p >= line2 && (*p == '\r' || *p == '\n')) *p-- = '\0';
+               if(p >= line2 && (*p == '\r' || *p == '\n')) *p-- = '\0';
+               printf("Retrieving file: %s\n", line2); fflush(stdout);
+               fd = open(line2, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+               if(fd < 0)
+                       printf("Unable to open local file %s\n", line2);
+               else {
+                       s = DOdata("RETR", line2, RETR, fd);
+                       close(fd);
+                       if(s < 0) break;
+               }
+       }
+       fclose(fp);
+   } else
+       unlink(name);
+
+   return(s);
+}
+
+int DOappe()
+{
+char *file, *remotefile;
+int fd;
+int s;
+
+   if(DOcmdcheck())
+       return(0);
+
+   file = cmdargv[1];
+
+   if(cmdargc < 2) {
+       if(readline("Local File: ", line2, sizeof(line2)) < 0)
+               return(-1);
+       file = line2;
+   }
+
+   if(cmdargc < 3)
+       remotefile = file;
+   else
+       remotefile = cmdargv[2];
+
+   fd = open(file, O_RDONLY);
+
+   if(fd < 0) {
+       printf("Could not open local file %s. Error %s\n", file, strerror(errno));
+       return(0);
+   }
+
+   s = DOdata("APPE", remotefile, STOR, fd);
+
+   close(fd);
+
+   return(s);
+}
+
+int DOstor()
+{
+char *file, *remotefile;
+int fd;
+int s;
+
+   if(DOcmdcheck())
+       return(0);
+
+   file = cmdargv[1];
+
+   if(cmdargc < 2) {
+       if(readline("Local File: ", line2, sizeof(line2)) < 0)
+               return(-1);
+       file = line2;
+   }
+
+   if(cmdargc < 3)
+       remotefile = file;
+   else
+       remotefile = cmdargv[2];
+
+   fd = open(file, O_RDONLY);
+
+   if(fd < 0) {
+       printf("Could not open local file %s. Error %s\n", file, strerror(errno));
+       return(0);
+   }
+
+   s = DOdata("STOR", remotefile, STOR, fd);
+
+   close(fd);
+
+   return(s);
+}
+
+int DOrstor()
+{
+char *file, *remotefile;
+int fd;
+int s;
+off_t filesize, rmtsize;
+char restart[16];
+
+   if(DOcmdcheck())
+       return(0);
+
+   file = cmdargv[1];
+
+   if(cmdargc < 2) {
+       if(readline("Local File: ", line2, sizeof(line2)) < 0)
+               return(-1);
+       file = line2;
+   }
+
+   if(cmdargc < 3)
+       remotefile = file;
+   else
+       remotefile = cmdargv[2];
+
+   s = DOcommand("SIZE", remotefile);
+
+   if(s != 215)
+       return(s);
+
+   rmtsize = atol(reply+4);
+
+   fd = open(file, O_RDONLY);
+
+   if(fd < 0) {
+       printf("Could not open local file %s. Error %s\n", file, strerror(errno));
+       return(0);
+   }
+
+   if(type == TYPE_A)
+       filesize = asciisetsize(fd, rmtsize);
+   else
+       filesize = lseek(fd, rmtsize, SEEK_SET);
+
+   if(filesize != rmtsize) {
+       printf("Could not set file start of %s\n", file);
+       close(fd);
+       return(0);
+   }
+
+   sprintf(restart, "%lu", rmtsize);
+
+   s = DOcommand("REST", restart);
+
+   if(s != 350) {
+       close(fd);
+       return(s);
+   }
+
+   s = DOdata("STOR", remotefile, STOR, fd);
+
+   close(fd);
+
+   return(s);
+}
+
+int DOstou()
+{
+char *file, *remotefile;
+int fd;
+int s;
+
+   if(DOcmdcheck())
+       return(0);
+
+   file = cmdargv[1];
+
+   if(cmdargc < 2) {
+       if(readline("Local File: ", line2, sizeof(line2)) < 0)
+               return(-1);
+       file = line2;
+   }
+
+   if(cmdargc < 3)
+       remotefile = file;
+   else
+       remotefile = cmdargv[2];
+
+   fd = open(file, O_RDONLY);
+
+   if(fd < 0) {
+       printf("Could not open local file %s. Error %s\n", file, strerror(errno));
+       return(0);
+   }
+
+   s = DOdata("STOU", remotefile, STOR, fd);
+
+   close(fd);
+
+   return(s);
+}
+
+int DOMstor()
+{
+char *files;
+char *name;
+char *p;
+int fd, s;
+FILE *fp;
+
+   if(DOcmdcheck())
+       return(0);
+
+   files = cmdargv[1];
+
+   if(cmdargc < 2) {
+       if(readline("Files: ", line2, sizeof(line2)) < 0)
+               return(-1);
+       files = line2;
+   }
+
+   name = dir(files, 0);
+
+   fp = fopen(name, "r");
+
+   if(fp == (FILE *)NULL) {
+       printf("Unable to open listing file.\n");
+       return(0);
+   }
+
+   while(fgets(line2, sizeof(line2), fp) != (char *)NULL) {
+       p = line2 + strlen(line2) - 1;
+       if(p >= line2 && (*p == '\r' || *p == '\n')) *p-- = '\0';
+       if(p >= line2 && (*p == '\r' || *p == '\n')) *p-- = '\0';
+       printf("Sending file: %s\n", line2); fflush(stdout);
+       fd = open(line2, O_RDONLY);
+       if(fd < 0)
+               printf("Unable to open local file %s\n", line2);
+       else {
+               s = DOdata("STOR", line2, STOR, fd);
+               close(fd);
+               if(s < 0) break;
+       }
+   }
+   fclose(fp);
+   unlink(name);
+
+   return(s);
+}
+
+static int asciisize(fd, filesize)
+int fd;
+off_t *filesize;
+{
+unsigned long count;
+char *p, *pp;
+int cnt;
+
+   count = 0;
+
+   while((cnt = read(fd, buffer, sizeof(buffer))) > 0) {
+       p = buffer; pp = buffer + cnt;
+       count += cnt;
+       while(p < pp)
+               if(*p++ == '\n')
+                       count++;
+   }
+
+   if(cnt == 0) {
+       *filesize = count;
+       return(0);
+   }
+
+   return(-1);
+}
+
+static off_t asciisetsize(fd, filesize)
+int fd;
+off_t filesize;
+{
+off_t sp;
+int s;
+
+   sp = 0;
+
+   while(sp < filesize) {
+       s = read(fd, buffer, 1);
+       if(s < 0)
+               return(-1);
+       if(s == 0) break;
+       sp++;
+       if(*buffer == '\n')
+               sp++;
+   }
+
+   return(sp);
+}
+
+int DOclone()
+{
+char *files;
+int fd, s;
+char *p;
+FILE *fp;
+char name[32];
+
+   if(DOcmdcheck())
+       return(0);
+
+   files = cmdargv[1];
+
+   tmpnam(name);
+
+   fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+
+   if(fd < 0) {
+       printf("Could not open local file %s. Error %s\n", name, strerror(errno));
+       return(0);
+   }
+
+   s = DOdata("NLST", files, RETR, fd);
+
+   close(fd);
+
+   if(s == 226 || s == 250) {
+       fp = fopen(name, "r");
+       unlink(name);
+       if(fp == (FILE *)NULL) {
+               printf("Unable to open file listing.\n");
+               return(0);
+       }
+       while(fgets(line2, sizeof(line2), fp) != (char *)NULL) {
+               p = line2 + strlen(line2) - 1;
+               if(p >= line2 && (*p == '\r' || *p == '\n')) *p-- = '\0';
+               if(p >= line2 && (*p == '\r' || *p == '\n')) *p-- = '\0';
+               cmdargv[1] = line2;
+               if(cloneit(line2, 1)) {
+                       printf("Retrieving file: %s\n", line2); fflush(stdout);
+                       fd = open(line2, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+                       if(fd < 0)
+                               printf("Unable to open local file %s\n", line2);
+                       else {
+                               s = DOdata("RETR", line2, RETR, fd);
+                               close(fd);
+                               if(s < 0) break;
+                       }
+                       s = cloneit(line2, 2);
+               }
+       }
+       fclose(fp);
+   } else
+       unlink(name);
+
+   return(s);
+}
diff --git a/commands/ftp101/file.h b/commands/ftp101/file.h
new file mode 100644 (file)
index 0000000..13b4621
--- /dev/null
@@ -0,0 +1,33 @@
+/* file.h Copyright 1992-2000 by Michael Temari All Rights Reserved
+ *
+ * This file is part of ftp.
+ *
+ *
+ * 01/25/96 Initial Release    Michael Temari, <Michael@TemWare.Com>
+ */
+
+_PROTOTYPE(int recvfile, (int fd, int fdin));
+_PROTOTYPE(int sendfile, (int fd, int fdout));
+_PROTOTYPE(int DOascii, (void));
+_PROTOTYPE(int DObinary, (void));
+_PROTOTYPE(int DOblock, (void));
+_PROTOTYPE(int DOstream, (void));
+_PROTOTYPE(int DOpwd, (void));
+_PROTOTYPE(int DOcd, (void));
+_PROTOTYPE(int DOmkdir, (void));
+_PROTOTYPE(int DOrmdir, (void));
+_PROTOTYPE(int DOdelete, (void));
+_PROTOTYPE(int DOmdtm, (void));
+_PROTOTYPE(int DOsize, (void));
+_PROTOTYPE(int DOstat, (void));
+_PROTOTYPE(int DOlist, (void));
+_PROTOTYPE(int DOnlst, (void));
+_PROTOTYPE(int DOretr, (void));
+_PROTOTYPE(int DOrretr, (void));
+_PROTOTYPE(int DOMretr, (void));
+_PROTOTYPE(int DOappe, (void));
+_PROTOTYPE(int DOstor, (void));
+_PROTOTYPE(int DOrstor, (void));
+_PROTOTYPE(int DOstou, (void));
+_PROTOTYPE(int DOMstor, (void));
+_PROTOTYPE(int DOclone, (void));
diff --git a/commands/ftp101/ftp.1 b/commands/ftp101/ftp.1
new file mode 100644 (file)
index 0000000..078b6a8
--- /dev/null
@@ -0,0 +1,148 @@
+.TH FTP 1
+.SH NAME
+ftp \- a File Transfer Protocol client for Minix
+.SH SYNOPSIS
+.B ftp
+.RI [ server_name ]
+.SH DESCRIPTION
+.B Ftp
+is a File Transfer Protocol client for Minix written by Michael Temari.  
+.P
+There are no command line options for 
+.B ftp
+except for the optional server name, which may be either a numeric IP address 
+or a domain name resolvable by DNS.
+.P
+If a server name is specified a connection attempt will be made, and you 
+will be prompted for a user name and password by the remote system. 
+Following the login (or immediately, if no server name was specified), the
+.br
+.B ftp>
+.br 
+prompt is displayed. The following commands are accepted at the prompt:
+.P
+Command:      Description
+.br
+!             Escape to a shell
+.br
+append        Append a file to remote host
+.br
+ascii         Set file transfer type to ascii
+.br
+binary        Set file transfer type to binary
+.br
+block         Set file transfer mode to block
+.br
+bye           Close connection and exit
+.br
+cd            Change directory on remote host
+.br
+close         Close connection
+.br
+clone         Clone a file
+.br
+del           Remove file on remote host
+.br
+dir           Display long form remote host directory listing
+.br
+exit          Close connection and exit
+.br
+get           Retrieve a file from remote host
+.br
+help          Display this text
+.br
+lcd           Change directory on local host
+.br
+ldir          Display long form local host directory listing
+.br
+lls           Display local host directory listing
+.br
+lmkdir        Create directory on local host
+.br
+lpwd          Display current directory on local host
+.br
+lrmdir        Remove directory on local host
+.br
+ls            Display remote host directory listing
+.br
+mget          Retrieve multiple files from remote host
+.br
+mkdir         Create directory on remote host
+.br
+mod           Get file modification time
+.br
+mput          Send multiple files to remote host
+.br
+noop          Send the ftp NOOP command
+.br
+open          Open connection to remote host
+.br
+pass          Enter remote user password
+.br
+passive       Toggle passive mode
+.br
+put           Send a file to remote host
+.br
+putu          Send a file to remote host(unique)
+.br
+pwd           Display current directory on remote host
+.br
+quit          Close connection and exit
+.br
+quote         Send raw ftp command to remote host
+.br
+reget         Restart a partial file retrieve from remote host
+.br
+remotehelp    Display ftp commands implemented on remote host
+.br
+reput         Restart a partial file send to remote host
+.br
+rm            Remove file on remote host
+.br
+rmdir         Remove directory on remote host
+.br
+site          Send a site specific command
+.br
+size          Get file size information
+.br
+status        Get connection/file status information
+.br
+stream        Set file transfer mode to stream
+.br
+system        Get remote system type information
+.br
+user          Enter remote user information
+.br
+ver           Display client version information
+
+.SH "SEE ALSO"
+.BR ftpd (8),
+.BR ftpget (1).
+.SH NOTES
+The FTP protocol passes unencrypted usernames and passwords to clients,
+so they are potentially exposed to evildoers with network sniffers. So be 
+wary of using this to exchange files between your own accounts. Obviously 
+if you have a root account on another system and the remote system will 
+accept a login as root this is extremely dangerous. (Many ftp servers will
+not allow a connection by root).
+.P
+Text-mode (ASCII) transfers are the default mode, be sure to enter the 
+"binary" command if you are downloading a program file or a compressed 
+archive, in fact anything other than a text file from a machine with a
+different text-file format than Minix uses.
+.P
+If you are behind a firewall you probably need to use passive mode to 
+successfully transfer files.
+.SH BUGS
+None are known, but there may be some unknown ones. Version 1.00 corrects
+a bug in previous versions that would append a \\r (0xd) character to file
+names on the destination when an mget transfer was used in binary mode.
+
+.SH AUTHOR
+The Minix httpd server was created by and is maintained by Michael Temari
+<Michael@TemWare.Com>. The earliest version was released in 1992, for use
+with Michael's TNet networking extensions for Minix 1.5. 
+.P
+Man page compiled by Al Woodhull <asw@woodhull.com>
+.\" updated 2006-06-18
diff --git a/commands/ftp101/ftp.c b/commands/ftp101/ftp.c
new file mode 100644 (file)
index 0000000..20c1661
--- /dev/null
@@ -0,0 +1,404 @@
+/* ftp.c Copyright 1992-2000 by Michael Temari All Rights Reserved
+ *
+ * ftp          An ftp client program for use with TNET.
+ *
+ * Usage:       ftp [host]
+ *
+ * Version:     0.10    06/21/92 (pre-release not yet completed)
+ *              0.20    07/01/92
+ *              0.30    01/15/96 (Minix 1.7.1 initial release)
+ *              0.40    08/27/96
+ *              0.50    03/08/00
+ *              1.00    12/12/03 (added ver command)
+ *              1.01    02/07/05
+ *
+ * Author:      Michael Temari, <Michael@TemWare.Com>
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ftp.h"
+#include "local.h"
+#include "file.h"
+#include "other.h"
+#include "net.h"
+
+char *FtpVersion = "1.01 02/07/05";
+
+int linkopen;
+int loggedin;
+int type;
+int format;
+int mode;
+int structure;
+int passive;
+int atty;
+
+int cmdargc;
+char *cmdargv[NUMARGS];
+
+int printreply = 1;
+char reply[1024];
+
+_PROTOTYPE(static void makeargs, (char *buff));
+_PROTOTYPE(int DOver,  (void));
+_PROTOTYPE(int DOhelp, (void));
+_PROTOTYPE(static int getline, (char *line, int len));
+_PROTOTYPE(int main, (int argc, char *argv[]));
+
+
+static void makeargs(buff)
+char *buff;
+{
+int i;
+char *p;
+
+   for(i = 0; i < NUMARGS; i++)
+       cmdargv[i] = (char *)0;
+
+   p = buff + strlen(buff) - 1;
+   while(p >= buff)
+       if(*p == '\r' || *p == '\n' || isspace(*p))
+               *p-- = '\0';
+       else
+               break;
+
+   p = buff;
+   cmdargc = 0;
+   while(cmdargc < NUMARGS) {
+       while(*p && isspace(*p))
+               p++;
+       if(*p == '\0')
+               break;
+       cmdargv[cmdargc++] = p;
+       while(*p && !isspace(*p)) {
+               if(cmdargc == 1)
+                       *p = tolower(*p);
+               p++;
+       }
+       if(*p == '\0')
+               break;
+       *p = '\0';
+       p++;
+   }
+}
+
+int readline(prompt, buff, len)
+char *prompt;
+char *buff;
+int len;
+{
+char *p;
+
+   printf(prompt); fflush(stdout);
+
+   if(fgets(buff, len, stdin) == (char *)NULL) {
+       printf("\nEnd of file on input!\n");
+       return(-1);
+   }
+
+   p = buff + strlen(buff) - 1;
+   while(p >= buff)
+       if(*p == '\r' || *p == '\n' || isspace(*p))
+               *p-- = '\0';
+       else
+               break;
+
+   if(!atty) {
+       printf("%s\n", buff);
+       fflush(stdout);
+   }
+
+   return(0);
+}
+
+static int getline(line, len)
+char *line;
+int len;
+{
+int s;
+int gotcr;
+
+   /* leave room for at end for null */
+   len--;
+
+   /* got to be able to put in at least 1 character */
+   if(len < 1)
+       return(-1);
+
+   gotcr = 0;
+   while(len-- > 0) {
+       s = read(ftpcomm_fd, line, 1);
+       if(s != 1)
+               return(-1);
+       if(*line == '\n')
+               break;
+       gotcr = (*line == '\r');
+       line++;
+   }
+   if(gotcr)
+       --line;
+
+   *line = '\0';
+
+   return(0);
+}
+
+int DOgetreply()
+{
+int firsttime;
+int s;
+char code[4];
+
+   do {
+       firsttime = 1;
+       do {
+               if((s = getline(reply, sizeof(reply))) < 0)
+                       return(s);
+               if(printreply) {
+                       printf("%s\n", reply);
+                       fflush(stdout);
+               }
+               if(firsttime) {
+                       firsttime = 0;
+                       strncpy(code, reply, 3);
+                       code[3] = '\0';
+               }
+          } while(strncmp(reply, code, 3) || reply[3] == '-');
+          s = atoi(code);
+   } while(s < 200 && s != 125 && s != 150);
+
+   return(s);
+}
+
+int DOcmdcheck()
+{
+   if(!linkopen) {
+       printf("You must \"OPEN\" a connection first.\n");
+       return(1);
+   }
+
+   if(!loggedin) {
+       printf("You must login first.\n");
+       return(1);
+   }
+
+   return(0);
+}
+
+int DOcommand(ftpcommand, ftparg)
+char *ftpcommand;
+char *ftparg;
+{
+int s;
+#if 1
+static char ss[64];
+   if(*ftparg)
+       sprintf(ss, "%s %s\r\n", ftpcommand, ftparg);
+   else
+       sprintf(ss, "%s\r\n", ftpcommand);
+
+   s = write(ftpcomm_fd, ss, strlen(ss));
+   if(s != strlen(ss))
+       return(-1);
+
+#else
+   s = write(ftpcomm_fd, ftpcommand, strlen(ftpcommand));
+   if(s != strlen(ftpcommand))
+       return(-1);
+
+   if(*ftparg) {
+       s = write(ftpcomm_fd, " ", 1);
+       if(s != 1)
+               return(-1);
+
+       s = write(ftpcomm_fd, ftparg, strlen(ftparg));
+       if(s != strlen(ftparg))
+               return(-1);
+   }
+
+   s = write(ftpcomm_fd, "\r\n", 2);
+   if(s != 2)
+       return(-1);
+#endif
+
+   return(DOgetreply());
+}
+
+int DOver()
+{
+   printf("FTP Version %s\n", FtpVersion);
+   return(0);
+}
+
+int DOhelp()
+{
+char junk[10];
+
+   printf("Command:      Description\n");
+   printf("!             Escape to a shell\n");
+   printf("append        Append a file to remote host\n");
+   printf("ascii         Set file transfer type to ascii\n");
+   printf("binary        Set file transfer type to binary\n");
+   printf("block         Set file transfer mode to block\n");
+   printf("bye           Close connection and exit\n");
+   printf("cd            Change directory on remote host\n");
+   printf("close         Close connection\n");
+   printf("clone         Clone a file\n");
+   printf("del           Remove file on remote host\n");
+   printf("dir           Display long form remote host directory listing\n");
+   printf("exit          Close connection and exit\n");
+   printf("get           Retrieve a file from remote host\n");
+   printf("help          Display this text\n");
+
+   if(readline("Press ENTER to continue... ", junk, sizeof(junk)))
+       return(-1);
+
+   printf("lcd           Change directory on local host\n");
+   printf("ldir          Display long form local host directory listing\n");
+   printf("lls           Display local host directory listing\n");
+   printf("lmkdir        Create directory on local host\n");
+   printf("lpwd          Display current directory on local host\n");
+   printf("lrmdir        Remove directory on local host\n");
+   printf("ls            Display remote host directory listing\n");
+   printf("mget          Retrieve multiple files from remote host\n");
+   printf("mkdir         Create directory on remote host\n");
+   printf("mod           Get file modification time\n");
+   printf("mput          Send multiple files to remote host\n");
+   printf("noop          Send the ftp NOOP command\n");
+
+   if(readline("Press ENTER to continue... ", junk, sizeof(junk)))
+       return(-1);
+
+   printf("open          Open connection to remote host\n");
+   printf("pass          Enter remote user password\n");
+   printf("passive       Toggle passive mode\n");
+   printf("put           Send a file to remote host\n");
+   printf("putu          Send a file to remote host(unique)\n");
+   printf("pwd           Display current directory on remote host\n");
+   printf("quit          Close connection and exit\n");
+   printf("quote         Send raw ftp command to remote host\n");
+   printf("reget         Restart a partial file retrieve from remote host\n");
+   printf("remotehelp    Display ftp commands implemented on remote host\n");
+   printf("reput         Restart a partial file send to remote host\n");
+   printf("rm            Remove file on remote host\n");
+   printf("rmdir         Remove directory on remote host\n");
+
+   if(readline("Press ENTER to continue... ", junk, sizeof(junk)))
+       return(-1);
+
+   printf("site          Send a site specific command\n");
+   printf("size          Get file size information\n");
+   printf("status        Get connection/file status information\n");
+   printf("stream        Set file transfer mode to stream\n");
+   printf("system        Get remote system type information\n");
+   printf("user          Enter remote user information\n");
+   printf("ver           Display client version information\n");
+
+   return(0);
+}
+
+struct commands {
+       char *name;
+       _PROTOTYPE(int (*func), (void));
+};
+
+static struct commands commands[] = {
+        "!",            DOlshell,
+       "append",       DOappe,
+       "ascii",        DOascii,
+       "binary",       DObinary,
+       "block",        DOblock,
+       "bye",          DOquit,
+       "cd",           DOcd,
+       "close",        DOclose,
+       "clone",        DOclone,
+       "del",          DOdelete,
+       "dir",          DOlist,
+       "exit",         DOquit,
+       "get",          DOretr,
+       "help",         DOhelp,
+       "lcd",          DOlcd,
+        "ldir",         DOllist,
+        "lls",          DOlnlst,
+       "lmkdir",       DOlmkdir,
+       "lpwd",         DOlpwd,
+       "lrmdir",       DOlrmdir,
+       "ls",           DOnlst,
+       "mget",         DOMretr,
+       "mkdir",        DOmkdir,
+       "mod",          DOmdtm,
+       "mput",         DOMstor,
+       "noop",         DOnoop,
+       "open",         DOopen,
+       "pass",         DOpass,
+       "passive",      DOpassive,
+       "put",          DOstor,
+       "putu",         DOstou,
+       "pwd",          DOpwd,
+       "quit",         DOquit,
+       "quote",        DOquote,
+       "reget",        DOrretr,
+       "remotehelp",   DOremotehelp,
+       "reput",        DOrstor,
+       "rm",           DOdelete,
+       "rmdir",        DOrmdir,
+       "site",         DOsite,
+       "size",         DOsize,
+       "status",       DOstat,
+       "stream",       DOstream,
+       "system",       DOsyst,
+       "user",         DOuser,
+       "ver",          DOver,
+       "",     (int (*)())0
+};
+
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+int s;
+struct commands *cmd;
+static char buffer[128];
+
+   if(NETinit())
+       return(-1);
+
+   FTPinit();
+
+   s = 0;
+
+   if(argc > 1) {
+       sprintf(buffer, "open %s ", argv[1]);
+       makeargs(buffer);
+       s = DOopen();
+       if(atty && s > 0) {
+               sprintf(buffer, "user");
+               makeargs(buffer);
+               s = DOuser();
+       }
+   }
+
+   while(s >= 0) {
+       s = readline("ftp>", buffer, sizeof(buffer));
+       if(s < 0) break;
+       makeargs(buffer);
+       if(cmdargc == 0) continue;
+       for(cmd = commands; *cmd->name != '\0'; cmd++)
+               if(!strcmp(cmdargv[0], cmd->name))
+                       break;
+       if(*cmd->name != '\0')
+               s = (*cmd->func)();
+       else {
+               s = 0;
+               printf("Command \"%s\" not recognized.\n", cmdargv[0]);
+       }
+   }
+
+   return(s);
+}
diff --git a/commands/ftp101/ftp.h b/commands/ftp101/ftp.h
new file mode 100644 (file)
index 0000000..ee72871
--- /dev/null
@@ -0,0 +1,39 @@
+/* ftp.h Copyright 1992-2000 by Michael Temari All Rights Reserved
+ *
+ * This file is part of ftp.
+ *
+ *
+ * 01/25/96 Initial Release    Michael Temari, <Michael@TemWare.Com>
+ */
+
+extern int linkopen;
+extern int loggedin;
+extern int type;
+extern int format;
+extern int mode;
+extern int structure;
+extern int passive;
+extern int atty;
+
+#define        NUMARGS 10
+extern int cmdargc;
+extern char *cmdargv[NUMARGS];
+
+extern int printreply;
+extern char reply[1024];
+
+#define        RETR    0
+#define        STOR    1
+
+#define        TYPE_A  0
+#define        TYPE_I  1
+
+#define        MODE_S  0
+#define        MODE_B  1
+
+#define        MODE_B_EOF      64
+
+_PROTOTYPE(int readline, (char *prompt, char *buff, int len));
+_PROTOTYPE(int DOgetreply, (void));
+_PROTOTYPE(int DOcmdcheck, (void));
+_PROTOTYPE(int DOcommand, (char *ftpcommand, char *ftparg));
diff --git a/commands/ftp101/local.c b/commands/ftp101/local.c
new file mode 100644 (file)
index 0000000..08b1099
--- /dev/null
@@ -0,0 +1,137 @@
+/* local.c Copyright 1992-2000 by Michael Temari All Rights Reserved
+ *
+ * This file is part of ftp.
+ *
+ *
+ * 01/25/96 Initial Release    Michael Temari, <Michael@TemWare.Com>
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include "ftp.h"
+#include "local.h"
+
+static char line2[512];
+
+_PROTOTYPE(static void dodir, (char *path, int full));
+
+int DOlpwd()
+{
+   if(getcwd(line2, sizeof(line2)) == (char *)NULL)
+       printf("Could not determine local directory. %s\n", strerror(errno));
+   else
+       printf("Current local directory: %s\n", line2);
+
+   return(0);
+}
+
+int DOlcd()
+{
+char *path;
+int s;
+
+   path = cmdargv[1];
+
+   if(cmdargc < 2) {
+       if(readline("Path: ", line2, sizeof(line2)) < 0)
+               return(-1);
+       path = line2;
+   }
+
+   if(chdir(path))
+       printf("Could not change local directory. %s\n", strerror(errno));
+   else
+       return(DOlpwd());
+   
+   return(0);
+}
+
+int DOlmkdir()
+{
+char *path;
+int s;
+
+   path = cmdargv[1];
+
+   if(cmdargc < 2) {
+       if(readline("Path: ", line2, sizeof(line2)) < 0)
+               return(-1);
+       path = line2;
+   }
+
+   if(mkdir(path, 0777))
+       printf("Could not make directory %s. %s\n", path, strerror(errno));
+   else
+       printf("Directory created.\n");
+   
+   return(0);
+}
+
+int DOlrmdir()
+{
+char *path;
+int s;
+
+   path = cmdargv[1];
+
+   if(cmdargc < 2) {
+       if(readline("Path: ", line2, sizeof(line2)) < 0)
+               return(-1);
+       path = line2;
+   }
+
+   if(rmdir(path))
+       printf("Could not remove directory %s. %s\n", path, strerror(errno));
+   else
+       printf("Directory removed.\n");
+   
+   return(0);
+}
+
+int DOllist(void)
+{
+   dodir(".", 1);
+
+   return(0);
+}
+
+int DOlnlst(void)
+{
+   dodir(".", 0);
+
+   return(0);
+}
+
+int DOlshell(void)
+{
+   (void) system("$SHELL");
+
+   return(0);
+}
+
+static void dodir(path, full)
+char *path;
+int full;
+{
+static char cmd[128];
+static char name[32];
+
+   (void) tmpnam(name);
+
+   if(full)
+       sprintf(cmd, "ls -l %s > %s", path, name);
+   else
+       sprintf(cmd, "ls %s > %s", path, name);
+
+   (void) system(cmd);
+   sprintf(cmd, "more %s", name);
+   (void) system(cmd);
+   sprintf(cmd, "rm %s", name);
+   (void) system(cmd);
+}
diff --git a/commands/ftp101/local.h b/commands/ftp101/local.h
new file mode 100644 (file)
index 0000000..c55a8a9
--- /dev/null
@@ -0,0 +1,15 @@
+/* local.h Copyright 1992-2000 by Michael Temari All Rights Reserved
+ *
+ * This file is part of ftp.
+ *
+ *
+ * 01/25/96 Initial Release    Michael Temari, <Michael@TemWare.Com>
+ */
+
+_PROTOTYPE(int DOlpwd, (void));
+_PROTOTYPE(int DOlcd, (void));
+_PROTOTYPE(int DOlmkdir, (void));
+_PROTOTYPE(int DOlrmdir, (void));
+_PROTOTYPE(int DOllist, (void));
+_PROTOTYPE(int DOlnlst, (void));
+_PROTOTYPE(int DOlshell, (void));
diff --git a/commands/ftp101/net.c b/commands/ftp101/net.c
new file mode 100644 (file)
index 0000000..b2c9e87
--- /dev/null
@@ -0,0 +1,567 @@
+/* net.c Copyright 1992-2000 by Michael Temari All Rights Reserved
+ *
+ * This file is part of ftp.
+ *
+ *
+ * 01/25/96 Initial Release    Michael Temari, <Michael@TemWare.Com>
+ */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <errno.h>
+#include <net/netlib.h>
+#include <net/hton.h>
+#include <net/gen/netdb.h>
+#include <net/gen/in.h>
+#include <net/gen/inet.h>
+#include <net/gen/tcp.h>
+#include <net/gen/tcp_io.h>
+
+#include "ftp.h"
+#include "xfer.h"
+#include "net.h"
+
+_PROTOTYPE(void donothing, (int sig));
+
+int ftpcomm_fd;
+static ipaddr_t myip;
+static ipaddr_t hostip;
+static char host[256];
+static int lpid;
+
+int NETinit()
+{
+int s;
+char *tcp_device;
+int tcp_fd;
+nwio_tcpconf_t nwio_tcpconf;
+
+   /* All this just to get our ip address */
+
+   if((tcp_device = getenv("TCP_DEVICE")) == (char *)NULL)
+       tcp_device = TCP_DEVICE;
+
+   tcp_fd = open(tcp_device, O_RDWR);
+   if(tcp_fd < 0) {
+       perror("ftp: Could not open tcp_device");
+       return(-1);
+   }
+   s = ioctl(tcp_fd, NWIOGTCPCONF, &nwio_tcpconf);
+   if(s < 0) {
+       perror("ftp: Could not get tcp configuration");
+       return(-1);
+   }
+
+   myip = nwio_tcpconf.nwtc_locaddr;
+
+   close(tcp_fd);
+
+   return(0);
+}
+
+int DOopen()
+{
+nwio_tcpconf_t tcpconf;
+nwio_tcpcl_t tcpcopt;
+char *tcp_device;
+tcpport_t port;
+int s;
+struct hostent *hp;
+struct servent *servent;
+
+   if(linkopen) {
+       printf("Use \"CLOSE\" to close the connection first.\n");
+       return(0);
+   }
+
+   if(cmdargc < 2) {
+       if(readline("Host: ", host, sizeof(host)) < 0)
+               return(-1);
+   } else
+       strncpy(host, cmdargv[1], sizeof(host));
+
+   if((servent = getservbyname("ftp", "tcp")) == (struct servent *)NULL) {
+       fprintf(stderr, "ftp: Could not find ftp tcp service\n");
+       port = htons(21);
+   } else
+       port = (tcpport_t)servent->s_port;
+
+   hp = gethostbyname(host);
+   if(hp == (struct hostent *)NULL) {
+       hostip = (ipaddr_t)0;
+       printf("Unresolved host %s\n", host);
+       return(0);
+   } else
+       memcpy((char *) &hostip, (char *) hp->h_addr, hp->h_length);
+
+   /* This HACK allows the server to establish data connections correctly */
+   /* when using the loopback device to talk to ourselves */
+   if((hostip & NTOHL(0xFF000000)) == inet_addr("127.0.0.0"))
+       hostip = myip;
+
+   if((tcp_device = getenv("TCP_DEVICE")) == NULL)
+       tcp_device = "/dev/tcp";
+
+   if((ftpcomm_fd = open(tcp_device, O_RDWR)) < 0) {
+       perror("ftp: open error on tcp device");
+       return(-1);
+   }
+
+   tcpconf.nwtc_flags = NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP;
+   tcpconf.nwtc_remaddr = hostip;
+   tcpconf.nwtc_remport = port;
+
+   s = ioctl(ftpcomm_fd, NWIOSTCPCONF, &tcpconf);
+   if(s < 0) {
+       perror("ftp: ioctl error on NWIOSTCPCONF");
+       close(ftpcomm_fd);
+       return(-1);
+   }
+
+   tcpcopt.nwtcl_flags = 0;
+
+   s = ioctl(ftpcomm_fd, NWIOTCPCONN, &tcpcopt);
+   if(s < 0) {
+       perror("ftp: ioctl error on NWIOTCPCONN");
+       close(ftpcomm_fd);
+       return(-1);
+   }
+
+   s = ioctl(ftpcomm_fd, NWIOGTCPCONF, &tcpconf);
+   if(s < 0) {
+       perror("ftp: ioctl error on NWIOGTCPCONF");
+       close(ftpcomm_fd);
+       return(-1);
+   }
+
+   s = DOgetreply();
+
+   if(s < 0) {
+       close(ftpcomm_fd);
+       return(s);
+   }
+
+   if(s != 220) {
+       close(ftpcomm_fd);
+       return(0);
+   }
+
+   linkopen = 1;
+
+   return(s);
+}
+
+int DOclose()
+{
+   if(!linkopen) {
+       printf("You can't close a connection that isn't open.\n");
+       return(0);
+   }
+
+   close(ftpcomm_fd);
+
+   linkopen = 0;
+   loggedin = 0;
+
+   return(0);
+}
+
+int DOquit()
+{
+int s;
+
+   if(linkopen) {
+       s = DOcommand("QUIT", "");
+       s = DOclose();
+   }
+
+   printf("FTP done.\n");
+
+   exit(0);
+}
+
+void donothing(sig)
+int sig;
+{
+}
+
+int DOdata(datacom, file, direction, fd)
+char *datacom;
+char *file;
+int direction;  /* RETR or STOR */
+int fd;
+{
+nwio_tcpconf_t tcpconf;
+nwio_tcpcl_t tcplopt, tcpcopt;
+char *tcp_device;
+static int ftpdata_fd = -1;
+char *buff;
+ipaddr_t ripaddr;
+tcpport_t rport;
+static tcpport_t lport = HTONS(0xF000);
+int s;
+int i;
+int wpid;
+int cs;
+int pfd[2];
+char dummy;
+char port[32];
+int wasopen;
+
+#ifdef DEBUG
+   printf("DOdata %s %s %d %d\n", datacom, file, direction, fd);
+#endif
+
+   ripaddr = hostip;
+   rport = HTONS(20);
+
+   /* here we set up a connection to listen on if not passive mode */
+   /* otherwise we use this to connect for passive mode */
+
+   if((tcp_device = getenv("TCP_DEVICE")) == NULL)
+       tcp_device = "/dev/tcp";
+
+   if(ftpdata_fd >= 0 && mode != MODE_B) {
+       close(ftpdata_fd);
+       ftpdata_fd = -1;
+   }
+
+   wasopen = (ftpdata_fd >= 0);
+
+#ifdef DEBUG
+   printf("wasopen = %d\n", wasopen);
+#endif
+
+   if(wasopen)
+       goto WASOPEN;
+
+#ifdef DEBUG
+   printf("b4 open = %d\n", ftpdata_fd);
+#endif
+
+   if(ftpdata_fd == -1)
+       if((ftpdata_fd = open(tcp_device, O_RDWR)) < 0) {
+               perror("ftp: open error on tcp device");
+               return(0);
+       }
+
+#ifdef DEBUG
+   printf("at open = %d\n", ftpdata_fd);
+#endif
+
+   if(passive) {
+#ifdef DEBUG
+       printf("b4 PASV command\n");
+#endif
+       s = DOcommand("PASV", "");
+#ifdef DEBUG
+       printf("PASV command returned %d\n", s);
+#endif
+       if(s != 227) {
+               close(ftpdata_fd);
+               ftpdata_fd = -1;
+               return(s);
+       }
+       /* decode host and port */
+       buff = reply;
+       while(*buff && (*buff != '(')) buff++;
+       buff++;
+       ripaddr = (ipaddr_t)0;
+       for(i = 0; i < 4; i++) {
+               ripaddr = (ripaddr << 8) + (ipaddr_t)atoi(buff);
+               if((buff = strchr(buff, ',')) == (char *)0) {
+                       printf("Could not parse PASV reply\n");
+                       return(0);
+               }
+               buff++;
+       }
+       rport = (tcpport_t)atoi(buff);
+       if((buff = strchr(buff, ',')) == (char *)0) {
+               printf("Could not parse PASV reply\n");
+               return(0);
+       }
+       buff++;
+       rport = (rport << 8) + (tcpport_t)atoi(buff);
+       ripaddr = ntohl(ripaddr);
+       rport = ntohs(rport);
+#ifdef DEBUG
+       printf("PASV %08x %04x\n", ripaddr, rport);
+#endif
+   }
+
+   while(1) {
+       tcpconf.nwtc_flags = NWTC_SET_RA | NWTC_SET_RP;
+       if(passive || ntohs(lport) >= 0xF000) {
+               tcpconf.nwtc_flags |= NWTC_LP_SEL;
+       } else {
+               /* For no good reason Sun hosts don't like it if they have to
+                * connect to the same port twice in a short time...
+                */
+               lport = htons(ntohs(lport) + 1);
+               tcpconf.nwtc_flags |= NWTC_LP_SET;
+               tcpconf.nwtc_locport = lport;
+       }
+
+       tcpconf.nwtc_remaddr = ripaddr;
+       tcpconf.nwtc_remport = rport;
+
+#ifdef DEBUG
+       printf("b4 STCPCONF locport = %d\n", lport);
+#endif
+
+       s = ioctl(ftpdata_fd, NWIOSTCPCONF, &tcpconf);
+#ifdef DEBUG
+       printf("at STCPCONF %d %d\n", s, errno);
+#endif
+       if(s < 0) {
+               if(errno == EADDRINUSE) continue;
+               perror("ftp: ioctl error on NWIOSTCPCONF");
+               close(ftpdata_fd);
+               ftpdata_fd = -1;
+               return(0);
+       }
+       break;
+   }
+
+#ifdef DEBUG
+       printf("b4 GTCPCONF\n");
+#endif
+   s = ioctl(ftpdata_fd, NWIOGTCPCONF, &tcpconf);
+#ifdef DEBUG
+   printf("at GTCPCONF %d %d\n", s, errno);
+#endif
+   if(s < 0) {
+       perror("ftp: ioctl error on NWIOGTCPCONF");
+       close(ftpdata_fd);
+       ftpdata_fd = -1;
+       return(0);
+   }
+   lport = tcpconf.nwtc_locport;
+
+#ifdef DEBUG
+   printf("lport = %04x\n", lport);
+#endif
+
+   if(passive) {
+       /* passive mode we connect to them */
+       tcplopt.nwtcl_flags = 0;
+#ifdef DEBUG
+       printf("Doing TCPCONN\n");
+#endif
+       s = ioctl(ftpdata_fd, NWIOTCPCONN, &tcpcopt);
+#ifdef DEBUG
+       printf("TCPCONN %d %d\n", s, errno);
+#endif
+       if(s < 0) {
+               perror("ftp: error on ioctl NWIOTCPCONN");
+               close(ftpdata_fd);
+               ftpdata_fd = -1;
+               return(0);
+       }
+#ifdef DEBUG
+       printf("GTCPCONF\n");
+#endif
+       s = ioctl(ftpdata_fd, NWIOGTCPCONF, &tcpconf);
+#ifdef DEBUG
+       printf("GTCPCONF %d %d\n", s, errno);
+#endif
+       if(s < 0) {
+               perror("ftp: error on ioctl NWIOGTCPCONF");
+               close(ftpdata_fd);
+               ftpdata_fd = -1;
+               return(0);
+       }
+   } else {
+       /* we listen for them */
+       tcplopt.nwtcl_flags = 0;
+#ifdef DEBUG
+       printf("Listen\n");
+#endif
+
+       if (pipe(pfd) < 0) {
+               perror("ftp: could not create a pipe");
+               close(ftpdata_fd);
+               ftpdata_fd = -1;
+               return(0);
+       }
+       lpid = fork();
+       if(lpid < 0) {
+               perror("ftp: could not fork listener");
+               close(ftpdata_fd);
+               ftpdata_fd = -1;
+               close(pfd[0]);
+               close(pfd[1]);
+               return(0);
+       } else if(lpid == 0) {
+#ifdef DEBUG
+               printf("Child here\n");
+#endif
+               close(pfd[0]);
+               signal(SIGALRM, donothing);
+               alarm(15);
+               close(pfd[1]);
+#ifdef DEBUG
+               printf("child TCPLISTEN\n");
+#endif
+               s = ioctl(ftpdata_fd, NWIOTCPLISTEN, &tcplopt);
+               alarm(0);
+#ifdef DEBUG
+               printf("listen %d %d\n", s, errno);
+#endif
+               if(s < 0)
+                       exit(errno);            /* error */
+               else
+                       exit(0);                /* connection made */
+       }
+#ifdef DEBUG
+       printf("Fork = %d\n", lpid);
+#endif
+       /* Wait for the pipe to close, then the listener is ready (almost). */
+       close(pfd[1]);
+       (void) read(pfd[0], &dummy, 1);
+       close(pfd[0]);
+       while(1) {
+               wpid = waitpid(lpid, &cs, WNOHANG);
+#ifdef DEBUG
+               printf("waitpid %d %d\n", wpid, cs);
+               printf("GTCPCONF loop\n");
+#endif
+               if(wpid != 0) break;
+               signal(SIGALRM, donothing);
+               alarm(1);
+               s = ioctl(ftpdata_fd, NWIOGTCPCONF, &tcpconf);
+               alarm(0);
+#ifdef DEBUG
+               printf("GTCPCONF loop %d %d\n", s, errno);
+#endif
+               if(s == -1) break;
+               sleep(1);
+       }
+#ifdef DEBUG
+       printf("GTCPCONF = %d\n", s);
+#endif
+   }
+
+#define hiword(x)       ((u16_t)((x) >> 16))
+#define loword(x)       ((u16_t)(x & 0xffff)) 
+#define hibyte(x)       (((x) >> 8) & 0xff)
+#define lobyte(x)       ((x) & 0xff)
+
+   if(!passive) {
+       if(wpid != 0) {
+               close(ftpdata_fd);
+               ftpdata_fd = -1;
+               cs = (cs >> 8) & 0x00ff;
+               printf("Child listener error %s\n", strerror(cs));
+               return(0);
+       }
+       sprintf(port, "%u,%u,%u,%u,%u,%u",
+               hibyte(hiword(ntohl(myip))), lobyte(hiword(ntohl(myip))),
+               hibyte(loword(ntohl(myip))), lobyte(loword(ntohl(myip))),
+               hibyte(ntohs(lport)), lobyte(ntohs(lport)));
+#ifdef DEBUG
+       printf("sending port command %s\n", port);
+#endif
+       s = DOcommand("PORT", port);
+#ifdef DEBUG
+       printf("port command = %d\n", s);
+#endif
+       if(s != 200) {
+               close(ftpdata_fd);
+               ftpdata_fd = -1;
+               kill(lpid, SIGKILL);
+               (void) wait(&cs);
+               return(s);
+       }
+   }
+
+WASOPEN:
+
+#ifdef DEBUG
+   printf("doing data command %s %s\n", datacom, file);
+#endif
+   s = DOcommand(datacom, file);
+#ifdef DEBUG
+   printf("do command reply %d\n", s);
+#endif
+   if(s == 125 || s == 150) {
+       if(!passive && !wasopen) {
+               while(1) {
+#ifdef DEBUG
+                       printf("Waiting for child %d\n", lpid);
+#endif
+                       s = wait(&cs);
+#ifdef DEBUG
+                       printf("Wait returned %d cs=%d errno=%d\n", s, cs, errno);
+#endif
+                       if(s < 0 || s == lpid)
+                               break;
+               }
+               if(s < 0) {
+                       perror("wait error:");
+                       close(ftpdata_fd);
+                       ftpdata_fd = -1;
+                       kill(lpid, SIGKILL);
+                       (void) wait(&cs);
+                       return(s);
+               }
+               if((cs & 0x00ff)) {
+                       printf("Child listener failed %04x\n", cs);
+                       close(ftpdata_fd);
+                       ftpdata_fd = -1;
+                       return(-1);
+               }
+               cs = (cs >> 8) & 0x00ff;
+               if(cs) {
+                       printf("Child listener error %s\n", strerror(cs));
+                       close(ftpdata_fd);
+                       ftpdata_fd = -1;
+                       return(DOgetreply());
+               }
+       }
+#ifdef DEBUG
+       printf("Before recvfile/sendfile call\n");
+#endif
+       switch(direction) {
+               case RETR:
+                       s = recvfile(fd, ftpdata_fd);
+                       break;
+               case STOR:
+                       s = sendfile(fd, ftpdata_fd);
+                       break;
+       }
+#ifdef DEBUG
+       printf("send/recieve %d\n", s);
+#endif
+       if(mode != MODE_B) {
+               close(ftpdata_fd);
+               ftpdata_fd = -1;
+       }
+
+       s = DOgetreply();
+#ifdef DEBUG
+       printf("send/recieve reply %d\n", s);
+#endif
+       if(mode == MODE_B && s == 226) {
+               close(ftpdata_fd);
+               ftpdata_fd = -1;
+       }
+   } else {
+       if(!passive) {
+               kill(lpid, SIGKILL);
+               (void) wait(&cs);
+       }
+       close(ftpdata_fd);
+       ftpdata_fd = -1;
+   }
+
+   return(s);
+}
diff --git a/commands/ftp101/net.h b/commands/ftp101/net.h
new file mode 100644 (file)
index 0000000..ffe3439
--- /dev/null
@@ -0,0 +1,15 @@
+/* net.h Copyright 1992-2000 by Michael Temari All Rights Reserved
+ *
+ * This file is part of ftp.
+ *
+ *
+ * 01/25/96 Initial Release    Michael Temari, <Michael@TemWare.Com>
+ */
+
+_PROTOTYPE(int NETinit, (void));
+_PROTOTYPE(int DOopen, (void));
+_PROTOTYPE(int DOclose, (void));
+_PROTOTYPE(int DOquit, (void));
+_PROTOTYPE(int DOdata, (char *datacom, char *file, int direction, int fd));
+
+extern int ftpcomm_fd;
diff --git a/commands/ftp101/other.c b/commands/ftp101/other.c
new file mode 100644 (file)
index 0000000..8718da7
--- /dev/null
@@ -0,0 +1,173 @@
+/* other.c Copyright 1992-2000 by Michael Temari All Rights Reserved
+ *
+ * ftp          An ftp client program for use with TNET.
+ *
+ * Author:      Michael Temari, <Michael@TemWare.Com>
+ */
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include "ftp.h"
+#include "other.h"
+
+_PROTOTYPE(static int docmdargs, (char *cmd, int fa));
+
+void FTPinit()
+{
+   linkopen = 0;
+   loggedin = 0;
+   type = TYPE_A;
+   format = 0;
+   mode = MODE_S;
+   structure = 0;
+   passive = 0;
+   atty = isatty(0);
+}
+
+int DOpass()
+{
+int s;
+struct termios oldtty, newtty;
+char *pass;
+char password[64];
+
+   if(!linkopen) {
+       printf("You must \"OPEN\" a connection first.\n");
+       return(0);
+   }
+
+   pass = cmdargv[1];
+
+   s = 0;
+
+   if(cmdargc < 2) {
+       if(atty) {
+               tcgetattr(fileno(stdout), &oldtty);
+               newtty = oldtty;
+               newtty.c_lflag &= ~ECHO;
+               tcsetattr(fileno(stdout), TCSANOW, &newtty);
+       }
+       s = readline("Password: ", password, sizeof(password));
+       if(atty) {
+               tcsetattr(fileno(stdout), TCSANOW, &oldtty);
+               printf("\n");
+       }
+       pass = password;
+   }
+
+   if(s < 0)
+       return(-1);
+
+   s = DOcommand("PASS", pass);
+
+   if(s == 230)
+       loggedin = 1;
+
+   return(s);
+}
+
+int DOuser()
+{
+char *user;
+int s;
+char username[32];
+
+   if(!linkopen) {
+       printf("You must \"OPEN\" a connection first.\n");
+       return(0);
+   }
+
+   loggedin = 0;
+
+   user = cmdargv[1];
+
+   s = 0;
+
+   if(cmdargc < 2) {
+       if(readline("Username: ", username, sizeof(username)) < 0)
+               return(-1);
+       user = username;
+   }
+
+   s = DOcommand("USER", user);
+
+   if(atty && s == 331) {
+       cmdargv[0] = "password";
+       cmdargc = 1;
+       return(DOpass());
+   }
+
+   if(s == 230)
+       loggedin = 1;
+
+   return(s);
+}
+
+int DOnoop()
+{
+   if(DOcmdcheck())
+       return(0);
+
+   return(DOcommand("NOOP", ""));
+}
+
+int DOpassive()
+{
+   passive = 1 - passive;
+
+   printf("Passive mode is now %s\n", (passive ? "ON" : "OFF"));
+
+   return(0);
+}
+
+int DOsyst()
+{
+   if(DOcmdcheck())
+       return(0);
+
+   return(DOcommand("SYST", ""));
+}
+
+int DOremotehelp()
+{
+   if(!linkopen) {
+       printf("You must \"OPEN\" a connection first.\n");
+       return(0);
+   }
+
+   return(DOcommand("HELP", ""));
+}
+
+static int docmdargs(cmd, fa)
+char *cmd;
+int fa;
+{
+int i;
+static char args[512];
+
+   args[0] = '\0';
+
+   for(i = fa; i < cmdargc; i++) {
+       if(i != fa)
+               strcat(args, " ");
+       strcat(args, cmdargv[i]);
+   }
+
+   return(DOcommand(cmd, args));
+}
+
+int DOquote()
+{
+   return(docmdargs(cmdargv[1], 2));
+}
+
+int DOsite()
+{
+   return(docmdargs("SITE", 1));
+}
diff --git a/commands/ftp101/other.h b/commands/ftp101/other.h
new file mode 100644 (file)
index 0000000..e8b46f0
--- /dev/null
@@ -0,0 +1,17 @@
+/* other.h Copyright 1992-2000 by Michael Temari All Rights Reserved
+ *
+ * This file is part of ftp.
+ *
+ *
+ * 01/25/96 Initial Release    Michael Temari, <Michael@TemWare.Com>
+ */
+
+_PROTOTYPE(void FTPinit, (void));
+_PROTOTYPE(int DOpass, (void));
+_PROTOTYPE(int DOuser, (void));
+_PROTOTYPE(int DOnoop, (void));
+_PROTOTYPE(int DOpassive, (void));
+_PROTOTYPE(int DOsyst, (void));
+_PROTOTYPE(int DOremotehelp, (void));
+_PROTOTYPE(int DOquote, (void));
+_PROTOTYPE(int DOsite, (void));
diff --git a/commands/ftp101/xfer.c b/commands/ftp101/xfer.c
new file mode 100644 (file)
index 0000000..35d9f69
--- /dev/null
@@ -0,0 +1,305 @@
+/* xfer.c Copyright 1992-2000 by Michael Temari All Rights Reserved
+ *
+ * This file is part of ftp.
+ *
+ *
+ * 03/14/00 Initial Release    Michael Temari, <Michael@TemWare.Com>
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <time.h>
+#include <utime.h>
+#include <net/hton.h>
+
+#include "ftp.h"
+#include "xfer.h"
+
+_PROTOTYPE(static int asciisend, (int fd, int fdout));
+_PROTOTYPE(static int binarysend, (int fd, int fdout));
+_PROTOTYPE(static int asciirecv, (int fd, int fdin));
+_PROTOTYPE(static int binaryrecv, (int fd, int fdin));
+
+#if (__WORD_SIZE == 4)
+static char buffer[8192];
+static char bufout[8192];
+#else
+static char buffer[2048];
+static char bufout[2048];
+#endif
+
+static int asciisend(fd, fdout)
+int fd;
+int fdout;
+{
+int s, len;
+char c;
+char *p;
+char *op, *ope;
+unsigned long total=0L;
+char block[3];
+
+   if(atty) {
+       printf("Sent ");
+       fflush(stdout);
+   }
+
+   op = bufout;
+   ope = bufout + sizeof(bufout) - 3;
+
+   while((s = read(fd, buffer, sizeof(buffer))) > 0) {
+       total += (long)s;
+       p = buffer;
+       while(s-- > 0) {
+               c = *p++;
+               if(c == '\n') {
+                       *op++ = '\r';
+                       total++;
+               }
+               *op++ = c;
+               if(op >= ope) {
+                       if(mode == MODE_B) {
+                               block[0] = '\0';
+                               *(u16_t *)&block[1] = htons(op - bufout);
+                               write(fdout, block, sizeof(block));
+                       }
+                       write(fdout, bufout, op - bufout);
+                       op = bufout;
+               }
+       }
+       if(atty) {
+               printf("%8lu bytes\b\b\b\b\b\b\b\b\b\b\b\b\b\b", total);
+               fflush(stdout);
+       }
+   }
+   if(op > bufout) {
+       if(mode == MODE_B) {
+               block[0] = MODE_B_EOF;
+               *(u16_t *)&block[1] = htons(op - bufout);
+               write(fdout, block, sizeof(block));
+       }
+       write(fdout, bufout, op - bufout);
+   } else if(mode == MODE_B) {
+       block[0] = MODE_B_EOF;
+       *(u16_t *)&block[1] = htons(0);
+       write(fdout, block, sizeof(block));
+       s = 0;
+   }
+   if(atty) {
+       printf("\n");
+       fflush(stdout);
+   }
+
+   return(s);
+}
+
+static int binarysend(fd, fdout)
+int fd;
+int fdout;
+{
+int s;
+unsigned long total=0L;
+char block[3];
+
+   if(atty) {
+       printf("Sent ");
+       fflush(stdout);
+   }
+
+   while((s = read(fd, buffer, sizeof(buffer))) > 0) {
+       if(mode == MODE_B) {
+               block[0] = MODE_B_EOF;
+               *(u16_t *)&block[1] = htons(s);
+               write(fdout, block, sizeof(block));
+       }
+       write(fdout, buffer, s);
+       total += (long)s;
+       if(atty) {
+               printf("%8lu bytes\b\b\b\b\b\b\b\b\b\b\b\b\b\b", total);
+               fflush(stdout);
+       }
+   }
+   if(mode == MODE_B) {
+       block[0] = MODE_B_EOF;
+       *(u16_t *)&block[1] = htons(0);
+       write(fdout, block, sizeof(block));
+       s = 0;
+   }
+   if(atty) {
+       printf("\n");
+       fflush(stdout);
+   }
+
+   return(s);
+}
+
+int sendfile(fd, fdout)
+int fd;
+int fdout;
+{
+int s;
+
+   switch(type) {
+       case TYPE_A:
+               s = asciisend(fd, fdout);
+               break;
+       default:
+               s = binarysend(fd, fdout);
+   }
+
+   if(s < 0)
+       return(-1);
+   else
+       return(0);
+}
+
+static int asciirecv(fd, fdin)
+int fd;
+int fdin;
+{
+int s, len;
+int gotcr;
+char c;
+char *p;
+char *op, *ope;
+unsigned long total=0L;
+char block[3];
+unsigned short cnt;
+
+   if(isatty && fd > 2) {
+       printf("Received ");
+       fflush(stdout);
+   }
+   gotcr = 0;
+   op = bufout; ope = bufout + sizeof(bufout) - 3;
+   cnt = 0;
+   while(1) {
+       if(mode != MODE_B)
+               cnt = sizeof(buffer);
+       else
+               if(cnt == 0) {
+                       s = read(fdin, block, sizeof(block));
+                       cnt = ntohs(*(u16_t *)&block[1]);
+                       s = 0;
+                       if(cnt == 0 && block[0] & MODE_B_EOF)
+                               break;
+               }
+       s = read(fdin, buffer, cnt > sizeof(buffer) ? sizeof(buffer) : cnt);
+       if(s <= 0) break;
+       cnt -= s;
+       total += (long)s;
+       p = buffer;
+       while(s-- > 0) {
+               c = *p++;
+               if(gotcr) {
+                       gotcr = 0;
+                       if(c != '\n')
+                               *op++ = '\r';
+               }
+               if(c == '\r')
+                       gotcr = 1;
+               else
+                       *op++ = c;
+               if(op >= ope) {
+                       write(fd, bufout, op - bufout);
+                       op = bufout;
+               }
+       }
+       if(atty && fd > 2) {
+               printf("%8lu bytes\b\b\b\b\b\b\b\b\b\b\b\b\b\b", total);
+               fflush(stdout);
+       }
+       if(cnt == 0 && mode == MODE_B && block[0] & MODE_B_EOF) {
+                       s = 0;
+                       break;
+       }
+   }
+   if(gotcr)
+       *op++ = '\r';
+   if(op > bufout)
+       write(fd, bufout, op - bufout);
+   if(atty && fd > 2) {
+       printf("\n");
+       fflush(stdout);
+   }
+   if((mode == MODE_B && cnt != 0) || s != 0)
+       return(-1);
+   else
+       return(0);
+}
+
+static binaryrecv(fd, fdin)
+int fd;
+int fdin;
+{
+int s;
+unsigned long total=0L;
+char block[3];
+unsigned short cnt;
+
+   if(atty && fd > 2) {
+       printf("Received ");
+       fflush(stdout);
+   }
+   cnt = 0;
+   while(1) {
+       if(mode != MODE_B)
+               cnt = sizeof(buffer);
+       else
+               if(cnt == 0) {
+                       s = read(fdin, block, sizeof(block));
+                       cnt = ntohs(*(u16_t *)&block[1]);
+                       s = 0;
+                       if(cnt == 0 && block[0] & MODE_B_EOF)
+                               break;
+               }
+       s = read(fdin, buffer, cnt > sizeof(buffer) ? sizeof(buffer) : cnt);
+       if(s <= 0) break;
+       cnt -= s;
+       total += (long)s;
+       write(fd, buffer, s);
+       if(atty && fd > 2) {
+               printf("%8lu bytes\b\b\b\b\b\b\b\b\b\b\b\b\b\b", total);
+               fflush(stdout);
+       }
+       if(cnt == 0 && mode == MODE_B && block[0] & MODE_B_EOF) {
+               s = 0;
+               break;
+       }
+   }
+   if(atty && fd > 2) {
+       printf("\n");
+       fflush(stdout);
+   }
+   if((mode == MODE_B && cnt != 0) || s != 0)
+       return(-1);
+   else
+       return(0);
+}
+
+int recvfile(fd, fdin)
+int fd;
+int fdin;
+{
+int s;
+
+   switch(type) {
+       case TYPE_A:
+               s = asciirecv(fd, fdin);
+               break;
+       default:
+               s = binaryrecv(fd, fdin);
+   }
+
+   if(s < 0)
+       return(-1);
+   else
+       return(0);
+}
diff --git a/commands/ftp101/xfer.h b/commands/ftp101/xfer.h
new file mode 100644 (file)
index 0000000..696eacc
--- /dev/null
@@ -0,0 +1,8 @@
+/* xfer.h Copyright 1992-2000 by Michael Temari All Rights Reserved
+ *
+ * This file is part of ftp.
+ *
+ */
+
+_PROTOTYPE(int recvfile, (int fd, int fdin));
+_PROTOTYPE(int sendfile, (int fd, int fdout));
diff --git a/commands/httpd0995/Makefile b/commands/httpd0995/Makefile
new file mode 100644 (file)
index 0000000..19b52c4
--- /dev/null
@@ -0,0 +1,65 @@
+# Makefile for httpd
+#
+# 02/17/1996                   Michael Temari <Michael@TemWare.Com>
+# 07/07/1996 Initial Release   Michael Temari <Michael@TemWare.Com>
+# 12/29/2002                   Michael Temari <Michael@TemWare.Com>
+# 07/07/2003                   Al Woodhull <asw@woodhull.com>
+#
+
+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
+
+
diff --git a/commands/httpd0995/README b/commands/httpd0995/README
new file mode 100644 (file)
index 0000000..c557401
--- /dev/null
@@ -0,0 +1,252 @@
+httpd documentation 7/16/96 by Michael Temari <Michael@TemWare.Com>
+updated 2006-06-01 by Al Woodhull <asw@woodhull.com>
+
+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 redirect 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.
+
+
+redirect url
+
+If redirect is defined in the configuration file then all request urls 
+will be redirected. For example, if in the configuration file of 
+minix1.hampshire.edu this line appears:
+   redirect http://minix1.woodhull.com/
+a request for http://minix1.hampshire.edu/some/page will return a 301 error 
+which is a redirect permanent to http://minix1.woodhull.com/some/page.
+
+
+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)
diff --git a/commands/httpd0995/SECURITY b/commands/httpd0995/SECURITY
new file mode 100644 (file)
index 0000000..88c7305
--- /dev/null
@@ -0,0 +1,52 @@
+SECURITY NOTE 
+
+Al Woodhull <asw@woodhull.com> updated 2006-06-01
+
+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 you have provided a /etc/serv.access
+file. This file can be used to limit access only to permitted nodes or
+networks, or to deny access to specified nodes or networks (see the 
+serv.access (5) man page). Also, even if your /etc/serv.access file is
+empty, if it is present tcpd will exec its paranoid twin tcpdp, which
+will refuse service if the connecting IP address cannot be associated
+with a name. 
+
+- 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.
+
diff --git a/commands/httpd0995/cgiexec.c b/commands/httpd0995/cgiexec.c
new file mode 100644 (file)
index 0000000..856a512
--- /dev/null
@@ -0,0 +1,255 @@
+/* cgiexec.c by Michael Temari 02/17/96
+ *
+ * This file is part of httpd.
+ *
+ * 02/17/1996                  Michael Temari <Michael@TemWare.Com>
+ * 07/07/1996 Initial Release  Michael Temari <Michael@TemWare.Com>
+ * 12/29/2002                  Michael Temari <Michael@TemWare.Com>
+ * 02/08/2005                  Michael Temari <Michael@TemWare.Com>
+ *
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <time.h>
+
+#include "http.h"
+#include "config.h"
+#include "net.h"
+
+_PROTOTYPE(char **cgienv, (struct http_request *rq, struct http_reply *rp));
+_PROTOTYPE(static int addenv, (char *name, char *value, char **buf, int *len));
+
+int cgiexec(rq, rp)
+struct http_request *rq;
+struct http_reply *rp;
+{
+struct stat st;
+char *prog;
+int cmdpid;
+int status;
+char *argv[5];
+int ifds[2];
+int ofds[2];
+static char cmd[2048];
+char **cmdenv;
+int dirflag = 0;
+
+    if(stat(rp->realurl, &st)) {
+       if(errno == EACCES)
+               rp->status = HTTP_STATUS_FORBIDDEN;
+       else
+               rp->status = HTTP_STATUS_NOT_FOUND;
+       strcpy(rp->statusmsg, strerror(errno));
+       return(-1);
+    }
+
+    if((st.st_mode & S_IFMT) == S_IFDIR)
+       if(direxec != NULL) {
+               prog = direxec; dirflag = 1;
+       } else
+               return(0);
+    else
+       prog = rp->realurl;
+
+    /* check if prog is allowed to be exec'd */
+    if(!dirflag && !(rp->urlaccess & URLA_EXEC))
+       return(0);
+
+    /* if cannot exec mode then return */
+    if( (st.st_mode & S_IXUSR) == 0 &&
+       (st.st_mode & S_IXGRP) == 0 &&
+       (st.st_mode & S_IXOTH) == 0 )
+       return(0);
+
+   if((cmdenv = cgienv(rq, rp)) == NULL) {
+       rp->status = HTTP_STATUS_SERVER_ERROR;
+       strcpy(rp->statusmsg, "Could not setup cgi environment");
+       return(-1);
+   }
+
+   argv[0] = prog;
+   argv[1] = rp->realurl;
+   argv[2] = rq->url;
+   argv[3] = (char *)NULL;
+
+   if(pipe(ifds) < 0) {
+       rp->status = HTTP_STATUS_NOT_FOUND;
+       strcpy(rp->statusmsg, strerror(errno));
+       return(-1);
+   }
+
+   if(pipe(ofds) < 0) {
+       rp->status = HTTP_STATUS_NOT_FOUND;
+       strcpy(rp->statusmsg, strerror(errno));
+       close(ifds[0]); close(ifds[1]);
+       return(-1);
+   }
+
+   if((cmdpid = fork()) < 0) {
+       close(ifds[0]); close(ofds[0]);
+       close(ifds[1]); close(ofds[1]);
+       rp->status = HTTP_STATUS_NOT_FOUND;
+       strcpy(rp->statusmsg, strerror(errno));
+       return(-1);
+   }
+
+   /* We don't know how much data is going to be passed back */
+   rp->size = 0;
+
+   if(cmdpid == 0) { /* Child */
+#if 0
+       if((cmdpid = fork()) < 0) {
+               close(ifds[0]); close(ofds[0]);
+               close(ifds[1]); close(ofds[1]);
+               exit(-1);
+       }
+       if(cmdpid != 0) {
+               close(ifds[0]); close(ofds[0]);
+               close(ifds[1]); close(ofds[1]);
+               exit(0);
+       }
+#endif
+       setsid();
+       close(ifds[0]); close(ofds[1]);
+       dup2(ofds[0], 0);
+       dup2(ifds[1], 1);
+       dup2(ifds[1], 2);
+       close(ifds[1]); close(ofds[0]);
+       execve(argv[0], argv, cmdenv);
+       exit(0);
+   }
+
+#if 0
+   /* Get rid of Zombie child */
+   (void) wait(&status);
+#endif
+
+   close(ifds[1]); close(ofds[0]);
+
+   rp->fd = ifds[0];
+   rp->ofd = ofds[1];
+   rp->pid = cmdpid;
+
+   if(rp->urlaccess & URLA_HEADERS)
+       rp->headers = -1;
+
+   return(-1);
+}
+
+char **cgienv(rq, rp)
+struct http_request *rq;
+struct http_reply *rp;
+{
+static char buffer[4096];
+char *p, *p2;
+char **e;
+int len;
+char temp[20];
+
+   p = buffer;
+   len = sizeof(buffer);
+
+   if(addenv("PATH", "/usr/local/bin:/bin:/usr/bin", &p, &len)) return(NULL);
+   if(getenv("TZ") != (char *)NULL)
+       if(addenv("TZ", getenv("TZ"), &p, &len)) return(NULL);
+
+   /* HACK - some of these are hardcoded and should not be MAT 3/17/96 */
+
+   /* HTTP_ */
+
+   if(addenv("SERVER_SOFTWARE", "Temari httpd/1.0", &p, &len)) return(NULL);
+   if(addenv("SERVER_NAME", myhostname, &p, &len)) return(NULL);
+   if(addenv("GATEWAY_INTERFACE", "CGI/1.1", &p, &len)) return(NULL);
+   if(addenv("SERVER_PROTOCOL", "HTTP/1.0", &p, &len)) return(NULL);
+   if(rq->port)
+       sprintf(temp, "%u", rq->port);
+   else
+       strcpy(temp, "80");
+   if(addenv("SERVER_PORT", temp, &p, &len)) return(NULL);
+   switch(rq->method) {
+       case HTTP_METHOD_GET:
+               if(addenv("REQUEST_METHOD", "GET", &p, &len)) return(NULL);
+               break;
+       case HTTP_METHOD_POST:
+               if(addenv("REQUEST_METHOD", "POST", &p, &len)) return(NULL);
+               break;
+       case HTTP_METHOD_HEAD:
+               if(addenv("REQUEST_METHOD", "HEAD", &p, &len)) return(NULL);
+               break;
+       case HTTP_METHOD_PUT:
+               if(addenv("REQUEST_METHOD", "PUT", &p, &len)) return(NULL);
+               break;
+       default:
+               if(addenv("REQUEST_METHOD", "UNKNOWN", &p, &len)) return(NULL);
+   }
+   if(addenv("PATH_INFO", "?", &p, &len)) return(NULL);
+   if(addenv("PATH_TRANSLATED", "?", &p, &len)) return(NULL);
+   if(addenv("SCRIPT_NAME", rq->url, &p, &len)) return(NULL);
+   if(addenv("QUERY_STRING", rq->query, &p, &len)) return(NULL);
+   if(addenv("REMOTE_HOST", rmthostname, &p, &len)) return(NULL);
+   if(addenv("REMOTE_ADDR", rmthostaddr, &p, &len)) return(NULL);
+   if(rq->authuser != (char *)NULL)
+       if(addenv("AUTH_USER", rq->authuser, &p, &len)) return(NULL);
+   /* AUTH_TYPE */
+   /* REMOTE_USER */
+   /* REMOTE_IDENT */
+   if(rq->method == HTTP_METHOD_POST) {
+       if(addenv("CONTENT_TYPE", "application/x-www-form-urlencoded", &p, &len)) return(NULL);
+       sprintf(temp, "%lu", rq->size);
+       if(addenv("CONTENT_LENGTH", temp, &p, &len)) return(NULL);
+   }
+   /* COOKIE */
+   if(rq->cookie[0] != '\0')
+       if(addenv("COOKIE", rq->cookie, &p, &len)) return(NULL);
+   /* HOST */
+   if(addenv("HOST", rq->host, &p, &len)) return(NULL);
+
+   if(len < 1) return(NULL);
+   *p++ = '\0';
+
+   p2 = buffer;
+   e = (char **)p;
+   while(*p2) {
+       if(len < sizeof(e)) return(NULL);
+       len -= sizeof(e);
+       *e++ = p2;
+       while(*p2) p2++;
+       p2++;
+   }
+   if(len < sizeof(e)) return(NULL);
+   *e++ = NULL;
+
+   return((char **)p);
+}
+
+static int addenv(name, value, buf, len)
+char *name;
+char *value;
+char **buf;
+int *len;
+{
+char *p;
+int size;
+
+   p = *buf;
+
+   size = strlen(name)+1+strlen(value)+1;
+
+   if(size > *len)
+       return(-1);
+
+   sprintf(p, "%s=%s", name, value);
+
+   p += size;
+   *buf = p;
+   *len -= size;
+
+   return(0);
+}
diff --git a/commands/httpd0995/config.c b/commands/httpd0995/config.c
new file mode 100644 (file)
index 0000000..4c81874
--- /dev/null
@@ -0,0 +1,841 @@
+/* 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>
+ * 05/14/2006                  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 *Redirect = NULL;
+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 doredirect, (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("Redirect: %s\n", Redirect == NULL ? "" : Redirect);
+       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], "redirect")) s = doredirect(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 doredirect(parms, np)
+char *parms[];
+int np;
+{
+char *redir;
+
+   if(np < 2) return(0);
+
+   redir = subvpath(parms[1]);
+
+   Redirect = malloc(strlen(redir)+1);
+   if(Redirect == NULL) {
+       fprintf(stderr, "httpd: malloc failed in doredirect\n");
+       return(-1);
+   }
+   strcpy(Redirect, redir);
+   if(Redirect[strlen(Redirect)-1] == '/')
+       Redirect[strlen(Redirect)-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);
+}
diff --git a/commands/httpd0995/config.h b/commands/httpd0995/config.h
new file mode 100644 (file)
index 0000000..7beeb83
--- /dev/null
@@ -0,0 +1,86 @@
+/* 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 <asw@woodhull.com>  
+ * 02/08/2005                  Michael Temari <Michael@TemWare.Com>
+ * 05/14/2006                  Michael Temari <Michael@TemWare.Com>
+ *
+ */
+
+#define VERSION  "Minix httpd 0.995"
+
+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 *Redirect;
+extern char *LogFile;
+extern char *DbgFile;
+extern char *User;
+extern char *Chroot;
diff --git a/commands/httpd0995/dir2html.c b/commands/httpd0995/dir2html.c
new file mode 100644 (file)
index 0000000..36634d6
--- /dev/null
@@ -0,0 +1,187 @@
+/* dir2html.c by Michael Temari 3/3/96 */
+
+#include <sys/types.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <dirent.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/stat.h>
+
+typedef struct namelist {      /* Obviously a list of names. */
+       struct namelist *next;
+       char            name[1];
+} namelist_t;
+
+_PROTOTYPE(static void sort, (namelist_t **anl));
+_PROTOTYPE(static namelist_t *collect, (char *dir));
+_PROTOTYPE(int main, (int argc, char *argv[]));
+
+static void sort(anl)
+namelist_t **anl;
+/* A stable mergesort disguised as line noise.  Must be called like this:
+ *     if (L != NULL && L->next != NULL) sort(&L);
+ */
+{
+    /* static */ namelist_t *nl1, **mid;  /* Need not be local */
+    namelist_t *nl2;
+
+    nl1 = *(mid = &(*anl)->next);
+    do {
+       if ((nl1 = nl1->next) == NULL) break;
+       mid = &(*mid)->next;
+    } while ((nl1 = nl1->next) != NULL);
+
+    nl2 = *mid;
+    *mid = NULL;
+
+    if ((*anl)->next != NULL) sort(anl);
+    if (nl2->next != NULL) sort(&nl2);
+
+    nl1 = *anl;
+    for (;;) {
+       if (strcmp(nl1->name, nl2->name) <= 0) {
+           if ((nl1 = *(anl = &nl1->next)) == NULL) {
+               *anl = nl2;
+               break;
+           }
+       } else {
+           *anl = nl2;
+           nl2 = *(anl = &nl2->next);
+           *anl = nl1;
+           if (nl2 == NULL) break;
+       }
+    }
+}
+
+static namelist_t *collect(dir)
+char *dir;
+/* Return a sorted list of directory entries.  Returns null with errno != 0
+ * on error.
+ */
+{
+    namelist_t *names, **pn = &names;
+    DIR *dp;
+    struct dirent *entry;
+
+    if ((dp = opendir(dir)) == NULL) return NULL;
+
+    while ((entry = readdir(dp)) != NULL) {
+       if (strcmp(entry->d_name, ".") == 0) continue;
+       *pn = malloc(offsetof(namelist_t, name) + strlen(entry->d_name) + 1);
+       if (*pn == NULL) {
+           closedir(dp);
+           errno = ENOMEM;
+           return NULL;
+       }
+       strcpy((*pn)->name, entry->d_name);
+       pn = &(*pn)->next;
+    }
+    closedir(dp);
+    *pn = NULL;
+    if (names != NULL && names->next != NULL) sort(&names);
+    errno = 0;
+    return names;
+}
+
+int main(argc, argv)
+int argc;
+char *argv[];
+{
+    namelist_t *np;
+    char *rpath, *vpath;
+    static char cwd[1024];
+    static char work[64];
+    char *filename;
+    struct stat st;
+    struct tm *tmp;
+    static char month[][4] = {
+       "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+       "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+    };
+
+    if(argc > 1) {
+       rpath = argv[1];
+       if (chdir(rpath) < 0) {
+           fprintf(stderr, "dir2html: %s: %s\n", rpath, strerror(errno));
+           return(-1);
+       }
+    } else {
+       if(getcwd(cwd, sizeof(cwd)) == NULL) {
+           fprintf(stderr, "dir2html: getcwd(): %s", strerror(errno));
+           return(-1);
+       }
+       rpath = cwd;
+    }
+
+    if(argc > 2) {
+       vpath = argv[2];
+    } else {
+       vpath = rpath;
+    }
+
+    if ((np = collect(".")) == NULL && errno != 0) {
+       fprintf(stderr, "dir2html: %s: %s\n", vpath, strerror(errno));
+       return(-1);
+    }
+
+    printf("<HTML><HEAD><TITLE>Index of %s</TITLE></HEAD>\n", vpath);
+    printf("<BODY>\n");
+    printf("<H1>Index of %s</H1>\n", vpath);
+
+    printf("<PRE>\n");
+    printf("%-22s  %-17s  %s\n", "Name", "Last modified", "Size/Type");
+    printf("<HR>\n");
+
+    while (np != NULL) {
+       errno = 0;
+       filename = np->name;
+       np= np->next;
+
+       if (stat(filename, &st) < 0) continue;
+
+       printf("<A HREF=\"%s%s\">",
+           filename, S_ISDIR(st.st_mode) ? "/" : "");
+       sprintf(work, "%.23s%s",
+           filename, S_ISDIR(st.st_mode) ? "/" : "");
+       if (strcmp(filename, "..") == 0) strcpy(work, "Parent Directory");
+       printf("%-22.22s%s</A>",
+           work, strlen(work) > 22 ? "&gt;" : " ");
+       tmp = localtime(&st.st_mtime);
+       printf(" %02d %s %d %02d:%02d",
+           tmp->tm_mday, month[tmp->tm_mon], 1900+tmp->tm_year,
+           tmp->tm_hour, tmp->tm_min);
+       if (S_ISREG(st.st_mode)) {
+           if (st.st_size < 10240) {
+               sprintf(work, "%lu ", (unsigned long) st.st_size);
+           } else
+           if (st.st_size < 10240 * 1024L) {
+               sprintf(work, "%luK",
+                   ((unsigned long) st.st_size - 1) / 1024 + 1);
+           } else {
+               sprintf(work, "%luM",
+                   ((unsigned long) st.st_size - 1) / (1024 * 1024L) + 1);
+           }
+       } else {
+           strcpy(work,
+               S_ISDIR(st.st_mode) ? "[dir]" :
+               S_ISBLK(st.st_mode) ? "[block]" :
+               S_ISCHR(st.st_mode) ? "[char]" :
+               S_ISFIFO(st.st_mode) ? "[pipe]" :
+                                       "[???]");
+       }
+       printf(" %8s\n", work);
+    }
+
+    printf("</PRE>\n");
+
+    printf("<HR>\n");
+    printf("<SMALL><i>Minix httpd 0.99</i></SMALL>\n");
+    printf("</BODY>\n");
+    printf("</HTML>\n");
+
+    return(0);
+}
diff --git a/commands/httpd0995/dir2html.sh b/commands/httpd0995/dir2html.sh
new file mode 100755 (executable)
index 0000000..5a4b101
--- /dev/null
@@ -0,0 +1,42 @@
+# dir2html.sh by Michael Temari 03/03/96
+#
+#!/bin/sh
+if [ $# != 0 ]
+then
+cd $1
+fi
+dname=`pwd`
+fdname=$2
+if [ $dname != / ]
+then
+  dname=${dname}/
+fi
+echo "<HTML>"
+echo "<TITLE>"
+echo Directory of $fdname
+echo "</TITLE>"
+echo "<H1>"
+echo Directory of $fdname
+echo "</H1>"
+echo "<HR>"
+#
+ls $dname |
+{
+while read fname
+do
+lname=$fdname$fname
+echo "<H3>"
+echo -n "<A HREF=\""
+echo -n $lname
+echo -n "\">"
+echo -n $fname
+echo "</A><BR>"
+echo "</H3>"
+done
+}
+echo "<HR>"
+echo "<H6>"
+echo Directory Generated at `date`
+echo "</H6>"
+echo "</HTML>"
+exit 0
diff --git a/commands/httpd0995/http.h b/commands/httpd0995/http.h
new file mode 100644 (file)
index 0000000..bf868f3
--- /dev/null
@@ -0,0 +1,118 @@
+/* http.h
+ *
+ * This file is part of httpd.
+ *
+ * 02/17/1996                  Michael Temari <Michael@TemWare.Com>
+ * 07/07/1996 Initial Release  Michael Temari <Michael@TemWare.Com>
+ * 12/29/2002                  Michael Temari <Michael@TemWare.Com>
+ *
+ */
+
+#define        INDEX_FILE_NAME "index.html"
+
+#define        HTTP_REQUEST_TYPE_SIMPLE        0
+#define        HTTP_REQUEST_TYPE_FULL          1
+#define        HTTP_REQUEST_TYPE_PROXY         2
+
+#define        HTTP_METHOD_UNKNOWN     0
+#define        HTTP_METHOD_OPTIONS     1
+#define        HTTP_METHOD_GET         2
+#define        HTTP_METHOD_HEAD        3
+#define        HTTP_METHOD_POST        4
+#define        HTTP_METHOD_PUT         5
+#define        HTTP_METHOD_PATCH       6
+#define        HTTP_METHOD_COPY        7
+#define        HTTP_METHOD_MOVE        8
+#define        HTTP_METHOD_DELETE      9
+#define        HTTP_METHOD_LINK        10
+#define        HTTP_METHOD_UNLINK      11
+#define        HTTP_METHOD_TRACE       12
+#define        HTTP_METHOD_WRAPPED     13
+
+#define        HTTP_STATUS_OK                  200
+#define        HTTP_STATUS_CREATED             201
+#define        HTTP_STATUS_ACCEPTED            202
+#define        HTTP_STATUS_NO_CONTENT          204
+#define        HTTP_STATUS_MOVED_PERM          301
+#define        HTTP_STATUS_MOVED_TEMP          302
+#define        HTTP_STATUS_NOT_MODIFIED        304
+#define        HTTP_STATUS_USE_PROXY           305
+#define        HTTP_STATUS_BAD_REQUEST         400
+#define        HTTP_STATUS_UNAUTHORIZED        401
+#define        HTTP_STATUS_FORBIDDEN           403
+#define        HTTP_STATUS_NOT_FOUND           404
+#define        HTTP_STATUS_METHOD_NOT_ALLOWED  405
+#define        HTTP_STATUS_PROXY_AUTH_REQRD    407
+#define        HTTP_STATUS_LENGTH_REQUIRED     411
+#define        HTTP_STATUS_SERVER_ERROR        500
+#define        HTTP_STATUS_NOT_IMPLEMENTED     501
+#define        HTTP_STATUS_BAD_GATEWAY         502
+#define        HTTP_STATUS_SERVICE_UNAVAILABLE 503
+#define        HTTP_STATUS_GATEWAY_TIMEOUT     504
+#define        HTTP_STATUS_UNSUPPORTED_VERSION 505
+
+struct http_request {
+       int type;
+       int method;
+       char uri[256];
+       char url[256];
+       char query[256];
+       char host[256];
+       int port;
+       char useragent[256];
+       int vmajor;
+       int vminor;
+       time_t ifmodsince;
+       off_t size;
+       time_t msgdate;
+       int keepopen;
+       char wwwauth[128];
+       char authuser[128];
+       char authpass[128];
+       char cookie[128];
+};
+
+struct http_reply {
+       int status;
+       char statusmsg[128];
+       int keepopen;
+       int headers;
+       char *mtype;
+       char realurl[256];
+       struct auth *auth;
+       int urlaccess;
+       off_t size;
+       time_t modtime;
+       int fd;
+       int ofd;
+       int pid;
+};
+
+/* from httpd.c */
+
+extern FILE *stdlog;
+extern FILE *dbglog;
+
+/* from reply.c */
+
+_PROTOTYPE(int sendreply, (struct http_reply *rp, struct http_request *rq));
+
+/* from request.c */
+
+_PROTOTYPE(int getrequest, (struct http_request *rq));
+
+/* from process.c */
+
+_PROTOTYPE(int processrequest, (struct http_request *rq, struct http_reply *rp));
+
+/* from police.c */
+
+_PROTOTYPE(int police, (struct http_request *rq, struct http_reply *rp));
+
+/* from cgiexec.c */
+
+_PROTOTYPE(int cgiexec, (struct http_request *rq, struct http_reply *rp));
+
+/* from proxy.c */
+
+_PROTOTYPE(void proxy, (struct http_request *rq, struct http_reply *rp));
diff --git a/commands/httpd0995/http_status.5 b/commands/httpd0995/http_status.5
new file mode 100644 (file)
index 0000000..5301a57
--- /dev/null
@@ -0,0 +1,72 @@
+.TH HTTP_STATUS 5
+.SH NAME
+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.woodhull.com/http11.html#Status-Codes
+.SH AUTHOR
+The Minix httpd server was created by and is maintained by Michael Temari 
+<Michael@TemWare.Com>
+.P
+Man page compiled by Al Woodhull <asw@woodhull.com>
+.\"updated 2006-06-01
diff --git a/commands/httpd0995/httpd.8 b/commands/httpd0995/httpd.8
new file mode 100644 (file)
index 0000000..04fed2a
--- /dev/null
@@ -0,0 +1,124 @@
+.TH HTTPD 8
+.SH NAME
+httpd, in.httpd, dir2html \- a web server for Minix 2 and Minix 3
+.SH SYNOPSIS
+.B httpd
+.RB [\-t|\-v]
+.RI [ config_file ]
+.P
+.B "tcpd http /usr/local/bin/in.httpd &"
+.P 
+.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 (8),  
+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 enable  
+.B in.httpd
+to start you use (in a startup script):
+.P
+.B  "tcpd http /usr/local/bin/in.httpd &"
+.P
+or
+.P
+.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).
+To enable or reenable  
+.B in.httpd
+from the command line a user a system administrator should use 
+.B intr (8),
+like this:
+.P
+.B "intr -d tcpd http /usr/local/bin/in.httpd &"
+.P
+to start 
+.B tcpd
+as a daemon (getting input from /dev/null, writing output to /dev/log,
+and not part of a process group).
+.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.
+.TP
+.B 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 http_status (5),
+.BR serv.access (5),
+.BR intr (8),
+.BR tcpd (8).
+.SH NOTES
+This server has been tested on both Minix 2 and Minix 3.
+.P
+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.
+.P
+The 
+.B tcpd (8)
+man page needs to be written. The important thing to know is that if
+the access control file
+.B /etc/serv.access
+exists tcpd will exec its paranoid twin, tcpdp, which will deny access from
+any IP for which a name cannot be found.
+.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>
+.P
+This man page was compiled by Al Woodhull <asw@woodhull.com>
+.P
+.\" updated 2006-06-17
+
diff --git a/commands/httpd0995/httpd.c b/commands/httpd0995/httpd.c
new file mode 100644 (file)
index 0000000..bbe7672
--- /dev/null
@@ -0,0 +1,175 @@
+/* httpd.c
+ *
+ * httpd       A Server implementing the HTTP protocol.
+ *
+ * usage:      tcpd http httpd &
+ *
+ * 02/17/1996                  Michael Temari <Michael@TemWare.Com>
+ * 07/07/1996 Initial Release  Michael Temari <Michael@TemWare.Com>
+ * 12/29/2002                  Michael Temari <Michael@TemWare.Com>
+ * 07/04/2003                  Al Woodhull <asw@woodhull.com>
+ *
+ */
+
+#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);
+}
diff --git a/commands/httpd0995/httpd.conf b/commands/httpd0995/httpd.conf
new file mode 100644 (file)
index 0000000..78a2d87
--- /dev/null
@@ -0,0 +1,166 @@
+# httpd.conf Sample httpd.conf file By Michael Temari 2006-06-01
+
+#serverroot path
+#
+# path = sets the translation for //
+#
+# these have special meaning if at beginning of path
+#
+# /~user = gets replaced with user home directory
+
+#redirect      http://SomeWhere.Else.Com/
+
+#redirect url
+#
+# url = Will redirect entire website via error code 301 MOVED PERM to
+#       url and original url path of request.
+
+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
diff --git a/commands/httpd0995/httpd.conf.5 b/commands/httpd0995/httpd.conf.5
new file mode 100644 (file)
index 0000000..c8b96c1
--- /dev/null
@@ -0,0 +1,334 @@
+.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 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 redirect user chroot logfile dbgfile dirsend direxec 
+.B vhost auth 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 redirect url
+
+The
+.B redirect 
+directive will redirect the entire website via error code 
+"301 MOVED PERM" to specified url and original path of request.
+
+.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
+      // will 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>
+.P
+Man page was compiled by Al Woodhull <asw@woodhull.com>
+.\" updated 2006-06-01
diff --git a/commands/httpd0995/httpd.mtype b/commands/httpd0995/httpd.mtype
new file mode 100644 (file)
index 0000000..d39335a
--- /dev/null
@@ -0,0 +1,40 @@
+# mime types By Michael Temari 12/29/2002 Ver 0.40
+
+# if a file extension is not found in the configuration below the default
+# mime type will be application/octet-stream.  This default can be changed
+# by entering a line with a mime type only with no extension.
+
+mtype
+       application/octet-stream
+       application/compress            .Z
+       application/msword              .doc
+       application/octet-stream        .bin    .exe
+       application/pdf                 .pdf
+       application/postscript          .ps     .ai     .eps
+       application/smil                .smil
+       application/x-gtar              .gtar
+       application/x-gzip              .gz
+       application/x-sh                .sh
+       application/x-pn-realaudio      .ra     .ram
+       application/x-tar               .tar
+       application/zip                 .zip
+       audio/basic                     .au     .snd
+       audio/mpeg                      .mp3
+       audio/x-aiff                    .aif    .aiff   .aifc
+       audio/x-midi                    .mid
+       audio/x-wav                     .wav
+       image/bmp                       .bmp
+       image/gif                       .gif
+       image/jpeg                      .jpg    .jpeg   .jpe
+       image/png                       .png
+       image/tiff                      .tiff   .tif
+       image/x-rgb                     .rgb
+       image/x-xbitmap                 .xbm
+       multipart/x-www-form-urlencoded .wfu
+       text/html                       .html   .htm
+       text/plain                      .txt    .c      .h
+       text/richtext                   .rtf    .rtx
+       video/mpeg                      .mpg    .mpeg   .mpe
+       video/quicktime                 .qt     .mov
+       video/x-msvideo                 .avi
+       video/x-sgi-movie               .movie
diff --git a/commands/httpd0995/httpd0995.txt b/commands/httpd0995/httpd0995.txt
new file mode 100644 (file)
index 0000000..fc30e9a
--- /dev/null
@@ -0,0 +1,59 @@
+httpd0995 --- A www server for Minix 2 and Minix 3 
+written by Michael Temari <Michael@TemWare.Com> release 0.995 2006-05-14
+
+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.
+
+Earlier versions of this web server were in use for many years on 
+minix1.hampshire.edu and minix1.bio.umass.edu.
+
+Installation: unpack the tarball in /usr/local/src or another directory 
+of your choice:
+
+  zcat < httpd0995.taz | tar xvfp -
+
+An httpd0995 directory will be created and files will be unpacked
+there.  The README file explains compilation, installation,
+configuration, and use. Please also read the SECURITY file if you plan
+to make your system accessible over the net.   
+
+Changes for release 0.995:
+
+- a redirect capability has been added.  If redirect is defined in the 
+configuration file then all request url's will be redirected to that 
+host with the original request. For instance, if in the configuration 
+file of minix1.hampshire.edu this line appears:
+   redirect http://minix1.woodhull.com/
+a request of http://minix1.hampshire.edu/some/page will return a 301 error 
+which is a redirect permanent to: http://minix.woodhull.com/some/page
+
+- several documentation files and man pages have been updated.
+
+Changes for release 0.994:
+
+- calling CGI programs has been made more secure.
+
+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 2006-06-01 (ASW)
diff --git a/commands/httpd0995/net.c b/commands/httpd0995/net.c
new file mode 100644 (file)
index 0000000..4d26385
--- /dev/null
@@ -0,0 +1,240 @@
+/* net.c
+ *
+ * This file is part of httpd.
+ *
+ * 01/25/1996                  Michael Temari <Michael@TemWare.Com>
+ * 07/07/1996 Initial Release  Michael Temari <Michael@TemWare.Com>
+ * 12/29/2002                  Michael Temari <Michael@TemWare.Com>
+ *
+ */
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+#include <net/netlib.h>
+#include <net/hton.h>
+#include <net/gen/in.h>
+#include <net/gen/inet.h>
+#include <net/gen/tcp.h>
+#include <net/gen/tcp_io.h>
+#include <net/gen/socket.h>
+#include <net/gen/netdb.h>
+
+#include "net.h"
+
+_PROTOTYPE(static void release, (int *fd));
+
+ipaddr_t myipaddr, rmtipaddr;
+tcpport_t myport, rmtport;
+char myhostname[256];
+char rmthostname[256];
+char rmthostaddr[3+1+3+1+3+1+3+1];
+
+void GetNetInfo()
+{
+nwio_tcpconf_t tcpconf;
+int s;
+struct hostent *hostent;
+
+   /* Ask the system what our hostname is. */
+   if(gethostname(myhostname, sizeof(myhostname)) < 0)
+       strcpy(myhostname, "unknown");
+
+   /* lets get our ip address and the clients ip address */
+   s = ioctl(0, NWIOGTCPCONF, &tcpconf);
+   if(s < 0) {
+       myipaddr = 0;
+       myport = 0;
+       rmtipaddr = 0;
+       rmtport = 0;
+       strcpy(rmthostname, "??Unknown??");
+       strcpy(rmthostaddr, "???.???.???.???");
+       return;
+   }
+
+   myipaddr = tcpconf.nwtc_locaddr;
+   myport = tcpconf.nwtc_locport;
+   rmtipaddr = tcpconf.nwtc_remaddr;
+   rmtport = tcpconf.nwtc_remport;
+
+   /* Look up the host name of the remote host. */
+   hostent = gethostbyaddr((char *) &rmtipaddr, sizeof(rmtipaddr), AF_INET);
+   if(!hostent)
+       strncpy(rmthostname, inet_ntoa(rmtipaddr), sizeof(rmthostname)-1);
+   else
+       strncpy(rmthostname, hostent->h_name, sizeof(rmthostname)-1);
+
+   strcpy(rmthostaddr, inet_ntoa(rmtipaddr));
+
+   rmthostname[sizeof(rmthostname)-1] = '\0';
+
+   return;
+}
+
+static void release(fd)
+int *fd;
+{
+   if(*fd != -1) {
+       close(*fd);
+       *fd= -1;
+   }
+}
+
+void daemonloop(service)
+char *service;
+{
+tcpport_t port;
+struct nwio_tcpcl tcplistenopt;
+struct nwio_tcpconf tcpconf;
+struct nwio_tcpopt tcpopt;
+struct servent *servent;
+char *tcp_device;
+int tcp_fd, client_fd, r;
+int pfd[2];
+unsigned stall= 0;
+
+   if((servent= getservbyname(service, "tcp")) == NULL) {
+       unsigned long p;
+       char *end;
+
+       p = strtoul(service, &end, 0);
+       if(p <= 0 || p > 0xFFFF || *end != 0) {
+               fprintf(stderr, "httpd: %s: Unknown service\n", service);
+               exit(1);
+       }
+       port= htons((tcpport_t) p);
+   } else
+       port= servent->s_port;
+
+   /* No client yet. */
+   client_fd= -1;
+
+   while (1) {
+       if((tcp_device = getenv("TCP_DEVICE")) == NULL)
+               tcp_device = TCP_DEVICE;
+       if ((tcp_fd= open(tcp_device, O_RDWR)) < 0) {
+                       fprintf(stderr, "httpd: Can't open %s: %s",
+                               tcp_device, strerror(errno));
+                       if (errno == ENOENT || errno == ENODEV
+                                                       || errno == ENXIO) {
+                               exit(1);
+                       }
+                       goto bad;
+               }
+
+               tcpconf.nwtc_flags= NWTC_LP_SET | NWTC_UNSET_RA | NWTC_UNSET_RP;
+               tcpconf.nwtc_locport= port;
+
+               if (ioctl(tcp_fd, NWIOSTCPCONF, &tcpconf) < 0) {
+                       fprintf(stderr, "httpd: Can't configure TCP channel",
+                               strerror(errno));
+                       exit(1);
+               }
+
+#ifdef NWTO_DEL_RST
+               tcpopt.nwto_flags= NWTO_DEL_RST;
+
+               if (ioctl(tcp_fd, NWIOSTCPOPT, &tcpopt) < 0) {
+                       fprintf(stderr, "httpd: Can't set TCP options",
+                               strerror(errno));
+                       exit(1);
+               }
+#endif
+
+               if (client_fd != -1) {
+                       /* We have a client, so start a server for it. */
+
+#ifdef NWTO_DEL_RST
+                       tcpopt.nwto_flags= 0;
+                       (void) ioctl(client_fd, NWIOSTCPOPT, &tcpopt);
+#endif
+
+                       fflush(NULL);
+
+                       /* Create a pipe to serve as an error indicator. */
+                       if (pipe(pfd) < 0) {
+                               fprintf(stderr, "httpd: pipe", strerror(errno));
+                               goto bad;
+                       }
+
+                       /* Fork twice to daemonize child. */
+                       switch (fork()) {
+                       case -1:
+                               fprintf(stderr, "httpd: fork", strerror(errno));
+                               close(pfd[0]);
+                               close(pfd[1]);
+                               goto bad;
+                       case 0:
+                               close(tcp_fd);
+                               close(pfd[0]);
+                               switch (fork()) {
+                               case -1:
+                                       fprintf(stderr, "httpd: fork",
+                                               strerror(errno));
+                                       write(pfd[1], &errno, sizeof(errno));
+                                       exit(1);
+                               case 0:
+                                       break;
+                               default:
+                                       exit(0);
+                               }
+                               dup2(client_fd, 0);
+                               dup2(client_fd, 1);
+                               close(client_fd);
+                               close(pfd[1]);
+
+                               /* Break out of the daemon loop, continuing with
+                                * the normal httpd code to serve the client.
+                                */
+                               return;
+
+                       default:
+                               release(&client_fd);
+                               close(pfd[1]);
+                               wait(NULL);
+                               r= read(pfd[0], &errno, sizeof(errno));
+                               close(pfd[0]);
+                               if (r != 0) goto bad;
+                               break;
+                       }
+               }
+
+               /* Wait for a new connection. */
+               tcplistenopt.nwtcl_flags= 0;
+
+               while (ioctl(tcp_fd, NWIOTCPLISTEN, &tcplistenopt) < 0) {
+                       if (errno != EAGAIN) {
+                               fprintf(stderr, "httpd: Unable to listen: %s",
+                                       strerror(errno));
+                       }
+                       goto bad;
+               }
+
+               /* We got a connection. */
+               client_fd= tcp_fd;
+               tcp_fd= -1;
+
+               /* All is well, no need to stall. */
+               stall= 0;
+               continue;
+
+       bad:
+               /* All is not well, release resources. */
+               release(&tcp_fd);
+               release(&client_fd);
+
+               /* Wait a bit if this happens more than once. */
+               if (stall != 0) {
+                       sleep(stall);
+                       stall <<= 1;
+               } else {
+                       stall= 1;
+               }
+       }
+}
diff --git a/commands/httpd0995/net.h b/commands/httpd0995/net.h
new file mode 100644 (file)
index 0000000..255fd05
--- /dev/null
@@ -0,0 +1,17 @@
+/* net.h
+ *
+ * This file is part of httpd.
+ *
+ *
+ * 01/25/1996                  Michael Temari <Michael@TemWare.Com>
+ * 07/07/1996 Initial Release  Michael Temari <Michael@TemWare.Com>
+ * 12/29/2002                  Michael Temari <Michael@TemWare.Com>
+ *
+ */
+
+_PROTOTYPE(void GetNetInfo, (void));
+_PROTOTYPE(void daemonloop, (char *service));
+
+extern char myhostname[256];
+extern char rmthostname[256];
+extern char rmthostaddr[3+1+3+1+3+1+3+1];
diff --git a/commands/httpd0995/pass.c b/commands/httpd0995/pass.c
new file mode 100644 (file)
index 0000000..c701132
--- /dev/null
@@ -0,0 +1,213 @@
+/* pass.c
+ *
+ * This file is part of httpd.
+ *
+ * 07/07/1996 Initial Release  Michael Temari <Michael@TemWare.Com>
+ * 12/29/2002                  Michael Temari <Michael@TemWare.Com>
+ *
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <pwd.h>
+#ifdef _MINIX
+#include <minix/minlib.h>
+#endif
+
+#define        STD_PASSWD_FILE "/etc/passwd"
+
+#include "pass.h"
+
+static char buffer[1024];
+static char *pwduser;
+static char *pwdpass;
+static char *pwde[4];
+
+_PROTOTYPE(static int getuser, (char *pwdfile, char *user));
+
+static int getuser(pwdfile, user)
+char *pwdfile;
+char *user;
+{
+FILE *fp;
+char *p;
+int i;
+
+   if((fp = fopen(pwdfile, "r")) == (FILE *)NULL)
+       return(-1);
+
+   for(i = 0; i < 4; i ++) pwde[i] = "";
+
+   while(1) {
+       if(fgets(buffer, sizeof(buffer), fp) == (char *)NULL) {
+               fclose(fp);
+               return(-1);
+       }
+       p = buffer;
+       pwduser = p;
+       while(*p && *p != ':') p++;
+       if(*p != ':') continue;
+       *p++ = '\0';
+       if(strcmp(pwduser, user)) continue;
+       pwdpass = p;
+       while(*p && *p != ':' && *p != '\r' && *p != '\n') p++;
+       if(*p == ':')
+               *p++ = '\0';
+       else {
+               if(*p) *p = '\0';
+               fclose(fp);
+       }
+       for(i = 0; i < 4; i++) {
+               pwde[i] = p;
+               while(*p && *p != ':' && *p != '\r' && *p != '\n') p++;
+               if(*p == ':')
+                       *p++ = '\0';
+               else {
+                       if(*p) *p = '\0';
+                       break;
+               }
+       }
+       fclose(fp);
+
+       return(0);
+   }
+}
+
+int passfile(pwdfile)
+char *pwdfile;
+{
+FILE *fp;
+
+   if(!strcmp(pwdfile, STD_PASSWD_FILE))
+       return(0);
+
+   if((fp = fopen(pwdfile, "r")) == (FILE *)NULL)
+       return(-1);
+
+   fclose(fp);
+
+   return(0);
+}
+
+int passuser(pwdfile, user)
+char *pwdfile;
+char *user;
+{
+   if(!strcmp(pwdfile, STD_PASSWD_FILE))
+       if(getpwnam(user) == (struct passwd *)NULL)
+               return(-1);
+       else
+               return(0);
+
+   return(getuser(pwdfile, user));
+}
+
+int passnone(pwdfile, user)
+char *pwdfile;
+char *user;
+{
+struct passwd *pwd;
+
+   if(!strcmp(pwdfile, STD_PASSWD_FILE))
+       if((pwd = getpwnam(user)) == (struct passwd *)NULL)
+               return(-1);
+       else
+               if(!strcmp(pwd->pw_passwd, crypt("", pwd->pw_passwd)))
+                       return(-1);
+               else
+                       return(0);
+
+   if(getuser(pwdfile, user))
+       return(-1);
+
+   if(!strcmp(pwdpass, crypt("", pwdpass)))
+       return(-1);
+   else
+       return(0);
+}
+
+int passpass(pwdfile, user, pass)
+char *pwdfile;
+char *user;
+char *pass;
+{
+struct passwd *pwd;
+
+   if(!strcmp(pwdfile, STD_PASSWD_FILE))
+       if((pwd = getpwnam(user)) == (struct passwd *)NULL)
+               return(-1);
+       else
+               if(strcmp(pwd->pw_passwd, crypt(pass, pwd->pw_passwd)))
+                       return(-1);
+               else
+                       return(0);
+
+   if(getuser(pwdfile, user))
+       return(-1);
+
+   if(strcmp(pwdpass, crypt(pass, pwdpass)))
+       return(-1);
+   else
+       return(0);
+}
+
+int passadd(pwdfile, user, pass, e1, e2, e3, e4)
+char *pwdfile;
+char *user;
+char *pass;
+char *e1;
+char *e2;
+char *e3;
+char *e4;
+{
+FILE *fp;
+time_t salt;
+char sl[2];
+int cn;
+char *ee1;
+char *ee2;
+char *ee3;
+char *ee4;
+
+
+   if(pwdfile == (char *)NULL ||
+        user == (char *)NULL ||
+        pass == (char *)NULL)
+       return(PASS_ERROR);
+
+   if(!strcmp(pwdfile, STD_PASSWD_FILE))
+       return(PASS_ERROR);
+
+   if(!getuser(pwdfile, user))
+       return(PASS_USEREXISTS);
+
+   time(&salt);
+   sl[0] = (salt & 077) + '.';
+   sl[1] = ((salt >> 6) & 077) + '.';
+   for (cn = 0; cn < 2; cn++) {
+       if (sl[cn] > '9') sl[cn] += 7;
+       if (sl[cn] > 'Z') sl[cn] += 6;
+   }
+
+   if(e1 == (char *)NULL) ee1 = ""; else ee1 = e1;
+   if(e2 == (char *)NULL) ee2 = ""; else ee2 = e2;
+   if(e3 == (char *)NULL) ee3 = ""; else ee3 = e3;
+   if(e4 == (char *)NULL) ee4 = ""; else ee4 = e4;
+
+   /* XXX need to add locking mechanics to add new user */
+
+   if((fp = fopen(pwdfile, "a")) == (FILE *)NULL)
+       return(PASS_ERROR);
+
+   fprintf(fp, "%s:%s:%s:%s:%s:%s\n", user, crypt(pass, sl), ee1, ee2, ee3, ee4);
+
+   fclose(fp);
+
+   /* XXX need to add unlocking mechanics to add new user */
+
+   return(PASS_GOOD);
+}
diff --git a/commands/httpd0995/pass.h b/commands/httpd0995/pass.h
new file mode 100644 (file)
index 0000000..22a4e1d
--- /dev/null
@@ -0,0 +1,18 @@
+/* pass.h
+ *
+ * This file is part of httpd.
+ *
+ * 07/07/1996 Initial Release  Michael Temari <Michael@TemWare.Com>
+ * 12/29/2002 Initial Release  Michael Temari <Michael@TemWare.Com>
+ *
+ */
+
+_PROTOTYPE(int passfile, (char *pwdfile));
+_PROTOTYPE(int passuser, (char *pwdfile, char *user));
+_PROTOTYPE(int passnone, (char *pwdfile, char *user));
+_PROTOTYPE(int passpass, (char *pwdfile, char *user, char *pass));
+_PROTOTYPE(int passadd,  (char *pwdfile, char *user, char *pass, char *e1, char *e2, char *e3, char *e4));
+
+#define        PASS_GOOD       0
+#define        PASS_USEREXISTS 1
+#define        PASS_ERROR      -1      
diff --git a/commands/httpd0995/police.c b/commands/httpd0995/police.c
new file mode 100644 (file)
index 0000000..b71af83
--- /dev/null
@@ -0,0 +1,407 @@
+/* police.c
+ *
+ * This file is part of httpd.
+ *
+ * 02/17/1996                  Michael Temari <Michael@TemWare.Com>
+ * 07/07/1996 Initial Release  Michael Temari <Michael@TemWare.Com>
+ * 12/29/2002                  Michael Temari <Michael@TemWare.Com>
+ *
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "http.h"
+#include "utility.h"
+#include "config.h"
+#include "pass.h"
+
+#define        MATCH_NONE      0
+#define        MATCH_WILD      1
+#define        MATCH_FULL      2
+
+_PROTOTYPE(static int authaccess, (struct http_request *rq, struct http_reply *rp));
+_PROTOTYPE(static void purl, (struct http_request *rq, struct http_reply *rp));
+_PROTOTYPE(static char *virt, (char *to, char *host));
+
+static int authaccess(rq, rp)
+struct http_request *rq;
+struct http_reply *rp;
+{
+struct auth *auth;
+struct authuser *pu;
+
+   /* set authorization to be checked against */
+   if(rq->type == HTTP_REQUEST_TYPE_PROXY)
+       auth = proxyauth;
+   else
+       auth = rp->auth;
+
+   /* no authorization so no access to anyone */
+   if(auth == NULL) {
+       rp->status = HTTP_STATUS_FORBIDDEN;
+       strcpy(rp->statusmsg, "No Authoriation");
+       return(-1);
+   }
+
+   /* access must be R for PROXY */
+   if(rq->type == HTTP_REQUEST_TYPE_PROXY)
+       if(!(auth->urlaccess & URLA_READ)) {
+               rp->status = HTTP_STATUS_FORBIDDEN;
+               strcpy(rp->statusmsg, "Proxy not authorized");
+               return(-1);
+       }
+
+   /* no password file so it is a free for all */
+   if(auth->passwdfile == NULL)
+       return(0);
+
+   /* they did not give us an authorized user */
+   if(rq->authuser[0] == '\0') {
+       if(rq->type == HTTP_REQUEST_TYPE_PROXY)
+               rp->status = HTTP_STATUS_PROXY_AUTH_REQRD;
+       else
+               rp->status = HTTP_STATUS_UNAUTHORIZED;
+       strcpy(rp->statusmsg, "No Authorized User Given");
+       return(-1);
+   }
+
+   /* check if user okay */
+   pu = auth->users;
+   if(pu == NULL)
+       ;       /* no user list we allow anyone in file */
+   else {
+       while(pu != NULL) {
+               if(!strcmp(pu->user, rq->authuser))
+                       break;
+               pu = pu->next;
+       }
+       /* user is not in list so no access */
+       if(pu == NULL) {
+               if(rq->type == HTTP_REQUEST_TYPE_PROXY)
+                       rp->status = HTTP_STATUS_PROXY_AUTH_REQRD;
+               else
+                       rp->status = HTTP_STATUS_UNAUTHORIZED;
+               strcpy(rp->statusmsg, "Forbidden User not authorized");
+               return(-1);
+       }
+   }
+
+   /* check if password file exists, if not no access */
+   if(passfile(auth->passwdfile)) {
+       rp->status = HTTP_STATUS_FORBIDDEN;
+       strcpy(rp->statusmsg, "Invalid passwd file");
+       return(-1);
+   }
+
+   /* check if user in password file, if not no access */
+   if(passuser(auth->passwdfile, rq->authuser)) {
+       if(rq->type == HTTP_REQUEST_TYPE_PROXY)
+               rp->status = HTTP_STATUS_PROXY_AUTH_REQRD;
+       else
+               rp->status = HTTP_STATUS_UNAUTHORIZED;
+       strcpy(rp->statusmsg, "Forbidden Bad User");
+       return(-1);
+   }
+
+   /* check if a password exists, if not no access */
+   if(passnone(auth->passwdfile, rq->authuser)) {
+       if(rq->type == HTTP_REQUEST_TYPE_PROXY)
+               rp->status = HTTP_STATUS_PROXY_AUTH_REQRD;
+       else
+               rp->status = HTTP_STATUS_UNAUTHORIZED;
+       strcpy(rp->statusmsg, "Forbidden no password");
+       return(-1);
+   }
+
+   /* check if password matches, if not no access */
+   if(passpass(auth->passwdfile, rq->authuser, rq->authpass)) {
+       if(rq->type == HTTP_REQUEST_TYPE_PROXY)
+               rp->status = HTTP_STATUS_PROXY_AUTH_REQRD;
+       else
+               rp->status = HTTP_STATUS_UNAUTHORIZED;
+       strcpy(rp->statusmsg, "Forbidden bad password");
+       return(-1);
+   }
+
+   /* whew, all the checks passed so I guess we let them have it */
+   return(0);
+}
+
+int police(rq, rp)
+struct http_request *rq;
+struct http_reply *rp;
+{
+int size;
+struct stat st;
+struct dirsend *ds;
+
+   purl(rq, rp);
+
+   rp->mtype = "text/html";
+
+#ifdef DEBUG
+   fprintf(stderr, "httpd: Trying %s\n", rp->realurl);
+#endif
+
+   /* now check authorizations */
+   if(authaccess(rq, rp)) {
+       /* Don't give them any details why authorization failed */
+       strcpy(rp->statusmsg, "No Access Granted");
+       return(0);
+   }
+
+   /* a proxy request only needs an authorization check */
+   if(rq->type == HTTP_REQUEST_TYPE_PROXY)
+       return(0);
+
+   /* check access to real url */
+   if(stat(rp->realurl, &st)) {
+       if(errno == EACCES)
+               rp->status = HTTP_STATUS_FORBIDDEN;
+       else
+               rp->status = HTTP_STATUS_NOT_FOUND;
+       strcpy(rp->statusmsg, strerror(errno));
+       /* a PUT and NOT FOUND is okay since we are creating */
+       if(rq->method != HTTP_METHOD_PUT || rp->status != HTTP_STATUS_NOT_FOUND)
+               return(0);
+   }
+
+   /* If it is a directory do the appropriate thang! */
+   if(rq->method == HTTP_METHOD_GET || rq->method == HTTP_METHOD_HEAD)
+   if((st.st_mode & S_IFMT) == S_IFDIR) {
+       if(rq->url[strlen(rq->url) - 1] != '/') {
+               strncat(rq->url, "/", sizeof(rq->url) - strlen(rq->url));
+               rp->status = HTTP_STATUS_MOVED_TEMP;
+               sprintf(rp->statusmsg, "Moved to %s", rq->url);
+               return(0);
+       }
+       size = strlen(rq->url);
+       ds = dirsend;
+       while(ds != NULL) {
+               strncpy(rq->url+size, ds->file, sizeof(rq->url)-size);
+               purl(rq, rp);
+               if(stat(rp->realurl, &st)) {
+                       if(errno == EACCES)
+                               rp->status = HTTP_STATUS_FORBIDDEN;
+                       else
+                       if(errno != ENOENT)
+                               rp->status = HTTP_STATUS_NOT_FOUND;
+               } else
+                       break;
+               if(rp->status != HTTP_STATUS_OK) {
+                       strcpy(rp->statusmsg, strerror(errno));
+                       return(0);
+               }
+               ds = ds->next;
+       }
+       if(ds == NULL) {
+               rq->url[size] = '\0';
+               purl(rq, rp);
+               if(stat(rp->realurl, &st)) {
+                       if(errno == EACCES)
+                               rp->status = HTTP_STATUS_FORBIDDEN;
+                       else
+                               rp->status = HTTP_STATUS_NOT_FOUND;
+                       strcpy(rp->statusmsg, strerror(errno));
+                       return(0);
+               }
+       }
+   }
+
+   if(rq->method == HTTP_METHOD_PUT && !(rp->urlaccess & URLA_WRITE)) {
+       rp->status = HTTP_STATUS_METHOD_NOT_ALLOWED;
+       strcpy(rp->statusmsg, "Method not allowed");
+       return(0);
+   }
+
+   if(rp->status == HTTP_STATUS_OK) {
+       /* Here is where we check if it is a program or script to run */
+       if(cgiexec(rq, rp))
+               return(0);
+
+       if((st.st_mode & S_IFMT) == S_IFDIR) {
+               rp->status = HTTP_STATUS_NOT_FOUND;
+               strcpy(rp->statusmsg, "Directory listing not available");
+               return(0);
+       }
+
+       if((st.st_mode & S_IFMT) != S_IFREG) {
+               rp->status = HTTP_STATUS_NOT_FOUND;
+               strcpy(rp->statusmsg, "Not a regular file");
+               return(0);
+       }
+   }
+
+   /* open the URL for updating */
+   if(rq->method == HTTP_METHOD_PUT) {
+       rp->status = HTTP_STATUS_OK;
+       strcpy(rp->statusmsg, "OK");
+       rp->ofd = open(rp->realurl, O_WRONLY | O_CREAT | O_TRUNC);
+       if(rp->ofd < 0) {
+               if(errno == EACCES)
+                       rp->status = HTTP_STATUS_FORBIDDEN;
+               else
+                       rp->status = HTTP_STATUS_NOT_FOUND;
+               strcpy(rp->statusmsg, strerror(errno));
+               return(0);
+       }
+       return(0);
+   }
+
+   if(!(rp->urlaccess & URLA_READ)) {
+       rp->status = HTTP_STATUS_FORBIDDEN;
+       strcpy(rp->statusmsg, "No way...");
+       return(0);
+   }
+
+   rp->mtype = mimetype(rp->realurl);
+
+   rp->size = st.st_size;
+   rp->modtime = st.st_mtime;
+
+   /* open the url if it is a file */
+   rp->fd = open(rp->realurl, O_RDONLY);
+   if(rp->fd < 0) {
+       if(errno == EACCES)
+               rp->status = HTTP_STATUS_FORBIDDEN;
+       else
+               rp->status = HTTP_STATUS_NOT_FOUND;
+       strcpy(rp->statusmsg, strerror(errno));
+       return(0);
+   }
+
+   return(0);
+}
+
+static void purl(rq, rp)
+struct http_request *rq;
+struct http_reply *rp;
+{
+struct vpath *pv;
+int gotreal, gotperm;
+char *p;
+int match;
+int len;
+
+   gotreal = 0; gotperm = 0;
+
+#ifdef DEBUG
+   fprintf(stderr, "httpd: Processing url = \"%s\"\n", rq->url);
+#endif
+
+   /* remove any .. references */
+   p = rq->url;
+   while(*p) {
+       while(*p && *p != '/') p++;
+       if(*p != '/') continue;
+       p++;
+       if(*p != '.') continue;
+       p++;
+       if(*p != '.') continue;
+       p++;
+       strcpy(p - 3, p);
+       p = p - 3;
+   }
+
+   for(pv = vpath; pv != NULL; pv = pv->next) {
+       len = strlen(pv->from) - 1;
+       if(pv->from[len] == '*' || pv->from[len] == '$')
+               if(len == 0)
+                       match = MATCH_WILD;
+               else
+                       match = strncmp(rq->url, pv->from, len) ? MATCH_NONE : MATCH_WILD;
+       else
+               if(!strcmp(rq->url, pv->from))
+                       match = MATCH_FULL;
+               else
+                       match = MATCH_NONE;
+#ifdef DEBUG
+       fprintf(stderr, "httpd: Trying \"%s\" %d %d %d %s\n",
+               pv->from, match, gotreal, gotperm, pv->auth->name);
+#endif
+       if(match != MATCH_NONE) {
+               gotperm = 1;
+               rp->auth = pv->auth;
+               if(pv->urlaccess == -1 && rp->auth != NULL)
+                       rp->urlaccess = rp->auth->urlaccess;
+               else
+                       rp->urlaccess = pv->urlaccess;
+               if(strcmp(pv->to, ".")) {
+                       gotreal = 1;
+                       strncpy(rp->realurl, virt(pv->to, rq->host), sizeof(rp->realurl));
+                       rp->realurl[sizeof(rp->realurl)-1] = '\0';
+                       if(match == MATCH_WILD && pv->from[len] != '$') {
+                               strncat(rp->realurl, rq->url+len, sizeof(rp->realurl) - strlen(rp->realurl));
+                               rp->realurl[sizeof(rp->realurl)-1] = '\0';
+                       }
+               }
+       }
+       if(match == MATCH_FULL) break;
+   }
+
+   if(rp->urlaccess == -1) rp->urlaccess = mkurlaccess("");
+
+   if(!gotreal) {
+       strncpy(rp->realurl, rq->url, sizeof(rp->realurl));
+       rp->realurl[sizeof(rp->realurl)-1] = '\0';
+   }
+
+   if(!gotperm)
+       rp->auth = NULL;
+
+#ifdef DEBUG
+   fprintf(stderr, "DEBUG: url = \"%s\"  realurl = \"%s\"  auth = \"%s\"\n",
+       rq->url, rp->realurl, ((rp->auth == NULL) ? "No Access" : rp->auth->name));
+   fprintf(stderr, "DEBUG: query = %s\n", rq->query);
+#endif
+
+   return;
+}
+
+static char *virt(to, host)
+char *to;
+char *host;
+{
+static char vroot[256];
+struct vhost *ph;
+
+#ifdef DEBUG
+fprintf(stderr, "virt: %s %s\n", to, host);
+#endif
+
+   if(vhost == NULL) return(to);
+
+   if(to[0] != '/') return(to);
+   if(to[1] != '/') return(to);
+   if(to[2] != '/') return(to);
+
+   vroot[0] = '\0';
+
+   for(ph = vhost; ph != NULL; ph = ph->next) {
+#ifdef DEBUG
+       fprintf(stderr, "ph: %s %s %s\n", ph->hname, ph->root, vroot);
+#endif
+       if(!strcmp(ph->hname, "*") && vroot[0] == '\0')
+               strncpy(vroot, ph->root, sizeof(vroot));
+       if(!strcasecmp(ph->hname, host)) {
+               strncpy(vroot, ph->root, sizeof(vroot));
+               break;
+       }
+   }
+
+   strncat(vroot, to+3, sizeof(vroot));
+
+#ifdef DEBUG
+   fprintf(stderr, "vroot: %s\n", vroot);
+#endif
+
+   return(vroot);
+}
diff --git a/commands/httpd0995/process.c b/commands/httpd0995/process.c
new file mode 100644 (file)
index 0000000..665fc70
--- /dev/null
@@ -0,0 +1,90 @@
+/* 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>
+ * 05/14/2006                  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;
+
+   if(Redirect != NULL) {
+       rp->status = HTTP_STATUS_MOVED_PERM;
+       strcpy(rp->realurl, Redirect);
+       strcat(rp->realurl, rq->uri);
+       strcpy(rq->url, rp->realurl);
+       return(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);
+}
diff --git a/commands/httpd0995/proxy.c b/commands/httpd0995/proxy.c
new file mode 100644 (file)
index 0000000..d93acee
--- /dev/null
@@ -0,0 +1,292 @@
+/* proxy.c Copyright 2000 by Michael Temari All Rights Reserved */
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <unistd.h>
+#include <time.h>
+#include <net/netlib.h>
+#include <net/hton.h>
+#include <net/gen/in.h>
+#include <net/gen/inet.h>
+#include <net/gen/tcp.h>
+#include <net/gen/tcp_io.h>
+#include <net/gen/socket.h>
+#include <net/gen/netdb.h>
+
+#include "config.h"
+#include "http.h"
+#include "utility.h"
+#include "net.h"
+
+_PROTOTYPE(static int connect, (char *host));
+#if 0
+_PROTOTYPE(static int readline, (char *p, int len));
+#endif
+_PROTOTYPE(static int sendout, (int fd, char *data));
+
+static int connect(host)
+char *host;
+{
+nwio_tcpconf_t tcpconf;
+nwio_tcpcl_t tcpcopt;
+char *tcp_device;
+int netfd;
+ipaddr_t nethost;
+tcpport_t netport = 0;
+struct hostent *hp;
+struct servent *sp;
+char *p;
+int s;
+int tries;
+
+   p = host;
+   while(*p && *p != ':') p++;
+   if(*p == ':') {
+       *p++ = '\0';
+       netport = htons(atoi(p));
+   }
+
+   if((hp = gethostbyname(host)) == (struct hostent *)NULL) {
+       fprintf(stderr, "Unknown host %s!\n", host);  
+       return(-1);
+   } else
+       memcpy((char *) &nethost, (char *) hp->h_addr, hp->h_length);
+
+   /* Now, to which port must we connect? */
+   if(netport == 0)
+       if((sp = getservbyname("http", "tcp")) == (struct servent *)NULL) {
+               fprintf(stderr, "HTTP port is unknown????\n");
+               return(-1);
+       } else
+               netport = sp->s_port;
+
+   /* Connect to the host */
+   if((tcp_device = getenv("TCP_DEVICE")) == NULL)
+       tcp_device = TCP_DEVICE;
+
+   if((netfd = open(tcp_device, O_RDWR)) < 0) {
+       perror("httpget: opening tcp");
+       return(-1);
+   }
+
+   tcpconf.nwtc_flags = NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP;
+   tcpconf.nwtc_remaddr = nethost;
+   tcpconf.nwtc_remport = netport;
+
+   s = ioctl(netfd, NWIOSTCPCONF, &tcpconf);
+   if(s < 0) {
+       perror("httpget: NWIOSTCPCONF");
+       close(netfd);
+       return(-1);
+   }
+
+   s = ioctl(netfd, NWIOGTCPCONF, &tcpconf);
+   if(s < 0) {
+       perror("httpget: NWIOGTCPCONF");
+       close(netfd);
+       return(-1);
+   }
+
+   tcpcopt.nwtcl_flags = 0;
+
+   tries = 0;
+   do {
+       s = ioctl(netfd, NWIOTCPCONN, &tcpcopt);
+       if(s == -1 && errno == EAGAIN) {
+               if(tries++ >= 10)
+                       break;
+               sleep(10);
+       } else
+               break;
+   } while(1);
+
+   if(s < 0) {
+       perror("httpget: NWIOTCPCONN");
+       close(netfd);
+       return(-1);
+   }
+
+   return(netfd);
+}
+
+char buffer[8192];
+
+#if 0
+static int readline(p, len)
+char *p;
+int len;
+{
+int c;
+int cr = 0;
+int n = 0;
+
+   len--;
+   if(len < 0) return(-1);
+   while(len > 0 && (c = getchar()) != EOF) {
+       if(c == '\n' && cr) {
+               *p = '\0';
+               return(n);
+       }
+       if(c == '\r') {
+               cr = 1;
+               continue;
+       }
+       n++;
+       *p++ = c;
+   }
+   *p = '\0';
+   return(n);
+}
+#endif
+
+static int sendout(fd, data)
+int fd;
+char *data;
+{
+   if(strlen(data) > 0)
+       write(fd, data, strlen(data));
+       write(fd, "\r\n", 2);
+       if(dbglog != (FILE *)NULL) {
+               fprintf(dbglog, "REPLY: %s\n", data);
+       fflush(dbglog);
+   }
+
+   return(0);
+}
+
+void proxy(rq, rp)
+struct http_request *rq;
+struct http_reply *rp;
+{
+int s;
+char *p;
+char *ps;
+char *b;
+char *host;
+static char user[256];
+static char pass[256];
+char *url;
+char *at;
+int fd;
+int bad;
+
+   while(1) {
+       bad = 0;
+       p = rq->uri;
+       if(tolower(*p++) != 'h') bad++;
+       if(tolower(*p++) != 't') bad++;
+       if(tolower(*p++) != 't') bad++;
+       if(tolower(*p++) != 'p') bad++;
+       if(tolower(*p++) != ':') bad++;
+       if(tolower(*p++) != '/') bad++;
+       if(tolower(*p++) != '/') bad++;
+       if(bad) {
+               sprintf(buffer, "HTTP/%d.%d 400 Bad Request",
+                       rq->vmajor, rq->vminor);
+               sendout(1, buffer);
+               sendout(1, "");
+               sendout(1, "Proxy Request was not http:");
+               return;
+       }
+       host = p;
+       while(*p && *p != '/') p++;
+       url = p;
+       *url = '\0';
+       at = strchr(host, '@');
+       if(at != (char *)NULL) {
+               *at = '\0';
+               p = host;
+               while(*p && *p != ':') p++;
+               if(*p)
+                       *p++ = '\0';
+               strcpy(user, host);
+               strcpy(pass, p);
+               host = at + 1;
+       } else {
+               user[0] = '\0';
+               pass[0] = '\0';
+       }
+
+       fd = connect(host);
+       if(fd < 0) {
+               sprintf(buffer, "HTTP/%d.%d 400 Bad Request",
+                       rq->vmajor, rq->vminor);
+               sendout(1, buffer);
+               sendout(1, "");
+               sendout(1, "Could not connect to host");
+               return;
+       }
+       if(rq->method == HTTP_METHOD_GET)
+               write(fd, "GET ", 4); else
+       if(rq->method == HTTP_METHOD_POST)
+               write(fd, "POST ", 5);
+       *url = '/';
+       if(strlen(url) > 0)
+               write(fd, url, strlen(url));
+       write(fd, " ", 1);
+       sprintf(buffer, "HTTP/%d.%d", rq->vmajor, rq->vminor);
+       sendout(fd, buffer);
+       if(rq->ifmodsince != -1) {
+               write(fd, "If-Mod-Since: ", 14);
+               sendout(fd, httpdate(&rq->ifmodsince));
+       }
+       if(rq->size != 0) {
+               sendout(fd, "Content-Type: application/x-www-form-urlencoded");
+               sprintf(buffer, "Content-Length: %lu", rq->size);
+               sendout(fd, buffer);
+       }
+       if(*rq->cookie) {
+               sprintf(buffer, "Cookie: %s", rq->cookie);
+               sendout(fd, buffer);
+       }
+       if(*rq->useragent) {
+               sprintf(buffer, "User-Agent: %s", rq->useragent);
+               sendout(fd, buffer);
+       }
+       if(*rq->host) {
+               sprintf(buffer, "Host: %s", rq->host);
+               sendout(fd, buffer);
+       }
+       if(*rq->wwwauth) {
+               sprintf(buffer, "Authorization: %s", rq->wwwauth);
+               sendout(fd, buffer);
+       }
+       sprintf(buffer, "X-Forwarded-From: %s", rmthostaddr);
+       sendout(fd, buffer);
+       sendout(fd, "");
+       if(rq->size != 0) {
+               if(stdlog != (FILE *)NULL) {
+                       fprintf(stdlog, "%s %s %d %d ",
+                               logdate((time_t *)NULL), rmthostname,
+                               rq->method, rp->status);
+                       fprintf(stdlog, "proxy %s?", rq->uri);
+               }
+               while((s = read(0, buffer, rq->size >
+                       sizeof(buffer) ? sizeof(buffer) : rq->size)) > 0) {
+                       write(fd, buffer, s);
+                       rq->size -= s;
+                       b = buffer;
+                       if(stdlog != (FILE *)NULL)
+                               while(s--) fputc(*b++, stdlog);
+                       if(rq->size == 0) break;
+               }
+               if(stdlog != (FILE *)NULL) {
+                       fprintf(stdlog, "\n");
+                       fflush(stdlog);
+               }
+       }
+       while((s = read(fd, buffer, sizeof(buffer))) > 0) {
+               write(1, buffer, s);
+       }
+       close(fd);
+       return;
+   }
+}
diff --git a/commands/httpd0995/reply.c b/commands/httpd0995/reply.c
new file mode 100644 (file)
index 0000000..ba46535
--- /dev/null
@@ -0,0 +1,189 @@
+/* reply.c
+ *
+ * This file is part of httpd.
+ *
+ * 02/17/1996                  Michael Temari <Michael@TemWare.Com>
+ * 07/07/1996 Initial Release  Michael Temari <Michael@TemWare.Com>
+ * 12/29/2002                  Michael Temari <Michael@TemWare.Com>
+ *
+ */
+#include <sys/types.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+
+#include "http.h"
+#include "utility.h"
+#include "net.h"
+#include "config.h"
+
+#define        SERVER  "Server: "VERSION
+
+_PROTOTYPE(static void GotAlarm, (int sig));
+_PROTOTYPE(static int sendout, (char *data));
+
+static void GotAlarm(sig)
+int sig;
+{
+}
+
+static int sendout(data)
+char *data;
+{
+   if(strlen(data) > 0)
+       write(1, data, strlen(data));
+   write(1, "\r\n", 2);
+   if(dbglog != (FILE *)NULL) {
+       fprintf(dbglog, "REPLY: %s\n", data);
+       fflush(dbglog);
+   }
+
+   return(0);
+}
+
+int sendreply(rp, rq)
+struct http_reply *rp;
+struct http_request *rq;
+{
+int s;
+int s2;
+int e;
+static char buffer[8192];
+
+   if(rq->type != HTTP_REQUEST_TYPE_PROXY)
+   /* We're receiving data from a */
+   if(rq->method == HTTP_METHOD_POST ||
+     (rq->method == HTTP_METHOD_PUT && rp->status == HTTP_STATUS_OK)) {
+       if(rq->type != HTTP_REQUEST_TYPE_FULL)
+               return(0);
+       if(rq->method == HTTP_METHOD_PUT)
+               rp->status = HTTP_STATUS_CREATED;
+       else
+               rp->status = HTTP_STATUS_OK;
+       while(rq->size != 0) {
+               s = read(0, buffer, (rq->size > sizeof(buffer)) ? sizeof(buffer) : rq->size);
+               if(s <= 0) {
+                       rp->status = HTTP_STATUS_SERVER_ERROR;
+                       strcpy(rp->statusmsg, strerror(errno));
+                       close(rp->fd);
+                       close(rp->ofd);
+                       break;
+               }
+               rq->size -= s;
+               s2 = write(rp->ofd, buffer, s);
+               if(s2 != s) break;
+       }
+   }
+
+   if(rp->status != HTTP_STATUS_OK && rp->status != HTTP_STATUS_CREATED &&
+      rp->status != HTTP_STATUS_NOT_MODIFIED)
+       rp->keepopen = 0;
+
+   if(rp->status == HTTP_STATUS_NOT_MODIFIED) {
+       sprintf(buffer, "<h2>Error %03d %s</h2>",
+               rp->status, rp->statusmsg);
+       rp->size = strlen(buffer);
+       rp->keepopen = rq->keepopen;
+   }
+
+   if(!rp->headers) {
+
+   if((rq->type == HTTP_REQUEST_TYPE_PROXY && rp->status != HTTP_STATUS_OK) ||
+       rq->type == HTTP_REQUEST_TYPE_FULL) {
+       sprintf(buffer, "HTTP/%d.%d %03d %s",
+               rq->vmajor, rq->vminor, rp->status, rp->statusmsg);
+       sendout(buffer);
+       sendout(SERVER);
+       if(rp->status == HTTP_STATUS_MOVED_PERM ||
+          rp->status == HTTP_STATUS_MOVED_TEMP) {
+#if 1
+               sprintf(buffer, "Location: %s", rq->url);
+#else
+               sprintf(buffer, "Location: http://%s%s", myhostname, rq->url);
+#endif
+               sendout(buffer);
+       }
+       if(rp->keepopen)
+               sendout("Connection: Keep-Alive");
+       else
+               sendout("Connection: Close");
+       if(rp->status == HTTP_STATUS_UNAUTHORIZED && rp->auth != NULL) {
+               sprintf(buffer, "WWW-Authenticate: Basic realm=\"%s\"", rp->auth->desc);
+               sendout(buffer);
+       }
+       if(rp->status == HTTP_STATUS_PROXY_AUTH_REQRD && proxyauth != NULL) {
+               sprintf(buffer, "Proxy-Authenticate: Basic realm=\"%s\"", proxyauth->desc);
+               sendout(buffer);
+       }
+       if(rp->modtime != (time_t) -1) {
+               sprintf(buffer, "Last-Modified: %s", httpdate(&rp->modtime));
+               sendout(buffer);
+       }
+       if(rp->size != 0) {
+               sprintf(buffer, "Content-Length: %lu", rp->size);
+               sendout(buffer);
+       }
+       if(rp->status == HTTP_STATUS_OK) {
+               sprintf(buffer, "Content-Type: %s", rp->mtype);
+               sendout(buffer);
+       } else
+               sendout("Content-Type: text/html");
+       if(!rp->headers)
+               sendout("");
+   } else
+       if(rp->status != HTTP_STATUS_OK)
+               return(0);
+   }
+
+   if(rp->status != HTTP_STATUS_OK && rp->status != HTTP_STATUS_CREATED) {
+       sprintf(buffer, "<h2>Error %03d %s</h2>",
+               rp->status, rp->statusmsg);
+       sendout(buffer);
+       return(0);
+   }
+
+   if(rq->type == HTTP_REQUEST_TYPE_PROXY) {
+       proxy(rq, rp);
+       return(0);
+   }
+
+   /* send out entity body */
+   if(rq->method == HTTP_METHOD_GET || rq->method == HTTP_METHOD_POST) {
+       errno = 0;
+       while(1) {
+               alarm(0);
+               signal(SIGALRM, GotAlarm);
+               alarm(10);
+               s = read(rp->fd, buffer, sizeof(buffer));
+               e = errno;
+               alarm(0);
+               if(s > 0) {
+                       s2 = write(1, buffer, s);
+                       e = errno;
+                       if(s2 != s) break;
+                       continue;
+               }
+               if(s == 0) break;
+               if(s < 0 && e != EINTR) break;
+               signal(SIGALRM, GotAlarm);
+               alarm(2);
+               s = read(0, buffer, 1);
+               e = errno;
+               alarm(0);
+               if(s < 0 && e != EINTR) break;
+       }
+   }
+
+   close(rp->fd);
+   rp->fd = -1;
+   if(rp->ofd != -1)
+       close(rp->ofd);
+   if(rp->pid != 0 && e != 0) {
+       kill(-rp->pid, SIGHUP);
+       rp->pid = 0;
+   }
+
+   return(0);
+}
diff --git a/commands/httpd0995/request.c b/commands/httpd0995/request.c
new file mode 100644 (file)
index 0000000..2b5b36a
--- /dev/null
@@ -0,0 +1,369 @@
+/* request.c
+ *
+ * This file is part of httpd.
+ *
+ * 02/17/1996                  Michael Temari <Michael@TemWare.Com>
+ * 07/07/1996 Initial Release  Michael Temari <Michael@TemWare.Com>
+ * 12/29/2002                  Michael Temari <Michael@TemWare.Com>
+ *
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <signal.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pwd.h>
+#ifdef _MINIX
+#include <minix/minlib.h>
+#endif
+#include <errno.h>
+
+#include "http.h"
+#include "utility.h"
+#include "config.h"
+
+_PROTOTYPE(static void Timeout, (int sig));
+_PROTOTYPE(static int getline, (char *buffer, int size));
+_PROTOTYPE(static void authorize, (char *p, struct http_request *rq));
+_PROTOTYPE(static void decurl, (char *u));
+
+static int TimeOut;
+
+static void Timeout(sig)
+int sig;
+{
+   TimeOut = 1;
+}
+
+static int getline(buffer, size)
+char *buffer;
+int size;
+{
+char *p;
+int s;
+
+   p = buffer;
+
+   while(p < (buffer + size - 1)) {
+       TimeOut = 0;
+       signal(SIGALRM, Timeout);
+       alarm(5*60);
+       s = read(0, p, 1);
+       alarm(0);
+       if(TimeOut)
+               return(-1);
+       if(s != 1)
+               return(-1);
+       if(*p == '\n') break;
+       p++;
+   }
+   *++p = '\0';
+
+   p = &buffer[strlen(buffer) - 1];
+   if(p >= buffer && (*p == '\r' || *p == '\n')) *p-- ='\0';
+   if(p >= buffer && (*p == '\r' || *p == '\n')) *p-- ='\0';
+
+   return(strlen(buffer));
+}
+
+static void authorize(p, rq)
+char *p;
+struct http_request *rq;
+{
+char *s;
+
+   if(toupper(*p++) == 'B' &&
+      toupper(*p++) == 'A' &&
+      toupper(*p++) == 'S' &&
+      toupper(*p++) == 'I' &&
+      toupper(*p++) == 'C' &&
+      toupper(*p++) == ' ') ;
+   else
+       return;
+
+   s = decode64(p);
+
+   if((p = strchr(s, ':')) == (char *)NULL)
+       p = "";
+   else
+       *p++ = '\0';
+
+   strncpy(rq->authuser, s, sizeof(rq->authuser));
+   strncpy(rq->authpass, p, sizeof(rq->authpass));
+
+   return;
+}
+
+int getrequest(rq)
+struct http_request *rq;
+{
+static char line[4096];
+char *p, *p2, *ps;
+int s, len;
+struct vhost *ph;
+
+   /* get request, it may be simple */
+
+   s = getline(line, sizeof(line));
+   if(s < 0)
+       return(-1);
+
+   if(dbglog != (FILE *)NULL) {
+       fprintf(dbglog, "REQUEST: %s\n", line);
+       fflush(dbglog);
+   }
+
+   /* clear http_request */
+   memset(rq, 0, sizeof(*rq));
+   rq->ifmodsince = (time_t) -1;
+
+   /* assume simple request */
+   rq->type = HTTP_REQUEST_TYPE_SIMPLE;
+
+   /* parse the method */
+   p = line;
+   while(*p && !LWS(*p)) {
+       *p = toupper(*p);
+       p++;
+   }
+   if(*p) *p++ = '\0';
+
+   if(!strcmp(line, "GET"))
+       rq->method = HTTP_METHOD_GET; else
+   if(!strcmp(line, "HEAD"))
+       rq->method = HTTP_METHOD_HEAD; else
+   if(!strcmp(line, "POST"))
+       rq->method = HTTP_METHOD_POST; else
+   if(!strcmp(line, "PUT"))
+       rq->method = HTTP_METHOD_PUT; else
+#if 0
+   if(!strcmp(line, "OPTIONS"))
+       rq->method = HTTP_METHOD_OPTIONS; else
+   if(!strcmp(line, "PATCH"))
+       rq->method = HTTP_METHOD_PATCH; else
+   if(!strcmp(line, "COPY"))
+       rq->method = HTTP_METHOD_COPY; else
+   if(!strcmp(line, "MOVE"))
+       rq->method = HTTP_METHOD_MOVE; else
+   if(!strcmp(line, "DELETE"))
+       rq->method = HTTP_METHOD_DELETE; else
+   if(!strcmp(line, "LINK"))
+       rq->method = HTTP_METHOD_LINK; else
+   if(!strcmp(line, "UNLINK"))
+       rq->method = HTTP_METHOD_UNLINK; else
+   if(!strcmp(line, "TRACE"))
+       rq->method = HTTP_METHOD_TRACE; else
+   if(!strcmp(line, "WRAPPED"))
+       rq->method = HTTP_METHOD_WRAPPED; else
+#endif
+       rq->method = HTTP_METHOD_UNKNOWN;
+
+   /* parse the requested URI */
+   p2 = rq->uri;
+   len = sizeof(rq->uri) - 1;
+   while(*p && !LWS(*p) && len > 0) {
+       *p2++ = *p++;
+       len--;
+   }
+   *p2 = '\0';
+
+   /* eat up any leftovers if uri was too big */
+   while(*p && !LWS(*p))
+       p++;
+
+   /* save for continued processing later */
+   ps = p;
+
+   /* parse the requested URL */
+   p = rq->uri;
+   p2 = rq->url;
+   len = sizeof(rq->url) - 1;
+   while(*p && !LWS(*p) && *p != '?' && len > 0) {
+       *p2++ = *p++;
+       len--;
+   }
+   *p2 = '\0';
+
+   /* See if there is a query string */
+   if(*p == '?') {
+       p++;
+       p2 = rq->query;
+       len = sizeof(rq->query) - 1;
+       while(*p && !LWS(*p) && len > 0) {
+               *p2++ = *p++;
+               len--;
+       }
+   }
+
+   /* eat up any leftovers */
+   while(*p && !LWS(*p)) p++;
+
+   if(rq->url[0] == '\0') {
+       rq->url[0] = '/';
+       rq->url[1] = '\0';
+   }
+
+   /* url is a decoded copy of the uri */
+   decurl(rq->url);
+
+   /* restore and continue processing */
+   p = ps;
+
+   /* if this is true it is a simple request */
+   if(*p == '\0')
+       return(0);
+
+   /* parse HTTP version */
+   while(*p && LWS(*p)) p++;
+   if(toupper(*p++) != 'H') return(0);
+   if(toupper(*p++) != 'T') return(0);
+   if(toupper(*p++) != 'T') return(0);
+   if(toupper(*p++) != 'P') return(0);
+   if(        *p++  != '/') return(0);
+
+   /* version major */
+   rq->vmajor = 0;
+   while((*p >= '0') && (*p <= '9'))
+       rq->vmajor = rq->vmajor * 10 + (*p++ - '0');
+   if(*p != '.')
+       return(0);
+   p++;
+
+   /* version minor */
+   rq->vminor = 0;
+   while((*p >= '0') && (*p <= '9'))
+       rq->vminor = rq->vminor * 10 + (*p++ - '0');
+   if(*p)
+       return(0);
+
+   rq->type = HTTP_REQUEST_TYPE_FULL;
+
+   p = rq->uri;
+
+   /* check if it is a proxy request */
+   if(toupper(*p++) == 'H' &&
+      toupper(*p++) == 'T' &&
+      toupper(*p++) == 'T' &&
+      toupper(*p++) == 'P' &&
+      toupper(*p++) == ':')
+       rq->type = HTTP_REQUEST_TYPE_PROXY;
+
+   /* parse any header fields */
+   while((s = getline(line, sizeof(line))) > 0) {
+       if(toupper(line[0]) == 'A' &&
+          toupper(line[1]) == 'U')
+               if(dbglog != (FILE *)NULL) {
+                       fprintf(dbglog, "REQUEST: Authorization:\n");
+                       fflush(dbglog);
+               } else ;
+       else
+               if(dbglog != (FILE *)NULL) {
+                       fprintf(dbglog, "REQUEST: %s\n", line);
+                       fflush(dbglog);
+               }
+       p = line;
+       while(*p && *p != ':') {
+               *p = toupper(*p);
+               p++;
+       }
+       if(*p != ':') continue;         /* bad header field, skip it */
+       *p++ = '\0';
+       while(*p && LWS(*p)) p++;
+
+       /* header field value parsing here */
+       if(!strcmp(line, "HOST")) {
+               strncpy(rq->host, p, sizeof(rq->host));
+               p2 = strrchr(rq->host, ':');
+               if(p2 != (char *)NULL) {
+                       *p2++ = '\0';
+                       rq->port = atoi(p2);
+               }
+               /* if unknown virtual host then exit quietly */
+               for(ph = vhost; ph != NULL; ph = ph->next) {
+                       if(!strcasecmp(ph->hname, "*")) break;
+                       if(!strcasecmp(ph->hname, rq->host)) break;
+               }
+               if(rq->type != HTTP_REQUEST_TYPE_PROXY)
+                       if(ph == NULL && vhost != NULL) return(1);
+       } else
+       if(!strcmp(line, "USER-AGENT"))
+               strncpy(rq->useragent, p, sizeof(rq->useragent)); else
+       if(!strcmp(line, "CONNECTION"))
+               rq->keepopen = strcasecmp(p, "Keep-Alive") ? 0 : 1; else
+       if(!strcmp(line, "IF-MODIFIED-SINCE"))
+               rq->ifmodsince = httptime(p); else
+       if(!strcmp(line, "CONTENT-LENGTH"))
+               rq->size = atol(p); else
+       if(!strcmp(line, "AUTHORIZATION")) {
+               strncpy(rq->wwwauth, p, sizeof(rq->wwwauth));
+               if(rq->type != HTTP_REQUEST_TYPE_PROXY)
+                       authorize(p, rq);
+       } else
+       if(!strcmp(line, "PROXY-AUTHORIZATION")) {
+               if(rq->type == HTTP_REQUEST_TYPE_PROXY)
+                       authorize(p, rq);
+       } else
+       if(!strcmp(line, "DATE"))
+               rq->msgdate = httptime(p); else
+       if(!strcmp(line, "COOKIE")) {
+               strncpy(rq->cookie, p, sizeof(rq->cookie)-1);
+               rq->cookie[sizeof(rq->cookie)-1] = '\0';
+       }
+   }
+
+   if(rq->type != HTTP_REQUEST_TYPE_PROXY)
+       if(*rq->host == '\0' && vhost != NULL) return(1);
+
+   if(dbglog != (FILE *)NULL && rq->authuser[0] != '\0') {
+       fprintf(dbglog, "REQUEST: AuthUser=%s\n", rq->authuser);
+       fflush(dbglog);
+   }
+
+   if(s < 0) {
+       fprintf(stderr, "httpd: getrequest: Error getline (header fields)\n");
+       return(-1);
+   }
+
+   return(0);
+}
+
+static void decurl(u)
+char *u;
+{
+char *p;
+char h1, h2;
+char c;
+
+   p = u;
+   while(*p) {
+       switch(*p) {
+               case '\0':
+                       c = '\0';
+                       break;
+               case '+':
+                       c = ' ';
+                       p++;
+                       break;
+               case '%':
+                       h1 = '0';
+                       h2 = '0';
+                       p++;
+                       h1 = tolower(*p);
+                       if(*p) p++;
+                       h2 = tolower(*p);
+                       if(*p) p++;
+                       c = (h1 > '9') ? (10 + h1 - 'a') : (h1 - '0');
+                       c = 16 * c + ((h2 > '9') ? (10 + h2 - 'a') : (h2 - '0'));
+                       break;
+               default:
+                       c = *p++;
+       }
+       *u++ = c;
+   }
+   *u = '\0';
+}
diff --git a/commands/httpd0995/utility.c b/commands/httpd0995/utility.c
new file mode 100644 (file)
index 0000000..543a9d0
--- /dev/null
@@ -0,0 +1,265 @@
+/* utility.c
+ *
+ * This file is part of httpd
+ *
+ * 02/17/1996                  Michael Temari <Michael@TemWare.Com>
+ * 07/07/1996 Initial Release  Michael Temari <Michael@TemWare.Com>
+ * 12/29/2002 Initial Release  Michael Temari <Michael@TemWare.Com>
+ *
+ */
+#include <sys/types.h>
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "utility.h"
+#include "config.h"
+
+const char *days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
+const char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+                        "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+char *logdate(t)
+time_t *t;
+{
+time_t worktime;
+struct tm *tm;
+static char datebuffer[80];
+
+  if(t == (time_t *)NULL)
+       (void) time(&worktime);
+  else
+       worktime = *t;
+
+   tm = localtime(&worktime);
+
+   sprintf(datebuffer, "%4d%02d%02d%02d%02d%02d",
+               1900+tm->tm_year,
+               tm->tm_mon + 1,
+               tm->tm_mday,
+               tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+   return(datebuffer);
+}
+
+char *httpdate(t)
+time_t *t;
+{
+time_t worktime;
+struct tm *tm;
+static char datebuffer[80];
+
+  if(t == (time_t *)NULL)
+       (void) time(&worktime);
+  else
+       worktime = *t;
+
+   tm = gmtime(&worktime);
+
+   sprintf(datebuffer, "%s, %02d %s %4d %02d:%02d:%02d GMT",
+               days[tm->tm_wday],
+               tm->tm_mday, months[tm->tm_mon], 1900+tm->tm_year,
+               tm->tm_hour, tm->tm_min, tm->tm_sec);
+
+   return(datebuffer);
+}
+
+time_t httptime(p)
+char *p;
+{
+time_t worktime, gtime, ltime;
+struct tm tm;
+struct tm *tm2;
+int i;
+
+   worktime = (time_t) -1;
+
+   tm.tm_yday = 0;
+   tm.tm_isdst = -1;
+
+   /* day of week */
+   for(i = 0; i < 7; i++)
+       if(!strncmp(p, days[i], 3)) break;
+   if(i < 7)
+       tm.tm_wday = i;
+   else
+       return(worktime);
+   while(*p && *p != ' ') p++;
+   if(!*p) return(worktime);
+   while(*p && *p == ' ') p++;
+   if(!*p) return(worktime);
+
+   if(*p >= '0' && *p <= '9') {
+       /* day */
+       if(*(p+1) >= '0' && *(p+1) <= '9')
+               tm.tm_mday = 10 * (*p - '0') + (*(p+1) - '0');
+       else
+               return(worktime);
+       p += 3;
+       /* month */
+       for(i = 0; i < 12; i++)
+               if(!strncmp(p, months[i], 3)) break;
+       if(i < 12)
+               tm.tm_mon = i;
+       else
+               return(worktime);
+       p += 3;
+       if(!*p++) return(worktime);
+       /* year */
+       tm.tm_year = atoi(p);
+       while(*p && *p != ' ') p++;
+       if(*p) p++;
+   } else {
+       /* day */
+       tm.tm_mday = atoi(p);
+       while(*p && *p != ' ') p++;
+       while(*p && *p == ' ') p++;
+       if(!*p) return(worktime);
+   }
+
+   /* hour */
+   if(*p < '0' || *p > '9' || *(p+1) < '0' || *(p+1) > '9' || *(p+2) != ':') return(worktime);
+   tm.tm_hour = 10 * (*p - '0') + (*(p+1) - '0');
+   p += 3;
+
+   /* minute */
+   if(*p < '0' || *p > '9' || *(p+1) < '0' || *(p+1) > '9' || *(p+2) != ':') return(worktime);
+   tm.tm_min  = 10 * (*p - '0') + (*(p+1) - '0');
+   p += 3;
+
+   /* second */
+   if(*p < '0' || *p > '9' || *(p+1) < '0' || *(p+1) > '9' || *(p+2) != ' ') return(worktime);
+   tm.tm_sec  = 10 * (*p - '0') + (*(p+1) - '0');
+   p += 3;
+   while(*p && *p == ' ') p++;
+   if(!*p) return(worktime);
+
+   if(*p >= '0' && *p <= '9')
+       tm.tm_year = atoi(p);
+   else
+       if(*p++ != 'G' || *p++ != 'M' || *p++ != 'T')
+               return(worktime);
+
+   if(tm.tm_year == 0)
+       return(worktime);
+
+   if(tm.tm_year > 1900)
+       tm.tm_year -= 1900;
+
+   worktime = mktime(&tm);
+
+   gtime = mktime(gmtime(&worktime));
+   tm2 = localtime(&worktime);
+   tm2->tm_isdst = 0;
+   ltime = mktime(tm2);
+
+   worktime = worktime - (gtime - ltime);
+
+   return(worktime);
+}
+
+char *mimetype(url)
+char *url;
+{
+char *p;
+struct msufx *ps;
+char *dmt;
+
+   dmt = (char *) NULL;
+   p = url;
+   while(*p) {
+       if(*p != '.') {
+               p++;
+               continue;
+       }
+       for(ps = msufx; ps != NULL; ps = ps->snext)
+               if(!strcmp(ps->suffix, "") && dmt == (char *) NULL)
+                       dmt = ps->mtype->mimetype;
+               else
+                       if(!strcmp(p, ps->suffix))
+                               return(ps->mtype->mimetype);
+       p++;
+   }
+
+   if(dmt == (char *) NULL)
+       dmt = "application/octet-stream";
+
+   return(dmt);
+}
+
+char *decode64(p)
+char *p;
+{
+static char decode[80];
+char c[4];
+int i;
+int d;
+
+   i = 0;
+   d = 0;
+
+   while(*p) {
+       if(*p >= 'A' && *p <= 'Z') c[i++] = *p++ - 'A'; else
+       if(*p >= 'a' && *p <= 'z') c[i++] = *p++ - 'a' + 26; else
+       if(*p >= '0' && *p <= '9') c[i++] = *p++ - '0' + 52; else
+       if(*p == '+') c[i++] = *p++ - '+' + 62; else
+       if(*p == '/') c[i++] = *p++ - '/' + 63; else
+       if(*p == '=') c[i++] = *p++ - '='; else
+               return("");
+       if(i < 4) continue;
+       decode[d++] = ((c[0] << 2) | (c[1] >> 4));
+       decode[d++] = ((c[1] << 4) | (c[2] >> 2));
+       decode[d++] = ((c[2] << 6) |  c[3]);
+       decode[d] = '\0';
+       i = 0;
+   }
+
+   return(decode);
+}
+
+int getparms(p, parms, maxparms)
+char *p;
+char *parms[];
+int maxparms;
+{
+int np;
+
+   np = 0;
+
+   if(LWS(*p)) {
+       while(*p && LWS(*p)) p++;
+       if(!*p) return(0);
+       parms[np++] = (char *)NULL;
+   } else
+       np = 0;
+
+   while(np < maxparms && *p) {
+       parms[np++] = p;
+       while(*p && !LWS(*p)) p++;
+       if(*p) *p++ = '\0';
+       while(*p && LWS(*p)) p++;
+   }
+
+   return(np);
+}
+
+int mkurlaccess(p)
+char *p;
+{
+int ua;
+
+   ua = 0;
+
+   while(*p) {
+       if(toupper(*p) == 'R') ua |= URLA_READ; else
+       if(toupper(*p) == 'W') ua |= URLA_WRITE; else
+       if(toupper(*p) == 'X') ua |= URLA_EXEC; else
+       if(toupper(*p) == 'H') ua |= URLA_HEADERS; else
+               return(0);
+       p++;
+   }
+
+   return(ua);
+}
diff --git a/commands/httpd0995/utility.h b/commands/httpd0995/utility.h
new file mode 100644 (file)
index 0000000..a66160e
--- /dev/null
@@ -0,0 +1,19 @@
+/* utility.h
+ *
+ * This file is part of httpd.
+ *
+ * 02/17/1996                  Michael Temari <Michael@TemWare.Com>
+ * 07/07/1996 Initial Release  Michael Temari <Michael@TemWare.Com>
+ * 12/29/2002                  Michael Temari <Michael@TemWare.Com>
+ *
+ */
+
+#define        LWS(c)  ((c == ' ') || (c == '\t') || (c == '\r') || (c == '\n'))
+
+_PROTOTYPE(char *logdate, (time_t *t));
+_PROTOTYPE(char *httpdate, (time_t *t));
+_PROTOTYPE(time_t httptime, (char *p));
+_PROTOTYPE(char *mimetype, (char *url));
+_PROTOTYPE(char *decode64, (char *p));
+_PROTOTYPE(int getparms, (char *p, char *parms[], int maxparms));
+_PROTOTYPE(int mkurlaccess, (char *p));