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

Contents of /hydra/src/boa.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.18 - (show annotations)
Wed Oct 2 19:32:49 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
Changes since 1.17: +5 -4 lines
File MIME type: text/plain
*** empty log message ***

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26