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:
parent
8c88a0219b
commit
c460974814
75 changed files with 0 additions and 15019 deletions
|
@ -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
|
|
@ -1,3 +0,0 @@
|
|||
#!/bin/sh
|
||||
make clean
|
||||
make && make install
|
|
@ -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);
|
||||
}
|
|
@ -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));
|
|
@ -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);
|
||||
}
|
|
@ -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));
|
|
@ -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);
|
||||
}
|
|
@ -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));
|
|
@ -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);
|
||||
}
|
|
@ -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));
|
|
@ -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));
|
||||
}
|
|
@ -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));
|
|
@ -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
|
||||
|
||||
|
|
@ -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)
|
|
@ -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.
|
|
@ -1,3 +0,0 @@
|
|||
#!/bin/sh
|
||||
make clean
|
||||
make && make install
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
|
@ -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 ? ">" : " ");
|
||||
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);
|
||||
}
|
|
@ -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
|
|
@ -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));
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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];
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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';
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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));
|
|
@ -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
|
||||
|
||||
|
|
@ -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)
|
|
@ -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.
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
|
@ -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 ? ">" : " ");
|
||||
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);
|
||||
}
|
|
@ -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
|
|
@ -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));
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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];
|
|
@ -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);
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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';
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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));
|
|
@ -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
|
1059
commands/i86/cc.c
1059
commands/i86/cc.c
File diff suppressed because it is too large
Load diff
|
@ -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>
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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 */
|
Loading…
Reference in a new issue