remove subdirs that aren't built.

ftp is superseded by other dirs, i86 is not used, httpd* is superseded
by packages, sed is superseded by simple/sed.c.
This commit is contained in:
Ben Gras 2010-02-19 16:31:43 +00:00
parent 8c88a0219b
commit c460974814
75 changed files with 0 additions and 15019 deletions

View file

@ -1,33 +0,0 @@
# Makefile for ftp
#
# 01/25/96 Initial Release Michael Temari, <temari@ix.netcom.com>
#
CFLAGS= -O -D_MINIX -D_POSIX_SOURCE
LDFLAGS=-i
BINDIR=/usr/bin
PROG= ftp
OBJS= ftp.o local.o file.o other.o net.o
all: $(PROG)
CC = exec cc
$(PROG): $(OBJS)
$(CC) $(LDFLAGS) -o $@ $(OBJS)
install -S 8kw $@
clean:
rm -f $(PROG) $(OBJS)
install: $(BINDIR)/$(PROG)
$(BINDIR)/$(PROG): $(PROG)
install -cs -o bin $? $@
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 file.h net.h

View file

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

View file

@ -1,922 +0,0 @@
/* file.c
*
* This file is part of ftp.
*
*
* 01/25/96 Initial Release Michael Temari, <temari@ix.netcom.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 "ftp.h"
#include "file.h"
#include "net.h"
_PROTOTYPE(static char *dir, (char *path, int full));
_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));
_PROTOTYPE(static int asciisize, (int fd, off_t *filesize));
_PROTOTYPE(static off_t asciisetsize, (int fd, off_t filesize));
static char buffer[512 << sizeof(char *)];
static char bufout[512 << sizeof(char *)];
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 %s > %s", path, name);
system(cmd);
return(name);
}
static int asciisend(fd, fdout)
int fd;
int fdout;
{
int s, len;
char c;
char *p;
char *op, *ope;
unsigned long total=0L;
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 == '\r') {
*op++ = '\r';
total++;
}
*op++ = c;
if(op >= ope) {
write(fdout, bufout, op - bufout);
op = bufout;
}
}
if(atty) {
printf("%9lu bytes\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", total);
fflush(stdout);
}
}
if(op > bufout)
write(fdout, bufout, op - bufout);
if(atty) {
printf("\n");
fflush(stdout);
}
return(s);
}
static int binarysend(fd, fdout)
int fd;
int fdout;
{
int s;
unsigned long total=0L;
if(atty) {
printf("Sent ");
fflush(stdout);
}
while((s = read(fd, buffer, sizeof(buffer))) > 0) {
write(fdout, buffer, s);
total += (long)s;
if(atty) {
printf("%9lu bytes\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", total);
fflush(stdout);
}
}
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;
if(isatty && fd > 2) {
printf("Received ");
fflush(stdout);
}
gotcr = 0;
op = bufout; ope = bufout + sizeof(bufout) - 3;
while((s = read(fdin, buffer, sizeof(buffer))) > 0) {
p = buffer;
total += (long)s;
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("%11lu bytes\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", total);
fflush(stdout);
}
}
if(gotcr)
*op++ = '\r';
if(op > bufout)
write(fd, bufout, op - bufout);
if(atty && fd > 2) {
printf("\n");
fflush(stdout);
}
return(s);
}
static binaryrecv(fd, fdin)
int fd;
int fdin;
{
int s;
unsigned long total=0L;
if(atty && fd > 2) {
printf("Received ");
fflush(stdout);
}
while((s = read(fdin, buffer, sizeof(buffer))) > 0) {
write(fd, buffer, s);
total += (long)s;
if(atty && fd > 2) {
printf("%11lu bytes\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b", total);
fflush(stdout);
}
}
if(atty && fd > 2) {
printf("\n");
fflush(stdout);
}
return(s);
}
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);
}
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 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) {
readline("Path: ", line2, sizeof(line2));
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) {
readline("Directory: ", line2, sizeof(line2));
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) {
readline("Directory: ", line2, sizeof(line2));
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) {
readline("File: ", line2, sizeof(line2));
file = line2;
}
return(DOcommand("DELE", file));
}
int DOmdtm()
{
char *file;
if(DOcmdcheck())
return(0);
file = cmdargv[1];
if(cmdargc < 2) {
readline("File: ", line2, sizeof(line2));
file = line2;
}
return(DOcommand("MDTM", file));
}
int DOsize()
{
char *file;
if(DOcmdcheck())
return(0);
file = cmdargv[1];
if(cmdargc < 2) {
readline("File: ", line2, sizeof(line2));
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) {
readline("File: ", line2, sizeof(line2));
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) {
readline("Remote File: ", line2, sizeof(line2));
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) {
readline("Remote File: ", line2, sizeof(line2));
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);
}
int DOMretr()
{
char *files;
int fd, s;
FILE *fp;
char name[32];
if(DOcmdcheck())
return(0);
files = cmdargv[1];
if(cmdargc < 2) {
readline("Files: ", line2, sizeof(line2));
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) {
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) {
line2[strlen(line2)-1] = '\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) {
readline("Local File: ", line2, sizeof(line2));
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) {
readline("Local File: ", line2, sizeof(line2));
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) {
readline("Local File: ", line2, sizeof(line2));
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) {
readline("Local File: ", line2, sizeof(line2));
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;
int fd, s;
FILE *fp;
if(DOcmdcheck())
return(0);
files = cmdargv[1];
if(cmdargc < 2) {
readline("Files: ", line2, sizeof(line2));
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) {
line2[strlen(line2)-1] = '\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);
}

View file

@ -1,30 +0,0 @@
/* file.h
*
* This file is part of ftp.
*
*
* 01/25/96 Initial Release Michael Temari, <temari@ix.netcom.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 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));

View file

@ -1,312 +0,0 @@
/* ftp.c by Michael Temari 06/21/92
*
* ftp An ftp client program for use with TNET.
*
* Usage: ftp [[host] [port]]
*
* 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
*
* Author: Michael Temari, <temari@ix.netcom.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "ftp.h"
#include "local.h"
#include "file.h"
#include "other.h"
#include "net.h"
FILE *fpcommin;
FILE *fpcommout;
int linkopen;
int loggedin;
int type;
int format;
int mode;
int structure;
int passive;
int atty;
int cmdargc;
char *cmdargv[NUMARGS];
char reply[1024];
_PROTOTYPE(static int makeargs, (char *buff));
_PROTOTYPE(int DOhelp, (void));
_PROTOTYPE(int main, (int argc, char *argv[]));
static int makeargs(buff)
char *buff;
{
char *p;
int i;
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;
{
printf(prompt); fflush(stdout);
if(fgets(buff, len, stdin) == (char *)NULL) {
printf("\nEnd of file on input!\n");
exit(1);
}
*strchr(buff, '\n') = 0;
if(!atty) {
printf("%s\n", buff);
fflush(stdout);
}
return(0);
}
int DOgetreply()
{
char *p;
char buff[6];
int s;
int firsttime;
do {
firsttime = 1;
do {
if(fgets(reply, sizeof(reply), fpcommin) == (char *)0)
return(-1);
p = reply + strlen(reply) - 1;
while(p != reply)
if(*p == '\r' || *p == '\n' || isspace(*p))
*p-- = '\0';
else
break;
printf("%s\n", reply); fflush(stdout);
if(firsttime) {
firsttime = 0;
strncpy(buff, reply, 4);
buff[3] = ' ';
}
} while(strncmp(reply, buff, 3) || reply[3] == '-');
s = atoi(buff);
} 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;
{
if(*ftparg)
fprintf(fpcommout, "%s %s\r\n", ftpcommand, ftparg);
else
fprintf(fpcommout, "%s\r\n", ftpcommand);
fflush(fpcommout);
return(DOgetreply());
}
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 mode to ascii\n");
printf("binary Set file transfer mode to binary\n");
printf("bye Close connection and exit\n");
printf("cd Change directory on remote host\n");
printf("close Close connection\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");
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");
readline("Press ENTER to continue... ", junk, sizeof(junk));
printf("mput Send multiple files to remote host\n");
printf("noop Send the ftp NOOP command\n");
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");
printf("site Send a site specific command\n");
printf("size Get file size information\n");
printf("status Get connection/file status information\n");
printf("system Get remote system type information\n");
printf("user Enter remote user information\n");
return(0);
}
struct commands {
char *name;
_PROTOTYPE(int (*func), (void));
};
static struct commands commands[] = {
"!", DOlshell,
"append", DOappe,
"ascii", DOascii,
"binary", DObinary,
"bin", DObinary,
"bye", DOquit,
"cd", DOcd,
"close", DOclose,
"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,
"system", DOsyst,
"user", DOuser,
"", (int (*)())0
};
int main(argc, argv)
int argc;
char *argv[];
{
int s;
struct commands *cmd;
static char buffer[128];
NETinit();
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) {
readline("ftp>", buffer, sizeof(buffer));
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(0);
}

View file

@ -1,36 +0,0 @@
/* ftp.h
*
* This file is part of ftp.
*
*
* 01/25/96 Initial Release Michael Temari, <temari@ix.netcom.com>
*/
extern FILE *fpcommin;
extern FILE *fpcommout;
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 char reply[1024];
#define RETR 0
#define STOR 1
#define TYPE_A 0
#define TYPE_I 1
_PROTOTYPE(int readline, (char *prompt, char *buff, int len));
_PROTOTYPE(int DOgetreply, (void));
_PROTOTYPE(int DOcmdcheck, (void));
_PROTOTYPE(int DOcommand, (char *ftpcommand, char *ftparg));

View file

@ -1,128 +0,0 @@
/* local.c
*
* This file is part of ftp.
*
*
* 01/25/96 Initial Release Michael Temari, <temari@ix.netcom.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) {
readline("Path: ", line2, sizeof(line2));
path = line2;
}
if(chdir(path))
printf("Could not change local directory. %s\n", strerror(errno));
else
DOlpwd();
return(0);
}
int DOlmkdir()
{
char *path;
int s;
path = cmdargv[1];
if(cmdargc < 2) {
readline("Directory: ", line2, sizeof(line2));
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) {
readline("Directory: ", line2, sizeof(line2));
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);
}
int DOlnlst(void)
{
dodir(".", 0);
}
int DOlshell(void)
{
system("$SHELL");
}
static void dodir(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 %s > %s", path, name);
system(cmd);
sprintf(cmd, "more %s", name);
system(cmd);
sprintf(cmd, "rm %s", name);
system(cmd);
}

View file

@ -1,15 +0,0 @@
/* local.h
*
* This file is part of ftp.
*
*
* 01/25/96 Initial Release Michael Temari, <temari@ix.netcom.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));

View file

@ -1,421 +0,0 @@
/* net.c
*
* This file is part of ftp.
*
*
* 01/25/96 Initial Release Michael Temari, <temari@ix.netcom.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 "file.h"
#include "net.h"
_PROTOTYPE(void donothing, (int sig));
static int ftpcomm_fd;
static ipaddr_t myip;
static ipaddr_t hostip;
static char host[256];
static int lpid;
void 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");
exit(-1);
}
s = ioctl(tcp_fd, NWIOGTCPCONF, &nwio_tcpconf);
if(s < 0) {
perror("ftp: Could not get tcp configuration");
exit(-1);
}
myip = nwio_tcpconf.nwtc_locaddr;
close(tcp_fd);
}
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)
readline("Host: ", host, sizeof(host));
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");
return(-1);
}
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 == inet_addr("127.0.0.1"))
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(s);
}
tcpcopt.nwtcl_flags = 0;
s = ioctl(ftpcomm_fd, NWIOTCPCONN, &tcpcopt);
if(s < 0) {
perror("ftp: ioctl error on NWIOTCPCONN");
close(ftpcomm_fd);
return(s);
}
s = ioctl(ftpcomm_fd, NWIOGTCPCONF, &tcpconf);
if(s < 0) {
perror("ftp: ioctl error on NWIOGTCPCONF");
close(ftpcomm_fd);
return(s);
}
fpcommin = fdopen(ftpcomm_fd, "r");
fpcommout = fdopen(ftpcomm_fd, "w");
s = DOgetreply();
if(s < 0) {
fclose(fpcommin);
fclose(fpcommout);
close(ftpcomm_fd);
return(s);
}
if(s != 220) {
fclose(fpcommin);
fclose(fpcommout);
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);
}
fclose(fpcommin);
fclose(fpcommout);
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;
int ftpdata_fd;
char *buff;
ipaddr_t ripaddr;
tcpport_t rport;
static tcpport_t lport = HTONS(0xF000);
int s;
int i;
int cs;
int pfd[2];
char dummy;
char port[32];
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 = open(tcp_device, O_RDWR)) < 0) {
perror("ftp: open error on tcp device");
return(-1);
}
if(passive) {
s = DOcommand("PASV", "");
if(s != 227) {
close(ftpdata_fd);
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(-1);
}
buff++;
}
rport = (tcpport_t)atoi(buff);
if((buff = strchr(buff, ',')) == (char *)0) {
printf("Could not parse PASV reply\n");
return(-1);
}
buff++;
rport = (rport << 8) + (tcpport_t)atoi(buff);
ripaddr = ntohl(ripaddr);
rport = ntohs(rport);
}
for (;;) {
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;
s = ioctl(ftpdata_fd, NWIOSTCPCONF, &tcpconf);
if(s < 0) {
if (errno == EADDRINUSE) continue;
perror("ftp: ioctl error on NWIOSTCPCONF");
close(ftpdata_fd);
return(s);
}
break;
}
s = ioctl(ftpdata_fd, NWIOGTCPCONF, &tcpconf);
if(s < 0) {
perror("ftp: ioctl error on NWIOGTCPCONF");
close(ftpdata_fd);
return(s);
}
lport = tcpconf.nwtc_locport;
if(passive) {
tcplopt.nwtcl_flags = 0;
s = ioctl(ftpdata_fd, NWIOTCPCONN, &tcpcopt);
if(s < 0) {
perror("ftp: error on ioctl NWIOTCPCONN");
close(ftpdata_fd);
return(0);
}
s = ioctl(ftpdata_fd, NWIOGTCPCONF, &tcpconf);
if(s < 0) {
perror("ftp: error on ioctl NWIOGTCPCONF");
close(ftpdata_fd);
return(0);
}
} else {
tcplopt.nwtcl_flags = 0;
if (pipe(pfd) < 0) {
perror("ftp: could not create a pipe");
return(s);
}
lpid = fork();
if(lpid < 0) {
perror("ftp: could not fork listener");
close(ftpdata_fd);
close(pfd[0]);
close(pfd[1]);
return(s);
} else if(lpid == 0) {
close(pfd[0]);
signal(SIGALRM, donothing);
alarm(15);
close(pfd[1]);
s = ioctl(ftpdata_fd, NWIOTCPLISTEN, &tcplopt);
alarm(0);
if(s < 0)
if(errno == EINTR)
exit(1); /* timed out */
else
exit(-1); /* error */
else
exit(0); /* connection made */
}
/* 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) {
signal(SIGALRM, donothing);
alarm(1);
s = ioctl(ftpdata_fd, NWIOGTCPCONF, &tcpconf);
alarm(0);
if(s == -1) break;
}
}
#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) {
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)));
s = DOcommand("PORT", port);
if(s != 200) {
close(ftpdata_fd);
kill(lpid, SIGKILL);
return(s);
}
}
s = DOcommand(datacom, file);
if(s == 125 || s == 150) {
if(!passive) {
while(1) {
s = wait(&cs);
if(s < 0 || s == lpid)
break;
}
if(s < 0) {
perror("wait error:");
close(ftpdata_fd);
kill(lpid, SIGKILL);
return(s);
}
if((cs & 0x00ff)) {
printf("Child listener failed %04x\n", cs);
close(ftpdata_fd);
return(-1);
}
cs = (cs >> 8) & 0x00ff;
if(cs == 1) {
printf("Child listener timed out\n");
return(DOgetreply());
} else if(cs) {
printf("Child listener returned %02x\n", cs);
close(ftpdata_fd);
return(-1);
}
}
switch(direction) {
case RETR:
s = recvfile(fd, ftpdata_fd);
break;
case STOR:
s = sendfile(fd, ftpdata_fd);
break;
}
close(ftpdata_fd);
s = DOgetreply();
} else {
if(!passive)
kill(lpid, SIGKILL);
close(ftpdata_fd);
}
return(s);
}

View file

@ -1,13 +0,0 @@
/* net.h
*
* This file is part of ftp.
*
*
* 01/25/96 Initial Release Michael Temari, <temari@ix.netcom.com>
*/
_PROTOTYPE(void 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));

View file

@ -1,163 +0,0 @@
/* other.c by Michael Temari 06/21/92
*
* ftp An ftp client program for use with TNET.
*
* Author: Michael Temari, <temari@ix.netcom.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"
void FTPinit()
{
linkopen = 0;
loggedin = 0;
type = TYPE_A;
format = 0;
mode = 0;
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];
if(cmdargc < 2) {
tcgetattr(fileno(stdout), &oldtty);
newtty = oldtty;
newtty.c_lflag &= ~ECHO;
tcsetattr(fileno(stdout), TCSANOW, &newtty);
readline("Password: ", password, sizeof(password));
tcsetattr(fileno(stdout), TCSANOW, &oldtty);
printf("\n");
pass = password;
}
s = DOcommand("PASS", pass);
if(s == 230)
loggedin = 1;
return(s);
}
int DOuser()
{
char *user;
int s;
char username[64];
if(!linkopen) {
printf("You must \"OPEN\" a connection first.\n");
return(0);
}
loggedin = 0;
user = cmdargv[1];
if(cmdargc < 2) {
readline("Username: ", username, sizeof(username));
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", ""));
}
int DOquote()
{
int i;
static char args[512];
args[0] = '\0';
for(i = 2; i < cmdargc; i++) {
if(i != 2)
strcat(args, " ");
strcat(args, cmdargv[i]);
}
return(DOcommand(cmdargv[1], args));
}
int DOsite()
{
int i;
static char args[512];
args[0] = '\0';
for(i = 1; i < cmdargc; i++) {
if(i != 1)
strcat(args, " ");
strcat(args, cmdargv[i]);
}
return(DOcommand("SITE", args));
}

View file

@ -1,17 +0,0 @@
/* other.h
*
* This file is part of ftp.
*
*
* 01/25/96 Initial Release Michael Temari, <temari@ix.netcom.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));

View file

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

View file

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

View file

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

View file

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

View file

@ -1,255 +0,0 @@
/* 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);
}

View file

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

View file

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

View file

@ -1,187 +0,0 @@
/* 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);
}

View file

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

View file

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

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

View file

@ -1,240 +0,0 @@
/* 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;
}
}
}

View file

@ -1,17 +0,0 @@
/* 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];

View file

@ -1,213 +0,0 @@
/* 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);
}

View file

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

View file

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

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

View file

@ -1,292 +0,0 @@
/* 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;
}
}

View file

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

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

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

@ -1,19 +0,0 @@
/* 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));

View file

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

View file

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

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

@ -1,255 +0,0 @@
/* 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);
}

View file

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

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

@ -1,187 +0,0 @@
/* 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);
}

View file

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

View file

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

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

View file

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

View file

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

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

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

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

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

View file

@ -1,240 +0,0 @@
/* 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;
}
}
}

View file

@ -1,17 +0,0 @@
/* 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];

View file

@ -1,213 +0,0 @@
/* 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);
}

View file

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

View file

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

@ -1,90 +0,0 @@
/* 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);
}

View file

@ -1,292 +0,0 @@
/* 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;
}
}

View file

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

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

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

@ -1,19 +0,0 @@
/* 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));

View file

@ -1,20 +0,0 @@
# Makefile for commands/i86.
CFLAGS = -D_MINIX -D_POSIX_SOURCE
CCLD = $(CC) -i $(CFLAGS)
MAKE = exec make -$(MAKEFLAGS)
CC = exec cc
all: cc
cc: cc.c
$(CCLD) -o $@ $?
install -S 6kb $@
install: /usr/bin/cc
/usr/bin/cc: cc
install -cs -o bin $? $@
clean:
rm -rf a.out core cc

File diff suppressed because it is too large Load diff

View file

@ -1,10 +0,0 @@
So far no regression over the historic sed are known. If you find a bug,
please provide a test-case (.sed, .in and .out, look into tests/) - if
possible try to debug the problem and propose a patch.
We will focus on POSIX conformance and small size - GNU sed extensions are
most likely not accepted.
Please report issues to: Rene Rebe <rene@exactcode.de>

View file

@ -1,22 +0,0 @@
# Makefile for minised
# If your compiler does not support this flags, just remove them.
# They only ensure that no new warning regressions make it into the source.
CFLAGS = -Wall -Wwrite-strings
minised: sedcomp.o sedexec.o
$(CC) $(LFLAGS) sedcomp.o sedexec.o -o minised
sedcomp.o: sedcomp.c sed.h
sedexec.o: sedexec.c sed.h
install: minised
install -o bin -m 755 minised /usr/bin/
install -o bin -m 755 minised /bin/
clean:
rm -f minised sedcomp.o sedexec.o
check: minised
cd tests; ./run ../minised

View file

@ -1,81 +0,0 @@
small-sed
by Eric S. Raymond, <esr@snark.thyrsus.com>
and Rene Rebe <rene@exactcode.de>
This is a smaller, cheaper, and faster SED utility. Minix uses it. GNU used
to use it, until they built their own sed around an extended (some would
say over-extended) regexp package and it is used for embedded tasks (for
example by the T2 SDE - http://www.t2-project.org).
The original sed 1.0 was written in three pieces; sed.h, sedcomp.c, sedexec.c.
Some Minix hacker ran them together into a single-file version, mnsed.c which
is not supported and shipped these days; if changes are needed for Minix please
send a patch to the normal source.
The 1.2 version (9 Oct 1996) add mnsed's support for detecting
truncated hold spaces. The mnsed version is missing one feature in
of the 1.2 version; support of +. Also, the multiple-file I/O is
organized slightly differently.
The 1.3 version added a bug fix by Tom Oehser, and the `L' command. Also
this program is now distributed under GPL.
The 1.5 version incooperated a lot of bug fixes by Rene Rebe as well as
a real test suite. Also the function declaration and definition have been
converted from the K&R C to ANSI C.
The 1.6 version includes support for the n'th match for the substitude command
as well as support for predefined character classes and only writes lines
with newline if one was present in the input line (compatible with GNU sed).
The 1.7 version fixed a segmentation fault with empty regular expressions,
not to leak other buffer content for groups of commands and escaping
numerical seperators in regular expressions by disabling obscure code.
Additionally compilation with older compilers as well as warnings with the
latest gcc versions have been corrected.
The 1.8 version fixes matching of some escaped characters (a regression
introduced with \+ star matching), \+ star matching to corretly copy
and mark the internal bytecode representation, back references inside lhs
regular expressions matching (to work at all) and marking the correct
regular expression for star matches.
The 1.9 version included a microoptimization shaving some bytes off the
binary and some cpu cycles at run time, reusing the previous regular
expressions for empty ones, predefined character classes with control
characters, handling of escaped ampesands and support for backreference
\0 and Kleene star operator on groups.
The 1.10 version fixed a special case of grouped star matching where
\+1..n overwrote the last match, not to infinite loop on certain zero match
grouped star cases and not to crash on w(rite to file). The version also
no longer falls into the conservative end-of-file matching mode when just
end-of-line matching was used.
The 1.11 version again fixed w(rite to file) handling to correctly honor
/dev/stdout and /dev/stderr as GNU sed does and thus keep the streams in
sync. Some unused variables have been removed and a two diagnostics
fixed to be printed correctly.
The 1.12 version fixed the l(ist) command to actually work, some tiny
optimizations have been performed as well as some more compiler warnings
fixed.
Makefile -- how to build sed
sed.h -- declarations and structures
sedcomp.c -- sed pattern compilation
sedexec.c -- sed program execution
sed.1 -- source for the man page
tests/ -- a small set of sed tests
For some releases the man page in the man format.
Surf to
http://www.exactcode.de/oss/minised/
http://www.catb.org/~esr/
for updates of this software. There is a sed FAQ kept at these
locations:
http://www.dreamwvr.com/sed-info/sed-faq.html

View file

@ -1,85 +0,0 @@
/* sed.h -- types and constants for the stream editor
Copyright (C) 1995-2003 Eric S. Raymond
Copyright (C) 2004-2005 Rene Rebe
*/
#define TRUE 1
#define FALSE 0
/* data area sizes used by both modules */
#define MAXBUF 4000 /* current line buffer size */
#define MAXAPPENDS 20 /* maximum number of appends */
#define MAXTAGS 9 /* tagged patterns are \1 to \9 */
#define MAXCMDS 200 /* maximum number of compiled commands */
#define MAXLINES 256 /* max # numeric addresses to compile */
/* constants for compiled-command representation */
#define EQCMD 0x01 /* = -- print current line number */
#define ACMD 0x02 /* a -- append text after current line */
#define BCMD 0x03 /* b -- branch to label */
#define CCMD 0x04 /* c -- change current line */
#define DCMD 0x05 /* d -- delete all of pattern space */
#define CDCMD 0x06 /* D -- delete first line of pattern space */
#define GCMD 0x07 /* g -- copy hold space to pattern space */
#define CGCMD 0x08 /* G -- append hold space to pattern space */
#define HCMD 0x09 /* h -- copy pattern space to hold space */
#define CHCMD 0x0A /* H -- append hold space to pattern space */
#define ICMD 0x0B /* i -- insert text before current line */
#define LCMD 0x0C /* l -- print pattern space in escaped form */
#define CLCMD 0x20 /* L -- hexdump */
#define NCMD 0x0D /* n -- get next line into pattern space */
#define CNCMD 0x0E /* N -- append next line to pattern space */
#define PCMD 0x0F /* p -- print pattern space to output */
#define CPCMD 0x10 /* P -- print first line of pattern space */
#define QCMD 0x11 /* q -- exit the stream editor */
#define RCMD 0x12 /* r -- read in a file after current line */
#define SCMD 0x13 /* s -- regular-expression substitute */
#define TCMD 0x14 /* t -- branch on last substitute successful */
#define CTCMD 0x15 /* T -- branch on last substitute failed */
#define WCMD 0x16 /* w -- write pattern space to file */
#define CWCMD 0x17 /* W -- write first line of pattern space */
#define XCMD 0x18 /* x -- exhange pattern and hold spaces */
#define YCMD 0x19 /* y -- transliterate text */
typedef struct cmd_t /* compiled-command representation */
{
char *addr1; /* first address for command */
char *addr2; /* second address for command */
union
{
char *lhs; /* s command lhs */
struct cmd_t *link; /* label link */
} u;
char command; /* command code */
char *rhs; /* s command replacement string */
FILE *fout; /* associated output file descriptor */
struct
{
unsigned allbut : 1; /* was negation specified? */
unsigned global : 1; /* was p postfix specified? */
unsigned print : 2; /* was g postfix specified? */
unsigned inrange : 1; /* in an address range? */
} flags;
unsigned nth; /* sed nth occurance */
}
sedcmd; /* use this name for declarations */
#define BAD ((char *) -1) /* guaranteed not a string ptr */
/* address and regular expression compiled-form markers */
#define STAR 1 /* marker for Kleene star */
#define CCHR 2 /* non-newline character to be matched follows */
#define CDOT 4 /* dot wild-card marker */
#define CCL 6 /* character class follows */
#define CNL 8 /* match line start */
#define CDOL 10 /* match line end */
#define CBRA 12 /* tagged pattern start marker */
#define CKET 14 /* tagged pattern end marker */
#define CBACK 16 /* backslash-digit pair marker */
#define CLNUM 18 /* numeric-address index follows */
#define CEND 20 /* symbol for end-of-source */
#define CEOF 22 /* end-of-field mark */
#define bits(b) (1 << (b))
/* sed.h ends here */

View file

@ -1,956 +0,0 @@
/* sedcomp.c -- stream editor main and compilation phase
Copyright (C) 1995-2003 Eric S. Raymond
Copyright (C) 2004-2006 Rene Rebe
The stream editor compiles its command input (from files or -e options)
into an internal form using compile() then executes the compiled form using
execute(). Main() just initializes data structures, interprets command line
options, and calls compile() and execute() in appropriate sequence.
The data structure produced by compile() is an array of compiled-command
structures (type sedcmd). These contain several pointers into pool[], the
regular-expression and text-data pool, plus a command code and g & p flags.
In the special case that the command is a label the struct will hold a ptr
into the labels array labels[] during most of the compile, until resolve()
resolves references at the end.
The operation of execute() is described in its source module.
*/
#include <stdlib.h> /* exit */
#include <stdio.h> /* uses getc, fprintf, fopen, fclose */
#include <ctype.h> /* isdigit */
#include <string.h> /* strcmp */
#include "sed.h" /* command type struct and name defines */
/***** public stuff ******/
#define MAXCMDS 200 /* maximum number of compiled commands */
#define MAXLINES 256 /* max # numeric addresses to compile */
/* main data areas */
char linebuf[MAXBUF+1]; /* current-line buffer */
sedcmd cmds[MAXCMDS+1]; /* hold compiled commands */
long linenum[MAXLINES]; /* numeric-addresses table */
/* miscellaneous shared variables */
int nflag; /* -n option flag */
int eargc; /* scratch copy of argument count */
sedcmd *pending = NULL; /* next command to be executed */
int last_line_used = 0; /* last line address ($) was used */
void die (const char* msg) {
fprintf(stderr, "sed: ");
fprintf(stderr, msg, linebuf);
fprintf(stderr, "\n");
exit(2);
}
/***** module common stuff *****/
#define POOLSIZE 10000 /* size of string-pool space */
#define WFILES 10 /* max # w output files that can be compiled */
#define RELIMIT 256 /* max chars in compiled RE */
#define MAXDEPTH 20 /* maximum {}-nesting level */
#define MAXLABS 50 /* max # of labels that can be handled */
#define SKIPWS(pc) while ((*pc==' ') || (*pc=='\t')) pc++
#define IFEQ(x, v) if (*x == v) x++ , /* do expression */
/* error messages */
static char AGMSG[] = "garbled address %s";
static char CGMSG[] = "garbled command %s";
static char TMTXT[] = "too much text: %s";
static char AD1NG[] = "no addresses allowed for %s";
static char AD2NG[] = "only one address allowed for %s";
static char TMCDS[] = "too many commands, last was %s";
static char COCFI[] = "cannot open command-file %s";
static char UFLAG[] = "unknown flag %c";
/*static char COOFI[] = "cannot open %s";*/
static char CCOFI[] = "cannot create %s";
static char ULABL[] = "undefined label %s";
static char TMLBR[] = "too many {'s";
static char FRENL[] = "first RE must be non-null";
static char NSCAX[] = "no such command as %s";
static char TMRBR[] = "too many }'s";
static char DLABL[] = "duplicate label %s";
static char TMLAB[] = "too many labels: %s";
static char TMWFI[] = "too many w files";
static char REITL[] = "RE too long: %s";
static char TMLNR[] = "too many line numbers";
static char TRAIL[] = "command \"%s\" has trailing garbage";
static char RETER[] = "RE not terminated: %s";
static char CCERR[] = "unknown character class: %s";
/* cclass to c function mapping ,-) */
const char* cclasses[] = {
"alnum", "a-zA-Z0-9",
"lower", "a-z",
"space", " \f\n\r\t\v",
"alpha", "a-zA-Z",
"digit", "0-9",
"upper", "A-Z",
"blank", " \t",
"xdigit", "0-9A-Fa-f",
"cntrl", "\x01-\x1f\x7e",
"print", " -\x7e",
"graph", "!-\x7e",
"punct", "!-/:-@[-`{-\x7e",
NULL, NULL};
typedef struct /* represent a command label */
{
char *name; /* the label name */
sedcmd *last; /* it's on the label search list */
sedcmd *address; /* pointer to the cmd it labels */
} label;
/* label handling */
static label labels[MAXLABS]; /* here's the label table */
static label *lab = labels + 1; /* pointer to current label */
static label *lablst = labels; /* header for search list */
/* string pool for regular expressions, append text, etc. etc. */
static char pool[POOLSIZE]; /* the pool */
static char *fp = pool; /* current pool pointer */
static char *poolend = pool + POOLSIZE; /* pointer past pool end */
/* compilation state */
static FILE *cmdf = NULL; /* current command source */
static char *cp = linebuf; /* compile pointer */
static sedcmd *cmdp = cmds; /* current compiled-cmd ptr */
static char *lastre = NULL; /* old RE pointer */
static int bdepth = 0; /* current {}-nesting level */
static int bcount = 0; /* # tagged patterns in current RE */
static char **eargv; /* scratch copy of argument list */
/* compilation flags */
static int eflag; /* -e option flag */
static int gflag; /* -g option flag */
/* prototypes */
static char *address(char *expbuf);
static char *gettext(char* txp);
static char *recomp(char *expbuf, char redelim);
static char *rhscomp(char* rhsp, char delim);
static char *ycomp(char *ep, char delim);
static int cmdcomp(char cchar);
static int cmdline(char *cbuf);
static label *search(label *ptr);
static void compile(void);
static void resolve(void);
/* sedexec.c protypes */
void execute(char* file);
/* main sequence of the stream editor */
int main(int argc, char *argv[])
{
eargc = argc; /* set local copy of argument count */
eargv = argv; /* set local copy of argument list */
cmdp->addr1 = pool; /* 1st addr expand will be at pool start */
if (eargc == 1)
exit(0); /* exit immediately if no arguments */
/* scan through the arguments, interpreting each one */
while ((--eargc > 0) && (**++eargv == '-'))
switch (eargv[0][1])
{
case 'e':
eflag++; compile(); /* compile with e flag on */
eflag = 0;
continue; /* get another argument */
case 'f':
if (eargc-- <= 0) /* barf if no -f file */
exit(2);
if ((cmdf = fopen(*++eargv, "r")) == NULL)
{
fprintf(stderr, COCFI, *eargv);
exit(2);
}
compile(); /* file is O.K., compile it */
fclose(cmdf);
continue; /* go back for another argument */
case 'g':
gflag++; /* set global flag on all s cmds */
continue;
case 'n':
nflag++; /* no print except on p flag or w */
continue;
default:
fprintf(stdout, UFLAG, eargv[0][1]);
continue;
}
if (cmdp == cmds) /* no commands have been compiled */
{
eargv--; eargc++;
eflag++; compile(); eflag = 0;
eargv++; eargc--;
}
if (bdepth) /* we have unbalanced squigglies */
die(TMLBR);
lablst->address = cmdp; /* set up header of label linked list */
resolve(); /* resolve label table indirections */
if (eargc <= 0) /* if there were no -e commands */
execute(NULL); /* execute commands from stdin only */
else while(--eargc>=0) /* else execute only -e commands */
execute(*eargv++);
exit(0); /* everything was O.K. if we got here */
}
#define H 0x80 /* 128 bit, on if there's really code for command */
#define LOWCMD 56 /* = '8', lowest char indexed in cmdmask */
/* indirect through this to get command internal code, if it exists */
static char cmdmask[] =
{
0, 0, H, 0, 0, H+EQCMD,0, 0,
0, 0, 0, 0, H+CDCMD,0, 0, CGCMD,
CHCMD, 0, 0, 0, H+CLCMD,0, CNCMD, 0,
CPCMD, 0, 0, 0, H+CTCMD,0, 0, H+CWCMD,
0, 0, 0, 0, 0, 0, 0, 0,
0, H+ACMD, H+BCMD, H+CCMD, DCMD, 0, 0, GCMD,
HCMD, H+ICMD, 0, 0, H+LCMD, 0, NCMD, 0,
PCMD, H+QCMD, H+RCMD, H+SCMD, H+TCMD, 0, 0, H+WCMD,
XCMD, H+YCMD, 0, H+BCMD, 0, H, 0, 0,
};
/* precompile sed commands out of a file */
static void compile(void)
{
char ccode;
for(;;) /* main compilation loop */
{
SKIPWS(cp);
if (*cp == ';') {
cp++;
SKIPWS(cp);
}
if (*cp == '\0' || *cp == '#') /* get a new command line */
if (cmdline(cp = linebuf) < 0)
break;
SKIPWS(cp);
if (*cp == '\0' || *cp == '#') /* a comment */
continue;
/* compile first address */
if (fp > poolend)
die(TMTXT);
else if ((fp = address(cmdp->addr1 = fp)) == BAD)
die(AGMSG);
if (fp == cmdp->addr1) /* if empty RE was found */
{
if (lastre) /* if there was previous RE */
cmdp->addr1 = lastre; /* use it */
else
die(FRENL);
}
else if (fp == NULL) /* if fp was NULL */
{
fp = cmdp->addr1; /* use current pool location */
cmdp->addr1 = NULL;
}
else
{
lastre = cmdp->addr1;
if (*cp == ',' || *cp == ';') /* there's 2nd addr */
{
cp++;
if (fp > poolend) die(TMTXT);
fp = address(cmdp->addr2 = fp);
if (fp == BAD || fp == NULL) die(AGMSG);
if (fp == cmdp->addr2)
cmdp->addr2 = lastre;
else
lastre = cmdp->addr2;
}
else
cmdp->addr2 = NULL; /* no 2nd address */
}
if (fp > poolend) die(TMTXT);
SKIPWS(cp); /* discard whitespace after address */
if (*cp == '!') {
cmdp->flags.allbut = 1;
cp++; SKIPWS(cp);
}
/* get cmd char, range-check it */
if ((*cp < LOWCMD) || (*cp > '~')
|| ((ccode = cmdmask[*cp - LOWCMD]) == 0))
die(NSCAX);
cmdp->command = ccode & ~H; /* fill in command value */
if ((ccode & H) == 0) /* if no compile-time code */
cp++; /* discard command char */
else if (cmdcomp(*cp++)) /* execute it; if ret = 1 */
continue; /* skip next line read */
if (++cmdp >= cmds + MAXCMDS) die(TMCDS);
SKIPWS(cp); /* look for trailing stuff */
if (*cp != '\0')
{
if (*cp == ';')
{
continue;
}
else if (*cp != '#' && *cp != '}')
die(TRAIL);
}
}
}
/* compile a single command */
static int cmdcomp(char cchar)
{
static sedcmd **cmpstk[MAXDEPTH]; /* current cmd stack for {} */
static const char *fname[WFILES]; /* w file name pointers */
static FILE *fout[WFILES]; /* w file file ptrs */
static int nwfiles = 2; /* count of open w files */
int i; /* indexing dummy used in w */
sedcmd *sp1, *sp2; /* temps for label searches */
label *lpt; /* ditto, and the searcher */
char redelim; /* current RE delimiter */
fout[0] = stdout;
fout[1] = stderr;
fname[0] = "/dev/stdout";
fname[1] = "/dev/stderr";
switch(cchar)
{
case '{': /* start command group */
cmdp->flags.allbut = !cmdp->flags.allbut;
cmpstk[bdepth++] = &(cmdp->u.link);
if (++cmdp >= cmds + MAXCMDS) die(TMCDS);
if (*cp == '\0') *cp++ = ';', *cp = '\0'; /* get next cmd w/o lineread */
return(1);
case '}': /* end command group */
if (cmdp->addr1) die(AD1NG); /* no addresses allowed */
if (--bdepth < 0) die(TMRBR); /* too many right braces */
*cmpstk[bdepth] = cmdp; /* set the jump address */
return(1);
case '=': /* print current source line number */
case 'q': /* exit the stream editor */
if (cmdp->addr2) die(AD2NG);
break;
case ':': /* label declaration */
if (cmdp->addr1) die(AD1NG); /* no addresses allowed */
fp = gettext(lab->name = fp); /* get the label name */
if ((lpt = search(lab))) /* does it have a double? */
{
if (lpt->address) die(DLABL); /* yes, abort */
}
else /* check that it doesn't overflow label table */
{
lab->last = NULL;
lpt = lab;
if (++lab >= labels + MAXLABS) die(TMLAB);
}
lpt->address = cmdp;
return(1);
case 'b': /* branch command */
case 't': /* branch-on-succeed command */
case 'T': /* branch-on-fail command */
SKIPWS(cp);
if (*cp == '\0') /* if branch is to start of cmds... */
{
/* add current command to end of label last */
if ((sp1 = lablst->last))
{
while((sp2 = sp1->u.link))
sp1 = sp2;
sp1->u.link = cmdp;
}
else /* lablst->last == NULL */
lablst->last = cmdp;
break;
}
fp = gettext(lab->name = fp); /* else get label into pool */
if ((lpt = search(lab))) /* enter branch to it */
{
if (lpt->address)
cmdp->u.link = lpt->address;
else
{
sp1 = lpt->last;
while((sp2 = sp1->u.link))
sp1 = sp2;
sp1->u.link = cmdp;
}
}
else /* matching named label not found */
{
lab->last = cmdp; /* add the new label */
lab->address = NULL; /* it's forward of here */
if (++lab >= labels + MAXLABS) /* overflow if last */
die(TMLAB);
}
break;
case 'a': /* append text */
case 'i': /* insert text */
case 'r': /* read file into stream */
if (cmdp->addr2) die(AD2NG);
case 'c': /* change text */
if ((*cp == '\\') && (*++cp == '\n')) cp++;
fp = gettext(cmdp->u.lhs = fp);
break;
case 'D': /* delete current line in hold space */
cmdp->u.link = cmds;
break;
case 's': /* substitute regular expression */
if (*cp == 0) /* get delimiter from 1st ch */
die(RETER);
else
redelim = *cp++;
if ((fp = recomp(cmdp->u.lhs = fp, redelim)) == BAD)
die(CGMSG);
if (fp == cmdp->u.lhs) { /* if compiled RE zero len */
if (lastre) {
cmdp->u.lhs = lastre; /* use the previous one */
cp++; /* skip delim */
}
else
die(FRENL);
}
else /* otherwise */
lastre = cmdp->u.lhs; /* save the one just found */
if ((cmdp->rhs = fp) > poolend) die(TMTXT);
if ((fp = rhscomp(cmdp->rhs, redelim)) == BAD) die(CGMSG);
if (gflag) cmdp->flags.global++;
while (*cp == 'g' || *cp == 'p' || *cp == 'P' || isdigit(*cp))
{
IFEQ(cp, 'g') cmdp->flags.global++;
IFEQ(cp, 'p') cmdp->flags.print = 1;
IFEQ(cp, 'P') cmdp->flags.print = 2;
if(isdigit(*cp))
{
if (cmdp->nth)
break; /* no multiple n args */
cmdp->nth = atoi(cp); /* check 0? */
while (isdigit(*cp)) cp++;
}
}
case 'l': /* list pattern space */
case 'L': /* dump pattern space */
if (*cp == 'w')
cp++; /* and execute a w command! */
else
break; /* s or L or l is done */
case 'w': /* write-pattern-space command */
case 'W': /* write-first-line command */
if (nwfiles >= WFILES) die(TMWFI);
fname[nwfiles] = fp;
fp = gettext((fname[nwfiles] = fp, fp)); /* filename will be in pool */
for(i = nwfiles-1; i >= 0; i--) /* match it in table */
if (strcmp(fname[nwfiles], fname[i]) == 0)
{
cmdp->fout = fout[i];
return(0);
}
/* if didn't find one, open new out file */
if ((cmdp->fout = fopen(fname[nwfiles], "w")) == NULL)
{
fprintf(stderr, CCOFI, fname[nwfiles]);
exit(2);
}
fout[nwfiles++] = cmdp->fout;
break;
case 'y': /* transliterate text */
fp = ycomp(cmdp->u.lhs = fp, *cp++); /* compile translit */
if (fp == BAD) die(CGMSG); /* fail on bad form */
if (fp > poolend) die(TMTXT); /* fail on overflow */
break;
}
return(0); /* succeeded in interpreting one command */
}
/* generate replacement string for substitute command right hand side
rhsp: place to compile expression to
delim: regular-expression end-mark to look for */
static char *rhscomp(char* rhsp, char delim) /* uses bcount */
{
register char *p = cp;
for(;;)
/* copy for the likely case it is not s.th. special */
if ((*rhsp = *p++) == '\\') /* back reference or escape */
{
if (*p >= '0' && *p <= '9') /* back reference */
{
dobackref:
*rhsp = *p++;
/* check validity of pattern tag */
if (*rhsp > bcount + '0')
return(BAD);
*rhsp++ |= 0x80; /* mark the good ones */
}
else /* escape */
{
switch (*p) {
case 'n': *rhsp = '\n'; break;
case 'r': *rhsp = '\r'; break;
case 't': *rhsp = '\t'; break;
default: *rhsp = *p;
}
rhsp++; p++;
}
}
else if (*rhsp == delim) /* found RE end, hooray... */
{
*rhsp++ = '\0'; /* cap the expression string */
cp = p;
return(rhsp); /* pt at 1 past the RE */
}
else if (*rhsp == '&') /* special case, convert to backref \0 */
{
*--p = '0';
goto dobackref;
}
else if (*rhsp++ == '\0') /* last ch not RE end, help! */
return(BAD);
}
/* compile a regular expression to internal form
expbuf: place to compile it to
redelim: RE end-marker to look for */
static char *recomp(char *expbuf, char redelim) /* uses cp, bcount */
{
register char *ep = expbuf; /* current-compiled-char pointer */
register char *sp = cp; /* source-character ptr */
register int c; /* current-character pointer */
char negclass; /* all-but flag */
char *lastep; /* ptr to last expr compiled */
char *lastep2; /* dito, but from the last loop */
char *svclass; /* start of current char class */
char brnest[MAXTAGS]; /* bracket-nesting array */
char *brnestp; /* ptr to current bracket-nest */
char *pp; /* scratch pointer */
int classct; /* class element count */
int tags; /* # of closed tags */
if (*cp == redelim) { /* if first char is RE endmarker */
return(ep);
}
lastep = lastep2 = NULL; /* there's no previous RE */
brnestp = brnest; /* initialize ptr to brnest array */
tags = bcount = 0; /* initialize counters */
if ((*ep++ = (*sp == '^'))) /* check for start-of-line syntax */
sp++;
for (;;)
{
if (*sp == 0) /* no termination */
die (RETER);
if (ep >= expbuf + RELIMIT) /* match is too large */
return(cp = sp, BAD);
if ((c = *sp++) == redelim) /* found the end of the RE */
{
cp = sp;
if (brnestp != brnest) /* \(, \) unbalanced */
return(BAD);
*ep++ = CEOF; /* write end-of-pattern mark */
return(ep); /* return ptr to compiled RE */
}
lastep = lastep2;
lastep2 = ep;
switch (c)
{
case '\\':
if ((c = *sp++) == '(') /* start tagged section */
{
if (bcount >= MAXTAGS)
return(cp = sp, BAD);
*brnestp++ = bcount; /* update tag stack */
*ep++ = CBRA; /* enter tag-start */
*ep++ = bcount++; /* bump tag count */
lastep2 = NULL;
continue;
}
else if (c == ')') /* end tagged section */
{
if (brnestp <= brnest) /* extra \) */
return(cp = sp, BAD);
*ep++ = CKET; /* enter end-of-tag */
*ep++ = *--brnestp; /* pop tag stack */
tags++; /* count closed tags */
for (lastep2 = ep-1; *lastep2 != CBRA; )
--lastep2; /* FIXME: lastep becomes start */
continue;
}
else if (c >= '1' && c <= '9' && c != redelim) /* tag use, if !delim */
{
if ((c -= '1') >= tags) /* too few */
return(BAD);
*ep++ = CBACK; /* enter tag mark */
*ep++ = c; /* and the number */
continue;
}
else if (c == '\n') /* escaped newline no good */
return(cp = sp, BAD);
else if (c == 'n') /* match a newline */
c = '\n';
else if (c == 't') /* match a tab */
c = '\t';
else if (c == 'r') /* match a return */
c = '\r';
else if (c == '+') /* 1..n repeat of previous pattern */
{
if (lastep == NULL) /* if + not first on line */
goto defchar; /* match a literal + */
pp = ep; /* else save old ep */
*ep++ = *lastep++ | STAR; /* flag the copy */
while (lastep < pp) /* so we can blt the pattern */
*ep++ = *lastep++;
lastep2 = lastep; /* no new expression */
continue;
}
goto defchar; /* else match \c */
case '\0': /* ignore nuls */
continue;
case '\n': /* trailing pattern delimiter is missing */
return(cp = sp, BAD);
case '.': /* match any char except newline */
*ep++ = CDOT;
continue;
case '*': /* 0..n repeat of previous pattern */
if (lastep == NULL) /* if * isn't first on line */
goto defchar; /* match a literal * */
*lastep |= STAR; /* flag previous pattern */
lastep2 = lastep; /* no new expression */
continue;
case '$': /* match only end-of-line */
if (*sp != redelim) /* if we're not at end of RE */
goto defchar; /* match a literal $ */
*ep++ = CDOL; /* insert end-symbol mark */
continue;
case '[': /* begin character set pattern */
if (ep + 17 >= expbuf + RELIMIT)
die(REITL);
*ep++ = CCL; /* insert class mark */
if ((negclass = ((c = *sp++) == '^')))
c = *sp++;
svclass = sp; /* save ptr to class start */
do {
if (c == '\0') die(CGMSG);
/* handle predefined character classes */
if (c == '[' && *sp == ':')
{
/* look for the matching ":]]" */
char *p;
const char *p2;
for (p = sp+3; *p; p++)
if (*p == ']' &&
*(p-1) == ']' &&
*(p-2) == ':')
{
char cc[8];
const char **it;
p2 = sp+1;
for (p2 = sp+1;
p2 < p-2 && p2-sp-1 < sizeof(cc);
p2++)
cc[p2-sp-1] = *p2;
cc[p2-sp-1] = 0; /* termination */
it = cclasses;
while (*it && strcmp(*it, cc))
it +=2;
if (!*it++)
die(CCERR);
/* generate mask */
p2 = *it;
while (*p2) {
if (p2[1] == '-' && p2[2]) {
for (c = *p2; c <= p2[2]; c++)
ep[c >> 3] |= bits(c & 7);
p2 += 3;
}
else {
c = *p2++;
ep[c >> 3] |= bits(c & 7);
}
}
sp = p; c = 0; break;
}
}
/* handle character ranges */
if (c == '-' && sp > svclass && *sp != ']')
for (c = sp[-2]; c < *sp; c++)
ep[c >> 3] |= bits(c & 7);
/* handle escape sequences in sets */
if (c == '\\')
{
if ((c = *sp++) == 'n')
c = '\n';
else if (c == 't')
c = '\t';
else if (c == 'r')
c = '\r';
}
/* enter (possibly translated) char in set */
if (c)
ep[c >> 3] |= bits(c & 7);
} while
((c = *sp++) != ']');
/* invert the bitmask if all-but was specified */
if (negclass)
for(classct = 0; classct < 16; classct++)
ep[classct] ^= 0xFF;
ep[0] &= 0xFE; /* never match ASCII 0 */
ep += 16; /* advance ep past set mask */
continue;
defchar: /* match literal character */
default: /* which is what we'd do by default */
*ep++ = CCHR; /* insert character mark */
*ep++ = c;
}
}
}
/* read next command from -e argument or command file */
static int cmdline(char *cbuf) /* uses eflag, eargc, cmdf */
{
register int inc; /* not char because must hold EOF */
cbuf--; /* so pre-increment points us at cbuf */
/* e command flag is on */
if (eflag)
{
register char *p; /* ptr to current -e argument */
static char *savep; /* saves previous value of p */
if (eflag > 0) /* there are pending -e arguments */
{
eflag = -1;
if (eargc-- <= 0)
exit(2); /* if no arguments, barf */
/* else transcribe next e argument into cbuf */
p = *++eargv;
while((*++cbuf = *p++))
if (*cbuf == '\\')
{
if ((*++cbuf = *p++) == '\0')
return(savep = NULL, -1);
else
continue;
}
else if (*cbuf == '\n') /* end of 1 cmd line */
{
*cbuf = '\0';
return(savep = p, 1);
/* we'll be back for the rest... */
}
/* found end-of-string; can advance to next argument */
return(savep = NULL, 1);
}
if ((p = savep) == NULL)
return(-1);
while((*++cbuf = *p++))
if (*cbuf == '\\')
{
if ((*++cbuf = *p++) == '0')
return(savep = NULL, -1);
else
continue;
}
else if (*cbuf == '\n')
{
*cbuf = '\0';
return(savep = p, 1);
}
return(savep = NULL, 1);
}
/* if no -e flag read from command file descriptor */
while((inc = getc(cmdf)) != EOF) /* get next char */
if ((*++cbuf = inc) == '\\') /* if it's escape */
*++cbuf = inc = getc(cmdf); /* get next char */
else if (*cbuf == '\n') /* end on newline */
return(*cbuf = '\0', 1); /* cap the string */
return(*++cbuf = '\0', -1); /* end-of-file, no more chars */
}
/* expand an address at *cp... into expbuf, return ptr at following char */
static char *address(char *expbuf) /* uses cp, linenum */
{
static int numl = 0; /* current ind in addr-number table */
register char *rcp; /* temp compile ptr for forwd look */
long lno; /* computed value of numeric address */
if (*cp == '$') /* end-of-source address */
{
*expbuf++ = CEND; /* write symbolic end address */
*expbuf++ = CEOF; /* and the end-of-address mark (!) */
cp++; /* go to next source character */
last_line_used = TRUE;
return(expbuf); /* we're done */
}
if (*cp == '/') /* start of regular-expression match */
return(recomp(expbuf, *cp++)); /* compile the RE */
rcp = cp; lno = 0; /* now handle a numeric address */
while(*rcp >= '0' && *rcp <= '9') /* collect digits */
lno = lno*10 + *rcp++ - '0'; /* compute their value */
if (rcp > cp) /* if we caught a number... */
{
*expbuf++ = CLNUM; /* put a numeric-address marker */
*expbuf++ = numl; /* and the address table index */
linenum[numl++] = lno; /* and set the table entry */
if (numl >= MAXLINES) /* oh-oh, address table overflow */
die(TMLNR); /* abort with error message */
*expbuf++ = CEOF; /* write the end-of-address marker */
cp = rcp; /* point compile past the address */
return(expbuf); /* we're done */
}
return(NULL); /* no legal address was found */
}
/* accept multiline input from *cp..., discarding leading whitespace
txp: where to put the text */
static char *gettext(char* txp) /* uses global cp */
{
register char *p = cp;
SKIPWS(p); /* discard whitespace */
do {
if ((*txp = *p++) == '\\') /* handle escapes */
*txp = *p++;
if (*txp == '\0') /* we're at end of input */
return(cp = --p, ++txp);
else if (*txp == '\n') /* also SKIPWS after newline */
SKIPWS(p);
} while (txp++); /* keep going till we find that nul */
return(txp);
}
/* find the label matching *ptr, return NULL if none */
static label *search(label *ptr) /* uses global lablst */
{
register label *rp;
for(rp = lablst; rp < ptr; rp++)
if ((rp->name != NULL) && (strcmp(rp->name, ptr->name) == 0))
return(rp);
return(NULL);
}
/* write label links into the compiled-command space */
static void resolve(void) /* uses global lablst */
{
register label *lptr;
register sedcmd *rptr, *trptr;
/* loop through the label table */
for(lptr = lablst; lptr < lab; lptr++)
if (lptr->address == NULL) /* barf if not defined */
{
fprintf(stderr, ULABL, lptr->name);
exit(2);
}
else if (lptr->last) /* if last is non-null */
{
rptr = lptr->last; /* chase it */
while((trptr = rptr->u.link)) /* resolve refs */
{
rptr->u.link = lptr->address;
rptr = trptr;
}
rptr->u.link = lptr->address;
}
}
/* compile a y (transliterate) command
ep: where to compile to
delim: end delimiter to look for */
static char *ycomp(char *ep, char delim)
{
char *tp, *sp;
int c;
/* scan the 'from' section for invalid chars */
for(sp = tp = cp; *tp != delim; tp++)
{
if (*tp == '\\')
tp++;
if ((*tp == '\n') || (*tp == '\0'))
return(BAD);
}
tp++; /* tp now points at first char of 'to' section */
/* now rescan the 'from' section */
while((c = *sp++ & 0x7F) != delim)
{
if (c == '\\' && *sp == 'n')
{
sp++;
c = '\n';
}
if ((ep[c] = *tp++) == '\\' && *tp == 'n')
{
ep[c] = '\n';
tp++;
}
if ((ep[c] == delim) || (ep[c] == '\0'))
return(BAD);
}
if (*tp != delim) /* 'to', 'from' parts have unequal lengths */
return(BAD);
cp = ++tp; /* point compile ptr past translit */
for(c = 0; c < 128; c++) /* fill in self-map entries in table */
if (ep[c] == 0)
ep[c] = c;
return(ep + 0x80); /* return first free location past table end */
}
/* sedcomp.c ends here */

View file

@ -1,819 +0,0 @@
/* sedexec.c -- axecute compiled form of stream editor commands
Copyright (C) 1995-2003 Eric S. Raymond
Copyright (C) 2004-2006 Rene Rebe
The single entry point of this module is the function execute(). It
may take a string argument (the name of a file to be used as text) or
the argument NULL which tells it to filter standard input. It executes
the compiled commands in cmds[] on each line in turn.
The function command() does most of the work. match() and advance()
are used for matching text against precompiled regular expressions and
dosub() does right-hand-side substitution. Getline() does text input;
readout() and memcmp() are output and string-comparison utilities.
*/
#include <stdlib.h> /* exit */
#include <stdio.h> /* {f}puts, {f}printf, getc/putc, f{re}open, fclose */
#include <ctype.h> /* for isprint(), isdigit(), toascii() macros */
#include <string.h> /* for memcmp(3) */
#include "sed.h" /* command type structures & miscellaneous constants */
/***** shared variables imported from the main ******/
/* main data areas */
extern char linebuf[]; /* current-line buffer */
extern sedcmd cmds[]; /* hold compiled commands */
extern long linenum[]; /* numeric-addresses table */
/* miscellaneous shared variables */
extern int nflag; /* -n option flag */
extern int eargc; /* scratch copy of argument count */
extern sedcmd *pending; /* ptr to command waiting to be executed */
extern int last_line_used; /* last line address ($) used */
/***** end of imported stuff *****/
#define MAXHOLD MAXBUF /* size of the hold space */
#define GENSIZ MAXBUF /* maximum genbuf size */
static char LTLMSG[] = "sed: line too long\n";
static char *spend; /* current end-of-line-buffer pointer */
static long lnum = 0L; /* current source line number */
/* append buffer maintenance */
static sedcmd *appends[MAXAPPENDS]; /* array of ptrs to a,i,c commands */
static sedcmd **aptr = appends; /* ptr to current append */
/* genbuf and its pointers */
static char genbuf[GENSIZ];
static char *loc1;
static char *loc2;
static char *locs;
/* command-logic flags */
static int lastline; /* do-line flag */
static int line_with_newline; /* line had newline */
static int jump; /* jump to cmd's link address if set */
static int delete; /* delete command flag */
static int needs_advance; /* needs inc after substitution */
/* ugly HACK - neds REWORK */
/* tagged-pattern tracking */
static char *bracend[MAXTAGS]; /* tagged pattern start pointers */
static char *brastart[MAXTAGS]; /* tagged pattern end pointers */
/* prototypes */
static char *getline(char *buf, int max);
static char *place(char* asp, char* al1, char* al2);
static int advance(char* lp, char* ep, char** eob);
static int match(char *expbuf, int gf);
static int selected(sedcmd *ipc);
static int substitute(sedcmd *ipc);
static void command(sedcmd *ipc);
static void dosub(char *rhsbuf);
static void dumpto(char *p1, FILE *fp);
static void listto(char *p1, FILE *fp);
static void readout(void);
static void truncated(int h);
/* execute the compiled commands in cmds[] on a file
file: name of text source file to be filtered */
void execute(char* file)
{
register sedcmd *ipc; /* ptr to current command */
char *execp; /* ptr to source */
if (file != NULL) /* filter text from a named file */
if (freopen(file, "r", stdin) == NULL)
fprintf(stderr, "sed: can't open %s\n", file);
if (pending) /* there's a command waiting */
{
ipc = pending; /* it will be first executed */
pending = FALSE; /* turn off the waiting flag */
goto doit; /* go to execute it immediately */
}
/* here's the main command-execution loop */
for(;;)
{
/* get next line to filter */
if ((execp = getline(linebuf, MAXBUF+1)) == BAD)
return;
spend = execp;
/* loop through compiled commands, executing them */
for(ipc = cmds; ipc->command; )
{
/* address command to select? - If not address
but allbut then invert, that is skip, the commmand */
if (ipc->addr1 || ipc->flags.allbut) {
if (!ipc->addr1 || !selected(ipc)) {
ipc++; /* not selected, next cmd */
continue;
}
}
doit:
command(ipc); /* execute the command pointed at */
if (delete) /* if delete flag is set */
break; /* don't exec rest of compiled cmds */
if (jump) /* if jump set, follow cmd's link */
{
jump = FALSE;
if ((ipc = ipc->u.link) == 0)
{
ipc = cmds;
break;
}
}
else /* normal goto next command */
ipc++;
}
/* we've now done all modification commands on the line */
/* here's where the transformed line is output */
if (!nflag && !delete)
{
fwrite(linebuf, spend - linebuf, 1, stdout);
if (line_with_newline)
putc('\n', stdout);
}
/* if we've been set up for append, emit the text from it */
if (aptr > appends)
readout();
delete = FALSE; /* clear delete flag; about to get next cmd */
}
}
/* is current command selected */
static int selected(sedcmd *ipc)
{
register char *p1 = ipc->addr1; /* point p1 at first address */
register char *p2 = ipc->addr2; /* and p2 at second */
unsigned char c;
int selected = FALSE;
if (ipc->flags.inrange)
{
selected = TRUE;
if (*p2 == CEND)
;
else if (*p2 == CLNUM)
{
c = p2[1];
if (lnum >= linenum[c])
ipc->flags.inrange = FALSE;
}
else if (match(p2, 0))
ipc->flags.inrange = FALSE;
}
else if (*p1 == CEND)
{
if (lastline)
selected = TRUE;
}
else if (*p1 == CLNUM)
{
c = p1[1];
if (lnum == linenum[c]) {
selected = TRUE;
if (p2)
ipc->flags.inrange = TRUE;
}
}
else if (match(p1, 0))
{
selected = TRUE;
if (p2)
ipc->flags.inrange = TRUE;
}
return ipc->flags.allbut ? !selected : selected;
}
/* match RE at expbuf against linebuf; if gf set, copy linebuf from genbuf */
static int match(char *expbuf, int gf) /* uses genbuf */
{
char *p1, *p2, c;
if (gf)
{
if (*expbuf)
return(FALSE);
p1 = linebuf; p2 = genbuf;
while ((*p1++ = *p2++));
if (needs_advance) {
loc2++;
}
locs = p1 = loc2;
}
else
{
p1 = linebuf + needs_advance;
locs = FALSE;
}
needs_advance = 0;
p2 = expbuf;
if (*p2++)
{
loc1 = p1;
if(*p2 == CCHR && p2[1] != *p1) /* 1st char is wrong */
return(FALSE); /* so fail */
return(advance(p1, p2, NULL)); /* else try to match rest */
}
/* quick check for 1st character if it's literal */
if (*p2 == CCHR)
{
c = p2[1]; /* pull out character to search for */
do {
if (*p1 != c)
continue; /* scan the source string */
if (advance(p1, p2,NULL)) /* found it, match the rest */
return(loc1 = p1, 1);
} while
(*p1++);
return(FALSE); /* didn't find that first char */
}
/* else try for unanchored match of the pattern */
do {
if (advance(p1, p2, NULL))
return(loc1 = p1, 1);
} while
(*p1++);
/* if got here, didn't match either way */
return(FALSE);
}
/* attempt to advance match pointer by one pattern element
lp: source (linebuf) ptr
ep: regular expression element ptr */
static int advance(char* lp, char* ep, char** eob)
{
char *curlp; /* save ptr for closures */
char c; /* scratch character holder */
char *bbeg;
int ct;
signed int bcount = -1;
for (;;)
switch (*ep++)
{
case CCHR: /* literal character */
if (*ep++ == *lp++) /* if chars are equal */
continue; /* matched */
return(FALSE); /* else return false */
case CDOT: /* anything but newline */
if (*lp++) /* first NUL is at EOL */
continue; /* keep going if didn't find */
return(FALSE); /* else return false */
case CNL: /* start-of-line */
case CDOL: /* end-of-line */
if (*lp == 0) /* found that first NUL? */
continue; /* yes, keep going */
return(FALSE); /* else return false */
case CEOF: /* end-of-address mark */
loc2 = lp; /* set second loc */
return(TRUE); /* return true */
case CCL: /* a closure */
c = *lp++ & 0177;
if (ep[c>>3] & bits(c & 07)) /* is char in set? */
{
ep += 16; /* then skip rest of bitmask */
continue; /* and keep going */
}
return(FALSE); /* else return false */
case CBRA: /* start of tagged pattern */
brastart[(unsigned char)*ep++] = lp; /* mark it */
continue; /* and go */
case CKET: /* end of tagged pattern */
bcount = *ep;
if (eob) {
*eob = lp;
return (TRUE);
}
else
bracend[(unsigned char)*ep++] = lp; /* mark it */
continue; /* and go */
case CBACK: /* match back reference */
bbeg = brastart[(unsigned char)*ep];
ct = bracend[(unsigned char)*ep++] - bbeg;
if (memcmp(bbeg, lp, ct) == 0)
{
lp += ct;
continue;
}
return(FALSE);
case CBRA|STAR: /* \(...\)* */
{
char *lastlp;
curlp = lp;
if (*ep > bcount)
brastart[(unsigned char)*ep] = bracend[(unsigned char)*ep] = lp;
while (advance(lastlp=lp, ep+1, &lp)) {
if (*ep > bcount && lp != lastlp) {
bracend[(unsigned char)*ep] = lp; /* mark it */
brastart[(unsigned char)*ep] = lastlp;
}
if (lp == lastlp) break;
}
ep++;
/* FIXME: scan for the brace end */
while (*ep != CKET)
ep++;
ep+=2;
needs_advance = 1;
if (lp == curlp) /* 0 matches */
continue;
lp++;
goto star;
}
case CBACK|STAR: /* \n* */
bbeg = brastart[(unsigned char)*ep];
ct = bracend[(unsigned char)*ep++] - bbeg;
curlp = lp;
while(memcmp(bbeg, lp, ct) == 0)
lp += ct;
while(lp >= curlp)
{
if (advance(lp, ep, eob))
return(TRUE);
lp -= ct;
}
return(FALSE);
case CDOT|STAR: /* match .* */
curlp = lp; /* save closure start loc */
while (*lp++); /* match anything */
goto star; /* now look for followers */
case CCHR|STAR: /* match <literal char>* */
curlp = lp; /* save closure start loc */
while (*lp++ == *ep); /* match many of that char */
ep++; /* to start of next element */
goto star; /* match it and followers */
case CCL|STAR: /* match [...]* */
curlp = lp; /* save closure start loc */
do {
c = *lp++ & 0x7F; /* match any in set */
} while
(ep[c>>3] & bits(c & 07));
ep += 16; /* skip past the set */
goto star; /* match followers */
star: /* the recursion part of a * or + match */
needs_advance = 1;
if (--lp == curlp) { /* 0 matches */
continue;
}
#if 0
if (*ep == CCHR)
{
c = ep[1];
do {
if (*lp != c)
continue;
if (advance(lp, ep, eob))
return(TRUE);
} while
(lp-- > curlp);
return(FALSE);
}
if (*ep == CBACK)
{
c = *(brastart[ep[1]]);
do {
if (*lp != c)
continue;
if (advance(lp, ep, eob))
return(TRUE);
} while
(lp-- > curlp);
return(FALSE);
}
#endif
/* match followers, try shorter match, if needed */
do {
if (lp == locs)
break;
if (advance(lp, ep, eob))
return(TRUE);
} while
(lp-- > curlp);
return(FALSE);
default:
fprintf(stderr, "sed: internal RE error, %o\n", *--ep);
exit (2);
}
}
/* perform s command
ipc: ptr to s command struct */
static int substitute(sedcmd *ipc)
{
unsigned int n = 1;
/* find a match */
/* the needs_advance code got a bit tricky - might needs a clean
refactoring */
while (match(ipc->u.lhs, 0)) {
/* nth 0 is implied 1 */
if (!ipc->nth || n == ipc->nth) {
dosub(ipc->rhs); /* perform it once */
n++; /* mark for return */
break;
}
needs_advance = n++;
}
if (n == 1)
return(FALSE); /* command fails */
if (ipc->flags.global) /* if global flag enabled */
do { /* cycle through possibles */
if (match(ipc->u.lhs, 1)) { /* found another */
dosub(ipc->rhs); /* so substitute */
}
else /* otherwise, */
break; /* we're done */
} while (*loc2);
return(TRUE); /* we succeeded */
}
/* generate substituted right-hand side (of s command)
rhsbuf: where to put the result */
static void dosub(char *rhsbuf) /* uses linebuf, genbuf, spend */
{
char *lp, *sp, *rp;
int c;
/* copy linebuf to genbuf up to location 1 */
lp = linebuf; sp = genbuf;
while (lp < loc1) *sp++ = *lp++;
for (rp = rhsbuf; (c = *rp++); )
{
if (c & 0200 && (c & 0177) == '0')
{
sp = place(sp, loc1, loc2);
continue;
}
else if (c & 0200 && (c &= 0177) >= '1' && c < MAXTAGS+'1')
{
sp = place(sp, brastart[c-'1'], bracend[c-'1']);
continue;
}
*sp++ = c & 0177;
if (sp >= genbuf + MAXBUF)
fprintf(stderr, LTLMSG);
}
lp = loc2;
loc2 = sp - genbuf + linebuf;
while ((*sp++ = *lp++))
if (sp >= genbuf + MAXBUF)
fprintf(stderr, LTLMSG);
lp = linebuf; sp = genbuf;
while ((*lp++ = *sp++));
spend = lp-1;
}
/* place chars at *al1...*(al1 - 1) at asp... in genbuf[] */
static char *place(char* asp, char* al1, char* al2) /* uses genbuf */
{
while (al1 < al2)
{
*asp++ = *al1++;
if (asp >= genbuf + MAXBUF)
fprintf(stderr, LTLMSG);
}
return(asp);
}
/* list the pattern space in visually unambiguous form *p1... to fp
p1: the source
fp: output stream to write to */
static void listto(char *p1, FILE *fp)
{
for (; p1<spend; p1++)
if (isprint(*p1))
putc(*p1, fp); /* pass it through */
else
{
putc('\\', fp); /* emit a backslash */
switch(*p1)
{
case '\b': putc('b', fp); break; /* BS */
case '\t': putc('t', fp); break; /* TAB */
case '\n': putc('n', fp); break; /* NL */
case '\r': putc('r', fp); break; /* CR */
case '\033': putc('e', fp); break; /* ESC */
default: fprintf(fp, "%02x", *p1);
}
}
putc('\n', fp);
}
/* write a hex dump expansion of *p1... to fp
p1: source
fp: output */
static void dumpto(char *p1, FILE *fp)
{
for (; p1<spend; p1++)
fprintf(fp, "%02x", *p1);
fprintf(fp, "%02x", '\n');
putc('\n', fp);
}
static void truncated(int h)
{
static long last = 0L;
if (lnum == last) return;
last = lnum;
fprintf(stderr, "sed: ");
fprintf(stderr, h ? "hold space" : "line %ld", lnum);
fprintf(stderr, " truncated to %d characters\n", MAXBUF);
}
/* execute compiled command pointed at by ipc */
static void command(sedcmd *ipc)
{
static int didsub; /* true if last s succeeded */
static char holdsp[MAXHOLD]; /* the hold space */
static char *hspend = holdsp; /* hold space end pointer */
register char *p1, *p2;
char *execp;
needs_advance = 0;
switch(ipc->command)
{
case ACMD: /* append */
*aptr++ = ipc;
if (aptr >= appends + MAXAPPENDS)
fprintf(stderr,
"sed: too many appends after line %ld\n",
lnum);
*aptr = 0;
break;
case CCMD: /* change pattern space */
delete = TRUE;
if (!ipc->flags.inrange || lastline)
printf("%s\n", ipc->u.lhs);
break;
case DCMD: /* delete pattern space */
delete++;
break;
case CDCMD: /* delete a line in hold space */
p1 = p2 = linebuf;
while(*p1 != '\n')
if ((delete = (*p1++ == 0)))
return;
p1++;
while((*p2++ = *p1++)) continue;
spend = p2-1;
jump++;
break;
case EQCMD: /* show current line number */
fprintf(stdout, "%ld\n", lnum);
break;
case GCMD: /* copy hold space to pattern space */
p1 = linebuf; p2 = holdsp; while((*p1++ = *p2++));
spend = p1-1;
break;
case CGCMD: /* append hold space to pattern space */
*spend++ = '\n';
p1 = spend; p2 = holdsp;
do {
if (p1 > linebuf + MAXBUF) {
truncated(FALSE);
p1[-1] = 0;
break;
}
} while((*p1++ = *p2++));
spend = p1-1;
break;
case HCMD: /* copy pattern space to hold space */
p1 = holdsp; p2 = linebuf; while((*p1++ = *p2++));
hspend = p1-1;
break;
case CHCMD: /* append pattern space to hold space */
*hspend++ = '\n';
p1 = hspend; p2 = linebuf;
do {
if (p1 > holdsp + MAXBUF) {
truncated(TRUE);
p1[-1] = 0;
break;
}
} while((*p1++ = *p2++));
hspend = p1-1;
break;
case ICMD: /* insert text */
printf("%s\n", ipc->u.lhs);
break;
case BCMD: /* branch to label */
jump = TRUE;
break;
case LCMD: /* list text */
listto(linebuf, (ipc->fout != NULL)?ipc->fout:stdout); break;
case CLCMD: /* dump text */
dumpto(linebuf, (ipc->fout != NULL)?ipc->fout:stdout); break;
case NCMD: /* read next line into pattern space */
if (!nflag)
puts(linebuf); /* flush out the current line */
if (aptr > appends)
readout(); /* do pending a, r commands */
if ((execp = getline(linebuf, MAXBUF+1)) == BAD)
{
pending = ipc;
delete = TRUE;
break;
}
spend = execp;
break;
case CNCMD: /* append next line to pattern space */
if (aptr > appends)
readout();
*spend++ = '\n';
if ((execp = getline(spend,
linebuf + MAXBUF+1 - spend)) == BAD)
{
pending = ipc;
delete = TRUE;
break;
}
spend = execp;
break;
case PCMD: /* print pattern space */
puts(linebuf);
break;
case CPCMD: /* print one line from pattern space */
cpcom: /* so s command can jump here */
for(p1 = linebuf; *p1 != '\n' && *p1 != '\0'; )
putc(*p1++, stdout);
putc('\n', stdout);
break;
case QCMD: /* quit the stream editor */
if (!nflag)
puts(linebuf); /* flush out the current line */
if (aptr > appends)
readout(); /* do any pending a and r commands */
exit(0);
case RCMD: /* read a file into the stream */
*aptr++ = ipc;
if (aptr >= appends + MAXAPPENDS)
fprintf(stderr,
"sed: too many reads after line %ld\n",
lnum);
*aptr = 0;
break;
case SCMD: /* substitute RE */
didsub = substitute(ipc);
if (ipc->flags.print && didsub)
{
if (ipc->flags.print == TRUE)
puts(linebuf);
else
goto cpcom;
}
if (didsub && ipc->fout)
fprintf(ipc->fout, "%s\n", linebuf);
break;
case TCMD: /* branch on last s successful */
case CTCMD: /* branch on last s failed */
if (didsub == (ipc->command == CTCMD))
break; /* no branch if last s failed, else */
didsub = FALSE;
jump = TRUE; /* set up to jump to assoc'd label */
break;
case CWCMD: /* write one line from pattern space */
for(p1 = linebuf; *p1 != '\n' && *p1 != '\0'; )
putc(*p1++, ipc->fout);
putc('\n', ipc->fout);
break;
case WCMD: /* write pattern space to file */
fprintf(ipc->fout, "%s\n", linebuf);
break;
case XCMD: /* exchange pattern and hold spaces */
p1 = linebuf; p2 = genbuf; while((*p2++ = *p1++)) continue;
p1 = holdsp; p2 = linebuf; while((*p2++ = *p1++)) continue;
spend = p2 - 1;
p1 = genbuf; p2 = holdsp; while((*p2++ = *p1++)) continue;
hspend = p2 - 1;
break;
case YCMD:
p1 = linebuf; p2 = ipc->u.lhs;
while((*p1 = p2[(unsigned char)*p1]))
p1++;
break;
}
}
/* get next line of text to be filtered
buf: where to send the input
max: max chars to read */
static char *getline(char *buf, int max)
{
if (fgets(buf, max, stdin) != NULL)
{
int c;
lnum++; /* note that we got another line */
/* find the end of the input and overwrite a possible '\n' */
while (*buf != '\n' && *buf != 0)
buf++;
line_with_newline = *buf == '\n';
*buf=0;
/* detect last line - but only if the address was used in a command */
if (last_line_used) {
if ((c = fgetc(stdin)) != EOF)
ungetc (c, stdin);
else {
if (eargc == 0) /* if no more args */
lastline = TRUE; /* set a flag */
}
}
return(buf); /* return ptr to terminating null */
}
else
{
return(BAD);
}
}
/* write file indicated by r command to output */
static void readout(void)
{
register int t; /* hold input char or EOF */
FILE *fi; /* ptr to file to be read */
aptr = appends - 1; /* arrange for pre-increment to work right */
while(*++aptr)
if ((*aptr)->command == ACMD) /* process "a" cmd */
printf("%s\n", (*aptr)->u.lhs);
else /* process "r" cmd */
{
if ((fi = fopen((*aptr)->u.lhs, "r")) == NULL)
continue;
while((t = getc(fi)) != EOF)
putc((char) t, stdout);
fclose(fi);
}
aptr = appends; /* reset the append ptr */
*aptr = 0;
}
/* sedexec.c ends here */