/[hydra]/hydra/src/boa.c
ViewVC logotype

Contents of /hydra/src/boa.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.28 - (show annotations)
Thu Mar 9 18:11:07 2006 UTC (18 years, 1 month ago) by nmav
Branch: MAIN
CVS Tags: hydra_0_1_6_without_hic, hydra_0_1_8, HEAD
Changes since 1.27: +1 -75 lines
File MIME type: text/plain
Removed the HIC support.

1 /*
2 * Hydra, an http server (based on Boa 0.94.13)
3 * Copyright (C) 1995 Paul Phillips <paulp@go2net.com>
4 * Some changes Copyright (C) 1996 Charles F. Randall <crandall@goldsys.com>
5 * Some changes Copyright (C) 1996 Larry Doolittle <ldoolitt@boa.org>
6 * Some changes Copyright (C) 1996-2002 Jon Nelson <jnelson@boa.org>
7 * Portions Copyright (C) 2002 Nikos Mavroyanopoulos <nmav@gnutls.org>
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 1, 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 /* $Id: boa.c,v 1.27 2003/01/22 07:51:49 nmav Exp $*/
26
27 #include "boa.h"
28 #include "ssl.h"
29 #include <sys/resource.h>
30 #ifdef ENABLE_SMP
31 pthread_t father_id;
32 #endif
33
34 /* globals */
35 int backlog = SO_MAXCONN;
36 time_t start_time;
37
38 time_t current_time;
39
40
41 /* static to boa.c */
42 static void fixup_server_root(void);
43 static socket_type create_server_socket(int port, int);
44 void hic_init(void);
45 static void initialize_rlimits();
46 static void drop_privs(void);
47 static server_params *smp_init(socket_type server_s[2]);
48 static void create_server_names( void);
49
50 static int sock_opt = 1;
51 static int do_fork = 1;
52
53 int main(int argc, char **argv)
54 {
55 int c; /* command line arg */
56 socket_type server_s[2] = { {-1, 0, 0, 0}, {-1, -1, 0, 0} }; /* boa socket */
57 server_params *params;
58 pid_t pid;
59
60 /* set umask to u+rw, u-x, go-rwx */
61 c = umask(077);
62 if (c == -1) {
63 perror("umask");
64 exit(1);
65 }
66
67 { int devnullfd = -1;
68 devnullfd = open("/dev/null", 0);
69
70 /* make STDIN and STDOUT point to /dev/null */
71 if (devnullfd == -1) {
72 DIE("can't open /dev/null");
73 }
74
75 if (dup2(devnullfd, STDIN_FILENO) == -1) {
76 DIE("can't dup2 /dev/null to STDIN_FILENO");
77 }
78
79 close(devnullfd);
80 }
81
82 /* but first, update timestamp, because log_error_time uses it */
83 (void) time(&current_time);
84
85 while ((c = getopt(argc, argv, "c:r:d")) != -1) {
86 switch (c) {
87 case 'c':
88 if (server_root)
89 free(server_root);
90 server_root = strdup(optarg);
91 if (!server_root) {
92 perror("strdup (for server_root)");
93 exit(1);
94 }
95 break;
96 case 'r':
97 if (chdir(optarg) == -1) {
98 log_error_time();
99 perror("chdir (to chroot)");
100 exit(1);
101 }
102 if (chroot(optarg) == -1) {
103 log_error_time();
104 perror("chroot");
105 exit(1);
106 }
107 if (chdir("/") == -1) {
108 log_error_time();
109 perror("chdir (after chroot)");
110 exit(1);
111 }
112 break;
113 case 'd':
114 do_fork = 0;
115 break;
116 default:
117 fprintf(stderr, "Usage: %s [-c serverroot] [-r chroot] [-d]\n",
118 argv[0]);
119 exit(1);
120 }
121 }
122
123 create_server_names();
124 fixup_server_root();
125 read_config_files();
126 open_logs();
127
128 if ((boa_ssl >= 2 || boa_ssl == 0) && server_port > 0) {
129 server_s[0] = create_server_socket(server_port, 0);
130 }
131
132 if (boa_ssl != 0 && ssl_port > 0) {
133 server_s[1] = create_server_socket(ssl_port, 1);
134 }
135
136 if (server_s[1].socket == -1 && server_s[0].socket == -1) {
137 log_error_time();
138 fprintf(stderr, "Could not initialize sockets\n");
139 exit(1);
140 }
141
142 init_signals();
143 initialize_rlimits();
144
145 create_common_env();
146 build_needs_escape();
147
148 if (boa_ssl) {
149 initialize_ssl();
150 }
151
152 initialize_mmap();
153
154 /* background ourself */
155 if (do_fork) {
156 pid = fork();
157 } else {
158 pid = getpid();
159 }
160
161 switch (pid) {
162 case -1:
163 /* error */
164 perror("fork");
165 exit(1);
166 break;
167 case 0:
168 /* child, success */
169 break;
170 default:
171 /* parent, success */
172 if(pid_file != NULL) {
173 FILE *PID_FILE = fopen(pid_file, "w");
174 if(PID_FILE != NULL) {
175 fprintf(PID_FILE, "%d", pid);
176 fclose(PID_FILE);
177 } else {
178 perror("fopen pid file");
179 }
180 }
181 if (do_fork)
182 exit(0);
183 break;
184 }
185
186 drop_privs();
187
188 /* main loop */
189 timestamp();
190
191 start_time = current_time;
192
193 /* Blocks signals that are not supposed to be catched
194 * by the children.
195 */
196 block_main_signals();
197
198 /* spawn the children pool
199 */
200 params = smp_init(server_s);
201
202 /* unblock signals for daddy
203 */
204 unblock_main_signals();
205
206 /* regenerate parameters in that time interval
207 */
208 if (maintenance_interval < MIN_MAINTENANCE_INTERVAL) {
209 log_error_time();
210 fprintf(stderr,
211 "Changing maintenance mode time interval to %d minutes\n",
212 MIN_MAINTENANCE_INTERVAL / 60);
213 maintenance_interval = MIN_MAINTENANCE_INTERVAL;
214 }
215 alarm(maintenance_interval);
216
217 select_loop(params);
218
219 return 0;
220 }
221
222 server_params *global_server_params;
223 int global_server_params_size = 0;
224
225 /* This function will return a server_params pointer. This
226 * pointer is to be used as a pointer to the select loop.
227 */
228 static server_params *smp_init(socket_type server_s[2])
229 {
230 int i;
231 server_params *params;
232
233 #ifdef ENABLE_SMP
234 pthread_t tid;
235 int max_threads = max_server_threads;
236
237 father_id = pthread_self();
238 #else
239 const int max_threads = 1;
240 #endif
241
242 params = malloc(sizeof(server_params) * max_threads);
243 if (params == NULL) {
244 log_error_time();
245 fprintf(stderr, "Could not allocate memory.\n");
246 exit(1);
247 }
248
249 for (i = 0; i < max_threads; i++) {
250 params[i].server_s[0] = server_s[0];
251 params[i].server_s[1] = server_s[1];
252 params[i].request_ready = NULL;
253 params[i].request_block = NULL;
254 params[i].request_free = NULL;
255
256 /* for signal handling */
257 params[i].sighup_flag = 0;
258 params[i].sigchld_flag = 0;
259 params[i].sigalrm_flag = 0;
260 params[i].sigusr1_flag = 0;
261 params[i].sigterm_flag = 0;
262
263 params[i].sockbufsize = SOCKETBUF_SIZE;
264
265 params[i].status.requests = 0;
266 params[i].status.errors = 0;
267
268 params[i].total_connections = 0;
269 params[i].max_fd = 0;
270
271 params[i].handle_sigbus = 0;
272 }
273
274 #ifdef ENABLE_SMP
275 params[0].tid = father_id;
276
277 for (i = 1; i < max_threads; i++) {
278 if (pthread_create(&tid, NULL, &select_loop, &params[i]) != 0) {
279 log_error_time();
280 fprintf(stderr, "Could not dispatch threads.\n");
281 exit(1);
282 }
283 params[i].tid = tid;
284 }
285 #endif
286
287 if (max_threads > 1) {
288 log_error_time();
289 fprintf(stderr,
290 "%s: Dispatched %d HTTP server threads.\n", SERVER_NAME,
291 max_threads);
292 }
293
294 global_server_params_size = max_threads;
295 global_server_params = params;
296
297 return &params[0];
298 }
299
300 void smp_reinit()
301 {
302 #ifdef ENABLE_SMP
303 int i;
304 server_params *params = global_server_params;
305 int max_threads = max_server_threads;
306 #else
307 int max_threads = 1;
308 #endif
309
310 if (global_server_params_size < max_threads) {
311 log_error_time();
312 fprintf(stderr, "Cannot increase threads on runtime.\n");
313 max_threads = global_server_params_size;
314 }
315 #ifdef ENABLE_SMP
316 for (i = 1; i < max_threads; i++) {
317 pthread_t tid;
318 if (pthread_create(&tid, NULL, &select_loop, &params[i]) != 0) {
319 log_error_time();
320 fprintf(stderr, "Could not dispatch threads.\n");
321 exit(1);
322 }
323 params[i].tid = tid;
324 }
325 #endif
326
327 if (max_threads > 0) {
328 log_error_time();
329 fprintf(stderr, "Regenerated a pool of %d threads.\n", max_threads);
330 }
331
332 return;
333 }
334
335
336 static socket_type create_server_socket(int port, int secure)
337 {
338 socket_type server_s;
339
340 server_s.secure = secure;
341 server_s.port = port;
342
343 server_s.socket = socket(SERVER_AF, SOCK_STREAM, IPPROTO_TCP);
344 if (server_s.socket == -1) {
345 DIE("unable to create socket");
346 }
347
348 /* server socket is nonblocking */
349 if (set_nonblock_fd(server_s.socket) == -1) {
350 DIE("fcntl: unable to set server socket to nonblocking");
351 }
352
353 /* close server socket on exec so cgi's can't write to it */
354 if (set_cloexec_fd(server_s.socket) == -1) {
355 DIE("can't set close-on-exec on server socket!");
356 }
357
358 /* reuse socket addr */
359 if ((setsockopt
360 (server_s.socket, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt,
361 sizeof(sock_opt))) == -1) {
362 DIE("setsockopt");
363 }
364
365 /* internet family-specific code encapsulated in bind_server() */
366 if (bind_server(server_s.socket, server_ip, port) == -1) {
367 DIE("unable to bind");
368 }
369
370 /* listen: large number just in case your kernel is nicely tweaked */
371 if (listen(server_s.socket, backlog) == -1) {
372 DIE("unable to listen");
373 }
374 return server_s;
375 }
376
377 static void drop_privs(void)
378 {
379 /* give away our privs if we can */
380 if (getuid() == 0) {
381 struct passwd *passwdbuf;
382 passwdbuf = getpwuid(server_uid);
383 if (passwdbuf == NULL) {
384 DIE("getpwuid");
385 }
386 if (initgroups(passwdbuf->pw_name, passwdbuf->pw_gid) == -1) {
387 DIE("initgroups");
388 }
389 if (setgid(server_gid) == -1) {
390 DIE("setgid");
391 }
392 if (setuid(server_uid) == -1) {
393 DIE("setuid");
394 }
395 /* test for failed-but-return-was-successful setuid
396 * http://www.securityportal.com/list-archive/bugtraq/2000/Jun/0101.html
397 */
398 if (setuid(0) != -1 && server_uid != 0) {
399 DIE("icky Linux kernel bug!");
400 }
401 } else {
402 if (server_gid || server_uid) {
403 log_error_time();
404 fprintf(stderr, "Warning: "
405 "Not running as root: no attempt to change"
406 " to uid %d gid %d\n", server_uid, server_gid);
407 }
408 server_gid = getgid();
409 server_uid = getuid();
410 }
411 }
412
413 /*
414 * Name: fixup_server_root
415 *
416 * Description: Makes sure the server root is valid.
417 *
418 */
419
420 static void fixup_server_root()
421 {
422 if (!server_root) {
423 #ifdef SERVER_ROOT
424 server_root = strdup(SERVER_ROOT);
425 if (!server_root) {
426 perror("strdup (SERVER_ROOT)");
427 exit(1);
428 }
429 #else
430 fputs(SERVER_NAME
431 ": don't know where server root is. Please #define "
432 "SERVER_ROOT in defines.h\n"
433 "and recompile, or use the -c command line option to "
434 "specify it.\n", stderr);
435 exit(1);
436 #endif
437 }
438
439 if (chdir(server_root) == -1) {
440 fprintf(stderr, "Could not chdir to \"%s\": aborting\n",
441 server_root);
442 exit(1);
443 }
444
445 }
446
447 char boa_tls_version[64] = "\0";
448 char boa_version[] = "Server: "SERVER_NAME"/"SERVER_VERSION"\r\n";
449
450 static void create_server_names()
451 {
452 #ifdef ENABLE_SSL
453 if ( boa_tls_version[0] == 0) {
454 strcpy( boa_tls_version, "Server: "SERVER_NAME"/"SERVER_VERSION" GnuTLS/");
455 strcat( boa_tls_version, gnutls_check_version(NULL));
456 strcat( boa_tls_version, "\r\n");
457 }
458 #endif
459 }
460
461 #ifdef HAVE_GETRLIMIT
462
463 #ifndef RLIMIT_NOFILE
464 # define RLIMIT_NOFILE RLIMIT_OFILE
465 #endif
466
467 static void initialize_rlimits( )
468 {
469 int c;
470 struct rlimit rl;
471
472 /* Get system limits */
473 c = getrlimit(RLIMIT_NOFILE, &rl);
474 if (c < 0) {
475 perror("getrlimit");
476 exit(1);
477 }
478
479 #ifdef HAVE_SETRLIMIT
480 if (rl.rlim_max > rl.rlim_cur) {
481 log_error_time();
482 fprintf(stderr, "%s: Increasing max open files from %ld to %ld.\n",
483 SERVER_NAME, (unsigned long int)rl.rlim_cur,
484 (unsigned long int)rl.rlim_max);
485
486 rl.rlim_cur = rl.rlim_max;
487 c = setrlimit(RLIMIT_NOFILE, &rl);
488 if (c < 0) {
489 log_error_time();
490 perror("setrlimit:");
491 }
492 }
493 #endif
494
495 if (max_connections < 1)
496 max_connections = INT_MAX;
497
498 if (max_ssl_connections < 1)
499 max_ssl_connections = INT_MAX;
500
501 }
502
503 #else /* rlimits are not present */
504 static void initialize_rlimits( )
505 {
506 if (max_ssl_connections < 1)
507 max_ssl_connections = INT_MAX;
508
509 if (max_connections < 1)
510 max_connections = INT_MAX;
511
512 return;
513 }
514 #endif

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26