Playing around with 4.3BSD in simh vax emulator, I wanted to put the 4.3BSD to some use. I have used my image that I have made available here https://astr0baby.wordpress.com/2019/09/22/4-3bsd-and-metasploit/ which includes GCC to compile the code.
While I could not compile the first ever web server on it (w3c-httpd)
drwxr-xr-x 6 root 512 Oct 16 16:05 . drwxr-xr-x 5 root 512 Oct 16 16:53 .. drwxr-xr-x 32 13449 1024 Jun 23 1996 All -rwxr-xr-x 1 13449 3111 Sep 24 1994 BUILD -rwxr-xr-x 1 13449 3076 Sep 23 1994 BUILD.SH -rw-r--r-- 1 13449 495 Jun 23 1996 CERN -rw-r--r-- 1 13449 1834 Jun 23 1996 COPYRIGH drwxr-xr-x 4 13449 512 Jul 15 1996 Daemon drwxr-xr-x 4 13449 512 Oct 16 16:09 Library -rw-r--r-- 1 13449 580 Jun 11 1994 Makefile -rw-r--r-- 1 13449 1823 Jun 23 1996 README -rw-r--r-- 1 13449 5218 Jun 11 1994 README-SOCKS drwxr-xr-x 4 13449 512 Jul 8 1994 server_root -rw-r--r-- 1 root 2703360 Oct 16 16:04 w3c-httpd-3.0A.tar
I was able to run Nigel Griffith’s nweb.c on it quite smoothly without any issues, the code compiles on the VAX 4.3BSD with an ancient gcc version 2.7.2.2
The original article is here https://www.ibm.com/developerworks/systems/library/es-nweb/index.html
nweb is a small and very safe mini web server
nweb only servers out file/web pages with extensions named below
and only from the named directory or its sub-directories.
There is no fancy features = safe and secure.
Example: nweb 8181 /home/nwebdir &
Only Supports: gif jpg jpeg png zip gz tar htm html
Not Supported: URLs including “..”, Java, Javascript, CGI
Not Supported: directories / /etc /bin /lib /tmp /usr /dev /sbin
No warranty given or implied
Nigel Griffiths nag@uk.ibm.com
In our test it compiles on 4.3BSD VAX via gcc version 2.7.2.2
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <string.h> #include <fcntl.h> #include <signal.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #define BUFSIZE 8096 #define ERROR 42 #define SORRY 43 #define LOG 44 struct { char *ext; char *filetype; } extensions [] = { {"gif", "image/gif" }, {"jpg", "image/jpeg"}, {"jpeg","image/jpeg"}, {"png", "image/png" }, {"zip", "image/zip" }, {"gz", "image/gz" }, {"tar", "image/tar" }, {"htm", "text/html" }, {"html","text/html" }, {0,0} }; void log(int type, char *s1, char *s2, int num) { int fd ; char logbuffer[BUFSIZE*2]; switch (type) { case ERROR: (void)sprintf(logbuffer,"ERROR: %s:%s Errno=%d exiting pid=%d",s1, s2, errno,getpid()); break; case SORRY: (void)sprintf(logbuffer, "<HTML><BODY><H1>nweb Web Server Sorry: %s %s</H1></BODY></HTML>\r\n", s1, s2); (void)write(num,logbuffer,strlen(logbuffer)); (void)sprintf(logbuffer,"SORRY: %s:%s",s1, s2); break; case LOG: (void)sprintf(logbuffer," INFO: %s:%s:%d",s1, s2,num); break; } /* no checks here, nothing can be done a failure anyway */ if((fd = open("nweb.log", O_CREAT| O_WRONLY | O_APPEND,0644)) >= 0) { (void)write(fd,logbuffer,strlen(logbuffer)); (void)write(fd,"\n",1); (void)close(fd); } if(type == ERROR || type == SORRY) exit(3); } /* this is a child web server process, so we can exit on errors */ void web(int fd, int hit) { int j, file_fd, buflen, len; long i, ret; char * fstr; static char buffer[BUFSIZE+1]; /* static so zero filled */ ret =read(fd,buffer,BUFSIZE); /* read Web request in one go */ if(ret == 0 || ret == -1) { /* read failure stop now */ log(SORRY,"failed to read browser request","",fd); } if(ret > 0 && ret < BUFSIZE) /* return code is valid chars */ buffer[ret]=0; /* terminate the buffer */ else buffer[0]=0; for(i=0;i<ret;i++) /* remove CF and LF characters */ if(buffer[i] == '\r' || buffer[i] == '\n') buffer[i]='*'; log(LOG,"request",buffer,hit); if( strncmp(buffer,"GET ",4) && strncmp(buffer,"get ",4) ) log(SORRY,"Only simple GET operation supported",buffer,fd); for(i=4;i<BUFSIZE;i++) { /* null terminate after the second space to ignore extra stuff */ if(buffer[i] == ' ') { /* string is "GET URL " +lots of other stuff */ buffer[i] = 0; break; } } for(j=0;j<i-1;j++) /* check for illegal parent directory use .. */ if(buffer[j] == '.' && buffer[j+1] == '.') log(SORRY,"Parent directory (..) path names not supported",buffer,fd); if( !strncmp(&buffer[0],"GET /\0",6) || !strncmp(&buffer[0],"get /\0",6) ) /* convert no filename to index file */ (void)strcpy(buffer,"GET /index.html"); /* work out the file type and check we support it */ buflen=strlen(buffer); fstr = (char *)0; for(i=0;extensions[i].ext != 0;i++) { len = strlen(extensions[i].ext); if( !strncmp(&buffer[buflen-len], extensions[i].ext, len)) { fstr =extensions[i].filetype; break; } } if(fstr == 0) log(SORRY,"file extension type not supported",buffer,fd); if(( file_fd = open(&buffer[5],O_RDONLY)) == -1) /* open the file for reading */ log(SORRY, "failed to open file",&buffer[5],fd); log(LOG,"SEND",&buffer[5],hit); (void)sprintf(buffer,"HTTP/1.0 200 OK\r\nContent-Type: %s\r\n\r\n", fstr); (void)write(fd,buffer,strlen(buffer)); /* send file in 8KB block - last block may be smaller */ while ( (ret = read(file_fd, buffer, BUFSIZE)) > 0 ) { (void)write(fd, buffer, ret); } #ifdef LINUX sleep(1); /* to allow socket to drain */ #endif exit(1); } int main(int argc, char **argv) { int i, port, pid, listenfd, socketfd, hit; /* size_t length; */ unsigned int length; static struct sockaddr_in cli_addr; /* static = initialised to zeros */ static struct sockaddr_in serv_addr; /* static = initialised to zeros */ if( argc < 3 || argc > 3 || !strcmp(argv[1], "-?") ) { (void)printf("hint: nweb Port-Number Top-Directory\n\n" "\tnweb is a small and very safe mini web server\n" "\tnweb only servers out file/web pages with extensions named below\n" "\t and only from the named directory or its sub-directories.\n" "\tThere is no fancy features = safe and secure.\n\n" "\tExample: nweb 8181 /home/nwebdir &\n\n" "\tOnly Supports:"); for(i=0;extensions[i].ext != 0;i++) (void)printf(" %s",extensions[i].ext); (void)printf("\n\tNot Supported: URLs including \"..\", Java, Javascript, CGI\n" "\tNot Supported: directories / /etc /bin /lib /tmp /usr /dev /sbin \n" "\tNo warranty given or implied\n\tNigel Griffiths nag@uk.ibm.com\n" ); exit(0); } if( !strncmp(argv[2],"/" ,2 ) || !strncmp(argv[2],"/etc", 5 ) || !strncmp(argv[2],"/bin",5 ) || !strncmp(argv[2],"/lib", 5 ) || !strncmp(argv[2],"/tmp",5 ) || !strncmp(argv[2],"/usr", 5 ) || !strncmp(argv[2],"/dev",5 ) || !strncmp(argv[2],"/sbin",6) ){ (void)printf("ERROR: Bad top directory %s, see nweb -?\n",argv[2]); exit(3); } if(chdir(argv[2]) == -1){ (void)printf("ERROR: Can't Change to directory %s\n",argv[2]); exit(4); } /* Become deamon + unstopable and no zombies children (= no wait()) */ if(fork() != 0) return 0; /* parent returns OK to shell */ (void)signal(SIGCLD, SIG_IGN); /* ignore child death */ (void)signal(SIGHUP, SIG_IGN); /* ignore terminal hangups */ for(i=0;i<32;i++) (void)close(i); /* close open files */ (void)setpgrp(); /* break away from process group */ log(LOG,"nweb starting",argv[1],getpid()); /* setup the network socket */ if((listenfd = socket(AF_INET, SOCK_STREAM,0)) <0) log(ERROR, "system call","socket",0); log(LOG, "listenfd", NULL, listenfd); port = atoi(argv[1]); if(port < 0 || port >60000) log(ERROR,"Invalid port number (try 1->60000)",argv[1],0); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(port); if(bind(listenfd, (struct sockaddr *)&serv_addr,sizeof(serv_addr)) <0) log(ERROR,"system call","bind",0); if( listen(listenfd,64) <0) log(ERROR,"system call","listen",0); for(hit=1; ;hit++) { length = sizeof(cli_addr); if((socketfd = accept(listenfd, (struct sockaddr *)&cli_addr, &length)) < 0) log(ERROR,"system call","accept",0); log(LOG, "socketfd", NULL, socketfd); if((pid = fork()) < 0) { log(ERROR,"system call","fork",0); } else { if(pid == 0) { /* child */ (void)close(listenfd); web(socketfd,hit); /* never returns */ } else { /* parent */ (void)close(socketfd); } } } }
Running it is fairly simple (we place index.html in /home/www for example)
# ./nweb 80 /home/www
And here are the screenshots of this page actually running in nweb on the 4.3BSD :)
Even WhatWeb gets some info about it :)
http://10.0.2.10 [200 OK] Country[RESERVED][ZZ], Email[nag@uk.ibm.com], IP[10.0.2.10]
And Nmap scan looks like this
Starting Nmap 7.80 ( https://nmap.org ) at 2019-10-17 00:07 CEST Nmap scan report for 10.0.2.10 Host is up (0.0046s latency). Not shown: 986 closed ports PORT STATE SERVICE 7/tcp open echo 9/tcp open discard 13/tcp open daytime 19/tcp open chargen 21/tcp open ftp 23/tcp open telnet 25/tcp open smtp |_smtp-commands: SMTP: EHLO 500 Command unrecognized\x0D 37/tcp open time 79/tcp open finger | finger: Login Name TTY Idle When Office\x0D |_root System Manager co 3 Thu 15:35 \x0D 80/tcp open http |_http-title: Site doesn't have a title (text/html). 512/tcp open exec 513/tcp open login 514/tcp open shell 515/tcp open printer MAC Address: 08:00:2B:AA:BB:CC (Digital Equipment)