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

Annotation of /hydra/src/boa.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.26 - (hide annotations)
Sun Oct 27 10:06:28 2002 UTC (21 years, 5 months ago) by nmav
Branch: MAIN
CVS Tags: hydra_0_0_10, hydra_0_0_9, hydra_0_1_1, hydra_0_1_0
Branch point for: hydra_0_1_0_patches
Changes since 1.25: +2 -2 lines
File MIME type: text/plain
Added file access control lists per virtual host. Based on patch for
Boa by Peter Korsgaard <jacmet@sunsite.dk>.

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.26 /* $Id: boa.c,v 1.25 2002/10/27 08:45:51 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 nmav 1.14 #ifdef ENABLE_HIC
199 nmav 1.15 hic_init();
200 nmav 1.14 #endif
201 nmav 1.1
202 nmav 1.15 /* spawn the children pool
203     */
204     params = smp_init(server_s);
205    
206     /* unblock signals for daddy
207     */
208     unblock_main_signals();
209 nmav 1.1
210 nmav 1.15 /* regenerate parameters in that time interval
211     */
212 nmav 1.25 if (maintenance_interval < MIN_MAINTENANCE_INTERVAL) {
213     log_error_time();
214     fprintf(stderr,
215 nmav 1.26 "Changing maintenance mode time interval to %d minutes\n",
216 nmav 1.25 MIN_MAINTENANCE_INTERVAL / 60);
217     maintenance_interval = MIN_MAINTENANCE_INTERVAL;
218 nmav 1.15 }
219 nmav 1.25 alarm(maintenance_interval);
220 nmav 1.1
221 nmav 1.15 select_loop(params);
222 nmav 1.1
223 nmav 1.15 return 0;
224 nmav 1.1 }
225    
226     server_params *global_server_params;
227 nmav 1.15 int global_server_params_size = 0;
228 nmav 1.1
229 nmav 1.15 #ifdef ENABLE_HIC
230     hic_params *global_hic_params = NULL;
231     int global_hic_params_size = 0;
232     #endif
233 nmav 1.1
234     /* This function will return a server_params pointer. This
235     * pointer is to be used as a pointer to the select loop.
236     */
237 nmav 1.15 static server_params *smp_init(socket_type server_s[2])
238 nmav 1.1 {
239 nmav 1.15 int i;
240     server_params *params;
241 nmav 1.1
242     #ifdef ENABLE_SMP
243 nmav 1.15 pthread_t tid;
244     int max_threads = max_server_threads;
245 nmav 1.1
246 nmav 1.15 father_id = pthread_self();
247 nmav 1.1 #else
248 nmav 1.15 const int max_threads = 1;
249 nmav 1.1 #endif
250    
251 nmav 1.15 params = malloc(sizeof(server_params) * max_threads);
252     if (params == NULL) {
253 nmav 1.1 log_error_time();
254 nmav 1.15 fprintf(stderr, "Could not allocate memory.\n");
255 nmav 1.1 exit(1);
256 nmav 1.15 }
257    
258     for (i = 0; i < max_threads; i++) {
259     params[i].server_s[0] = server_s[0];
260     params[i].server_s[1] = server_s[1];
261     params[i].request_ready = NULL;
262     params[i].request_block = NULL;
263     params[i].request_free = NULL;
264    
265     /* for signal handling */
266     params[i].sighup_flag = 0;
267     params[i].sigchld_flag = 0;
268     params[i].sigalrm_flag = 0;
269     params[i].sigusr1_flag = 0;
270     params[i].sigterm_flag = 0;
271    
272     params[i].sockbufsize = SOCKETBUF_SIZE;
273    
274     params[i].status.requests = 0;
275     params[i].status.errors = 0;
276    
277     params[i].total_connections = 0;
278     params[i].max_fd = 0;
279    
280     params[i].handle_sigbus = 0;
281     }
282 nmav 1.1
283     #ifdef ENABLE_SMP
284 nmav 1.15 params[0].tid = father_id;
285 nmav 1.1
286 nmav 1.15 for (i = 1; i < max_threads; i++) {
287     if (pthread_create(&tid, NULL, &select_loop, &params[i]) != 0) {
288     log_error_time();
289     fprintf(stderr, "Could not dispatch threads.\n");
290     exit(1);
291 nmav 1.1 }
292     params[i].tid = tid;
293 nmav 1.15 }
294 nmav 1.1 #endif
295    
296 nmav 1.15 if (max_threads > 1) {
297 nmav 1.1 log_error_time();
298 nmav 1.15 fprintf(stderr,
299     "%s: Dispatched %d HTTP server threads.\n", SERVER_NAME,
300     max_threads);
301     }
302 nmav 1.1
303 nmav 1.15 global_server_params_size = max_threads;
304     global_server_params = params;
305 nmav 1.1
306 nmav 1.15 return &params[0];
307 nmav 1.1 }
308    
309     void smp_reinit()
310     {
311     #ifdef ENABLE_SMP
312 nmav 1.2 int i;
313     server_params *params = global_server_params;
314 nmav 1.15 int max_threads = max_server_threads;
315 nmav 1.1 #else
316 nmav 1.2 int max_threads = 1;
317 nmav 1.1 #endif
318    
319 nmav 1.2 if (global_server_params_size < max_threads) {
320 nmav 1.15 log_error_time();
321     fprintf(stderr, "Cannot increase threads on runtime.\n");
322     max_threads = global_server_params_size;
323 nmav 1.2 }
324 nmav 1.1 #ifdef ENABLE_SMP
325 nmav 1.15 for (i = 1; i < max_threads; i++) {
326 nmav 1.1 pthread_t tid;
327 nmav 1.15 if (pthread_create(&tid, NULL, &select_loop, &params[i]) != 0) {
328     log_error_time();
329     fprintf(stderr, "Could not dispatch threads.\n");
330     exit(1);
331 nmav 1.1 }
332     params[i].tid = tid;
333 nmav 1.2 }
334 nmav 1.1 #endif
335    
336 nmav 1.2 if (max_threads > 0) {
337 nmav 1.1 log_error_time();
338 nmav 1.15 fprintf(stderr, "Regenerated a pool of %d threads.\n", max_threads);
339     }
340 nmav 1.1
341 nmav 1.2 return;
342 nmav 1.1 }
343    
344 nmav 1.8 #ifdef ENABLE_HIC
345 nmav 1.10
346     pthread_t hic_tid;
347 nmav 1.8
348     /* This function will return a server_params pointer. This
349     * pointer is to be used as a pointer to the select loop.
350     */
351 nmav 1.15 void hic_init()
352 nmav 1.8 {
353 nmav 1.15 hic_params *params = global_hic_params;
354     int i;
355     #ifdef ENABLE_SMP
356     pthread_t tid;
357     #endif
358    
359     if (max_hic_threads == 0)
360     return;
361 nmav 1.8
362     #ifdef ENABLE_SMP
363    
364 nmav 1.15 if (global_hic_params_size > 0
365     && global_hic_params_size != max_hic_threads) {
366     log_error_time();
367     fprintf(stderr,
368     "Cannot change the HIC threads number on runtime.\n");
369     max_hic_threads = global_hic_params_size;
370     } else {
371     /* first time.. Allocate memory */
372     params = calloc(1, sizeof(hic_params) * max_hic_threads);
373     if (params == NULL) {
374     log_error_time();
375     fprintf(stderr,
376     "Could not allocate memory for HIC parameters.\n");
377     exit(1);
378     }
379    
380     for (i = 0; i < max_hic_threads; i++) { /* initialize mutexes */
381     pthread_mutex_init(&params[i].lock, NULL);
382 nmav 1.8 }
383    
384 nmav 1.15 global_hic_params = params;
385     global_hic_params_size = max_hic_threads;
386    
387     }
388    
389     for (i = 0; i < max_hic_threads; i++) {
390     if (pthread_create(&tid, NULL, &hic_main_loop, &params[i]) != 0) {
391     log_error_time();
392     fprintf(stderr, "Could not dispatch hic thread.\n");
393     exit(1);
394     }
395     params[i].tid = tid;
396     }
397    
398     log_error_time();
399     fprintf(stderr,
400     "%s: Dispatched %d HIC threads.\n", SERVER_NAME,
401     max_hic_threads);
402 nmav 1.8
403     #endif
404    
405 nmav 1.15 return;
406 nmav 1.8 }
407    
408 nmav 1.15 #endif /* ENABLE_HIC */
409 nmav 1.1
410 nmav 1.15 static socket_type create_server_socket(int port, int secure)
411 nmav 1.1 {
412 nmav 1.15 socket_type server_s;
413 nmav 1.1
414 nmav 1.15 server_s.secure = secure;
415     server_s.port = port;
416    
417     server_s.socket = socket(SERVER_AF, SOCK_STREAM, IPPROTO_TCP);
418     if (server_s.socket == -1) {
419     DIE("unable to create socket");
420     }
421    
422     /* server socket is nonblocking */
423     if (set_nonblock_fd(server_s.socket) == -1) {
424     DIE("fcntl: unable to set server socket to nonblocking");
425     }
426    
427     /* close server socket on exec so cgi's can't write to it */
428 nmav 1.24 if (set_cloexec_fd(server_s.socket) == -1) {
429 nmav 1.15 DIE("can't set close-on-exec on server socket!");
430     }
431 nmav 1.1
432 nmav 1.15 /* reuse socket addr */
433     if ((setsockopt
434     (server_s.socket, SOL_SOCKET, SO_REUSEADDR, (void *) &sock_opt,
435     sizeof(sock_opt))) == -1) {
436     DIE("setsockopt");
437     }
438    
439     /* internet family-specific code encapsulated in bind_server() */
440     if (bind_server(server_s.socket, server_ip, port) == -1) {
441     DIE("unable to bind");
442     }
443    
444     /* listen: large number just in case your kernel is nicely tweaked */
445     if (listen(server_s.socket, backlog) == -1) {
446     DIE("unable to listen");
447     }
448     return server_s;
449 nmav 1.1 }
450    
451     static void drop_privs(void)
452     {
453 nmav 1.15 /* give away our privs if we can */
454     if (getuid() == 0) {
455     struct passwd *passwdbuf;
456     passwdbuf = getpwuid(server_uid);
457     if (passwdbuf == NULL) {
458     DIE("getpwuid");
459     }
460     if (initgroups(passwdbuf->pw_name, passwdbuf->pw_gid) == -1) {
461     DIE("initgroups");
462     }
463     if (setgid(server_gid) == -1) {
464     DIE("setgid");
465     }
466     if (setuid(server_uid) == -1) {
467     DIE("setuid");
468     }
469     /* test for failed-but-return-was-successful setuid
470     * http://www.securityportal.com/list-archive/bugtraq/2000/Jun/0101.html
471     */
472     if (setuid(0) != -1) {
473     DIE("icky Linux kernel bug!");
474     }
475     } else {
476     if (server_gid || server_uid) {
477     log_error_time();
478     fprintf(stderr, "Warning: "
479     "Not running as root: no attempt to change"
480     " to uid %d gid %d\n", server_uid, server_gid);
481     }
482     server_gid = getgid();
483     server_uid = getuid();
484     }
485 nmav 1.1 }
486    
487     /*
488     * Name: fixup_server_root
489     *
490     * Description: Makes sure the server root is valid.
491     *
492     */
493    
494     static void fixup_server_root()
495     {
496 nmav 1.15 if (!server_root) {
497 nmav 1.1 #ifdef SERVER_ROOT
498 nmav 1.15 server_root = strdup(SERVER_ROOT);
499     if (!server_root) {
500     perror("strdup (SERVER_ROOT)");
501     exit(1);
502     }
503 nmav 1.1 #else
504 nmav 1.15 fputs(SERVER_NAME
505     ": don't know where server root is. Please #define "
506     "SERVER_ROOT in defines.h\n"
507     "and recompile, or use the -c command line option to "
508     "specify it.\n", stderr);
509     exit(1);
510     #endif
511     }
512    
513     if (chdir(server_root) == -1) {
514     fprintf(stderr, "Could not chdir to \"%s\": aborting\n",
515     server_root);
516     exit(1);
517     }
518    
519 nmav 1.1 }
520    
521 nmav 1.15 char boa_tls_version[64] = "\0";
522 nmav 1.16 char boa_version[] = "Server: "SERVER_NAME"/"SERVER_VERSION"\r\n";
523 nmav 1.15
524     static void create_server_names()
525     {
526 nmav 1.19 #ifdef ENABLE_SSL
527 nmav 1.15 if ( boa_tls_version[0] == 0) {
528     strcpy( boa_tls_version, "Server: "SERVER_NAME"/"SERVER_VERSION" GnuTLS/");
529     strcat( boa_tls_version, gnutls_check_version(NULL));
530 nmav 1.16 strcat( boa_tls_version, "\r\n");
531 nmav 1.15 }
532 nmav 1.19 #endif
533 nmav 1.15 }
534 nmav 1.17
535     #ifdef HAVE_GETRLIMIT
536    
537     #ifndef RLIMIT_NOFILE
538     # define RLIMIT_NOFILE RLIMIT_OFILE
539     #endif
540    
541     #define SET_MAX_CON( lim) \
542     if (lim == RLIM_INFINITY) { \
543 nmav 1.21 max_connections = INT_MAX; \
544 nmav 1.17 } else { \
545     max_connections = lim; \
546     }
547    
548     static void initialize_rlimits( )
549     {
550     int c;
551     struct rlimit rl;
552    
553 nmav 1.20 if (max_connections < 1) {
554 nmav 1.17 /* 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 nmav 1.18 } 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 nmav 1.17 }
572     }
573     #endif
574     }
575     }
576    
577     #else /* rlimits are not present */
578     static void initialize_rlimits( )
579     {
580 nmav 1.21 if (max_connections < 1)
581     max_connections = INT_MAX;
582 nmav 1.17 return;
583     }
584     #endif

webmaster@linux.gr
ViewVC Help
Powered by ViewVC 1.1.26