Initial revision

This commit is contained in:
Ben Gras 2006-06-19 14:55:09 +00:00
parent ede3e5ab83
commit aa5efff203
43 changed files with 7995 additions and 0 deletions

42
commands/ftp101/Makefile Normal file
View file

@ -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

39
commands/ftp101/README Normal file
View file

@ -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

132
commands/ftp101/crc.c Normal file
View file

@ -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
}

934
commands/ftp101/file.c Normal file
View file

@ -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);
}

33
commands/ftp101/file.h Normal file
View file

@ -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));

148
commands/ftp101/ftp.1 Normal file
View file

@ -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

404
commands/ftp101/ftp.c Normal file
View file

@ -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);
}

39
commands/ftp101/ftp.h Normal file
View file

@ -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));

137
commands/ftp101/local.c Normal file
View file

@ -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);
}

15
commands/ftp101/local.h Normal file
View file

@ -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));

567
commands/ftp101/net.c Normal file
View file

@ -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);
}

15
commands/ftp101/net.h Normal file
View file

@ -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;

173
commands/ftp101/other.c Normal file
View file

@ -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));
}

17
commands/ftp101/other.h Normal file
View file

@ -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));

305
commands/ftp101/xfer.c Normal file
View file

@ -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);
}

8
commands/ftp101/xfer.h Normal file
View file

@ -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));

View file

@ -0,0 +1,65 @@
# Makefile for httpd
#
# 02/17/1996 Michael Temari <Michael@TemWare.Com>
# 07/07/1996 Initial Release Michael Temari <Michael@TemWare.Com>
# 12/29/2002 Michael Temari <Michael@TemWare.Com>
# 07/07/2003 Al Woodhull <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

252
commands/httpd0995/README Normal file
View file

@ -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)

View file

@ -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.

View file

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

841
commands/httpd0995/config.c Normal file
View file

@ -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);
}

View file

@ -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;

View file

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

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

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

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

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

View file

@ -0,0 +1,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

124
commands/httpd0995/httpd.8 Normal file
View file

@ -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

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

@ -0,0 +1,175 @@
/* httpd.c
*
* httpd A Server implementing the HTTP protocol.
*
* usage: tcpd http httpd &
*
* 02/17/1996 Michael Temari <Michael@TemWare.Com>
* 07/07/1996 Initial Release Michael Temari <Michael@TemWare.Com>
* 12/29/2002 Michael Temari <Michael@TemWare.Com>
* 07/04/2003 Al Woodhull <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);
}

View file

@ -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

View file

@ -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

View file

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

View file

@ -0,0 +1,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)

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

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

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

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

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

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

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

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

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

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

View file

@ -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);
}

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

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

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

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

View file

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

View file

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

View file

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