Subversion Repositories wimsdev

Rev

Rev 3841 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*    Copyright (C) 2002-2003 XIAO, Gang of Universite de Nice - Sophia Antipolis
  2.  *
  3.  *  This program is free software; you can redistribute it and/or modify
  4.  *  it under the terms of the GNU General Public License as published by
  5.  *  the Free Software Foundation; either version 2 of the License, or
  6.  *  (at your option) any later version.
  7.  *
  8.  *  This program is distributed in the hope that it will be useful,
  9.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  10.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11.  *  GNU General Public License for more details.
  12.  *
  13.  *  You should have received a copy of the GNU General Public License
  14.  *  along with this program; if not, write to the Free Software
  15.  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16.  */
  17.  
  18. /* http dawmon for WIMS */
  19.  
  20. #include "../wims.h"
  21. #include <netdb.h>
  22. #include <sys/socket.h>
  23. #include <netinet/in.h>
  24. #include <arpa/inet.h>
  25.  
  26. #if !HAVE_SOCKLEN_T
  27. typedef size_t socklen_t;
  28. #endif
  29.  
  30. #define WIMS_TIMEOUT    200
  31. #define WIMSD_TICK      10
  32. #define WIMSD_IDLE      500
  33. #define PIDLIM          100
  34.  
  35. char *acceptstr="127.0.0.1";
  36.  
  37. int pidtab[PIDLIM];
  38. int pidcnt;
  39.  
  40. int sock;
  41. int sport;
  42. int idle; /* limited to WIMSD_TICK * WIMSD_IDLE */
  43.  
  44. void errorquit(char *msg)
  45. {
  46.     fprintf(stderr,"%s: %s\n",msg,strerror(errno)); exit(1);
  47. }
  48.  
  49. void checkpid(void)
  50. {
  51.     int i,k;
  52.     for(i=0;i<pidcnt;i++) {
  53.         waitpid(pidtab[i],&k,WNOHANG);
  54.         if(WIFEXITED(k)) {
  55.             memmove(pidtab+i,pidtab+i+1,(pidcnt-i-1)*sizeof(pidtab[0]));
  56.             pidcnt--;
  57.         }
  58.     }
  59. }
  60.  
  61. void addpid(int pid)
  62. {
  63.     while(pidcnt>=PIDLIM) {
  64.         sleep(1); checkpid();
  65.     }
  66.     pidtab[pidcnt++]=pid;
  67. }
  68.  
  69. void alarm1(int s)
  70. {
  71.     fprintf(stderr,"Time out.\n"); close(sock); exit(1);
  72. }
  73.  
  74. void alarm2(int s)
  75. {
  76.     checkpid(); idle++; alarm(WIMSD_TICK);
  77.     if(idle>=WIMSD_IDLE) alarm1(0);
  78. }
  79.  
  80.         /* Points to the end of the word */
  81. char *find_word_end(char *p)
  82. {
  83.     int i;
  84.     for(i=0;!isspace(*p) && *p!=0 && i<MAX_LINELEN; p++,i++);
  85.     return p;
  86. }
  87.  
  88.         /* Strips leading spaces */
  89. char *find_word_start(char *p)
  90. {
  91.     int i;
  92.     for(i=0; isspace(*p) && i<MAX_LINELEN; p++,i++);
  93.     return p;
  94. }
  95.  
  96.         /* Read/write to a file with variable parms to print filename */
  97. void accessfile(char *content, char *type, char *s,...)
  98. {
  99.     va_list vp;
  100.     char buf[MAX_LINELEN+1];
  101.     FILE *f;
  102.     int l;
  103.  
  104.     va_start(vp,s);
  105.     vsnprintf(buf,sizeof(buf),s,vp);
  106.     va_end(vp);
  107.     f=fopen(buf,type); if(f==NULL) {
  108.         if(*type=='r') content[0]=0; return;
  109.     }
  110.     switch(*type) {
  111.         case 'a':
  112.         case 'w': {
  113.             l=strlen(content); fwrite(content,1,l,f); break;
  114.         }
  115.         case 'r': {
  116.             l=fread(content,1,MAX_LINELEN-1,f);
  117.             if(l>0 && l<MAX_LINELEN) content[l]=0;
  118.             else content[0]=0;
  119.             break;
  120.         }
  121.         default: {
  122.             content[0]=0; break;
  123.         }
  124.     }
  125.     fclose(f);
  126. }
  127.  
  128. void badreq(void)
  129. {
  130.     printf("HTTP/1.0 400 Bad Request\r\n\r\nBad Request.\r\n");
  131.     exit(0);
  132. }
  133.  
  134.         /* open a TCP/IP socket with host/port
  135.          * returns the file descriptor for the socket */
  136. int net_connect(int port)
  137. {
  138.     struct sockaddr_in sin;
  139.     int soc, vrai;
  140.  
  141.     if ((soc = socket(AF_INET, SOCK_STREAM, 0)) == -1)
  142.       errorquit("socket() error");
  143.     if(setsockopt(soc, SOL_SOCKET, SO_REUSEADDR, &vrai, sizeof(vrai)) == -1)
  144.       errorquit("setsockopt() error");
  145.  
  146.     sin.sin_port=htons(port);
  147.     sin.sin_family = AF_INET;
  148.     inet_aton(acceptstr,&sin.sin_addr);
  149.     if(bind(soc,(struct sockaddr *)&sin, sizeof(sin))==-1)
  150.       errorquit("bind() error");
  151.     if(listen(soc,10)==-1) errorquit("listen() error");
  152.     return soc;
  153. }
  154.  
  155. void putfile(char *fname,int soc)
  156. {
  157.     int l;
  158.     long int siz;
  159.     char *p, namebuf[4096], buf[4096];
  160.     char cbuf[MAX_LINELEN+1];
  161.     struct stat st;
  162.     FILE *f;
  163.    
  164.     if(fname[strlen(fname)-1]=='/')
  165.       snprintf(namebuf,sizeof(namebuf),"%sindex.html",fname);
  166.     else snprintf(namebuf,sizeof(namebuf),"%s",fname);
  167.     statit: if(stat(namebuf,&st)!=0) badreq();
  168.     if(S_ISDIR(st.st_mode)) {
  169.         snprintf(namebuf,sizeof(namebuf),"%s/index.html",fname);
  170.         goto statit;
  171.     }
  172.     if(!S_ISREG(st.st_mode)) badreq();
  173.     if(strncmp(namebuf,"modules/adm/",strlen("modules/adm/"))==0 ||
  174.        strncmp(namebuf,"modules/home/",strlen("modules/home/"))==0)
  175.       badreq();
  176.     for(p=strchr(namebuf,'/'); p!=NULL; p=strchr(p+1,'/')) {
  177.         *p=0; snprintf(buf,sizeof(buf),"%s/.htaccess",namebuf); *p='/';
  178.         if(stat(cbuf,&st)==0) {
  179.             accessfile(cbuf,"r","%s",buf);
  180.             if(strstr(cbuf,"deny from all")!=NULL) badreq();
  181.         }
  182.     }
  183.     siz=st.st_size;
  184.     printf("HTTP/1.0 200 OK\r\n\
  185. Content-Length: %ld\r\n\r\n",
  186.            siz);
  187.     f=fopen(namebuf,"r"); if(f==NULL) badreq();
  188.     do {
  189.         l=fread(buf,1,sizeof(buf),f);
  190.         if(l>0 && l<=sizeof(buf)) fwrite(buf,1,l,stdout);
  191.     } while(l==sizeof(buf));
  192.     fclose(f); fclose(stdin); fclose(stdout); close(soc);
  193.     exit(0);
  194. }
  195.  
  196. struct sockaddr_in saddr;
  197.  
  198. void onereq(int soc)
  199. {
  200.     char buf[QUERY_STRING_LIMIT+1], buf2[MAX_LINELEN+1];
  201.     int i, k, l;
  202. /*     FILE *fin, *fout; */
  203.     struct stat st;
  204.     char *query_method, *query_url, *p, *pp, *p2, *parms;
  205.  
  206.     i=fork(); if(i!=0) {
  207.         if(i==-1) errorquit("fork() error");
  208.         addpid(i); return;
  209.     }
  210.     alarm(WIMS_TIMEOUT);
  211.     signal(SIGALRM,alarm1);
  212.     chdir("public_html");
  213.     i=0; do {
  214.         l=read(soc, buf+i, 1); i++;
  215.     }
  216.     while(i<QUERY_STRING_LIMIT && l>0 && (i<4 || memcmp(buf+i-4,"\r\n\r\n",4)!=0));
  217.     buf[i]=0;
  218. /*printf("%s\n",buf);*/
  219.     dup2(soc,0); /* fin=fdopen(0,"r"); stdin=fin; */
  220.     dup2(soc,1); /* fout=fdopen(1,"w"); stdout=fout; */
  221.     query_method=find_word_start(buf);
  222.     query_url=find_word_end(query_method); if(query_url) *query_url++=0;
  223.     query_url=find_word_start(query_url);
  224.     p=find_word_end(query_url); if(*p) *p++=0;
  225.     parms=strchr(p,'\n'); if(parms) parms++;
  226.     if(strcmp(query_method,"GET")!=0 &&
  227.        strcmp(query_method,"HEAD")!=0 &&
  228.        strcmp(query_method,"POST")!=0) badreq();
  229.     if(query_url[0]!='/' || query_url[1]=='/' || strstr(query_url,"..")!=NULL)
  230.       badreq();
  231.     setenv("REQUEST_URL",query_url,1);
  232.     p=strchr(query_url,'?'); if(p!=NULL) *p++=0; else p="";
  233.     k=stat(query_url+1,&st);
  234.     if(k!=0 && strchr(query_url+1,'/')==NULL)
  235.       query_url="/wims.cgi";
  236.     i=strlen(query_url);
  237.     if(i<4 || strcasecmp(query_url+i-4,".cgi")!=0)
  238.       putfile(query_url+1,soc);
  239.     if(strchr(query_url+1,'/')!=NULL && strncmp(query_url,"/test/",strlen("/test/"))!=0)
  240.       badreq();
  241.     setenv("QUERY_STRING",p,1);
  242.     setenv("QUERY_URL",query_url,1);
  243.     setenv("SCRIPT_NAME",query_url,1);
  244.     setenv("REQUEST_METHOD",query_method,1);
  245.     setenv("SERVER_SOFTWARE","WIMS",1);
  246.     snprintf(buf2,sizeof(buf2),"%d",sport);
  247.     setenv("SERVER_PORT",buf2,1);
  248.     for(; *parms; parms=p) {
  249.         p=strchr(parms,'\n');
  250.         if(p==NULL) p=parms+strlen(parms);
  251.         else {
  252.             if(*(p-1)=='\r') *(p-1)=0;
  253.             *p++=0;
  254.         }
  255.         for(pp=parms; isalnum(*pp) || *pp=='-'; pp++);
  256.         if(*pp==':') {
  257.             *pp++=0; pp=find_word_start(pp);
  258.             for(p2=parms; *p2; p2++) {
  259.                 if(*p2=='-') *p2='_'; else *p2=toupper(*p2);
  260.             }
  261.             if(strcmp(parms,"CONTENT_LENGTH")==0 ||
  262.                strcmp(parms,"CONTENT_TYPE")==0) {
  263.                 snprintf(buf2,sizeof(buf2),"%s",parms);
  264.                 setenv(buf2,pp,1);         
  265.             }
  266.             snprintf(buf2,sizeof(buf2),"HTTP_%s",parms);
  267.             setenv(buf2,pp,1);     
  268.         }
  269.     }
  270.     setenv("REMOTE_ADDR",inet_ntoa(saddr.sin_addr),1);
  271.     snprintf(buf2,sizeof(buf2),"%u",ntohs(saddr.sin_port));
  272.     setenv("REMOTE_PORT",buf2,1);
  273.  
  274.     snprintf(buf2,sizeof(buf2),".%s",query_url);
  275.     execl(buf2,buf2,NULL);
  276.    
  277.     /* fclose(fout); fclose(fin); */ close(soc); exit(0);
  278. }
  279.  
  280. void serve(int soc)
  281. {
  282.     int newsoc;
  283.     socklen_t slen=sizeof(saddr);
  284.    
  285.     wait:
  286.     alarm(WIMSD_TICK);
  287.     newsoc=accept(soc,(struct sockaddr *)&saddr, &slen);
  288.     if(newsoc==-1) errorquit("accept() error");
  289.     checkpid(); idle=0;
  290.     onereq(newsoc); close(newsoc); goto wait;
  291. }
  292.  
  293. void parm(void)
  294. {
  295.     char *p;
  296.     p=getenv("WIMS_HOME");
  297.     if(p!=NULL && *p!=0) chdir(p);
  298.     p=getenv("WIMSD_PORT");
  299.     if(p!=NULL && *p!=0) {
  300.         int i;
  301.         i=atoi(p);
  302.         if(i>0 && i<65536) sport=i;
  303.     }
  304.     p=getenv("WIMSD_ACCEPT");
  305.     if(p!=NULL && strstr(p,"all")!=NULL) acceptstr="0.0.0.0";
  306. }
  307.  
  308. int main(int argc, char *argv[])
  309. {
  310.     struct stat st;
  311.  
  312.     signal(SIGALRM,alarm2);
  313.     sport=8088; pidcnt=0; idle=0;
  314.     parm();
  315.     if(stat("public_html/wims.cgi",&st)!=0) {
  316.         char buf[1024];
  317.         getcwd(buf,sizeof(buf));
  318.         fprintf(stderr,"Bad home directory %s: \
  319. wims.cgi not found.\n",buf); exit(1);
  320.     }
  321. /*    if(stat("public_html/bin/pari",&st)==0) {
  322.         fprintf(stderr,"wimsd must be run as nobody, \
  323. for security reasons!\n\n\
  324. Run bin/wrapuid as root to set things up correctly.\n"); exit(1);
  325.     }
  326. */    setreuid(geteuid(),getuid());setregid(getegid(),getgid());
  327.     sock=net_connect(sport);
  328.    
  329.     serve(sock);
  330.     close(sock); return 0;
  331. }
  332.  
  333.