#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <syslog.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#define VHOST_ROOT "/var/www/vhosts"
#define SITES_ROOT "/var/www/sites"
#define CGI "cgi-bin"
#define SERVER "epochttpd/2.0 (Unix)"
// WARNING: this http software is vulnerable. I'm leaving it that way.
/* just notes for environment variables for CGIs when I need them.
Key Value
DOCUMENT_ROOT The root directory of your server
HTTP_COOKIE The visitor's cookie, if one is set
HTTP_HOST The hostname of the page being attempted
HTTP_REFERER The URL of the page that called your program
HTTP_USER_AGENT The browser type of the visitor
HTTPS "on" if the program is being called through a secure server
PATH The system path your server is running under
QUERY_STRING The query string (see GET, below)
REMOTE_ADDR The IP address of the visitor
REMOTE_HOST The hostname of the visitor (if your server has
reverse-name-lookups on; otherwise this is the IP address again)
REMOTE_PORT The port the visitor is connected to on the web server
REMOTE_USER The visitor's username (for .htaccess-protected pages)
REQUEST_METHOD GET or POST
REQUEST_URI The interpreted pathname of the requested document or CGI
(relative to the document root)
SCRIPT_FILENAME The full pathname of the current CGI
SCRIPT_NAME The interpreted pathname of the current CGI (relative to
the document root)
SERVER_ADMIN The email address for your server's webmaster
SERVER_NAME Your server's fully qualified domain name (e.g.
www.cgi101.com)
SERVER_PORT The port number your server is listening on
SERVER_SOFTWARE The server software you're using (e.g. Apache 1.3)
*/
void standard_headers() {
printf("Server: %s\r\n",SERVER);
printf("Connection: close\r\n");
}
int main(int argc,char *argv[]) {
int fd;
char *name[10];
int s,n;
char *method;
char *page;
char *version;
char *get_param;
char line[getpagesize()];
fgets(line,sizeof(line)-1,stdin);
struct sockaddr_in6 sa6;
unsigned int sl=sizeof(sa6);
char h[NI_MAXHOST];
char p[NI_MAXSERV];
openlog("httpd",LOG_PID,LOG_DAEMON);
if(getpeername(0,(struct sockaddr *)&sa6,&sl) == -1)
syslog(LOG_WARNING,"getpeername: %m");
getnameinfo((struct sockaddr *)&sa6,sl,h,sizeof(h),p,sizeof(p),NI_NUMERICHOST|NI_NUMERICSERV);
setenv("REMOTE_ADDR",h,1);
setenv("REMOTE_PORT",p,1);
if(getsockname(0,(struct sockaddr *)&sa6,&sl) == -1)
syslog(LOG_WARNING,"getsockname: %m");
getnameinfo((struct sockaddr *)&sa6,sl,h,sizeof(h),p,sizeof(p),NI_NUMERICHOST|NI_NUMERICSERV);
setenv("SERVER_ADDR",h,1);
setenv("SERVER_PORT",p,1);
if(!strchr(line,'\n')) {
printf("HTTP/1.1 413 Entity Too Large\r\n");
standard_headers();
printf("Content-type: text/plain\r\n\r\n");
printf("use smaller (<%d bytes) headers.\n",getpagesize());
syslog(LOG_WARNING,"413 Entity Too Large %s len: %d\n",h,strlen(line));
return 0;
}
if(strchr(line,'\r')) *strchr(line,'\r')=0;
method=strdup(line);
if((page=strchr(method,' '))) {
*page=0;
page++;
if((version=strchr(page,' '))) {
*version=0;
version++;
}
if((get_param=strchr(page,'?'))) {
*get_param=0;
get_param++;
setenv("QUERY_STRING",get_param,1);
}
}
signal(SIGALRM,exit);
alarm(10);//maximum of 10s to receive requests sound good?
while(fgets(line,sizeof(line)-1,stdin)) {
if(!strchr(line,'\n')) {
printf("HTTP/1.1 413 Entity Too Large\r\n");
standard_headers();
printf("Content-type: text/plain\r\n\r\n");
printf("use smaller (<%d bytes) headers.\n",getpagesize());
syslog(LOG_WARNING,"413 somewhere in request line 2+: %s %d\n",h,strlen(line));
return 0;
}
if(strchr(line,'\r')) *strchr(line,'\r')=0;
if(!strncasecmp(line,"Host: ",6)) {
setenv("HTTP_HOST",line+6,1);
}
if(!strncasecmp(line,"User-agent: ",12)) {
setenv("HTTP_USER_AGENT",line+12,1);
}
if(!strcmp(line,"")) {
break;
}
}
alarm(0);//no more timeout.
//
syslog(LOG_WARNING,"%s: %s %s %s %s\n",h,getenv("HTTP_HOST"),getenv("HTTP_USER_AGENT"),page,get_param);
//TODO: sanitize this.
if(chdir(VHOST_ROOT) == -1) {
printf("HTTP/1.1 500 Internal Server Error\r\n");
standard_headers();
printf("Content-type: text/html\r\n\r\ncouldn't chdir(\"%s\");",VHOST_ROOT);
syslog(LOG_WARNING,"can't chdir to VHOST_ROOT: %s",VHOST_ROOT);
exit(3);
}
//I had fun exploiting this. :)
if(chdir((char*)getenv("HTTP_HOST")) == -1) {
if(chdir(SITES_ROOT) != -1) {
if(chdir("default") == -1) {
//no backup site to show people. fuck. shit happens.
printf("HTTP/1.1 500 Internal Server Error\r\n");
standard_headers();
printf("Content-type: text/html\r\n\r\nfuck");
syslog(LOG_WARNING,"can't chdir to default site dir.");
exit(1);
}
//we're good.
} else {
printf("HTTP/1.1 500 Internal Server Error\r\n");
standard_headers();
printf("Content-type: text/html\r\n\r\ncouldn't chdir(\"%s\");",SITES_ROOT);
//wtf? no sites dir???
syslog(LOG_WARNING,"can't chdir to SITES_ROOT: %s",SITES_ROOT);
exit(2);
}
}