Subversion Repositories wimsdev

Rev

Rev 8342 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
10 reyssat 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
 
11047 bpr 18
/* http daemon for WIMS */
10 reyssat 19
 
20
#include <netdb.h>
21
#include <sys/socket.h>
22
#include <netinet/in.h>
23
#include <arpa/inet.h>
8177 bpr 24
#include "../wims.h"
10 reyssat 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 */
8342 bpr 97
void wimsdaccessfile(char *content, char *type, char *s,...)
10 reyssat 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
 
8177 bpr 141
    if ((soc = socket(AF_INET, SOCK_STREAM, 0)) == -1)
10 reyssat 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;
8177 bpr 163
 
10 reyssat 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) {
8342 bpr 179
            wimsdaccessfile(cbuf,"r","%s",buf);
10 reyssat 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);
3841 kbelabas 212
    (void)chdir("public_html");
10 reyssat 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) {
8177 bpr 249
        p=strchr(parms,'\n');
10 reyssat 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);
8177 bpr 264
                setenv(buf2,pp,1);
10 reyssat 265
            }
266
            snprintf(buf2,sizeof(buf2),"HTTP_%s",parms);
8177 bpr 267
            setenv(buf2,pp,1);
10 reyssat 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);
8177 bpr 276
 
10 reyssat 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);
8177 bpr 284
 
10 reyssat 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");
3841 kbelabas 297
    if(p!=NULL && *p!=0) (void)chdir(p);
10 reyssat 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];
3841 kbelabas 317
        (void)getcwd(buf,sizeof(buf));
10 reyssat 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);
8177 bpr 328
 
10 reyssat 329
    serve(sock);
330
    close(sock); return 0;
331
}
332