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