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

Contents of /hydra/src/boa.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.27 - (show annotations)
Wed Jan 22 07:51:49 2003 UTC (18 years, 10 months ago) by nmav
Branch: MAIN
CVS Tags: hydra_0_1_7, hydra_0_1_6, hydra_0_1_4
Changes since 1.26: +32 -28 lines
File MIME type: text/plain
merged changes from 0.1.x branch.

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.26.2.6 2003/01/19 15:54:34 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 #ifdef ENABLE_HIC
199 hic_init();
200 #endif
201
202 /* spawn the children pool
203 */
204 params = smp_init(server_s);
205
206 /* unblock signals for daddy
207 */
208 unblock_main_signals();
209
210 /* regenerate parameters in that time interval
211 */
212 if (maintenance_interval < MIN_MAINTENANCE_INTERVAL) {
213 log_error_time();
214 fprintf(stderr,
215 "Changing maintenance mode time interval to %d minutes\n",
216 MIN_MAINTENANCE_INTERVAL / 60);
217 maintenance_interval = MIN_MAINTENANCE_INTERVAL;
218 }
219 alarm(maintenance_interval);
220
221 select_loop(params);
222
223 return 0;
224 }
225
226 server_params *global_server_params;
227 int global_server_params_size = 0;
228
229 #ifdef ENABLE_HIC
230 hic_params *global_hic_params = NULL;
231 int global_hic_params_size = 0;
232 #endif
233
234 /* This function will return a server_params pointer. This
235 * pointer is to be used as a pointer to the select loop.
236 */
237 static server_params *smp_init(socket_type server_s[2])
238 {
239 int i;
240 server_params *params;
241
242 #ifdef ENABLE_SMP
243 pthread_t tid;
244 int max_threads = max_server_threads;
245
246 father_id = pthread_self();
247 #else
248 const int max_threads = 1;
249 #endif
250
251 params = malloc(sizeof(server_params) * max_threads);
252 if (params == NULL) {
253 log_error_time();
254 fprintf(stderr, "Could not allocate memory.\n");
255 exit(1);
256 }
257
258 for (i = 0; i < max_threads; i++) {
259 params[i].server_s[0] = server_s[0];
260 params[i].server_s[1] = server_s[1];
261 params[i].request_ready = NULL;
262 params[i].request_block = NULL;
263 params[i].request_free = NULL;
264
265 /* for signal handling */
266 params[i].sighup_flag = 0;
267 params[i].sigchld_flag = 0;
268 params[i].sigalrm_flag = 0;
269 params[i].sigusr1_flag = 0;
270 params[i].sigterm_flag = 0;
271
272 params[i].sockbufsize = SOCKETBUF_SIZE;
273
274 params[i].status.requests = 0;
275 params[i].status.errors = 0;
276
277 params[i].total_connections = 0;
278 params[i].max_fd = 0;
279
280 params[i].handle_sigbus = 0;
281 }
282
283 #ifdef ENABLE_SMP
284 params[0].tid = father_id;
285
286 for (i = 1; i < max_threads; i++) {
287 if (pthread_create(&tid, NULL, &select_loop, &params[i]) != 0) {
288 log_error_time();
289 fprintf(stderr, "Could not dispatch threads.\n");
290 exit(1);
291 }
292 params[i].tid = tid;
293 }
294 #endif
295
296 if (max_threads > 1) {
297 log_error_time();
298 fprintf(stderr,
299 "%s: Dispatched %d HTTP server threads.\n", SERVER_NAME,
300 max_threads);
301 }
302
303 global_server_params_size = max_threads;
304 global_server_params = params;
305
306 return &params[0];
307 }
308
309 void smp_reinit()
310 {
311 #ifdef ENABLE_SMP
312 int i;
313 server_params *params = global_server_params;
314 int max_threads = max_server_threads;
315 #else
316 int max_threads = 1;
317 #endif
318
319 if (global_server_params_size < max_threads) {
320 log_error_time();
321 fprintf(stderr, "Cannot increase threads on runtime.\n");
322 max_threads = global_server_params_size;
323 }
324 #ifdef ENABLE_SMP
325 for (i = 1; i < max_threads; i++) {
326 pthread_t tid;
327 if (pthread_create(&tid, NULL, &select_loop, &params[i]) != 0) {
328 log_error_time();
329 fprintf(stderr, "Could not dispatch threads.\n");
330 exit(1);
331 }
332 params[i].tid = tid;
333 }
334 #endif
335
336 if (max_threads > 0) {
337 log_error_time();
338 fprintf(stderr, "Regenerated a pool of %d threads.\n", max_threads);
339 }
340
341 return;
342 }
343
344 #ifdef ENABLE_HIC
345
346 pthread_t hic_tid;
347
348 /* This function will return a server_params pointer. This
349 * pointer is to be used as a pointer to the select loop.
350 */
351 void hic_init()
352 {
353 hic_params *params = global_hic_params;
354 int i;
355 #ifdef ENABLE_SMP
356 pthread_t tid;
357 #endif
358
359 if (max_hic_threads == 0)
360 return;
361
362 #ifdef ENABLE_SMP
363
364 if (global_hic_params_size > 0
365 && global_hic_params_size != max_hic_threads) {
366 log_error_time();
367 fprintf(stderr,
368 "Cannot change the HIC threads number on runtime.\n");
369 max_hic_threads = global_hic_params_size;
370 } else {
371 /* first time.. Allocate memory */
372 params = calloc(1, sizeof(hic_params) * max_hic_threads);
373 if (params == NULL) {
374 log_error_time();
375 fprintf(stderr,
376 "Could not allocate memory for HIC parameters.\n");
377 exit(1);
378 }
379
380 for (i = 0; i < max_hic_threads; i++) { /* initialize mutexes */
381 pthread_mutex_init(&params[i].lock, NULL);
382 }
383
384 global_hic_params = params;
385 global_hic_params_size = max_hic_threads;
386
387 }
388
389 for (i = 0; i < max_hic_threads; i++) {
390 if (pthread_create(&tid, NULL, &hic_main_loop, &params[i]) != 0) {
391 log_error_time();
392 fprintf(stderr, "Could not dispatch hic thread.\n");
393 exit(1);
394 }
395 params[i].tid = tid;
396 }
397
398 log_error_time();
399 fprintf(stderr,
400 "%s: Dispatched %d HIC threads.\n", SERVER_NAME,
401 max_hic_threads);
402
403 #endif
404
405 return;
406 }
407
408 #endif /* ENABLE_HIC */
409
410 static socket_type create_server_socket(int port, int secure)
411 {
412 socket_type server_s;
413
414 server_s.secure = secure;
415 server_s.port = port;
416
417 server_s.socket = socket(SERVER_AF, SOCK_STREAM, IPPROTO_TCP);
418 if (server_s.socket == -1) {
419 DIE("unable to create socket");
420 }
421
422 /* server socket is nonblocking */
423 if (set_nonblock_fd(server_s.socket) == -1) {
424 DIE("fcntl: unable to set server socket to nonblocking");
425 }
426
427 /* close server socket on exec so cgi's can't write to it */
428 if (set_cloexec_fd(server_s.socket) == -1) {
429 DIE("can't set close-on-exec on server socket!");
430 }
431
432 /* reuse socket addr */
433 if ((setsockopt
434 (server_s.socket, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt,
435 sizeof(sock_opt))) == -1) {
436 DIE("setsockopt");
437 }
438
439 /* internet family-specific code encapsulated in bind_server() */
440 if (bind_server(server_s.socket, server_ip, port) == -1) {
441 DIE("unable to bind");
442 }
443
444 /* listen: large number just in case your kernel is nicely tweaked */
445 if (listen(server_s.socket, backlog) == -1) {
446 DIE("unable to listen");
447 }
448 return server_s;
449 }
450
451 static void drop_privs(void)
452 {
453 /* give away our privs if we can */
454 if (getuid() == 0) {
455 struct passwd *passwdbuf;
456 passwdbuf = getpwuid(server_uid);
457 if (passwdbuf == NULL) {
458 DIE("getpwuid");
459 }
460 if (initgroups(passwdbuf->pw_name, passwdbuf->pw_gid) == -1) {
461 DIE("initgroups");
462 }
463 if (setgid(server_gid) == -1) {
464 DIE("setgid");
465 }
466 if (setuid(server_uid) == -1) {
467 DIE("setuid");
468 }
469 /* test for failed-but-return-was-successful setuid
470 * http://www.securityportal.com/list-archive/bugtraq/2000/Jun/0101.html
471 */
472 if (setuid(0) != -1 && server_uid != 0) {
473 DIE("icky Linux kernel bug!");
474 }
475 } else {
476 if (server_gid || server_uid) {
477 log_error_time();
478 fprintf(stderr, "Warning: "
479 "Not running as root: no attempt to change"
480 " to uid %d gid %d\n", server_uid, server_gid);
481 }
482 server_gid = getgid();
483 server_uid = getuid();
484 }
485 }
486
487 /*
488 * Name: fixup_server_root
489 *
490 * Description: Makes sure the server root is valid.
491 *
492 */
493
494 static void fixup_server_root()
495 {
496 if (!server_root) {
497 #ifdef SERVER_ROOT
498 server_root = strdup(SERVER_ROOT);
499 if (!server_root) {
500 perror("strdup (SERVER_ROOT)");
501 exit(1);
502 }
503 #else
504 fputs(SERVER_NAME
505 ": don't know where server root is. Please #define "
506 "SERVER_ROOT in defines.h\n"
507 "and recompile, or use the -c command line option to "
508 "specify it.\n", stderr);
509 exit(1);
510 #endif
511 }
512
513 if (chdir(server_root) == -1) {
514 fprintf(stderr, "Could not chdir to \"%s\": aborting\n",
515 server_root);
516 exit(1);
517 }
518
519 }
520
521 char boa_tls_version[64] = "\0";
522 char boa_version[] = "Server: "SERVER_NAME"/"SERVER_VERSION"\r\n";
523
524 static void create_server_names()
525 {
526 #ifdef ENABLE_SSL
527 if ( boa_tls_version[0] == 0) {
528 strcpy( boa_tls_version, "Server: "SERVER_NAME"/"SERVER_VERSION" GnuTLS/");
529 strcat( boa_tls_version, gnutls_check_version(NULL));
530 strcat( boa_tls_version, "\r\n");
531 }
532 #endif
533 }
534
535 #ifdef HAVE_GETRLIMIT
536
537 #ifndef RLIMIT_NOFILE
538 # define RLIMIT_NOFILE RLIMIT_OFILE
539 #endif
540
541 static void initialize_rlimits( )
542 {
543 int c;
544 struct rlimit rl;
545
546 /* Get system limits */
547 c = getrlimit(RLIMIT_NOFILE, &rl);
548 if (c < 0) {
549 perror("getrlimit");
550 exit(1);
551 }
552
553 #ifdef HAVE_SETRLIMIT
554 if (rl.rlim_max > rl.rlim_cur) {
555 log_error_time();
556 fprintf(stderr, "%s: Increasing max open files from %ld to %ld.\n",
557 SERVER_NAME, (unsigned long int)rl.rlim_cur,
558 (unsigned long int)rl.rlim_max);
559
560 rl.rlim_cur = rl.rlim_max;
561 c = setrlimit(RLIMIT_NOFILE, &rl);
562 if (c < 0) {
563 log_error_time();
564 perror("setrlimit:");
565 }
566 }
567 #endif
568
569 if (max_connections < 1)
570 max_connections = INT_MAX;
571
572 if (max_ssl_connections < 1)
573 max_ssl_connections = INT_MAX;
574
575 }
576
577 #else /* rlimits are not present */
578 static void initialize_rlimits( )
579 {
580 if (max_ssl_connections < 1)
581 max_ssl_connections = INT_MAX;
582
583 if (max_connections < 1)
584 max_connections = INT_MAX;
585
586 return;
587 }
588 #endif

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26