simple_httpd.c revision 42714
1/*	simpleHTTPd (C) 1998 netSTOR Technologies, Inc. ("netSTOR")
2	FreeBSD port and additional work by Marc Nicholas <marc@netstor.com>
3	Based on work by:-
4	Thierry Leconte & Yury Shimanovsky
5	My Russian webserver writing friends :-)
6
7	This is an HTTP daemon that will serve up HTML, text files, JPEGs,
8	GIFs and do simple CGI work.
9
10	You may use this code for non-commercial distribution only. Commercial
11	distribution requires the express, written permission of netSTOR. No
12	warranty is implied or given -- use at your own risk!
13*/
14
15/*
16 * $Id: simple_httpd.c,v 1.1.1.1 1998/08/27 17:38:45 abial Exp $
17 */
18
19#include <stdio.h>
20#include <unistd.h>
21#include <stdlib.h>
22#include <sys/stat.h>
23#include <sys/time.h>
24#include <sys/types.h>
25#include <time.h>
26#include <sys/socket.h>
27#include <netinet/in.h>
28#include <arpa/inet.h>
29#include <netdb.h>
30#include <fcntl.h>
31#include <string.h>
32#include <signal.h>
33#include <sys/wait.h>
34#define LOGDIR "/var/log"
35
36int             http_sock, con_sock;
37int             http_port = 80;
38struct sockaddr_in source;
39char           homedir[100];
40char           *adate();
41struct hostent *hst;
42
43void
44init_servconnection(void)
45{
46	struct sockaddr_in server;
47
48	/* Create a socket */
49	http_sock = socket(AF_INET, SOCK_STREAM, 0);
50	if (http_sock < 0) {
51		perror("socket");
52		exit(1);
53	}
54	server.sin_family = AF_INET;
55	server.sin_port = htons(http_port);
56	server.sin_addr.s_addr = INADDR_ANY;
57	if (bind(http_sock, (struct sockaddr *) & server, sizeof(server)) < 0) {
58		perror("bind socket");
59		exit(1);
60	}
61        printf("simpleHTTPd running on %d port\n",http_port);
62}
63
64attenteconnection(void)
65{
66	int lg;
67
68	lg = sizeof(struct sockaddr_in);
69
70	con_sock = accept(http_sock, (struct sockaddr *) & source, &lg);
71	if (con_sock <= 0) {
72		perror("accept");
73		exit(1);
74	}
75}
76
77outdate()
78{
79	time_t	tl;
80	char	buff[50];
81
82	tl = time(NULL);
83	strftime(buff, 50, "Date: %a, %d %h %Y %H:%M:%S %Z\r\n", gmtime(&tl));
84	write(con_sock, buff, strlen(buff));
85}
86
87char           *rep_err_nget[2] = {"<HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY><H1>Error 405</H1>\
88This server is supports only GET and HEAD  requests\n</BODY></HTML>\r\n",
89"HTTP/1.0 405 Method Not allowed\r\nAllow: GET,HEAD\r\nServer: jhttpd\r\n"};
90
91char           *rep_err_acc[2] = {"<HTML><HEAD><TITLE>Error</TITLE></HEAD><BODY><H1>Error 404</H1>\
92Not found - file doesn't exist or is read protected\n</BODY></HTML>\r\n",
93"HTTP/1.0 404 Not found\r\nServer: jhttpd\r\n"};
94
95outerror(char **rep, int http1) /* ������ ������ ������� � html- ���� */
96{
97
98	if (http1) {
99		write(con_sock, rep[1], strlen(rep[1]));
100		outdate();
101		write(con_sock, "\r\n", 2);
102	}
103	write(con_sock, rep[0], strlen(rep[0]));
104}
105
106char            rep_head[] = "HTTP/1.0 200 OK\r\nServer: simpleHTTPD\r\n";
107
108traite_req()
109{
110	char            buff[8192];
111	int             fd, lg, cmd, http1, i;
112	char           *filename, *c;
113	struct stat     statres;
114	char            req[1024];
115        char            logfile[80];
116        char            msg[1024];
117        char           *p,
118                       *par;
119        long            addr;
120        FILE           *log;
121
122	lg = read(con_sock, req, 1024);
123
124        if (p=strstr(req,"\n")) *p=0;
125        if (p=strstr(req,"\r")) *p=0;
126
127       if (geteuid())
128          {
129          strcpy(logfile,getenv("HOME"));
130          strcat(logfile,"/");
131          strcat(logfile,"jhttp.log");
132          }
133       else strcpy(logfile, LOGDIR "/jhttpd.log");
134
135       if ( access(logfile,W_OK))
136            {
137            lg=creat (logfile,O_WRONLY);
138            chmod (logfile,00600);
139            close(lg);
140            }
141
142        strcpy(buff,inet_ntoa(source.sin_addr));
143
144        addr=inet_addr(buff);
145
146        strcpy(msg,adate());
147        strcat(msg,"    ");
148        hst=gethostbyaddr((char*) &addr, 4, AF_INET);
149        if (hst) strcat(msg,hst->h_name);
150        strcat(msg," (");
151        strcat(msg,buff);
152        strcat(msg,")   ");
153        strcat(msg,req);
154
155        log=fopen(logfile,"a");
156        fprintf(log,"%s\n",msg);
157        fclose(log);
158
159	c = strtok(req, " ");
160	if (c == NULL) {
161		outerror(rep_err_nget, 0);
162		goto error;
163	}
164	cmd = 0;
165	if (strncmp(c, "GET", 3) == 0)
166		cmd = 1;
167	if (strncmp(c, "HEAD", 4) == 0) {
168		cmd = 2;
169	}
170
171	filename = strtok(NULL, " ");
172
173	http1 = 0;
174	c = strtok(NULL, " ");
175	if (c != NULL && strncmp(c, "HTTP", 4) == 0)
176		http1 = 1;
177
178	if (cmd == 0) {
179		outerror(rep_err_nget, http1);
180		goto error;
181	}
182
183	if (filename == NULL ||
184            strlen(filename)==1) filename="/index.html";
185
186         while (filename[0]== '/') filename++;
187
188        /**/
189        if (!strncmp(filename,"cgi-bin/",8))
190           {
191           par=0;
192           if (par=strstr(filename,"?"))
193              {
194               *par=0;
195                par++;
196              }
197           if (access(filename,X_OK)) goto conti;
198           stat (filename,&statres);
199           if (setuid(statres.st_uid)) return(0);
200           if (seteuid(statres.st_uid)) return(0);
201           if (!fork())
202              {
203               close(1);
204               dup(con_sock);
205               printf("HTTP/1.0 200 OK\nContent-type: text/html\n\n\n");
206               execlp (filename,filename,par,0);
207              }
208            wait(&i);
209            return(0);
210            }
211        conti:
212	if (filename == NULL) {
213		outerror(rep_err_acc, http1);
214		goto error;
215	}
216	/* interdit les .. dans le path */
217	c = filename;
218	while (*c != '\0')
219		if (c[0] == '.' && c[1] == '.') {
220			outerror(rep_err_acc, http1);
221			goto error;
222		} else
223			c++;
224
225	fd = open(filename, O_RDONLY);
226	if (fd < 0) {
227		outerror(rep_err_acc, http1);
228		goto error;
229	}
230	if (fstat(fd, &statres) < 0) {
231		outerror(rep_err_acc, http1);
232		goto error;
233	}
234	if (!S_ISREG(statres.st_mode))
235	    {
236	    outerror(rep_err_acc, http1);
237            goto error;
238	    }
239	if (http1) {
240		char            buff[50];
241		time_t          tl;
242
243		write(con_sock, rep_head, strlen(rep_head));
244		sprintf(buff, "Content-length: %d\r\n", statres.st_size);
245		write(con_sock, buff, strlen(buff));
246		outdate();
247
248                if (strstr(filename,"."))
249                   {
250                   strcpy(buff,"Content-type: ");
251                   strcat(buff,strstr(filename,".")+1);
252                   strcat(buff,"\r\n");
253                   write(con_sock,buff,strlen(buff));
254                   }
255
256                if (strstr(filename,".txt"))
257                   {
258                   strcpy(buff,"Content-type: text/plain\r\n");
259                   write(con_sock, buff, strlen(buff));
260                   }
261
262                if (strstr(filename,".html") ||
263                    strstr(filename,".htm"))
264                   {
265                   strcpy(buff,"Content-type: text/html\r\n");
266                   write(con_sock, buff, strlen(buff));
267                   }
268
269                if (strstr(filename,".gif"))
270                   {
271                   strcpy(buff,"Content-type: image/gif\r\n");
272                   write(con_sock, buff, strlen(buff));
273                   }
274
275                if (strstr(filename,".jpg"))
276                   {
277                   strcpy(buff,"Content-type: image/jpeg\r\n");
278                   write(con_sock, buff, strlen(buff));
279                   }
280
281		strftime(buff, 50, "Last-Modified: %a, %d %h %Y %H:%M:%S %Z\r\n\r\n", gmtime(&statres.st_mtime));
282		write(con_sock, buff, strlen(buff));
283	}
284	if (cmd == 1) {
285		while (lg = read(fd, buff, 8192))
286			write(con_sock, buff, lg);
287	}
288
289error:
290	close(fd);
291	close(con_sock);
292
293}
294
295
296main(int argc, char **argv)
297{
298	int             lg;
299        char            hello[100];
300
301        if (argc<2 && geteuid())
302           {
303           printf("Usage: simple_htppd <port>\n");
304           exit(1);
305           }
306
307	if (argc>=2) http_port = atoi(argv[1]);
308
309	strcpy (homedir,getenv("HOME"));
310        if (!geteuid()) strcpy (homedir,"/httphome");
311           else         strcat (homedir,"/httphome");
312
313        strcpy(hello,homedir);
314        strcat(hello,"/0hello.html");
315
316	if (chdir(homedir))
317           {
318	   perror("chdir");
319           puts(homedir);
320           exit(1);
321	   }
322        init_servconnection();
323
324        if (fork()) exit(0);
325
326        setpgrp(0,65534);
327	signal(SIGQUIT, SIG_IGN);
328	signal(SIGHUP, SIG_IGN);
329
330        if (listen(http_sock,100) < 0) exit(1);
331
332        label:
333	attenteconnection();
334        if (fork())
335           {
336           close(con_sock);
337           goto label;
338           }
339        alarm(1800);
340	traite_req();
341        exit(0);
342}
343
344
345
346char *adate()
347{
348        static char out[50];
349        long now;
350        struct tm *t;
351        time(&now);
352        t = localtime(&now);
353
354        sprintf(out, "%4d/%02d/%02d %02d:%02d:%02d",
355                     t->tm_year+1900, t->tm_mon+1, t->tm_mday,
356                     t->tm_hour, t->tm_min, t->tm_sec );
357        return out;
358}
359