1/*
2
3kHTTPd -- the next generation
4
5Sysctl interface
6
7*/
8/****************************************************************
9 *	This program is free software; you can redistribute it and/or modify
10 *	it under the terms of the GNU General Public License as published by
11 *	the Free Software Foundation; either version 2, or (at your option)
12 *	any later version.
13 *
14 *	This program is distributed in the hope that it will be useful,
15 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
16 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 *	GNU General Public License for more details.
18 *
19 *	You should have received a copy of the GNU General Public License
20 *	along with this program; if not, write to the Free Software
21 *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 *
23 ****************************************************************/
24
25
26#include <linux/kernel.h>
27#include <linux/errno.h>
28#include <linux/slab.h>
29#include <linux/net.h>
30#include <linux/sched.h>
31#include <linux/skbuff.h>
32#include <linux/smp_lock.h>
33#include <linux/sysctl.h>
34#include <linux/un.h>
35#include <linux/unistd.h>
36
37#include <net/ip.h>
38#include <net/sock.h>
39#include <net/tcp.h>
40
41#include <asm/atomic.h>
42#include <asm/semaphore.h>
43#include <asm/processor.h>
44#include <asm/uaccess.h>
45
46#include <linux/file.h>
47#include "prototypes.h"
48
49
50
51char 	sysctl_khttpd_docroot[200] = "/var/www";
52int 	sysctl_khttpd_stop 	= 0;
53int 	sysctl_khttpd_start 	= 0;
54int 	sysctl_khttpd_unload 	= 0;
55int 	sysctl_khttpd_clientport = 80;
56int 	sysctl_khttpd_permreq    = S_IROTH; /* "other" read-access is required by default*/
57int 	sysctl_khttpd_permforbid = S_IFDIR | S_ISVTX | S_IXOTH | S_IXGRP | S_IXUSR;
58 				/* forbidden is execute, directory and sticky*/
59int 	sysctl_khttpd_logging 	= 0;
60int 	sysctl_khttpd_serverport= 8080;
61
62char	sysctl_khttpd_dynamicstring[200];
63int 	sysctl_khttpd_sloppymime= 0;
64int	sysctl_khttpd_threads	= 2;
65int	sysctl_khttpd_maxconnect = 1000;
66
67atomic_t        khttpd_stopCount;
68
69static struct ctl_table_header *khttpd_table_header;
70
71static int sysctl_SecureString(ctl_table *table, int *name, int nlen,
72		  void *oldval, size_t *oldlenp,
73		  void *newval, size_t newlen, void **context);
74static int proc_dosecurestring(ctl_table *table, int write, struct file *filp,
75		  void *buffer, size_t *lenp);
76static int khttpd_stop_wrap_proc_dointvec(ctl_table *table, int write, struct file *filp,
77		  void *buffer, size_t *lenp);
78
79
80static ctl_table khttpd_table[] = {
81	{	NET_KHTTPD_DOCROOT,
82		"documentroot",
83		&sysctl_khttpd_docroot,
84		sizeof(sysctl_khttpd_docroot),
85		0644,
86		NULL,
87		proc_dostring,
88		&sysctl_string,
89		NULL,
90		NULL,
91		NULL
92	},
93	{	NET_KHTTPD_STOP,
94		"stop",
95		&sysctl_khttpd_stop,
96		sizeof(int),
97		0644,
98		NULL,
99		khttpd_stop_wrap_proc_dointvec,
100		&sysctl_intvec,
101		NULL,
102		NULL,
103		NULL
104	},
105	{	NET_KHTTPD_START,
106		"start",
107		&sysctl_khttpd_start,
108		sizeof(int),
109		0644,
110		NULL,
111		proc_dointvec,
112		&sysctl_intvec,
113		NULL,
114		NULL,
115		NULL
116	},
117	{	NET_KHTTPD_UNLOAD,
118		"unload",
119		&sysctl_khttpd_unload,
120		sizeof(int),
121		0644,
122		NULL,
123		proc_dointvec,
124		&sysctl_intvec,
125		NULL,
126		NULL,
127		NULL
128	},
129	{	NET_KHTTPD_THREADS,
130		"threads",
131		&sysctl_khttpd_threads,
132		sizeof(int),
133		0644,
134		NULL,
135		proc_dointvec,
136		&sysctl_intvec,
137		NULL,
138		NULL,
139		NULL
140	},
141	{	NET_KHTTPD_MAXCONNECT,
142		"maxconnect",
143		&sysctl_khttpd_maxconnect,
144		sizeof(int),
145		0644,
146		NULL,
147		proc_dointvec,
148		&sysctl_intvec,
149		NULL,
150		NULL,
151		NULL
152	},
153	{	NET_KHTTPD_SLOPPYMIME,
154		"sloppymime",
155		&sysctl_khttpd_sloppymime,
156		sizeof(int),
157		0644,
158		NULL,
159		proc_dointvec,
160		&sysctl_intvec,
161		NULL,
162		NULL,
163		NULL
164	},
165	{	NET_KHTTPD_CLIENTPORT,
166		"clientport",
167		&sysctl_khttpd_clientport,
168		sizeof(int),
169		0644,
170		NULL,
171		proc_dointvec,
172		&sysctl_intvec,
173		NULL,
174		NULL,
175		NULL
176	},
177	{	NET_KHTTPD_PERMREQ,
178		"perm_required",
179		&sysctl_khttpd_permreq,
180		sizeof(int),
181		0644,
182		NULL,
183		proc_dointvec,
184		&sysctl_intvec,
185		NULL,
186		NULL,
187		NULL
188	},
189	{	NET_KHTTPD_PERMFORBID,
190		"perm_forbid",
191		&sysctl_khttpd_permforbid,
192		sizeof(int),
193		0644,
194		NULL,
195		proc_dointvec,
196		&sysctl_intvec,
197		NULL,
198		NULL,
199		NULL
200	},
201	{	NET_KHTTPD_LOGGING,
202		"logging",
203		&sysctl_khttpd_logging,
204		sizeof(int),
205		0644,
206		NULL,
207		proc_dointvec,
208		&sysctl_intvec,
209		NULL,
210		NULL,
211		NULL
212	},
213	{	NET_KHTTPD_SERVERPORT,
214		"serverport",
215		&sysctl_khttpd_serverport,
216		sizeof(int),
217		0644,
218		NULL,
219		proc_dointvec,
220		&sysctl_intvec,
221		NULL,
222		NULL,
223		NULL
224	},
225	{	NET_KHTTPD_DYNAMICSTRING,
226		"dynamic",
227		&sysctl_khttpd_dynamicstring,
228		sizeof(sysctl_khttpd_dynamicstring),
229		0644,
230		NULL,
231		proc_dosecurestring,
232		&sysctl_SecureString,
233		NULL,
234		NULL,
235		NULL
236	},
237	{0,0,0,0,0,0,0,0,0,0,0}	};
238
239
240static ctl_table khttpd_dir_table[] = {
241	{NET_KHTTPD, "khttpd", NULL, 0, 0555, khttpd_table,0,0,0,0,0},
242	{0,0,0,0,0,0,0,0,0,0,0}
243};
244
245static ctl_table khttpd_root_table[] = {
246	{CTL_NET, "net", NULL, 0, 0555, khttpd_dir_table,0,0,0,0,0},
247	{0,0,0,0,0,0,0,0,0,0,0}
248};
249
250
251void StartSysctl(void)
252{
253	khttpd_table_header = register_sysctl_table(khttpd_root_table,1);
254}
255
256
257void EndSysctl(void)
258{
259	unregister_sysctl_table(khttpd_table_header);
260}
261
262static int proc_dosecurestring(ctl_table *table, int write, struct file *filp,
263		  void *buffer, size_t *lenp)
264{
265	size_t len;
266	char *p, c=0;
267	char String[256];
268
269	if ((table->data==0) || (table->maxlen==0) || (*lenp==0) ||
270	    ((filp->f_pos!=0) && (write==0))) {
271		*lenp = 0;
272		return 0;
273	}
274
275	if (write!=0) {
276		len = 0;
277		p = buffer;
278		while (len < *lenp) {
279			if(get_user(c, p++))
280				return -EFAULT;
281			if (c == 0 || c == '\n')
282				break;
283			len++;
284		}
285		if (len >= table->maxlen)
286			len = table->maxlen-1;
287		if(copy_from_user(String, buffer,(unsigned long)len))
288			return -EFAULT;
289		((char *) String)[len] = 0;
290		filp->f_pos += *lenp;
291		AddDynamicString(String);
292	} else {
293		GetSecureString(String);
294		len = strlen(String);
295		if (len > table->maxlen)
296			len = table->maxlen;
297		if (len > *lenp)
298			len = *lenp;
299		if (len!=0)
300			if(copy_to_user(buffer, String,(unsigned long)len))
301				return -EFAULT;
302		if (len < *lenp) {
303			if(put_user('\n', ((char *) buffer) + len))
304				return -EFAULT;
305			len++;
306		}
307		*lenp = len;
308		filp->f_pos += len;
309	}
310	return 0;
311}
312
313/* A wrapper around proc_dointvec that computes
314 * khttpd_stopCount = # of times sysctl_khttpd_stop has gone true
315 * Sensing sysctl_khttpd_stop in other threads is racy;
316 * sensing khttpd_stopCount in other threads is not.
317 */
318static int khttpd_stop_wrap_proc_dointvec(ctl_table *table, int write, struct file *filp,
319		  void *buffer, size_t *lenp)
320{
321	int rv;
322	int oldstop = sysctl_khttpd_stop;
323	rv = proc_dointvec(table, write, filp, buffer, lenp);
324	if (sysctl_khttpd_stop && !oldstop)
325		atomic_inc(&khttpd_stopCount);
326
327	return rv;
328}
329
330
331static int sysctl_SecureString (/*@unused@*/ctl_table *table,
332				/*@unused@*/int *name,
333				/*@unused@*/int nlen,
334		  		/*@unused@*/void *oldval,
335		  		/*@unused@*/size_t *oldlenp,
336		  		/*@unused@*/void *newval,
337		  		/*@unused@*/size_t newlen,
338		  		/*@unused@*/void **context)
339{
340	return -ENOSYS;
341}
342