1 /*
2 
3 kHTTPd -- the next generation
4 
5 RFC related functions (headers and stuff)
6 
7 */
8 
9 /****************************************************************
10  *	This program is free software; you can redistribute it and/or modify
11  *	it under the terms of the GNU General Public License as published by
12  *	the Free Software Foundation; either version 2, or (at your option)
13  *	any later version.
14  *
15  *	This program is distributed in the hope that it will be useful,
16  *	but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *	GNU General Public License for more details.
19  *
20  *	You should have received a copy of the GNU General Public License
21  *	along with this program; if not, write to the Free Software
22  *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  ****************************************************************/
25 
26 
27 #include <linux/kernel.h>
28 
29 #include <linux/ctype.h>
30 #include <linux/errno.h>
31 #include <linux/slab.h>
32 #include <linux/net.h>
33 #include <linux/sched.h>
34 #include <linux/skbuff.h>
35 #include <linux/unistd.h>
36 #include <linux/file.h>
37 #include <linux/smp_lock.h>
38 
39 #include <net/ip.h>
40 #include <net/sock.h>
41 
42 #include <asm/atomic.h>
43 #include <asm/semaphore.h>
44 #include <asm/processor.h>
45 #include <asm/uaccess.h>
46 
47 
48 #include "prototypes.h"
49 #include "structure.h"
50 #include "sysctl.h"
51 
52 
53 #define KHTTPD_NUMMIMETYPES 	40
54 
55 static atomic_t	MimeCount;
56 
57 struct MimeType
58 {
59 	__u32 	identifier;
60 	char	type[64-sizeof(__u32)-sizeof(__kernel_size_t)];
61 	__kernel_size_t	len;
62 };
63 
64 static struct MimeType	MimeTypes[KHTTPD_NUMMIMETYPES];
65 
66 
AddMimeType(const char * Ident,const char * Type)67 void AddMimeType(const char *Ident,const char *Type)
68 {
69 	__u32	*I;
70 
71 	EnterFunction("AddMimeType");
72 
73 	if (strlen(Ident)!=4)
74    	{
75    		(void)printk(KERN_ERR "httpd: Only 4-byte mime-identifiers are accepted\n");
76    		return;
77    	}
78 
79 	if (strlen(Type)>(64-sizeof(__u32)-sizeof(__kernel_size_t) ) )
80    	{
81    		(void)printk(KERN_ERR "httpd: Mime-string too long.\n");
82    		return;
83    	}
84 
85    	I=(__u32*)Ident;
86 
87    	/* FIXME: Need to lock-down all access to the mime-structure here */
88    	/*        For now, just don't add mime-types after initialisation */
89 
90 
91    	MimeTypes[atomic_read(&MimeCount)].identifier=*I;
92    	strncpy(MimeTypes[atomic_read(&MimeCount)].type,Type,(64-sizeof(__u32)-sizeof(__kernel_size_t)));
93    	MimeTypes[atomic_read(&MimeCount)].len = strlen(Type);
94 
95    	atomic_inc(&MimeCount);
96    	LeaveFunction("AddMimeType");
97 }
98 
99 
ResolveMimeType(const char * File,__kernel_size_t * Len)100 char *ResolveMimeType(const char *File,__kernel_size_t *Len)
101 /*
102 
103 	The returned string is for READ ONLY, ownership of the memory is NOT
104 	transferred.
105 
106 */
107 {
108 	__u32	*I;
109 	int pos,lc,filelen;
110 
111 	EnterFunction("ResolveMimeType");
112 
113 	*Len = 0;
114 
115 	if (File==NULL)
116 		return NULL;
117 
118 	filelen = (int)strlen(File);
119 
120 	if (filelen<4)
121    	{
122    		return NULL;
123    	}
124 
125    	/* The Merced-people are NOT going to like this! So this has to be fixed
126    	   in a later stage. */
127 
128 	pos = filelen-4;
129    	I=(__u32*)(File+pos);
130 
131    	lc=0;
132 
133    	while (lc<atomic_read(&MimeCount))
134  	{
135    		if (MimeTypes[lc].identifier == *I)
136    		{
137    			*Len = MimeTypes[lc].len;
138    			LeaveFunction("ResolveMimeType - success");
139    	  		return MimeTypes[lc].type;
140    	  	}
141    	  	lc++;
142    	}
143 
144 	if (sysctl_khttpd_sloppymime)
145 	{
146 		*Len = MimeTypes[0].len;
147 		LeaveFunction("ResolveMimeType - unknown");
148 	   	return MimeTypes[0].type;
149 	}
150 	else
151 	{
152 		LeaveFunction("ResolveMimeType - failure");
153 	   	return NULL;
154 	}
155 }
156 
157 
158 static char HeaderPart1[] = "HTTP/1.0 200 OK\r\nServer: kHTTPd/0.1.6\r\nDate: ";
159 #ifdef BENCHMARK
160 static char HeaderPart1b[] ="HTTP/1.0 200 OK";
161 #endif
162 static char HeaderPart3[] = "\r\nContent-type: ";
163 static char HeaderPart5[] = "\r\nLast-modified: ";
164 static char HeaderPart7[] = "\r\nContent-length: ";
165 static char HeaderPart9[] = "\r\n\r\n";
166 
167 #ifdef BENCHMARK
168 /* In BENCHMARK-mode, just send the bare essentials */
SendHTTPHeader(struct http_request * Request)169 void SendHTTPHeader(struct http_request *Request)
170 {
171 	struct msghdr	msg;
172 	mm_segment_t	oldfs;
173 	struct iovec	iov[9];
174 	int 		len,len2;
175 
176 
177 	EnterFunction("SendHTTPHeader");
178 
179 	msg.msg_name     = 0;
180 	msg.msg_namelen  = 0;
181 	msg.msg_iov	 = &iov[0];
182 	msg.msg_iovlen   = 6;
183 	msg.msg_control  = NULL;
184 	msg.msg_controllen = 0;
185 	msg.msg_flags    = 0;  /* Synchronous for now */
186 
187 	iov[0].iov_base = HeaderPart1b;
188 	iov[0].iov_len  = 15;
189 	iov[1].iov_base = HeaderPart3;
190 	iov[1].iov_len  = 16;
191 	iov[2].iov_base = Request->MimeType;
192 	iov[2].iov_len  = Request->MimeLength;
193 
194 	iov[3].iov_base = HeaderPart7;
195 	iov[3].iov_len  = 18;
196 
197 
198 	sprintf(Request->LengthS,"%i",Request->FileLength);
199 	iov[4].iov_base = Request->LengthS;
200 	iov[4].iov_len  = strlen(Request->LengthS);
201 	iov[5].iov_base = HeaderPart9;
202 	iov[5].iov_len  = 4;
203 
204 	len2=15+16+18+iov[2].iov_len+iov[4].iov_len+4;
205 
206 
207 	len = 0;
208 
209 
210 	oldfs = get_fs(); set_fs(KERNEL_DS);
211 	len = sock_sendmsg(Request->sock,&msg,len2);
212 	set_fs(oldfs);
213 
214 
215 	return;
216 }
217 #else
SendHTTPHeader(struct http_request * Request)218 void SendHTTPHeader(struct http_request *Request)
219 {
220 	struct msghdr	msg;
221 	mm_segment_t	oldfs;
222 	struct iovec	iov[9];
223 	int 		len,len2;
224 	__kernel_size_t	slen;
225 
226 	EnterFunction("SendHTTPHeader");
227 
228 	msg.msg_name     = 0;
229 	msg.msg_namelen  = 0;
230 	msg.msg_iov	 = &(iov[0]);
231 	msg.msg_iovlen   = 9;
232 	msg.msg_control  = NULL;
233 	msg.msg_controllen = 0;
234 	msg.msg_flags    = 0;  /* Synchronous for now */
235 
236 	iov[0].iov_base = HeaderPart1;
237 	iov[0].iov_len  = 45;
238 	iov[1].iov_base = CurrentTime;
239 	iov[1].iov_len  = 29;
240 	iov[2].iov_base = HeaderPart3;
241 	iov[2].iov_len  = 16;
242 
243 	iov[3].iov_base = Request->MimeType;
244 	iov[3].iov_len  = Request->MimeLength;
245 
246 	iov[4].iov_base = HeaderPart5;
247 	iov[4].iov_len  = 17;
248 	iov[5].iov_base = &(Request->TimeS[0]);
249 	iov[5].iov_len  = 29;
250 	iov[6].iov_base = HeaderPart7;
251 	iov[6].iov_len  = 18;
252 	iov[7].iov_base = &(Request->LengthS[0]);
253 	slen = strlen(Request->LengthS);
254 	iov[7].iov_len  = slen;
255 	iov[8].iov_base = HeaderPart9;
256 	iov[8].iov_len  = 4;
257 
258 	len2=45+2*29+16+17+18+slen+4+iov[3].iov_len;
259 
260 	len = 0;
261 
262 	oldfs = get_fs(); set_fs(KERNEL_DS);
263 	len = sock_sendmsg(Request->sock,&msg,len2);
264 	set_fs(oldfs);
265 	LeaveFunction("SendHTTPHeader");
266 
267 
268 	return;
269 }
270 #endif
271 
272 
273 
274 /*
275 
276 Parse a HTTP-header. Be careful for buffer-overflows here, this is the most important
277 place for this, since the remote-user controls the data.
278 
279 */
ParseHeader(char * Buffer,const int length,struct http_request * Head)280 void ParseHeader(char *Buffer,const int length, struct http_request *Head)
281 {
282 	char *Endval,*EOL,*tmp;
283 
284 	EnterFunction("ParseHeader");
285 	Endval = Buffer + length;
286 
287 	/* We want to parse only the first header if multiple headers are present */
288 	tmp = strstr(Buffer,"\r\n\r\n");
289 	if (tmp!=NULL)
290 	    Endval = tmp;
291 
292 
293 	while (Buffer<Endval)
294 	{
295 		if (isspace(Buffer[0]))
296 		{
297 			Buffer++;
298 			continue;
299 		}
300 
301 
302 		EOL=strchr(Buffer,'\n');
303 
304 		if (EOL==NULL) EOL=Endval;
305 
306 		if (EOL-Buffer<4)
307 		{
308 			Buffer++;
309 			continue;
310 		}
311 
312 		if (strncmp("GET ",Buffer,4)==0)
313 		{
314 			int PrefixLen;
315 			Buffer+=4;
316 
317 			tmp=strchr(Buffer,' ');
318 			if (tmp==0)
319 			{
320 				tmp=EOL-1;
321 				Head->HTTPVER = 9;
322 			} else
323 				Head->HTTPVER = 10;
324 
325 			if (tmp>Endval) continue;
326 
327 			strncpy(Head->FileName,sysctl_khttpd_docroot,sizeof(Head->FileName));
328 			PrefixLen = strlen(sysctl_khttpd_docroot);
329 			Head->FileNameLength = min_t(unsigned int, 255, tmp - Buffer + PrefixLen);
330 
331 			strncat(Head->FileName,Buffer,min_t(unsigned int, 255 - PrefixLen, tmp - Buffer));
332 
333 			Buffer=EOL+1;
334 #ifdef BENCHMARK
335 			break;
336 #endif
337 			continue;
338 		}
339 #ifndef BENCHMARK
340 		if (strncmp("If-Modified-Since: ",Buffer,19)==0)
341 		{
342 			Buffer+=19;
343 
344 			strncpy(Head->IMS,Buffer,min_t(unsigned int, 127,EOL-Buffer-1));
345 
346 			Buffer=EOL+1;
347 			continue;
348 		}
349 
350 		if (strncmp("User-Agent: ",Buffer,12)==0)
351 		{
352 			Buffer+=12;
353 
354 			strncpy(Head->Agent,Buffer,min_t(unsigned int, 127,EOL-Buffer-1));
355 
356 			Buffer=EOL+1;
357 			continue;
358 		}
359 
360 
361 		if (strncmp("Host: ",Buffer,6)==0)
362 		{
363 			Buffer+=6;
364 
365 			strncpy(Head->Host,Buffer,min_t(unsigned int, 127,EOL-Buffer-1));
366 
367 			Buffer=EOL+1;
368 			continue;
369 		}
370 #endif
371 		Buffer = EOL+1;  /* Skip line */
372 	}
373 	LeaveFunction("ParseHeader");
374 }
375