#include #include #include #include #include #include #include #include #include #include #include #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]; 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),0,0,NI_NUMERICHOST); setenv("REMOTE_ADDR",h,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\n",h,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); } } if(strncmp(page,"/cgi-bin/",9)) { for(;*page == '/';page++); if(page[strlen(page)-1] == '/') { printf("HTTP/1.1 302 Moved Permanently\r\n"); standard_headers(); printf("Location: /%sindex.html\r\n\r\n",page); return 0; } if((fd=open(page,O_RDONLY)) != -1) {//need to check that the file isn't a directory. :P printf("HTTP/1.1 200 OK\r\n"); standard_headers(); name[0]="/usr/local/bin/mime-type"; name[1]=page; name[2]=0; printf("Content-type: "); fflush(stdout); switch(fork()) { case 0://child execv(name[0],name); break; case -1://error printf("fork failed.\n"); break; default://parent break; } wait(&s); fflush(stdout); printf("\r\n"); fflush(stdout); while((n=read(fd,line,sizeof(line)-1)) > 0) { write(STDOUT_FILENO,line,n); } } else { printf("HTTP/1.1 404 Not Found\r\n"); standard_headers(); printf("Content-type: text/plain\r\n\r\n"); printf("Can't open that page.\n"); } } else { //attempt to run this bastard! chdir(CGI); page+=strlen("/cgi-bin/"); for(;*page == '/';page++); name[0]=page; name[1]=0; printf("HTTP/1.1 200 OK\r\n"); standard_headers(); fflush(stdout); execv(name[0],name); } return 0; }