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

Contents of /hydra/src/boa.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.7 - (show annotations)
Fri Sep 27 07:03:45 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
Changes since 1.6: +1 -4 lines
File MIME type: text/plain
Added locks in the SSL session cache.

1 /*
2 * Boa, an http server
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.6 2002/09/25 19:55:53 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 static void drop_privs(void);
47 static server_params *smp_init(socket_type server_s[2]);
48 static int sock_opt = 1;
49 static int do_fork = 1;
50 int devnullfd = -1;
51
52 int main(int argc, char **argv)
53 {
54 int c; /* command line arg */
55 socket_type server_s[2] = {{ -1, 0, 0, 0}, { -1, -1, 0, 0 }}; /* boa socket */
56 server_params *params;
57
58 /* set umask to u+rw, u-x, go-rwx */
59 c = umask(~0600);
60 if (c == -1) {
61 perror("umask");
62 exit(1);
63 }
64
65 devnullfd = open("/dev/null", 0);
66
67 /* make STDIN and STDOUT point to /dev/null */
68 if (devnullfd == -1) {
69 DIE("can't open /dev/null");
70 }
71
72 if (dup2(devnullfd, STDIN_FILENO) == -1) {
73 DIE("can't dup2 /dev/null to STDIN_FILENO");
74 }
75
76 if (dup2(devnullfd, STDOUT_FILENO) == -1) {
77 DIE("can't dup2 /dev/null to STDOUT_FILENO");
78 }
79
80 /* but first, update timestamp, because log_error_time uses it */
81 (void) time(&current_time);
82
83 while ((c = getopt(argc, argv, "c:r:d")) != -1) {
84 switch (c) {
85 case 'c':
86 if (server_root)
87 free(server_root);
88 server_root = strdup(optarg);
89 if (!server_root) {
90 perror("strdup (for server_root)");
91 exit(1);
92 }
93 break;
94 case 'r':
95 if (chdir(optarg) == -1) {
96 log_error_time();
97 perror("chdir (to chroot)");
98 exit(1);
99 }
100 if (chroot(optarg) == -1) {
101 log_error_time();
102 perror("chroot");
103 exit(1);
104 }
105 if (chdir("/") == -1) {
106 log_error_time();
107 perror("chdir (after chroot)");
108 exit(1);
109 }
110 break;
111 case 'd':
112 do_fork = 0;
113 break;
114 default:
115 fprintf(stderr, "Usage: %s [-c serverroot] [-r chroot] [-d]\n", argv[0]);
116 exit(1);
117 }
118 }
119
120 fixup_server_root();
121 read_config_files();
122 open_logs();
123
124 if ((boa_ssl >= 2 || boa_ssl == 0) && server_port > 0) {
125 server_s[0] = create_server_socket( server_port, 0);
126 }
127
128 if (boa_ssl != 0 && ssl_port > 0) {
129 server_s[1] = create_server_socket( ssl_port, 1);
130 }
131
132 if (server_s[1].socket == -1 && server_s[0].socket == -1) {
133 log_error_time();
134 fprintf(stderr, "Could not initialize sockets\n");
135 exit(1);
136 }
137
138 init_signals();
139 drop_privs();
140 create_common_env();
141 build_needs_escape();
142
143 if (boa_ssl) {
144 initialize_ssl();
145 }
146
147 initialize_mmap();
148
149 if (max_connections < 1) {
150 struct rlimit rl;
151
152 /* has not been set explicitly */
153 c = getrlimit(RLIMIT_NOFILE, &rl);
154 if (c < 0) {
155 perror("getrlimit");
156 exit(1);
157 }
158 max_connections = rl.rlim_cur;
159 }
160
161 /* background ourself */
162 if (do_fork) {
163 switch(fork()) {
164 case -1:
165 /* error */
166 perror("fork");
167 exit(1);
168 break;
169 case 0:
170 /* child, success */
171 break;
172 default:
173 /* parent, success */
174 exit(0);
175 break;
176 }
177 }
178
179 /* main loop */
180 timestamp();
181
182 start_time = current_time;
183
184 /* Blocks signals that are not supposed to be catched
185 * by the children.
186 */
187 block_main_signals();
188
189 /* spawn the children pool
190 */
191 params = smp_init( server_s);
192
193 /* unblock signals for daddy
194 */
195 unblock_main_signals();
196
197 /* regenerate parameters in that time interval
198 */
199 if (boa_ssl) {
200 if (ssl_params_refresh < DEFAULT_SSL_PARAMS_REFRESH) {
201 log_error_time();
202 fprintf(stderr, "SSL parameters will be refreshed every %d minutes\n",
203 DEFAULT_SSL_PARAMS_REFRESH/60);
204 ssl_params_refresh = DEFAULT_SSL_PARAMS_REFRESH;
205 }
206 alarm( ssl_params_refresh);
207 }
208
209 select_loop( params);
210
211 return 0;
212 }
213
214 server_params *global_server_params;
215 int global_server_params_size;
216
217 extern int server_max_threads;
218
219 /* This function will return a server_params pointer. This
220 * pointer is to be used as a pointer to the select loop.
221 */
222 static server_params* smp_init( socket_type server_s[2])
223 {
224 int i;
225 server_params *params;
226
227 #ifdef ENABLE_SMP
228 pthread_t tid;
229 int max_threads = server_max_threads;
230
231 father_id = pthread_self();
232 #else
233 const int max_threads = 1;
234 #endif
235
236 params = malloc( sizeof(server_params) * max_threads);
237 if (params == NULL) {
238 log_error_time();
239 fprintf(stderr,
240 "Could not allocate memory.\n");
241 exit(1);
242 }
243
244 for (i=0;i<max_threads;i++) {
245 params[i].server_s[0] = server_s[0];
246 params[i].server_s[1] = server_s[1];
247 params[i].request_ready = NULL;
248 params[i].request_block = NULL;
249 params[i].request_free = NULL;
250
251 /* for signal handling */
252 params[i].sighup_flag = 0;
253 params[i].sigchld_flag = 0;
254 params[i].sigalrm_flag = 0;
255 params[i].sigusr1_flag = 0;
256 params[i].sigterm_flag = 0;
257
258 params[i].sockbufsize = SOCKETBUF_SIZE;
259
260 params[i].status.requests = 0;
261 params[i].status.errors = 0;
262
263 params[i].total_connections = 0;
264 params[i].max_fd = 0;
265
266 params[i].handle_sigbus = 0;
267 }
268
269 #ifdef ENABLE_SMP
270 params[0].tid = father_id;
271
272 for( i=1;i<max_threads;i++) {
273 if (pthread_create( &tid, NULL, &select_loop, &params[i]) != 0)
274 {
275 log_error_time();
276 fprintf(stderr,
277 "Could not dispatch threads.\n");
278 exit(1);
279 }
280 params[i].tid = tid;
281 }
282 #endif
283
284 if (max_threads > 1) {
285 log_error_time();
286 fprintf(stderr,
287 "Generated pool of %d threads.\n", max_threads);
288 }
289
290 global_server_params_size = max_threads;
291 global_server_params = params;
292
293 return &params[0];
294 }
295
296 void smp_reinit()
297 {
298 #ifdef ENABLE_SMP
299 int i;
300 server_params *params = global_server_params;
301 int max_threads = server_max_threads;
302 #else
303 int max_threads = 1;
304 #endif
305
306 if (global_server_params_size < max_threads) {
307 log_error_time();
308 fprintf(stderr,
309 "Cannot increase threads on runtime.\n");
310 max_threads = global_server_params_size;
311 }
312
313 #ifdef ENABLE_SMP
314 for( i=1;i<max_threads;i++) {
315 pthread_t tid;
316 if (pthread_create( &tid, NULL, &select_loop, &params[i]) != 0)
317 {
318 log_error_time();
319 fprintf(stderr,
320 "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,
330 "Regenerated a pool of %d threads.\n", max_threads);
331 }
332
333 return;
334 }
335
336
337 static socket_type create_server_socket( int port, int secure)
338 {
339 socket_type server_s;
340
341 server_s.secure = secure;
342 server_s.port = port;
343
344 server_s.socket = socket(SERVER_AF, SOCK_STREAM, IPPROTO_TCP);
345 if (server_s.socket == -1) {
346 DIE("unable to create socket");
347 }
348
349 /* server socket is nonblocking */
350 if (set_nonblock_fd(server_s.socket) == -1) {
351 DIE("fcntl: unable to set server socket to nonblocking");
352 }
353
354 /* close server socket on exec so cgi's can't write to it */
355 if (fcntl(server_s.socket, F_SETFD, 1) == -1) {
356 DIE("can't set close-on-exec on server socket!");
357 }
358
359 /* reuse socket addr */
360 if ((setsockopt(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) {
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 char *dirbuf;
423
424 if (!server_root) {
425 #ifdef SERVER_ROOT
426 server_root = strdup(SERVER_ROOT);
427 if (!server_root) {
428 perror("strdup (SERVER_ROOT)");
429 exit(1);
430 }
431 #else
432 fputs(SERVER_NAME": don't know where server root is. Please #define "
433 "SERVER_ROOT in defines.h\n"
434 "and recompile, or use the -c command line option to "
435 "specify it.\n", stderr);
436 exit(1);
437 #endif
438 }
439
440 if (chdir(server_root) == -1) {
441 fprintf(stderr, "Could not chdir to \"%s\": aborting\n",
442 server_root);
443 exit(1);
444 }
445
446 dirbuf = normalize_path(server_root);
447 free(server_root);
448 server_root = dirbuf;
449 }
450

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26