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

Annotation of /hydra/src/boa.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.28 - (hide annotations)
Thu Mar 9 18:11:07 2006 UTC (18 years, 1 month ago) by nmav
Branch: MAIN
CVS Tags: hydra_0_1_6_without_hic, hydra_0_1_8, HEAD
Changes since 1.27: +1 -75 lines
File MIME type: text/plain
Removed the HIC support.

1 nmav 1.1 /*
2 nmav 1.12 * Hydra, an http server (based on Boa 0.94.13)
3 nmav 1.1 * 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 nmav 1.28 /* $Id: boa.c,v 1.27 2003/01/22 07:51:49 nmav Exp $*/
26 nmav 1.1
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 nmav 1.15 static socket_type create_server_socket(int port, int);
44     void hic_init(void);
45 nmav 1.17 static void initialize_rlimits();
46 nmav 1.1 static void drop_privs(void);
47     static server_params *smp_init(socket_type server_s[2]);
48 nmav 1.15 static void create_server_names( void);
49    
50 nmav 1.1 static int sock_opt = 1;
51     static int do_fork = 1;
52    
53     int main(int argc, char **argv)
54     {
55 nmav 1.15 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 nmav 1.23 pid_t pid;
59 nmav 1.15
60     /* set umask to u+rw, u-x, go-rwx */
61 nmav 1.23 c = umask(077);
62 nmav 1.15 if (c == -1) {
63     perror("umask");
64     exit(1);
65     }
66    
67 nmav 1.23 { int devnullfd = -1;
68     devnullfd = open("/dev/null", 0);
69 nmav 1.15
70 nmav 1.23 /* 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 nmav 1.15
79 nmav 1.23 close(devnullfd);
80 nmav 1.15 }
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 nmav 1.21 initialize_rlimits();
144    
145 nmav 1.15 create_common_env();
146     build_needs_escape();
147 nmav 1.1
148 nmav 1.15 if (boa_ssl) {
149     initialize_ssl();
150     }
151    
152     initialize_mmap();
153    
154     /* background ourself */
155     if (do_fork) {
156 nmav 1.23 pid = fork();
157     } else {
158     pid = getpid();
159     }
160    
161     switch (pid) {
162 nmav 1.15 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 nmav 1.23 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 nmav 1.15 break;
184     }
185    
186 nmav 1.23 drop_privs();
187    
188 nmav 1.15 /* 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     /* spawn the children pool
199     */
200     params = smp_init(server_s);
201    
202     /* unblock signals for daddy
203     */
204     unblock_main_signals();
205 nmav 1.1
206 nmav 1.15 /* regenerate parameters in that time interval
207     */
208 nmav 1.25 if (maintenance_interval < MIN_MAINTENANCE_INTERVAL) {
209     log_error_time();
210     fprintf(stderr,
211 nmav 1.26 "Changing maintenance mode time interval to %d minutes\n",
212 nmav 1.25 MIN_MAINTENANCE_INTERVAL / 60);
213     maintenance_interval = MIN_MAINTENANCE_INTERVAL;
214 nmav 1.15 }
215 nmav 1.25 alarm(maintenance_interval);
216 nmav 1.1
217 nmav 1.15 select_loop(params);
218 nmav 1.1
219 nmav 1.15 return 0;
220 nmav 1.1 }
221    
222     server_params *global_server_params;
223 nmav 1.15 int global_server_params_size = 0;
224 nmav 1.1
225     /* This function will return a server_params pointer. This
226     * pointer is to be used as a pointer to the select loop.
227     */
228 nmav 1.15 static server_params *smp_init(socket_type server_s[2])
229 nmav 1.1 {
230 nmav 1.15 int i;
231     server_params *params;
232 nmav 1.1
233     #ifdef ENABLE_SMP
234 nmav 1.15 pthread_t tid;
235     int max_threads = max_server_threads;
236 nmav 1.1
237 nmav 1.15 father_id = pthread_self();
238 nmav 1.1 #else
239 nmav 1.15 const int max_threads = 1;
240 nmav 1.1 #endif
241    
242 nmav 1.15 params = malloc(sizeof(server_params) * max_threads);
243     if (params == NULL) {
244 nmav 1.1 log_error_time();
245 nmav 1.15 fprintf(stderr, "Could not allocate memory.\n");
246 nmav 1.1 exit(1);
247 nmav 1.15 }
248    
249     for (i = 0; i < max_threads; i++) {
250     params[i].server_s[0] = server_s[0];
251     params[i].server_s[1] = server_s[1];
252     params[i].request_ready = NULL;
253     params[i].request_block = NULL;
254     params[i].request_free = NULL;
255    
256     /* for signal handling */
257     params[i].sighup_flag = 0;
258     params[i].sigchld_flag = 0;
259     params[i].sigalrm_flag = 0;
260     params[i].sigusr1_flag = 0;
261     params[i].sigterm_flag = 0;
262    
263     params[i].sockbufsize = SOCKETBUF_SIZE;
264    
265     params[i].status.requests = 0;
266     params[i].status.errors = 0;
267    
268     params[i].total_connections = 0;
269     params[i].max_fd = 0;
270    
271     params[i].handle_sigbus = 0;
272     }
273 nmav 1.1
274     #ifdef ENABLE_SMP
275 nmav 1.15 params[0].tid = father_id;
276 nmav 1.1
277 nmav 1.15 for (i = 1; i < max_threads; i++) {
278     if (pthread_create(&tid, NULL, &select_loop, &params[i]) != 0) {
279     log_error_time();
280     fprintf(stderr, "Could not dispatch threads.\n");
281     exit(1);
282 nmav 1.1 }
283     params[i].tid = tid;
284 nmav 1.15 }
285 nmav 1.1 #endif
286    
287 nmav 1.15 if (max_threads > 1) {
288 nmav 1.1 log_error_time();
289 nmav 1.15 fprintf(stderr,
290     "%s: Dispatched %d HTTP server threads.\n", SERVER_NAME,
291     max_threads);
292     }
293 nmav 1.1
294 nmav 1.15 global_server_params_size = max_threads;
295     global_server_params = params;
296 nmav 1.1
297 nmav 1.15 return &params[0];
298 nmav 1.1 }
299    
300     void smp_reinit()
301     {
302     #ifdef ENABLE_SMP
303 nmav 1.2 int i;
304     server_params *params = global_server_params;
305 nmav 1.15 int max_threads = max_server_threads;
306 nmav 1.1 #else
307 nmav 1.2 int max_threads = 1;
308 nmav 1.1 #endif
309    
310 nmav 1.2 if (global_server_params_size < max_threads) {
311 nmav 1.15 log_error_time();
312     fprintf(stderr, "Cannot increase threads on runtime.\n");
313     max_threads = global_server_params_size;
314 nmav 1.2 }
315 nmav 1.1 #ifdef ENABLE_SMP
316 nmav 1.15 for (i = 1; i < max_threads; i++) {
317 nmav 1.1 pthread_t tid;
318 nmav 1.15 if (pthread_create(&tid, NULL, &select_loop, &params[i]) != 0) {
319     log_error_time();
320     fprintf(stderr, "Could not dispatch threads.\n");
321     exit(1);
322 nmav 1.1 }
323     params[i].tid = tid;
324 nmav 1.2 }
325 nmav 1.1 #endif
326    
327 nmav 1.2 if (max_threads > 0) {
328 nmav 1.1 log_error_time();
329 nmav 1.15 fprintf(stderr, "Regenerated a pool of %d threads.\n", max_threads);
330     }
331 nmav 1.1
332 nmav 1.2 return;
333 nmav 1.1 }
334    
335    
336 nmav 1.15 static socket_type create_server_socket(int port, int secure)
337 nmav 1.1 {
338 nmav 1.15 socket_type server_s;
339 nmav 1.1
340 nmav 1.15 server_s.secure = secure;
341     server_s.port = port;
342    
343     server_s.socket = socket(SERVER_AF, SOCK_STREAM, IPPROTO_TCP);
344     if (server_s.socket == -1) {
345     DIE("unable to create socket");
346     }
347    
348     /* server socket is nonblocking */
349     if (set_nonblock_fd(server_s.socket) == -1) {
350     DIE("fcntl: unable to set server socket to nonblocking");
351     }
352    
353     /* close server socket on exec so cgi's can't write to it */
354 nmav 1.24 if (set_cloexec_fd(server_s.socket) == -1) {
355 nmav 1.15 DIE("can't set close-on-exec on server socket!");
356     }
357 nmav 1.1
358 nmav 1.15 /* reuse socket addr */
359     if ((setsockopt
360     (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 nmav 1.1 }
376    
377     static void drop_privs(void)
378     {
379 nmav 1.15 /* 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 nmav 1.27 if (setuid(0) != -1 && server_uid != 0) {
399 nmav 1.15 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 nmav 1.1 }
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 nmav 1.15 if (!server_root) {
423 nmav 1.1 #ifdef SERVER_ROOT
424 nmav 1.15 server_root = strdup(SERVER_ROOT);
425     if (!server_root) {
426     perror("strdup (SERVER_ROOT)");
427     exit(1);
428     }
429 nmav 1.1 #else
430 nmav 1.15 fputs(SERVER_NAME
431     ": don't know where server root is. Please #define "
432     "SERVER_ROOT in defines.h\n"
433     "and recompile, or use the -c command line option to "
434     "specify it.\n", stderr);
435     exit(1);
436     #endif
437     }
438    
439     if (chdir(server_root) == -1) {
440     fprintf(stderr, "Could not chdir to \"%s\": aborting\n",
441     server_root);
442     exit(1);
443     }
444    
445 nmav 1.1 }
446    
447 nmav 1.15 char boa_tls_version[64] = "\0";
448 nmav 1.16 char boa_version[] = "Server: "SERVER_NAME"/"SERVER_VERSION"\r\n";
449 nmav 1.15
450     static void create_server_names()
451     {
452 nmav 1.19 #ifdef ENABLE_SSL
453 nmav 1.15 if ( boa_tls_version[0] == 0) {
454     strcpy( boa_tls_version, "Server: "SERVER_NAME"/"SERVER_VERSION" GnuTLS/");
455     strcat( boa_tls_version, gnutls_check_version(NULL));
456 nmav 1.16 strcat( boa_tls_version, "\r\n");
457 nmav 1.15 }
458 nmav 1.19 #endif
459 nmav 1.15 }
460 nmav 1.17
461     #ifdef HAVE_GETRLIMIT
462    
463     #ifndef RLIMIT_NOFILE
464     # define RLIMIT_NOFILE RLIMIT_OFILE
465     #endif
466    
467     static void initialize_rlimits( )
468     {
469     int c;
470     struct rlimit rl;
471    
472 nmav 1.27 /* Get system limits */
473     c = getrlimit(RLIMIT_NOFILE, &rl);
474     if (c < 0) {
475     perror("getrlimit");
476     exit(1);
477     }
478    
479     #ifdef HAVE_SETRLIMIT
480     if (rl.rlim_max > rl.rlim_cur) {
481     log_error_time();
482     fprintf(stderr, "%s: Increasing max open files from %ld to %ld.\n",
483     SERVER_NAME, (unsigned long int)rl.rlim_cur,
484     (unsigned long int)rl.rlim_max);
485    
486     rl.rlim_cur = rl.rlim_max;
487     c = setrlimit(RLIMIT_NOFILE, &rl);
488 nmav 1.17 if (c < 0) {
489 nmav 1.27 log_error_time();
490     perror("setrlimit:");
491 nmav 1.17 }
492 nmav 1.27 }
493 nmav 1.17 #endif
494 nmav 1.27
495     if (max_connections < 1)
496     max_connections = INT_MAX;
497    
498     if (max_ssl_connections < 1)
499     max_ssl_connections = INT_MAX;
500    
501 nmav 1.17 }
502    
503     #else /* rlimits are not present */
504     static void initialize_rlimits( )
505     {
506 nmav 1.27 if (max_ssl_connections < 1)
507     max_ssl_connections = INT_MAX;
508    
509 nmav 1.21 if (max_connections < 1)
510     max_connections = INT_MAX;
511 nmav 1.27
512 nmav 1.17 return;
513     }
514     #endif

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26