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

Contents of /hydra/src/boa.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.16 - (show annotations)
Mon Sep 30 18:18:52 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
CVS Tags: hydra_0_0_4, hydra_0_0_5
Changes since 1.15: +3 -2 lines
File MIME type: text/plain
Some cleanups in server version string generation.

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

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26