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