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

Contents of /hydra/src/boa.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.4 - (show annotations)
Tue Sep 24 18:07:58 2002 UTC (21 years, 6 months ago) by nmav
Branch: MAIN
Changes since 1.3: +7 -1 lines
File MIME type: text/plain
*** empty log message ***

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.3 2002/09/23 19:28:41 nmav Exp $*/
26
27 #include "boa.h"
28 #include "ssl.h"
29 #include <sys/resource.h>
30 #ifdef ENABLE_SMP
31 # include <pthread.h>
32
33 pthread_t father_id;
34
35 #endif
36
37 extern int ssl_params_refresh;
38
39 /* globals */
40 int backlog = SO_MAXCONN;
41 time_t start_time;
42
43 time_t current_time;
44
45
46 /* static to boa.c */
47 static void fixup_server_root(void);
48 static socket_type create_server_socket( int port, int);
49 static void drop_privs(void);
50 static server_params *smp_init(socket_type server_s[2]);
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", argv[0]);
119 exit(1);
120 }
121 }
122
123 fixup_server_root();
124 read_config_files();
125 open_logs();
126
127 if ((boa_ssl >= 2 || boa_ssl == 0) && server_port > 0) {
128 server_s[0] = create_server_socket( server_port, 0);
129 }
130
131 if (boa_ssl != 0 && ssl_port > 0) {
132 server_s[1] = create_server_socket( ssl_port, 1);
133 }
134
135 if (server_s[1].socket == -1 && server_s[0].socket == -1) {
136 log_error_time();
137 fprintf(stderr, "Could not initialize sockets\n");
138 exit(1);
139 }
140
141 init_signals();
142 drop_privs();
143 create_common_env();
144 build_needs_escape();
145
146 if (boa_ssl) {
147 initialize_ssl();
148 }
149
150 if (max_connections < 1) {
151 struct rlimit rl;
152
153 /* has not been set explicitly */
154 c = getrlimit(RLIMIT_NOFILE, &rl);
155 if (c < 0) {
156 perror("getrlimit");
157 exit(1);
158 }
159 max_connections = rl.rlim_cur;
160 }
161
162 /* background ourself */
163 if (do_fork) {
164 switch(fork()) {
165 case -1:
166 /* error */
167 perror("fork");
168 exit(1);
169 break;
170 case 0:
171 /* child, success */
172 break;
173 default:
174 /* parent, success */
175 exit(0);
176 break;
177 }
178 }
179
180 /* main loop */
181 timestamp();
182
183 start_time = current_time;
184
185 /* Blocks signals that are not supposed to be catched
186 * by the children.
187 */
188 block_main_signals();
189
190 /* spawn the children pool
191 */
192 params = smp_init( server_s);
193
194 /* unblock signals for daddy
195 */
196 unblock_main_signals();
197
198 /* regenerate parameters in that time interval
199 */
200 if (boa_ssl) {
201 if (ssl_params_refresh < DEFAULT_SSL_PARAMS_REFRESH) {
202 log_error_time();
203 fprintf(stderr, "SSL parameters will be refreshed every %d minutes\n",
204 DEFAULT_SSL_PARAMS_REFRESH/60);
205 ssl_params_refresh = DEFAULT_SSL_PARAMS_REFRESH;
206 }
207 alarm( ssl_params_refresh);
208 }
209
210 select_loop( params);
211
212 return 0;
213 }
214
215 server_params *global_server_params;
216 int global_server_params_size;
217
218 extern int server_max_threads;
219
220 /* This function will return a server_params pointer. This
221 * pointer is to be used as a pointer to the select loop.
222 */
223 static server_params* smp_init( socket_type server_s[2])
224 {
225 int i;
226 server_params *params;
227
228 #ifdef ENABLE_SMP
229 pthread_t tid;
230 int max_threads = server_max_threads;
231
232 father_id = pthread_self();
233 #else
234 const int max_threads = 1;
235 #endif
236
237 params = malloc( sizeof(server_params) * max_threads);
238 if (params == NULL) {
239 log_error_time();
240 fprintf(stderr,
241 "Could not allocate memory.\n");
242 exit(1);
243 }
244
245 for (i=0;i<max_threads;i++) {
246 params[i].server_s[0] = server_s[0];
247 params[i].server_s[1] = server_s[1];
248 params[i].request_ready = NULL;
249 params[i].request_block = NULL;
250 params[i].request_free = NULL;
251
252 /* for signal handling */
253 params[i].sighup_flag = 0;
254 params[i].sigchld_flag = 0;
255 params[i].sigalrm_flag = 0;
256 params[i].sigusr1_flag = 0;
257 params[i].sigterm_flag = 0;
258
259 params[i].sockbufsize = SOCKETBUF_SIZE;
260
261 params[i].status.requests = 0;
262 params[i].status.errors = 0;
263
264 params[i].total_connections = 0;
265 params[i].max_fd = 0;
266
267 params[i].handle_sigbus = 0;
268 }
269
270 #ifdef ENABLE_SMP
271 params[0].tid = father_id;
272
273 for( i=1;i<max_threads;i++) {
274 if (pthread_create( &tid, NULL, &select_loop, &params[i]) != 0)
275 {
276 log_error_time();
277 fprintf(stderr,
278 "Could not dispatch threads.\n");
279 exit(1);
280 }
281 params[i].tid = tid;
282 }
283 #endif
284
285 if (max_threads > 1) {
286 log_error_time();
287 fprintf(stderr,
288 "Generated pool of %d threads.\n", max_threads);
289 }
290
291 global_server_params_size = max_threads;
292 global_server_params = params;
293
294 return &params[0];
295 }
296
297 void smp_reinit()
298 {
299 #ifdef ENABLE_SMP
300 int i;
301 server_params *params = global_server_params;
302 int max_threads = server_max_threads;
303 #else
304 int max_threads = 1;
305 #endif
306
307 if (global_server_params_size < max_threads) {
308 log_error_time();
309 fprintf(stderr,
310 "Cannot increase threads on runtime.\n");
311 max_threads = global_server_params_size;
312 }
313
314 #ifdef ENABLE_SMP
315 for( i=1;i<max_threads;i++) {
316 pthread_t tid;
317 if (pthread_create( &tid, NULL, &select_loop, &params[i]) != 0)
318 {
319 log_error_time();
320 fprintf(stderr,
321 "Could not dispatch threads.\n");
322 exit(1);
323 }
324 params[i].tid = tid;
325 }
326 #endif
327
328 if (max_threads > 0) {
329 log_error_time();
330 fprintf(stderr,
331 "Regenerated a pool of %d threads.\n", max_threads);
332 }
333
334 return;
335 }
336
337
338 static socket_type create_server_socket( int port, int secure)
339 {
340 socket_type server_s;
341
342 server_s.secure = secure;
343 server_s.port = port;
344
345 server_s.socket = socket(SERVER_AF, SOCK_STREAM, IPPROTO_TCP);
346 if (server_s.socket == -1) {
347 DIE("unable to create socket");
348 }
349
350 /* server socket is nonblocking */
351 if (set_nonblock_fd(server_s.socket) == -1) {
352 DIE("fcntl: unable to set server socket to nonblocking");
353 }
354
355 /* close server socket on exec so cgi's can't write to it */
356 if (fcntl(server_s.socket, F_SETFD, 1) == -1) {
357 DIE("can't set close-on-exec on server socket!");
358 }
359
360 /* reuse socket addr */
361 if ((setsockopt(server_s.socket, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt,
362 sizeof (sock_opt))) == -1) {
363 DIE("setsockopt");
364 }
365
366 /* internet family-specific code encapsulated in bind_server() */
367 if (bind_server(server_s.socket, server_ip, port) == -1) {
368 DIE("unable to bind");
369 }
370
371 /* listen: large number just in case your kernel is nicely tweaked */
372 if (listen(server_s.socket, backlog) == -1) {
373 DIE("unable to listen");
374 }
375 return server_s;
376 }
377
378 static void drop_privs(void)
379 {
380 /* give away our privs if we can */
381 if (getuid() == 0) {
382 struct passwd *passwdbuf;
383 passwdbuf = getpwuid(server_uid);
384 if (passwdbuf == NULL) {
385 DIE("getpwuid");
386 }
387 if (initgroups(passwdbuf->pw_name, passwdbuf->pw_gid) == -1) {
388 DIE("initgroups");
389 }
390 if (setgid(server_gid) == -1) {
391 DIE("setgid");
392 }
393 if (setuid(server_uid) == -1) {
394 DIE("setuid");
395 }
396 /* test for failed-but-return-was-successful setuid
397 * http://www.securityportal.com/list-archive/bugtraq/2000/Jun/0101.html
398 */
399 if (setuid(0) != -1) {
400 DIE("icky Linux kernel bug!");
401 }
402 } else {
403 if (server_gid || server_uid) {
404 log_error_time();
405 fprintf(stderr, "Warning: "
406 "Not running as root: no attempt to change"
407 " to uid %d gid %d\n", server_uid, server_gid);
408 }
409 server_gid = getgid();
410 server_uid = getuid();
411 }
412 }
413
414 /*
415 * Name: fixup_server_root
416 *
417 * Description: Makes sure the server root is valid.
418 *
419 */
420
421 static void fixup_server_root()
422 {
423 char *dirbuf;
424
425 if (!server_root) {
426 #ifdef SERVER_ROOT
427 server_root = strdup(SERVER_ROOT);
428 if (!server_root) {
429 perror("strdup (SERVER_ROOT)");
430 exit(1);
431 }
432 #else
433 fputs("boa: don't know where server root is. Please #define "
434 "SERVER_ROOT in boa.h\n"
435 "and recompile, or use the -c command line option to "
436 "specify it.\n", stderr);
437 exit(1);
438 #endif
439 }
440
441 if (chdir(server_root) == -1) {
442 fprintf(stderr, "Could not chdir to \"%s\": aborting\n",
443 server_root);
444 exit(1);
445 }
446
447 dirbuf = normalize_path(server_root);
448 free(server_root);
449 server_root = dirbuf;
450 }
451

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26