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

Annotation of /hydra/src/boa.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.7 - (hide 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 nmav 1.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 nmav 1.7 /* $Id: boa.c,v 1.6 2002/09/25 19:55:53 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     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 nmav 1.3 socket_type server_s[2] = {{ -1, 0, 0, 0}, { -1, -1, 0, 0 }}; /* boa socket */
56 nmav 1.1 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 nmav 1.5
147     initialize_mmap();
148 nmav 1.1
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 nmav 1.4 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 nmav 1.1 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 nmav 1.2 int i;
300     server_params *params = global_server_params;
301     int max_threads = server_max_threads;
302 nmav 1.1 #else
303 nmav 1.2 int max_threads = 1;
304 nmav 1.1 #endif
305    
306 nmav 1.2 if (global_server_params_size < max_threads) {
307 nmav 1.1 log_error_time();
308     fprintf(stderr,
309     "Cannot increase threads on runtime.\n");
310     max_threads = global_server_params_size;
311 nmav 1.2 }
312 nmav 1.1
313     #ifdef ENABLE_SMP
314 nmav 1.2 for( i=1;i<max_threads;i++) {
315 nmav 1.1 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 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     fprintf(stderr,
330     "Regenerated a pool of %d threads.\n", max_threads);
331 nmav 1.2 }
332 nmav 1.1
333 nmav 1.2 return;
334 nmav 1.1 }
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 nmav 1.3 server_s.port = port;
343 nmav 1.1
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 nmav 1.6 fputs(SERVER_NAME": don't know where server root is. Please #define "
433 nmav 1.5 "SERVER_ROOT in defines.h\n"
434 nmav 1.1 "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